2021/8/10 学习小记
没有什么高深的知识,只是一个刚入职不久的新人的一些笔记外加碎碎念罢了
有关现在做的项目SSB(spring+springMVC+beetlSql),照例扫了一遍项目的大体配置xml,关于其中spring-mvc.xml的controller层扫描有一句注解说的很模糊:
<!-- 注意,不能让spring-mvc去直接扫Service层的包,因为spring-mvc为子上下文,此时的service还没有得到spring的增强 -->
-<context:component-scan use-default-filters="false" base-package="com.whfh.hhr.controller">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
按照我的理解来讲的话,项目起来时,web.xml中加载ContextloaderListener监听器进而创建spring容器,加载全局上下文,全局上下文中包含配置文件applicationContext.xml,然后继续加载dispatchServlet,初始化时加载配置文件spring-mvc.xml,这个serlvet又创建了一个springMvc子容器;其中springMVC子容器可以访问父容器spring的对象,而父容器不行;
也就是说,一种情况:
我们把dao,serivice,的bean扫描配置写在父容器spring中,controller层的bean扫描配置写在子容器springMVC中时,service可以注入到controller中,因为子容器可以访问父容器的对象;
第二种情况:
不管父容器写了什么,将dao,service,controller的bean扫描配置全部写在子容器springMVC中,bean都生成在子容器中,service也可以注入到controller中,但是由于service的bean是由springMvc容器创建的,生成的都是普通对象,而没有被spring代理,aop和事务都会失效;
第三种情况:
dao,service,controller的bean扫描配置写在父容器中,那么dispatchServlet寻找controller层的hander处理器映射时,就会找不到,因为子容器中就没有controller层的bean;
总之,回到注解上来,不是没有获得spring容器的增强,准确来说是子容器springMVC会覆盖掉父容器生产的dao或者service的bean的代理对象变成普通对象,进而导致功能—一般是事务失效;
第二个有兴趣的地方:
<mvc:annotation-driven>
<!-- 这里应该算是spring的一个漏洞,StringHttpMessageConverter默认字符集是ISO-8859-1导致spring-mvc返回的字符串会乱码,
只能通过这种方式修改为UTF-8,每一种类文本的mediaType都要添加。也许将来spring会修正这个问题 -->
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
<value>text/html;charset=UTF-8</value>
<value>text/xml;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
<!-- 装载自定义的urlPathHelper -->
<mvc:path-matching path-helper="urlPathHelper" />
</mvc:annotation-driven>
这段配置用于解决乱码问题,一般是后端传送给前端的json数据中文乱码;不过有关消息转换类,HttpMessageConverter,我基本不了解,准确的来说就知道有这个类,大概是用来转换请求和响应中数据的数据编码等等,也没有使用过,解决乱码的问题,我一般是直接在requestMap注解中设定响应类型为
“produces=text/html;charset=utf-8”,
@RequestMapping(value="/getTxjs_did.do",produces="text/html;charset=utf-8")
@ResponseBody
public String getTxjsByPId(String txjs_id) {
就能解决,不过今天在搜索过有关httpMessageConverter的讲解后,也确实发现这个类的强大;
StringHttpMessageConverter是HttpMessageConventer的实现类,可以完成请求报文到对象到响应报文之间的转换,说人话就是对客户端来的请求中请求体中的数据进行编码转换成对象,然后被handler处理器方法中的参数比如被@requestBody注释的参数接受,然后在逻辑处理完以后,如果方法上被注释了@reponseBody,那么就会将数据进行编码转换为响应报文中的响应体的数据返回到客户端;总之,消息转换类和@RequestBody和@RsponseBody一起使用;
以上是xml写法,如果要使用注释的方法的话,继承springMvc的配置类,WebMvcConfigurer
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
for(HttpMessageConverter httpMessageConverter:converters){
// 判断消息转换器的类型,然后设置默认编码
if(StringHttpMessageConverter.class.isAssignableFrom(httpMessageConverter.getClass())){
((StringHttpMessageConverter)httpMessageConverter).setDefaultCharset(Charset.forName("UTF-8"));
}
}
}
}
还有一种写法,是从其他人的博文看到的
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Bean
public HttpMessageConverter<String> responseBodyConverter() {
return new StringHttpMessageConverter(Charset.forName("UTF-8"));
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(responseBodyConverter());
addDefaultHttpMessageConverters(converters);
}
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
}
}
用法先不论,不过我好想问一个地方,为什么在添加消息转换器的时候,非要单独写一个方法,然后注册成bean,最后却调用方法responseBodyConverter()????????,这方法不是会生产一个新的消息转换器,那被注册的消息转换器有什么用?这种问题也不知道怎么百度,只好找时间自己试一下有没有什么问题了;
最后有关自己自定义的消息转换器,继承AbstractHttpMessageConventer就行了,具体我就不写了,毕竟没时间试,试过再说;
参考的几位大佬的文章:
https://www.cnblogs.com/hhhshct/p/9676604.html
https://blog.csdn.net/qq_41071876/article/details/104234304
https://blog.csdn.net/x_iya/article/details/77872173