SSM项目实操——CRUD

  • Post author:
  • Post category:其他



ssm:SpringMVC+Spring+MyBatis

CRUD:Create


(创建)

Retrieve(查询)

Update(更新)

Delete(删除)


功能点


• 1、分页

• 2、数据校验(前后端双校验)

• jquery前端校验+JSR303


后端校验

• 3、


ajax

• 4、


Rest


风格的


URI


;使用


HTTP


协议请求方式的动词,来表示对资源的操作(GET(查询),POST


(新增),


PUT


(修改),


DELETE(删除))


技术点


• 基础框架-ssm





SpringMVC+Spring+MyBatis




• 数据库-MySQL

• 前端框架-bootstrap


快速搭建简洁美观的界面

• 项目的依赖管理-Maven

• 分页-pagehelper

• 逆向工程-MyBatis Generator


基础环境搭建


• 1、创建一个


maven


工程

• 2、引入项目依赖的


jar




• spring

• springmvc

• mybatis

• 数据库连接池,驱动包

• 其他(jstl,


servlet-api





junit




• 3、引入


bootstrap


前端框架

• 4、编写


ssm


整合的关键配置文件

• web.xml,spring,springmvc,mybatis


,使用


mybatis


的逆向工程生成对应的


bean


以及mapper

• 5、测试


mapper

1. 创建一个maven工程



idea创建maven工程

创建如下目录结构:

2. 引入项目依赖的jar包

在maven仓库找到jar坐标位置


• spring

• springmvc

• mybatis

• 数据库连接池,驱动包

• 其他(jstl,


servlet-api





junit



 <!--引入项目依赖的jar包 -->
  <dependencies>
    <!-- SpringMVC、Spring -->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.3.7.RELEASE</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面向切面编程 -->
    <!-- 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</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>


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


3. 引入


bootstrap


前端框架

下载完成的bootstrap和jquery放入static文件夹

使用:

引入bootstrap核心的css和js文件,参考基本模板的使用方法

新建index.jsp,代码如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <!--引入jquery-->
    <script type="text/javascript" src="static/js/jquery-1.12.4.min.js"></script>
    <!--引入样式-->
    <link href="static/bootstrap-3.4.1-dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="static/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
</head>
<body>
<button class="btn btn-success">按钮</button>
</body>
</html>

代码中演示的按钮样式就是采用的bootstrap的风格,tomcat运行效果如下


4. 编写


ssm


整合的关键配置文件

web.xml

<?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_2_5.xsd"
	id="WebApp_ID" version="2.5">
	
	<!--1spring 监听器-->
	<!-- needed for ContextLoaderListener -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<!--spring的配置文件-->
		<param-value>classpath:applicationContext.xml</param-value>
	</context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
	
	<!--2、springmvc的前端控制器,拦截所有请求  -->
	<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
	<servlet>
		<servlet-name>dispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:springMVC.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<!-- Map all requests to the DispatcherServlet for handling -->
	<servlet-mapping>
		<servlet-name>dispatcherServlet</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风格的URI,将页面普通的post请求转为指定的delete或者put请求 -->
	<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-mapping>
		<filter-name>HttpPutFormContentFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
</web-app>

springMVC.xml

新建package,结构如下

<?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-3.2.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">
		<!--只扫描控制器。  -->
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>
	
	<!--配置视图解析器,方便页面返回  -->
	<bean 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/>

</beans>

applicationContext.xml(spring配置)


Idea整合SSM框架出现:applicationcontext in module file is included in 5 contexts

<?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/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
Url		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

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

	<!-- Spring的配置文件,这里主要配置和业务逻辑有关的 -->
	<!--=================== 数据源,事务控制,xxx ================-->
	<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">
		<!-- 指定mybatis全局配置文件的位置 -->
		<property name="configLocation" value="classpath:mybatis-config.xml"></property>
		<property name="dataSource" ref="pooledDataSource"></property>
		<!-- 指定mybatis的mapper文件的位置 -->
		<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>
	
	<!-- 配置一个可以执行批量的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>
	<!--=============================================  -->

	<!-- ===============事务控制的配置(给service包下的所有方法添加事务控制) ================-->
	<!--创建事务管理器-->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<!--控制住数据源  -->
		<property name="dataSource" ref="pooledDataSource"></property>
	</bean>


	<!--配置事务增强(通知),事务如何切入  -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<!--配置事务参数-->
		<tx:attributes>
			 <!--指定哪种规则的方法上面添加事务-->
			<!-- 所有方法都是事务方法 -->
			<tx:method name="*"/>
			<!--以get开始的所有方法都是只读 -->
			<tx:method name="get*" read-only="true"/>
		</tx:attributes>
	</tx:advice>
	
		<!--开启基于注解的事务,使用xml配置形式的事务(主要的都是使用配置式)  -->
	<!--配置aop增强(配置切入点和切面)-->
	<aop:config>
		<!-- 切入点表达式 -->
		<aop:pointcut expression="execution(* com.atguigu.crud.service..*(..))" id="txPoint"/>
		<!-- 配置事务增强(配置切面,即把通知应用到切入点的过程) -->
		<aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
	</aop:config>
	<!-- Spring配置文件的核心点(数据源、与mybatis的整合,事务控制) -->
	
</beans>

dbconfig.properties

jdbc.jdbcUrl=jdbc:mysql://localhost:3306/ssm_crud
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.user=root
jdbc.password=root

mybatis.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.crud.bean"/>
	</typeAliases>

</configuration>


tbl_emp


tbl_dept


使用mybatis的逆向工程生成对应的bean以及mapper

pom中引入mybatis的generate jar包

   <dependency>
      <groupId>org.mybatis.generator</groupId>
      <artifactId>mybatis-generator-core</artifactId>
      <version>1.3.5</version>
    </dependency>

在项目中创建mbg.xml

注意idea使用

绝对路径

<?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.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/ssm_crud" userId="root"
                        password="Aa-11111">
        </jdbcConnection>

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

        <!-- 指定javaBean生成的位置 -->
        <javaModelGenerator targetPackage="com.atguigu.crud.bean"
                            targetProject="D:\idea_work\ssm-curd\src\main\java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>

        <!--指定sql映射文件生成的位置 -->
        <sqlMapGenerator targetPackage="mapper" targetProject="D:\idea_work\ssm-curd\src\main\resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>

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


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

写代码运行配置文件

问题1:


运行maven项目时出现Error:(3, 38) java: 程序包不存在_久殇酒妄的博客-CSDN博客

Error:(6, 33) java: 程序包org.mybatis.generator.xxx不存在

给这个问题耽搁了一下午

。已解决

提问,为什么我的IDEA中Maven工程必须勾选Maven设置中的Delegate IDE build/run actions to Maven才能运行?

  1. 现在我来统一回复一下大家关于这个问题的疑问吧!其实这个就是IDEA版本与Maven之间存在的问题,看到你们的IDEA的版本是2020版的,问题就在这里,2020版的IDEA是无法导入MAVEN工程的jar包的,所以就需要我们强制的进行导入,如果你细心,你就会发现2020版的IDEA上是没有File → Settings → Importing → Import Maven projects automatically → OK这个路径的。

  2. 其实勾选这个选项只是其中的一种解决方案,还有一种解决方案就是修改本地仓库的路径,同样可以屏蔽掉这个问题。

  3. 最后我想说的是,其实这就是一个大坑。真是坑死我了。

问题2;


Intellij IDEA junit 使用之org.junit不存在_he99774的博客-CSDN博客_org.junit不存在

MBGTest.java

问题3:

找不到mbg.xml

IDEA要使用绝对路径,xml中的路径配置错误

package com.atguigu.crud.test;


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

import org.junit.Test;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;


public class MBGTest {

    @Test
    public  void test() throws Exception {
        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;
        File configFile = new File("D:\\idea_work\\ssm-curd\\src\\main\\resources\\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);
    }
}

修改mapper文件

1.查员工信息的时候附带部门信息。在employeeMapper中新增方法

//查询员工时带部门信息
List<Employee> selectByExampleWithDept(EmployeeExample example);

Employee selectByPrimaryKeyWithDept(Integer empId);

2.Employee中增加department属性和对应的get/set方法

EmployeeMapper

<resultMap id="WithDeptResultMap" type="com.atguigu.crud.bean.Employee">
    <id column="emp_id" jdbcType="INTEGER" property="empId" />
    <result column="emp_name" jdbcType="VARCHAR" property="empName" />
    <result column="gender" jdbcType="CHAR" property="gender" />
    <result column="email" jdbcType="VARCHAR" property="email" />
    <result column="d_id" jdbcType="INTEGER" property="dId" />
    <!--指定联合查询出的部门字段的封装-->
    <association property="department" javaType="com.atguigu.crud.bean.Department">
      <id column="dept_id" property="deptId"/>
      <result column="dept_name" property="deptName"/>
    </association>
</resultMap>

<sql id="WithDept_Colusmn_List">
    e.emp_id, e.emp_name, e.gender, e.email, e.d_id,d.dept_id,d.dept_name
</sql>

<select id="selectByExampleWithDept" resultMap="WithDeptResultMap">
    select
    <if test="distinct">
      distinct
    </if>
    <include refid="WithDept_Colusmn_List" />
    from tbl_emp e left join  tbl_dept d on e.`d_id`=d.`dept_id`
    <if test="_parameter != null">
      <include refid="Example_Where_Clause" />
    </if>
    <if test="orderByClause != null">
      order by ${orderByClause}
    </if>
</select>
 <select id="selectByPrimaryKeyWithDept" resultMap="WithDeptResultMap">
    select
    <include refid="WithDept_Colusmn_List" />
    from  tbl_emp e left join  tbl_dept d on e.`d_id`=d.`dept_id`
    where emp_id = #{empId,jdbcType=INTEGER}
  </select>

5. 测试mapper

测试dao层的工作


推荐Spring的项目使用Spring的单元测试

,可以自动注入我们需要的组件

1、导入SpringTest模块


		<!--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>
		</dependency>

2、@ContextConfiguration指定Spring配置文件的位置

3、直接autowired要使用的组件即可

问题1

警告: Exception encountered during context initialization – cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘sqlSessionFactory’ defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is org.springframework.core.NestedIOException: Failed to parse mapping resource: ‘file [D:\idea_work\ssm-curd\target\classes\mapper\EmployeeMapper.xml]’; nested exception is org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. Cause: org.apache.ibatis.builder.BuilderException:

Error resolving JdbcType. Cause: java.lang.IllegalArgumentException: No enum constant org.apache.ibatis.type.



Jdbc



Type.com.atguigu.crud.bean.Departmen


t

解决:查找数据库中的department表发现department_id写成了department__id。(折腾了一晚上)

javaType写成了jdbcType

4. 为了批量插入多条数据,在spring配置文件中配置一个可以执行批量的sqlSession

	<!-- 配置一个可以执行批量的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>

MapperTest.java

package com.atguigu.crud.test;


import com.atguigu.crud.bean.Department;
import com.atguigu.crud.bean.Employee;
import com.atguigu.crud.dao.DepartmentMapper;
import com.atguigu.crud.dao.EmployeeMapper;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.UUID;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class MapperTest {

    @Autowired
    DepartmentMapper departmentMapper;

    @Autowired
    EmployeeMapper employeeMapper;

    @Autowired
    SqlSession sqlSession;

    @Test
    public void testCRUD(){
        /*	//1、创建SpringIOC容器
		ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
		//2、从容器中获取mapper
		DepartmentMapper bean = ioc.getBean(DepartmentMapper.class);*/

        System.out.println(departmentMapper);

//        //1.插入几个部门(department生成有参构造器)
//        departmentMapper.insertSelective(new Department(null,"开发部"));
//        departmentMapper.insertSelective(new Department(null,"测试部"));

        //2.生成员工数据,测试员工插入(employee生成有参(无department参数)无参)
        employeeMapper.insertSelective((new Employee(null,"jerry","M","jerry@163.com",1)));

        //3.批量插入多个员工:批量,使用可以执行批量操作的sqlSession。
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        for (int i = 0; i < 1000; i++) {
            String uuid = UUID.randomUUID().toString().substring(0, 5)+i;
            mapper.insertSelective(new Employee(null,uuid,"M",uuid+"@atguigu.com",1));

        }
        System.out.println("批量执行完");
    }

}

另外测试别的功能,到这一步结果正常,恭喜读者已完成所有配置。开始新的操作。


CRUD-


查询

查询


• 1、访问index.jsp页面

• 2、index.jsp页面发送出查询员工列表请求,请求的URI:/emps

• 3、EmployeeController接受请求,查出员工数据

• 4、来到list.jsp页面进行展示

• 5、pageHelper分页插件完成分页查询功能



访问index.jsp页面,index.jsp页面发送出查询员工列表请求,请求的URI:/emps


index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:forward page="/emps"/>
<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="static/js/jquery-1.12.4.min.js"></script>
    <link href="static/bootstrap-3.4.1-dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="static/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
</head>
<body>
</body>
</html>



EmployeeController接受请求,查出员工数据

package com.atguigu.crud.controller;

import com.atguigu.crud.bean.Employee;
import com.atguigu.crud.service.EmployeeService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

/*
    处理员工CRUD请求
 */
@Controller
public class EmployeeController {
    @Autowired//自动装配service层业务逻辑组件
    EmployeeService employeeService;
    /**
     * 查询员工数据(分页查询)
     * @return
     */
    @RequestMapping("/emps")
    public String getEmps(@RequestParam(value="pn",defaultValue = "1")Integer pn,Model model){
        ... ...
        return "list";
    }
}



pageHelper分页插件完成分页查询功能

1.pom中引入pageHelper分页插件

    <!--引入pageHelper分页插件 -->
    <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>5.0.0</version>
    </dependency>

2.mybaits全局配置中注册插件

   <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"/>
    </plugins>

3.分页后台代码

 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";
    }


使用Spring单元测试测试分页请求

模拟发送请求,处理数据

package com.atguigu.crud.test;

import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import com.atguigu.crud.bean.Employee;
import com.github.pagehelper.PageInfo;

/**
 * 使用Spring测试模块提供的测试请求功能,测试curd请求的正确性
 * Spring4测试的时候,需要servlet3.0的支持
 * @author lfy
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = { "classpath:applicationContext.xml",
        "classpath:springMVC.xml" })
public class MvcTest {
    // 传入Springmvc的ioc
    @Autowired //autowired只能装配IOC内部, IOC容器自己被装配需要加webappconfiguration
    WebApplicationContext context;
    // 虚拟mvc请求,获取到处理结果。
    MockMvc mockMvc;

    @Before//每次要用之前初始化
    public void initMokcMvc() {
        mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
    }

    @Test
    public void testPage() throws Exception {
        //模拟请求拿到返回值,此处为egt请求,参数pn
        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/emps").param("pn", "1"))
                .andReturn();

        //请求成功以后,请求域中会有pageInfo;我们可以取出pageInfo进行验证
        MockHttpServletRequest request = result.getRequest();//拿到请求对象
        PageInfo pi = (PageInfo) request.getAttribute("pageInfo");//从请求域中拿到pageinfo
        System.out.println("当前页码:"+pi.getPageNum());
        System.out.println("总页码:"+pi.getPages());
        System.out.println("总记录数:"+pi.getTotal());
        System.out.println("在页面需要连续显示的页码");
        int[] nums = pi.getNavigatepageNums();
        for (int i : nums) {
            System.out.print(" "+i);
        }

        //获取员工数据(员工数据也包装在pageinfo中)
        List<Employee> list = pi.getList();
        for (Employee employee : list) {
            System.out.println("ID:"+employee.getEmpId()+"==>Name:"+employee.getEmpName());
        }
    }
}



来到list.jsp页面进行展示

使用Bootstrap搭建显示页面

技术点:使用Bootstrap

栅格系统

布局,使用bootstrap组件的分页,图标以及表格,按钮样式搭建页面。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title>员工列表</title>
    <%
        pageContext.setAttribute("APP_PATH",request.getContextPath());//当前页面域放置项目路径的属性,以/开始,不以/结束
    %>
    <!-- web路径:
不以/开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题。
以/开始的相对路径,找资源,以服务器的路径为标准(http://localhost:3306);需要加上项目名
		http://localhost:3306/crud
 -->
    <script type="text/javascript" src="${APP_PATH}/static/js/jquery-1.12.4.min.js"></script>
    <link href="${APP_PATH}/static/bootstrap-3.4.1-dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="${APP_PATH}/static/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
</head>

<body>
<!--搭建显示页面-->
<div class="container">
    <!--4行-->
    <!--标题-->
    <div class="row">
        <div class="col-md-12"><!--占12列-->
            <h1>SSM-CRUD</h1>
        </div>
    </div>
    <!--按钮-->
    <div class="row">
        <div class="col-md-4 col-md-offset-8"><!--占四列,偏移8列-->
            <button class="btn btn-primary">新增</button>
            <button class="btn btn-danger">删除</button>
        </div>
    </div>
    <!--显示表格数据-->
    <div class="row">
        <table class="table table-hover">
            <tr>
                <th>#</th>
                <th>empName</th>
                <th>gender</th>
                <th>email</th>
                <th>deptName</th>
                <th>操作</th>
            </tr>
            <c:forEach items="${pageInfo.list}" var="emp">
                <tr>
                    <th>${emp.empId}</th>
                    <th>${emp.empName}</th>
                    <th>${emp.gender=="M"?"男":"女"}</th>
                    <th>${emp.email}</th>
                    <th>${emp.department.deptName}</th>
                    <th>
                        <button type="button" class="btn btn-primary btn-sm" aria-label="Left Align">
                            <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span><!--小图标-->
                            编辑
                        </button>
                        <button type="button" class="btn btn-danger btn-sm" aria-label="Left Align">
                        <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
                        删除
                        </button>
                    </th>
                </tr>
            </c:forEach>

        </table>
    </div>
    .......
</body>
</html>

遇到pagecontext.setattribute爆红,添加属性

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.0</version>
      <scope>provided</scope>
    </dependency>


显示分页信息

bootstrap分页条

<nav aria-label="Page navigation">
  <ul class="pagination">
    <li>
      <a href="#" aria-label="Previous">
        <span aria-hidden="true">&laquo;</span>
      </a>
    </li>
    <li><a href="#">1</a></li>
    <li><a href="#">2</a></li>
    <li><a href="#">3</a></li>
    <li><a href="#">4</a></li>
    <li><a href="#">5</a></li>
    <li>
      <a href="#" aria-label="Next">
        <span aria-hidden="true">&raquo;</span>
      </a>
    </li>
  </ul>
</nav>
<!--显示分页信息-->
    <div class="row">
        <!--分页文字信息-->
        <div class="col-md-6">
            当前${pageInfo.pageNum}页,总${pageInfo.pages}页,总${pageInfo.total}条记录
        </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="page_Num">
                        <c:if test="${page_Num == pageInfo.pageNum}"><!--判断是不是当前页码。是的话高亮显示-->
                            <li class="active"><a href="#">${page_Num}</a></li>
                        </c:if>
                        <c:if test="${page_Num != pageInfo.pageNum}"><!--判断是不是当前页码。不是的话正常显示-->
                            <li ><a href="${APP_PATH}/emps?pn=${page_Num}">${page_Num}</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>


配置 tomcat运行项目


war和war exploded的区别


Tomcat与Maven环境搭建

运行效果:


查询-ajax

以上只适用于浏览器和服务器的交互,要适用于多客户端,服务器需要将数据以json的形式传递给客户端。我们把查询做成ajax引用。提升系统的扩展性。
改造查询


• 1





index.jsp


页面直接发送


ajax


请求进行员工分页数据的查询

• 2、服务器将查出的数据,以


json


字符串的形式返回给浏览器

• 3、浏览器收到


json


字符串。可以使用


js





json


进行解析,使用


js


通过dom增删改改变页面。

• 4、返回


json


。实现客户端的无关性。
导入json包
   <!--返回json字符串的支持-->   
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.8.8</version>
    </dependency>

controller代码改进:

/*
    处理员工CRUD请求
 */
@Controller
public class EmployeeController {
    @Autowired//自动装配service层业务逻辑组件
    EmployeeService employeeService;

    /**
     * 导入jackson包
     * @param pn
     * @return
     */
    @RequestMapping("/emps")
    @ResponseBody//自动把返回的对象转为字符串
    public PageInfo getEmpsWithJson(@RequestParam(value="pn",defaultValue = "1")Integer pn){
        //引入pagehelper分页插件
        //在查询之前只需要调用,传入页码,以及每页大小
        PageHelper.startPage(pn,5);
        //startPage后面紧跟的这个查询就是一个分页查询
        List<Employee> emps =  employeeService.getAll();
        //使用pageinfo包装查询后的结果,只需将pageinfo交给页面就行
        //封装了详细的分页信息,包括我们查询出来的数据,传入连续显示的页数
        PageInfo page = new PageInfo(emps,5);
        return page;
    }
}

运行效果:

上图为pageinfo的json字符串数据。此结果不具通用性,如删除,需要返回状态信息给浏览器。


改进:

在bean包中设计通用的返回类Msg

package com.atguigu.crud.bean;

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

/**
 * 通用的返回类
 */
public class Msg {
    //状态码 100-成功 200-失败
    private int code;
    //提示信息,如失败的原因
    private String msg;

    //用户要返回给浏览器的数据
    private Map<String,Object> extend = new HashMap<String,Object>();

    //定义成功的方法
    public static Msg success(){
        Msg result = new Msg();
        result.setCode(100);
        result.setMsg("处理成功");
        return result;
    }

    //定义失败的方法
    public static Msg fail(){
        Msg result = new Msg();
        result.setCode(200);
        result.setMsg("处理失败");
        return result;
    }

    //实现链式操作的方法
    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;
    }
}

controller

  @RequestMapping("/emps")
    @ResponseBody//自动把返回的对象转为字符串
    public Msg getEmpsWithJson(@RequestParam(value="pn",defaultValue = "1")Integer pn){
        //引入pagehelper分页插件
        //在查询之前只需要调用,传入页码,以及每页大小
        PageHelper.startPage(pn,5);
        //startPage后面紧跟的这个查询就是一个分页查询
        List<Employee> emps =  employeeService.getAll();
        //使用pageinfo包装查询后的结果,只需将pageinfo交给页面就行
        //封装了详细的分页信息,包括我们查询出来的数据,传入连续显示的页数
        PageInfo page = new PageInfo(emps,5);
        return Msg.success().add("pageInfo",page);//链式操作。携带数据
    }

运行效果:

后面我们发送ajax请求获取这些数据,使用js进行解析使用dom进行展示


改造index页面
构建员工列表
function build_emps_table(result) {//结果进行解析
    var emps = result.extend.pageInfo.list;
    $.each(emps,function (index,item) {
        //alert(item.empName)
        var empIdTd = $("<td></td>").append(item.empId);//员工id单元格
        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);
        var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm").append($("<span></span>").addClass("glyphicon glyphicon-pencil")).append("编辑");
        var delBtn = $("<button></button>").addClass("btn btn-danger btn-sm").append($("<span></span>").addClass("glyphicon glyphicon-trash")).append("删除");
        var btnTd = $("<td></td>").append(editBtn).append(" ").append(delBtn);
        //append执行完成后还是返回原来的元素
        $("<tr></tr>").append(empIdTd).append(empNameTd).append(genderTd).append(emailTd).append(deptNameTd).append(btnTd).appendTo("#emps_table tbody");//创建tr元素
    });//遍历方法,要遍历的元素和每次遍历的回调函数(索引,当前对象)
  }

构建分页条
 //解析显示分页信息
  function bulid_page_info(result) {
      $("#page_info_area").append("当前"+result.extend.pageInfo.pageNum+"页,总"+
          result.extend.pageInfo.pages+"页,总"+
          result.extend.pageInfo.total+"条记录");
  }
  //解析显示分页条

    // <nav aria-label="Page navigation">
    //     <ul class="pagination">
    //     <li>
    //     <a href="#" aria-label="Previous">
    //     <span aria-hidden="true">&laquo;</span>
    // </a>
    // </li>
    // <li><a href="#">1</a></li>
    // <li><a href="#">2</a></li>
    // <li><a href="#">3</a></li>
    // <li><a href="#">4</a></li>
    // <li><a href="#">5</a></li>
    // <li>
    // <a href="#" aria-label="Next">
    //     <span aria-hidden="true">&raquo;</span>
    // </a>
    // </li>
    //</ul>
    //</nav>
  function build_page_nav(result) {
    //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;"));
       var nextPageLi = $("<li></li>").append($("<a></a>").append("&raquo;"));
       var lastPageLi = $("<li></li>").append($("<a></a>").append("末页").attr("href","#"));
        ul.append(firstPageLi).append(prePageLi);//添加首页和前一页
      //ul中添加页面页码
       $.each(result.extend.pageInfo.navigatepageNums,function (index,item) {
            var numLi = $("<li></li>").append($("<a></a>").append(item));
            ul.append(numLi);
       })
      //添加下一页和末页的提示
      ul.append(nextPageLi).append(lastPageLi);
       //ul添加到nav
       var navEle = $("<nav></nav>").append(ul);
       navEle.appendTo("#page_nav_area");
  }
  //1.页面加载完成后,直接发送一个ajax数据,要到分页数据
  $(function () {
    $.ajax({
        url:"${APP_PATH}/emps",
        data:"pn=1",
        type:"get",
        success:function (result) {
            //console.log(result)
            //1.页面解析并显示员工数据
            build_emps_table(result);
            //2.解析并显示分页信息
            bulid_page_info(result);
            //3、解析显示分页条数据
            build_page_nav(result);

        }
    })
  });


分页显示添加事件

当前页突出显示,当前页为首页(末页)时无法向上(向下)跳转。点击各页实现跳转,点击向上向下实现跳转

<script type="text/javascript">
    //1.页面加载完成后,直接发送一个ajax数据,要到分页数据
  $(function () {
    //去首页
      to_page(1);
  });

  function to_page(pn) {
      $.ajax({
          url:"${APP_PATH}/emps",
          data:"pn="+pn,
          type:"get",
          success:function (result) {
              //console.log(result)
              //1.页面解析并显示员工数据
              build_emps_table(result);
              //2.解析并显示分页信息
              bulid_page_info(result);
              //3、解析显示分页条数据
              build_page_nav(result);

          }
      })
  }

  function build_emps_table(result) {//结果进行解析
      //清空table表格
      $("#emps_table tbody").empty();
    var emps = result.extend.pageInfo.list;
    $.each(emps,function (index,item) {
        //alert(item.empName)
        var empIdTd = $("<td></td>").append(item.empId);//员工id单元格
        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);
        var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm").append($("<span></span>").addClass("glyphicon glyphicon-pencil")).append("编辑");
        var delBtn = $("<button></button>").addClass("btn btn-danger btn-sm").append($("<span></span>").addClass("glyphicon glyphicon-trash")).append("删除");
        var btnTd = $("<td></td>").append(editBtn).append(" ").append(delBtn);
        //append执行完成后还是返回原来的元素
        $("<tr></tr>").append(empIdTd).append(empNameTd).append(genderTd).append(emailTd).append(deptNameTd).append(btnTd).appendTo("#emps_table tbody");//创建tr元素
    });//遍历方法,要遍历的元素和每次遍历的回调函数(索引,当前对象)
  }

  //解析显示分页信息
  function bulid_page_info(result) {
      $("#page_info_area").empty();
      $("#page_info_area").append("当前"+result.extend.pageInfo.pageNum+"页,总"+
          result.extend.pageInfo.pages+"页,总"+
          result.extend.pageInfo.total+"条记录");
  }
  //解析显示分页条

    // <nav aria-label="Page navigation">
    //     <ul class="pagination">
    //     <li>
    //     <a href="#" aria-label="Previous">
    //     <span aria-hidden="true">&laquo;</span>
    // </a>
    // </li>
    // <li><a href="#">1</a></li>
    // <li><a href="#">2</a></li>
    // <li><a href="#">3</a></li>
    // <li><a href="#">4</a></li>
    // <li><a href="#">5</a></li>
    // <li>
    // <a href="#" aria-label="Next">
    //     <span aria-hidden="true">&raquo;</span>
    // </a>
    // </li>
    //</ul>
    //</nav>
  function build_page_nav(result) {
    //page_nav_area
       $("#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==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);//添加首页和前一页
      //ul中添加页面页码
       $.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");
  }
</script>


新增


新增-


逻辑


• 1、在


index.jsp


页面点击





新增




• 2、弹出新增对话框

• 3、去数据库查询部门列表,显示在对话框中

• 4、用户输入数据,并进行校验

• jquery前端校验,ajax


用户名重复校验,重要数据(后端校验


(JSR303)


,唯一约束);

• 5、完成保存


• URI:



• /emp/{id} GET 查询员工



• /emp POST 保存员工



• /emp/{id} PUT 修改员工



• /emp/{id} DELETE 删除员工


对话框,选用bootstrap插件的模态框
实现效果

<!-- 员工添加模态框 -->
<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" class="form-control" name="empName" id="empName_add_input" placeholder="empName">
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">email</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" name="email" id="email_add_input" placeholder="email@atguigu.com">
                        </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="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">
                            <!--部门提交部门ID即可-->
                            <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">保存</button>
            </div>
        </div>
    </div>
</div>

  //点击新增按钮弹出模态框
  $("#emp_add_modal_btn").click(function () {

    //弹出模态框
    $("#empAddModal").modal({
        backdrop:"static"
    });
  })


模态框的下拉列表要显示在数据库中的部门的下拉信息

{code: 100, msg: "处理成功", extend: {depts: [{deptId: 1, deptName: "开发部"}, {deptId: 2, deptName: "测试部"}]}}
code:100
extend:{depts: [{deptId: 1, deptName: "开发部"}, {deptId: 2, deptName: "测试部"}]}
msg:"处理成功"
//点击新增按钮弹出模态框
  $("#emp_add_modal_btn").click(function () {
      //发送ajax请求,查出部门信息,显示在下拉列表中
      getDepts();
    $("#empAddModal").modal({
        backdrop:"static"
    });
  })

    //查出所有的部门信息并显示在下拉列表中
    function getDepts() {
        $.ajax({
            url:"${APP_PATH}/depts",
            type: "GET",
            success:function (result) {
                //console.log(result)
                //显示部门信息在下拉列表中
                // $("#dept_add_select").append("")
                $.each(result.extend.depts,function () {
                    var optionEle = $("<option></option>").append(this.deptName).attr("value",this.deptId);
                    optionEle.appendTo("#dept_add_select");
                })

            }
        })
    }


departmentController

 */
@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);

    }
}


serviceController

@Service
public class DepartmentService {

    @Autowired
    private DepartmentMapper departmentMapper;

    public List<Department> getDepts() {
        List<Department> list = departmentMapper.selectByExample(null);
        return list;
    }
}


完成点击保存添加员工的方法

<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>
$("#emp_save_btn").click(function () {
        //`1.模态框中填写的表单数据提交给服务器进行保存
        //2.发送ajax保存员工
        //alert($("#empAddModal form").serialize());//empName=1&email=1&gender=M&dId=1
        $.ajax({
            url:"${APP_PATH}/emp",
            type:"POST",
            data: $("#empAddModal form").serialize(),//拿出表格中的内容为字符串,发送给服务器
            success:function (result) {//发送请求成功后
               // alert(result.msg);处理成功
                //员工保存成功:
                //1.关闭模态框
                $("#empAddModal").modal('hide');
                //2.来到最后一页,显示刚才保存的数据
                to_page(totalRecord);
            }
        })
    })

controller

/**
     * 员工保存
     * @param employee
     * @return
     */
    @RequestMapping(value = "/emp",method = RequestMethod.POST)
    @ResponseBody
    public Msg saveEmp(Employee employee){
        employeeService.saveEmp(employee);
        return Msg.success();
    }

service

    //员工保存方法
    public void saveEmp(Employee employee) {
        employeeMapper.insertSelective(employee);
    }


对待新增的数据进行校验,校验通过后保存


jquery前端校验,ajax用户名重复校验

<div class="col-sm-10">
    <input type="text" class="form-control" name="empName" id="empName_add_input" placeholder="empName">
    <span class="help-block"></span>
</div>

<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>
  //清空表单样式和内容
  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 () {
      //清除表单数据(表单数据和表单样式重置)
      //$("#empAddModal form")[0].reset();//reset是dom的方法(取出dom对象调用reset方法)
      reset_form("#empAddModal form");
      //发送ajax请求,查出部门信息,显示在下拉列表中
      getDepts();
    $("#empAddModal").modal({
        backdrop:"static"
    });
  })

... ... 
 //校验表单数据
    function validate_add_form() {
        //1.拿到要校验的数据,使用js正则进行
        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)) {
            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");
            $(ele).next("span").text(msg);
        }else if("error" == status){//校验失败
            $(ele).parent().addClass("has-error");
            $(ele).next("span").text(msg);
        }
    }

    //检验用户名是否可用
    $("#empName_add_input").change(function () {
        //发送ajax请求校验用户名是否可用
        var empName = this.value;//输入框的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");
                }
            }
        })
    })

controller

/**
     * 检查用户名是否可用
     * @param empName
     * @return
     */
   @RequestMapping("checkuser")
   @ResponseBody
    public Msg checkuse(@RequestParam("empName") String empName){
       //先判断用户名是否合法
       String rex = "(^[a-zA-Z0-9_-]{6,16}$)|(^[\\u2E80-\\u9FFF]{2,5})";
       if(!empName.matches(rex)){
           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","用户名不可用");
        }

    }

service

   /**
     * 检验用户名是否可用
     * true:可用,false:不可用
     * @param empName
     * @return
     */
    public boolean checkUser(String empName) {
        EmployeeExample example = new EmployeeExample();
        EmployeeExample.Criteria criteria = example.createCriteria();//创造查询条件
        criteria.andEmpNameEqualTo(empName);
        long count = employeeMapper.countByExample(example);//统计符合条件的记录数
        return count == 0;
    }


后端校验


采用springMVC提供的基于js的JSR303校验(重要数据校验)

前端校验更多的是给用户带来交互体验,关键数据上一定要前端校验后后台继续校验。

添加iar

    <!--JSR303数据校验支持;tomcat7及以上的服务器, 
tomcat7以下的服务器:el表达式。额外给服务器的lib包中替换新的标准的el
-->
    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>5.4.1.Final</version>
    </dependency>
  </dependencies>

employee

import javax.validation.constraints.Pattern;

public class Employee {
    private Integer empId;

    @Pattern(regexp = "(^[a-zA-Z0-9_-]{6,16}$)|(^[\\u2E80-\\u9FFF]{2,5})",message = "用户名必须是2-5位中文或者6-16位英文和数字的组合")
    private String empName;

    private String gender;

    //@Email
    @Pattern(regexp = "^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})",message = "邮箱格式不正确")
    private String email;

    private Integer dId;

    private Department department;
    ......
}

employeeController

  /**
     * 员工保存
     * 1.要支持JSR303校验,需要导入Hibernate-Validator
     * @param employee
     * @return
     */
    @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();
        }
    }

index.jsp

//点击保存,保存员工
    $("#emp_save_btn").click(function () {
        //1.模态框中填写的表单数据提交给服务器进行保存
        //1.对要先提交给服务器的数据进行校验
        // if(!validate_add_form()){//模拟绕过前端校验非法进行保存
        //     return false;
        // }

        //1.判断之前的ajax用户名校验是否成功,如果成功继续
        if($(this).attr("ajax-va")=="error"){//当前按钮的属性值
            return false;
        }

        //2.发送ajax保存员工
        //alert($("#empAddModal form").serialize());//empName=1&email=1&gender=M&dId=1
        $.ajax({
            url:"${APP_PATH}/emp",
            type:"POST",
            data: $("#empAddModal form").serialize(),//拿出表格中的内容为字符串,发送给服务器
            success:function (result) {//发送请求成功后
               // alert(result.msg);处理成功
                if(result.code==100){//后台验证反馈
                    //员工保存成功:
                    //1.关闭模态框
                    $("#empAddModal").modal('hide');
                    //2.来到最后一页,显示刚才保存的数据
                    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.errorFidlds.empName){
                        //显示员工名字的错误信息
                        show_validate_msg("#empName_add_input", "error", result.extend.errorFields.empName);
                    }
                }
            }
        })
    })


修改


修改-逻辑


• 1、点击编辑

• 2、弹出用户修改的模态框(显示用户信息)

• 3、点击更新,完成用户修改


修改的模态框

<!-- 员工修改的模态框 -->
<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="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">
		    	<!-- 部门提交部门id即可 -->
		      <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>

给编辑删除按钮添加class标识,绑定单击事件,使用

on

绑事件

   $(".edit_btn").click(function () {
        
    })

此处这方法无法绑定事件。因为绑事件的按钮是在ajax访问请求后才创建,而事件是在页面加载后就创建。(钮创建之前就绑定了click,所以绑定不上)

解决方法:1)、可以在创建按钮的时候绑定。耦合度高    2)、绑定点击.live()方法,jquery新版没有live,使用on进行替代

    //1、我们是按钮创建之前就绑定了click,所以绑定不上。
    //1)、可以在创建按钮的时候绑定。    2)、绑定点击.live()
    //jquery新版没有live,使用on进行替代
  $(document).on("click",".edit_btn",function () {
      //alert("alert");

  });


回显员工信息:

此示例员工名字不用修改,采用没有输入框的表单静态控件

<p class="form-control-static" id="empName_update_static"></p>

设置部门查询信息的ajax为同步,解决员工信息和部门信息结果查询不一致的问题

controller 处理查询员工信息的方法

    /**
     * 按照员工id查询员工
     * @param id
     * @return
     */
    @RequestMapping(value = "emp/{id}",method = RequestMethod.GET)
    @ResponseBody
    public Msg getEmp(@PathVariable("id") Integer id){
        Employee employee = employeeService.getEmp(id);
        return Msg.success().add("emp",employee);
    }

service

    /**
     * 按照员工id查询
     * @param id
     * @return
     */
    public Employee getEmp(Integer id) {
        Employee employee = employeeMapper.selectByPrimaryKey(id);
        return employee;
    }

如何获取修改员工的id

给编辑按钮自定义一个属性,属性的值就是员工的id

 var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm edit_btn").append($("<span></span>").addClass("glyphicon glyphicon-pencil")).append("编辑");
 //为编辑按钮添加一个自定义的属性,来表示当前员工id
editBtn.attr("edit-id",item.empId);
    //1、我们是按钮创建之前就绑定了click,所以绑定不上。
    //1)、可以在创建按钮的时候绑定。    2)、绑定点击.live()
    //jquery新版没有live,使用on进行替代
  $(document).on("click",".edit_btn",function () {
      //alert("alert");
      //1、查出部门信息,并显示部门列表
      getDepts("#empUpdateModal select");
      //2、查出员工信息,显示员工信息
        getEmp($(this).attr("edit-id"));//this表示当前被点击的按钮
      $("#empUpdateModal").modal({
          backdrop:"static"
      });

  });

    function getEmp(id) {
        $.ajax({
            url:"${APP_PATH}/emp/"+id,
            type:"GET",
            success:function (result) {
                //console.log(result);
                var empData = result.extend.emp;
                $("#empName_update_static").text(empData.empName);
                $("#email_Update_input").val(empData.email);
                $("#empUpdateModal input[name=gender]").val([empData.gender]);
                $("#empUpdateModal select").val([empData.dId]);
            }
        })
    }

给更新按钮绑定单机事件

web.xml

	<!-- 4、使用Rest风格的URI,将页面普通的post请求转为指定的delete或者put请求 -->
	<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>

员工id传递到更新按钮上(通过编辑按钮)

  $(document).on("click",".edit_btn",function () {
      //alert("alert");
      //1、查出部门信息,并显示部门列表
      getDepts("#empUpdateModal select");
      //2、查出员工信息,显示员工信息
        getEmp($(this).attr("edit-id"));//this表示当前被点击的按钮

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

  });
 //点击更新,更新员工信息
    $("#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:"POST",
            data:$("#empUpdateModal form").serialize()+"&_method=PUT",
            success:function (result) {
                alert(result.msg);
            }
        })
    })

此时发现更新没有生效,测试发现controller中的employee为

将要更新的员工数据Employee{


empId=null, empName=’null’

, gender=’M’, email=’ed6062@guigu.com’, dId=1, department=null}

发现因为empId是null,所以sql没有执行更新。将路径id写成empId

@RequestMapping(value = "/emp/{empId}",method = RequestMethod.PUT)
@ResponseBody
public Msg saveEmp(Employee employee){
}

jquery的ajax能直接发送PUT请求

如果直接发送ajax=PUT形式的请求,则封装的数据为Employee [empId=1014, empName=null, gender=null, email=null, dId=null]

问题:

请求体中有数据;但是Employee对象封装不上;update tbl_emp  where emp_id = 1014;


解决方案


我们要能支持直接发送PUT之类的请求还要封装请求体中的数据

1、配置上HttpPutFormContentFilter;

2、作用;将请求体中的数据解析包装成一个map。

3、request被重新包装,request.getParameter()被重写,就会从自己封装的map中取数据

员工更新方法

<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>
 //点击更新,更新员工信息
    $("#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) {
               //1.关闭对话框
                $("#empUpdateModal").modal("hide");
                //2.回到本页面
                to_page(currentPage);
            }
        })
    })
</script>

controller
    @RequestMapping(value = "/emp/{empId}",method = RequestMethod.PUT)
    @ResponseBody
    public Msg saveEmp(Employee employee){
        System.out.println("将要更新的员工数据"+employee);
        employeeService.updateEmp(employee);
        return Msg.success();
    }

service

    /**
     * 员工更新
     * @param employee
     */
    public void updateEmp(Employee employee) {
        employeeMapper.updateByPrimaryKeySelective(employee);
    }


删除


删除-逻辑


• 1、单个删除

• URI:/emp/{id} DELETE

• 2、批量删除
单个删除
controller
   @RequestMapping(value = "/emp/{id}",method = RequestMethod.DELETE)
    @ResponseBody
    public Msg deleteEmpById(@PathVariable("id") Integer id){
        employeeService.deleteEmp(id);
        return Msg.success();
    }

service
    public void deleteEmp(Integer id) {
        employeeMapper.deleteByPrimaryKey(id);
    }

//为删除按钮添加一个自定义的属性,来表示当前员工id
delBtn.attr("del_id",item.empId);

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


全选全不选

 <!--显示表格数据-->
    <div class="row">
        <table class="table table-hover" id="emps_table">
            <thead>
            <tr>
                <th>
                    <input type="checkbox" id="check_all"/>
                </th>
                <th>#</th>
                <th>empName</th>
                ......
//完成全选/全不选功能
		$("#check_all").click(function(){
			//attr获取checked是undefined;
			//我们这些dom原生的属性;attr获取自定义属性的值;
			//prop修改和读取dom原生属性的值
			$(".check_item").prop("checked",$(this).prop("checked"));
		});
		
		//check_item
		$(document).on("click",".check_item",function(){
			//判断当前选择中的元素是否5个
			var flag = $(".check_item:checked").length==$(".check_item").length;//.check_item:checked匹配被选中的复选框
			$("#check_all").prop("checked",flag);
		});


全部删除

 <!--按钮-->
    <div class="row">
        <div class="col-md-4 col-md-offset-8"><!--占四列,偏移8列-->
            <button class="btn btn-primary" id="emp_add_modal_btn">新增</button>
            <button class="btn btn-danger" id="emp_delete_all_btn">删除</button>
        </div>
    </div>
    controller
    @RequestMapping(value = "/emp/{ids}",method = RequestMethod.DELETE)
    @ResponseBody
    public Msg deleteEmp(@PathVariable("ids") String ids){
        if(ids.contains("-")){
            String[] split = ids.split("-");
            List<Integer> del_ids= new ArrayList<>();
            for(String s:split){
                del_ids.add(Integer.parseInt(s));
            }
            employeeService.deleteBatch(del_ids);
        }else{
            Integer id = Integer.parseInt(ids);
            employeeService.deleteEmp(id);
        }
        return Msg.success();
    }
service
public void deleteBatch(List<Integer> del_ids) {
        EmployeeExample example = new EmployeeExample();
        EmployeeExample.Criteria criteria = example.createCriteria();
        criteria.andEmpIdIn(del_ids);
        employeeMapper.deleteByExample(example);
    }
    $("#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,empNames.length-1);
        if(confirm("确定要删除【"+empNames+"】吗?")){
            $.ajax({
                url:"${APP_PATH}/emp/"+del_idstr,
                type:"DELETE",
                success:function (result) {
                    alert(result.msg);
                    to_page(currentPage);
                }
            })
        }
    })


总结

执行maven的install,会在工程的target文件夹下生成ssm-crud-new.war,将此war放在tomcat的webapp文件夹下,执行tomcat文件夹下的startup.bat命令,会生成war对应的工程文件,在浏览器中输入localhost:8080//工程名即可本地运行此项目。



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