ssm整合CRUD(典藏版)
目录
前言
ssm框架整合之后,我们需要用其进行一个简单的CRUD。那么该如何进行呢?步骤是怎样的呢?本文将会从最开始环境搭建到最后所有功能的开发具体实现,一步步教会你改如何使用SSM框架进行CRUD。让我们开始吧。
1 准备工作
1.1 创建工程
本案例使用工具:
工具 | 版本 |
---|---|
IDEA | 2021.3 |
MYSQL | 5.0 |
maven | 3.8.4 |
- IDEA中创建maven工程,准备好基础包。
包名 | 作用 |
---|---|
entity | 存放实体类 |
handler | 存放控制器类 |
service | 存放service类和其实现类 |
mapper | 存放mapper接口 |
test | 存放测试类 |
- 注意设置maven本地仓库和使用自己的设置(防止都在默认的c盘,导致占用c盘空间过多)
1.2 物理建模
物理建模顾名思义就是在数据库中创建一个具体的table表,在数据库中实实在在存在的。那么本文以t-emp表为例。
下图给出数据库名称和表中字段名。
1.3 逻辑建模
物理建模完成之后,我们要在java代码中创建其实体类,即逻辑视图,以便将数据库与java代码进行绑定,便于后续操作。
public class Emp {
private Integer empId;
private String empName;
private Double empSalary;
public Emp() {
}
public Emp(Integer empId, String empName, Double empSalary) {
this.empId = empId;
this.empName = empName;
this.empSalary = empSalary;
}
public Integer getEmpId() {
return empId;
}
public void setEmpId(Integer empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Double getEmpSalary() {
return empSalary;
}
public void setEmpSalary(Double empSalary) {
this.empSalary = empSalary;
}
@Override
public String toString() {
return "Emp{" +
"empId=" + empId +
", empName='" + empName + '\'' +
", empSalary=" + empSalary +
'}';
}
}
1.4引入依赖
将整个SSM整合需要的依赖全部用maven配置。其余按需添加
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.atguigu.ssm</groupId>
<artifactId>demo-ssm-test</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<!-- 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>
<!--分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.1</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
1.5 加入日志配置文件
日志文件对于我们进行调试代码有很好的作用,我们可以使用日志配置文件进行更好的查询到异常问题所在。
注意:配置文件全部放在resources目录下。
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
<!-- 指定日志输出的位置 -->
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- 日志输出的格式 -->
<!-- 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 -->
<pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern>
</encoder>
</appender>
<!-- 设置全局日志级别。日志级别按顺序分别是:DEBUG、INFO、WARN、ERROR -->
<!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
<root level="INFO">
<!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->
<appender-ref ref="STDOUT" />
</root>
<!-- 根据特殊需求指定局部日志级别 -->
<logger name="org.springframework.web.servlet.DispatcherServlet" level="DEBUG" />
</configuration>
全局日志级别我们一般都设置为debug。其余根据需求进行设置。比如说test测试类。
2 连接数据库并进行测试
2.1 创建jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:13306/mybatis-example
jdbc.username=root
jdbc.password=abc123
2.2 创建Spring配置文件
spring-persist.xml
创建spring-persist.xml配置文件引入jdbc.properties要注意引入context空间,如果不引入,接下来的操作会报各种错误。比如说:
引入名称空间:
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
2.3 在Spring配置文件中引入jdbc.properties
<!-- 引入外部文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
2.4 在spring配置文件中配置数据源
<!-- 装配数据源(使用druid数据库连接池)-->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="url" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
</bean>
2.5 创建junit测试类测试
①在日志配置文件中为测试类设置日志级别
<logger name="src/test/java/com/atguigu/ssm/SSMTest.java" level="DEBUG"/>
② 在test目录下创建一个测试类SSMTest
@SpringJUnitConfig(locations = {"classpath:spring-persist.xml"})
public class SSMTest {
@Autowired
private DruidDataSource dataSource;
//使用日志进行输出,需要在logback.xml中设置类的日志级别为DUBUG
Logger logger = LoggerFactory.getLogger(getClass());
@Test
public void testConn() throws SQLException {
DruidPooledConnection connection = dataSource.getConnection();
//使用日志级别输出
logger.debug(connection.toString());
}
}
@SpringJUnitConfig -----spring整合junit5单元测试注解,指定spring配置文件位置,自动加载上下文。
注意:
我们使用的日志文件导入的包是:org.slf4j.Logge
千万不要导错了。
3 spring整合mybatis
3.1 创建mybatis的配置文件
mybatis-config.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"/>
</settings>
<!-- 设置实体类所在包的别名-->
<typeAliases>
<package name="com.atguigu.entity"/>
</typeAliases>
</configuration>
3.2 测试mybatis
① 创建Mapper接口
public interface EmpMapper {
List<Emp> getAllEmp();
}
以查询全部数据为例。
② 创建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="com.atguigu.mapper.EmpMapper">
<!--List<Emp> getAllEmp();-->
<select id="getAllEmp" resultType="Emp">
select * from t_emp
</select>
</mapper>
③ 在junit测试类中装配Mapper接口
@SpringJUnitConfig(locations = {"classpath:spring-persist.xml"})
public class SSMTest {
@Autowired
private DruidDataSource dataSource;
@Autowired
private EmpMapper empMapper;
//使用日志进行输出,需要在logback.xml中设置类的日志级别为DUBUG
Logger logger = LoggerFactory.getLogger(getClass());
@Test
public void testList(){
List<Emp> empList = empMapper.getAllEmp();
for (Emp emp : empList) {
System.out.println("emp=" +emp);
}
}
}
3.3 配置spring配置文件
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd ">
<!-- 引入外部文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 装配数据源(使用druid数据库连接池)-->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="url" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
</bean>
<!-- 设置自动扫描service的包-->
<context:component-scan base-package="com.atguigu.service"/>
<!-- 整合mybatis-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 指定mybatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!--指定mapper.xml-->
<property name="mapperLocations" value="classpath:mappers/*Mapper.xml"/>
<!--装配数据源-->
<property name="dataSource" ref="druidDataSource"/>
<!--配置分页插件-->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<props>
<!--设置reasonable为true表示将页码进行合理化ixuzheng,页码的有效范围是1-总页数-->
<prop key="reasonable">true</prop>
<!--数据库方言,即同样的sql语句在不同数据库中语法会有差异。默认mysql-->
<prop key="helperDialect">mysql</prop>
</props>
</property>
</bean>
</array>
</property>
</bean>
<!--配置扫描Mapper接口到IOC容器-->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.atguigu.mapper"/>
</bean>
<!-- 配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="druidDataSource"/>
</bean>
<!-- 开启声明式事务-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
注意:
- 注意开启注解声明式事务需要引入的名称空间为
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd ">
- 注意配置sqlsessionFactoryBean的时候,要将mapper.xml中开启对哪一个mapper接口的配置,如果不写,会报错
Error creating bean with name ‘sqlSessionFactory’ defined in class path resource [spring-persist.xml]: Invocation of init method failed; nested exception is org.springframework.core.NestedIOException: Failed to parse mapping resource
应该这样写
<?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="com.atguigu.mapper.EmpMapper">
</mapper>
3.4 测试Spring
①创建Service接口
List<Emp> getALL();
② 创建Service类
在需要使用事务的方法上加@Transaction注解,readOnly ----只读
@Service
public class EmpServiceImpl implements EmpService {
@Autowired
private EmpMapper empMapper;
@Override
@Transactional(readOnly = true)
public List<Emp> getALL() {
return empMapper.getAllEmp();
}
}
③ 测试
@Autowired
private EmpService empService;
@Test
public void testtx(){
List<Emp> empList = empService.getALL();
for (Emp emp : empList) {
System.out.println("emp=" +emp);
}
}
4 web.xml
4.1 生成web.xml
在pom.xml中将当前module的打包方式修改为war。
<packaging>war</packaging>
4.2 设置web工程
4.3 配置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">
<!-- 配置contextLoaderListener-->
<!-- 使用contextConfigLocation读取配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-persist.xml</param-value>
</context-param>
<!-- 配置监听器-->
<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>
<!-- 指定springmvc-config.xml-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-config.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>
<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>
<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>
</web-app>
5 创建SpringMVC的配置文件
springmvc-config.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="com.atguigu.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>
<!--view-controller-->
<mvc:view-controller path="/" view-name="index"/>
<!--默认访问处理器-->
<mvc:default-servlet-handler/>
<!--注解驱动-->
<mvc:annotation-driven/>
</beans>
6 显示首页
① 创建首页对应的视图模板文件
index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body style="text-align: center">
<h1>首页</h1>
</body>
</html>
②配置访问首页的view-controller
<mvc:view-controller path="/" view-name="index"/>
一般默认首页是index。
小结
经过前面的六个步骤,基本准备工作已经完成。其中1-3步骤是持久层操作,4-6是表述层操作。
下面让我们进行具体功能开发吧。
在此之前我们先将后面的地址使用Rest风格进行规范下吧。
功能 | 地址 | 请求方式 |
---|---|---|
删除 | /emp/{empId}/{pageNo} | DELETE |
前往新增页面 | /emp/add | view-controller |
提交新增表单 | /emp | POST |
前往更新页面 | /emp/{empId}/{pageNo} | GET |
提交更新表单 | /emp | PUT |
7 显示数据列表
7.1 创建EmpHandler类并完成编写
①首页上设置一个超链接,点击超链接跳转到显示全部数据页面
<a th:href="@{/get/all}">显示全部数据</a><br>
②在类上标记@Controller注解
③在handler中装配EmpService
前面我们在进行测试的时候就已经将mapper接口和mapper.xml以及empService接口及实现类中查询全部数据的代码已经完成了,现在我们只需要编写EmpHandler。
@Controller
public class EmpHandler {
@Autowired
private EmpService empService;
@RequestMapping("/get/all")
public String getALLEmpList(Model model){
//调用EmployeeService的方法获取所需数据
List<Emp> empList = empService.getALL();
//将EmployeeService的方法返回的数据存入模型
model.addAttribute("empList",empList);
//返回逻辑视图
return "emp-list";
}
7.2 创建逻辑视图对应的视图模板页面
创建emp-list.html页面来展示全部数据页面。
① 从请求域 读取要显示的数据
②遍历数据集合显示数据
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
table{
border-collapse: collapse;
margin: 0px auto 0px auto;
}
table th,td {
border: 1px solid black;
text-align: center;
}
</style>
</head>
<body>
<table>
<tr>
<td>ID</td>
<td>empName</td>
<td>empSalary</td>
</tr>
<tbody th:if="${#lists.isEmpty(empList)}">
<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}">这里显示员工姓名</td>
<td th:text="${emp.empSalary}">这里显示员工工资</td>
</tr>
</tbody>
</table>
<a th:href="@{/}">回首页</a>
</body>
</html>
我们还可以设置一个超链接返回首页。
8 分页显示数据列表
当数据很多的时候,我们适当分页并设置简单导航来使得查看数据更加便捷。
8.1 环境准备
① 导入依赖
<!--分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.1</version>
</dependency>
②在SqlsessionFactoryBean中配置PageHelper插件
<!--配置分页插件-->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<props>
<!--设置reasonable为true表示将页码进行合理化ixuzheng,页码的有效范围是1-总页数-->
<prop key="reasonable">true</prop>
<!--数据库方言,即同样的sql语句在不同数据库中语法会有差异。默认mysql-->
<prop key="helperDialect">mysql</prop>
</props>
</property>
</bean>
</array>
</property>
8.2在首页添加超链接,需要考虑页码值(pageNo)传入
<a th:href="@{/get/page/1}">显示分页数据</a>
这里我们默认设置点击超链接,跳转页面显示从第一页开始。
8.3 service方法中实现分页功能
①empservice接口
```java
//分页实现
PageInfo<Emp> getPageInfo(Integer pageNo);
```
②实现类
@Override
public PageInfo<Emp> getPageInfo(Integer pageNo) {
//设置每页显示的数据条数
int pageSize = 6;
//设定分页数据,开启分页功能
PageHelper.startPage(pageNo,pageSize);
//执行查询功能
List<Emp> empList = empMapper.getAllEmp();
//封装为pageInfo对象返回
return new PageInfo<>(empList);
}
8.4 EmpHandler实现
@RequestMapping("/get/page/{pageNo}")
public String getPage(
//传入页码值
@PathVariable("pageNo")Integer pageNo,
Model model
){
PageInfo<Emp> pageInfo = empService.getPageInfo(pageNo);
//分页数据存入模型
model.addAttribute("pageInfo",pageInfo);
//返回逻辑视图
return "emp-page";
}
注意映射文件中页码值不能写具体数据,那样就直接写死了。
8.5 完成页面显示
创建emp-page.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
table{
border-collapse: collapse;
margin: 0px auto 0px auto;
}
table th,td {
border: 1px solid black;
text-align: center;
}
</style>
</head>
<body>
<table>
<tr>
<td>ID</td>
<td>empName</td>
<td>empSalary</td>
</tr>
<tbody th:if="${#lists.isEmpty(pageInfo.list)}">
<tr>
<td colspan="3">抱歉,没有查询到数据!</td>
</tr>
</tbody>
<tbody th:if="${not #lists.isEmpty(pageInfo.list)}">
<tr th:each="emp:${pageInfo.list}">
<td th:text="${emp.empId}">这里显示员工ID</td>
<td th:text="${emp.empName}">这里显示员工姓名</td>
<td th:text="${emp.empSalary}">这里显示员工工资</td>
</tr>
<tr>
<td colspan="3">
<!--判断是否有上一页-->
<span th:if="${pageInfo.hasPreviousPage}">
<a th:href="@{/get/page/1}">首页</a>
<!-- 不能是@{/get/page/prePage},如果这样写就变成路径了。-->
<a th:href="@{/get/page/}+${pageInfo.prePage}">上一页</a>
</span>
<!--循环页码,判断是否是当前页[1]-->
<span th:each="navigator:${pageInfo.navigatepageNums}">
<!--如果不是,显示可跳转的超链接-->
<a th:if="${navigator != pageInfo.pageNum}"
th:href="@{/get/page/}+${navigator}"
th:text="'['+${navigator}+']'"></a>
<!--如果是当前页,显示页码-->
<span th:if="${navigator == pageInfo.pageNum}"
th:text="'['+${navigator}+']'">
</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>
</td>
</tr>
</tbody>
<tr>
<td colspan="3">
<!--绑定值改变事件响应函数-->
<input id="jumpToPageNumInput" type="text" name="jumpToPageNum" placeholder="请输入你想直接跳转的页码"/>
</td>
</tr>
</table>
<!--编辑点击响应函数-->
<script type="text/javascript">
// 获取页码文本框的元素对象
var jumpPageNumEle = document.getElementById("jumpToPageNumInput");
// 给页码文本框绑定至改变响应函数
jumpPageNumEle.onchange = function () {
// 触发值改变响应函数后,获取当前文本框中用户输入的值
var targetNum = this.value;
// 检测用户输入的数据是否是数字
if(isNaN(targetNum)){
// 如果不是数字则恢复文本框
this.value="";
// 当前函数结束
return ;
}
//如果用户输入合法,则跳转页面
//[[@{/get/page/}]] 表示解析thymeleaf表达式
window.location.href="[[@{/get/page/}]]" + targetNum;
}
</script>
<a th:href="@{/}">首页</a><br>
</body>
</html>
9 删除操作
9.1 在页面上给每一条记录编写超链接
<tr>
<th>ID</th>
<th>NAME</th>
<th>SALARY</th>
<th>删除</th>
<th>更新</th>
</tr>
<!--设置删除超链接并绑定事件-->
<td>
<a onclick="convertMethod(this,event)"
th:href="@{/emp/}+${emp.empId}+'/'+${pageInfo.pageNum}">删除</a>
</td>
9.2 转换请求方式,将点击超链接的GET请求转换为最终的DELETE请求
我们的思路是提供一个空表单,作为通用组件。
<!--提供一个空表单,实现请求转换-->
<!--id作用是通过js代码获取表单对象,rest风格要求将post请求,以_method为参数名,delete为参数值转换请求-->
<form id="convertFrom" method="post" >
<input type="hidden" name="_method" value="delete">
</form>
配套的js代码
<!--给每一个删除超链接绑定单击响应函数-->
<script type="text/javascript">
function convertMethod(anchorElement,event) {
//获取超链接原本要访问的目标地址
var targetURL =anchorElement.href;
//获取表单对象
var formEle = document.getElementById("convertFrom");
//把超链接要访问的地址设置给表单action属性
formEle.action = targetURL;
//提交表单
formEle.submit();
//取消控件的默认行为,让超链接不会跳转
event.preventDefault();
}
</script>
9.3 mapper接口及配置文件
void deleteEmpByPrimaryId(Integer empId);
<!-- void deleteEmpByPrimaryId(Integer empId);-->
<delete id="deleteEmpByPrimaryId">
delete from t_emp where emp_id = #{empId}
</delete>
9.4 service接口及实现类
//删除
void doDeleteEmpByPrimaryId(Integer empId);
@Override
public void doDeleteEmpByPrimaryId(Integer empId) {
empMapper.deleteEmpByPrimaryId(empId);
}
9.5 handler类
@RequestMapping(value="/emp/{empId}/{pageNo}",method = RequestMethod.DELETE)
public String doDelete(
@PathVariable("empId")Integer empId,
@PathVariable("pageNo")Integer pageNo
){
empService.doDeleteEmpByPrimaryId(empId);
return "redirect:/get/page/"+pageNo;
}
10 新增操作
10.1 跳转到表单(edit-add.html)
① 编写超链接
<a th:href="@{/emp/add}">添加数据</a>
②在springmvc-config.xml中配置
<mvc:view-controller path="/emp/add" view-name="emp-add"/>
③创建表单所在的视图模板文件(edit-add.html)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
table{
border-collapse: collapse;
margin: 0px auto 0px auto;
}
table th,td {
border: 1px solid black;
text-align: center;
}
</style>
</head>
<body>
<form th:action="@{/emp}" method="post">
姓名:<input type="text" name="empName"/><br/>
工资:<input type="text" name="empSalary"/><br/>
<button type="submit">保存</button>
</form>
</body>
</html>
10.2 提交表单
①mapper接口及配置
void insert(Emp emp);
<!-- void insert(Emp emp);-->
<insert id="insert">
insert into t_emp values(null,#{empName},#{empSalary})
</insert>
②serivce方法及实现类
//新增
void doAdd(Emp emp);
@Override
public void doAdd(Emp emp) {
empMapper.insert(emp);
}
③handler方法
@RequestMapping(value="/emp",method = RequestMethod.POST)
public String doSave(
//使用实体类接收发送过来的请求参数
Emp emp ){
empService.save(emp);
//跳转到最后一页,Integer.MAX_VALUE---为了确保直接前往最后一页
return "redirect:/get/page/"+Integer.MAX_VALUE;
}
11 更新操作(回显+提交)
11.1 跳转到表单页面(emp-edit.html),回显数据(本质是查询)
①编写超链接,传参数:empId和pageNum
<tr>
<td>ID</td>
<td>empName</td>
<td>empSalary</td>
<td>删除</td>
<td>更新</td>
</tr>
<td>
<a th:href="@{/emp/}+${emp.empId}+'/'+${pageInfo.pageNum}">更新</a>
</td>
②mapper接口及配置文件
Emp selectedEmpByPrimaryId(Integer empId);
<!-- Emp selectedEmpByPrimaryId(Integer empId);-->
<select id="selectedEmpByPrimaryId" resultType="emp">
select emp_id,emp_name,emp_salary from t_emp where emp_id=#{empId}
</select>
③ service方法及实现类
//查询
Emp selectEmpById(Integer empId);
@Override
public Emp selectEmpById(Integer empId) {
return empMapper.selectedEmpByPrimaryId(empId);
}
④handler方法
@RequestMapping(value="/emp/{empId}/{pageNo}",method = RequestMethod.GET)
public String doFormResisPlayer(
@PathVariable("empId") Integer empId,
@PathVariable("pageNo") Integer pageNo,
Model model
){
Emp emp = empService.getEmpById(empId);
//将实体类对象存入模型
model.addAttribute("emp",emp);
//前往表单页面
return "emp-edit";
}
④ 创建表单所在的视图模板文件
emp-edit
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>更新</title>
</head>
<body>
<form th:action="@{/emp}" method="post">
<!--id 页数等都要回显,但是用户不关心,所以用隐藏域-->
<input type="hidden" name="_method" value="put"/>
<input type="hidden" name="pageNo" th:value="${pageNo}"/>
<input type="hidden" name="empId" th:value="${emp.empId}"/>
姓名:<input type="text" name="empName" th:value="${emp.empName}"/><br/>
工资:<input type="text" name="empSalary" th:value="${emp.empSalary}"/><br/>
<button type="submit">更新</button>
</form>
</body>
</html>
11.2 提交表单
①mapper接口及配置文件
void updateByPrimaryKey(Emp emp);
<!-- void updateByPrimaryKey(Emp emp);-->
<update id="updateByPrimaryKey">
update t_emp set emp_name=#{empName},emp_salary=#{empSalary} where emp_id = #{empId}
</update>
② service方法及实现类
void doUpdate(Emp emp);
@Override
public void doUpdate(Emp emp) {
empMapper.updateByPrimaryKey(emp);
}
③ handler方法
@RequestMapping(value = "/emp",method = RequestMethod.PUT)
public String doUpdate(
Emp emp,
@RequestParam("pageNo") Integer pageNo
){
empService.doUpdate(emp);
// 跳转到最后一页
return "redirect:/get/page/"+pageNo;
}
总结
至此我们已经完成了基于ssm框架基本的crud操作,可以将此案例作为一个练手项目。
不足之处还请多多指教。