0

In a Servlet, you can include an @Override service method which gets called before the doGet or doPost, is there a way to achieve the same in a Spring @Controller?

Or more precisely, in each method in the Controller, I need to make sure an Entity (in this case, a Product) exists and redirect otherwise, like so, so how would one achieve that in Spring? Note that I also need the Product available in each Method.

@Controller
@RequestMapping("/product/{prod_id}/attribute")
public class AttributeController {

    @Autowired
    private AttributeService attributeService;

    @RequestMapping(value = "/add", method = RequestMethod.GET)
    public String add(Model model, @PathVariable Long prod_id) {
        Product product = attributeService.getProduct(prod_id);
        if (product == null) {
            return "products/products";
        }
        model.addAttribute("product", product);
        model.addAttribute("attribute", new Attribute());
        return "products/attribute_add";
    }


    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public String save(Model model, @PathVariable Long prod_id, @Valid Attribute attribute, BindingResult result) {
        Product product = attributeService.getProduct(prod_id);
        if (product == null) {
            return "products/products";
        }

        // ...
    }

    // ...
}
Christian
  • 3,708
  • 3
  • 39
  • 60

1 Answers1

1

This can be done with HandlerInterceptor. All you need to do is to extend HandlerInterceptorAdapter#preHandle and then register your interceptor through WebMvcConfigurer#addInterceptors. You can choose to use interceptor with all your mappings or with some specific mappers through InterceptorRegistration object with is returned by InterceptorRegistry#addInterceptor method.

By the way, HandlerInterceptors are useful to do some utility operations with requests and responses in general, like logging, adding headers, authentication, etc. For business-related operations I would recommend to use ControllerAdvice with custom business-oriented exceptions. In this case it would be a method which retrieves Product from database and throws custom exception if not found.

Everv0id
  • 1,862
  • 3
  • 25
  • 47
  • Is it possible to have `Product product` available in each method without retrieving it again from the database? – Christian Dec 22 '17 at 18:03
  • You can use standard [ServletRequest](https://docs.oracle.com/javaee/6/api/javax/servlet/ServletRequest.html#setAttribute(java.lang.String,%20java.lang.Object)) methods to store some objects in requests. – Everv0id Dec 22 '17 at 18:06
  • `HandlerInterceptor` is a standard Spring bean and can autowire any Spring bean. But this is a very strange that you want to work with DB in interceptor, because it is basically used for some common and utility operations like logging, authentication, fraud protection etc. But if you need you can easily inject your beans. Make sure that you are not autowiring interceptor to your service class, and that you declared interceptor as a Spring bean in your context configuration. – Everv0id Dec 22 '17 at 18:26
  • I worked that out using https://stackoverflow.com/questions/18218386/cannot-autowire-service-in-handlerinterceptoradapter – Christian Dec 22 '17 at 18:27
  • You say strange, and I agree it seems disjointed to normal design but then how would you achieve the same result? – Christian Dec 22 '17 at 18:27
  • 1
    I would use a custom method of getting a product from DB with throwing an exception if not found, then managed the exception with simple [ControllerAdvice](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html) – Everv0id Dec 22 '17 at 18:32
  • oo yes, I just did it that way and it's a much nicer solution. Thanks – Christian Dec 22 '17 at 18:38
  • Good to hear! If you found my answer useful, you can always say thanks by accepting it :) – Everv0id Dec 22 '17 at 19:48
  • Accepted and gave you a +1 Thanks – Christian Dec 22 '17 at 19:49