Spring、SpringMVC、Mybatis、SSM 的 XML 配置文件与注解
目录
文章目录
前置说明与条件
这篇文章主要讲解在 SSM 项目中,Spring、SpringMVC、Mybatis 的 xml 配置与纯注解配置的对应与注意事项(不包含其他依赖的 xml 配置与注解)
日志框架依赖引入与配置
这里日志框架使用的是 logback
引入 logback-classic
依赖(背后会自动引入 logback-core
、slf4j-api
等依赖包)
<!-- 日志 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
logback 配置:logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 logs为当前项目的logs目录 还可以设置为../logs -->
<property name="LOG_HOME" value="logs" />
<!--控制台日志, 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度,%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 日志输出级别 -->
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
如果有其他需求(例如这个也想用类配置,而不是配置文件),可以参考以下文档:
-
Logback 官方文档:https://logback.qos.ch/manual/
-
Logback 中文文档:https://www.docs4dev.com/docs/zh/logback/1.3.0-alpha4/reference/
-
Logback 快速入门 / 使用详解:https://www.cnblogs.com/simpleito/p/15133654.html
数据库依赖引入与配置
本篇文章的数据库使用 MySQL
,连接池使用 Druid
,其他数据库大同小异,请自行翻阅文档
注:我的本地数据库版本是 8.0.31
导入依赖
<!-- mySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.16</version>
</dependency>
编写数据库配置文件db.properties
db.driver=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/【数据库名称】
#db.url=jdbc:mysql://localhost:3306/【数据库名称】?serverTimezone=UTC
db.username=【数据库用户名】
db.password=【数据库用户名对应的密码】
应该不会有人忘了把中括号去掉吧
框架整合依赖
全部依赖整合位于文章末尾
Spring 和 SpringMVC 整合
注:本教程使用 Tomcat 9.0 所以 Servlet-api 依赖为
javax.servlet-api
Tomcat 10 及以上版本请使用
jakarta.servlet-api
(只是依赖变了,代码中只需要将 import 中的 javax 替换为 jakarta 即可)
<!-- Spring 和 SpringMVC 整合 -->
<!--spring-webmvc(包含了Spring的依赖项)-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.27</version>
</dependency>
<!-- servlet-api (适用于 Tomcat 9) -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- servlet-api (适用于 Tomcat 10) -->
<!-- <dependency> -->
<!-- <groupId>jakarta.servlet</groupId> -->
<!-- <artifactId>jakarta.servlet-api</artifactId> -->
<!-- <version>5.0.0</version> -->
<!-- <scope>provided</scope> -->
<!-- </dependency> -->
<!-- 导入thymeleaf与spring5的整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.15.RELEASE</version>
</dependency>
<!-- jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>
Spring 和 Mybatis 整合
<!-- Spring 和 Mybatis 整合 -->
<!-- Spring相关 -->
<!-- spring-orm(包含了spring-jdbc) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.27</version>
</dependency>
<!-- AOP框架 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.27</version>
</dependency>
<!-- Mybatis相关 -->
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
<!-- mybatis 和 spring的整合包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
其他依赖
<!-- 其他依赖 -->
<!-- Mybatis分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.2</version>
</dependency>
准备数据表、POJO 和 Mapper、首页
这里用 user 表的实例和 UserMapper 作为例子
user 表
CREATE TABLE `user` (
`name` varchar(50) NOT NULL,
`password` varchar(50) NOT NULL,
PRIMARY KEY (`name`) USING BTREE
)
测试数据
INSERT INTO `user` VALUES ('a', 'C4CA4238A0B923820DCC509A6F75849B');
INSERT INTO `user` VALUES ('aa', 'C81E728D9D4C2F636F067F89CC14862C');
INSERT INTO `user` VALUES ('aaa', 'ECCBC87E4B5CE2FE28308FD9F2A7BAF3');
user 的 POJO 类
public class User {
private String name;
private String password;
public User() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
}
UserMapper 接口
xml 配置 Mapper
@Repository // 可以不写(因为配置了 Mapper 扫描)
public interface UserMapper {
// 查询全部
List<User> selectUser();
}
注解配置 Mapper(可选)
@Repository // 可以不写(因为配置了 Mapper 扫描)
public interface UserMapper {
// 查询全部
@Select("SELECT `name`, `password` FROM user")
List<User> selectUser();
}
UserMapper.xml
注:如果上面选择了注解配置 Mapper,这个文件可以不用创建
在 resources 目录下新建 mapper 目录,里面新建 UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mapper.UserMapper">
<!-- 查询全部 -->
<select id="selectUser" resultType="org.example.pojo.User">
SELECT
name,
password
FROM
user
</select>
</mapper>
创建首页 index.html
在 webapp 目录下的 WEB-INF 下新建 pages
目录(本篇文章的视图解析器目录将会配置为这个目录)
在 pages
目录中新建 index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title>首页</title>
</head>
<body>
<h1>启动成功 hello world!</h1>
<a th:href="@{/user/select}">user/select</a>
</body>
</html>
Spring 整合 Mybatis
需要做的事
首先,一个 SSM 项目得有一个 Spring 配置文件或者配置类用于
- 开启组件扫描【排除 Controller 层】。排除 Controller 层是为了防止 SpringMVC 和 Spring 配置重复扫描包导致事务失效(失效原因自行查询)
- 开启AspectJ注解支持(没用到AOP可以不写)
- 装配 dataSource 数据源
- 装配事务管理器
- 开启声明式事务管理注解支持
- 装配并管理 SQLSessionFactoryBean
- 扫描 Mapper 接口(装配 MapperScannerConfigurer 以管理 Mapper 代理对象)
参考文档
官方文档:
- SqlSessionFactoryBean 的说明 : https://github.com/mybatis/spring/blob/master/src/site/markdown/factorybean.md
- 第三方中文文档(官网中文暂时 404 了): http://doc.vrd.net.cn/mybatis/spring/zh/factorybean.html
- sqlsession 的使用 : https://mybatis.org/mybatis-3/zh_CN/java-api.html#sqlsession
- configuration 配置 : https://mybatis.org/mybatis-3/zh_CN/configuration.html
使用 xml 配置文件
Mybatis 配置文件 mybatis-config.xml
注:分页插件需要额外引入 pagehelper 依赖(可以不配置,这里为了演示所以写一下)
<?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>
<!-- 官方文档: https://mybatis.org/mybatis-3/zh/configuration.html#setting -->
<settings>
<!-- 驼峰命名自动映射 (默认false) -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<plugins>
<!-- 分页插件 com.github.pagehelper为PageHelper类所在包名 -->
<!-- 需要额外引入 pagehelper 依赖,不用的话这里可以不配置 -->
<plugin interceptor="com.github.pagehelper.PageInterceptor"/>
</plugins>
<!-- 其他的Spring管了 -->
</configuration>
Spring 配置文件 spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">
<!-- 开启组件扫描【排除Controller层】 -->
<context:component-scan base-package="org.example">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 开启AspectJ注解支持(没用到AOP可以不写) -->
<aop:aspectj-autoproxy/>
<!-- Spring整合mybatis -->
<!-- 加载外部属性文件 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 装配 dataSource 数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</bean>
<!-- 装配事务管理器(id最好为 transactionManager,便于开启声明式事务管理注解支持) -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 开启声明式事务管理注解支持(命名空间的末尾是tx) -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 装配SQLSessionFactoryBean,管理SQLSessionFactory -->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 设置数据源 -->
<property name="dataSource" ref="dataSource"/>
<!-- 设置mybatis核心配置文件路径 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- 设置类型别名 -->
<property name="typeAliasesPackage" value="org.example.pojo"/>
<!-- 设置Mapper映射文件路径 -->
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
<!-- 扫描Mapper接口(装配MapperScannerConfigurer管理Mapper代理对象) -->
<mybatis-spring:scan base-package="org.example.mapper"/>
</beans>
题外话
Spring 配置文件的命名空间的注意事项:
-
开启声明式事务管理注解支持 的标签
tx:annotation-driven
的命名空间引入时的结尾是 tx 而不是其他 -
这个标签名字可以是 mybatis-spring ,也可以是 spring-mybatis
具体和上面的命名空间绑定有关
Mybatis 与 Spring 不整合的实现方式(题外话,不推荐)
自己封装 MapperTools 工具
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.github.pagehelper.PageInterceptor;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import javax.sql.DataSource;
import java.util.Properties;
/**
* 获取和关闭会话的工具类
*/
public class MapperTools {
private static final SqlSessionFactory sqlSessionFactory;
private static final ThreadLocal<SqlSession> threadLocal;
// 初始化SqlSessionFactory和连接池,只需要执行一次(使用静态代码块)
static {
try {
// 读取druid.properties文件
Properties properties = new Properties();
properties.load(Resources.getResourceAsStream("db.properties"));
// 创建一个数据库连接池
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
// 事务管理器
TransactionFactory transactionFactory = new JdbcTransactionFactory();
// 设置数据库连接环境
Environment environment = new Environment("development", transactionFactory, dataSource);
// 配置
Configuration configuration = new Configuration(environment);
// 驼峰命名自动映射 (默认false)
configuration.setMapUnderscoreToCamelCase(true);
configuration.getTypeAliasRegistry().registerAliases("org.example.pojo");
configuration.addInterceptor(new PageInterceptor());
configuration.addMappers("org.example.mapper");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
// 创建线程池
threadLocal = new ThreadLocal<>();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取会话
*/
public static SqlSession getSqlSession() {
SqlSession sqlSession = threadLocal.get(); // 拿到线程共享的SqlSession对象
if (sqlSession == null) {
sqlSession = sqlSessionFactory.openSession();// 创建会话
threadLocal.set(sqlSession); // 将会话与当前线程绑定
}
return sqlSession;
}
/**
* 获取mapper
*/
public static <T> T getMapper(Class<T> tClass) {
return getSqlSession().getMapper(tClass);
}
/**
* 关闭会话
*/
public static void closeSqlSession() {
SqlSession sqlSession = threadLocal.get(); // 得到当前线程中的SqlSession
if (sqlSession != null) {
sqlSession.close(); // 关闭会话
threadLocal.remove(); // 从ThreadLocal中移除当前线程已关闭的SqlSession对象
}
}
}
使用注解配置(配置类)
同样的,注解配置也需要
- 开启组件扫描
- 开启AspectJ注解支持(没用到AOP可以不写)
- 装配 dataSource 数据源
- 装配事务管理器
- 开启声明式事务管理注解支持
- 装配并管理 SQLSessionFactoryBean
- 扫描 Mapper 接口(装配 MapperScannerConfigurer 以管理 Mapper 代理对象)
JdbcConfig 类
在这个类中,需要
- 装配 dataSource 数据源
- 装配事务管理器
@PropertySource("classpath:db.properties") // 加载外部属性文件
public class JdbcConfig {
@Value("${db.driver}")
private String driver;
@Value("${db.url}")
private String url;
@Value("${db.username}")
private String username;
@Value("${db.password}")
private String password;
// 装配数据源
@Bean
public DruidDataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
// 装配事务管理器(id最好为 transactionManager,便于开启声明式事务管理注解支持)
@Bean
public DataSourceTransactionManager transactionManager(DataSource dataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
MybatisConfig 类
这个类需要
- 装配并管理 SQLSessionFactoryBean
- 扫描 Mapper 接口(装配 MapperScannerConfigurer 以管理 Mapper 代理对象)
注:MapperScannerConfigurer 一定不能在有 @Value 注入的类中装配 Bean,否则 @Value 会失效
原因如下(想了解详细一点的可以评论再开一篇解释):
MapperScannerConfigurer 的实现类 BeanDefinitionRegistryPostProcessor [类 1] 的优先级极高
因为 @Value 注解由 BeanPostProcessor 执行,所以不能在BeanPostProcessor 或 BeanFactoryPostProcessor [类 0] 类型中使用 @Value 。由于BeanDefinitionRegistryPostProcessor [类 1] 继承了 BeanFactoryPostProcessor [类 0] ,所以 @Value 也不能在 BeanDefinitionRegistryPostProcessor [类 1] 中使用
注:分页插件需要额外引入 pagehelper 依赖(可以不配置,这里为了演示所以写一下)
public class MybatisConfig {
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) throws IOException {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
// 设置数据源
factoryBean.setDataSource(dataSource);
// 设置 Mybatis 核心配置文件路径(如果还想用XML文件管理一部分配置,可以用此方法)
// factoryBean.setConfigLocation(new ClassPathResource("mybatis-config.xml"));
// 如果想连 Mybatis 核心XML配置文件都省了,可以用官方的 Configuration 配置方式
Configuration configuration = new Configuration();
// 驼峰命名自动映射(默认false)
configuration.setMapUnderscoreToCamelCase(true);
factoryBean.setConfiguration(configuration);
// 分页插件设置【多个插件可以用逗号分隔】
factoryBean.setPlugins(new PageInterceptor());
// 设置类型别名
factoryBean.setTypeAliasesPackage("org.example.pojo");
// 设置Mapper映射文件路径(如果使用了注解配置Mapper,这里可以不写)
// factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
return factoryBean;
}
// 扫描Mapper接口(装配MapperScannerConfigurer管理Mapper代理对象)
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage("org.example.mapper");
return configurer;
}
}
SpringConfig 类
这个类需要
- 开启组件扫描
- 开启AspectJ注解支持(没用到AOP可以不写)
- 开启声明式事务管理注解支持
- 引入
// 标记为配置类
@Configuration
// 开启组件扫描【排除Controller层】
@ComponentScan(
// 按理来说应该是需要扫描什么就写什么,这里为了方便演示排除的用法就直接全部扫描了
value = {"org.example"},
excludeFilters = {
// 使用正则排除
@ComponentScan.Filter(type = FilterType.REGEX, pattern = {"org.example.controller.*"})
// 使用注解类型排除 Controller (交给SpringMVC管理) (org.springframework.stereotype.Controller)
// , @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
}
)
// 引入数据库和Mybatis的配置
@Import({JdbcConfig.class, MybatisConfig.class})
@EnableTransactionManagement // 开启事务注解
@EnableAspectJAutoProxy // 开启AspectJ注解支持(没用到AOP可以不写)
public class SpringConfig {
}
Spring 整合 SpringMVC
需要做的事
其次,一个 SSM 项目得有一个 SpringMVC 配置文件或者配置类用于
-
开启组件扫描【只扫描 Controller】。只扫描 Controller 层是为了防止 SpringMVC 和 Spring 配置重复扫描包导致事务失效(失效原因自行查询)
-
配置视图解析器
-
注:此处使用的视图解析器是 thymeleaf ,其他解析器请自行查阅对应文档进行配置
-
-
装配 default-servlet-handler ,解决静态资源加载问题
-
装配 annotation-driven ,解决后续其他问题(view-controller、default-servlet-handler、Jackson 消息转换器等 23+种问题)
使用 XML 配置文件
SpringMVC 配置文件 springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 开启组件扫描【只扫描Controller】 -->
<!-- <context:component-scan base-package="org.example.controller"/> -->
<context:component-scan base-package="org.example" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 配置视图解析器 -->
<bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver" id="viewResolver">
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<property name="characterEncoding" value="UTF-8"/>
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".html"/>
</bean>
</property>
</bean>
</property>
</bean>
<!-- 此处还可以装配 multipartResolver(文件上传)、拦截器、异常处理器 -->
<!-- 装配视图控制器 -->
<mvc:view-controller path="/" view-name="index"/>
<!-- 装配default-servlet-handler,解决静态资源加载问题 -->
<mvc:default-servlet-handler/>
<!-- 装配,解决后续其他问题(view-controller、default-servlet-handler、Jackson消息转换器等23+种问题) -->
<mvc:annotation-driven/>
</beans>
使用注解配置(配置类)
要通过 Java 配置类启用 Spring MVC 支持,只需添加 @EnableWebMvc 注解即可
参考文档
- MVC 配置(官方):https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-config.html
- MVC 配置(第三方中文): https://springdoc.cn/spring/web.html#mvc-config
SpringMvcConfig 代码
java 配置中,可以使用 @EnableWebMvc
启用 MVC 配置(相当于 XML 配置中的 <mvc:annotation-driven>
)
可以通过实现 WebMvcConfigurer 接口的方式配置 MVC 的 API,在 idea 可以用 Ctrl+O 的方式查看可以实现的接口
在这个类中,可以装配视图解析器 viewResolver()
、配置静态资源加载default-servlet-handler
、装配拦截器等
// 标记为配置类
@Configuration
// 开启组件扫描【只扫描Controller】
@ComponentScan(basePackages = "org.example.controller")
// 启用MVC配置,解决后续其他问题(view-controller、default-servlet-handler、Jackson消息转换器等23+种问题)
// 相当于 XML 配置中的 <mvc:annotation-driven>
@EnableWebMvc
// 可以通过实现 WebMvcConfigurer 接口的方式配置 MVC 的 API
public class SpringMvcConfig implements WebMvcConfigurer {
// idea 可以用 Ctrl+O 的方式查看可以实现的接口
// 装配 default-servlet-handler,解决静态资源加载问题
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
// 静态资源加载问题的另一个解决方法(添加资源处理程序),对应注解 mvc:resources
// @Override
// public void addResourceHandlers(ResourceHandlerRegistry registry) {
// // 请求路径,资源路径
// registry.addResourceHandler("/js/**").addResourceLocations("/js/");
// registry.addResourceHandler("/css/**").addResourceLocations("/css/");
// registry.addResourceHandler("/img/**").addResourceLocations("/img/");
// }
/*
// 拦截器需用注入的方式引入
@Autowired
private XXXInterceptor xxxInterceptor;
// 添加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
InterceptorRegistration xxxInter = registry.addInterceptor(xxxInterceptor);
xxxInter.addPathPatterns("/user/**", "/file/**")
.excludePathPatterns("/user/login", "/user/signup", "/file/download/**");
}
*/
// 装配视图控制器,对应标签 mvc:view-controller
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
// 如果需要装配多个,可继续往下写,例如
// registry.addViewController("/test").setViewName("test/test");
}
// 以下是 配置视图解析器 ,拆成了三个,便于观看(其实就是装配 Bean)
// 模板解析器
@Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setCharacterEncoding("UTF-8");
resolver.setPrefix("/WEB-INF/pages/");
resolver.setSuffix(".html");
return resolver;
}
// 模板引擎(注入模板解析器)
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver());
return engine;
}
// 配置视图解析器(并注入模板引擎)
@Bean
public ViewResolver viewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setCharacterEncoding("UTF-8");
resolver.setTemplateEngine(templateEngine());
return resolver;
}
}
web.xml 与 WebConfig 类
需要做的事
在一个普通的 Spring Web MVC 项目中,web.xml 需要
注册 ContextLoaderListener
用于管理 spring 容器对象注册前端控制器 DispatcherServlet
,管理 SpringMVC 容器对象
当然,我们也可以注册其他过滤器例如注册CharacterEncodingFilter
以解决请求乱码问题
参考文档
-
DispatcherServlet 解析(官方文档):https://springdoc.cn/spring/web.html#mvc-servlet
-
DispatcherServlet 解析(第三方中文):https://springdoc.cn/spring/web.html#mvc-servlet
-
Spring 中 WebApplicationInitializer 的理解-优快云:https://blog.youkuaiyun.com/zq17865815296/article/details/79464403
使用 XML 配置文件
web.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 开发时配置文件顺序习惯监听器,过滤器,servlet -->
<!-- 注册上下文参数,配置 spring.xml文件路径 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</context-param>
<!-- 注册ContextLoaderListener,管理spring容器对象 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 注册前端控制器,管理springmvc容器对象 -->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 注册CharacterEncodingFilter解决请求乱码 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
使用注解配置(配置类)
Tomcat 启动时会自动扫描WebApplicationInitializer
接口的实现类,或者继承AbstractAnnotationConfigDispatcherServletInitializer
的类来初始化DispatcherServlet
原理参考(该链接已放置到上方 参考文档 里了):https://blog.youkuaiyun.com/zq17865815296/article/details/79464403
WebConfig 类
public class WebConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
// 用于 “根” 应用程序上下文(非web基础结构)配置
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
// 用于 DispatcherServlet 应用程序上下文(Spring MVC基础结构)配置
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
// 指定DispatcherServlet的servlet映射,例如 “/” 、 “/app” 等。
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
// 以上三个方法为继承该类必须实现的方法,下面是可选项
// 添加过滤器
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
// 可以放置多个过滤器
return new Filter[]{characterEncodingFilter};
}
}
DispatcherServlet 的层次结构(题外话)
官方文档 上下文层次结构(Context Hierarchy) 图:

创建其它层运行测试
Service 层
UserService 接口类
public interface UserService {
/**
* 查询所有
*/
List<User> selectAll();
}
UserServiceImpl 实现类
@Service
// @Transactional // 开启事务
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public List<User> selectAll() {
return userMapper.selectUser();
}
}
Controller 层
UserController 类
@RestController // ResponseBody + Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/select")
public List<User> select() {
List<User> users = userService.selectAll();
System.out.println("users = " + users);
return users;
}
}
测试运行
主页没问题

数据也可以查得出来

注解版的主页也没问题

数据也能正常查询

项目结构
XML 配置

注解配置

Tree
xml-to-annotation
│
├─annotation-demo
│ │ pom.xml
│ │
│ └─src
│ ├─main
│ │ ├─java
│ │ │ └─org
│ │ │ └─example
│ │ │ ├─config
│ │ │ │ JdbcConfig.java
│ │ │ │ MybatisConfig.java
│ │ │ │ SpringConfig.java
│ │ │ │ SpringMvcConfig.java
│ │ │ │ WebConfig.java
│ │ │ │
│ │ │ ├─controller
│ │ │ │ UserController.java
│ │ │ │
│ │ │ ├─mapper
│ │ │ │ UserMapper.java
│ │ │ │
│ │ │ ├─pojo
│ │ │ │ User.java
│ │ │ │
│ │ │ └─service
│ │ │ │ UserService.java
│ │ │ │
│ │ │ └─impl
│ │ │ UserServiceImpl.java
│ │ │
│ │ ├─resources
│ │ │ db.properties
│ │ │ logback.xml
│ │ │
│ │ └─webapp
│ │ └─WEB-INF
│ │ └─pages
│ │ index.html
│ │
│ └─test
│ └─java
└─xml-demo
│ pom.xml
│
└─src
├─main
│ ├─java
│ │ └─org
│ │ └─example
│ │ ├─controller
│ │ │ UserController.java
│ │ │
│ │ ├─mapper
│ │ │ UserMapper.java
│ │ │
│ │ ├─pojo
│ │ │ User.java
│ │ │
│ │ └─service
│ │ │ UserService.java
│ │ │
│ │ └─impl
│ │ UserServiceImpl.java
│ │
│ ├─resources
│ │ │ db.properties
│ │ │ logback.xml
│ │ │ mybatis-config.xml
│ │ │ spring.xml
│ │ │ springmvc.xml
│ │ │
│ │ └─mapper
│ │ UserMapper.xml
│ │
│ └─webapp
│ └─WEB-INF
│ │ web.xml
│ │
│ └─pages
│ index.html
│
└─test
└─java
全部依赖合集
<!-- 日志 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- mySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.16</version>
</dependency>
<!-- Spring 和 SpringMVC 整合 -->
<!--spring-webmvc(包含了Spring的依赖项)-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.27</version>
</dependency>
<!-- servlet-api (适用于 Tomcat 9) -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- servlet-api (适用于 Tomcat 10) -->
<!-- <dependency> -->
<!-- <groupId>jakarta.servlet</groupId> -->
<!-- <artifactId>jakarta.servlet-api</artifactId> -->
<!-- <version>5.0.0</version> -->
<!-- <scope>provided</scope> -->
<!-- </dependency> -->
<!-- 导入thymeleaf与spring5的整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.15.RELEASE</version>
</dependency>
<!-- jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>
<!-- Spring 和 Mybatis 整合 -->
<!-- Spring相关 -->
<!-- spring-orm(包含了spring-jdbc) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.27</version>
</dependency>
<!-- AOP框架 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.27</version>
</dependency>
<!-- Mybatis相关 -->
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
<!-- mybatis 和 spring的整合包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
<!-- 其他依赖 -->
<!-- Mybatis分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.2</version>
</dependency>
参考文档汇总
Logback 参考文档
-
Logback 官方文档:https://logback.qos.ch/manual/
-
Logback 中文文档:https://www.docs4dev.com/docs/zh/logback/1.3.0-alpha4/reference/
-
Logback 快速入门 / 使用详解:https://www.cnblogs.com/simpleito/p/15133654.html
Mybatis 参考文档
- SqlSessionFactoryBean 的说明 : https://github.com/mybatis/spring/blob/master/src/site/markdown/factorybean.md
- 第三方中文文档(官网中文暂时 404 了): http://doc.vrd.net.cn/mybatis/spring/zh/factorybean.html
- sqlsession 的使用 : https://mybatis.org/mybatis-3/zh_CN/java-api.html#sqlsession
- configuration 配置 : https://mybatis.org/mybatis-3/zh_CN/configuration.html
Spring MVC 参考文档
- MVC 配置(官方):https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-config.html
- MVC 配置(第三方中文): https://springdoc.cn/spring/web.html#mvc-config
Servlet 参考文档
- DispatcherServlet 解析(官方文档):https://springdoc.cn/spring/web.html#mvc-servlet
- DispatcherServlet 解析(第三方中文):https://springdoc.cn/spring/web.html#mvc-servlet
- Spring 中 WebApplicationInitializer 的理解-优快云:https://blog.youkuaiyun.com/zq17865815296/article/details/79464403
诚挚感谢亲爱的 SPRuala 对文档提出建议