How to use Spring MVC with Spring Boot

Table of contents

1.MVC

2.Spring MVC

3. Using Spring MVC in Spring Boot

3.1. Configuration

3.1.1. File configuration

3.1.2. Code configuration

3.2. Use

3.2.1. Mapping Processors

3.2.2. Parameter passing

3.2.3. Parameter conversion

3.2.4. Data verification

3.2.5. Data Model

3.2.6. Views and resolvers

3.2.7. Interceptors


1.MVC

MVC is a common software design pattern used to separate different parts of an application to achieve loose coupling and high cohesion. The MVC pattern consists of three core components:

  • Model (Model): Represents the data and business logic of the application. The model processes the data of the application and performs corresponding actions according to the instructions of the controller.

  • View (View): Provides a user interface for model data. Views are usually templates, HTML pages, XML files, or other formats that present model data to the user.

  • Controller: Handles user interaction and updates models and views. The controller is responsible for receiving user input from the view, acting on the model accordingly, and updating the view to reflect the changes.

The advantage of the MVC pattern is that it can separate the code into three independent components, making the application easier to maintain and expand. For example, if you want to change the appearance of a view, you can modify the view without affecting the model and controller; if you want to change how data is stored, you can modify the model without affecting the view and controller. At the same time, the MVC pattern also helps to reduce the degree of coupling in the application, making each component more independent and reusable.

2.Spring MVC

The flow of a request processing in the MVC architecture under the Spring system is as follows:

The request is sent to the controller (controller), and after being processed by the business model (model), the response is returned to the recognition layer.

What did Spring MVC do in the whole process:

The core of the entire Spring MVC is DispatcherServlet, and around DispatcherServlet SpringMVC provides a set of components to cooperate with DispatcherServlet to complete the entire workflow.

DispatcherServlet first receives the request, maps the request to the corresponding processor (controller), and triggers the interceptor when it is mapped to the controller; after the processor finishes processing, it encapsulates the data model and hands it to the view parser to parse the data model into the corresponding The view is returned to the front end.

Of course, sometimes the above process will not be completed. For example, when using @RestController or @ResponseBody, because the response is returned directly, it will not jump to recognize the image, so the view parser will not be used.

3. Using Spring MVC in Spring Boot

3.1. Configuration

Because of the existence of Spring Boot's automatic assembly mechanism, generally speaking, we don't need to configure Spring MVC. If you want to make a special customized configuration, Spring Boot also supports configuration files or two ways of writing code to configure.

3.1.1. File configuration

# Enable Spring MVC
spring.mvc.enabled=true

# Configure static resource path
spring.mvc.static-path-pattern=/static/**
spring.resources.static-locations=classpath:/static/

# Configure view parser
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

# Configure HTTP cache
spring.resources.cache.period=3600

# Configuration file upload
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB

# Deployment JSON serialization
spring.jackson.serialization.indent_output=true
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss

# Configure exception handling
server.error.whitelabel.enabled=false

# Configure the interceptor
spring.mvc.interceptor.exclude-path-patterns=/login,/logout
spring.mvc.interceptor.include-path-patterns=/admin/**

# Configure session management
server.session.timeout=1800
server.session.cookie.max-age=1800

3.1.2. Code configuration

@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {

    // 配置视图解析器
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        registry.viewResolver(resolver);
    }

    // 配置静态资源
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("/static/");
    }

    // 配置拦截器
    @Autowired
    private MyInterceptor myInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor).addPathPatterns("/**");
    }

    // 配置消息转换器
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        List<MediaType> supportedMediaTypes = new ArrayList<MediaType>();
        supportedMediaTypes.add(MediaType.APPLICATION_JSON);
        converter.setSupportedMediaTypes(supportedMediaTypes);
        converters.add(converter);
    }

    // 配置异常处理器
    @ControllerAdvice
    public class GlobalExceptionHandler {
        @ExceptionHandler(value = Exception.class)
        public ModelAndView handleException(HttpServletRequest req, Exception e) {
            ModelAndView mav = new ModelAndView();
            mav.addObject("exception", e);
            mav.addObject("url", req.getRequestURL());
            mav.setViewName("error");
            return mav;
        }
    }

    // 配置跨域资源共享(CORS)
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**").allowedOrigins("http://localhost:8080");
    }

    // 配置文件上传
    @Bean
    public MultipartResolver multipartResolver() {
        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        resolver.setMaxUploadSize(10485760);
        resolver.setMaxInMemorySize(4096);
        return resolver;
    }

    // 配置请求缓存
    @Bean
    public KeyGenerator keyGenerator() {
        return new DefaultKeyGenerator();
    }

    @Bean
    public RequestCache requestCache() {
        return new HttpSessionRequestCache();
    }

    // 配置视图控制器
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/login").setViewName("login");
    }
}

3.2. Use

3.2.1. Mapping Processors

Only @RequestMapping is introduced here, and @GETMapping is similar to @PostMapping.

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
	
    String name() default "";
    
    @AliasFor("path")
    String[] value() default {};
	
    @AliasFor("value")
    String[] path() default {};

    RequestMethod[] method() default {};

    String[] params() default {};

    String[] headers() default {};

    String[] consumes() default {};

    String[] produces() default {};
}

The function of each parameter is as follows:

  1. value and path: used to specify the URL path of the request, placeholders and regular expressions can be used.

  2. method: Specifies the HTTP request method, which can be GET, POST, PUT, DELETE, etc.

  3. params: Specifies the conditions of request parameters, supports expressions, multiple parameters and logical operations.

  4. headers: specifies the conditions of the request header, supports expressions, multiple headers, and logical operations.

  5. consumes: Specifies the MIME type of the request, which is used to limit the request content type.

  6. produces: Specifies the MIME type of the response, which is used to limit the response content type.

  7. name: Specifies the name of the request parameter, which is used to automatically bind the parameter value.

  8. defaultValue: Specifies the default value of the request parameter.

  9. pathVariable: Used to bind placeholders in the URL path.

  10. required: Specifies whether the request parameter is required.

  11. The value, method, params, headers, consumes and produces attributes all support array form and can match multiple conditions.

3.2.2. Parameter passing

1. Match by parameter name

@Controller
@RequestMapping("/user")
public class UserController {
    
    @RequestMapping("/info")
    public String getUserInfo(Integer userId, Model model) {
        // 根据用户ID查询用户信息并返回
        User user = userService.getUserById(userId);
        model.addAttribute("user", user);
        return "user_info";
    }
}

URL:

ip:port/info?userId=1

2.@RequestParam

The matching parameters can be specified through the @RequestParam annotation.

@Controller
@RequestMapping("/user")
public class UserController {
    
    @RequestMapping(value = "/search", method = RequestMethod.GET, params = "keyword")
    public String searchUser(@RequestParam("keyword") String keyword, Model model) {
        // 根据关键词查询用户信息并返回
        List<User> userList = userService.searchUser(keyword);
        model.addAttribute("userList", userList);
        return "user_list";
    }
}

3. Pass the array

@RequestMapping("/delete")
public String deleteUsers(int[] userIds, Model model) {
    // 根据用户ID数组删除多个用户,并返回用户列表页面
    userService.deleteUsers(userIds);
    List<User> userList = userService.getUserList();
    model.addAttribute("userList", userList);
    return "user_list";
}

4. Pass JSON

Only the POST method can be used to pass JSON. Use @ResponseBody to annotate the parameters in the parameter list to receive JSON. If the annotated parameter is an object, JSON will be automatically converted into an object.

@RequestMapping(value = "/save", method = RequestMethod.POST)
@ResponseBody
public Map<String, Object> saveUser(@RequestBody User user) {
    // 保存用户信息,并返回成功的响应
    userService.saveUser(user);
    return Collections.singletonMap("success", true);
}

Note that when passing parameters, set contentType: "application/json"

5.Restful

@Controller
@RequestMapping("/user")
public class UserController {
    
    @RequestMapping("/info/{id}")
    public String getUserInfo(@PathVariable("id") Integer userId, Model model) {
        // 根据用户ID查询用户信息并返回
        User user = userService.getUserById(userId);
        model.addAttribute("user", user);
        return "user_info";
    }
}

The frontend URL is:

ip:port/info/1

3.2.3. Parameter conversion

When the parameter list of the backend interface is an object type, Spring MVC will automatically complete the conversion and filling of parameters according to the parameter name. Of course, this conversion rule can also be defined by ourselves. Spring MVC has prepared a conversion interface for us. The following is a Full example:

Entity object:

public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
    // 省略 getter 和 setter 方法
}

Parameter converter:

public class UserConverter implements Converter<String, User> {

    @Override
    public User convert(String source) {
        // 将请求参数解析为User对象
        String[] values = source.split(",");
        User user = new User();
        user.setId(Long.parseLong(values[0]));
        user.setName(values[1]);
        user.setAge(Integer.parseInt(values[2]));
        user.setEmail(values[3]);
        return user;
    }
}

Register parameter converters:

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new UserConverter());
    }
}

When passing parameters of the corresponding type in the future, our custom conversion rules will be used for conversion:

@RequestMapping(value = "/save", method = RequestMethod.POST)
@ResponseBody
public Map<String, Object> saveUser(User user) {
    // 保存用户信息,并返回成功的响应
    userService.saveUser(user);
    return Collections.singletonMap("success", true);
}

3.2.4. Data verification

Sometimes we hope that the parameters passed by the front end meet a certain format. Spring MVC also takes this into consideration and provides us with an annotation-based parameter verification function.

public class User {
    @NotNull(message = "id不能为空")
    private Long id;

    @NotBlank(message = "name不能为空")
    private String name;

    @Min(value = 0, message = "age不能小于0")
    @Max(value = 150, message = "age不能大于150")
    private Integer age;

    @Email(message = "email格式不正确")
    private String email;

    // 省略 getter 和 setter 方法
}

Just using annotations, the verification will not take effect, and you need to add @Validated to enable verification where you want to verify:

@RestController
@RequestMapping("/user")
public class UserController {

    @PostMapping("/save")
    public Map<String, Object> saveUser(@Validated @RequestBody User user, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            // 参数校验失败,返回错误信息
            List<ObjectError> errors = bindingResult.getAllErrors();
            List<String> errorMessages = new ArrayList<>();
            for (ObjectError error : errors) {
                errorMessages.add(error.getDefaultMessage());
            }
            return Collections.singletonMap("success", false, "errors", errorMessages);
        }

        // 保存用户信息,并返回成功的响应
        userService.saveUser(user);
        return Collections.singletonMap("success", true);
    }
}

3.2.5. Data Model

The data model in Spring MVC is used to pass data between the processor method (Controller) and the view. There are three types:

  • Model

  • ModelMap

  • ModelAndView

Model:

Can only carry parameters

@GetMapping("/hello")
public String hello(Model model) {
    model.addAttribute("message", "Hello, world!");
    return "hello";
}

ModelMap:

Similar to the Model function.

@GetMapping("/hello")
public String hello(ModelMap model) {
    model.put("message", "Hello, world!");
    return "hello";
}

ModelAndView:

Can carry both parameters and view names.

@GetMapping("/hello")
public ModelAndView hello() {
    ModelAndView mav = new ModelAndView("hello");
    mav.addObject("message", "Hello, world!");
    return mav;
}

3.2.6. Views and resolvers

1. view

The view of Spring MVC can be understood as what is finally returned to the front end, which can be divided into two categories:

  • logical view

  • illogical view

Logical view:

Logical view refers to a string, which represents the logical name of a view, decoupled from the actual view, but mapped to the actual view by the view resolver. In Spring MVC, the processor method can return the logical view name, which is mapped to the actual view by the DispatcherServlet according to the configuration of the view resolver.

Commonly used logical views include:

  • JSP Views: Use the InternalResourceViewResolver view resolver to map logical view names to JSP file names.

  • Velocity Views: Use the VelocityViewResolver view resolver to map logical view names to Velocity template file names.

  • Thymeleaf views: use the ThymeleafViewResolver view resolver, which maps logical view names to Thymeleaf template file names.

illogical view:

A non-logical view refers to a specific view implementation, usually a view class or a RESTful Web Service. In the handler method, you can directly return a non-logical view, which will be rendered directly without conversion through the view resolver.

Commonly used illogical views include:

  • JSON view: use the MappingJackson2JsonView view to convert the model data into JSON format and return it to the client.

  • XML view: use the MappingJackson2XmlView view to convert the model data into XML format and return it to the client.

  • PDF View: Implemented using iText PDF library and AbstractPdfView view, convert model data into PDF format and return to the client.

It should be noted that non-logical views usually require additional configuration and processing. For example, JSON views need to add the Jackson dependency library, and configure the MappingJackson2JsonView view resolver in the Spring configuration file.

2. View resolver

The view resolver determines what type of view the return of @Controller is mapped to. The default is to use the InternalResourceViewResolver view resolver, which is the JSP view resolver. When we configure the prefix and suffix, it will automatically map the return of @Controller Go to the corresponding jsp.

spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

Of course, Spring Boot also supports us to switch the view parser. The following is an example of switching to the JSON view parser. After switching to the JSON view parser, return will directly return JSON to the front end:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    // 重写configureViewResolvers方法,配置视图解析器
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        // 使用视图解析器注册表启用内容协商,并指定MappingJackson2JsonView作为视图实现类
        registry.enableContentNegotiation(new MappingJackson2JsonView());
    }
}

3.2.7. Interceptors

The code for using the custom Spring MVC interceptor chain in Spring Boot is as follows:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new FirstInterceptor());
        registry.addInterceptor(new SecondInterceptor());
    }
}

public class FirstInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // 在处理器处理请求之前执行
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        // 在处理器处理请求之后,渲染视图之前执行
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) throws Exception {
        // 在渲染视图之后执行
    }
}

public class SecondInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // 在处理器处理请求之前执行
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        // 在处理器处理请求之后,渲染视图之前执行
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) throws Exception {
        // 在渲染视图之后执行
    }
}

Guess you like

Origin blog.csdn.net/Joker_ZJN/article/details/130095326