##SpringBoot配置详解及相关原理解析
1.信息转换器
场景需求:某功能想前端返送请求,然后后端响应的数据是按自己业务要求来的格式,而不是springmvc默认的json,xml等数据。
1.自定义
- 创建自定义信息转换器
/**
* 自定义的MessageConverter(信息转换器)
* 实现多协议数据格式兼容:xml,json,x-xunmeng
* 1.@ResponseBody响应数据出去调用RequestResponseBodyMethondProcessor(返回值处理器)处理
* 2.processor处理方法返回值。通过MessageConverter处理
* 3.所有MessageConverter转换器合起来可以支持各种媒体类型数据的操作(读写)
* 4.内容协商最终找到MessageConverter
*/
public class XunmengMessageConverter implements HttpMessageConverter<User> {
@Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
return false;
}
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return clazz.isAssignableFrom(User.class);
}
/**
* 服务器需要统计所有MessageConverter都能写出哪些内容类型
*
* application/x-xunmeng
* @return
*/
@Override
public List<MediaType> getSupportedMediaTypes() {
return MediaType.parseMediaTypes("application/x-xunmeng");
}
@Override
public User read(Class<? extends User> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return null;
}
/**
* 自定义数据类型的写出
* @param user
* @param contentType
* @param outputMessage
* @throws IOException
* @throws HttpMessageNotWritableException
*/
@Override
public void write(User user, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
//自定义数据
String data=user.getName()+";"+user.getAge()+";"+user.getPet();
//写出数据
OutputStream body = outputMessage.getBody();
body.write(data.getBytes());
}
}
- 到配置文件中扩展信息转换器
@Configuration(proxyBeanMethods = false)//告诉SpringBoot这是一个配置类==配置文件
public class MyConfig {
//@ConditionalOnBean(name = "cat")//判断容器中是否含有cat组件,如果又就将user01组件放到容器中,反之,则不放入
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer() {
@Override//扩展信息转换器
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new XunmengMessageConverter());
}
};
}
}
2.参数内容协商管理器
- 在1.2中加上
@Override//重新书写内容协商策略
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
Map<String, MediaType> maptypes=new HashMap<>();
//指定哪些参数对应哪些媒体型
maptypes.put("json",MediaType.APPLICATION_JSON);
maptypes.put("xml",MediaType.APPLICATION_XML);
maptypes.put("xunmeng",MediaType.parseMediaType("application/x-xunmeng"));
//创建参数内容协商管理器
ParameterContentNegotiationStrategy parameterContentNegotiationStrategy = new ParameterContentNegotiationStrategy(maptypes);
//创建表头内容协商管理器
HeaderContentNegotiationStrategy headerContentNegotiationStrategy = new HeaderContentNegotiationStrategy();
configurer.strategies(Arrays.asList(parameterContentNegotiationStrategy,headerContentNegotiationStrategy));//设置内容协商管理器
}
- 注意:要使用参数内容协商管理器要到配置文件中加上
#开启请求参数内容协商模式
spring:
mvc:
contentnegotiation:
favor-parameter: true
3.总结
数据响应方式:
①@ResponseBody响应数据出去调用RequestResponseBodyMethondProcessor(返回值处理器)处理
②内容协商处策略判断是参数策略还是表头策略,一般如果有参数format按参数策略
③根据相关策略获取相关协商管理器
④协商管理器根据参数类型或者表头所标识的数据类型获取信息转换器
⑤信息转换器将数据处理成对应的类型数据
⑤返回数据。
2.自定义类型转换器
场景需求:当前端将数据以表单数据提交给后端时,对数据进行特定的封装
<form action="/typetotype" method="post">
<input type="text" value="刘腾" name="name"><br>
<input type="text" value="19" name="age"><br>
<input type="text" value="阿猫,阿狗" name="pet"><br>
<input type="submit" value="提交"><br>
</form>
当这个表单数据提交给下面这个映射方法时
@PostMapping("/typetotype")
public User typetotype(User user){
return user;
}
由于属性pet是一个对象,所以普通的springboot对其不能封装,比如我要把我的pet里面的pet.name属性设置成阿猫,那么只能我们自定义封装类型转换器,将字符串封装成Pet
- 配置自定义类型转换器
@Configuration(proxyBeanMethods = false)//告诉SpringBoot这是一个配置类==配置文件
public class MyConfig {
//@ConditionalOnBean(name = "cat")//判断容器中是否含有cat组件,如果又就将user01组件放到容器中,反之,则不放入
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer() {
@Override//自定义类型转换器
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new Converter<String, Pet>() {
@Override
public Pet convert(String source) {
Pet pet = new Pet();
//对自负串进行处理
String[] split = source.split(",");
pet.setName(split[0]);
return pet;
}
});
}
};
}
}
3.矩阵变量
- 矩阵变量必须要有url路径变量才能被解析
- 开启矩阵变量
public class MyConfig {
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer() {
@Override//处理矩阵变量开启
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
};
}
}
4.静态资源设置
spring:
mvc:
# #静态资源路径设置
static-path-pattern: /res/**
web:
#静态资源映射路径
resources:
static-locations: classpath:/public/
5.拦截器
- 作用:当用户向服务端某个目标路径发送请求时,由于请求数据中不一定
有我们想要的或者目标数据需要进行处理再发送给目标路径。比如用
户登录,只需要判断该有没有用户登录过,如果登录过就可以进入主页面。 - 实现步骤:
- 自定义一个拦截器,该类要实现HandlerInterceptor接口
- 将该拦截器加入到springboot加入到容器中
- 实践代码
- 创建一个拦截器
public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //当请求还未到达目标访问路径之前,先判断用户名是否存在 HttpSession session = request.getSession(); User user = (User)session.getAttribute("user"); if (user!=null){ return true; }else { request.setAttribute("msg","请重新登录!"); request.getRequestDispatcher("/login").forward(request,response); return false; } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { //响应数据但还未到达目标路径之前时执行。 System.out.println("postHandle方法执行了。。。"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("所有数据加载完了,afterCompletion方法执行"); } }
- 将拦截器加入容器
@Configuration(proxyBeanMethods = false) public class myconfig { @Bean public WebMvcConfigurer webMvcConfigurer(){ return new WebMvcConfigurer() { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .addPathPatterns("/**") .excludePathPatterns("/css/**","/fonts/**","/images/**","/js/**","/","/login"); } }; } }
- 拦截器原理
1.根据当前请求,找到HandlerExecutionChain【可以处理请求的handler以及handler的所有拦截器】
2.先来顺序执行所有拦截器的preHandle方法
* 1.如果当前拦截器prehandler返回true。则执行下一个拦截器的preHandle
* 2.如果当前拦截器返回为false。直接倒序执行所有已经执行了拦截器afterCompletion;
3.如果任何一个拦截器返回false。直接跳出不执行目标方法
4.所有拦截器都返回True。执行目标方法。
5.倒序执行所有拦截器的postHandle方法。
6.前面的步骤有任何异常都会直接触发afterComptetion。
7.页面成功渲染完成以后,也会倒序触发afterCOmpletion。