功能点
技术点
创建完成,如下
由于缺少web.xml配置文件,补上即可
点击项目名--》鼠标右键--》Properties--》Project facets
创建成功,目录结构
spring
springmvc ?
mybatis ?
数据库连接池,驱动包
其他(jstl,servlet-api,junit)
<!--引入项目依赖的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>
在项目中引入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>
需要编写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逆向工程:
创建数据表
部门表: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
)
导入mybatis generator依赖
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.7</version>
</dependency>
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>
运行
@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);
}
此时的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>
测试:
@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>
? 引入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
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
public class EmployeeService {
@Autowired
EmployeeMapper employeeMapper;
public List<Employee> getAll() {
List<Employee> list = employeeMapper.selectByExampleWithDept(null);
return list;
}
}
使用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);
}
}
}
测试结果
引入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字符串,如下
现在可以把返回的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("«")));
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("»")));
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>
思路:
关键代码
//为‘添加模态框‘中的保存按钮绑定单击事件
//数据校验
//姓名格式校验
//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;
}
由于前端主要用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);
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章