diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java index a1156798b08..30d29e1414b 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java @@ -103,11 +103,14 @@ import org.springframework.web.bind.support.WebBindingInitializer; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.RequestScope; import org.springframework.web.context.request.ServletWebRequest; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.method.HandlerMethod; import org.springframework.web.multipart.MultipartRequest; import org.springframework.web.servlet.HandlerAdapter; import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.View; +import org.springframework.web.servlet.mvc.LastModified; import org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver; import org.springframework.web.servlet.mvc.multiaction.MethodNameResolver; import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException; @@ -440,6 +443,13 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator return mav; } + /** + * This method always returns -1 since an annotated controller can have many methods, each + * requiring separate lastModified calculations. Instead an @{@link RequestMapping} method + * can calculate the lastModified value, call {@link WebRequest#checkNotModified(long)} to + * check it, and return {@code null} if that returns {@code true}. + * @see WebRequest#checkNotModified(long) + */ public long getLastModified(HttpServletRequest request, Object handler) { return -1; } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java index b5dc22e5f42..72b100d8614 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java @@ -56,6 +56,7 @@ import org.springframework.web.bind.support.WebArgumentResolver; import org.springframework.web.bind.support.WebBindingInitializer; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.ServletWebRequest; +import org.springframework.web.context.request.WebRequest; import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.HandlerMethodSelector; import org.springframework.web.method.annotation.ModelFactory; @@ -76,6 +77,7 @@ import org.springframework.web.method.support.InvocableHandlerMethod; import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.View; +import org.springframework.web.servlet.mvc.LastModified; import org.springframework.web.servlet.mvc.annotation.ModelAndViewResolver; import org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter; import org.springframework.web.servlet.mvc.method.annotation.support.DefaultMethodReturnValueHandler; @@ -432,6 +434,12 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i Void.TYPE.equals(methodReturnType.getParameterType())); } + /** + * This method always returns -1 since {@link HandlerMethod} does not implement {@link LastModified}. + * Instead an @{@link RequestMapping} method, calculate the lastModified value, and call + * {@link WebRequest#checkNotModified(long)}, and return {@code null} if that returns {@code true}. + * @see WebRequest#checkNotModified(long) + */ @Override protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) { return -1; diff --git a/spring-framework-reference/src/mvc.xml b/spring-framework-reference/src/mvc.xml index 7059dce44fb..4a60c74079d 100644 --- a/spring-framework-reference/src/mvc.xml +++ b/spring-framework-reference/src/mvc.xml @@ -790,7 +790,7 @@ public class ClinicController { URI Template Patterns URI templates can be used for convenient access to selected - segments of a URL in a @RequestMapping method. + parts of a URL in a @RequestMapping method. A URI Template is a URI-like string, containing one or more variable names. When you substitute values for these variables, the @@ -801,8 +801,8 @@ public class ClinicController { userId. Assigning the value fred to the variable yields http://www.example.com/users/fred. - In Spring MVC you can apply the @PathVariable annotation - to a method argument to indicate that it is bound to the value of a URI template variable: + In Spring MVC you can use the @PathVariable annotation on + a method argument to bind it to the value of a URI template variable: @RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET) public String findOwner(@PathVariable String ownerId, Model model) { @@ -815,30 +815,31 @@ public String findOwner(@PathVariable String ow The URI Template "/owners/{ownerId}" specifies the variable name ownerId. When the controller handles this request, the value of ownerId - is set to the value found in the appropriate segment of the URI. + is set to the value found in the appropriate part of the URI. For example, when a request comes in for /owners/fred, the value - fred is bound to the ownerId method argument. + of ownerId is fred. - The matching of method parameter names to URI Template variable - names can only be done if your code is compiled with debugging - enabled. This is normally the case, however, if you do not have debugging enabled, - you will need to specify the name of the URI Template variable as follows: - + To process the @PathVariable annotation, Spring MVC needs to find the + matching URI template variable by name. You can specify it in the annotation: + @RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET) -public String findOwner(@PathVariable("ownerId") String ownerId, Model model) { +public String findOwner(@PathVariable("ownerId") String theOwner, Model model) { // implementation omitted } - - You can do the same if you want the names of URI template variable and the method argument to differ: + + Or if the URI template variable name matches the method argument name + you can omit that detail. As long as your code is not compiled without debugging + information, Spring MVC will match the method argument name to the URI template variable name: @RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET) -public String findOwner(@PathVariable("ownerId") String theOwner, Model model) { +public String findOwner(@PathVariable String ownerId, Model model) { // implementation omitted } + - A method can have multiple @PathVariable annotations: + A method can have any number of @PathVariable annotations: @RequestMapping(value="/owners/{ownerId}/pets/{petId}", method=RequestMethod.GET) public String findPet(@PathVariable String ownerId, - @PathVariable method arguments can be of + A @PathVariable argument can be of any simple type such as int, long, Date, etc. Spring automatically converts to the appropriate type or throws a TypeMismatchException if it fails to do so. - This type conversion process can be customized through a data binder. + You can also register support for parsing additional data types. See and . +
+ URI Template Patterns with Regular Expressions + + Sometimes you need more precision in defining URI template variables. + Consider the URL "/spring-web/spring-web-3.0.5.jar". + How do you break it down into multiple parts? + + The @RequestMapping annotation supports the + use of regular expressions in URI template variables. + The syntax is {varName:regex} where the first part defines the + variable name and the second - the regular expression.For example: + + +@RequestMapping("/spring-web/{symbolicName:[a-z-]+}-{version:\d\.\d\.\d}.{extension:\.[a-z]}") + public void handle(@PathVariable String version, @PathVariable String extension) { + // ... + } +} + + +
+
Path Patterns @@ -1737,6 +1760,43 @@ public class MyFormController {
+
+ Support for the 'Last-Modified' Response Header To Facilitate Content Caching + + An @RequestMapping method may wish + to support 'Last-Modified' HTTP requests, + as defined in the contract for the Servlet API's + getLastModified method, to facilitate content caching. + This involves calculating a lastModified long + value for a given request, comparing it against the + 'If-Modified-Since' request header value, and + potentially returning a response with status code 304 (Not Modified). + An annotated controller method can achieve that as follows: + + +@RequestMapping +public String myHandleMethod(WebRequest webRequest, Model model) { + + long lastModified = // 1. application-specific calculation + + if (request.checkNotModified(lastModified)) { + // 2. shortcut exit - no further processing necessary + return null; + } + + // 3. or otherwise further request processing, actually preparing content + model.addAttribute(...); + return "myViewName"; +} + + There are two key elements to note: + calling request.checkNotModified(lastModified) + and returning null. The former sets + the response status to 304 before it returns true. + The latter, in combination with the former, causes + Spring MVC to do no further processing of the request. + +