文章目录
- 1. 创建maven 项目工程(略)
- 2. 创建如下演示目录:
- 3. 创建 `AbstractAnnotationConfigDispatcherServletInitializer` 的实现类
- (1) 配置DispatcherServlet上下文的过程
- (2) 配置配置ContextLoaderListener上下文的过程
- 4. 启动Spring MVC配置 : 前端视图解析器(DispatcherServlet)配置
- 5. 添加其他Servlet、Filter
- 6. 配置RootConfig --- 夹杂应用中的其他bean,通常是驱动应用后端的中间层和数据层组件。配置sessionFactory、事务管理等
- 总结: 其实我就是想记录一下,为了以后忘记了可以迅速找回。。。
- 以上:内容主要参考《Spring实战》、https://www.cnblogs.com/Qi1007/p/10129706.html 。如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正。
1. 创建maven 项目工程(略)
2. 创建如下演示目录:
3. 创建 AbstractAnnotationConfigDispatcherServletInitializer
的实现类
在Servlet3.0中,容器在启动时会在类路径中查找javax.servlet.ServletContainerInitializer
的实现类,如果能发现则会用它来配置Servlet容器。在Spring中Spring提供了其实现: SpringServletContainerInitializer
。 而SpringServletContainerInitializer
又会查找WebApplicationInitializer
的类并将配置的任务交给他们来完成。Spring 3.2 为其引入了一个便利的基础实现类即 AbstractAnnotationConfigDispatcherServletInitializer
。即 当 部署到Servlet3.0容器中的时候,容器会发现AbstractAnnotationConfigDispatcherServletInitializer
具体实现类,并使用该类来配置Servlet上下文。
(字符编码过滤器配置的两种方式 : https://blog.csdn.net/dgeek/article/details/70545338)
(1) 配置DispatcherServlet上下文的过程
查看 AbstractDispatcherServletInitializer
类可以发现里面的方法。其中有一个onStartup
方法和 createDispatcherServlet
方法。
onStartup
中注册了DispatcherServet, registerDispatcherServlet
方法调用了 createDispatcherServlet
,并进行了一些启动项的配置
找到 createServletApplicationContext()
方法的实现后发现 。其调用 getServletConfigClasses()
方法正是我们所实现的抽象方法
(2) 配置配置ContextLoaderListener上下文的过程
配置DispatcherServlet上下文是通过 onStartup
方法中 的 registerDispatcherServlet
。但是我们并没有在onStartup中看到注册
ContextLoaderListener 的方法。 答案在super.onStartup方法中。对ContextLoaderListener进行注册的方法放在了其父类AbstractContextLoaderInitializer
中。
registerContextLoaderListener
又调用了 createRootApplicationContext
方法。
查看 createRootApplicationContext
的实现方法发现和上面DispatcherServlet 类似。获取配置类并注册
注:
- DispatcherServlet启动时会创建Spring应用上下文,并加载配置文件或配置类中所声明的bean, 如控制器、视图解析器以以及处理器映射。
- ContextLoaderListener也会创建一个上下文 则用来加载应用中的一些其他bean。这些bean通常是驱动应用后端的中间层和数据层组件。
4. 启动Spring MVC配置 : 前端视图解析器(DispatcherServlet)配置
web.xml中的配置方式:
DispatcherServletConfig中的配置
- 通过注解
@EnableWebMvc
启动webmvc(), 并配置扫描目录。
这种配置方式存在以下一些问题:
- 没有配置视图解析器: Spring使用默认的BeanNameViewResolver 视图解析器,这个解析器会查找ID与视图名称匹配的bean,并且查找的Bean要实现View接口。
- 若不使用@ComponentScan注解,则Spring只能找到显式声明在配置类中的控制器。
- DispatcherServlet 会映射为应用的默认Servlet。所以对于静态资源文件的请求也会进行映射。
- <mvc:annotation-driven /> is also @EnableWebMvc
<tx:annotation-driven /> is @EnableTransactionManagement.
<context:component-scan /> is @ComponentScan
因此,实际使用中需要进行一些扩展如下
@Configuration
@EnableWebMvc // 启用Spring Mvc
@ComponentScan("com.kingfish") // 启用组件扫描
public class ServletConfig extends WebMvcConfigurerAdapter {
/**
* 配置视图解析器
*
* @return
*/
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/view/"); // 配置前缀
viewResolver.setSuffix(".jsp"); // 配置后缀
viewResolver.setExposeContextBeansAsAttributes(true); // 设置是否让应用程序上下文中的所有Spring bean都可访问*作为请求属性,
return viewResolver;
}
/**
* 配置文件解析器
*
* @return
*/
@Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
commonsMultipartResolver.setMaxUploadSize(10000000);
commonsMultipartResolver.setDefaultEncoding("UTF-8");
return commonsMultipartResolver;
}
/**
* 配置静态资源文件的处理
*
* @param configurer
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable(); // 使DispatcherServlet对静态资源的请求转发到Servlet容器中默认的Servlet上,而不是使用DispatcherServlet本身处理
}
/**
* 添加拦截器
*
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
}
/**
* 配置消息转换器的编码,解决后台传输json回前台时,中文乱码问题
* 如果客户端发送的消息是json格式,则调用 StringHttpMessageConverter 来进行 消息转换,而StringHttpMessageConverter 默认转换格式是ISO_8859_1
* @param converters
*/
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
// 消息转换器 - 默认支持所有类型 返回使用 text/plain, 这里写出来是将其编码转换为utf-8。 因为其默认编码是 ISO_8859_1 前端中文乱码
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(Charset.forName("UTF-8")); // 消息转换器
// 消息转换器 - 将JSON对象装转换为java对象,支持 application/json 格式
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
converters.add(stringHttpMessageConverter);
converters.add(mappingJackson2HttpMessageConverter);
}
这里解释一下 关于消息转换器 MessageConverters 的问题:
在请求中 @ResponseBody
和 @RequestBody
注解都会告诉Spring,让Spring查找一个消息转换器来将客户端资源表述转换为对象。当我们将字符串对象通过springmvc传回浏览器时,也会调用消息转换器进行资源转换。
默认情况下,如果返回的是对象,则会调用 MappingJackson2HttpMessageConverter
,这里没什么好说的,直接添加就可以了。
如果返回的格式是String,则会使用 StringHttpMessageConverter
消息转换器。根据其注释可以看出其返回的 Content-Type
是 text/plain
。而默认编码格式是 ISO-8859-1
。这就是造成返回前段时中文乱码的罪魁祸首。
为了解决上述问题,我们需要自己配置消息转换器,即如下:
/**
* 配置消息转换器的编码,解决后台传输json回前台时,中文乱码问题
* 如果客户端发送的消息是json格式,则调用 StringHttpMessageConverter 来进行 消息转换,而StringHttpMessageConverter 默认转换格式是ISO_8859_1
* @param converters
*/
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
// 消息转换器 - 默认支持所有类型 返回使用 text/plain, 这里写出来是将其编码转换为utf-8。 因为其默认编码是 ISO_8859_1 前端中文乱码
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(Charset.forName("UTF-8")); // 消息转换器
// 消息转换器 - 将JSON对象装转换为java对象,支持 application/json 格式
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
converters.add(stringHttpMessageConverter);
converters.add(mappingJackson2HttpMessageConverter);
}
5. 添加其他Servlet、Filter
按照 AbstractAnnotationConfigDispatcherServletInitializer
的定义。它会创建DispatcherServlet和ContextLoaderListener。但并未提及添加其他Servlet、Filter和Listener。
上面说到 : 在Servlet3.0中,容器会在类路径中查找javax.servlet.ServletContainerInitializer
的实现类,如果能发现则会用它来配置Servlet容器。在Spring中Spring提供了其实现: SpringServletContainerInitializer
。 而SpringServletContainerInitializer
又会查找WebApplicationInitializer
的类并将配置的任务交给他们来完成。
而实际上,基于java的初始化器(initializer) 的一个好处就是可以定义任意数量的初始化器。所以添加自定义的Servlet、Filter 最简单的方式是可以通过实现Spring的 WebApplicationInitializer
接口。
具体如下:
添加自定义的过滤器。
6. 配置RootConfig — 夹杂应用中的其他bean,通常是驱动应用后端的中间层和数据层组件。配置sessionFactory、事务管理等
(1) 创建一个简单的数据库,和user表用于测试
(2) 配置RootConfig
@Configuration
@EnableTransactionManagement // 启动事务管理
@ComponentScan(basePackages = {"com.kingfish"}, excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class)})
public class RootConfig {
/**
* 配置dataSource
*
* @return
*/
@Bean
public DataSource druidDataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
druidDataSource.setUrl("jdbc:mysql:///demo?useUnicode=true&characterEncoding=utf-8");
druidDataSource.setUsername("root");
druidDataSource.setPassword("123");
return druidDataSource;
}
/**
* 配置sessionFactory
*
* @param dataSource
* @return
*/
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) throws IOException {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setTypeAliasesPackage("com.kingfish.pojo");
sqlSessionFactoryBean.setConfigLocation(new ClassPathResource("mybatis/SqlSessionFactory.xml"));
sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mybatis/mapper/*.xml"));
return sqlSessionFactoryBean;
}
/**
* 配置事务管理器
*
* @param dataSource
* @return
*/
@Bean
public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource) {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
/**
* 配置事务过滤
*
* @param dataSourceTransactionManager
* @return
*/
@Bean
public TransactionInterceptor interceptor(DataSourceTransactionManager dataSourceTransactionManager) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionManager(dataSourceTransactionManager);
Properties transactionAttributes = new Properties();
transactionAttributes.setProperty("save*", "PROPAGATION_REQUIRED");
transactionAttributes.setProperty("del*", "PROPAGATION_REQUIRED");
transactionAttributes.setProperty("update*", "PROPAGATION_REQUIRED");
transactionAttributes.setProperty("get*", "PROPAGATION_REQUIRED,readOnly");
transactionAttributes.setProperty("find*", "PROPAGATION_REQUIRED,readOnly");
transactionAttributes.setProperty("*", "PROPAGATION_REQUIRED");
interceptor.setTransactionAttributes(transactionAttributes);
return interceptor;
}
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactoryBean");
mapperScannerConfigurer.setBasePackage("com.kingfish.dao");
return mapperScannerConfigurer;
}
}
(3). 创建相应的类进行数据库操作。目录结构如下
SqlSessionFactory.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!--使用jdbc的getGeneratekeys获取自增主键值-->
<setting name="useGeneratedKeys" value="true"/>
<!--使用列别名替换别名 默认true-->
<setting name="useColumnLabel" value="true"/>
<!--开启驼峰命名转换Table:create_time到 Entity(createTime)-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 打印日志 -->
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
</configuration>
(3). 访问测试
补充: pom.xml 配置:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>11</groupId>
<artifactId>123</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>123 Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<springVersion>4.3.12.RELEASE</springVersion>
<springVersion>4.3.12.RELEASE</springVersion>
<hibernateVersion>4.3.5.Final</hibernateVersion>
<jstlVersion>1.2</jstlVersion>
<taglibVersion>1.1.2</taglibVersion>
<servletVersion>3.0-alpha-1</servletVersion>
<jsonVersion>2.5.4</jsonVersion>
<mysqlVersion>8.0.13</mysqlVersion>
<c3p0Version>0.9.1.2</c3p0Version>
<log4jVersion>1.2.17</log4jVersion>
<fileuploadVersion>1.3.1</fileuploadVersion>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${springVersion}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${springVersion}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${springVersion}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${springVersion}</version>
</dependency>
<!-- spring web + spring MVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${springVersion}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${springVersion}</version>
</dependency>
<!--mysql jdbc-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jsonVersion}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jsonVersion}</version>
</dependency>
<!-- 引入gson依赖 -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.6.2</version>
</dependency>
<!-- file upload part -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
</dependency>
</dependencies>
<build>
<finalName>123</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
总结: 其实我就是想记录一下,为了以后忘记了可以迅速找回。。。
项目地址:https://download.csdn.net/download/qq_36882793/11665343