SpringBoot知识点一
1.前言
本章主要讲解一些在开发中常用的技术:过滤器、拦截器、消息转换器和 ResponseBodyAdvice,这几个部分都能修改返回值,我觉得有相同的地方。
(1)关于过滤器和拦截器的区别,spring boot 过滤器、拦截器的区别与使用 这篇文章写的很清楚了。主要有以下几个不同:
- 使用范围不同
- 规范不同
- 使用的资源不同
- 深度不同
(2)实现了 ResponseBodyAdvice 这个接口的类,处理返回的json值在传递给HttpMessageConverter之前
【1】.解决Spring Boot 拦截器注入service为空的问题 (这里有两个地方,一个是拦截器上加入@Compent注解,一个是WebMvcConfigurer配置中用@Bean注入拦截器)
【2】.SpringBoot统一响应,拦截Response返回 ResponseBodyAdvice接口
2.拦截器
(1) 编写拦截器
(2) 注入拦截器,在SpringMVC中的 Interceptor拦截器才用实现 HandlerInterceptor的方式,实现其中的三个方法。
preHandle():
该方法在请求处理之前执行,SpringMVC 中的Interceptor 是链式的调用的,在一个应用中或者说是在一个请求中可以同时存在多个Interceptor 。每个Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor 中的preHandle 方法。postHandle():
该方法在请求处理之后执行,但是他会在 DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的 ModeAndView 对象进行操作.需要注意的是,如果 Controller 执行过程中出现了异常,那么并不会执行该方法,而是执行 afterCompletion方法。afterCompletion():
在postHandle执行之后执行,发生异常也会执行,通常用于释放系统资源。
1 |
|
需要在WebMvcConfigurer 中注册。
【1】.Spring Boot 配置拦截器 这里可以参考
【2】.【springBoot】springBoot配置拦截器
【3】.springboot HandlerIntercepter拦截器实现修改request body数据
【4】.SpringBoot 拦截器中校验Json数据 为什么使用RequestBody只能读取一遍请求数据流?那是因为流对应的是数据,数据放在内存中,有的是部分放在内存中。read 一次标记一次当前位置(mark position),第二次read就从标记位置继续读(从内存中copy)数据。 所以这就是为什么读了一次第二次是空了。 怎么让它不为空呢?只要inputstream 中的pos 变成0就可以重写读取当前内存中的数据。javaAPI中有一个方法public void reset() 这个方法就是可以重置pos为起始位置,但是不是所有的IO读取流都可以调用该方法!ServletInputStream是不能调用reset方法,这就导致了只能调用一次getInputStream()。
问题
(1)拦截器不生效
我在测试拦截器的时候,出现了部分路径无法匹配的问题,后来我还是找到了解决方法。
1 |
|
1.SpringBoot添加Interceptor后addInterceptors方法不执行,拦截器不生效
2.Spring PathPattern-路径匹配器【超详细】 ** 只支持在模式的末尾,例如/pages/{ ** }是有效的,但是/pages/{**}/details是无效的。这同样适用于捕获变量{*spring}。目的是在比较模式的特异性时消除歧义。
3.spring mvc路径匹配原则 这里的匹配规则倒是挺多的。
4.过滤器和拦截器的路径匹配 这里是源码的讲解,倒是没有仔细的看了。
3.过滤器
1 |
|
1.SpringBoot 拦截并修改某个接口地址的返回值 这里用了一个过滤器进行了过滤,重写了 HttpServletResponseWrapper 方法,获取内容。
2.SpringBoot利用Filter获取请求数据request和修改返回response中的数据
4.ResponseBodyAdvice
在返回前端之前可以修改返回值,我使用了 jackson 的命名策略,使用 消息转换器,使用拦截器无法获取返回的内容,配置了过滤器,还没有实现,最后我通过 使用 ResponseBodyAdvice,更方便的解决了问题。
1 | package com.openmap.drone.configuration; |
实现了这个接口的类,处理返回的json值在传递给HttpMessageConverter之前。
【1】.spring boot postHandle处理返回结果 这篇文章错了,postHandle是在controller处理完成之后执行的,这里显示的是处理之前执行。
【2】.SpringBoot通过拦截器获取请求参数和返回结果进行操作 这里提到了 拦截器、过滤器,最后使用了 ResponseBodyAdvide 方法
【3】.SpringBoot利用Filter获取请求数据request和修改返回response中的数据 这里是用的过滤器,这个方法我还没有尝试过。
【4】.spring boot 拦截器 修改response 这篇文章提到了 ContentCachingResponseWrapper 这个包装器,但是我尝试之后报错了。
【5】.SpringBoot 拦截器中校验Json数据
【6】.SpringMVC进阶 - 利用@ControllerAdvice和ResponseBodyAdvice接口统一处理返回值
【7】.spring mvc之@ResponseBodyAdvice使用
5.消息转换器
除了上面的过滤器和拦截器之外,还有消息转换器可以进行返回值的处理。参考文章5写的挺明白的,使用转换器的时候,有下面的注意事项:
(1)系统有默认配置的消息转换器集合。
(2)处理过程会按集合顺序匹配合适的消息转换器,如果有合适的,就会使用该消息转换器处理(读、写),后续的消息转换器不再执行。
(3)自定义的消息转换器要想生效,必须放到集合中相同类型的消息转换器前面,原因参考第二点。
思考:既然自定义的消息转换器必须放到集合中相同类型的消息转换器前面,那是否能直接改动集合中原有的消息转换器来达到自定义的效果,而不必在加一个(暂未没研究)。
(4)添加自定义消息转换器时注意默认消息转换器是否生效
WebMvcConfigurer.configureMessageConverters方法会覆盖默认消息转换器集合
WebMvcConfigurer.extendMessageConverters方法不会覆盖默认消息转换器集合
我们继承了泛型类AbstractHttpMessageConverter,并重写了它的几个方法。
supports:设置处理哪些类。
readInternal:处理输入内容,即处理请求值。
writeInternal:处理输出内容,即处理返回值。
构造方法定义了要处理的MediaType。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53public class ResultMessageConverter extends AbstractHttpMessageConverter<Object> {
public ResultMessageConverter(){
super(new MediaType("application", "json", Charset.forName("UTF-8")));
}
protected boolean supports(Class<?> clazz) {
return HttpResultResponse.class.isAssignableFrom(clazz);
// return true;
}
protected void writeInternal(Object httpResultResponse, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
ObjectMapper objectMapper = new ObjectMapper();
//处理bigDecimal
objectMapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
objectMapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
//处理失败
objectMapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES, false);
//默认的处理日期时间格式
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
objectMapper.registerModule(javaTimeModule);
// 命名策略,下划线
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
// 执行消息转换
String dataStr=objectMapper.writeValueAsString(httpResultResponse);
byte[] bytes = dataStr.getBytes(StandardCharsets.UTF_8);
// 写入返回值
outputMessage.getBody().write(bytes);
}
protected Object readInternal(Class<? extends Object> clazz,
HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
String source = StreamUtils.copyToString(inputMessage.getBody(),Charset.forName("UTF-8"));
return new ObjectMapper().readValue(source, clazz);
}
}
1.SpringBoot 消息转换器 HttpMessageConverter
2.Spring Boot项目中如何定制HTTP消息转换器
3.SpringBoot 拦截器中校验Json数据
4.springboot HandlerIntercepter拦截器实现修改request body数据
5.SpringBoot消息转换器:HttpMessageConverter 消息转化器的作用;消息转化器的主要方法;默认配置的消息转化器;注意事项
6.Spring mvc 之 AbstractHttpMessageConverter 自定义Http消息转化器 只是类型为 text/html 为了解决该问题,可以指定Http的消息转化器,来解析
7.一步到位 SpringBoot 序列化与消息转换器 (你需要的这里都有) 序列化与反序列化;Jackson之ObjectMapper对象的使用;ObjectMapper常用API;配置ObjectMapper;添加自定义的消息转换器
8.自定义HttpMessageConverter 按这个写了。
9.Spring Boot之MessageConverter原理及自定义消息转换器 这个写了原理
10.【Spring】HttpMessageConverter的作用及替换
11.SpringMVC自定义消息转换器其实很简单