1

I have following Spring MVC 3.2.4 method:

@RequestMapping(value = "/products/{product}", method = RequestMethod.POST)
public String update(Product product, @Valid @ModelAttribute("productForm") ProductForm productForm, BindingResult bindingResult, Model model) {
    if (bindingResult.hasErrors()) {
        return "products/view";
    }
    mapper.map(productForm, product);
    productService.saveProduct(product);
    return "redirect:/products/{product}";
}

After success it should redirect back user to detail of product. Problem is that instead of redirecting to page "/products/1" I am redirected to page "/products/Product [code=1234567890, name=Nejaky]". It looks like placeholder {product} is replaced by product.toString() instead of original ID from URL. I am using built-in Spring Data converter:

<mvc:annotation-driven conversion-service="conversionService">
    <mvc:argument-resolvers>
        <bean class="org.springframework.data.web.PageableHandlerMethodArgumentResolver" />
    </mvc:argument-resolvers>
</mvc:annotation-driven>

<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />

<bean class="org.springframework.data.repository.support.DomainClassConverter">
    <constructor-arg ref="conversionService" />
</bean>

What should I do to make it work correctly and redirect me back to "/products/1" without doing things like "redirect:/product" + product.getId()?

1
  • Do you have an attribute named "product" in your model perhaps via ModelAttribute annotated method? Commented Oct 9, 2013 at 19:23

3 Answers 3

1

Our story starts in RedirectView source code, in the method replaceUriTemplateVariables.

protected StringBuilder replaceUriTemplateVariables(
        String targetUrl, Map<String, Object> model, Map<String, String> currentUriVariables, String encodingScheme)
        throws UnsupportedEncodingException {

    StringBuilder result = new StringBuilder();
    Matcher m = URI_TEMPLATE_VARIABLE_PATTERN.matcher(targetUrl);
    int endLastMatch = 0;
    while (m.find()) {
        String name = m.group(1);
        Object value = model.containsKey(name) ? model.remove(name) : currentUriVariables.get(name);
        Assert.notNull(value, "Model has no value for '" + name + "'");
        result.append(targetUrl.substring(endLastMatch, m.start()));
        result.append(UriUtils.encodePathSegment(value.toString(), encodingScheme));
        endLastMatch = m.end();
    }
    result.append(targetUrl.substring(endLastMatch, targetUrl.length()));
    return result;
}

As you had predicted, the method uses value.toString() where value is your product object in the Model. No other component like a conversion system is involved here. Your options are as follows:

Use

"redirect:/product" + product.getId()

Add a model attribute called "productId" and use that in your view name

model.addAttribute("productId", product.getId());
"redirect:/product/{productId}"

Or use uri variables. I don't have information on those yet.

Sign up to request clarification or add additional context in comments.

Comments

0

Ok, finally found reason for this. I had to annotate product param with @PathVariable. Wondering that it worked without it.

1 Comment

In this particular case, maybe, because product object ended up in the model and then that got used when string was replaced, but in general you don't even have to have product as an argument in the handler method for replacing of {product} to work in redirect string.
0

I know it's an old question but for anyone facing the same problem here is the answer

Just inject RedirectAttributes to your controller and use redirectAtrr.addAttribute([attrbuteName],[attributeValue])

@RequestMapping(value = "/products/{product}", method = RequestMethod.POST)
public String update(Product product,@Valid,@ModelAttribute("productForm") ProductForm productForm,BindingResult bindingResult,Model model,RedirectAttributes redirectAttr) {
    if (bindingResult.hasErrors()) {
        return "products/view";
    }
    mapper.map(productForm, product);
    productService.saveProduct(product);
    redirectAttr.addAttributte("productId",product.getId());
    return "redirect:/products/{productId}";
}

Read documentation for more understanding.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.