Java – 新 SSM 整合
Spring 理解
1.SpringMvc 框架中实际上是有2个IoC容器。
2.其中一个IoC容器负责承载SpringMvc中的DispatcherServlet,另一个IoC容器负责承载 Service和Mapper层的组件。
web容器 | web相关组件(controller,springmvc核心组件) |
root容器 | 业务和持久层相关组件(service,aop,tx,dataSource,mybatis,mapper等) |
3.SpringMvc的IoC容器是另一个IoC容器的子容器。
4.在配置方面,我们可以对不同架构创建一个对应的配置类,如SpringMvc层可以创建一个专用于配置SpringMvc的配置类,其类应当被SpringMvc的IoC容器承载,而另一个父IoC容器则可以承载Service层和Mapper层的配置类。
5.在容器创建中,Spring提供了抽象类 AbstractAnnotationConfigDispatcherServletInitializer 中的三个实现方法,可以对三个不同的配置类设置到不同的IoC容器中。
public class SpringMvcInit extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* 用于承载父 IoC 容器配置类的加载方法
* 在这里可以设置 Service 层与 Mapper 层的配置类
*
* @return
*/
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{ServiceConfig.class, MapperConfig.class};
}
/**
* 用于承载子 IoC 容器配置类的加载方法
* 在这里可以设置 SpringMVC 的配置类
* @return
*/
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMVCConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
SSM-必要依赖
<dependencies>
<!-- SpringIoC容器坐标 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.10</version>
</dependency>
<!-- JDBC实现 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.0.10</version>
</dependency>
<!-- SpringMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.0.10</version>
</dependency>
<!-- Spring事务管理 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>6.0.10</version>
</dependency>
<!-- SpringAOP切面 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>6.0.10</version>
</dependency>
<!-- Druid数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.16</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<!-- mybatis的Spring整合包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.4.8</version>
</dependency>
<!-- mybatis分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
<!-- javax注解 -->
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
<!-- JSR-303 实体类参数校验实现 -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>8.0.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>8.0.0.Final</version>
</dependency>
<!-- Json数据转换 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
</dependencies>
SSM-SpringMVC配置
从上一章我们知道,SpringMvc 需要一个子IoC容器进行承载,因此我们需要对SpringMvc单独创建一个配置类,这个配置类只用于与SpringMvc有关的配置。
@Configuration
@ComponentScan(basePackages = {"cn.unsoft.controller", "cn.unsoft.exception","cn.unsoft.interceptor"})
@EnableWebMvc // 创建 handlerMapping 和 handlerAdapter 和 json 处理器
public class WebMvcConfig implements WebMvcConfigurer {
/**
* 开启静态资源的 handlerMapping
*
* @param configurer
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
主要有以下两个重要的操作:
1.创建handlerMapping 和 handlerAdapter 和Json数据处理,体现在 @EnableWebMvc 注解上。
2.对SpringMvc有关的包进行扫描,controller 包 与 exception包和 interceptor 包等
SSM-Service配置
Service 配置是处于root主IoC容器中,Service 中主要的配置项如声明事务管理,service层包,AOP 切面编程等
/**
* 业务层的配置类
* 用于配置 service aop 和 tx
*/
@Configuration
@ComponentScan(basePackages = {"cn.unsoft.service"})
@EnableTransactionManagement // 开启 声明式事务管理注解支持
@EnableAspectJAutoProxy // 开启 Aop 切面
public class ServiceConfig {
/**
* 配置事务管理
* @return
*/
@Bean
public TransactionManager transactionManager(@Qualifier("dataSource") DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
}
Service 配置类主要做以下三个配置:
1.对 service 层的业务包进行扫描
2.配置声明事务管理,并开启 @Transactional 事务注解支持
3.开启AOP切面编程支持,开启后可以使用 @Before 等切面注解
SSM-数据源配置
我们可以使用 Druid 数据源作为Mybatis 的数据源,那么我们需要把 DruidDataSource 存入 IoC 容器中,如下代码配置DruidDataSource数据源
@Configuration
@PropertySource("classpath:jdbc.properties")
public class DataSourceConfig {
@Bean("dataSource")
public DataSource dataSource(@Value("${jdbc.url}") String url,
@Value("${jdbc.driver}") String driver,
@Value("${jdbc.username}") String username,
@Value("${jdbc.password}") String password){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(url);
dataSource.setDriverClassName(driver);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
特别注意:
DruidDataSource数据源 建议抽离到单独一个配置项中配置,因为如果DruidDataSource数据源配置在 Mybatis 配置类中的话,因Mybatis设置三方数据源方法执行时有可能早于 @Value 注解读取 properties 文件数据,导致 dataSource 方法中的形参没有及时获取数据,从而产生连接数据库失败的可能。
单独配置一个配置类,系统会把该类中所有工作做完才会操作下一步,避免抢处理顺序
SSM-Mybatis配置
Mapper 层的配置类应存放在Root 主IoC容器内,其主要配置的是与数据库相关的,与Mybatis 相关的配置。
首先我们要明白,Mybatis 的运行原理是使用 SqlSessionFactoryBuilder 生成 SqlSessionFactory ,再利用SqlSessionFactory创建 SqlSession的。因此 SqlSessionFactoryBuilder 不需要存入 IoC 中
那么如果我们需要把引用带到IoC容器中,本应该是把 SqlSession 存到IoC容器中的,但是SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
因此我们不能直接把 SqlSession 存到IoC容器中,而是把 SqlSessionFactory 存到IoC容器中动态生成不同线程的SqlSession。
mapper映射器是使用 SqlSession.getMapper() 获取到的,通常我们可以在IoC容器中获取mapper映射器,但是但是从使用的角度来说,业务类(service)需要注入mapper接口,所以mapper应该交给ioc容器管理!
最终我们得出结论,SqlSessionFactory 和 mapper 接口应该存到IoC容器中。
把SqlSessionFactory存到容器中
我们可以通过手动的方式把SqlSessionFactory存到IoC容器中,如下代码:
@Bean
public SqlSessionFactory sqlSessionFactory(){
//1.读取外部配置文件
InputStream ips = Resources.getResourceAsStream("mybatis-config.xml");
//2.创建sqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(ips);
return sqlSessionFactory;
}
但是我们不推荐自己创建SqlSessionFactory存入IoC中。
为了提高整合效率,mybatis提供了提供封装SqlSessionFactory和Mapper实例化的逻辑的FactoryBean组件,我们只需要声明和指定少量的配置即可!该类存在 mybatis-spring 包中。
我们使用 SqlSessionFactoryBean 创建 SqlSessionFactory 并存入 IoC容器中。
依赖xml配置的 SqlSessionFactory
若我们的项目中,mybatis 依然使用 xml 作为配置项的话,我们可以把 mybatis-config.xml 配置项文件在创建 SqlSessionFactoryBean 后载入,其配置就可以写在 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>
<!-- 开启驼峰式映射-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 开启logback日志输出-->
<setting name="logImpl" value="SLF4J"/>
<!--开启resultMap自动映射 -->
<setting name="autoMappingBehavior" value="FULL"/>
</settings>
<typeAliases>
<!-- 给实体类起别名 -->
<package name="com.atguigu.pojo"/>
</typeAliases>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!--
helperDialect:分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。
你可以配置helperDialect属性来指定分页插件使用哪种方言。配置时,可以使用下面的缩写值:
oracle,mysql,mariadb,sqlite,hsqldb,postgresql,db2,sqlserver,informix,h2,sqlserver2012,derby
(完整内容看 PageAutoDialect) 特别注意:使用 SqlServer2012 数据库时,
https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md#%E5%A6%82%E4%BD%95%E9%85%8D%E7%BD%AE%E6%95%B0%E6%8D%AE%E5%BA%93%E6%96%B9%E8%A8%80
-->
<property name="helperDialect" value="mysql"/>
</plugin>
</plugins>
</configuration>
/**
* 保留 Mybatis-config.xml 配置文件方式整合 Mybatis
*/
@Configuration
@ComponentScan("cn.unsoft.mapper")
public class MapperConfig {
/**
* 把 SqlSessionFactory 存入 IoC 容器中
* @param dataSource
* @return
*/
@Bean
public SqlSessionFactoryBean sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource){
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
Resource resource = new ClassPathResource("mybatis-config.xml");
sqlSessionFactoryBean.setConfigLocation(resource);
return sqlSessionFactoryBean;
}
/**
* 对所有 mapper 接口 使用 SqlSession.getMapper() 获取代理对象
* @return
*/
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setBasePackage("cn.unsoft.mapper");
return mapperScannerConfigurer;
}
}
不依赖xml 配置 SqlSessionFactory
若我们不希望再使用 mybatis-config.xml 文件配置mybatis 时,我们可以在 SqlSessionFactory 中配置与 xml 文件相同的各种设置,这样我们就可以不需要 xml 文件了。代码如下:
/**
* 不保留 Mybatis-config.xml 文件的方式整命 Mybatis
* 所有在 xml 文件中配置的配置项全部使用代码代替
*/
@Configuration
@ComponentScan("cn.unsoft.mapper")
public class MapperConfig {
/**
* 创建 SqlSessionFactoryBean 同时配置 Mybatis
*
* @param dataSource
* @return
*/
@Bean
public SqlSessionFactoryBean sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
/**
* 设置第三方数据源
*/
sqlSessionFactoryBean.setDataSource(dataSource);
/**
* 设置配置项
* 1.配置驼峰映射功能
* 2.配置深层映射功能
* 3.配置日志输出实现类
*/
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setMapUnderscoreToCamelCase(true);
configuration.setLogImpl(Log4j2Impl.class);
configuration.setAutoMappingBehavior(AutoMappingBehavior.FULL);
sqlSessionFactoryBean.setConfiguration(configuration);
/**
* 配置mapper接口位置
*/
sqlSessionFactoryBean.setTypeAliasesPackage("cn.unsoft.mapper");
/**
* 配置分页插件
*/
PageInterceptor pageInterceptor = new PageInterceptor();
/**
* 配置分页使用的数据库方言
*/
Properties properties = new Properties();
properties.setProperty("helperDialect", "mysql");
pageInterceptor.setProperties(properties);
sqlSessionFactoryBean.setPlugins(pageInterceptor);
return sqlSessionFactoryBean;
}
/**
* mapper代理对象加入到ioc容器中
*
* @return
*/
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setBasePackage("cn.unsoft.mapper");
return mapperScannerConfigurer;
}
}
配置mapper代理对象到 IoC 容器中
使用 MapperScannerConfigurer 类对所有mapper接口进行生成代理对象,并存到 IoC容器中。
/**
* mapper代理对象加入到ioc容器中
*
* @return
*/
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setBasePackage("cn.unsoft.mapper");
return mapperScannerConfigurer;
}
SSM-初始化容器启动配置
我们完成了 SpringMvc、Service、Mybatis三个层级的架构配置项后,就需要对这些配置项配置在DispatherServlet 启动时创建 IoC 容器后执行的启动操作类中。
前面我们说过,启动时创建 IoC 容器后 会执行 AbstractAnnotationConfigDispatcherServletInitializer 类,这个类将要求提供SpringMVC的配置类作为子IoC容器,和Root主IoC容器。
我们可以把 SpringMvc 、 Service、 Mybatis 这三个配置类配置到对应的IoC容器中:
/**
* Spring 启动类
*/
public class SpringInit extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* root Ioc 容器指定配置类
*
* @return
*/
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{DataSourceConfig.class, ServiceConfig.class, MapperConfigNew.class};
}
/**
* WebMvc Ioc 容器指定配置类
*
* @return
*/
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebMvcConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
其中,getServletConfigClasses 则是配置子 IoC 容器的方法,我们把SpringMvc配置类加载进去,DataSourceConfig.class, ServiceConfig.class, MapperConfigNew.class这三个配置类则加载到 Root 主 IoC容器中去。
致此,SpringMvc启动后会把这些配置项都加载到对应的 IoC 容器中去。
前后端分离跨域问题
跨域问题只能由后端进行配置。
如果目前使用的是SpringMvc基础框架搭建的Web程序,我们只需要在Controller 上加上注解 @CrossOrigin 即可开启跨域访问
@RestController
@CrossOrigin
@RequestMapping("/xxx")
public class ScheduleController { ... }
也可以在SpringMvc配置项中增加 CORS 匹配策略:
@Configuration
@EnableWebMvc // 创建 handlerMapping 和 handlerAdapter 和 json 处理器
public class WebMvcConfig implements WebMvcConfigurer {
/**
* 增加所有请求都允许使用CORS跨域请求
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").
// 设置允许跨域请求的域名
.allowedOriginPatterns("*")
// 是否允许cookie
.allowCredentials(true)
// 设置允许的请求方式
.allowedMethods("GET", "POST", "DELETE", "PUT")
// 设置允许的header属性
.allowedHeaders("*")
// 跨域允许时间
.maxAge(3600);
}
}
如果使用的是 Spring Security 框架,请参考 Spring Security 的相关CORS跨域配置。
项目下载
https://www.tzming.com/wp-content/uploads/2023/filesdown/SSM.rar
共有 0 条评论