spring mvc pattern implementation - technoangel/java GitHub Wiki
The DispatcherServlet is the main 'greeting place' or 'portal' for web traffic in Spring. This is where every request is routed and every response is delivered. This acts as a 'front-controller'. Handler Mappings registered with the DispatcherServlet take requests on behalf of the DispatcherServlet.
Spring Handlers and Handler Methods take the actual request. All controllers are handlers, but not all handlers are controllers (but most are). Handler Mapping is an implementation of a HandlerMapping interface, and it returns the configured Handler and HandlerMethod for a request. HandlerMappings are used by the DispatcherServlet to determine what code is handling what request.
It used to be that controller and method were selected in separate steps. Now (starting in 3.1) they are selected together in a single step.
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping rmhm = new RequestMappingHandlerMapping();
rmhm.setUseSuffixPatternMatch(true);
rmhm.setUseTrailingSlashMatch(true);
return rmhm;
}This example code is in the WebMvcConfig.java file and would be wired in using an initializer. The code is a sibling to declaring your JNDI data source and your View Resolver.
Similarly, you can override the configuration's default home page by putting code into the overridden #addViewControllers method.
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
WebMvcConfigurer.super.addViewControllers(registry);
}Once the Handler Mapper has determined what handler should be used to process a request, the DispatcherServlet then calls a Handler Adapter (code implementing the HandlerAdapter interface), which invokes a Handler Execution chain, consisting of a Handler and Handler Interceptors (pre-handle, post-handle, after-completion callbacks). pre-handler deals with pre-processing, post-handler deals with post-processing, and after-completion handles any cleanup. Call to the controller falls between pre- and post-handler callbacks.
The DispatcherServlet needs HandlerAdapters because it doesn't invoke a handler itself directly. Instead it calls on the HandlerAdapter to manage the invocation on its behalf.
public interface HandlerAdapter {
boolean supports(Object handler);
ModelAndView handle(HttpServletRequest request, HtpServletResponse response, Object handler) throws Exception;
long getLastModified(HttpServletRequest request, Object handler)
}In the above interface:
- supports - used to check if a particular handler instance (like a controller) is supported. This is always called before calling #handle
- handle - begins the Handler Execution Chain, handling a particular HTTP request. This returns a ModelAndView object, combining them into a single API.
Handler Interceptors seem like very formalized versions of before and after filters. All interceptors implement the HandlerInterceptor interface and they are wired to Spring as @Service. Interceptors can be restricted to only working on certain pages by using the #addPathPatterns method (the argument being the string representation of the URI path pattern).
public interface HandlerInterceptor {
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception;
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) throws Exception;
}The use cases are very similar to the before and after filters, and include:
- Add an avatar
- Gather statistics and add to request
- Add user-specified properties to view
You attach interceptors in the Configuration class/XML file. If working with a Configuration class, you'll create a new class inheriting from HandlerInterceptorAdapter:
public class HeaderInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
request.setAttribute("greeting", "We hope you have a scary and fun-filled Halloween");
String location = request.getParameter("locationName");
if(location != null) {
request.setAttribute("locationName", location);
}
return true;
}
}Then override #addInterceptors in your Configuration, adding a new instance of your inherited class:
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HeaderInterceptor());
}Now your requests will have the attributes in their ModelAndView information:
Welcome! <c:out value="${greeting }"> </c:out>NOTE: For some reason, using a HandlerMapping bean screws up Interceptors. I will find out why this happened, but for now just note their presence seems to be mutually exclusive.
The controller activity is called during interceptor calls. It is responsible for calling services and building a model.