Spring MVC

主要组件

  • HttpServletBean 是spring对HttpServlet简单扩展包含多环境的操作
  • FrameworkServlet 实现了ApplicationContextAware,所以包含了上下文WebApplicationContext
  • DispatcherServlet HTTP请求处理程序/控制器的中央调度程序,有自身的组件处理请求
    在这里插入图片描述

DispatcherServlet 组件

组件描述
Handler处理器,也就是controller层,可以是类,也可以是方法,只要是有@RequestMapping注解的
HandlerMapping根据请求,找到对应的Handler
HandlerAdapter适配器,将Servlet中的Request和Response转换为Handler 处理的形式
HandlerExceptionResolver异常处理的组件
LocaleResolver从Request中解析Locale
ViewResolver解析视图,将视图名(Handler返回)和Locale(LocaleResolver 获得)转换成View
RequestToViewNameTranslator如果用户未提供View或视图名称,则配置的RequestToViewNameTranslator将当前请求转换为视图名称
ThemeResolver解析主题的组件
MultipartResolver文件上传组件,将文件转换为MultipartFile并封装到MultipartHttpServletRequest
FlashMapManager用来管理FlashMap的,FlashMap主要用在redirect中传递参数
	/**
	 * Initialize the strategy objects that this servlet uses.
	 * DispatcherServlet 从应用程序上下文(ApplicationContext )中加载自身使用的组件
	 * <p>May be overridden in subclasses in order to initialize further strategyobjects.
	 */
	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}

请求处理流程

在这里插入图片描述

  1. 发送请求到DispatchServlet(中央控制器)
  2. DispatcherServlet(中央控制器)调用HandlerMapping(处理器映射器)根据请求url找到需要执行的处理器(此处做了简化实际返回的是执行链)
  3. DispatcherServlet(中央控制器)通过HandlerAdapter(处理器适配器)调用处理器
  4. 执行处理器,返回ModelAndView给中央控制器
  5. 中央控制器调用ViewResolver(视图解析器)根据处理器返回的ModelAndView中的逻辑视图名为中央控制器返回一个可用的view实例
  6. 中央控制器根据View渲染视图(将模型填充到视图),并响应给用户

自定义设置

实现WebMvcConfigurer 可以覆盖默认的设置。会让配置文件中关于MVC的配置失效。

package com.example.demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
public class SpringMVCConfig implements WebMvcConfigurer {
}

自定义入参转换

    /**
     * 入参转换
     *
     * @param registry 对象
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {

        // 不能替换为lambda表达式 无法类型推断
        // 将“2021-01-20 12:00:00”格式装换为LocalDateTime
        registry.addConverter(new Converter<String, LocalDateTime>() {
            @Override
            public LocalDateTime convert(String source) {
                return LocalDateTime.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            }
        });
    }

返回值包装

实现ResponseBodyAdvice<Object> 和注解@RestControllerAdvice 对所有返回值增加一层包装

package com.example.demo.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import com.example.demo.domain.Result;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectWriter;


/**
 * 处理解析 {@link ResponseBodyAdvice} 统一返回包装器
 *
 * @author 刘斌
 */
@RestControllerAdvice
public class GlobalResponseBodyHandler implements ResponseBodyAdvice<Object> {

    private static final Logger LOGGER = LoggerFactory.getLogger(GlobalResponseBodyHandler.class);

    @Autowired
    private ObjectWriter objectWriter;


    @Override
    public boolean supports(@Nullable MethodParameter returnType,
                            @Nullable Class<? extends HttpMessageConverter<?>> converterType) {

        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body,
                                  @Nullable MethodParameter returnType,
                                  @Nullable MediaType selectedContentType,
                                  @Nullable Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  @Nullable ServerHttpRequest request,
                                  @Nullable ServerHttpResponse response) {

        try {
            LOGGER.info(objectWriter.writeValueAsString(body));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        //返回值为空
        if (body == null) {
            return new Result();
        }
        //返回值为result
        if (body instanceof Result) {
            return body;
        }
        // 将方法原本的返回值设置到obj中
        final Result result = new Result();
        result.setObj(body);
        return result;
    }

}

成功在Controller返回值上包装了一层通用返回值
在这里插入图片描述

返回值转换

将上图中LocalDateTime转换成字符串格式。还是在SpringMVCConfig中重写configureMessageConverters方法

    /**
     * jackSon 的 ObjectMapper
     *
     * @return ObjectMapper
     */
    @Bean("myObjectMapper")
    public ObjectMapper objectMapper() {
        // 序列化设置
        final ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        objectMapper.setTimeZone(TimeZone.getDefault());
        // 序列换成json时,将所有的long变成string
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        // 日期序列化设置
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(
                "yyyy-MM-dd HH:mm:ss")));
        objectMapper.registerModule(simpleModule)
                    .registerModule(javaTimeModule);
        return objectMapper;
    }
    /**
     * 自定义的ObjectMapper 的转换器
     */
    @Autowired
    @Qualifier("myObjectMapper")
    private ObjectMapper objectMapper;

    /**
     * jackson json 转换器
     *
     * @return 对象
     */
    public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter() {
        MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
        jsonConverter.setObjectMapper(objectMapper);
        return jsonConverter;
    }
    /**
     * 全局的消息转换
     *
     * @param converters 集合
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {

        converters.add(customJackson2HttpMessageConverter());
    }

在这里插入图片描述

统一异常处理

通过@RestControllerAdvice注解,捕获Controller中的异常
-@ExceptionHandler 捕获的异常类型。抛出的RuntimeException会被handleRuntimeException方法处理。最小范围捕获
-@ResponseStatus 设置响应的状态

package com.example.demo.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import com.example.demo.domain.Result;


/**
 * 全局异常捕获。
 *
 * @author liubin
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger LOGGER =
            LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 全局异常捕获。
     *
     * @param exception 异常。
     * @return re
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result handleException(Exception exception) {
        final Result result = new Result();
        LOGGER.error("ApiException 异常抛出", exception);
        result.setSucceeded(false);
        result.setMsg("服务器崩溃了....");
        return result;
    }
    /**
     * 全局RuntimeException 异常捕获。
     *
     * @param exception 异常。
     * @return re
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result handleRuntimeException(RuntimeException exception) {
        final Result result = new Result();
        LOGGER.error("ApiException RuntimeException 异常抛出", exception);
        result.setSucceeded(false);
        result.setMsg("RuntimeException 服务器崩溃了....");
        return result;
    }

}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值