尚硅谷SSM框架——SSM实战演练学习笔记

一、搭建maven工程

在这里插入图片描述

1.1、补齐目录

先项目上右键,选择属性
先去掉,然后再勾上下图选项
在这里插入图片描述
在这里插入图片描述

1.2、配置生成的web.xml的位置

在这里插入图片描述
在这里插入图片描述

二、 通过pom.xml引进相关jar依赖

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.atguigu</groupId>
  <artifactId>ssm-crud</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  
  <dependencies>
  
  	<!-- spring-mvc、spring -->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-webmvc</artifactId>
	    <version>5.3.13</version>
	</dependency>


	<!-- spring-jdbc事务处理 -->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-jdbc</artifactId>
	    <version>5.3.13</version>
	</dependency>
    
    <!-- spring面向切面编程 -->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-aspects</artifactId>
	    <version>5.3.13</version>
	</dependency>
	
	<!-- mybatis -->
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
	<dependency>
	    <groupId>org.mybatis</groupId>
	    <artifactId>mybatis</artifactId>
	    <version>3.4.2</version>
	</dependency>
	
	<!-- mybatis和spring整合 -->
	<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
	<dependency>
	    <groupId>org.mybatis</groupId>
	    <artifactId>mybatis-spring</artifactId>
	    <version>1.3.1</version>
	</dependency>
	
	<!-- 数据库连接池 -->
    <!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
	<dependency>
	    <groupId>c3p0</groupId>
	    <artifactId>c3p0</artifactId>
	    <version>0.9.1.2</version>
	</dependency>
	
    <!-- mysql驱动 -->
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.26</version>
    </dependency>
    
    <!-- jstl -->
    <!-- https://mvnrepository.com/artifact/jstl/jstl -->
    <dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>

	<!-- servlet-api -->
    <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
	<dependency>
	    <groupId>javax.servlet</groupId>
	    <artifactId>javax.servlet-api</artifactId>
	    <version>3.1.0</version>
	    <scope>provided</scope>
	</dependency>


	<!-- junit -->
    <!-- https://mvnrepository.com/artifact/junit/junit -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    
  </dependencies>
</project>

三、 引进bootstrap和jQuery

https://v3.bootcss.com/
在这里插入图片描述

3.1、使用bootstrap

在这里插入图片描述

在这里插入图片描述
引入基本样式css和JavaScript和jQuery
在这里插入图片描述
使用
在这里插入图片描述
在这里插入图片描述

四、配置相关xml文件

4.1、配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.5" 
	xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://JAVA.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

	<!-- ====================Spring 的配置,启动spring容器========================= -->
    <!-- 配置使web项目启动就去找applicationContext.xml配置文件,进行解析 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
     <!-- 监听器,tomcat服务启动的时候,自动加载spring的核心容器 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <!-- ====================Spring MVC前端控制器的配置,拦截所有请求====================== -->
    <servlet>
        <servlet-name>springDispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param><!--init-param 指定spring-mvc的配置文件的路径 -->
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- Map all requests to the DispatcherServlet for handling
         将所有请求映射到DispatcherServlet进行处理 -->
    <servlet-mapping>
        <servlet-name>springDispatcherServlet</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>forceResponseEncoding</param-name>
            <param-value>true</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>

    <!-- ====================配置restful风格过滤器====================== -->
    <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>

附:
servlet-name标签出错的解决方案
在这里插入图片描述
在这里插入图片描述

4.2、配置spring的配置文件applicationContext.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:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	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-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

	<!-- spring主要配置和业务逻辑有关的 -->
	
	<!-- ================================组件扫描================================ -->
	<context:component-scan base-package="com.atguigu" >
		<!-- 扫描除了@Controller注解的组件  -->
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>
	
	<!-- ================================配置数据源================================ -->
	<context:property-placeholder location="classpath:db.properties"/>
	<!-- 读取数据源 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="${jdbc.driver}"></property>
		<property name="jdbcUrl" value="${jdbc.url}"></property>
		<property name="user" value="${jdbc.username}"></property>
		<property name="password" value="${jdbc.password}"></property>
	</bean>
	
	<!-- ========================spring整合Mybatis================================ -->
	<!-- 1、Mybatis的sqlsession的创建 -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" >
		<!-- Mybatis的全局配置文件 -->
		<property name="configLocation" value="classpath:mybatis-config.xml"></property>
		<!-- 数据源 -->
		<property name="dataSource" ref="dataSource"></property>
		<!-- Mybatis的SQL映射文件,这样就不用同名同位置了 -->
		<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
	</bean>

	<!--配置扫描器,将mybatis接口的实现加入到ioc容器中-->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<!--扫描所有dao接口的实现,加入到ioc容器中-->
		<property name="basePackage" value="com.atguigu.crud.dao"></property>
	</bean>
    
	<!-- ================================配置事务管理器================================ -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<!-- 控制数据源 -->
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 事务控制 -->
	<aop:config>
		<!-- 切入点表达式 -->
		<aop:pointcut expression="execution(* com.atguigu.crud.service..*(..))" id="txPoint"/>
		<!-- 配置事务增强 -->
		<aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
	</aop:config>
	
	<!--配置事务增强,事务如何切入-->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<!-- 所有方法都是事务方法 -->
			<tx:method name="*"/>
			<!-- 以get开始的所有方法 -->
			<tx:method name="get*" read-only="true"/>
		</tx:attributes>
	</tx:advice>
	
</beans>

4.3、配置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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		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-4.3.xsd">

	<!-- SpringMVC的配置文件,包含网站跳转逻辑的控制,配置 -->
	
	<!-- ===================组件扫描=================== -->
	<context:component-scan base-package="com.atguigu" use-default-filters="false">
		<!-- 结合use-default-filters="false",只扫描Controller,标有@Controller注解的组件  -->
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>
	
	<!-- ==========使用视图解析器,代替controller中的ModelAndView ,方便页面放回===========-->
	<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/"></property><!-- 前缀 -->
		<property name="suffix" value=".jsp"></property><!-- 后缀 -->
	</bean>
	
	<!-- ===================两个标准配置===================-->
	<!--不会拦截静态资源 将springmvc不能处理的请求交给tomcat,这样就可以访问动态和静态资源了 -->
	<mvc:default-servlet-handler/>
	<!-- 支持springmvc更高级的校验,JSR303校验\快捷的ajax...,及映射动态请求-->
	<mvc:annotation-driven></mvc:annotation-driven>

</beans>

4.4、配置数据库连接文件db.properties

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm_crud?serverTimezone=Hongkong
jdbc.username=root
jdbc.password=75688

4.5、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>
		 	<!-- 将数据库中的字段转换成小驼峰命名方式,例如member_id,转换成memberId -->
		 	<setting name="mapUnderscoreToCamelCase" value="true"/>
		 </settings>
		 
		 <!-- 取别名 -->
		 <typeAliases>
		 	<package name="com.atguigu.crud.bean"></package>
		 </typeAliases>
		 
	</configuration>

五、创建数据库表

在这里插入图片描述

六、mybatis逆向工程

6.1、引入mabatis逆向工程所需依赖

在这里插入图片描述

6.2、mbg.xml

参考http://mybatis.org/generator/
在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
  <context id="DB2Tables" targetRuntime="MyBatis3">
  	<!-- 不生成注释 -->
  	<commentGenerator>
  		<property name="suppressAllComments" value="true"/>
  	</commentGenerator>
  	
  	<!-- 配置数据库连接 -->
    <jdbcConnection 
    	driverClass="com.mysql.cj.jdbc.Driver"
        connectionURL="jdbc:mysql://localhost:3306/ssm_crud?serverTimezone=Hongkong"
        userId="root"
        password="75688">
    </jdbcConnection>

    <javaTypeResolver >
      <property name="forceBigDecimals" value="false" />
    </javaTypeResolver>

	<!-- 指定javaBean生成的位置 -->
    <javaModelGenerator 
    	targetProject=".\src\main\java"
    	targetPackage="com.atguigu.crud.bean" >
      <property name="enableSubPackages" value="true" />
      <property name="trimStrings" value="true" />
    </javaModelGenerator>
	
	<!--指定sql映射文件生成的位置-->
    <sqlMapGenerator 
    	targetProject=".\src\main\resources"
    	targetPackage="mapper">
      <property name="enableSubPackages" value="true" />
    </sqlMapGenerator>

	<!--指定dao接口生成的位置,mapper接口-->
    <javaClientGenerator type="XMLMAPPER" 
    	targetProject=".\src\main\java"
	    targetPackage="com.atguigu.crud.dao">
      <property name="enableSubPackages" value="true" />
    </javaClientGenerator>

    <!-- table指定每个表的生成策略 -->
	<table tableName="tbl_emp" domainObjectName="Employee"></table>
	<table tableName="tbl_dept" domainObjectName="Department"></table>
  </context>
</generatorConfiguration>

在这里插入图片描述

6.3、使用逆向工程生成代码

参考官方文档
在这里插入图片描述
在这里插入图片描述

6.3.1、MBGTest.java

package com.atguigu.crud.test;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;

public class MBGTest {
	public static void main(String[] args) throws Exception, XMLParserException {
		System.out.println("============开始执行逆向工程============");
		List<String> warnings = new ArrayList<String>();
		boolean overwrite = true;
		File configFile = new File("mbg.xml");
		ConfigurationParser cp = new ConfigurationParser(warnings);
		Configuration config = cp.parseConfiguration(configFile);
		DefaultShellCallback callback = new DefaultShellCallback(overwrite);
		MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
		myBatisGenerator.generate(null);
		System.out.println("============执行逆向工程结束============");
	}
}

运行上面代码将自动生成逆向工程
在这里插入图片描述

七、自定义SQL查询

在这里插入图片描述
在这里插入图片描述

7.1、新增查询1

查询结果封装
在这里插入图片描述
在这里插入图片描述

7.2、新增查询2

在这里插入图片描述

在这里插入图片描述

八、使用spring单元测试

在这里插入图片描述

8.1、简单插入

@RunWith(SpringJUnit4ClassRunner.class)//使用Springtest测试框架
@ContextConfiguration(locations= {"classpath:applicationContext.xml"})
public class MapperTest {
	@Autowired
	DepartmentMapper departmentMapper ;
	
	@Autowired
	EmployeeMapper employeeMapper;
	
	@Test
	public void testCRUD() {
		//1、部门插入测试
		//departmentMapper.insertSelective(new Department(null,"销售部"));
		
		//2、员工插入测试
		employeeMapper.insertSelective(new Employee(null,"苗丹","M","0103123@qq.com",1));
	}
}

8.2、批量插入

在这里插入图片描述

@RunWith(SpringJUnit4ClassRunner.class)//使用Springtest测试框架
@ContextConfiguration(locations= {"classpath:applicationContext.xml"})
public class MapperTest {
	@Autowired
	EmployeeMapper employeeMapper;
	
	@Autowired
	SqlSession sqlSession;
	
	@Test
	public void testCRUD() {
		//批量插入员工数据
		EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
		for(int i=0;i<968;i++){
			String uid= UUID.randomUUID().toString().toString().substring(0,5)+i;
			mapper.insertSelective(new Employee(null, uid, "M", uid+"@qq.com", 1));
		}
		System.out.println("============批量插入员工数据完成============");
	}
}

九、PageHelper分页插件的使用

9.1、引进PageHelper maven依赖

在这里插入图片描述

9.2、在mybatis-config.xml注册PageHelper分页插件

在这里插入图片描述
在这里插入图片描述

十、查询功能

在这里插入图片描述
在这里插入图片描述
controller处理请求
在这里插入图片描述

Service执行业务逻辑
在这里插入图片描述
分页查询的单元测试

//使用Spring测试模块提供的测试请求功能,测试curd请求的正确性
@RunWith(SpringJUnit4ClassRunner.class)//使用Springtest测i试框架
@ContextConfiguration(locations = {"classpath:applicationContext.xml","classpath:springmvc.xml"})
@WebAppConfiguration
public class MvcTest {
	
	//传入Springmvc的ioc 
	 @Autowired
	 WebApplicationContext context;
	
	//虚拟mvc请求,获取到处理结果。
	MockMvc mockMvc ;
	
	@Before
	public void initMokcMvc(){
		mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
	}
	
	@Test
	public void testPage() throws Exception {
		//模拟发送请求,获取第5页数据,得到返回值
        MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/emps").param("pn","5"))
                .andReturn();
 
        //请求成功以后  请求域中有pageINfo;我们可以取出来pageInfo进行验证
        MockHttpServletRequest request = mvcResult.getRequest();
        PageInfo pageInfo = (PageInfo) request.getAttribute("pageInfo");
        //进行输出
        System.out.println("当前页码:"+pageInfo.getPageNum());
        System.out.println("总页码:"+pageInfo.getPages());
        System.out.println("总记录数:"+pageInfo.getTotal());
       
        int[] nums = pageInfo.getNavigatepageNums();
        System.out.println("在页面需要连续显示的页码:");
		
		for (int i:nums ) {
			System. out.print(" "+i);
		}
		System. out.println("");
		//也获取员工数据
		List<Employee> list = pageInfo.getList();
		for (Employee employee : list) {
			System.out.println("ID: "+employee.getEmpId( )+"== >Name:"+employee.getEmpName());
		}
	}
}

在这里插入图片描述

10.1、前端页面设计

在这里插入图片描述

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!--引入标签库-->
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>员工列表</title>
		<%
			pageContext.setAttribute("APP_PATH", request.getContextPath());
		%>
		
<!-- web路径:
	不以“/”开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题
	以“/”开始的开始的相对路径,找资源,以服务器为标准(http//localhost/端口号)需要加项目名;
	就是http//localhost/端口号/ssm-crud/...
	${APP_PATH}/static/bootstrap-3.3.7-dist/css/bootstrap.min.css
-->
		<!-- Bootstrap -->
		<link href="${APP_PATH}/static/bootstrap-3.4.1-dist/css/bootstrap.min.css" rel="stylesheet">
		<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
		<script src="${APP_PATH}/static/js/jquery-3.6.0.min.js"></script>
		<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
		<script src="${APP_PATH}/static/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
		
	</head>
	
	<body>
		<!-- 搭建显示页面 -->
		<div class="container">
			<!-- 整体分成四行 -->
			
			<!-- 标题 -->
			<div class="row">
				<div class="col-md-12">
					<h1>SSM-CRUD</h1>
				</div>
			</div>
			<!-- 按钮 -->
			<div class="row">
				<div class="col-md-4 col-md-offset-8">
					<button class="btn btn-primary">新增</button>
					<button class="btn btn-danger">删除</button>
				</div>
			</div>
			<!-- 表格数据 -->
			<div class="row">
				<div class="col-md-12">
					<table class="table table-hover">
						<!-- 表头 -->
						<tr>
							<th>#</th>
							<th>empName</th>
							<th>gender</th>
							<th>email</th>
							<th>deptName</th>
							<th>operator</th>
						</tr>
						<!-- 表体 -->
						<c:forEach items="${pageInfo.list}" var="emp">
							<tr>
								<td >${emp.empId}</td>
								<td >${emp.empName}</td >
								<td >${emp.gender=="M"?"male":"female"}</td >
								<td >${emp.email}</td >
								<td >${emp.department.deptName}</td >
								<td >
									<button class="btn btn-primary btn-sm">
										<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
										编辑
									</button>
									<button class="btn btn-danger btn-sm">
										<span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
										删除
									</button>
								</td >
							</tr>
						</c:forEach>
					</table>
				</div>
			</div>
			<!-- 分页信息 -->
			<div class="row">
				<!-- 分页文字信息 -->
				<div class="col-md-6">
					<span>当前${pageInfo.pageNum}页,总${pageInfo.pages}页,共${pageInfo.total}条记录</span>
				</div>
				<!-- 分页条信息 -->
				<div class="col-md-6">
					<nav aria-label="Page navigation">
						<ul class="pagination">
							<li>
								<a href="${APP_PATH}/emps?pn=1">首页</a>
							</li>
							
							<c:if test="${pageInfo.hasPreviousPage }">
								<li>
									<a href="${APP_PATH}/emps?pn=${pageInfo.pageNum-1}" aria-label="Previous"> 
										<span aria-hidden="true">&laquo;</span>
									</a>
								</li>
							</c:if>
							
							<c:forEach items="${pageInfo.navigatepageNums}" var="pageNumber">
								<c:if test="${pageNumber == pageInfo.pageNum}">
									<li class="active">
										<a href="#">${pageNumber}</a>
									</li>
								</c:if>
								<c:if test="${pageNumber != pageInfo.pageNum}">
									<li>
										<a href="${APP_PATH}/emps?pn=${pageNumber}">${pageNumber}</a>
									</li>
								</c:if>
							</c:forEach>
							
							<c:if test="${pageInfo.hasNextPage }">
								<li>
									<a href="${APP_PATH}/emps?pn=${pageInfo.pageNum+1}" aria-label="Next"> 
										<span aria-hidden="true">&raquo;</span>
									</a>
								</li>
							</c:if>
							
							<li>
								<a href="${APP_PATH}/emps?pn=${pageInfo.pages}">末页</a>
							</li>
						</ul>
					</nav>
				</div>
			</div>
		</div>
	</body>
</html>

在这里插入图片描述

10.2、返回json数据

在这里插入图片描述
在这里插入图片描述

准备通用的返回类

package com.atguigu.crud.bean;

import java.util.HashMap;
import java.util.Map;

/**
 * 通用的返回类
 */
public class Msg {
	//状态码 100-success 200-fail
	private int code;
	
	//提示信息
	private String msg;
	
	//用户返回给浏览器的数据
	private Map<String, Object> extend = new HashMap<String, Object>();
	
	/*================自定义方法开始=======================*/
	public static Msg success() {
		Msg msg = new Msg();
		msg.setCode(100);
		msg.setMsg("处理成功!");
		return  msg;
	}
	
	public static Msg fail() {
		Msg msg = new Msg();
		msg.setCode(200);
		msg.setMsg("处理失败!");
		return  msg;
	}
	
	public Msg add(String key,Object value) {
		this.getExtend().put(key, value);
		return this;
	}
	/*================自定义方法结束=======================*/
	public int getCode() {
		return code;
	}
	public void setCode(int code) {
		this.code = code;
	}
	public String getMsg() {
		return msg;
	}
	public void setMsg(String msg) {
		this.msg = msg;
	}
	public Map<String, Object> getExtend() {
		return extend;
	}
	public void setExtend(Map<String, Object> extend) {
		this.extend = extend;
	}
	
}

在这里插入图片描述
在这里插入图片描述

10.3、使用ajax

10.3.1、使用ajax发起请求

在这里插入图片描述

10.3.2、jQuery遍历语法

在这里插入图片描述

10.3.3、jQuery添加样式和标签属性

在这里插入图片描述

10.3.4、jQuery将新增控件添加到页面语法

在这里插入图片描述

10.3.5、jQuery点击事件

在这里插入图片描述

10.3.6、jQuery清空表格数据

在这里插入图片描述

十一、新增功能

在这里插入图片描述

在这里插入图片描述

11.1、前端校验

11.1.1、jQuery获取表单的值

在这里插入图片描述

11.1.2、jQuery正则表达式使用

在这里插入图片描述
在这里插入图片描述

11.2、后端数据校验

前后端都要进行数据校验
在这里插入图片描述

11.2.1、后端优化校验JSR303和Hibernate Validator

使用Hibernate Validator
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

十二、编辑功能

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

jQuery按钮点击事件

在这里插入图片描述

十三、删除功能

十四、jsp完整代码

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>employees list</title>
		<!-- 使用request获取项目路径,使用pageContext添加值到域对象中 -->
		<%
			pageContext.setAttribute("APP_PATH", request.getContextPath());
		%>
		<!-- web路径:
	不以/开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题
	以/开始的开始的相对路径,找资源,以服务器为标准(http//localhost/端口号)需要加项目名;
	就是http//localhost/端口号/crud/...
	${APP_PATH}/static/bootstrap-3.3.7-dist/css/bootstrap.min.css
  -->
		<!-- Bootstrap -->
		<link href="${APP_PATH}/static/bootstrap-3.4.1-dist/css/bootstrap.min.css" rel="stylesheet">
		<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
		<script src="${APP_PATH}/static/js/jquery-3.6.0.min.js"></script>
		<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
		<script src="${APP_PATH}/static/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
	</head>
	<body>
		<!-- 员工修改的模态框 -->
		<div class="modal fade" id="empUpdateModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
			<div class="modal-dialog" role="document">
				<div class="modal-content">
					<div class="modal-header">
						<button type="button" class="close" data-dismiss="modal" aria-label="Close">
							<span aria-hidden="true">&times;</span>
						</button>
						<h4 class="modal-title">员工修改</h4>
					</div>
					<div class="modal-body">
						<form class="form-horizontal">
							<div class="form-group">
								<label for="empName_add_input" class="col-sm-2 control-label">empName</label>
								<div class="col-sm-10">
									<p class="form-control-static" id="empName_update_static"></p>
								</div>
							</div>
							<div class="form-group">
								<label for="email_add_input" class="col-sm-2 control-label">email</label>
								<div class="col-sm-10">
									<input type="text" class="form-control" name="email" id="email_update_input" placeholder="aaa@aaa.aaa"> <span
									 class="help-block"></span>
								</div>
							</div>
							<div class="form-group">
								<label class="col-sm-2 control-label">gender</label>
								<div class="col-sm-10">
									<label class="radio-inline"> <input type="radio" name="gender" id="gender1_update_input" value="M" checked="checked"></label> <label class="radio-inline"> <input type="radio" name="gender" id="gender2_update_input" value="W"></label>
								</div>
							</div>
							<div class="form-group">
								<label class="col-sm-2 control-label">deptName</label>
								<div class="col-sm-4">
									<select class="form-control" name="dId" id="dept_update_select">

									</select>
								</div>
							</div>


						</form>
					</div>
					<div class="modal-footer">
						<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
						<button type="button" class="btn btn-primary" id="emp_update_btn">更新</button>
					</div>
				</div>
			</div>
		</div>

		<!-- 员工添加的模态框 -->
		<div class="modal fade" id=empAddModal tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
			<div class="modal-dialog" role="document">
				<div class="modal-content">
					<div class="modal-header">
						<button type="button" class="close" data-dismiss="modal" aria-label="Close">
							<span aria-hidden="true">&times;</span>
						</button>
						<h4 class="modal-title" id="myModalLabel">员工添加</h4>
					</div>
					<div class="modal-body">
						<form class="form-horizontal">
							<div class="form-group">
								<label for="empName_add_input" class="col-sm-2 control-label">empName</label>
								<div class="col-sm-10">
									<input type="text" name="empName" class="form-control" id="empName_add_input" placeholder="empName"> 
									<span id="helpBlock2" class="help-block"></span>
								</div>
							</div>
							<div class="form-group">
								<label for="email_add_input" class="col-sm-2 control-label">email</label>
								<div class="col-sm-10">
									<input type="email" class="form-control" name="email" id="email_add_input" placeholder="aaa@qq.com"> <span
									 class="help-block"></span> <span id="helpBlock2" class="help-block"></span>
								</div>
							</div>
							<div class="form-group">
								<label class="col-sm-2 control-label">性别</label>
								<div class="col-sm-10">
									<label class="radio-inline"> <input type="radio" name="gender" id="gender1_add_input" value="M" checked="checked"></label> <label class="radio-inline"> <input type="radio" name="gender" id="gender2_add_input" value="W"></label>
								</div>
							</div>
							<div class="form-group">
								<label class="col-sm-2 control-label">部门名称</label>
								<div class="col-sm-4">
									<select class="form-control" name="dId" id="dept_add_select">

									</select>
								</div>
							</div>
						</form>
					</div>
					<div class="modal-footer">
						<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
						<button type="button" class="btn btn-primary" id="emp_save_btn">保存</button>
					</div>
				</div>
			</div>
		</div>

		<!-- 搭建页面 -->
		<div class="container">
			<!-- 标题开始 -->
			<div class="row">
				<div class="col-md-12">
					<h1>SSM-CRUD</h1>
				</div>
			</div>
			<!-- 标题结束 -->
			
			<!-- 添加和删除按钮开始 -->
			<div class="row">
				<div class="col-md-4 col-md-offset-8">
					<button id="emp_add_modal_btn" class="btn btn-primary">添加</button>
					<button id="emp_delete_all_btn" class="btn btn-danger">删除</button>
				</div>
			</div>
			<!-- 添加和删除按钮结束 -->
			
			<!-- 表格数据开始 -->
			<div class="row">
				<div class="col-md-12">
					<table class="table table-hover" id="emps-table">
						<!-- 表头开始 -->
						<thead>
							<tr>
								<th><input type="checkbox" id="check_all"></th>
								<th>员工Id</th>
								<th>员工姓名</th>
								<th>性别</th>
								<th>email</th>
								<th>部门名称</th>
								<th>操作</th>
							</tr>
						</thead>
						<!-- 表头结束 -->
						
						<!-- 表体开始 -->
						<tbody>
						</tbody>
						<!-- 表体结束 -->
					</table>
				</div>
			</div>
			<!-- 表格数据结束 -->
			
			<!-- 分页和页面信息开始 -->
			<div class="row">
				<!-- 分页文字信息开始 -->
				<div class="col-md-6" id="page-info-area"></div>
				<!-- 分页文字信息结束 -->
				<!-- 分页条信息开始 -->
				<div class="col-md-6" id="page_nav_area"></div>
				<!-- 分页条信息结束 -->
			</div>
			<!-- 分页和页面信息结束 -->
		</div>

		<script type="text/javascript">
			/*===================全局变量=================*/
			var totalRecord;//总记录数
			var currentPage;//当前页码
			
			/*========页面加载完成以后,直接发送ajax请求,要到分页数据=========*/
			$(function() {
				to_page(1);//默认显示第一页
			})

			/*===================查询所有信息=================*/
			function to_page(pageNumber) {
				$.ajax({
					url: "${APP_PATH}/emps/",
					data: "pn=" + pageNumber,
					type: "GET",
					success: function(result) {
						//console.log(result);
						//1、解释并显示员工数据
						bulid_emps_table(result);
						//2、解释并显示分页文字信息
						bulid_page_info(result);
						//3、解释并显示分页导航信息
						bulid_page_nav(result);
					}
				});
			}
			
			/*=================解释并显示员工数据===============*/
			function bulid_emps_table(result) {
				//先清空表体数据
				$("#emps-table tbody").empty();
				var emps = result.extend.pageInfo.list;
				$.each(emps, function(index, item) {
					var checkBoxTd = $("<td></td>").append("<input type='checkbox' class='check_item'/>");
					var empIdTd = $("<td></td>").append(item.empId);
					var empNameTd = $("<td></td>").append(item.empName);
					var empGenderTd = $("<td></td>").append(item.gender == "M" ? 'male' : "female");
					var empEmailTd = $("<td></td>").append(item.email);
					var deptNameTd = $("<td></td>").append(item.department.deptName);
					
					var editBtn = $("<button></button>")//添加button,并返回button对象
						.addClass("btn btn-primary btn-sm edit_btn")//给button添加样式
						.append($("<span></span>").addClass("glyphicon glyphicon-pencil"))//给span添加样式
						.append("编辑");//给span添加内容
					//为编辑按钮添加一个自定义的属性,来表示当前员工id
					editBtn.attr("edit_id", item.empId);
					
					var delBtn = $("<button></button>")
						.addClass("btn btn-danger btn-sm delete_btn")
						.append($("<span></span>").addClass("glyphicon glyphicon-trash"))
						.append("删除");
					//为删除按钮添加属性表示id
					delBtn.attr("del_id", item.empId);
					
					//将编辑按钮和删除按钮放在同一个单元格中
					var btnTd = $("<td></td>")
						.append(editBtn)
						.append(" ")
						.append(delBtn);
					
					//将单元格添加到行显示
					$("<tr></tr>").append(checkBoxTd)
								  .append(empIdTd)
								  .append(empNameTd)
								  .append(empGenderTd)
								  .append(empEmailTd)
								  .append(deptNameTd)
								  .append(btnTd)
								  .appendTo("#emps-table tbody");
				})
			}

			/*=================解释并显示分页文字信息===============*/
			function bulid_page_info(result) {
				$("#page-info-area").empty()//先清空
					.append("当前" + result.extend.pageInfo.pageNum + "页,总" +
					result.extend.pageInfo.pages + "页,共" +
					result.extend.pageInfo.total + "条记录");
				
				//记录当前总记录数
				totalRecord = result.extend.pageInfo.total;
				//记录当前页吗,更新员工信息后,需返回显示当前页
				currentPage = result.extend.pageInfo.pageNum;
			}

			/*=================解释并显示分页导航信息===============*/
			function bulid_page_nav(result) {
				$("#page_nav_area").empty();//先清空
				
				var ul = $("<ul></ul>").addClass("pagination");
				//构建元素
				var firstPageLi = $("<li></li>")
						.append($("<a></a>").append("首页").attr("href", "#"));
				var prePageLi = $("<li></li>")
						.append($("<a></a>").append("&laquo;"));
				
				//如果请求结果没有前一页,则首页和前一页按钮不能点击
				if (result.extend.pageInfo.hasPreviousPage == false) {
					firstPageLi.addClass("disabled");
					prePageLi.addClass("disabled");
				} else {
					//为元素添加翻页事件
					firstPageLi.click(function() {
						to_page(1);
					});
					prePageLi.click(function() {
						to_page(result.extend.pageInfo.pageNum - 1);
					});
				}

				var nextPageLi = $("<li></li>")
					.append($("<a></a>").append("&raquo;"));
				var lastPageLi = $("<li></li>")
					.append($("<a></a>").append("末页").attr("href", "#"));
				
				//如果请求结果没有有后一页,则末页和后一页按钮不能点击
				if (!result.extend.pageInfo.hasNextPage) {
					nextPageLi.addClass("disabled");
					lastPageLi.addClass("disabled");
				} else {
					nextPageLi.click(function() {
						to_page(result.extend.pageInfo.pageNum + 1);
					});
					lastPageLi.click(function() {
						to_page(result.extend.pageInfo.pages);
					});
				}

				//页码1,2,3,4
				ul.append(firstPageLi).append(prePageLi);
				
				$.each(result.extend.pageInfo.navigatepageNums, function(index,item) {
					var numLi = $("<li></li>").append($("<a></a>").append(item));
					if (result.extend.pageInfo.pageNum == item) {
						numLi.addClass("active");
					}
					numLi.click(function() {
						to_page(item);
					});
					ul.append(numLi);
				});
				ul.append(nextPageLi).append(lastPageLi);

				//把ul加入到nav
				var navEle = $("<nav></nav>").append(ul);
				navEle.appendTo("#page_nav_area");
			}

			/*=================重置表格信息===============*/
			function reset_form(ele) {
				//清空表单内容
				$(ele)[0].reset();
				//清空表单样式
				$(ele).find("*").removeClass("has-error has-success");
				//清空校验信息
				$(ele).find(".help-block").text("");
			}

			/*=================添加功能:点击新增按钮弹出模态框===============*/
			$("#emp_add_modal_btn").click(function() {
				//清除表单数据(表单重置)
				reset_form("#empAddModal form");
				//发送ajax请求,查出部门信息,显示在下拉列表中
				getDepts("#empAddModal select");
				//弹出模态框
				$("#empAddModal").modal({
					backdrop: "static"
				});
			});
			
			/*=============查出所有部门信息,显示在下拉列表中=============*/
			function getDepts(selectName) {
				$.ajax({
					url: "${APP_PATH}/depts",
					type: "GET",
					success: function(result) {
						$(selectName).empty();//清空
						//使用each循环显示所有部门到下拉列表中
						$.each(result.extend.depts, function() {
							var optionEle = $("<option></option>")
								.append(this.deptName)
								//添加一个自定义的属性,来表示当前部门id
								.attr("value", this.deptId);
							optionEle.appendTo(selectName);
						});
					}
				});
			}
			
			/*=================校验用户名是否可用===============*/
			$("#empName_add_input").change(
				function() {
					//发送ajax请求校验用户名是否可用
					var empName = this.value;
					$.ajax({
						url: "${APP_PATH}/checkuser/",
						data: "empName=" + empName,
						type: "POST",
						success: function(result) {
							if (result.code == 100) {
								show_validate_msg(
										"#empName_add_input",
										"success", 
										"用户名可用"
										);
								$("#emp_save_btn").attr("ajax-va", "success");
							} else {
								show_validate_msg(
										"#empName_add_input",
										"error", 
										result.extend.va_msg
										);
								$("#emp_save_btn").attr("ajax-va", "error");
							}
						}
					})

				});
			
			/*=================点击保存,保存员工===============*/
			$("#emp_save_btn").click(
					function() {
						//1、模态框中填写的数据提交到服务器进行保存
						//2、先对提交给服务器的数据进行校验
						if (!validate_add_form()) {
							return false;
						}
						//1、判断之前的ajax用户名校验是否成功
						if ($(this).attr("ajax-va") == "error") {
							return false;
						}
						//保存新增数据
						$.ajax({
							url: "${APP_PATH}/emp/",
							type: "POST",
							data: $("#empAddModal form").serialize(),
							success: function(result) {
								if (result.code == 100) {
									//员工保存成功
									//1、关闭模态框
									$("#empAddModal").modal('hide');
									//2、来到最后一页,显示刚才保存的数据
									//发送ajax请求显示最后一页数据即可
									to_page(totalRecord);
								} else {
									// 显示失败信息
									if (undefined != result.extend.errorFields.email) {
										//显示邮箱的错误信息
										show_validate_msg(
											"#email_add_input",
											"error",
											result.extend.errorFields.email);
									}
									if (undefined != result.extend.errorFields.empName) {
										//员工的错误信息
										show_validate_msg(
											"#empName_add_input",
											"error",
											result.extend.errorFields.empName);
									}
								}
							}
						});
					})
					
			/*=============先对提交给服务器的数据进行校验=============*/		
			function validate_add_form() {
				//1、校验员工姓名信息
				var empName = $("#empName_add_input").val();//员工姓名获取输入框的输入值
				//a-z0-9_-六到十六位,或二到五位中文
				var regName = /(^[a-z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;//校验规则
				//使用test()进行校验,员工姓名不符合校验规则
				if (!regName.test(empName)) {
					show_validate_msg(
							"#empName_add_input", 
							"error",
							"用户名为2-5中文或4-16英文数字组合"
							);
					return false;
				}
				//2、校验邮箱信息
				var empEmail = $("#email_add_input").val();
				var regEmail = /^([a-zA-Z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/
				//邮箱不符合校验规则
				if (!regEmail.test(empEmail)) {
					show_validate_msg(
							"#email_add_input", 
							"error", 
							"邮箱格式错误"
							);
					return false;
				} else {
					show_validate_msg(
							"#email_add_input", 
							"success", 
							""
							);
				}
				return true;
			}
			
			/*===============回显校验信息===============*/
			function show_validate_msg(ele, status, msg) {
				//首先清空当前元素
				$(ele).parent().removeClass("has-success has-error");
				$(ele).next("span").text("");
				if ("success" == status) {
					$(ele).parent().addClass("has-success");
				} else if ("error" == status) {
					$(ele).parent().addClass("has-error");
				}
				$(ele).next("span").text(msg);
			}

			/*=============编辑功能:=============*/
			//1)、我们是按钮创建之前就绑定了click,所以绑不上
			//2)、可以在创建按钮的时候绑定事件
			//3)、绑定点击.live()
			//jquery新版没有live,使用on方法进行替代
			$(document).on("click", ".edit_btn", function() {
				//清除表单数据(表单重置)
				reset_form("#empUpdateModal form");
				
				//1、查出部门信息,显示部门列表
				getDepts("#empUpdateModal select");

				//2、查出员工信息,显示员工信息
				getEmp($(this).attr("edit_id"));
				
				//3、把员工的id传递给模态框的更新按钮
				$("#emp_update_btn").attr("edit_id", $(this).attr("edit_id"));
				$("#empUpdateModal").modal({
					backdrop: "static"
				});
			})

			/*=============根据id获取部门信息=============*/
			function getEmp(id) {
				$.ajax({
					url: "${APP_PATH}/emp/" + id,
					type: "GET",
					success: function(result) {
						var empData = result.extend.emp;
						$("#empName_update_static").text(empData.empName);
						$("#email_update_input").val(empData.email);
						$("#empUpdateModal input[name=empGender]").val([empData.gender]);
						$("#empUpdateModal select").val([empData.dId]);
					}
				})
			}
			
			/*=============点击更新,更新员工信息=============*/
			$("#emp_update_btn").click(function() {
				//验证邮箱是否合法
				//1、校验邮箱信息
				var empEmail = $("#email_update_input").val();
				var regEmail = /^([a-zA-Z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
				if (!regEmail.test(empEmail)) {
					show_validate_msg(
							"#email_update_input", 
							"error", 
							"邮箱格式错误"
							);
					return false;
				} else {
					show_validate_msg(
							"#email_update_input", 
							"success", 
							""
							);
				}
				//2、发送ajax请求,保存更新员工信息
				$.ajax({
					url: "${APP_PATH}/emp/" + $(this).attr("edit_id"),
					type: "PUT",
					data: $("#empUpdateModal form").serialize(),
					success: function() {
						$("#empUpdateModal").modal("hide");
						to_page(currentPage);
					}
				});
			});

			/*=============单个删除=============*/
			$(document).on("click", ".delete_btn", function() {
				//1、弹出确认删除对话框
				var empName = $(this).parents("tr").find("td:eq(2)").text();
				var empId = $(this).attr("del_id");
				if (confirm("确认删除【" + empName + "】吗?")) {
					//发送ajax请求删除
					$.ajax({
						url: "${APP_PATH}/emp/" + empId,
						type: "DELETE",
						success: function(result) {
							alert(result.msg);
							//回到本页
							to_page(currentPage);
						}
					});
				}
			});

			/*=============完成全选/全不选功能=============*/
			$("#check_all").click(function() {
				var is_All_Check = $(this).prop("checked");
				$(".check_item").prop("checked", is_All_Check);
			});

			/*=============check_item,复选框选择操作=============*/
			$(document).on("click", ".check_item", function() {
				//判断当前选择中的元素是否选满
				var flag = $(".check_item:checked").length == $(".check_item").length;
				$("#check_all").prop("checked", flag);
			});

			/*=============点击全部删除,就批量删除=============*/
			$("#emp_delete_all_btn").click(function() {
				var empNames = "";
				var del_idstr = "";
				$.each($(".check_item:checked"), function() {
					//组装员工字符串
					empNames += $(this).parents("tr").find("td:eq(2)").text() + ",";
					//组织员工id字符串
					del_idstr += $(this).parents("tr").find("td:eq(1)").text() + "-";
				});
				//去除empnames多余的“,”
				empNames = empNames.substring(0, empNames.length - 1);
				//去除员工删除id多余的“-”
				del_idstr = del_idstr.substring(0, del_idstr.length - 1);
				
				if (confirm("确认删除【" + empNames + "】吗?")) {
					//发送ajax请求
					$.ajax({
						url: "${APP_PATH}/emp/" + del_idstr,
						type: "DELETE",
						success: function(result) {
							alert(result.msg);
							//回到当前页面
							to_page(currentPage);
							$("#check_all").prop("checked", false);
						}
					})

				}
			});
		</script>
	</body>
</html>


版权声明:本文为weixin_45084986原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。