码迷,mamicode.com
首页 > 其他好文 > 详细

SSM整合

时间:2021-06-21 21:10:42      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:drive   组件   random   dep   input   rtp   运行环境   tde   tran   

SSM整合

功能点

  • 分页
  • 数据校验
    • jquery前端校验+JSR303后端校验
  • ajax
  • Rest风格的URI;使用HTTP协议请求方式的动词,来表示对资 源的操作(GET(查询),POST(新增),PUT(修改),DELETE (删除))

技术点

  • 基础框架-ssm(SpringMVC+Spring+MyBatis)
  • 数据库-MySQL
  • 前端框架-bootstrap快速搭建简洁美观的界面
  • 项目的依赖管理-Maven
  • 分页-pagehelper
  • 逆向工程-MyBatis Generato

基础环境搭建

在eclipse中创建maven工程

技术图片

技术图片

技术图片

创建完成,如下

技术图片

由于缺少web.xml配置文件,补上即可

点击项目名--》鼠标右键--》Properties--》Project facets

技术图片

技术图片

技术图片

创建成功,目录结构

技术图片

引入相关jar包

  • spring
  • springmvc ?
  • mybatis ?
  • 数据库连接池,驱动包
  • 其他(jstl,servlet-api,junit)
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.atguigu</groupId>
	<artifactId>ssm-crud</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>


	<!--引入项目依赖的jar包 -->
	<!-- SpringMVC、Spring -->
	<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
	<dependencies>

		


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

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


		<!-- 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>
		</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>
        
        <!--引入pageHelper分页插件 -->
		<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>
	</dependencies>




</project>

引入Bootstrap前端框架

官网:https://v3.bootcss.com/

技术图片

技术图片

在项目中引入bootstrap方法

方法一:直接使用这些 BootstrapCDN 提供的链接即可。缺点:需要联网

<!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">

<!-- 可选的 Bootstrap 主题文件(一般不用引入) -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap-theme.min.css" integrity="sha384-6pzBo3FDv/PJ8r2KRkGHifhEocL+1X2rVCTTkUfGk7/0pbek5mMa1upzvWbrUbOZ" crossorigin="anonymous">

<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>

方法二:

把下载好的bootstrap压缩包,解压,放在项目中,另外还需要加入jQuery的支持(自行下载)

技术图片

示例

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet"
	href="static/bootstrap-3.4.1-dist/css/bootstrap.min.css">
<title>Insert title here</title>
</head>
<body>
 <jsp:forward page="/emps"/> 


	<script src="static/js/jquery-1.12.4.min.js"></script>
	<!--jquery的js引入文件一定要放在bootstrap的js引入文件之前  -->
	<script src="static/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
</body>
</html>

搭建ssm基本环境

需要编写web.xml, spring, springmvc, mybatis等相关配置文件

web.xml文件解析

1,启动Spring的容器

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

	<!-- Bootstraps the root web application context before servlet initialization -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

2,springmvc的前端控制器,拦截所有请求

? 方法一:在<param-value>location</param-value>中配置springmvc.xml文件路径,

		<!--2、springmvc的前端控制器,拦截所有请求  -->
	<servlet>
		<servlet-name>dispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>location</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>dispatcherServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

? 方法二:去掉以及其子标签,但是需要在web.xml的同级目录下配置springmvc配置文件:xxx-servlet.xml,此文件命名有要求,必须是servlet-name中的值-servlet,例如:dispatcherServlet-servlet.xml

		<!--2、springmvc的前端控制器,拦截所有请求  -->
	<servlet>
		<servlet-name>dispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	</servlet>
	<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>
		<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>

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

	<!-- Bootstraps the root web application context before servlet initialization -->
	<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>
		<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>
		<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>
	
	
</web-app>

springmvc配置文件:dispatcherServlet-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

	<!--SpringMVC的配置文件,包含网站跳转逻辑的控制,配置 -->
	<context:component-scan
		base-package="com.atguigu" use-default-filters="false">
		<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更高级的一些功能,JSR303校验,快捷的ajax...映射动态请求 -->
	<mvc:annotation-driven></mvc:annotation-driven>
	<!-- 将springmvc不能处理的请求交给tomcat ,主要处理静态资源,例如jsp,html,js等 -->
	<mvc:default-servlet-handler />

</beans>

在项目中创建相应的package

技术图片

spring配置文件:applicationContext.xml

Spring配置文件的核心点(数据源、与mybatis的整合,事务控制)

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

<!-- 扫描 -->
<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="dataSource" 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="dataSource"></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.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>
	<!--=============================================  -->

	<!-- ===============事务控制的配置 ================-->
	 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<!--控制住数据源  -->
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!--开启基于注解的事务,使用xml配置形式的事务(必要主要的都是使用配置式)  -->
	<aop:config>
		<!-- 切入点表达式 -->
		<aop:pointcut expression="execution(* com.atguigu.crud.service..*(..))" id="txPoint"/>
		<!-- 配置事务增强 -->
		<aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
	</aop:config>
	
	<!--配置事务增强,事务如何切入  -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<!-- 所有方法都是事务方法 -->
			<tx:method name="*"/>
			<!--以get开始的所有方法  -->
			<tx:method name="get*" read-only="true"/>
		</tx:attributes>
	</tx:advice>
	
	<!-- Spring配置文件的核心点(数据源、与mybatis的整合,事务控制) -->
	
</beans>

mybatis配置文件:mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--驼峰命名-->
	<settings>
		<setting name="mapUnderscoreToCamelCase" value="true" />
	</settings>
    
    <!--包的别名-->
	<typeAliases>
		<package name="com.atguigu.bean" />
	</typeAliases>
<plugins>
	<plugin interceptor="com.github.pagehelper.PageInterceptor">
	<!-- 分页合理化,若要查询的页码小于0,则只会查第一页;若若要查询的页码大于最后一页,则只会查询最后一页 -->
		<property name="reasonable" value="true"/>
	</plugin>
</plugins>
</configuration>

mybatis逆向工程:

  1. 创建数据表

    部门表:tbl_dept

    DROP TABLE IF EXISTS `tbl_dept`;
    CREATE TABLE `tbl_dept`  (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `dept_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
    
    

    员工表:tbl_employee

    DROP TABLE IF EXISTS `tbl_employee`;
    CREATE TABLE `tbl_employee`  (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `last_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      `gender` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      `email` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      `d_id` int(11) NULL DEFAULT NULL,
      `empStatus` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      PRIMARY KEY (`id`) USING BTREE,
      INDEX `fk_emp_dept`(`d_id`) USING BTREE,
      CONSTRAINT `fk_emp_dept` FOREIGN KEY (`d_id`) REFERENCES `tbl_dept` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
    ) 
    
  2. 导入mybatis generator依赖

    		<dependency>
    			<groupId>org.mybatis.generator</groupId>
    			<artifactId>mybatis-generator-core</artifactId>
    			<version>1.3.7</version>
    		</dependency>
    
  3. mybatis generator配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE generatorConfiguration
      PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
      "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
    
    <generatorConfiguration>
    
    	<context id="DB2Tables" targetRuntime="MyBatis3">
    <!-- 取消注释 -->	
    		<commentGenerator>
    			<property name="suppressAllComments" value="true" />
    		</commentGenerator>
    		<jdbcConnection driverClass="com.mysql.jdbc.Driver"
    			connectionURL="jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true"
    			userId="root" password="123123">
    		</jdbcConnection>
    
    		<javaTypeResolver>
    			<property name="forceBigDecimals" value="false" />
    		</javaTypeResolver>
    <!-- Bean类 -->
    		<javaModelGenerator
    			targetPackage="com.atguigu.bean" targetProject="./src/main/java/">
    			<property name="enableSubPackages" value="true" />
    			<property name="trimStrings" value="true" />
    		</javaModelGenerator>
    <!-- 映射文件 -->
    		<sqlMapGenerator targetPackage="mapper"
    			targetProject="./src/main/resources/">
    			<property name="enableSubPackages" value="true" />
    		</sqlMapGenerator>
    <!-- Mapper接口 -->
    		<javaClientGenerator type="XMLMAPPER"
    			targetPackage="com.atguigu.dao" targetProject="./src/main/java/">
    			<property name="enableSubPackages" value="true" />
    		</javaClientGenerator>
    <!-- 关联数据库表 -->
    		<table tableName="tbl_dept" domainObjectName="Department" />
    		<table tableName="tbl_employee" domainObjectName="Employee"></table>
    
    
    	</context>
    </generatorConfiguration>
    
  4. 运行

    	@Test
    	public void test01() throws Exception {
    		List<String> warnings = new ArrayList<String>();
    		boolean overwrite = true;
    		File configFile = new File("mbg.xml");
    		ConfigurationParser cp = new ConfigurationParser(warnings);
    		Configuration config = cp.parseConfiguration(configFile);
    		DefaultShellCallback callback = new DefaultShellCallback(overwrite);
    		MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
    		myBatisGenerator.generate(null);
    	}
    

    技术图片

  5. 此时的Mapper文件中只能做一些简单的增删改查,若想用复杂的连表查询,需要在对应的Mapper文件中自定义查询语句

    需求:查询员工的时候,可以一并查询查对应的员工部门

    在EmployeeBean中加入Department属性,并添加对应的get,set方法和构造器

    package com.atguigu.bean;
    
    public class Employee {
    	private Integer id;
    
    	private String lastName;
    
    	private String gender;
    
    	private String email;
    
    	private Integer dId;
    
    	private String empstatus;
    
    	private Department department;
    
    	public Department getDepartment() {
    		return department;
    	}
    
    	public void setDepartment(Department department) {
    		this.department = department;
    	}
    
    	public Integer getId() {
    		return id;
    	}
    
    	public void setId(Integer id) {
    		this.id = id;
    	}
    
    	public String getLastName() {
    		return lastName;
    	}
    
    	public void setLastName(String lastName) {
    		this.lastName = lastName == null ? null : lastName.trim();
    	}
    
    	public String getGender() {
    		return gender;
    	}
    
    	public void setGender(String gender) {
    		this.gender = gender == null ? null : gender.trim();
    	}
    
    	public Employee() {
    		super();
    	}
    
    	public Employee(Integer id, String lastName, String gender, String email, Integer dId, String empstatus,
    			Department department) {
    		super();
    		this.id = id;
    		this.lastName = lastName;
    		this.gender = gender;
    		this.email = email;
    		this.dId = dId;
    		this.empstatus = empstatus;
    		this.department = department;
    	}
    
    	public Employee(Integer id, String lastName, String gender, String email, Integer dId, String empstatus) {
    		super();
    		this.id = id;
    		this.lastName = lastName;
    		this.gender = gender;
    		this.email = email;
    		this.dId = dId;
    		this.empstatus = empstatus;
    	}
    
    	public String getEmail() {
    		return email;
    	}
    
    	public void setEmail(String email) {
    		this.email = email == null ? null : email.trim();
    	}
    
    	public Integer getdId() {
    		return dId;
    	}
    
    	public void setdId(Integer dId) {
    		this.dId = dId;
    	}
    
    	public String getEmpstatus() {
    		return empstatus;
    	}
    
    	public void setEmpstatus(String empstatus) {
    		this.empstatus = empstatus == null ? null : empstatus.trim();
    	}
    
    	@Override
    	public String toString() {
    		return "Employee [id=" + id + ", lastName=" + lastName + ", gender=" + gender + ", email=" + email + ", dId="
    				+ dId + ", empstatus=" + empstatus + ", department=" + department + "]";
    	}
    }
    

    在对应的Mapper接口中添加

    //查询有Department信息
    	List<Employee> selectByExampleWithDept(EmployeeExample example);
    
    //根据主键查询有Department信息
    	Employee selectByPrimaryKeyWithDept(Integer id);
    

    EmployeeMapper.java完整结构如下

    package com.atguigu.dao;
    
    import java.util.List;
    
    import org.apache.ibatis.annotations.Param;
    
    import com.atguigu.bean.Employee;
    import com.atguigu.bean.EmployeeExample;
    
    public interface EmployeeMapper {
    	long countByExample(EmployeeExample example);
    
    	int deleteByExample(EmployeeExample example);
    
    	int deleteByPrimaryKey(Integer id);
    
    	int insert(Employee record);
    
    	int insertSelective(Employee record);
    
    	List<Employee> selectByExample(EmployeeExample example);
    
    	Employee selectByPrimaryKey(Integer id);
    
    //查询有Department信息
    	List<Employee> selectByExampleWithDept(EmployeeExample example);
    
    //根据主键查询有Department信息
    	Employee selectByPrimaryKeyWithDept(Integer id);
    
    	int updateByExampleSelective(@Param("record") Employee record, @Param("example") EmployeeExample example);
    
    	int updateByExample(@Param("record") Employee record, @Param("example") EmployeeExample example);
    
    	int updateByPrimaryKeySelective(Employee record);
    
    	int updateByPrimaryKey(Employee record);
    }
    

    在对应的Mapper文件中添加SQL语句

    EmployeeMappper.xml

     <!-- 新增 --> 
      <resultMap id="WithDeptResultMap" type="com.atguigu.bean.Employee">
        <id column="id" jdbcType="INTEGER" property="id" />
        <result column="last_name" jdbcType="VARCHAR" property="lastName" />
        <result column="gender" jdbcType="CHAR" property="gender" />
        <result column="email" jdbcType="VARCHAR" property="email" />
        <result column="d_id" jdbcType="INTEGER" property="dId" />
        <result column="empStatus" jdbcType="VARCHAR" property="empstatus" />
        <association property="department" javaType="com.atguigu.bean.Department">
        	<id column="id" jdbcType="INTEGER" property="id" />
        	<result column="dept_name" jdbcType="VARCHAR" property="deptName"/>
        </association>
      </resultMap>  
      <!--新增   -->
      <sql id="WithDept_Column_List">
        e.id, e.last_name, e.gender, e.email, e.d_id, e.empStatus,d.id, d.dept_name
      </sql>
      
      <!--List<Employee> selectByExampleWithDept(EmployeeExample example);  -->
      <select id="selectByExampleWithDept" parameterType="com.atguigu.bean.EmployeeExample" resultMap="WithDeptResultMap">
        select
        <if test="distinct">
          distinct
        </if>
        <include refid="WithDept_Column_List" />
        from tbl_employee e left join tbl_dept on e.d_id = d.id
        <if test="_parameter != null">
          <include refid="Example_Where_Clause" />
        </if>
        <if test="orderByClause != null">
          order by ${orderByClause}
        </if>
      </select>
      <!--Employee selectByPrimaryKeyWithDept(Integer id);  -->
      <select id="selectByPrimaryKeyWithDept" parameterType="java.lang.Integer" resultMap="WithDeptResultMap">
        select 
        <include refid="WithDept_Column_List" />
        from tbl_employee e left join tbl_dept on e.d_id = d.id
        where e.id = #{id,jdbcType=INTEGER}
      </select>
      
    
  6. 测试:

    	@Test
    	public void test01() {
    		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
    				"applicationContext.xml");
    		EmployeeMapper mapper = applicationContext.getBean(EmployeeMapper.class);
    		long countByExample = mapper.countByExample(null);
    		System.out.println(countByExample);
    	}
    
    

    测试结果:

    技术图片

    推荐Spring的项目就可以使用Spring的单元测试,可以自动注入我们需要的组件

    1、导入SpringTest模块

    	<dependency>
    		<groupId>org.springframework</groupId>
    		<artifactId>spring-test</artifactId>
    		<version>5.3.6</version>
    		<scope>test</scope>
    	</dependency>
    

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

    3、@RunWith(SpringJUnit4ClassRunner.class): 指定用SpringJunit的运行环境

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

    测试类如下

    import java.util.List;
    import java.util.UUID;
    
    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 com.atguigu.bean.Employee;
    import com.atguigu.dao.EmployeeMapper;
    import com.github.pagehelper.PageHelper;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = { "classpath:applicationContext.xml" })
    public class MapperTest {
    	@Autowired
    	EmployeeMapper employeeMapper;
    	@Autowired
    	SqlSession sqlSession;
    
    	@Test
    	public void test01() {
    		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
    				"applicationContext.xml");
    		EmployeeMapper mapper = applicationContext.getBean(EmployeeMapper.class);
    		long countByExample = mapper.countByExample(null);
    		System.out.println("总记录数:" + countByExample);
    	}
    
    	// 插入
    	@Test
    	public void test02() {
    		employeeMapper.insertSelective(new Employee(null, "ADBCEE", "0", "126@qq.com", 2, "300"));
    
    	}
    
    	// 批量插入
    	@Test
    	public void test04() {
    		EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
    		String gender = null;
    		String last_name = null;
    		int dId = 1;
    		for (int i = 1; i <= 100; i++) {
    			if (i % 2 == 0) {
    				gender = "0";
    			} else
    				gender = "1";
    			last_name = UUID.randomUUID().toString().substring(0, 5);
    			dId = (int) (Math.random() * 3) + 1;
    			mapper.insertSelective(new Employee(null, last_name, gender, last_name + "126@qq.com", dId, "200"));
    		}
    		System.out.println("批量插入完成");
    	}
    
    	// 测试selectByExampleWithDept()
    	@Test
    	public void test05() {
    		PageHelper.startPage(1, 5);
    		List<Employee> list = employeeMapper.selectByExampleWithDept(null);
    		for (Employee employee : list) {
    			System.out.println(employee);
    		}
    	}
    
    	// 测试selectByPrimaryKeyWithDept()
    	@Test
    	public void test06() {
    		Employee employee = employeeMapper.selectByPrimaryKeyWithDept(1);
    		System.out.println(employee);
    	}
    }
    
    

    注意:

    做批量操作时,一定要配置Spring配置文件中(applicationContext.xml)配置SqlSessionTemplate对象

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

开始编写CRUD

1.编写EmployeeController

在编写Controller之前,可以配置pageHelp插件

  • ? 引入pageHelp依赖

    		<dependency>
    			<groupId>com.github.pagehelper</groupId>
    			<artifactId>pagehelper</artifactId>
    			<version>5.2.0</version>
    		</dependency>
    
  • 在mybatis-config.xml配置pageHelp过滤器

    <plugins>
    	<plugin interceptor="com.github.pagehelper.PageInterceptor">
    	<!-- 分页合理化,若要查询的页码小于0,则只会查第一页;若若要查询的页码大于最后一页,则只会查询最后一页 -->
    		<property name="reasonable" value="true"/>
    	</plugin>
    </plugins>
    

配置Controller

@Controller
public class EmployeeController {
	@Autowired
	EmployeeService employeeService;

	@RequestMapping("/emps")
	public String list(@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum, Model model) {
		PageHelper.startPage(1, 5);
		List<Employee> list = employeeService.getAll();
		// 使用pageInfo包装查询后的结果,只需要将pageInfo交给页面就行了。
		// 封装了详细的分页信息,包括有我们查询出来的数据,传入连续显示的页数
		PageInfo page = new PageInfo(list, 5);
		for (Employee employee : list) {
			System.out.println(employee);
		}
		model.addAttribute("pageInfo", list);
		return "list";
	}
}

配置Service层

@Service
public class EmployeeService {
	@Autowired
	EmployeeMapper employeeMapper;
	public List<Employee> getAll() {
		List<Employee> list = employeeMapper.selectByExampleWithDept(null);
		return list;
	}
}

2.Spring测试模块

使用Spring测试模块提供的测试请求功能,测试curd请求的正确性,Spring4测试的时候,需要servlet3.0的支持

主要作用:不用启动tomcat服务器测试业务逻辑

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:applicationContext.xml",
		"file:src/main/webapp/WEB-INF/dispatcherServlet-servlet.xml" })
@WebAppConfiguration
public class MvcTest {
	
	// 传入Springmvc的ioc,依赖@webAppConfiguration注解
	@Autowired
	WebApplicationContext context;
	// 虚拟mvc请求,获取到处理结果。
	MockMvc mockMvc;

	@Before
	public void initMockMvc() {
		mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
	}

	@Test
	public void testPage() throws Exception {
		ResultActions resultActions = mockMvc.perform(MockMvcRequestBuilders.get("/emps").param("pageNum", "1"));
		//模拟请求拿到返回值
		MvcResult result = resultActions.andReturn();
		
		//请求成功以后,请求域中会有pageInfo;我们可以取出pageInfo进行验证
		MockHttpServletRequest request = result.getRequest();
		PageInfo pi = (PageInfo) request.getAttribute("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);
		}

		// 获取员工数据
		List<Employee> list = pi.getList();
		for (Employee employee : list) {
			System.out.println(employee);
		}
	}

}

测试结果

技术图片

3.编写一个index.jsp

引入bootstrap

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<%
	pageContext.setAttribute("basePath", request.getContextPath());
%>

<link rel="stylesheet"
	href="${basePath }/static/bootstrap-3.4.1-dist/css/bootstrap.min.css">
<title>index</title>

<script src="${basePath }/static/js/jquery-1.12.4.min.js"></script>
<script
	src="${basePath }/static/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
</head>
<body>
	<div class="container">
		<!-- 页头 -->
		<div class="row">
			<div class="page-header">
				<h1>
					Example page header <small>Subtext for header</small>
				</h1>
			</div>
		</div>
		<!-- 按钮 -->
		<div class="row">
			<div class="col-md-2 col-md-offset-10">
				<button class="btn btn-primary" id="emp_add_modal_btn">增加</button>
				<button class="btn btn-danger" id="emp_delete_modal_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>empId</th>
							<th>empName</th>
							<th>gender</th>
							<th>email</th>
							<th>empstatus</th>
							<th>deptName</th>
							<th>操作</th>
						</tr>
					</thead>
					<!--表体  -->
					<tbody>

					</tbody>
				</table>
			</div>
		</div>
		<!-- 分页 -->
		<div class="row">
			<div class="col-md-6" id="page_info_area"></div>
			<div class="col-md-6" id="page_nav_area"></div>
		</div>
	</div>
</body>
</html>

技术图片

访问服务器返回数据,一般比较通用的方法:从后台返回一个字符串,而不是一个页面

重新编写Controller层

	@RequestMapping("/emps")
	@ResponseBody
	public PageInfo getEmpsWithJson(@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum) {
		PageHelper.startPage(1, 5);
		List<Employee> list = employeeService.getAll();
		// 使用pageInfo包装查询后的结果,只需要将pageInfo交给页面就行了。
		// 封装了详细的分页信息,包括有我们查询出来的数据,传入连续显示的页数
		PageInfo page = new PageInfo(list, 5);
		return page;
	}

还需要添加能解析和封装json字符串的工具,比如

<!-- json插件 -->		
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.12.3</version>
		</dependency>

在用户栏中输入访问地址:http://localhost:8080/ssm/emps,结果会返回一个json字符串,如下

技术图片

但是上面返回的字符串没有通用姓,客户不知道返回的数据是否是想要的还是不想要的,也不知道正确与否

我们需要编写一个通用的类,封装好json字符串

编写Msg类:

package com.atguigu.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 msg = new Msg();
		msg.setCode(100);
		msg.setMsg("处理成功!");
		return msg;
	}

	public static Msg fail() {
		Msg msg = new Msg();
		msg.setCode(200);
		msg.setMsg("处理失败!");
		return msg;
	}

	public Msg add(String key, Object value) {
		this.getExtend().put(key, value);
		return this;
	}

	public Msg(int code, String msg, Map<String, Object> extend) {
		super();
		this.code = code;
		this.msg = msg;
		this.extend = extend;
	}

	public Msg() {
		super();
	}

	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方法

	// 导入jackson依赖
	// 返回json字符串
	@RequestMapping("/emps")
	@ResponseBody
	public Msg getEmpsWithJson(@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum) {
		PageHelper.startPage(1, 5);
		List<Employee> list = employeeService.getAll();
		// 使用pageInfo包装查询后的结果,只需要将pageInfo交给页面就行了。 // 封装了详细的分页信息,包括有我们查询出来的数据,传入连续显示的页数
		PageInfo page = new PageInfo(list, 5);
		return Msg.success().add("pageInfo", page);
	}

测试:在用户栏中输入访问地址:http://localhost:8080/ssm/emps,结果会返回一个json字符串,如下

技术图片

查询

  1. index.jsp页面直接发送ajax请求进行员工分页数据的查询
  2. 服务器将查出的数据,以json字符串的形式返回给浏览器
  3. 浏览器收到js字符串。可以使用js对json进行解析,使用js通过 dom增删改改变页面。
  4. 返回json。实现客户端的无关性。

现在可以把返回的json字符串进行Dom的拼装,然后显示在页面上,关键是写js代码,过程很繁琐,需要有点耐心

步骤1:

思路:当访问首页的时候,自动显示数据(即json字符串拼装Dom,放在页面的相应位置)

? 页面布局:主要分为四个模块:模态框,表格数据,分页,分页导航条

技术图片

下列方法介绍:

to_page(pageNum):跳转到第pageNum页

build_emps_table(result) :显示表格中的数据

function build_page_info(result):显示分页数据

build_page_nav(result):显示分页导航条数据,点击能去到相应的页面

<script type="text/javascript">
	//默认调转到第一页
	var currentPage;
	$(function() {
		to_page(1);
	});
	//跳转页面
	function to_page(pageNum) {
		$.ajax({
			url : "${basePath}/emps",
			data : "pageNum=" + pageNum,
			type : "GET",
			success : function(result) {
				//console.log(result);
				//1、解析并显示员工数据
				build_emps_table(result);
				//2、解析并显示分页信息
				build_page_info(result);
				//3、解析显示分页条数据
				build_page_nav(result);
			}
		});
	}
	//1、解析并显示员工数据
	function build_emps_table(result) {
		console.log(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 empId = $("<td></td>").append(item.id);
			var empName = $("<td></td>").append(item.lastName);
			var gender = $("<td></td>").append(item.gender == "0" ? "男" : "女");
			var email = $("<td></td>").append(item.email);
			var empstatus = $("<td></td>").append(item.empstatus);
			var deptName = $("<td></td>").append(item.department.deptName);
	//		<button type="button" class="btn btn-primary"><span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> 修改</button>
			var edit_btn = $("<button></button>").addClass("btn btn-primary btn-sm ").append($("<span></span>").addClass("glyphicon glyphicon-pencil")).append("编辑");
			var delete_btn = $("<button></button>").addClass("btn btn-danger btn-sm ").append($("<span></span>").addClass("glyphicon glyphicon-trash")).append("删除");
			var btnTd = $("<td></td>").append(edit_btn).append(" ").append(delete_btn);
			$("<tr></tr>").append(checkBoxTd).append(empId).append(empName).append(gender).append(email).append(empstatus).append(deptName).append(edit_btn)
			.append(delete_btn).append(btnTd).appendTo("#emps_table tbody");
		});

	}
	//2、解析并显示分页信息
	function build_page_info(result) {
		//获取数据前,需要先清空原先的数据
		$("#page_info_area").empty();
		$("#page_info_area").append("当前"+result.extend.pageInfo.pageNum+"页,总"+
				result.extend.pageInfo.pages+"页,总"+
				result.extend.pageInfo.total+"条记录");
		currentPage = result.extend.pageInfo.pageNum;
	}
	//3、解析显示分页条数据,点击能去到相应的页面
	function build_page_nav(result) {
		//获取数据前,需要先清空原先的数据
		$("#page_nav_area").empty();
		var nav = $("<nav aria-label=‘Page navigation‘></nav>");
		var ul = $("<ul></ul>").addClass("pagination");
		var firstPageLi = $("<li></li>").append($("<a></a>").attr({"href":"#"})
				.append($("<span></span>").attr("aria-hidden","true").append("首页")));
		var prePageLi = $("<li></li>").append($("<a></a>").attr({"href":"#","aria-label":"true"})
				.append($("<span></span>").attr("aria-hidden","true").append("&laquo;")));
		if(!result.extend.pageInfo.hasPreviousPage){
			firstPageLi.addClass("disabled");
			prePageLi.addClass("disabled");
		}else{
			firstPageLi.click(function(){
				to_page(1);
			});
			prePageLi.click(function(){
				to_page(result.extend.pageInfo.pageNum - 1);
			});
		}
		
		//添加首页和前一页 的提示
		ul.append(firstPageLi).append(prePageLi);
		
		$.each(result.extend.pageInfo.navigatepageNums,function(index,item){
			var li = $("<li></li>").append($("<a></a>").attr("href","#").append(item));
			//如果等于当前页,添加样式
			if(currentPage == item){
				li.addClass("active");
			}
			//给每个li绑定点击事件
			li.click(function(){
				to_page(item);
			});
			ul.append(li);
		});
		
		var nextPageLi = $("<li></li>").append($("<a></a>").attr({"href":"#","aria-label":"true"})
				.append($("<span></span>").attr("aria-hidden","true").append("&raquo;")));
		var lastPageLi = $("<li></li>").append($("<a></a>").attr({"href":"#"})
				.append($("<span></span>").attr("aria-hidden","true").append("末页")));
		if(!result.extend.pageInfo.hasNextPage){
			nextPageLi.addClass("disabled");
			lastPageLi.addClass("disabled");
		}else{
			nextPageLi.click(function(){
				to_page(result.extend.pageInfo.pageNum + 1);
			});
			lastPageLi.click(function(){
				to_page(result.extend.pageInfo.pages);
			});
		}
		//添加末页和下一页 的提示
		ul.append(nextPageLi).append(lastPageLi);
		nav.append(ul).appendTo("#page_nav_area");
	}
</script>

结果

技术图片

注意:在分页导航中,点击页码跳转的时候,一定要注意页码的超出范围

在mybatis-config.xml配置文件中配置一下插件就非常安全了

<plugins>
	<plugin interceptor="com.github.pagehelper.PageInterceptor">
	<!-- 分页合理化,若要查询的页码小于0,则只会查第一页;若若要查询的页码大于最后一页,则只会查询最后一页 -->
		<property name="reasonable" value="true"/>
	</plugin>
</plugins>
  • 当前页码是第一页,如果在点击上一页,页面中显示的还是第一页(pageNum<=1,显示第一页)
  • 当前页码是末页,如果在点击下一页,页面中显示的还是末页(pageNum>=末页,显示最后一页)

添加

思路:

  1. 在index.jsp页面点击”新增”
  2. 弹出新增对话框
  3. 去数据库查询部门列表,显示在对话框中
  4. 用户输入数据,并进行校验 ? jquery前端校验,ajax用户名重复校验,重要数据(后端校验(JSR303),唯一约束);
  5. 完成保存

关键代码

	//为‘添加模态框‘中的保存按钮绑定单击事件
		//数据校验
			//姓名格式校验
			//email 校验
			//ajax校验用户名是否已经存在
		//通过ajax上传数据
			//后台JSR303校验
				//成功
					//关闭模态框
					//跳转到最后一页
				//失败
					//提示错误消息
	$("#emp_save_btn").click(function() {
		//1.表单数据校验,主要验证用户名和email
	 	if(!validate_add_form()){
			return false;
		}  
	 	
	 	//2.ajax校验用户名,会在#emp_save_btn按钮添加属性"ajax-va"="error"或者"ajax-va"="success",由这个条件判断是否需要向服务器提交表单
	 	if($("#emp_save_btn").attr("ajax-va") == "error"){
	 		return false;
	 	}
	 	//3.以上条件均满足,可以给服务器发送表单数据
		 $.ajax({
			url:"${basePath}/saveEmp",
			data:$("#empAddModal form").serialize(),
			type:"POST",
			success:function(result){
				//返回错误消息
				if(result.code == 200){
					if(undefined != result.extend.errorFields.lastName){
						show_validate_msg("#empName_add_input","error",result.extend.errorFields.lastName);
					}
					if(undefined != result.extend.errorFields.email){
						show_validate_msg("#email_add_input","error",result.extend.errorFields.email);
					}
				}else{
					//返回正确消息
					alert(result.msg);
					to_page(totalRecord);
					$("#empAddModal").modal("hide");
				}
			}
		}); 
	});
	
	//校验数据的合法性
	function validate_add_form() {
		//校验用户名
		var flag1 = checkName();
		//校验email
		var flag2 = checkEmail("#email_add_input")
		if(flag1 == true && flag2 == true ){
			return true;
		}else{
			return false;
		}
	}
	
	//输入框内容改变时,ajax校验
	$("#empName_add_input").change(function(){
		//校验用户名,满足正则才进行ajax进行验证
		if(checkName()){
			//用户名符合正则之后,ajax访问数据库校验,查看该用户名是否已经存在
			var empName = this.value;
			$.ajax({
				url:"${basePath}/checkUser1",
				data:"lastName="+empName,
				type:"POST",
				success:function(result){
					var code = result.code;
					//存在该用户名的记录,给模态框中的提交按钮添加自定义属性,此按钮在提交数据的时候可以判断是否满足提交条件
					if(code == "200"){
						$("#emp_save_btn").attr("ajax-va", "error");
						show_validate_msg("#empName_add_input","error","用户名已存在!!!");
						return false;
					}else{
					//不存在该用户名的记录,给模态框中的提交按钮添加自定义属性,此按钮在提交数据的时候可以判断是否满足提交条件
						$("#emp_save_btn").attr("ajax-va", "success");
						show_validate_msg("#empName_add_input","success","用户名可用!!!");
						return true;
					}
				}
			});
			
		}
	});
	//校验用户名
	function checkName(){
		//校验之前,清除先前的样式和数据
		var lastName = $("#empName_add_input").val();
		var regName = /(^[a-zA-Z0-9_-]{5,16}$)|(^[\u2E80-\u9FFF]{2,5}$)/;
		if(!regName.test(lastName)){
			show_validate_msg("#empName_add_input","error","用户名可以是2-5位中文或者5-16位英文和数字的组合");
			return false;
		}else{
			show_validate_msg("#empName_add_input","success","");
			return true;
		}
	}
	//校验email
	function checkEmail(ele){
		var email = $(ele).val();
		var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
		if(!regEmail.test(email)){
			show_validate_msg(ele,"error","邮箱格式不正确");
			return false;
		}else{
			$(ele).parent().addClass("has-success");
			show_validate_msg(ele,"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{
			$(ele).parent().addClass("has-error");
			$(ele).next("span").text(msg);
		}
	}

Controller层关键代码

@RequestMapping(value = "/saveEmp", method = RequestMethod.POST)
	@ResponseBody
	public Msg saveEmp(@Valid Employee employee, BindingResult result) {
		if (result.hasErrors()) {
			// 校验失败,应该返回失败,在模态框中显示校验失败的错误信息
			List<FieldError> errors = result.getFieldErrors();
			Map<String, Object> map = new HashMap<String, Object>();

			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 {
			System.out.println(employee);
			employeeService.saveEmp(employee);
			return Msg.success();
		}
	}

Service层

	public void saveEmp(Employee employee) {
		employeeMapper.insertSelective(employee);
	}

	/**
	 * 
	 * @Description 检验用户名是否可用
	 * @param lastName
	 * @return true:可用 false:不可用
	 */
	public boolean checkUser(String lastName) {
		EmployeeExample example = new EmployeeExample();
		Criteria criteria = example.createCriteria();
		criteria.andLastNameEqualTo(lastName);
		long count = employeeMapper.countByExample(example);
		return count == 0;
	}

JSR303校验

由于前端主要用js进行数据的校验,安全性不高,容易被别人禁用js而破坏数据,因此还需要后端校验

后端校验,这里用到了JSR303

使用JSR303插件步骤

1.引入依赖

<!-- JSR303数据校验 -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>5.4.1.Final</version>
		</dependency>

2.在Bean类中添加@Pattern注解

public class Employee {
	private Integer id;

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

	private String gender;

	/**
	 * regexp:校验规则,一般是正则表达式,
	 * message:校验不匹配时,返回的字符串内容
	 */
	@Pattern(regexp = "^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$", message = "邮箱格式不正确")
	private String email;

3.在Controller层添加 @Valid注解

@RequestMapping(value = "/saveEmp", method = RequestMethod.POST)
	@ResponseBody
	public Msg saveEmp(@Valid Employee employee, BindingResult result) {
		if (result.hasErrors()) {
			// 校验失败,应该返回失败,在模态框中显示校验失败的错误信息
			List<FieldError> errors = result.getFieldErrors();
			Map<String, Object> map = new HashMap<String, Object>();

			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 {
			System.out.println(employee);
			employeeService.saveEmp(employee);
			return Msg.success();
		}
	}

修改

  • 点击编辑
  • 弹出用户修改的模态框(显示用户信息)
  • 点击更新,完成用户修改

js关键代码

	
	//给编辑按钮绑定单击事件
	//此时的按钮是在ajax数据中返回后才渲染出来的,ajax数据是当前页面Dom文档加载完成后才加载的,
	//若此时直接给$(".edit_btn").click(funciotn(){});
	//事件无法生效,因为绑定的时候,对应的Dom按钮还没有生成,所以绑定事件的时候需要注意,此时需要用 ON函数绑定单击事件
	$(document).on("click",".edit_btn",function(){
		//1、查出部门信息,并显示部门列表
		getDepts("#empUpdateModal select");
		var id = $(this).attr("item_id");
		
		//2.查出员工信息,显示员工信息
		getEmp(id);
		//3、把员工的id传递给模态框的更新按钮
		$("#emp_update_btn").attr("item_id",id);
		
		$("#empUpdateModal").modal({
			backdrop:true
		});
	});
	
	//查出员工信息,显示员工信息
	function getEmp(id){
		$.ajax({
			url:"${basePath}/getEmpById/"+id,
			type:"GET",
			success:function(result){
				console.log(result);
				$("#empName_update_static").append(result.extend.emp.lastName);
				$("#email_update_input").val(result.extend.emp.email);
				$("#empUpdateModal input[name=gender]").val([result.extend.emp.gender]);
				$("#empstatus_update_input").val(result.extend.emp.empstatus);
				$("#depart_update_select").val([result.extend.emp.dId]);
			}
		});
	}
	
	//给模态框的更新按钮绑定单击事件
	$("#emp_update_btn").click(function(){
		//验证邮箱格式
		if(!checkEmail("#email_update_input")){
			return false;
		}
		var item_id = $(this).attr("item_id");
		$.ajax({
			url:"${basePath}/updateEmp/"+item_id,
//这种方法需要依赖HiddenHttpMethodFilter过滤器					
			type:"POST",	
			data:$("#empUpdateModal form").serialize()+"&_method=PUT",
			
//下面这种方法需要依赖HttpPutFormContentFilter过滤器			
//		    data:$("#empUpdateModal form").serialize(),
//			type:"PUT",	
			success:function(result){
				to_page(currentPage);
				//关闭模态框
				$("#empUpdateModal").modal(‘hide‘);
			}
		});
	});

注意:在数据更新的时候,需要注意post请求和put请求的细节,注意上方的注释

	<!-- 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>
<!-- 如果是put请求,会将请求体中的数据解析包装成一个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>

controller层

	/**
	 * 如果直接发送ajax=PUT形式的请求
	 * 封装的数据
	 * Employee 
	 * [empId=1014, empName=null, gender=null, email=null, dId=null]
	 * 
	 * 问题:
	 * 请求体中有数据;
	 * 但是Employee对象封装不上;
	 * update tbl_emp  where emp_id = 1014;
	 * 
	 * 原因:
	 * Tomcat:
	 * 		1、将请求体中的数据,封装一个map。
	 * 		2、request.getParameter("empName")就会从这个map中取值。
	 * 		3、SpringMVC封装POJO对象的时候。
	 * 				会把POJO中每个属性的值,request.getParamter("email");
	 * AJAX发送PUT请求引发的血案:
	 * 		PUT请求,请求体中的数据,request.getParameter("empName")拿不到
	 * 		Tomcat一看是PUT不会封装请求体中的数据为map,只有POST形式的请求才封装请求体为map
	 * org.apache.catalina.connector.Request--parseParameters() (3111);
	 * 
	 * protected String parseBodyMethods = "POST";
	 * if( !getConnector().isParseBodyMethod(getMethod()) ) {
                success = true;
                return;
            }
	 * 
	 * 
	 * 解决方案;
	 * 我们要能支持直接发送PUT之类的请求还要封装请求体中的数据
	 * 1、配置上HttpPutFormContentFilter;
	 * 2、他的作用;将请求体中的数据解析包装成一个map。
	 * 3、request被重新包装,request.getParameter()被重写,就会从自己封装的map中取数据
	 * 员工更新方法
	 * @param employee
	 * @return
	 */
/**
	 * 
	 * @Description 根据id查询Employee
	 * @author CGQ
	 * @date 2021年6月17日下午5:56:37
	 * @param id
	 * @return
	 */
	@RequestMapping("/getEmpById/{id}")
	@ResponseBody
	public Msg getEmpById(@PathVariable("id") Integer id) {
		Employee employee = employeeService.getEmpById(id);
		return Msg.success().add("emp", employee);
	}

	/**
	 * 根据Id更新员工
	 * 
	 * @Description
	 * @author CGQ
	 * @date 2021年6月17日下午10:42:12
	 * @param employee
	 * @return
	 */
	@RequestMapping(value = "/updateEmp/{id}", method = RequestMethod.PUT)
	@ResponseBody
	public Msg updateEmp(Employee employee) {
		// System.out.println(id);
		System.out.println("将要更新的员工数据:" + employee);
		employeeService.updateEmp(employee);
		return Msg.success();
	}

service层

//根据id返回employee对象	
public Employee getEmpById(Integer id) {
		Employee employee = employeeMapper.selectByPrimaryKeyWithDept(id);

		return employee;
	}

//更新
	public void updateEmp(Employee employee) {
		employeeMapper.updateByPrimaryKeySelective(employee);
	}

删除

js关键代码

//删除员工	
	$(document).on("click",".delete_btn",function(){
		var id = $(this).attr("item_id");
		var lastName = $(this).parent().parent().find("td:eq(2)").text();
		if(confirm("确定要删除【"+lastName+"】吗?")){
			$.ajax({
				url:"${basePath}/deleteEmpById/"+id,
				type:"delete",
				success:function(result){
					to_page(currentPage);
				}
			});
		}
	});
	
	$("#check_all").click(function(){
//用prop获取Dom的原生属性
//用attr获取自定义的Dom属性
		$(".check_item").prop("checked",$(this).prop("checked"))
	});
	
//给表格中的每一个checkBox绑定事件
	$(document).on("click",".check_item",function(){
		var flag = $(".check_item:checked").length == $(".check_item").length;
		$("#check_all").prop("checked",flag);
	});

//给删除按钮绑定事件,点击全部删除,就批量删除
	$("#emp_delete_modal_btn").click(function(){
		var empNames="";
		var ids="";
		//var items = $(".check_item:checked");
		$.each($(".check_item:checked"),function(index,item){
			//alert($(item).parent().parent("tr").find("td:eq(2)").text());
			empNames += $(item).parent().parent("tr").find("td:eq(2)").text()+",";
			ids += $(item).parent().parent("tr").find("td:eq(1)").text()+"-";
		});
		empNames = empNames.substring(0,empNames.length-1);
		ids = ids.substring(0,ids.length-1);
		//alert(empNames);
		//alert(ids);
		if(confirm("确定要删除【"+empNames+"】吗?")){
			$.ajax({
				url:"${basePath}/deletes/"+ids,
				type:"DELETE",
				success:function(result){
					to_page(currentPage);
				}
			});
		}
	});

controller层

	/**
	 * 根据id删除
	 * 
	 * @Description
	 * @author CGQ
	 * @date 2021年6月17日下午11:51:09
	 * @param id
	 * @return
	 */
	@RequestMapping(value = "/deleteEmpById/{id}", method = RequestMethod.DELETE)
	@ResponseBody
	public Msg deleteEmpById(@PathVariable("id") Integer id) {
		employeeService.deleteEmpById(id);
		return Msg.success();
	}

	/**
	 * 批量删除
	 * 
	 * @Description
	 * @author CGQ
	 * @date 2021年6月17日下午11:44:59
	 * @return
	 */
	@RequestMapping(value = "/deletes/{ids}", method = RequestMethod.DELETE)
	@ResponseBody
	public Msg deletes(@PathVariable("ids") String ids) {
		if (ids.contains("-")) {
			List<Integer> list = new ArrayList<>();
			String[] strings = ids.split("-");
			for (String string : strings) {
				list.add(Integer.parseInt(string));
			}
			employeeService.deleteBatch(list);
		} else {
			employeeService.deleteEmpById(Integer.parseInt(ids));
		}
		return Msg.success();
	}

service层

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

	public void deleteBatch(List<Integer> list) {
		EmployeeExample example = new EmployeeExample();
		Criteria criteria = example.createCriteria();
		criteria.andIdIn(list);
		employeeMapper.deleteByExample(example);

	}

总结

技术图片

SSM整合

标签:drive   组件   random   dep   input   rtp   运行环境   tde   tran   

原文地址:https://www.cnblogs.com/chenguanqin/p/14914619.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!