This is the 19th day of my participation in the August More Text Challenge

Spring MVC automatic configuration

SpringBoot implements custom functions, and you need to find its automatic configuration class. Generally, the automatic configuration class function will first determine whether there are related classes in the container. If not, the default automatic configuration class in Spring Boot will be used

SpringMVC execution flow:

Spring MVC Auto-configuration

Docs. Spring. IO/spring – the boot…

Spring Boot automatic configuration of Spring MVC

  • Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.

    • The ViewResolver is automatically configured (the View resolver: based on the method’s return value to the View object, the View object decides how to render (forward? Redirect? ……) )
    • ContentNegotiatingViewResolver: combines all view parsers;
    • We can add a view parser to the container ourselves;
  • Support for serving static resources, including support for WebJars (covered later in this document)). Static resource file path webjars

  • Static index.html support

  • Custom Favicon support (covered later in this document). favicon.ico

  • Converter, GenericConverter, and Formatter Beans are automatically registered.

    • To Converter D. Type conversion between front and back bean;

    • (2020/8/5 = Date)

    •  spring.mvc.date-format
      Copy the code

      Formatters and converters can be added by themselves, which need to be put into containers

  • Support for HttpMessageConverters (covered later in this document).

    • HttpMessageConverters: Used by SpringMVC to convert Http requests and responses; User—json;

    • HttpMessageConverters: Get all htPMessageconverters from the container.

      It can be added by yourself and must be placed in a container

  • Automatic registration of MessageCodesResolver (covered later in this document).

  • Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).

If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.

Spring MVC extension

SpringBoot 2.x web development, add (extension) automatic Configuration class, need to add @Configuration annotation, If you want to take over SpringMVC(Spring Boot does not automatically configure SpringMVC), Annotate @enableWebMVC in the Configuration class modified by @Configuration.

1. Change the view mapping address method

(Override addViewControllers() method)

@Configuration public class MyMvcConfig implements WebMvcConfigurer { @Override public void AddViewControllers (ViewControllerRegistry registry) { Request to success. The HTML page registry. AddViewController ("/yousee "). SetViewName ("/success "); / / / / access the home page, mapping registry. AddViewController ("/"). SetViewName (" login "); registry.addViewController("/index.html").setViewName("login"); registry.addViewController("/main.html").setViewName("dashboard"); }}Copy the code

Internationalization, language parser

(1). Internationalize the configuration file

Setting -> File Encoding -> UTF-8

(2). Spring Boot automatically configures components to manage internationalized resource files

We can place the internationalization configuration file directly in the classpath called message.properties (the default internationalization file is message_zh_CN, message_en_US).

You can also customize paths :(why use. Instead of/because it’s a package)

 spring.messages.basename=i18n.login
Copy the code

. <h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1> <label class="sr-only" th:text="#{login.username}">Username</label> <input type="text" class="form-control" placeholder="Username" th:placeholder="#{login.username}" required="" autofocus=""> <label class="sr-only" th:text="#{login.password}">Password</label> <input type="password" class="form-control" placeholder="Password" th:placeholder="#{login.password}" required=""> <div class="checkbox mb-3"> <label> <input type="checkbox" value="remember-me"> [[#{login.remember}]] </label> </div> <button class="btn btn-lg btn-primary btn-block" Type ="submit" th:text="#{login. BTN}">Sign in</button> < P class=" MT-5 MB-3 text-muted">© 2019-2020</ P > <a class=" BTN BTN - sm "Chinese > < / a > < a class =" BTN BTN - sm "> English < / a >...Copy the code

(4). Click the Chinese /English button to achieve internationalization switch

<! - hyperlinks take parameters - > < a class = "BTN BTN - sm" th: href = "@ {/ index. The HTML (language = 'zh_CN')}" > English < / a > < a class = "BTN BTN - sm" th:href="@{/index.html(language='en_US')}">English</a>Copy the code

Write the LocaleResolver implementation class manually; Override the resolveLocale method

public class MyLocaleResolver implements LocaleResolver { @Override public Locale resolveLocale(HttpServletRequest httpServletRequest) { String language = httpServletRequest.getParameter("language"); Locale locale = Locale.getDefault(); if(! StringUtils.isEmpty(language)){ String[] splits = language.split("_"); locale = new Locale(splits[0],splits[1]); } return locale; } @Override public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale Locale) {}} =================== // The method name must be the same as the returned value. @configuration public class MyMvcConfig implements WebMvcConfigurer { @Bean public LocaleResolver localeResolver(){ return new MyLocaleResolver(); }}Copy the code

3. Login submission, interceptor

(1). Login form

 <body class="text-center">
     <form class="form-signin" action="dashboard.html" th:action="@{/user/login}" method="post">
Copy the code

(2). LoginController

Prevent forms from being submitted repeatedly and use redirected pages;

Redirected pages can be mapped by view or specified directly;

The HTML file that directly specifies redirection should be placed in the static resources folder (static, public).

 @Controller
 public class LoginController {
 //    @RequestMapping(value = "/user/login",method = RequestMethod.POST)
     @PostMapping("/user/login")
     public String login(String username,
                         String password,
                         Map<String,Object> errorInfo,
                         HttpSession session){
 ​
         if(!StringUtils.isEmpty(username) && password.equals("123456")){
             // 登录成功,将用户存入 session
             session.setAttribute("loginUser",username);
             // 防止表单重复提交,需要重定向页面
             return "redirect:/main.html";
         } else{
             errorInfo.put("message","用户名或密码错误!");
             return "login";
         }
     }
 }
Copy the code
 @Configuration
 public class MyMvcConfig implements WebMvcConfigurer {
     @Override
     public void addViewControllers(ViewControllerRegistry registry) {
         // 映射
         registry.addViewController("/main.html").setViewName("dashboard");
     }
 }
Copy the code

But dashboard.html pages can be accessed directly without logging in, so you need an interceptor

(3). The interceptor

(Override addInterceptors() method)

public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); Object user = session.getAttribute("loginUser"); if(user ! = null){return true; } else{request. SetAttribute ("message"," Please login first "); request.getRequestDispatcher("/index.html").forward(request,response); return false; }}... ==================== @Configuration public class MyMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**") .excludePathPatterns("/","/index.html","/user/login","/webjars/**","/asserts/**"); }}Copy the code

Restful style

1. Rest style

URI: / Resource name/RESOURCE ID HTTP request mode Distinguishes CRUD operations on resources

Plain CRUD (URI differentiation) RestfulCRUD (request mode)
The query getEmp emp—GET
add addEmp? xxx emp—POST
Modify the updateEmp? id=1 emp/{id}—PUT
delete deleteEmp? id=1 emp/{id}—DELETE

2. Request architecture of the experiment

function The request URI Request way
Query all employees emps GET
Querying an employee emp/1 GET
Go to the Add page emp GET
Add employees emp POST
Go to the modify page (employee information echo) emp/1 GET
Modify the employee emp PUT
Delete staff emp/1 DELETE

4. How to send a PUT request

  • Configure HiddenHttpMethodFilter in SpringMVC; (SpringBoot automatically configured, but SpringBoot default does not support, need to modify the spring configuration file. The MVC. Hiddenmethod. Filter. The enabled = true)
  • Page to create a POST form
  • Create an input item, name=’_method’; The value is the request we specify
WebMvcAutoConfiguration.java @Bean @ConditionalOnMissingBean(HiddenHttpMethodFilter.class) @ConditionalOnProperty(prefix  = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false) public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() { return new OrderedHiddenHttpMethodFilter(); }Copy the code
# enable Http request method to filter the spring. MVC. Hiddenmethod. Filter. The enabled = trueCopy the code
<form th:action="@{/emp}" method="post"> <input type="hidden" name="_method" value="put" th:if="${emp! =null}"/> ... </form>Copy the code

In order to make the layout more beautiful, use JS to submit

<! <button th:attr="del_uri=@{emp/} + ${emp.id}" class=" BTN btn-sm btn-danger deleteBtn"> delete </button> <! -- The form to submit, <form id="deleteEmpForm" method="post"> <input type="hidden" name="_method" value="delete"/> </form> <! --> <script> $(".deletebtn ").click(function(){// Delete current employee $("#deleteEmpForm").attr("action",$(this).attr("del_uri")).submit(); return false; }); </script>Copy the code