赞
踩
WebMvcConfigurer配置类是使用Java代码代替传统的xml配置文件,对SpirngMvc进行配置的一种方式,需要创建一个配置类@Configuration
并实现WebMvcConfigurer 接口
(推荐
)
继承WebMvcConfigurerAdapter类
来实现代码配置的。 SpringBoot 2.0 后,WebMvcConfigurerAdapter类被@Deprecated(弃用)
配置类继承WebMvcConfigurerAdapter类
@Configuration
public class WebMvcConfg extends WebMvcConfigurerAdapter{}
实现WebMvcConfigurer接口(推荐)
或者继承WebMvcConfigurationSupport类
来实现代码配置1.配置类实现WebMvcConfigurer接口
@Configuration
public class WebMvcConfg implements WebMvcConfigurer {}
2.配置类继承WebMvcConfigurationSupport
@Configuration
public class WebMvcConfg extends WebMvcConfigurationSupport {}
addInterceptor:需要一个实现HandlerInterceptor接口的拦截器实例
addPathPatterns:用于设置拦截器的过滤路径规则;- addPathPatterns(“/**”)对所有请求都拦截
excludePathPatterns:用于设置不需要拦截的过滤规则
拦截器主要用途:进行用户登录状态的拦截,日志的拦截等。
@Override
public void addInterceptors(InterceptorRegistry registry) {
super.addInterceptors(registry);
registry.addInterceptor(new TestInterceptor()).addPathPatterns(“/**”);
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*") //浏览器允许所有的域访问 / 注意 * 不能满足带有cookie的访问,Origin 必须是全匹配
.allowCredentials(true) // 允许带cookie访问
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("token")
.maxAge(3600);
}
内容协商:在 HTTP 协议中,内容协商是这样一种机制,通过为同一 URI 指向的资源提供不同的展现形式,可以使用户代理选择与用户需求相适应的最佳匹配
一个请求路径返回多种数据格式
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
/* 是否通过请求Url的扩展名来决定media type /
configurer.favorPathExtension(true)
/ 不检查Accept请求头 /
.ignoreAcceptHeader(true)
.parameterName(“mediaType”)
/ 设置默认的media yype /
.defaultContentType(MediaType.TEXT_HTML)
/ 请求以.html结尾的会被当成MediaType.TEXT_HTML*/
.mediaType(“html”, MediaType.TEXT_HTML)
/* 请求以.json结尾的会被当成MediaType.APPLICATION_JSON*/
.mediaType(“json”, MediaType.APPLICATION_JSON);
}
上面代码说白了就是告诉系统什么类型用什么来标识
以前写SpringMVC的时候,如果需要访问一个页面,必须要写Controller类,然后再写一个方法跳转到页面,感觉好麻烦,其实重写WebMvcConfigurer中的addViewControllers方法即可达到效果了
@Override
public void addViewControllers(ViewControllerRegistry registry) {
super.addViewControllers(registry);
registry.addViewController("/").setViewName("/index");
//实现一个请求到视图的映射,而无需书写controller
registry.addViewController("/login").setViewName("forward:/index.html");
}
/** * 视图配置 * @param registry */ @Override public void configureViewResolvers(ViewResolverRegistry registry) { super.configureViewResolvers(registry); registry.viewResolver(resourceViewResolver()); /*registry.jsp("/WEB-INF/jsp/",".jsp");*/ } /** * 配置请求视图映射 * @return */ @Bean public InternalResourceViewResolver resourceViewResolver() { InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver(); //请求视图文件的前缀地址 internalResourceViewResolver.setPrefix("/WEB-INF/jsp/"); //请求视图文件的后缀 internalResourceViewResolver.setSuffix(".jsp"); return internalResourceViewResolver; }
配置在接收request (请求)和返回response (响应)时的数据转换器
,最常用到的就是fastJson的转换,配置如下所示:
该方法会替换所有默认的MessageConverters,使用自定义添加converters,在实际项目中应用比例也比较小;
/** * 消息内容转换配置 */ @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { //StringHttpMessageConverter默认使用的字符集是ISO-8859-1,改为输出的JSON字符串为UTF-8字符集 converters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8)); //添加fastjson消息转换器 converters.add(fastJsonHttpMessageConverters()); } /** * 引入Fastjson解析json,不使用默认的jackson,必须在pom.xml引入fastjson的jar包,并且版必须大于1.2.10 * * @return */ @Bean public FastJsonHttpMessageConverter fastJsonHttpMessageConverters() { //1、定义一个convert转换消息的对象 FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); //2、添加fastjson的配置信息 FastJsonConfig fastJsonConfig = new FastJsonConfig(); SerializerFeature[] serializerFeatures = new SerializerFeature[]{ // 输出key是包含双引号 //SerializerFeature.QuoteFieldNames, // 是否输出为null的字段,若为null 则显示该字段 SerializerFeature.WriteMapNullValue, // 数值字段如果为null,则输出为0 SerializerFeature.WriteNullNumberAsZero, // List字段如果为null,输出为[],而非null SerializerFeature.WriteNullListAsEmpty, // 字符类型字段如果为null,输出为"",而非null SerializerFeature.WriteNullStringAsEmpty, // Boolean字段如果为null,输出为false,而非null SerializerFeature.WriteNullBooleanAsFalse, // Date的日期转换器 SerializerFeature.WriteDateUseDateFormat, // 循环引用(如果不配置有可能会进入死循环) SerializerFeature.DisableCircularReferenceDetect, // 格式化JSON SerializerFeature.PrettyFormat }; fastJsonConfig.setSerializerFeatures(serializerFeatures); fastJsonConfig.setCharset(Charset.forName("UTF-8")); //3.解决乱码问题。定义响应的MIME类型,设置响应的content-type为application/json;charset=UTF-8 List<MediaType> fastMediaType = new ArrayList<>(); fastMediaType.add(MediaType.valueOf(MediaType.APPLICATION_JSON_VALUE)); //4.converter消息转换器添加配置信息 fastConverter.setSupportedMediaTypes(fastMediaType); //5、在convert中添加配置信息 fastConverter.setFastJsonConfig(fastJsonConfig); return fastConverter; }
springboot2.0版本以后推荐使用extendMessageConverters
来进行web配置,这个方法不会覆盖springmvc已默认添加的HttpMessageConverter
即:在默认加载的消息转换器基础上
继续添加自定义的converters实例
@Override public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(customerMappingJackson2HttpMessageConverter()); converters.add(stringHttpMessageConverter()); converters.add(fastJsonHttpMessageConverters()); } @Bean public MappingJackson2HttpMessageConverter customerMappingJackson2HttpMessageConverter(){ MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter(); //设置日期格式 ObjectMapper objectMapper = new ObjectMapper(); SimpleDateFormat smt = new SimpleDateFormat("yyyy-MM-dd"); objectMapper.setDateFormat(smt); messageConverter.setObjectMapper(objectMapper); //设置中文编码格式 List<MediaType> list = new ArrayList<MediaType>(); list.add(MediaType.APPLICATION_JSON); messageConverter.setSupportedMediaTypes(list); return messageConverter; } @Bean public StringHttpMessageConverter stringHttpMessageConverter(){ StringHttpMessageConverter stringConvert = new StringHttpMessageConverter(); List<MediaType> stringMediaTypes = new ArrayList<MediaType>(){{ add(new MediaType("text","plain",Charset.forName("UTF-8"))); }}; stringConvert.setSupportedMediaTypes(stringMediaTypes); return stringConvert; } /** * 引入Fastjson解析json,不使用默认的jackson,必须在pom.xml引入fastjson的jar包,并且版必须大于1.2.10 * * @return */ @Bean public FastJsonHttpMessageConverter fastJsonHttpMessageConverters() { //1、定义一个convert转换消息的对象 FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); //2、添加fastjson的配置信息 FastJsonConfig fastJsonConfig = new FastJsonConfig(); SerializerFeature[] serializerFeatures = new SerializerFeature[]{ // 输出key是包含双引号 //SerializerFeature.QuoteFieldNames, // 是否输出为null的字段,若为null 则显示该字段 SerializerFeature.WriteMapNullValue, // 数值字段如果为null,则输出为0 SerializerFeature.WriteNullNumberAsZero, // List字段如果为null,输出为[],而非null SerializerFeature.WriteNullListAsEmpty, // 字符类型字段如果为null,输出为"",而非null SerializerFeature.WriteNullStringAsEmpty, // Boolean字段如果为null,输出为false,而非null SerializerFeature.WriteNullBooleanAsFalse, // Date的日期转换器 SerializerFeature.WriteDateUseDateFormat, // 循环引用(如果不配置有可能会进入死循环) SerializerFeature.DisableCircularReferenceDetect, // 格式化JSON SerializerFeature.PrettyFormat }; fastJsonConfig.setSerializerFeatures(serializerFeatures); fastJsonConfig.setCharset(Charset.forName("UTF-8")); //3.解决乱码问题。定义响应的MIME类型,设置响应的content-type为application/json;charset=UTF-8 List<MediaType> fastMediaType = new ArrayList<>(); fastMediaType.add(MediaType.valueOf(MediaType.APPLICATION_JSON_VALUE)); //4.converter消息转换器添加配置信息 fastConverter.setSupportedMediaTypes(fastMediaType); //5、在convert中添加配置信息 fastConverter.setFastJsonConfig(fastJsonConfig); return fastConverter; }
应用场景
空值处理
- 请求和返回的数据有很多空值,这些值有时候并没有实际意义,我们可以过滤掉和不返回,或设置成默认值。比如通过重写
getObjectMapper
方法,将返回结果的空值不进行序列化:
converters.add(0, new MappingJackson2HttpMessageConverter(){
@Override
public ObjectMapper getObjectMapper() {
super.getObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
return super.getObjectMapper();
}
}
XSS 脚本攻击
为了保证输入的数据更安全,防止 XSS 脚本攻击,我们可以添加自定义反序列化器
//对应无法直接返回String类型
converters.add(0, new MappingJackson2HttpMessageConverter(){
@Override
public ObjectMapper getObjectMapper() {
super.getObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
// XSS 脚本过滤
SimpleModule simpleModule = new SimpleModule();
simpleModule.addDeserializer(String.class, new StringXssDeserializer());
super.getObjectMapper().registerModule(simpleModule);
return super.getObjectMapper();
}
}
字符串
,当请求报文到java程序会被封装为一个ServletInputStream流
,供开发人员读取请求报文,响应报文则通过ServletOutputStream流
,来输出响应报文。一个字符串到java对象的转化问题
。这一过程,在SpringMVC是通过HttpMessageConverter
来解决的。一次请求报文和一次响应报文
,分别被抽象为一个请求消息HttpInputMessage
和一个响应消息HttpOutputMessage
。处理请求时,由合适的消息转换器将请求报文绑定为方法中的形参对象,在这里同一个对象就有可能出现多种不同的消息形式,如json、xml。同样响应请求也是同样道理。
(1)HttpInputMessage 将请求的信息先转为 InputStream 对象,InputStream 再由 HttpMessageConverter 转换为 SpringMVC 需要的java对象;
(2)SpringMVC 返回一个 java 对象, 并通过 HttpMessageConverter 转为响应信息,接着 HttpOutputMessage 将响应的信息转换为OutputStream,接着给出响应。
HttpMessageConverter接口源码:
简单说就是 HTTP request (请求)和response (响应)数据的转换器
public interface HttpMessageConverter<T> { //该方法指定转换器可以读取的对象类型,即转换器可将请求信息转换为clazz 类型的对象,同时指定支持的MIME类型(text/html、application/json) //用于判断接受什么类型的数据且 boolean canRead(Class<?> clazz, MediaType mediaType); //该方法指定类型转换器可以将clazz类型的对象写到相应流当中,响应流支持的媒体类型在mediaType中定义 boolean canWrite(Class<?> clazz, MediaType mediaType); //该方法返回当前转换器支持的媒体类型 List<MediaType> getSupportedMediaTypes(); //该方法将请求信息流转换为T类型的对象 T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException; //该方法将T类型的对象写到响应流当中,同时指定响应的媒体类型为contentType void write(T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException; }
通常实现HttpMessageConverter接口的转换器有以下几种:
ByteArrayHttpMessageConverter
: 负责读取二进制格式的数据和写出二进制格式的数据;StringHttpMessageConverter
: 负责读取字符串格式的数据和写出二进制格式的数据;ResourceHttpMessageConverter
:负责读取资源文件和写出资源文件数据;在SpringMVC / SpringBoot中
@ResponseBody
这类注解默认使用的是jackson来解析json
当用户发送请求后,@Requestbody 注解
会读取请求body中的数据,默认的请求转换器HttpMessageConverter通过获取请求头Header中的Content-Type来确认请求头的数据格式
,从而来为请求数据适配合适的转换器。
MappingJacksonHttpMessageConverter
@Responsebody注解
会启用HttpMessageConverter,通过检测Header中Accept属性
来适配的响应的转换器。1.自定义HttpMessageConverter
@Data @AllArgsConstructor public class UserEntity { private String name; private String address; } public class MyMessageConverter extends AbstractHttpMessageConverter<UserEntity> { /** * 当前消息转换器处理的 消息类型为 application/oyjp */ public MyMessageConverter() { // 新建一个我们自定义的媒体类型application/oyjp super(new MediaType("application", "oyjp", Charset.forName("UTF-8"))); } @Override protected boolean supports(Class<?> clazz) { // 表明只处理UserEntity类型的参数。 return UserEntity.class.isAssignableFrom(clazz); } /** * 重写readlntenal 方法,处理请求的数据。代码表明我们处理由“-”隔开的数据,并转成 UserEntity类型的对象。 */ @Override protected UserEntity readInternal(Class<? extends UserEntity> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { String temp = StreamUtils.copyToString(inputMessage.getBody(), Charset.forName("UTF-8")); String[] tempArr = temp.split("-"); return new UserEntity(tempArr[0],tempArr[1]); } /** * 重写writeInternal ,处理如何输出数据到response。 */ @Override protected void writeInternal(UserEntity userEntity, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { String out = "hello: " + userEntity.getName() + "-" + userEntity.getAddress(); outputMessage.getBody().write(out.getBytes()); } }
2.配置类中添加自定义的HttpMessageConverter
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
System.out.println(converters.size());
converters.add(myConverter());
}
@Bean
public MyMessageConverter myConverter() {
return new MyMessageConverter();
}
3.控制器使用
@RequestMapping(method = RequestMethod.POST, value = "/convert", produces = {"application/oyjp"})
public @ResponseBody UserEntity converter(@RequestBody UserEntity user) {
return user;
}
4.postman请求
- Content-Type设置为application/oyjp
- Controller方法使用@RequestBody修饰,表明以对象方式接受指定类型的数据
- postman设置请求参数
- 查看postman响应
当在使用SpringMVC做服务器数据接收时,尤其是在做Ajax请求的时候,尤其要注意contentType属性,和accepte 属性的设置
,在springmvc配置好相应的转换器。
HttpMessageConverter是这样转换数据的
类型转换HttpMessageConverter
addResoureHandler:请求静态资源的路径
addResourceLocations:静态资源存放位置,可以配置多个,按先后顺序查找
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//添加对swagger-ui的处理
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
//registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/static/");
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
Convert,GenericConvert和Formatter接口的实现类的Bean
以下配置代码用于使用LocalDate,LocalTime ,LocalDateTime属性
接收前端传来的标准时间字符串,并返回指定的时间格式,LocalDate对应 yyyy-MM-dd
,LocalDateTime对应yyyy-MM-dd HH:mm:dd
,LocalTime对应 HH:mm:dd
,不论参数的形式传递如body、pathVariable、requestParam里,只要时间字符串满足格式要求都可以转为对应的时间日期属性。
@Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(localDateTimeConverter()); registry.addConverter(localDateConverter()); registry.addConverter(localTimeConverter()); } /** * LocalDate转换器,用于转换RequestParam和PathVariable参数 */ private Converter<String, LocalDate> localDateConverter() { return new Converter<String, LocalDate>() { @Override public LocalDate convert(String source) { if(!ObjectUtils.isEmpty(source)){ return LocalDate.parse(source, DateTimeFormatter.ofPattern(DateUtil.DATE_FORMAT_yyyy_MM_dd)); } return null ; } }; } /** * LocalDateTime转换器,用于转换RequestParam和PathVariable参数 */ private Converter<String, LocalDateTime> localDateTimeConverter() { return new Converter<String, LocalDateTime>() { @Override public LocalDateTime convert(String source) { if(!ObjectUtils.isEmpty(source)) { return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DateUtil.DATE_FORMAT_yyyy_MM_dd_HH_mm_ss)); } return null ; } }; } /** * LocalTime转换器,用于转换RequestParam和PathVariable参数 */ private Converter<String, LocalTime> localTimeConverter() { return new Converter<String, LocalTime>() { @Override public LocalTime convert(String source) { if(!ObjectUtils.isEmpty(source)) { return LocalTime.parse(source, DateTimeFormatter.ofPattern(DateUtil.DATE_FORMAT_HH_mm_ss)); } return null; } }; }
如果想为某个状态码
展示一个自定义的HTML错误页面,你需要将文件添加到/error文件夹下
。错误页面既可以是静态HTML
,也可以是使用模板构建的
,文件名必须是状态码
或一系列标签。
例如,映射404到一个静态HTML文件,你的目录结构可能如下:
src/
main/
java/
resources/
public/
error/
404.html
test/
使用FreeMarker模板映射所有5xx错误,你需要如下的目录结构:
src/
main/
java/
resources/
templates/
error/
5xx.ftl
test/
对于更复杂的映射,你可以添加实现ErrorViewResolver接口
的beans:
public class MyErrorViewResolver implements ErrorViewResolver {
@Override
public ModelAndView resolveErrorView(HttpServletRequest request,
HttpStatus status, Map<String, Object> model) {
// Use the request or status to optionally return a ModelAndView
return ...
}
}
也可以使用@ExceptionHandler方法
和@ControllerAdvice的ErrorController
将处理所有未处理的异常。
测试请求SpringBoot项目发生返回404状态时跳转到404页面
404页面
随便乱发起一个不存在的请求
测试请求SpringBoot项目发生返回500状态时跳转到500页面
500页面
请求一个报错接口
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。