As you know, Spring MVC is using a new annotation-based configuration model since version 2.5. To get these buns, you need to use the
<mvc: annotation-driven /> tag in the configuration file. This tag registers the
DefaultAnnotationHandlerMapping and
AnnotationMethodHandlerAdaptor in the context of the application.
DefaultAnnotationHandlerMapping does a search for
@RequestMapping annotations in the classes and creates a mapping for the handler for each plus two mappings with the suffix '. *' And '/' to the same handler. The
AnnotationMethodHandlerAdaptor's task is responsible delegation of HTTP request processing to the correct method that has the annotation noticed.
')
Therefore, for the next controller
@Controller @RequestMapping("/service/hotels") public class HotelsCollectionController { @Autowired private HotelService hotelService; @RequestMapping(method = RequestMethod.GET) public String getHotelList(Model model) { List<Hotel> list = hotelService .getHotelList(); model.addAttribute("hotels", list); return "service/hotels/read"; } public void setHotelService(HotelService hotelService) { this.hotelService = hotelService; } }
You will receive three mappings for requests to
/ service / hotels, / service / hotels / and
/service/hotels.* .
The goal of the first two is clearly to be a more user-friendly application, and the latter is used in determining the best resource representation in
ContentNegotiatingViewResolver .
Everything is good ...
The problem occurs when you try to apply a RESTful approach to web services using annotations to display requests in handlers in a similar way. Since the URL in REST is a resource, various URLs now point to various resources and your application should not carelessly handle them and use such implicit handlers for non-existing resources. The problem is aggravated by the desire to use a slash or an asterisk as a collection marker, that is, instead of
/ service / hotels in this case, someone could use, for example
/ service / hotel / or
/ service / hotel / * as the URL for the list of all hotels, though it is not very intuitive and even less expandable.
Roughly speaking - you need to return 404, and for this you need to disable the generation of such implicit mappings.
Another thing is that the spring itself refers to the processing of these implied addresses, let's say, carelessly. The obvious way out is to set the
DefaultAnnotationHandlerMapping for the application and set its
defaultSuffixPattern property to
false , not as simple as you might think.
At first glance it turns out:
<mvc:annotation-driven /> <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"> <property name="useDefaultSuffixPattern" value="false" /> </bean>
Now let's think together what will happen when creating the context. As soon as spring sees
<mvc: annotation-driven /> , it creates one
DefaultAnnotationHandlerMapping and puts it into context. As soon as she sees the above defined beans, she creates another instance of
DefaultAnnotationHandlerMapping , and also puts it in context. So our cool app will have two instances of
DefaultAnnotationHandlerMapping , one with the default settings and the other configured as needed. Which
HandlerMapping will chew the HTTP request first, depending on their internal order, and out of your control (well, almost ... ordering can be applied, but this is a crutch in this case).
Although for
/ service / hotels there is no difference, for
/ service / hotels / and
/service/hotels.* there is a difference. Most likely, you will use
ContentNegotiatingViewResolver and negotiate with the client about the best representation of resources for it, in which case you actually lost control of this interesting and important REST process for implicitly created mappings. The result of a request to them can be either a correct representation or a wrong one. In some situations, the result will be an exception and 500. I will not go into the details, but the elephant understands that this behavior should be avoided.
To avoid this, you must remove one of
HandlerMapping 's from the context. Thus, we have to remove
<mvc: annotation-driven /> and do the hard work of registering
AnnotationMethodHandlerAdaptor with our hands:
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"> <property name="useDefaultSuffixPattern" value="false" /> </bean> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
This should do what is required, and you will get a guaranteed and desired 404 to implicit URLs to existing resources, that is, I wanted to say, to explicit URLs to non-existent, in short, you know better.