Spring Web MVC
DispatcherServlet
- Use Java configuration or web.xml to declare and map according to the Servlet specification.
- The Spring configuration is then used to discover the delegate components needed for request mapping, view resolution, exception handling, etc.
Servlet configuration
public class MyWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletCxt) { // Load Spring web application configuration AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext(); ac.register(AppConfig.class); ac.refresh(); // Register and initialize Dispatcher Servlet DispatcherServlet servlet = new DispatcherServlet(ac); ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet); registration.setLoadOnStartup(1); registration.addMapping("/app/*"); } }
perhaps
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class<?>[] { RootConfig.class };//No null substitution } @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[] { App1Config.class }; } @Override protected String[] getServletMappings() { return new String[] { "/app1/*" }; } @Override protected void customizeRegistration(Dynamic registration) { registration.setInitParameter("enableLoggingRequestDetails", "true"); } }
Processing process
- Search the Web Application Context in the request and bind it to attributes that can be used by other elements in the controller and process
- Bind the language environment parser to the request so that the elements in the process parse the language environment used to process the request (rendering views, preparing data, etc.)
- Theme parsers are bound to requests that allow elements such as views to decide which theme to use
- If a multipart file parser is specified, the requested multipart is checked. When found, encapsulate the request in Multipartite Http ServletRequest
- Search for the appropriate handler. Find and execute the execution chain associated with the handler (preprocessor, postprocessor, and controller) to prepare the model or render
- If the model is returned, the view is rendered. If no model is returned, the view is not rendered because the request has been executed
Special Bean
-
Handler Mapping -- Mapping requests to handlers with pre- and post-interceptors. details
- Main implementers RequestMapping Handler Mapping and BeanNameUrlHandler Mapping
-
Method of Interceptor Implementing Handler Interceptor by Interceptor
- preHandle(.): Execute before the handler
- postHandle(.): Execute after the handler
- afterCompletion(.): Execute after the request has been completed
public interface HandlerMapping { /** * Map HttpServletRequest to Handler and bind the matching Handler Interceptor to Handler Execution Chain */ HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; } public class HandlerExecutionChain { private final Object handler; private HandlerInterceptor[] interceptors; }
- Handler Adapter - Assists Dispatcher Servlet to call the handler mapped to the request. control
public interface HandlerAdapter { /** * Processing requests with a given handler returns Model AndView encapsulated with model data and view names */ ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; } /** * Objects encapsulated by characters and Map s */ public class ModelAndView { private Object view; private ModelMap model; }
-
ViewResolver -- Resolves the string view name returned from the handler to the actual view to be presented to the response
- Internal ResourceViewResolver - Resolving Views into Internal Resources of Web Applications
- UrlBasedViewResolver - Resolve views directly by their name
- Content Negotiating ViewResolver -- Resolve Views Based on Request File Name or Accept Header
- FreeMarkerViewResolver - Parsing Views into FreeMarker Templates
- ResourceBundleViewResolver - Resolve views into resource attribute files
- AbstractCaching ViewResolver, an abstract view parser class, provides the ability to cache views
public interface ViewResolver { /** * Resolves the return based on the specified view name */ View resolveViewName(String viewName, Locale locale) throws Exception; } public interface View { /** * Rendering views based on specified model data */ void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception; }
-
Handler Exception Resolver -- A strategy for parsing exceptions that may map exceptions to handlers, HTML error views, or other targets
- SimpleMapping Exception Resolver -- Mapping between Exception Class Names and Error View Names
- DefaultHandler Exception Resolver - Resolves exceptions thrown by Spring MVC and maps them to HTTP status codes
- ResponseStatusException Resolver - Resolves exceptions using @ResponseStatus and maps them to the specified HTTP status code
- ExceptionHandlerExceptionResolver -- Resolve exceptions by calling @ExceptionHandler in the @Controller or @ControllerAdvice class
@RestController public class ErrorController { @RequestMapping(path = "/error") public Map<String, Object> handle(HttpServletRequest request) { Map<String, Object> map = new HashMap<String, Object>(); map.put("status", request.getAttribute("javax.servlet.error.status_code")); map.put("reason", request.getAttribute("javax.servlet.error.message")); return map; } }
- LocaleResolver - Provides an internationalized view of the client's local environment
- Theme Resolver - Provides personalized layout to parse topics that web applications can use
- MultipartResolver - Provides form file upload and parses multi-part requests
Annotation Controller
- Declare Configuration - Activate @Controller Automatic Detection
@Configuration @ComponentScan("org.example.web") public class WebConfig { // ... }
-
Request Mapping --@RequestMapping completes the mapping of the request to the Controller method
- Variants: @GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping
- Access URI variables through @PathVariable (support placed on classes and methods)
- {varName:regex} declares URI variables using regular expressions
- consumes specifies the Content-Type of the request to restrict the mapping of the request
- produces specifies the Accept of the request header to restrict the mapping of the request
- params specifies the parameters of the request
- headers specify the request header for the request
@RestController @RequestMapping("/persons") class PersonController { @GetMapping("/{id}") public Person getPerson(@PathVariable Long id) { // ... } @GetMapping("/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}") public void handle(@PathVariable String version, @PathVariable String ext) { // ... } @PostMapping(path = "/pets", consumes = "application/json") public void addPet(@RequestBody Pet pet) { // ... } @GetMapping(path = "/pets/{petId}", produces = "application/json;charset=UTF-8") @ResponseBody public Pet getPet(@PathVariable String petId) { // ... } @GetMapping(path = "/pets/{petId}", params = "myParam=myValue") public void findPet(@PathVariable String petId) { // ... } @GetMapping(path = "/pets", headers = "myHeader=myValue") public void findPet(@PathVariable String petId) { // ... } @PostMapping @ResponseStatus(HttpStatus.CREATED) public void add(@RequestBody Person person) { // ... } }
- exception handling
@Controller public class SimpleController { // ... @ExceptionHandler public ResponseEntity<String> handle(IOException ex) { // ... } }
- Controller Advice - Global exception handling, global data preprocessing, global data binding
@ControllerAdvice(basePackages = "com.cc.controller") public class SpringControllerAdvice { @ExceptionHandler(RuntimeException.class) public ModelAndView runtimeException(RuntimeException e) { return new ModelAndView("error"); } } @ControllerAdvice(basePackages = "com.cc.controller") public class SpringControllerAdvice { @InitBinder public void globalInitBinder(WebDataBinder binder) { binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd")); } } @ControllerAdvice(basePackages = "com.cc.controller") public class SpringControllerAdvice { @ModelAttribute(value = "message") public String globalModelAttribute() { return "this is from model attribute"; } }
MVC configuration
- @ Enable WebMvc activation
- Implementing WebMvcConfigurer Add Function
- Rewrite addFormatters for type conversion
- Rewrite getValidator custom global Validator instance, or add it through @InitBinder
@Controller public class MyController { @InitBinder protected void initBinder(WebDataBinder binder) { binder.addValidators(new FooValidator()); } }
- Rewrite addInterceptors to add interceptors
- Rewrite the media type of configureContentNegotiation configuration request
- Rewrite configureMessageConverters to configure message converters
- Rewrite addViewControllers to add view controllers
- Rewrite the configureViewResolvers configuration view parser
- Rewrite addResourceHandlers to add static resource processors
- Rewrite configureDefault Servlet Handling to configure the default Servlet processor
- Rewrite configurePathMatch configuration path matching
@Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { @Override public void addFormatters(FormatterRegistry registry) { // ... } @Override public Validator getValidator(); { // ... } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LocaleChangeInterceptor()); registry.addInterceptor(new ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**"); registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*"); } @Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { configurer.mediaType("json", MediaType.APPLICATION_JSON); configurer.mediaType("xml", MediaType.APPLICATION_XML); } @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder() .indentOutput(true) .dateFormat(new SimpleDateFormat("yyyy-MM-dd")) .modulesToInstall(new ParameterNamesModule()); converters.add(new MappingJackson2HttpMessageConverter(builder.build())); converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build())); } @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("home"); } @Override public void configureViewResolvers(ViewResolverRegistry registry) { registry.enableContentNegotiation(new MappingJackson2JsonView()); registry.jsp(); } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**") .addResourceLocations("/public", "classpath:/static/") .setCachePeriod(31556926); } @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable();//Or configurer. enable ("myCustomDefault Servlet"); } @Override public void configurePathMatch(PathMatchConfigurer configurer) { configurer .setUseSuffixPatternMatch(true) .setUseTrailingSlashMatch(false) .setUseRegisteredSuffixPatternMatch(true) .setPathMatcher(antPathMatcher()) .setUrlPathHelper(urlPathHelper()) .addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController.class)); } @Bean public UrlPathHelper urlPathHelper() { //... } @Bean public PathMatcher antPathMatcher() { //... } }
View Technology
- Thymeleaf —— Modernized server-side Java template engine, native HTML support, double-click preview in browser
- FreeMarker —— Template Engine for Generating Text Output of Types from HTML to E-mail
@Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { @Override public void configureViewResolvers(ViewResolverRegistry registry) { registry.freemarker(); } // Configure FreeMarker... @Bean public FreeMarkerConfigurer freeMarkerConfigurer() { FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); configurer.setTemplateLoaderPath("/WEB-INF/freemarker"); return configurer; } }
<#import "/spring.ftl" as spring/> <html> ... <form action="" method="POST"> Name: <@spring.bind "myModelObject.name"/> <input type="text" name="${spring.status.expression}" value="${spring.status.value?html}"/><br> <#list spring.status.errorMessages as error> <b>${error}</b> <br> </#list> <br> ... <input type="submit" value="submit"/> </form> ... </html>
- Groovy Markup —— Generating XML-like Tags
@Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { @Override public void configureViewResolvers(ViewResolverRegistry registry) { registry.groovy(); } // Configure the Groovy Markup Template Engine... @Bean public GroovyMarkupConfigurer groovyMarkupConfigurer() { GroovyMarkupConfigurer configurer = new GroovyMarkupConfigurer(); configurer.setResourceLoaderPath("/WEB-INF/"); return configurer; } }
yieldUnescaped '<!DOCTYPE html>' html(lang:'en') { head { meta('http-equiv':'"Content-Type" content="text/html; charset=utf-8"') title('My page') } body { p('This is an example of HTML contents') } }
- Script view
@Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { @Override public void configureViewResolvers(ViewResolverRegistry registry) { registry.scriptTemplate(); } @Bean public ScriptTemplateConfigurer configurer() { ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer(); configurer.setEngineName("nashorn"); configurer.setScripts("mustache.js"); configurer.setRenderObject("Mustache"); configurer.setRenderFunction("render"); return configurer; } }
<html> <head> <title>{{title}}</title> </head> <body> <p>{{body}}</p> </body> </html>
- JSP
<form:form> <table> <tr> <td>First Name:</td> <td><form:input path="firstName"/></td> </tr> <tr> <td>Last Name:</td> <td><form:input path="lastName"/></td> </tr> <tr> <td colspan="2"> <input type="submit" value="Save Changes"/> </td> </tr> </table> </form:form>
- RSS and Atom
public class SampleContentAtomView extends AbstractAtomFeedView { @Override protected void buildFeedMetadata(Map<String, Object> model, Feed feed, HttpServletRequest request) { // implementation omitted } @Override protected List<Entry> buildFeedEntries(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { // implementation omitted } }
public class SampleContentRssView extends AbstractRssFeedView { @Override protected void buildFeedMetadata(Map<String, Object> model, Channel feed, HttpServletRequest request) { // implementation omitted } @Override protected List<Item> buildFeedItems(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { // implementation omitted } }
- PDF and Excel
public class PdfWordList extends AbstractPdfView { protected void buildPdfDocument(Map<String, Object> model, Document doc, PdfWriter writer, HttpServletRequest request, HttpServletResponse response) throws Exception { List<String> words = (List<String>) model.get("wordList"); for (String word : words) { doc.add(new Paragraph(word)); } } }
public class ExcelViewBuilder extends AbstractExcelView { protected void buildExcelDocument(Map<String,Object> model,HSSFWorkbook wb,HttpServletRequest req, HttpServletResponse resp) { // ... } }
- XSLT
@EnableWebMvc @ComponentScan @Configuration public class WebConfig implements WebMvcConfigurer { @Bean public XsltViewResolver xsltViewResolver() { XsltViewResolver viewResolver = new XsltViewResolver(); viewResolver.setPrefix("/WEB-INF/xsl/"); viewResolver.setSuffix(".xslt"); return viewResolver; } }
@Controller public class XsltController { @RequestMapping("/") public String home(Model model) throws Exception { Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); Element root = document.createElement("wordList"); List<String> words = Arrays.asList("Hello", "Spring", "Framework"); for (String word : words) { Element wordNode = document.createElement("word"); Text textNode = document.createTextNode(word); wordNode.appendChild(textNode); root.appendChild(wordNode); } model.addAttribute("wordList", root); return "home"; } }
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" omit-xml-declaration="yes"/> <xsl:template match="/"> <html> <head><title>Hello!</title></head> <body> <h1>My First Words</h1> <ul> <xsl:apply-templates/> </ul> </body> </html> </xsl:template> <xsl:template match="word"> <li><xsl:value-of select="."/></li> </xsl:template> </xsl:stylesheet>