SSM 整合是指将学习的 Spring,SpringMVC,MyBatis 进行整合,来进行项目的开发。
1 项目基本的配置类
1.1 Spring 配置类
这个配置类主要是管理 Service 中的 bean,controller 层的 bean 对象是 SpringMVC 管理的
package cn.edu.njust.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
/**
* -- coding: UTF-8 -- *
*
* @author wangs
* @description: Spring 的配置文件,设置Spring容器的上下文
* @date 2023/11/20 11:12
*/
@Configuration
@ComponentScan({"cn.edu.njust.service"})
@PropertySource("classpath:jdbc.properties")
@Import({JDBCConfig.class, MyBatisConfig.class})
@EnableTransactionManagement
public class SpringConfig {
}
说明:
(1)@Configuration
:声明这是一个配置类;
(2)@ComponentScan
:添加包扫描,Spring 的配置类管理 service 层的 bean 对象;
(3)@PropertySource
:添加参数配置文件,其中包含数据库连接的信息等等;
(4)@Import
:导入其他配置类;
(5)@EnableTransactionManagement
:启动 Spring 的事务管理;
1.2 JDBC 配置类
JDBC 配置类的主要作用有两个:
1)配置数据源:即配置数据库的连接信息,配置使用到的数据库连接池,并交给 Spring 管理
2)配置事务管理器:Spring 的事务管理器需要配置,主要是配置使用的是什么事务管理;
package cn.edu.njust.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
/**
* -- coding: UTF-8 -- *
*
* @author wangs
* @description: JDBC 数据源配置类
* @date 2023/11/20 11:13
*/
public class JDBCConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
DataSourceTransactionManager ts = new DataSourceTransactionManager();
ts.setDataSource(dataSource);
return ts;
}
}
(1)dataSource():获取一个数据库连接池,这里使用到的是 Druid;
(2)transactionManager():获取 Spring 的事务管理器,这里将数据库连接池给到事务管理器;
1.3 MyBatis 配置类
主要是配置 MyBatis 的相关信息,即使就是使用一个配置类代替之前使用的 xml 文件,直接调用方法设置相关的属性,如AliasesPackage
和配置 mapper 的映射文件路径等等。
package cn.edu.njust.config;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;
/**
* -- coding: UTF-8 -- *
*
* @author wangs
* @description: MyBatis配置文件
* 1) 工厂bean管理
* 2) Mapper映射配置文件
* @date 2023/11/20 11:20
*/
public class MyBatisConfig {
/**
* MyBatis 是根据工厂获取数据库的连接对象的,所以应该将工厂的bean将给Spring管理
* @param dataSource 在其他地方配置的数据源
* @return 返回一个MyBatis的工厂bean
*/
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
// 设置数据源
factoryBean.setDataSource(dataSource);
// 设置包扫描
factoryBean.setTypeAliasesPackage("cn.edu.njust.pojo");
return factoryBean;
}
/**
* 设置MyBatis的配置
* 这个配置类是MyBatis提供的,专属的
* @return 返回一个配置类bean对象
*/
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
// 设置SQL映射文件的位置
mapperScannerConfigurer.setBasePackage("cn.edu.njust.dao");
return mapperScannerConfigurer;
}
}
说明:
(1)factoryBean.setTypeAliasesPackage("cn.edu.njust.pojo")
:这行代码的作用是,设置类型的别名,具体参数定位到 pojo 类的所在包,这样在 MyBatis 的 xml 文件中就可以直接使用类名来指定 resultType 了,不需要写全类名;
(2)mapperScannerConfigurer.setBasePackage("cn.edu.njust.dao")
:这个可以指定 xml 文件的路径,主要关联对象的 xml 文件和 MyBatis 的接口类;
1.4 SpringMVC 的配置
配置 SpringMVC 的 bean 管理,主要是控制层,以及开启一些 SpringMVC 的增强功能
package cn.edu.njust.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
/**
* -- coding: UTF-8 -- *
*
* @author wangs
* @date 2023/11/20 11:32
* @description: SpringMVC的上下文配置文件
* 1) @ComponentScan({"cn.edu.njust.config"}): 这个包的主要作用是扫描 SpringMvcSupport 类
*/
@Configuration
@ComponentScan({"cn.edu.njust.controller", "cn.edu.njust.config"})
@EnableWebMvc
public class SpringMvcConfig {
}
说明:
(1)@Configuration
:声明这是配置类;
(2)@ComponentScan
:添加包扫描,SpringMVC 的配置类一般管理的是 controller 类的 bean 对象;
(3)@EnableWebMvc
:启用 MVC 的增强功能,如将 POJO 类自动转化为 JSON 数据格式;
1.5 Web 项目入口配置
在传统的项目中,只用 Servlet 来处理请求响应,其实 SpringMVC 底层使用的也是 Servlet,但是不需要像 Servlet 那样麻烦,只需要配置相关的路径映射等等,再配合相关的注解,就可以达到效果。
package cn.edu.njust.config;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import javax.servlet.Filter;
/**
* -- coding: UTF-8 -- *
*
* @author wangs
* @description: web项目入口配置类
* 1) 配置路径信息规则
* 2) 加载Spring与SpringMVC的配置文件
* @date 2023/11/20 11:34
*/
public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* 加载Spring配置的方法
* @return Spring配置文件的Class对象
*/
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {SpringConfig.class};
}
/**
* 加载SpringMVC的配置文件
* @return SpringMVC配置文件的Class对象
*/
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
/**
* 拦截、管理的路径
* @return "/" 表示拦截所有路径
*/
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
/**
* 设置post请求中文乱码过滤器
* @return 设置了编码格式的过滤器
*/
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("utf-8");
return new Filter[]{filter};
}
}
说明:
(1)getRootConfigClasses()
:返回 Spring 配置类的 class 文件;用于获取 Spring 的上下文信息;
(2)getServletConfigClasses
:返回 SpringMvc 配置类的 class 文件,用于获取 SpringMvc 的上下文信息;
(3)getServletMappings()
:返回拦截路径的集合;
(4)getServletFilters()
:返回拦截器集合;
1.6 静态资源配置释放
配置静态资源的访问路径,直接继承WebMvcConfigurationSupport
只是其中一种方法;
package cn.edu.njust.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
}
}
2 统一响应结果封装
前端会有很多类型的请求,而后端响应这些请求,根据请求去进行业务处理得到的结果很可能是不一样的,但是前端希望得到一个看上去是规范的响应结果,以便根据这种结果来正确的进行响应和封装。
2.1 个人喜欢封装(简单版)
package cn.edu.njust.pojo;
/**
* -- coding: UTF-8 -- *
*
* @author wangs
* @description: 统一响应结果
* @date 2023/11/20 15:40
*/
public class Result {
private Integer code;
private String msg;
private Object data;
public Result() {
}
public Result(Integer code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public static Result success() {
return new Result(1, "success", null);
}
public static Result success(Object data) {
return new Result(1, "success", data);
}
public static Result error(String msg) {
return new Result(0, msg, null);
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
2.2 正式版(黑马资料)
public class Result {
//描述统一格式中的数据
private Object data;
//描述统一格式中的编码,用于区分操作,可以简化配置0或1表示成功失败
private Integer code;
//描述统一格式中的消息,可选属性
private String msg;
public Result() {
}
//构造方法是方便对象的创建
public Result(Integer code,Object data) {
this.data = data;
this.code = code;
}
//构造方法是方便对象的创建
public Result(Integer code, Object data, String msg) {
this.data = data;
this.code = code;
this.msg = msg;
}
//setter...getter...省略
}
//状态码
public class Code {
public static final Integer SAVE_OK = 20011;
public static final Integer DELETE_OK = 20021;
public static final Integer UPDATE_OK = 20031;
public static final Integer GET_OK = 20041;
public static final Integer SAVE_ERR = 20010;
public static final Integer DELETE_ERR = 20020;
public static final Integer UPDATE_ERR = 20030;
public static final Integer GET_ERR = 20040;
}
3 统一异常处理
虽然我们封装了统一的响应结果,但是这是程序正常执行的结果,如果程序执行出错,抛出异常,则浏览器页面响应的就是异常,不会给我们这种统一的结果,当然,前端也是期望得到统一的处理信息,便于解析。
package cn.edu.njust.controller;
import cn.edu.njust.pojo.Result;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
//@RestControllerAdvice用于标识当前类为REST风格对应的异常处理器
@RestControllerAdvice
public class ProjectExceptionAdvice {
//除了自定义的异常处理器,保留对Exception类型的异常处理,用于处理非预期的异常
@ExceptionHandler(Exception.class)
public Result doException(Exception ex) {
System.out.println("嘿嘿,异常你哪里跑!");
return Result.error("程序异常");
}
}
说明:
(1)@RestControllerAdvice
:用于标识当前类为REST风格对应的异常处理器;
(2)@ExceptionHandler(Exception.class)
:说明捕获那种类型的异常,这里 Exception.class 需要捕获全部异常类型;
(3)return
:返回统一数据响应格式,这样就算程序报错,前端也能正常的收到提示信息,而不是得到一个报错的代码页面;
4 静态资源释放
静态资源的的管理有很多中方式,我自己了解到的有三种:重写 WebMvcConfigurer 接口、继承 WebMvcConfigurerAdapter,继承 WebMvcConfigurationSupport;
4.1 重写 WebMvcConfigurer 接口
这是 SpringBoot 中文网中的做法,在 SpringMvc 中有可以这样做
Spring Boot 中的静态资源配置
4.2 继承 WebMvcConfigurerAdapter
这是一个比较老的做法,网上有很多都是继承这个类来重写相关方法实现的,但是,这个类现在已经过时了
具体的就是继承这个类,然后重写其中的方法,和继承 WebMvcConfigurationSupport 类似,不再演示代码,具体参考 4.3;
4.3 继承 WebMvcConfigurationSupport
4.3.1 配置演示
(1)需要导入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.18</version>
</dependency>
(2)配置类
package cn.edu.njust.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
}
}
3)将该配置类引入 SpringMVC 的配置类中
@Configuration
@ComponentScan({"cn.edu.njust.controller", "cn.edu.njust.config"})
@EnableWebMvc
public class SpringMvcConfig {
}
这里是使用 @ComponentScan 这个注解来扫描配置类所在的包 cn.edu.njust.config;
4.3.2 一些有趣的知识
WebMvcConfigurationSupport 类其实是一个“高级”的类,因为在使用 WebMvcConfigurerAdapter 的时候其实需要使用到这个类,在使用 WebMvcConfigurerAdapter 类时,我们需要声明@EnableWebMvc,查看这个注解的代码,会有如下发现
1)它使用到了 DelegatingWebMvcConfiguration 类
2)DelegatingWebMvcConfiguration 其实继承了 WebMvcConfigurationSupport
3)我们自己写的配置类,Spring 是如何知道获取我们的配置的呢?
在 DelegatingWebMvcConfiguration 有如下代码,Spring 会获取所有的配置类,并添加到配置中;