Spring + SpringMVC + Mybatis 整合,实现 CRUD (增删改查)

本文介绍了一个使用Spring+SpringMVC+MyBatis整合方案的实战项目。通过搭建环境、引入框架、实现CRUD操作,展示了如何构建一个完整的SSM项目,并使用了PageHelper进行分页处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这次暑假在腾讯课堂学习了尚硅谷SSM整合视频(SSM开发是目前企业流行使用的框架整合方案)免费教程,该视频讲解了 Spring + SpringMVC + MyBatis 整合实现了 CRUD (增删改查)。将代码整理,运行成功后,写下这篇博文记录一下。

1.创建 Maven 项目,配置 Maven

maven 项目的目录 创建 Maven 项目

配置 maven 的 .m2(我的是 C:\Users\cjc.m2) 目录下的 settings.xml 文件

使用 使用阿里云的 maven 仓库 配置 Maven

指定 jdk 的版本

配置 Maven

2.在 pom.xml 引入 jar 包

配置 pom.xml

<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.atguigu</groupId>
  <artifactId>ssm</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>ssm-crud Maven Webapp</name>
  <url>http://maven.apache.org</url>

  <!-- 引入项目依赖 jar 包 -->
  <dependencies>
  <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>5.0.0</version>
  </dependency>

    <!-- MBG -->
    <!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
  <dependency>
      <groupId>org.mybatis.generator</groupId>
      <artifactId>mybatis-generator-core</artifactId>
      <version>1.3.5</version>
  </dependency>


    <!-- Spring SpringMvc -->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.3.7.RELEASE</version>
  </dependency>

  <!-- 返回 json 字符串的支持 -->
  <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
  <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.8.8</version>
  </dependency>

  <!-- 添加 file upload 组件,支持文件上传 -->
  <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
  <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
  </dependency>

  <!--  JSR303 -->
  <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
  <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>5.4.1.Final</version>
  </dependency>

    <!-- Spring JDBC -->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>4.3.7.RELEASE</version>
  </dependency>

    <!-- 导入单元测试模块 spring-test -->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>4.3.7.RELEASE</version>
      <scope>test</scope>
  </dependency>


    <!-- Spring 面向切面编程 -->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>4.3.7.RELEASE</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>


    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.41</version>
  </dependency>

    <!-- jstl servlet-api junit-->
    <!-- https://mvnrepository.com/artifact/jstl/jstl -->
  <dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
  </dependency>

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


    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <finalName>ssm-crud</finalName>
  </build>

  <properties>  
        <!-- 文件拷贝时的编码 -->  
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>  
        <!-- 编译时的编码 -->  
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>  
    </properties>
  </project>

3.引入 Bootstrap, jQuery

引入 Bootstrap, jQuery

4.配置 web.xml, SpringMVC, Spring

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>ssm-crud</display-name>

  <!-- 1、启动 Spring 的容器 -->
  <!--  needed for ContextLoaderListener -->
  <context-param>
  	<param-name>contextConfigLocation</param-name>
  	<param-value>classpath:applicationContext.xml</param-value>
  </context-param>

  <listener>
 		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <!-- 2、springmvc 的前端控制器,拦截所以请求 -->
  <!-- 写错了 diapatcher 会报 java.io.FileNotFoundException:
   Could not open ServletContext resource [/WEB-INF/diapatcher-servlet.xml] -->
   <!--
   		默认为 WEB-INF 下的[servlet-name]-servlet.xml
   		也可以使用 init-param 显式指定
  		<servlet>
			<servlet-name>dispather</servlet-name>
			<servlet-class>
				org.springframework.web.servlet.DispatcherServlet
			</servlet-class>
			<init-param>
				<param-name>contextConfigLocation</param-name>
				<param-value>/WEB-INF/**.xml</param-value>
			</init-param>
			<load-on-startup>1</load-on-startup>
		</servlet>
		<servlet-mapping>
			<servlet-name>dispather</servlet-name>
			<url-pattern>/**</url-pattern>
		</servlet-mapping>
    -->
	<servlet>
		<servlet-name>dispatcher</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
	    <servlet-name>dispatcher</servlet-name>
	    <url-pattern>/</url-pattern>
	</servlet-mapping>

	<!-- 3.字符编码过滤器 -->
	<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>

	<!-- 4.使用 Rest 风格 的 URL -->
	<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>

	<filter>
		<filter-name>HttpPutFormContentFilter</filter-name>
		<filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>HttpPutFormContentFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	 <welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>

配置 SpringMVC dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- xml必须在第一行,且不能有空格,不能重复写 	  
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	因为 applicationContext 已经包含了-->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
    	 http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- SpringMVC 的配置文件,包含网站跳转逻辑的控制, 配置 -->
	 <context:component-scan base-package="com.atguigu" use-default-filters="false">
	 	<!-- 只扫描控制器 -->
	 	<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
	 </context:component-scan>

	 <!-- 配置视图解析器,方便页面返回-->
	   <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	     <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
	     <property name="prefix" value="/WEB-INF/views/"/>
	     <property name="suffix" value=".jsp"/>
	  </bean>

	  <!-- 配置文件上传支持, 使用 apache common fileupload -->
       <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--  上传文件大小上限,单位为字节(500MB)  -->
         <property name="maxUploadSize">  
            <value>5242880000</value>  
        </property>    
        <!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
         <property name="defaultEncoding">
            <value>UTF-8</value>
        </property>
   	 </bean>  

	  <!-- 两个标准配置 -->
	  <!-- 将springmvc 不能处理的请求交给 tomcat -->
	  <mvc:default-servlet-handler />
	  <!-- 能支持 springmvc 更高级的一些功能 -->
 <mvc:annotation-driven/>
</beans>

配置 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:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
    	 	http://www.springframework.org/schema/context
    		http://www.springframework.org/schema/context/spring-context.xsd
    		http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
    	    http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

	  <context:component-scan base-package="com.atguigu">
	  	<!-- 不扫描控制器 -->
	  	<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
	  </context:component-scan>

	 <!-- Spring 的配置文件,这里主要配置和业务逻辑有关的  -->
  	<!-- 数据源、事务控制 -->
  	<context:property-placeholder location="classpath:dbconfig.properties" />

  	<bean id="pooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
  		<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
  		<property name="driverClass" value="${jdbc.driverClass}"></property>
  		<property name="user" value="${jdbc.user}"></property>
  		<property name="password" value="${jdbc.password}"></property>
  	</bean>

    <!-- 配置和 MyBatis 整合 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    	<property name="configLocation" value="classpath:mybatis-config.xml"></property>
  		<property name="dataSource" ref="pooledDataSource" />
  		<property name="mapperLocations" value="classpath:mapper/*.xml" />
	</bean>

	<!-- 配置扫描器,将mybatis 接口的实现加入到 IOC 容器中 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  		<property name="basePackage" value="com.atguigu.crud.dao" />
	</bean>


	<!-- 配置一个可以批量操作的 sqlSession -->
	<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"></constructor-arg>
		<constructor-arg name="executorType" value="BATCH"></constructor-arg>
	</bean>

	<!-- 事务控制 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  		<property name="dataSource" ref="pooledDataSource" />
	</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="*" />
			<tx:method name="get" read-only="true" />
		</tx:attributes>
	</tx:advice>
</beans>

5.MyBatis 逆向工程生成 mapper 和 xml 等文件,需要先创建两个表

DROP TABLE IF EXISTS `tbl_dept`;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tbl_dept` (
`dept_id` int(11) NOT NULL AUTO_INCREMENT,
`dept_name` varchar(255) NOT NULL,
PRIMARY KEY (`dept_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

LOCK TABLES `tbl_dept` WRITE;
INSERT INTO `tbl_dept` VALUES (1,'开发部'),(2,'测试部');
/*!40000 ALTER TABLE `tbl_dept` ENABLE KEYS */;
UNLOCK TABLES;

DROP TABLE IF EXISTS `tbl_emp`;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tbl_emp` (
  `emp_id` int(11) NOT NULL AUTO_INCREMENT,
  `emp_name` varchar(255) NOT NULL,
  `gender` char(1) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `d_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`emp_id`),
  KEY `fk_emp_dept` (`d_id`),
  CONSTRAINT `fk_emp_dept` FOREIGN KEY (`d_id`) REFERENCES `tbl_dept` (`dept_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1012 DEFAULT CHARSET=utf8;

编译执行 MBGTest.java, 还有配置文件 mbg.xml, 可以得到 MyBatis 生成的 xml 和 mapper 文件。

6.项目的两个 controller,DepartmentController.java 和 EmployeeController.java 处理 list.jsp 的 ajax 请求。

package com.atguigu.crud.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.atguigu.crud.bean.Department;
import com.atguigu.crud.bean.Msg;
import com.atguigu.crud.service.DepartmentService;

/**
 * 处理有关部门请求
 *
 *
 */
@Controller
public class DepartmentController {
	@Autowired
	private DepartmentService departmentService;

	/*
	 * 返回部门方法
	 * */
	@RequestMapping("/depts")
	@ResponseBody
	public Msg getDepts() {
		List<Department> list = departmentService.getDepts();
		return Msg.success().add("depts", list);
	}
}

package com.atguigu.crud.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.atguigu.crud.bean.Employee;
import com.atguigu.crud.bean.Msg;
import com.atguigu.crud.service.EmployeeService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import net.sf.jsqlparser.statement.create.table.Index;


/**
 * 处理员工请求
 *
 *
 */
@Controller
public class EmployeeController {

	@Autowired
	EmployeeService  employeeService;

	@ResponseBody
	@RequestMapping(value="/emp/{ids}", method=RequestMethod.DELETE)
	public Msg deleteEmpById(@PathVariable("ids")String ids) {
		if(ids.contains("-")) {
			List<Integer> del_ids = new ArrayList<>();
			String[] str_ids = ids.split("-");
			for(String string : str_ids) {
				del_ids.add(Integer.parseInt(string));
			}
			employeeService.deleteBatch(del_ids);
		} else {
			Integer id = Integer.parseInt(ids);
			employeeService.deleteEmp(id);
		}

		return Msg.success();
	}

	@ResponseBody
	@RequestMapping(value="/emp/{empId}", method=RequestMethod.PUT)
	public Msg saveEmp(Employee employee) {
		System.out.println(employee);
		employeeService.updateEmp(employee);
		return Msg.success();
	}

	@RequestMapping(value="/emp/{id}", method=RequestMethod.GET)
	@ResponseBody
	public Msg getEmp(@PathVariable("id")Integer id) {
		System.out.println(id);
		Employee employee = employeeService.getEmp(id);
		return Msg.success().add("emp", employee);
	}

	/*检查用户名是否可用*/
	@ResponseBody
	@RequestMapping("/checkuser")
	public Msg checkuser(@RequestParam("empName")String empName) {
		String regx = "(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})";
		if(!empName.matches(regx)) {
			return Msg.fail().add("va_msg", "用户名必须是 6-16 位数字和字母的组合或者2-5位中文");
		}

		boolean b = employeeService.checkUser(empName);
		if(b) {
			return Msg.success();
		} else {
			return Msg.fail().add("va_msg", "用户名不可用");
		}
	}

	@RequestMapping(value="/emp", method=RequestMethod.POST)
	@ResponseBody
	public Msg saveEmp(@Valid Employee employee, BindingResult result) {
		if(result.hasErrors()) {
			//校验失败,返回失败
			Map<String, Object> map = new HashMap<>();
			List<FieldError> errors = result.getFieldErrors();
			for(FieldError fieldError : errors) {
				System.out.println(" 错误的字段名: " + fieldError.getField());
				System.out.println(" 错误信息: " + fieldError.getDefaultMessage());
				map.put(fieldError.getField(), fieldError.getDefaultMessage());
			}
			return Msg.fail().add("errorFields", map);
		}else {
			employeeService.saveEmp(employee);
			return Msg.success();
		}


	}

	/*
	 * @ResponseBody 需要导入包
	 * param pn
	 * 返回 json 数据
	 * */
	@RequestMapping("/emps")
	@ResponseBody
	public Msg getEmpsWithJson(@RequestParam(value="pn", defaultValue="1")Integer pn,Model model) {
		//这不是一个分页查询
		// 引入 PageHelper
		//在查询之前只需要调用,传入页码,以及每页的大小
		PageHelper.startPage(pn, 5);
		// startPage 后面紧跟的这个查询就是一个分页查询
		List<Employee> emps = employeeService.getAll();

		//使用 PageInfo 包装查询后的结果,只需要将 PageInfo 交给页面就行了
		//封装了详细的分页信息,包含有我们查询出来的数据,传入连续显示的页数
		PageInfo page = new PageInfo(emps, 5);
		//model.addAttribute("pageInfo", page);
		return Msg.success().add("pageInfo" , page);
	}


	/**
	 *  查询员工数据(分页查询)
	 * @return
	 */
	//@RequestMapping("/emps")
	public String getEmps(@RequestParam(value="pn", defaultValue="1")Integer pn,Model model) {
		//这不是一个分页查询
		// 引入 PageHelper
		//在查询之前只需要调用,传入页码,以及每页的大小
		PageHelper.startPage(pn, 5);
		// startPage 后面紧跟的这个查询就是一个分页查询
		List<Employee> emps = employeeService.getAll();

		//使用 PageInfo 包装查询后的结果,只需要将 PageInfo 交给页面就行了
		//封装了详细的分页信息,包含有我们查询出来的数据,传入连续显示的页数
		PageInfo page = new PageInfo(emps, 5);
		model.addAttribute("pageInfo", page);
		return "list";
	}
}

7.页面的展示 list.jsp, ajax 请求返回 json 格式数据,前端 js 解析

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%-- <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> --%>
	<%
        pageContext.setAttribute("APP_PATH", request.getContextPath());
        String path = request.getScheme() + "://" + request.getServerName()
                + ":" + request.getServerPort() + request.getContextPath()
                + "/";
        System.out.println(path);
		System.out.println("APP_PATH = " + pageContext.getAttribute("APP_PATH"));
	%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
	<!-- 写成这样会报错 <%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix='c'%> -->
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>员工列表</title>
	<!-- 不以/开始的相对路径,找资源,以当前资源的路径为基准,容易出问题
		以/开始的相对路径,找资源,以服务器的路径为标准(http://localhost:3306),需要加上项目名称
		http://localhost:3306/crud
	-->
	<!-- 引入 JQuery -->
	<script type="text/javascript" src="${APP_PATH}/static/js/jquery-3.2.1.js"></script>
	<!-- 引入 BootStrap css 样式-->
	<link href="${APP_PATH}/static/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet">
	<!-- 引入 JS -->
	<script src="${APP_PATH}/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
</head>
<body>
	<!-- 员工添加模态框 -->
	<!-- Modal -->
	<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 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 class="help-block"></span>
			    </div>
			  </div>
			 <div class="form-group">
			    <label class="col-sm-2 control-label">email</label>
			    <div class="col-sm-10">
			      <input type="text" name="email" class="form-control" id="email_add_input" placeholder="email@atguigu.com">
			      <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_add_input" value="M" checked> 男
				  </label>
				  <label class="radio-inline">
					  <input type="radio" name="gender" id="gender2_add_input" value="F"> 女
			      </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_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>

	<!-- 员工修改模态框 -->
	<!-- Modal -->
	<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 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 class="col-sm-2 control-label">email</label>
			    <div class="col-sm-10">
			      <input type="text" name="email" class="form-control" id="email_update_input" placeholder="email@atguigu.com">
			      <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> 男
				  </label>
				  <label class="radio-inline">
					  <input type="radio" name="gender" id="gender2_update_input" value="F"> 女
			      </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">

					</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="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 type="button" class="btn btn-primary btn-sm" id="emp_add_modal_btn">新增</button>
				<button type="button" class="btn btn-danger btn-sm" id="emp_delete_all_btn">删除</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>#</th>
							<th>empName</th>
							<th>gender</th>
							<th>email</th>
							<th>department</th>
							<th>操作</th>
						</tr>
					</thead>
					<tbody>

					</tbody>
				</table>
			</div>
		</div>
		<!-- 显示分页信息栏 -->
		<div class="row">
			<!-- 分页文字信息 -->
			<div id="page_info_area" class="col-md-6">

			</div>

			<!-- 分页条信息 -->
			<div id="page_nav_area" class="col-md-6">

			</div>
		</div>
	</div>
	<script type="text/javascript">

		var totalRecord, currentPage;
		//1、页面加载完成以后,直接去发送一个 ajax 请求,要到分页数据,$表示页面加载完再执行这个函数
		$(function(){
			to_page(1);
		});

		function to_page(pn) {
			$.ajax({
				url:"${APP_PATH}/emps",
				data:"pn="+pn,
				type:"GET",
				success:function(result){
					//解析数据,显示数据
					build_emps_table(result);
					//显示分页信息
					build_page_info(result);
					//添加分页条
					build_page_nav(result);
				}
			});
		}

		//显示员工信息
		function build_emps_table(result) {
			//清空数据
			$("#emps_table tbody").empty();

			var emps = result.extend.pageInfo.list;

			$.each(emps, function(index, item) {
				var checkBoxTd = $("<td><input type='checkbox' class='check_item'/></td>");
				var empIdTd = $("<td></td>").append(item.empId);
				var empNameTd = $("<td></td>").append(item.empName);

				var genderTd = $("<td></td>").append(item.gender=='M'?'男':'女');
				var emailTd = $("<td></td>").append(item.email);
				var deptNameTd = $("<td></td>").append(item.department.deptName);
				/*
				<button type="button" class="">新增</button>
				<button type="button" class="btn btn-danger btn-sm">删除</button>
				<span class="" aria-hidden="true"></span>
				*/
				var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm edit_btn").append($("<span></span>"))
				.addClass("glyphicon glyphicon-pencil").append("编辑");
				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("删除");
				delBtn.attr("del-id", item.empId);

				var btnTd = $("<td></td>").append(editBtn).append(" ").append(delBtn);

				$("<tr></tr>").append(checkBoxTd)
				.append(empIdTd)
				.append(empNameTd)
				.append(genderTd)
				.append(emailTd)
				.append(deptNameTd)
				.append(btnTd)
				.appendTo("#emps_table tbody");

			});
		}

		//显示分页信息
		function build_page_info(result) {
			//清空数据
			$("#page_info_area").empty();
			//alert("hello");
			$("#page_info_area").append("当前 " +
					result.extend.pageInfo.pageNum + " 页,总 " +
					result.extend.pageInfo.pages + " 页,总 " + 	
					result.extend.pageInfo.total + " 条记录");
			totalRecord = result.extend.pageInfo.total;
			currentPage = result.extend.pageInfo.pageNum;
		}

		//显示导航条
		function build_page_nav(result) {
			//清空数据
			$("#page_nav_area").empty();
			//page_nav_area
			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 == false) {
				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);
				});
			}



			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);

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

		function reset_form(ele) {
			$(ele)[0].reset();
			$(ele).find("*").removeClass("has-error");
			$(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(ele) {
			$(ele).empty();
			$.ajax({
				url:"${APP_PATH}/depts",
				type:"GET",
				success:function(result) {
					//console.log(result);
					//$("#dept_add_select")
					//$("#empAddModal select").append("")
					$.each(result.extend.depts,function() {
						var optionEle = $("<option></option>").append(this.deptName).attr("value",this.deptId);
						optionEle.appendTo(ele);
					});
				}
			});
		}

		//校验表单数据
		function validate_add_form() {
			//拿到要校验的数据,使用正则表达式
			var empName = $("#empName_add_input").val();
			var regName = /(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;
			if(!regName.test(empName)) {
				show_validate_msg("#empName_add_input", "error", "用户名可以是 2-5 位中文或者6-16位英文和数字、-、_、的组合");
				return false;
			}else {
				show_validate_msg("#empName_add_input", "success", "");
			}

			var email = $("#email_add_input").val();
			var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
			if(!regEmail.test(email)) {
				//alert("邮箱格式不正确");
				show_validate_msg("#email_add_input", "error", "邮箱格式不正确");
			/* 	$("#email_add_input").parent().addClass("has-error");
				$("#email_add_input").next("span").text("邮箱格式不正确"); */
				return false;
			} else {
				show_validate_msg("#email_add_input", "success", "");
				/* $("#email_add_input").parent().addClass("has-success");
				$("#email_add_input").next("span").text(""); */
			}

			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");
				$(ele).next("span").text(msg);
			}else if("error"==status){
				//alert("用户名可以是 2-5 位中文或者6-16位英文和数字、-、_、的组合");
				$(ele).parent().addClass("has-error");
				$(ele).next("span").text(msg);
			}
		}

		$("#empName_add_input").change(function() {
			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(){
			/* if(!validate_add_form()) {
				return false;
			} */


			if($(this).attr("ajax-va") == "error") {
				return false;
			}

			//1、模态框中填写的表单数据提交给服务器
			//2、发送 Ajax 请求保存员工

			 $.ajax({
				url:"${APP_PATH}/emp",
				type:"POST",
				data:$("#empAddModal form").serialize(),
				success:function(result) {
					if(result.code == 100) {
						//alert(result.msg);
						//1. 关闭模态框
						$("#empAddModal").modal("hide");
						//2.来到最后一页
						//发送 ajax 显示最后一页的数据
						to_page(totalRecord);
					} else {
						//显示失败信息
						//console.log(result);

						//有哪个字段错误信息就返回哪一个
						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);
						}
					}

				}
			});
		});


		//我们是按钮,
		$(document).on("click", ".edit_btn",function() {
			//alert("edit");
			//弹出模态框

			getDepts("#empUpdateModal select");
			//alert($(this).attr("edit-id"));
			getEmp($(this).attr("edit-id"));

			//把员工 的 id 传递给模态框的更新按钮
			$("#emp_update_btn").attr("edit-id",$(this).attr("edit-id"));
			$("#empUpdateModal").modal({
				backdrop:"static"
			});

		});

		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);
					$("#empUpdateModalinput[name=gender]").val([empData.gender]);
					$("#empUpdateModal select").val([empData.dId]);
				}
			});
		}

		//点击更新,更新员工信息
		$("#emp_update_btn").click(function() {
			//验证邮箱
			var email = $("#email_update_input").val();
			var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
			if(!regEmail.test(email)) {
				show_validate_msg("#email_update_input", "error", "邮箱格式不正确");
				return false;
			} else {
				show_validate_msg("#email_update_input", "success", "");
			}

			//发送 ajax 请求
			$.ajax({
				url:"${APP_PATH}/emp/" + $(this).attr("edit-id"),
				type: "PUT",
				data:$("#empUpdateModal form").serialize(),
				success:function(result) {
					//alert(result.msg);
					$("#empUpdateModal").modal("hide");
					to_page(currentPage);
				}
			});
		});

		//单个删除
		$(document).on("click",".delete_btn", function(){
				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() {
			$(".check_item").prop("checked", $(this).prop("checked"));
		});

		$(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() + ",";
				del_idstr += $(this).parents("tr").find("td:eq(1)").text() + "-";
			});
			empNames = empNames.substring(0, empNames.length - 1);
			del_idstr = del_idstr.substring(0, del_idstr.length - 1);
			if(confirm("确认删除【" + empNames + "】吗?")) {
				$.ajax({
					url:"${APP_PATH}/emp/" + del_idstr,
					type:"DELETE",
					success:function(result) {
						alert(result.msg);
						to_page(currentPage);
					}
				});
			}
		});
	</script>
</body>
</html>

8.运行效果图:

运行效果

总结:这个视频教程还是非常不错的,项目从无到有,跟着视频一步一步敲代码,就可以做出同样的效果。【视频教程】。使用 maven 构建项目, SSM、 BootStrap、 jQuery、ajax、分页插件 PageHelper、JSR_303校验等框架和插件、技术。

项目 github 地址

码云地址

转载于:https://my.oschina.net/oldbiwang/blog/1528328

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值