Spring、SpringMVC、Mybatis、SSM 的 XML 配置文件与注解

Spring、SpringMVC、Mybatis、SSM 的 XML 配置文件与注解

目录

前置说明与条件

这篇文章主要讲解在 SSM 项目中,Spring、SpringMVC、Mybatis 的 xml 配置与纯注解配置的对应与注意事项(不包含其他依赖的 xml 配置与注解)

日志框架依赖引入与配置

这里日志框架使用的是 logback

引入 logback-classic 依赖(背后会自动引入 logback-coreslf4j-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>

如果有其他需求(例如这个也想用类配置,而不是配置文件),可以参考以下文档:

数据库依赖引入与配置

本篇文章的数据库使用 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 代理对象)

参考文档

官方文档:

使用 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 配置文件的命名空间的注意事项:

  1. 开启声明式事务管理注解支持 的标签 tx:annotation-driven 的命名空间引入时的结尾是 tx 而不是其他

    image-20240324181146126
  2. 这个标签名字可以是 mybatis-spring ,也可以是 spring-mybatis

    image-20240324182030229

    具体和上面的命名空间绑定有关

    image-20240324182755503
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 会失效

原因如下(想了解详细一点的可以评论再开一篇解释):

  1. MapperScannerConfigurer 的实现类 BeanDefinitionRegistryPostProcessor [类 1] 的优先级极高

  2. 因为 @Value 注解由 BeanPostProcessor 执行,所以不能在BeanPostProcessorBeanFactoryPostProcessor [类 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 注解即可

参考文档
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以解决请求乱码问题

参考文档

使用 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.csdn.net/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) 图:

mvc-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;
    }

}

测试运行

主页没问题

image-20240325182900548

数据也可以查得出来

image-20240325182939116

注解版的主页也没问题

image-20240325183031398

数据也能正常查询

image-20240325183042366

项目结构

XML 配置

image-20240327093509104

注解配置

image-20240327093427122

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 参考文档

Mybatis 参考文档

Spring MVC 参考文档

Servlet 参考文档

诚挚感谢亲爱的 SPRuala 对文档提出建议

  • 29
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值