views:

379

answers:

2

Hi Guys,

I'm trying out Spring MVC 3.0 for the first time and like to make it RESTfull.

This is my controller:

    @Controller
@RequestMapping(value = "/product")
@SessionAttributes("product")
public class ProductController {

    @Autowired
    private ProductService productService;

    public void setProductValidator(ProductValidator productValidator, ProductService productService) {
        this.productService = productService;
    }

    @RequestMapping(method = RequestMethod.GET)
    public Product create() {
        //model.addAttribute(new Product());
        return new Product();
    }

    @RequestMapping(method = RequestMethod.POST)
    public String create(@Valid Product product, BindingResult result) {
        if (result.hasErrors()) {
            return "product/create";
        }
        productService.add(product);
        return "redirect:/product/show/" + product.getId();
    }

    @RequestMapping(value = "/show/{id}", method = RequestMethod.GET)
    public Product show(@PathVariable int id) {
        Product product = productService.getProductWithID(id);
        if (product == null) {
            //throw new ResourceNotFoundException(id);
        }
        return product;
    }

    @RequestMapping(method = RequestMethod.GET)
    public List<Product> list()
    {
        return productService.getProducts();
    }

}

I have 2 questions about this.

I'm a believer in Convention over Configuration and therefor my views are in jsp/product/ folder and are called create.jsp , list.jsp and show.jsp this works relatively well until I add the @PathVariable attribute. When I hit root/product/show/1 I get the following error: ../jsp/product/show/1.jsp" not found how do I tell this method to use the show.jsp view ?

If I don't add the RequestMapping on class level my show method will be mapped to root/show instead of root/owner/show how do I solve this ? I'd like to avoid using the class level RequestMapping.

+2  A: 

add your 'product' to Model and return a String /product/show instead of Product. In your show.jsp, you can access the product object form pageContext

Teja Kantamneni
I know I can use a return type String but I prefer not to do that. I'd like to use the return types as is now. It should be possible since it works for all other methods. Thanks for the quick reply though
Gidogeek
+1  A: 

Check out the section in the manual about "Supported handler method arguments and return types".

Basically, when your @RequestMapping method returns just an object, then Spring uses this as a single model attribute, and, I'm guessing, attempts to use the request URL as the basis for the view name.

The easiest way to return the view and data you want from the same method is probably to just have the method return a ModelAndView, so you can explicitly specify the viewName and the model data.

matt b
Like I mentioned above, I know there are various different approaches to solve this problem. I do however like to use my current method and like to solve the problem with the current approach/convention of return types. It should be possible with my current return type convention instead of the void/String/Model/ModelAndView return types. Thanks for your reply and I'm aware of your solution.
Gidogeek
But I'm afraid that this is how Spring MVC with annotations expects you to return the viewName - through the return type of the method.
matt b
the create() method has a return type of Product but uses the create.jsp as does the list() method use the list.jsp so why wouldn't the show() method be able to use the show.jsp ? I appreciate your time and I'm new to Spring but when the other 2 examples work I can't see why show() wouldn't work.
Gidogeek
The other methods "work" because when you don't specify a logical view name, DispatcherServlet defaults to using a RequestToViewNameTranslator which simply chomps off the last part of the request URL to form the viewname ("/root/owner/list" -> "list","root/owner/show/1" -> "1"). To use view names other than what the default translator would determine (which is probably 90% of the time), you need to specify the view name yourself. All you need to do is change your method to return a ModelAndView, set the viewName, and add the Product to the model, everything else will still work the same.
matt b
Ok Matt, that makes sense. I'll have to accept that it won't work as I want out of the box then. However let me ask you this then. What's the advantage over using ModelAndView as return type over String ? I've got it working with String return type now already but try to avoid having to change it in the future. So before I change all my methods to use String is their any reason why I should use ModalAndView over String ? since it seems they both accomplish the same thing. In this example: http://blog.springsource.com/2009/03/08/rest-in-spring-3-mvc/ they use the String return type.
Gidogeek
`ModelAndView` is just a simple holder of viewName and model data. It has it's origins in the pre-annotation versions of MVC; controllers had to return a ModelAndView object (since a controller is responsible for determining both view and model and a method can't return two things). I'm not super experienced with using the new annotations, but I believe the choice would come down to one of style, or how much model data your method needs to return. Functionally, if you can still specify the other model data with `@ModelAttribute`s, it should be the same functionally.
matt b
Okey Matt, Thank you very much. You've been a great help.
Gidogeek