SSM整合(借鉴版)
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path>
</svg>
<h1><a id="SSM_0"></a>SSM整合系列</h1>
前言
总体来说,就是两件事情,两个层次:
- 顶层:开发功能
- 底层:搭建环境
- Spring和Mybatis整合
- Spring和SpringMVC整合
文章目录
第一章、Spring 和 MyBatis整合
第一节 连接数据库
1、总体 SSM 整合所需依赖
<!-- SpringMVC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.1</version> </dependency>
<!-- Spring 持久化层所需依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.1</version>
</dependency><!-- 日志 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency><!-- ServletAPI -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency><!-- Spring5和Thymeleaf整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</dependency><!-- Mybatis核心 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency><!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.3</version>
</dependency><!-- 数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.31</version>
</dependency><!-- junit5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency><!-- Spring 的测试功能 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.1</version>
</dependency>
<!-- Mybatis 和 Spring 的整合包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
2、配置数据源(连接数据库)
①创建 jdbc.properties
jdbc.user=root
jdbc.password=atguigu
jdbc.url=jdbc:mysql://192.168.198.100:3306/mybatis-example
jdbc.driver=com.mysql.jdbc.Driver
②加入日志配置文件
③创建 Spring 配置文件
<!-- 加载外部属性文件 --> <context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置数据源 -->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
</bean>
- 注意在配置数据源的过程中,其中property标签中的name属性dirverClassName必须写成这样,写成driver或者其它会报错
报错参考
④创建 junit 测试类
@SpringJUnitConfig(locations = {"classpath:spring-persist.xml"}) public class SSMTest {
<span class="token annotation punctuation">@Autowired</span> <span class="token keyword">private</span> <span class="token class-name">DataSource</span> dataSource<span class="token punctuation">;</span> <span class="token class-name">Logger</span> logger <span class="token operator">=</span> <span class="token class-name">LoggerFactory</span><span class="token punctuation">.</span><span class="token function">getLogger</span><span class="token punctuation">(</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token annotation punctuation">@Test</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testConn</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">SQLException</span> <span class="token punctuation">{<!-- --></span> <span class="token class-name">Connection</span> connection <span class="token operator">=</span> dataSource<span class="token punctuation">.</span><span class="token function">getConnection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> logger<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span>connection<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
第二节 整合Mybatis
1、思路
①理解方式一:简单版
② 理解方式二:进阶版
本质:Spring接管一切,代码更加简洁。
- Spring管理数据源,连接数据库
- Spring管理SqlSessionFactory,开启SqlSession的细节被屏蔽了
- Spring的IOC容器负责注入Mapper接口
- Spring管理声明式事务
2、Mybatis-Spring技术
相关技术之间版本匹配说明:
Mybatis-Spring 的依赖:
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
3、配置 SqlSessionFactoryBean
①创建 Mybatis 全局配置文件
<?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>
<span class="token comment"><!-- Mybatis全局配置 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>settings</span><span class="token punctuation">></span></span> <span class="token comment"><!-- 将数据库表字段映射到驼峰式命名的Java实体类属性中 --></span> <span class="token comment"><!-- 数据库表字段格式:单词_单词 --></span> <span class="token comment"><!-- Java实体类属性:首字母小写的驼峰式命名 --></span> <span class="token comment"><!--将_自动映射为驼峰,emp_name: empName--></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>setting</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mapUnderscoreToCamelCase<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>settings</span><span class="token punctuation">></span></span> <span class="token comment"><!--指定实体类别名--></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>typeAliases</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>package</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.atguigu.ssm.entity<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>typeAliases</span><span class="token punctuation">></span></span>
</configuration>
②创建模型
public class Emp {
<span class="token keyword">private</span> <span class="token class-name">Integer</span> empId<span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token class-name">String</span> empName<span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token class-name">Double</span> empSalary<span class="token punctuation">;</span>
③创建Mapper接口
public interface EmpMapper {
<span class="token class-name">List</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">Emp</span><span class="token punctuation">></span></span> <span class="token function">selectAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
}
④创建Mapper配置文件
<?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属性是找到当前配置的依据 -->
<!-- 由于最理想的Mybatis使用方式是:通过Mapper接口调用接口方法,访问数据库 -->
<!-- 这样的理想方式要求:能够通过接口全类名找到Mapper配置 -->
<!-- 所以:我们就用Mapper接口的全类名来给namespace属性赋值 -->
<mapper namespace="com.atguigu.ssm.mapper.EmpMapper"><span class="token comment"><!-- List<Emp> selectAll(); --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>select</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>selectAll<span class="token punctuation">"</span></span> <span class="token attr-name">resultType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Emp<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> select emp_id,emp_name,emp_salary from t_emp <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>select</span><span class="token punctuation">></span></span>
</mapper>
⑤配置 SqlSessionFactoryBean
[1]风格一:保留 Mybatis 全局配置文件
<!-- 配置 SqlSessionFactoryBean --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<span class="token comment"><!-- 指定 Mybatis 全局配置文件位置 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>configLocation<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>classpath:mybatis-config.xml<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token comment"><!-- 指定 Mapper 配置文件位置 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mapperLocations<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>classpath:mappers/*Mapper.xml<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token comment"><!-- 装配数据源 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dataSource<span class="token punctuation">"</span></span> <span class="token attr-name">ref</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>druidDataSource<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
</bean>
[2]风格二:彻底舍弃 Mybatis 全局配置文件
<!-- 配置 SqlSessionFactoryBean --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<span class="token comment"><!-- 舍弃 Mybatis 全局配置文件,使用 configuration 属性 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>configuration<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>bean</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>org.apache.ibatis.session.Configuration<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mapUnderscoreToCamelCase<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>bean</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>property</span><span class="token punctuation">></span></span> <span class="token comment"><!-- 舍弃 Mybatis 全局配置文件,使用 typeAliasesPackage 属性配置实体类所在包 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>typeAliasesPackage<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.atguigu.ssm.entity<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token comment"><!-- 指定 Mapper 配置文件位置 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mapperLocations<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>classpath:mappers/*Mapper.xml<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token comment"><!-- 装配数据源 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dataSource<span class="token punctuation">"</span></span> <span class="token attr-name">ref</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>druidDataSource<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
</bean>
注意:上面两种方式如果并存,会抛出异常:
java.lang.IllegalStateException: Property ‘configuration’ and ‘configLocation’ can not specified with together
⑥配置 Mapper 接口扫描
[1]方式一:使用扫描器
<!-- 配置 Mapper 接口类型的bean的扫描器 -->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.atguigu.ssm.mapper"/>
</bean>
[2]方式二:使用 mybatis-spring 名称空间
<mybatis-spring:scan base-package="com.atguigu.ssm.mapper"/>
⑦测试
@Autowired private EmpMapper empMapper;
@Test
public void testMybatis() {
List<Emp> empList = empMapper.selectAll();<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Emp</span> emp <span class="token operator">:</span> empList<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">//使用 iter 快捷键可以快速生成foreach循环</span> logger<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span>emp<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
第三节、加入声明式事务
1、配置事务管理器
<!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 装配数据源 --> <property name="dataSource" ref="druidDataSource"/> </bean>
<!-- 开启基于注解的声明式事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
注意:引入tx名称空间时千万注意名称空间的值
2、创建 Service 组件
@Service public class EmpServiceImpl implements EmpService {
<span class="token annotation punctuation">@Autowired</span> <span class="token keyword">private</span> <span class="token class-name">EmpMapper</span> empMapper<span class="token punctuation">;</span> <span class="token annotation punctuation">@Override</span> <span class="token annotation punctuation">@Transactional</span><span class="token punctuation">(</span>readOnly <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token comment">//为当前业务层添加事务</span> <span class="token keyword">public</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">Emp</span><span class="token punctuation">></span></span> <span class="token function">getAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> empMapper<span class="token punctuation">.</span><span class="token function">selectAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
3、配置自动扫描的包
<context:component-scan base-package="com.atguigu.ssm.service"/>
4、 测试
@Autowired private EmpService empService;
@Test
public void testTx() {
List<Emp> empList = empService.getAll();
for (Emp emp : empList) {
System.out.println("emp = " + emp); //使用 soutv 快捷键可以生成
}
}
在框架打印的日志中能够看到事务打开、提交、回滚等操作即可确认声明式事务已生效。
相关日志信息节选:
urceTransactionManager - Acquired Connection [com.mysql.jdbc.JDBC4Connection@488d1cd7] for JDBC transaction
urceUtils - Setting JDBC Connection [com.mysql.jdbc.JDBC4Connection@488d1cd7] read-only
urceTransactionManager - Switching JDBC Connection [com.mysql.jdbc.JDBC4Connection@488d1cd7] to manual commit
ing a new SqlSession
tering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@babafc2]
edTransaction - JDBC Connection [com.mysql.jdbc.JDBC4Connection@488d1cd7] will be managed by Spring
ctAll - = = > Preparing: select emp_id,emp_name,emp_salary from t_emp
ctAll - = = > Parameters:
ctAll - <== Total: 15
sing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@babafc2]
action synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@babafc2]
action synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@babafc2]
action synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@babafc2]
urceTransactionManager - Initiating transaction commit
urceTransactionManager - Committing JDBC transaction on Connection [com.mysql.jdbc.JDBC4Connection@488d1cd7]
urceUtils - Resetting read-only flag of JDBC Connection [com.mysql.jdbc.JDBC4Connection@488d1cd7]
urceTransactionManager - Releasing JDBC Connection [com.mysql.jdbc.JDBC4Connection@488d1cd7] after transaction
第四节 最终bean图
`
第二章、Spring 和 SpringMVC整合
前言
- ContextLoaderListener:读取 spring-persist.xml
- DispatcherServlet:读取 spring-mvc.xml
第一节、配置web.xml
classpath就是代表 /WEB-INF /classes/ 这个路径(所有src目录下面的java、xml、properties等文件编译后都会在此)
<!-- ContextLoaderListener --> <!-- 通过 context-param 指定 Spring 框架的配置文件位置 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-persist.xml</param-value> </context-param>
<!-- 配置 ContextLoaderListener 监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener><!-- DispatcherServlet -->
<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:spring-mvc.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><!-- 需要注意两个 Filter 的顺序:字符集过滤器在前,转换请求方式过滤器在后 -->
<!-- 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>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- HiddenHttpMethodFilter -->
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
第二节、SpringMVC 配置
<!-- SpringMVC 只扫描 handler 类所在的包 --> <!-- Spring 和 SpringMVC 扫描各自负责的组件,扫描的范围没有重合的部分,直接避免了重复创建对象 --> <context:component-scan base-package="com.atguigu.ssm.handler"/>
<!-- 配置 Thymeleaf 的视图解析器 -->
<bean id="thymeleafViewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<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="prefix" value="/WEB-INF/templates/"/>
<property name="suffix" value=".html"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateMode" value="HTML5"/>
</bean>
</property>
</bean>
</property>
</bean><!-- SpringMVC 注解驱动(标配) -->
<mvc:annotation-driven/><!-- 对于没有映射的请求直接转发放行,主要是静态资源 -->
<mvc:default-servlet-handler/>
<!-- 匹配请求路径直接前往视图,不经过 handler 方法 -->
<mvc:view-controller path="/" view-name="portal"/>
<mvc:view-controller path="/index.html" view-name="portal"/>
第三节 显示数据列表
1、显示首页
①声明view-controller
<!-- 匹配请求路径直接前往视图,不经过 handler 方法 -->
<mvc:view-controller path="/" view-name="portal"/>
<mvc:view-controller path="/index.html" view-name="portal"/>
②创建页面
<!DOCTYPE html> <html lang="en" xml:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body>
</body>
</html>
③编写超链接
<a th:href="@{/get/all}">显示全部数据</a>
2、显示数据列表
①创建handler类
@Controller public class EmpHandler {
<span class="token annotation punctuation">@Autowired</span> <span class="token keyword">private</span> <span class="token class-name">EmpService</span> empService<span class="token punctuation">;</span> <span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span><span class="token string">"/get/all"</span><span class="token punctuation">)</span> <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">getAll</span><span class="token punctuation">(</span><span class="token class-name">Model</span> model<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">// 1、查询数据</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">Emp</span><span class="token punctuation">></span></span> empList <span class="token operator">=</span> empService<span class="token punctuation">.</span><span class="token function">getAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 2.存入模型</span> model<span class="token punctuation">.</span><span class="token function">addAttribute</span><span class="token punctuation">(</span><span class="token string">"empList"</span><span class="token punctuation">,</span> empList<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token string">"emp-list"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
②在页面上显示数据列表
<table> <tr> <th>ID</th> <th>NAME</th> <th>SALARY</th> </tr> <tbody th:if="${#lists.isEmpty(empList)}"><!--#lists:thymeleaf内置对象--> <tr> <td colspan="3">抱歉!没有查询到数据!</td> </tr> </tbody> <tbody th:if="${not #lists.isEmpty(empList)}"> <tr th:each="emp : ${empList}"> <td th:text="${emp.empId}">这里显示员工ID</td> <td th:text="${emp.empName}">这里显示员工NAME</td> <td th:text="${emp.empSalary}">这里显示员工SALARY</td> </tr> </tbody> </table>
<a th:href="@{/}">回首页</a>
第四节 最终bean图
第三章、 分页
第一节 分页的概念
1、提出问题
如果应用程序显示数据不分页,会有三个问题:
- 用户查看数据非常不方便。
- 所有数据不分冷热全部显示出来,冷数据白白占用存储空间,浪费内存。
- 在服务器端查询全部数据占用内存很大,给整个系统增加了很大压力。
2、分页的概念
①分页本身的概念
把系统中要显示的数据分成较小的单元,每个单元作为『一页』显示给用户。每次访问服务器只查询一页数据。
分页的好处:
- 用户体验较好。
- 服务器端每次只查询一部分数据,内存压力减小。
- 对冷数据减少查询的次数,据此对系统性能进行优化。
②分页的细节
3、实现分页的基本逻辑
①物理分页
具体数据库不同,分页语法有区别。下面我们以 MySQL 为例来说明。MySQL 的分页需要借助 LIMIT 子句来完成。
select emp_id,emp_name,emp_salary from t_emp limit 0,5; # 查询第一页数据
select emp_id,emp_name,emp_salary from t_emp limit 5,5; # 查询第二页数据
select emp_id,emp_name,emp_salary from t_emp limit 10,5;# 查询第三页数据
LIMIT 子句的公式:
limit (pageNo-1)*pageSize,pageSize
注意:在 SQL 的语法中,要么就不加 LIMIT 子句,如果非要写 LIMIT 子句,那么 LIMIT 子句必须出现在 SQL 语句最后,什么 ORDER BY、GROUP BY、WHERE 等子句都必须在 LIMIT 子句前面。
②逻辑分页
[1]需求
为了能够在页面上全面显示分页相关的细节数据,总页数需要计算得到。
[2]总页数计算方式
[3]页码的合理化
合理化的英文表述是:reasonable。页码的有效范围:1~总页数。修正方式:
- 用户输入的页码 < 1:将页码设定为第一页
- 用户输入的页码 > 总页数:将页码设定为最后一页
③分页执行流程
- 查询总记录数
- 查询当前页数据
- 根据总记录数和每页条数计算总页数
- 在1~总页数之间修正页码
- 封装上述所有数据,发送到页面显示
第二节、Mybatis 的分页插件
1、官方支持
具体使用细节可以参考:官方文档
2、操作步骤
①依赖
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
②配置
<!-- 配置 SqlSessionFactoryBean --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
…… <span class="token comment"><!-- 在 plugins 属性中配置 Mybatis 插件 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>plugins<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>array</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>bean</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.github.pagehelper.PageInterceptor<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>properties<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>props</span><span class="token punctuation">></span></span> <span class="token comment"><!-- 设置 reasonable 为 true 表示将页码进行合理化修正。页码的有效范围:1~总页数 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>prop</span> <span class="token attr-name">key</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>reasonable<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>true<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>prop</span><span class="token punctuation">></span></span> <span class="token comment"><!-- 数据库方言:同样都是 SQL 语句,拿到不同数据库中,在语法上会有差异 --></span> <span class="token comment"><!-- 默认情况下,按照 MySQL 作为数据库方言来运行 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>prop</span> <span class="token attr-name">key</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>helperDialect<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>mysql<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>prop</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>props</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>property</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>bean</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>array</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>property</span><span class="token punctuation">></span></span>
</bean>
③PageHelper 非侵入式的体现
PageHelper.startPage(pageNo, pageSize);
开启分页功能,就在 SQL 语句后面附加 LIMIT 子句并查询总记录数;不开启就还是按照原样查询。分页功能对原有的 Mapper 接口、SQL 语句没有任何影响。这个效果可以称之为是非侵入式,也可以说是可插拔的。
第三节 案例中的分页功能
1、首页超链接
<a th:href="@{/get/page/1}">显示分页数据</a>
2、handler 方法
@RequestMapping("/get/page/{pageNo}") public String getPage( @PathVariable("pageNo") Integer pageNo, Model model) {
<span class="token comment">// PageInfo 对象封装了和分页相关的所有信息</span> <span class="token class-name">PageInfo</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">Emp</span><span class="token punctuation">></span></span> pageInfo <span class="token operator">=</span> empService<span class="token punctuation">.</span><span class="token function">getPageInfo</span><span class="token punctuation">(</span>pageNo<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 将 PageInfo 对象存入模型</span> model<span class="token punctuation">.</span><span class="token function">addAttribute</span><span class="token punctuation">(</span><span class="token string">"pageInfo"</span><span class="token punctuation">,</span> pageInfo<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token string">"emp-page"</span><span class="token punctuation">;</span>
}
3、service 方法
@Override public PageInfo<Emp> getPageInfo(Integer pageNo) {
<span class="token comment">// 1、确定每页显示数据的条数</span> <span class="token keyword">int</span> pageSize <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span> <span class="token comment">// 2、设定分页数据:开启分页功能。开启后,后面执行的 SELECT 语句会自动被附加 LIMIT 子句,</span> <span class="token comment">// 而且会自动查询总记录数</span> <span class="token class-name">PageHelper</span><span class="token punctuation">.</span><span class="token function">startPage</span><span class="token punctuation">(</span>pageNo<span class="token punctuation">,</span> pageSize<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 3、正常执行查询</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">Emp</span><span class="token punctuation">></span></span> empList <span class="token operator">=</span> empMapper<span class="token punctuation">.</span><span class="token function">selectAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 4、封装为 PageInfo 对象返回</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">PageInfo</span><span class="token generics"><span class="token punctuation"><</span><span class="token punctuation">></span></span><span class="token punctuation">(</span>empList<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
4、页面展示
[1]显示数据
……
<tr th:each="emp : ${pageInfo.list}">
……
[2]显示翻页导航栏
<span th:if="${pageInfo.hasPreviousPage}"> <a th:href="@{/get/page/1}">首页</a> <a th:href="@{/get/page/}+${pageInfo.prePage}">上一页</a> </span>
<span th:each="navigator : ${pageInfo.navigatepageNums}">
<span class="token comment"><!-- th:if 判断当前标签是否是当前页 --></span> <span class="token comment"><!-- 如果不是当前页则显示超链接 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name"><span class="token namespace">th:</span>if</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${navigator != pageInfo.pageNum}<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>@{/get/page/}+${navigator}<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">'</span>[<span class="token punctuation">'</span>+${navigator}+<span class="token punctuation">'</span>]<span class="token punctuation">'</span><span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span> <span class="token comment"><!-- 如果是当前页则显示页码本身 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name"><span class="token namespace">th:</span>if</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${navigator == pageInfo.pageNum}<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">'</span>[<span class="token punctuation">'</span>+${navigator}+<span class="token punctuation">'</span>]<span class="token punctuation">'</span><span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span>
</span>
<span th:if="${pageInfo.hasNextPage}">
<a th:href="@{/get/page/}+${pageInfo.nextPage}">下一页</a>
<a th:href="@{/get/page/}+${pageInfo.pages}">最后一页</a>
</span>
<span th:text="${pageInfo.pageNum}+'/'+${pageInfo.pages}"></span>
[3]打印的 SQL 语句
5、为什么是 PageInfo 而不是 Page
①List接口的具体实现
当我们开启了分页功能后,查询一个 List 集合,实际返回的是: com.github.pagehelper.Page 类型。这个 Page 类继承了 ArrayList,所以也兼容 List 接口类型。
②提出问题
如果我们将 Page 类型的对象存入模型,转发到视图模板上显示数据,会存在一个问题:视图模板技术只承认这个对象是一个 List 集合,不识别 List 集合之外的其它属性。
这一点在其他场合也需要注意:我们开发时尽量不要继承 ArrayList、HashMap 等类似的集合实现类。如果继承了,那么页面视图模板技术或其他表达式往往只能识别我们的对象是一个集合,而无法访问额外封装的其他属性。
所以 Page 对象需要封装为 PageInfo,让 list、pageNum 等等数据作为 PageInfo 对象的属性;PageInfo 本身并不是一个 List 类型的集合。
第四节 增删改查
相关知识合集
总结
主要是参考
代码重工-SSM整合1.0