Web-Servlet Technology Stack of Spring Framework Documents

Posted by dopp on Thu, 25 Jul 2019 05:47:30 +0200

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>
@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>

Topics: Java Spring xml FreeMarker JSON