每日金句
专注和简单一直是我的秘诀之一。简单可能比复杂更难做到:你必须努力理清思路,从而使其变得简单。但最终这是值得的,因为一旦你做到了,便可以创造奇迹。——源自乔布斯
题记
前两天有点忙,没有连续更新,今天接着聊。金句里老乔的话说得多好,但能真正做到的人又有多少?至少就我个人而言,我还远远没有做到这样,只是一个在朝着这个方向努力的人,力求简明易懂,用大白话让人快速的明白理解,简单的例子上手,让使用的人更多的去实战使用扩展,折腾记即是对自己学习使用很好的一次总结,对看的人也是一个参考的方法,希望大家能够找到对自己有用的思路或方法。今天主要说的是,继续上一章的配置,我们自己如何自定义类型安全的配置,并使用一个常用的工具fastjson集成来切入,虽然有自定义的jacson和gson,折腾记就是要折腾一下嘛,不然怎么能打开新思路。
类型安全的配置
在上一篇文章中,我们有使用过直接在application.properties中设置变量,这种方式是Spring中常用的方式,但对Spring Boot来说,既不是安全的,也会因为频繁使用@Value来注入配置而过于繁琐,项目中使用起来尤其麻烦,真实项目中的变量就不像我演示的Demo里的只有一两行了,很多时候都会是几十行上百行,所以,Spring Boot中提供了基于类型安全的配置方式,通过@ConfigurationProperties将properties属性和一个Bean及其属性关联,从而实现类型安全的配置。
实战1——自定义的配置通过类似Service的方式注入是使用
项目使用:boot_properties
1、创建Bean。
// TestInfoSettings.class
@Component
@ConfigurationProperties( //1
prefix = "usetest",
locations = "classpath:config/app.properties"
)
public class TestInfoSettings {
private String name;
private String age;
//省略get、set
}
说明:
1:@ConfigurationProperties加载properties文件内的配置,prefix属性指定配置的前缀,例如:usetest.*=string 。locations可以指定自定义的文件位置,不指定默认使用application.properties。
2、在src/main/resources下新增config/app.properties。
usetest.name=mickjoust
usetest.age=18
3、在Controller里添加一个接口调用.
//TestController.class
...原有省略
@RequestMapping("/showSetting")
public Object showSetting(){
StringBuffer sb = new StringBuffer();
sb.append("setting name is : ").append(testInfoSettings.getName());
sb.append("setting age is : ").append(testInfoSettings.getAge());
sb.append("all is : ").append(testInfoSettings);
return JsonResp.success(sb);
}
4、启动,设置的数据注入进去了。
Spring Boot里的Spring MVC配置
用惯了Spring MVC,突然用Spring Boot反而会觉得很不习惯,因为很多配置消失了。简单不是说配置都没有了,而是Spring Boot通过某种方式帮助你快速的完成了一些前期的工作,上一章里说过,Spring Boot的一大特性就是自动配置并采用了条件注解@Conditional的方式自动扫描并开启你配置的功能,二是对于MVC里的viewResolver、interceptors、静态资源、formatter和converter、HttpMessageConverts、Servlet、Filter、Listener等,Spring Boot使用了一个叫WebMvcAutoConfiguration和WebMvcProperties的文件来进行自动配置,如图路径下:
接下来我们看看一般都有哪些自动配置
自动配置的静态资源
在原有的Spring MVC的配置,静态资源通常是这样配置的。
<mvc:default-servlet-handler />
<mvc:resources location="/static/" mapping="/static/**" cache-period="864000" />
在Spring Boot里是在方法addResourceHandlers中来定义静态资源的配置的。其实,就是一个if-else(有兴趣的同学自行看看源码),概括起来包含两类:
1、类路径文件
把类路径下的/static、/public、/resources和/META-INF/resources文件夹下的静态文件直接映射为/**来提供访问。
2、webjar
把webjar的/META-INF/resources/webjars下的静态文件映射为/webjar/**。
什么是webjar?就是有人帮我们将常用的前端脚本框架之类封装在jar包里,然后通过jar包的方式来调用脚本,详细的可以看网站:http://www.webjar.org
最后,如果我们要修改静态路径的映射并增加缓存时间,只需要在配置文件修改static-path-pattern和cache-period:
spring.mvc.static-path-pattern=/static/**
spring.resources.cache-period=864000
至于静态文件的存放路径,因为一般常用的静态文件都是放在这几个目录下的,基本上可以满足要求了,如果要自定义,修改spring.resources.static-locations=即可。
自动配置Formatter和Converter
搜索Formatter,就能够找到addFormatters这个方法里的定义,我们只需要定义Converter、GenericConverter和Formatter接口实现的实现类Bean,就会注册Bean到Spring MVC中了。比较简单,不再举例子了。
自动配置HttpMessageConverters
同理,搜索MessageConverters,会找到configureMessageConverters,这个方法就是直接添加HttpMessageConverters的Bean,而这个Bean是在HttpMessageConvertAutoConfiguration类中定义的,源码如下:
比较简单,就是加入定义好的converter,其中,默认加载的有以下八类:
有同学要问StringHttpMessageConverter为什么有两个,其实只是字符集使用了一个UTF-8和一个ISO-8859-1。还有默认goson的convert为啥没有看到呢,本章后面会说到原因。
自动配置的ViewResolver
同样道理,搜索ViewResolver,会搜索到三个: InternalResourceViewResolver、BeanNameViewResolver、ContentNegotiatingViewResolver。
【1】ContentNegotiatingViewResolver
Spring MVC里提供的特殊的ViewResolver,它自己是不处理View的,它的作用是代理给不同的ViewResolver来处理不同的View。源码如下:
【2】InternalResourceViewResolver
这个是内置最常用的解析器,通过设置前缀,后缀和controller中方法来返回视图名的字符串,以此来得到实际页面。源码如下:
它是通过配置文件获取前后缀的,设置参数如下:
spring.mvc.view.prefix=
spring.mvc.view.suffix=
【3】BeanNameViewResolver
定义很简单,作用就是它会去查找Controller方法返回值的字符串中是否有定义过的Bean名称,如果有,则用定义的View来渲染。
例如:我们定义一个Bean叫testView,返回类型是MappingJackson2JsonView,只要在@Controller返回的方法中返回,就可以获得指定的视图渲染。
return "testView";
对于视图,这里多说一句,不同的人有不同的喜好和习惯,有的项目喜欢直接前后分离,有的项目需要返回一些视图模板渲染基本的框架,怎么用顺手怎么用,没有好坏优劣之分,只有使用的场景不同,用得好,视图一样能发挥作用。
上面只是简单说明了一些常用的自动配置,至于更多更详细的配置,大家抽空可以看看自动配置的相关源码,对思路扩展也是有好处的。因为如果只想快速应用,通常的常用配置已经够用了,对于需要自定义的应用场景里,可自行参看配置修改。
扩展Spring MVC配置
上面大概介绍了Spring Boot里对MVC的自动配置,其实,大家可以对照着原有MVC的配置查看Spring Boot都有哪些配置项,你会发现其实都是原来已经有的,现在只是换了一种方式:通过配置或重写方法来达到修改或增加Spring MVC的配置。下面用一个例子来说明接管Spring Boot的Spring MVC的配置的方式并通过修改的方式来配置一个fastjson的converter。
如何定制Boot里的MVC配置?
在又需要默认的配置,又需要自己定制的配置的时候,我们需要自定义配置,Spring Boot官方提供了一个适配器类WebMvcConfigurerAdapter来扩展功能。可以通过重写接口来支持MVC配置。
@Configuration
public class CustomMVCConfiguration extends WebMvcConfigurerAdapter{//1
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.clear(); //实验发现,不起作用,可能是boot的bug,或者官方不让修改?
}
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
for (HttpMessageConverter<?> messageConverter : converters) {
System.out.println(messageConverter); //2
}
}
}
说明:
1:继承父类,是一个适配器模式类,可以重新定义MVC的功能和配置,但不会影响已有配置,属于增加功能扩展,不知道这是好还是不好。
2:找到扩展方法,可以添加自定义方法。
实战2——在已有的自动功能中增加新的功能fastjson
fastjson,国产,有很多人喜欢用,因为速度快,操作简单。以前老版本时其实也是坑很多啦,不过还是挺好用的,支持起,现在官方版本1.2.12,并没有支持Spring Boot的starter,但是它有HttpMessageConvert的支持,其实要支持也很方便。下面演示一下如何集成。
方法1:直接注册HttpMessageConverts的Bean
1、首先新建一个配置文件。
//FastJsonHttpMessageConvertersConfiguration .class
@Configuration
@ConditionalOnClass({JSON.class}) //1
public class FastJsonHttpMessageConvertersConfiguration {
@Bean
public HttpMessageConverters fastJsonHttpMessageConverters(){
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();//2
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(
SerializerFeature.PrettyFormat,
SerializerFeature.WriteClassName
);
fastConverter.setFastJsonConfig(fastJsonConfig);
HttpMessageConverter<?> converter = fastConverter;
return new HttpMessageConverters(converter);
}
说明:
1、判断JSON这个类文件是否存在,存在才会创建配置。
2、我看官方文档说的1.2.10以后,会有两个方法支持HttpMessageconvert,一个是FastJsonHttpMessageConverter,支持4.2以下的版本,一个是FastJsonHttpMessageConverter4支持4.2以上的版本,具体有什么区别暂时没有深入研究。
2、查看是否注册成功。
成功了。
3、启动。执行http://locahost:8080/showSetting
这个方法其实只是注册了Bean,由于没有指定执行的配置,使用了新方法,这种方式其实并不好,没办法灵活控制。所以我们看能不能像gson那样指定使用,看图:
如图,httpmessageconvert在自动配置时就会自动初始化gson和jackson,默认使用用jackson,找到了配置名为:spring.http.converters.preferred-json-mapper。于是有了方法2.
方法2:自动配置Bean并指定配置项
1、创建新配置
// FastJsonHttpMessageConvertersConfiguration.class
//...注释方法1的代码
@Configuration
@ConditionalOnClass({FastJsonHttpMessageConverter.class}) //1
@ConditionalOnProperty(//2
name = {"spring.http.converters.preferred-json-mapper"},
havingValue = "fastjson",
matchIfMissing = true
)
protected static class FastJson2HttpMessageConverterConfiguration{
protected FastJson2HttpMessageConverterConfiguration() {
}
@Bean
@ConditionalOnMissingBean({FastJsonHttpMessageConverter.class})//3
public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();//4
fastJsonConfig.setSerializerFeatures(
SerializerFeature.PrettyFormat,
SerializerFeature.WriteClassName,
SerializerFeature.WriteMapNullValue
);
ValueFilter valueFilter = new ValueFilter() {//5
//o 是class
//s 是key值
//o1 是value值
public Object process(Object o, String s, Object o1) {
if (null == o1){
o1 = "";
}
return o1;
}
};
fastJsonConfig.setSerializeFilters(valueFilter);
converter.setFastJsonConfig(fastJsonConfig);
return converter;
}
}
说明:
1:判断是否存在类。
2:使用spring.http.converters.preferred-json-mapper属性来启动功能。
3:当没有注册这个类时,自动注册Bean。
4:使用最新的官方推荐配置对象的方式来注入fastjson的序列化特征。
5:添加对json值的过滤,因为像移动APP,服务端在传json值时最好不要传null,而是使用“”,这是一个演示。
2、指定使用fastjson。
spring.http.converters.preferred-json-mapper=fastjson
3、启动运行,成功。现在就能很方便的切换fastjson或gson了。
小结
本章主要是说明了如何在自定义配置的基础上定制MVC和集成新的自动配置功能,很多同学觉得配置很简单基本已经够用了,自定义配置干啥?默认配置也许刚开始能满足一些需求,但更多的时候还需要针对特定的场景来自定义配置,比如拦截器和过滤器,虽然这一节没有讲,实际中用得是很多的,但通常基本原理是想通的,多实战实战,有写的不对的地方,大家多讨论交流。
本章示例地址:boot-properties
page 168 of 366 in chapter 2016