SSM-CRUD
ssm:SpringMVC+Spring+Mybatis
CRUD:Create(建立)、Retrieve(查詢)、Update(更新)、Delete(删除)
功能點:
- 分頁
- 資料校驗
- JQuery前端校驗+JSR303後端校驗
- ajax
- Rest風格的URI;使用HTTP協定請求方式的動詞,來表示對資源的操作(GET(查詢)、POST(新增)、PUT(修改)、DELETE(删除))
技術點
- 基礎架構-SSM(SpringMVC+Spring+Mybatis)
- 資料庫-MySQL
- 前端架構-BootStrap快速搭建簡潔美觀的界面
- 項目的依賴管理-Maven
- 分頁-pagehelper
- 逆向工程-Mybatis Generator
路徑問題:
不以/開始的相對路徑,找資源,以目前資源的路徑為準,經常容易出現問題
以/開始的相對路徑,找資源,以伺服器的路徑為标準(http://localhost:8080/)需要加上項目名
http://localhost:8080/ssm_crud
基礎環境搭建
建立一個maven工程
可以看到我們的 dreamland-web 子工程沒有 java、resources 和 test 目錄,我們需要手動建立一下,操作過程如下:
main -> New -> Directory ==> 建立 java
main -> New -> Directory ==> 建立 resources
src -> New -> Directory ==> 建立 test
test -> New -> Directory ==> 建立 java
test -> New -> Directory ==> 建立 resources
然後對建立好的 java、resources 和 test/java、test/resourcs 目錄均右鍵選擇 Mark Diretory as,然後分别進行如下操作:
java -> Sources Root //java源碼根目錄
resources -> Resources Root//java 配置檔案目錄
test/java -> Test Sources Root//java 測試源碼目錄
test/java -> Test Sources Root//java 測試配置檔案目錄
引入項目依賴的jar包
- spring
- springmvc
- mybatis
- 資料庫連接配接池,驅動包
- 其他(jstl、servlet-api、junit)
<dependencies>
<!--引入項目依賴的jar包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.2</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!--Mybatis整合Spring的适配包-->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!--資料庫連接配接池、驅動-->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<!--jstl、servlet-api、junit-->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
引入BootStrap前端架構
BookStrap官方網站
- 在官方網站下載下傳BookStrap 樣式所需css、js
- 下載下傳jQuery,因jQuery官網通路一般容易出現問題,可以在這個網站下載下傳jQuery
- 引入Bootstrap
-
<% pageContext.setAttribute("APP_PATH",request.getContextPath()); %> <%-- 不以/開始的相對路徑,找資源,以目前資源的路徑為準,經常容易出現問題 以/開始的相對路徑,找資源,以伺服器的路徑為标準(http://localhost:8080/)需要加上項目名 http://localhost:8080/ssm_crud --%> <link type="text/css" rel="stylesheet" href="${APP_PATH}/static/bootstrap/css/bootstrap.css"> <%--引入jquery--%> <script src="${APP_PATH}/static/js/jquery-3.5.1.js"></script> <script src="${APP_PATH}/static/bootstrap/js/bootstrap.js"></script>
-
測試結果
可以看到這個按鈕已經發生變化了
- 可能會出現以下錯誤:
原因:Bootstrap的JavaScript要求jQuery 1.9.1或更高版本,但低于版本4bootstrap.min.js:6 Uncaught Error: Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4
編寫SSM整合的關鍵配置檔案
web.xml、spring、springmvc、mybatis
web.xml(web.xml)
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="3.1"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<display-name>Archetype Created Web Application</display-name>
<!--1、配置Spring的配置檔案-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--2、SpringMVC的前端控制器,攔截所有請求-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<!-- <init-param>-->
<!-- <param-name>contextConfigLocation</param-name>-->
<!--不指定位置時,預設就是類路徑下servlet-name後加上-servlet-->
<!-- <param-value>classpath:</param-value>-->
<!-- </init-param>-->
</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>
</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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--SpringMVC的配置檔案,包含網站跳轉邏輯,配置,use-default-filters="false"禁用預設行為,隻掃描Controller注解-->
<context:component-scan base-package="com.qykhhr.crud" use-default-filters="false">
<!--隻掃描控制器-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--配置視圖解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--兩個标準配置-->
<!--将SpringMVC不能處理的請求交給Tomcat-->
<mvc:default-servlet-handler></mvc:default-servlet-handler>
<!--能支援SpringMVC更進階的一些功能,比如JSR303校驗,快捷的ajax請求,映射動态請求-->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
Spring(applicationContext.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--Spring的配置檔案,這裡主要配置和業務邏輯有關的-->
<!--Spring配置檔案的核心點:資料源、與Mybatis的整合、事務控制-->
<context:component-scan base-package="com.qykhhr">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<context:property-placeholder location="classpath:dbconfig.properties"></context:property-placeholder>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></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.qykhhr.crud.dao"></property>
</bean>
<!--==========================================================================-->
<!--==============事務控制的配置==============-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--控制住資料源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--開啟基于注解的事務,使用xml配置形式的事務(必要主要的都是使用配置式)-->
<aop:config>
<!--切入點表達式-->
<aop:pointcut id="txPoint" expression="execution(* com.qykhhr.crud.service..*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"></aop:advisor>
</aop:config>
<!--配置事務增強,事務如何切入-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--所有方法都是事務方法-->
<tx:method name="*"/>
<!--以get開始的所有方法-->
<tx:method name="get*" read-only="true"></tx:method>
</tx:attributes>
</tx:advice>
<!--========================================================-->
</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.qykhhr.crud.bean"/>
</typeAliases>
</configuration>
使用mybatis的逆向工程生成對應的bean以及mapper
首先導包mybatis-generator-core
<!--MBG,mybatis逆向工程-->
<!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.4.0</version>
</dependency>
在目前工程路徑下編寫generatorConfig.xml(mgb.xml)
<?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">
<!--逆向生成的bean以及mapper沒有注釋-->
<commentGenerator>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--配置資料庫連接配接-->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/ssm_crud?useSSL=false"
userId="root"
password="614310">
</jdbcConnection>
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!--指定javaBean生成位置-->
<javaModelGenerator targetPackage="com.qykhhr.crud.bean" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!--指定sql映射檔案生成的位置-->
<sqlMapGenerator targetPackage="mapper" targetProject=".\src\main\resources">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!--指定dao接口生成的位置:mapper接口-->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.qykhhr.crud.dao"
targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!--指定每個表的生成政策-->
<table tableName="tbl_emp" domainObjectName="Employee"></table>
<table tableName="tbl_dept" domainObjectName="Department"></table>
</context>
</generatorConfiguration>
在編寫一個測試類,運作
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class MBGTest {
public static void main(String[] args) 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);
}
}
-
資料庫表對應的bean以及mapper就會自動生成
Department.java、DepartmentExample.java、Employee.java、EmployeeExample.java
DepartmentMapper.java、EmployeeMapper.java
DepartmentMapper.xml、EmployeeMapper.xml
5.在執行main方法的時候出現了報錯
解決辦法:javax.net.ssl.SSLException MESSAGE: closing inbound before receiving peer's close_notify
設定useSSL為false
<!--配置資料庫連接配接--> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/ssm_crud?useSSL=false" userId="root" password="614310"> </jdbcConnection>
修改mapper檔案,添加自己需要的
Employee.java添加
//希望查詢員工的同時,部門資訊也是查詢好的
private Department department;
EmployeeMapper.java添加
List<Employee> selectByExampleWithDept(EmployeeExample example);
Employee selectByPrimaryKeyWithDept(Integer empId);
EmployeeMapper.xml添加
<resultMap id="WithDeptResultMap" type="com.qykhhr.crud.bean.Employee">
<id column="emp_id" jdbcType="INTEGER" property="empId" />
<result column="emp_name" jdbcType="VARCHAR" property="empName" />
<result column="gender" jdbcType="CHAR" property="gender" />
<result column="email" jdbcType="VARCHAR" property="email" />
<result column="d_id" jdbcType="INTEGER" property="dId" />
<!--指定聯合查詢出的部門字段的封裝-->
<association property="department" javaType="com.qykhhr.crud.bean.Department">
<id column="dept_id" property="deptId"/>
<result column="dept_name" property="deptName"/>
</association>
</resultMap>
<sql id="WithDept_Column_List">
e.emp_id, e.emp_name, e.gender, e.email, e.d_id , d.dept_id,d.dept_name
</sql>
<!-- List<Employee> selectByExampleWithDept(EmployeeExample example);
Employee selectByPrimaryKeyWithDept(Integer empId);
-->
<!--查詢員工同時帶部門資訊-->
<select id="selectByExampleWithDept" resultMap="WithDeptResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="WithDept_Column_List" />
from tbl_emp e
left join tbl_dept d on e.d_id=d.dept_id
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKeyWithDept" resultMap="WithDeptResultMap">
select
<include refid="WithDept_Column_List" />
from tbl_emp e
left join tbl_dept d on e.d_id=d.dept_id
where emp_id = #{empId,jdbcType=INTEGER}
</select>
測試mapper
package com.qykhhr.crud.test;
import com.qykhhr.crud.dao.DepartmentMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* 測試dao層工作
* 推薦Spring的項目就可以使用Spring的單元測試,可以自動注入我們需要的元件
*
* 1、導入SpringTest子產品
* 2、@ContextConfiguration指定Spring配置檔案的位置
* 3、直接autowired要使用的元件即可
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class MapperTest {
@Autowired
DepartmentMapper departmentMapper;
/**
* 測試DepartmentMapper
*/
@Test
public void testCRUD(){
// //1、建立SpringIOC容器
// ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
// //2、從容器中擷取mapper
// DepartmentMapper bean = ioc.getBean(DepartmentMapper.class);
System.out.println(departmentMapper);
}
}
測試出現的問題:
Caused by: java.lang.IllegalArgumentException: Result Maps collection already contains value for com.qykhhr.crud.dao.EmployeeMapper.BaseResultMap
原因:
使用MyBatis Generator逆向生成mapper的時候,如果多次生成會造成mapper内容重複生成,然後mapper裡面的id出現了沖突
解決:
在mapper檔案中找到相同的id,會發現後面有一半内容和前面相同,将後面相同的内容删除就行了
查詢
- 通路index.jsp
- index.jsp頁面發送查詢員工清單的請求
- EmployeeController來接收請求,查出員工資料
- 來到list.jsp頁面進行展示
- 引入PageHelper分頁插件
- 導包
-
<!--pagehelper分頁插件--> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.2.0</version> </dependency>
-
- 在mybatis配置檔案(mybatis-config.xml)中進行注冊
-
<!--注冊分頁插件--> <plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"> </plugin> </plugins>
-
- 在Controller中使用
-
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.qykhhr.crud.bean.Employee; import com.qykhhr.crud.service.EmployeeService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.stereotype.Repository; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import java.util.List; /** * 處理員工CRUD請求 */ @Controller public class EmployeeController { @Autowired EmployeeService employeeService; /** * 查詢員工資料(分頁查詢) * @return */ @RequestMapping("/emps") public String getEmps(@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, Model model){ //引入PageHelper分頁插件 //在查詢之前隻需要調用:傳入頁碼以及每頁的大小 PageHelper.startPage(pageNo,5); //startPage後面緊跟的這個查詢就是一個分頁查詢 List<Employee> emps = employeeService.getAll(); //使用PageInfo包裝查詢後的結果,隻需要将pageInfo交給頁面就行了 //封裝了詳細的分頁資訊,包括我們查詢出來的資料,傳入連續顯示的頁數 PageInfo page = new PageInfo(emps,5); model.addAttribute("pageInfo",page); return "list"; } }
-
list頁面的編寫
路徑問題:
不以/開始的相對路徑,找資源,以目前資源的路徑為準,經常容易出現問題
以/開始的相對路徑,找資源,以伺服器的路徑為标準(http://localhost:8080/)需要加上項目名
http://localhost:8080/ssm_crud
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
Created by IntelliJ IDEA.
User: 雨林
Date: 2021/1/12
Time: 13:16
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>員工清單</title>
<%
pageContext.setAttribute("APP_PATH",request.getContextPath());
%>
<%--
不以/開始的相對路徑,找資源,以目前資源的路徑為準,經常容易出現問題
以/開始的相對路徑,找資源,以伺服器的路徑為标準(http://localhost:8080/)需要加上項目名
http://localhost:8080/ssm_crud
--%>
<link type="text/css" rel="stylesheet" href="${APP_PATH}/static/bootstrap/css/bootstrap.css" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >
<%--引入jquery--%>
<script src="${APP_PATH}/static/js/jquery-3.5.1.js"></script>
<script src="${APP_PATH}/static/bootstrap/js/bootstrap.js"></script>
</head>
<body>
<%--搭建顯示頁面--%>
<div class="container">
<%--标題SSM-CRUD--%>
<div class="row">
<div class="col-md-12">
<h1>SSM-CRUD</h1>
</div>
</div>
<%--按鈕--%>
<div class="row">
<div class="col-md-4 col-md-offset-8">
<button class="btn btn-primary">新增</button>
<button class="btn btn-danger">删除</button>
</div>
</div>
<%--顯示表格資料--%>
<div class="row">
<div class="col-md-12">
<table class="table table-hover">
<tr>
<th>#</th>
<th>empName</th>
<th>gender</th>
<th>email</th>
<th>deptName</th>
<th>操作</th>
</tr>
<c:forEach items="${pageInfo.list}" var="emp">
<tr>
<th>${emp.empId}</th>
<th>${emp.empName}</th>
<th>${emp.gender=="M"?"男":"女"}</th>
<th>${emp.email}</th>
<th>${emp.department.deptName}</th>
<th>
<button class="btn btn-primary btn-sm">
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
編輯
</button>
<button class="btn btn-danger btn-sm">
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
删除
</button>
</th>
</tr>
</c:forEach>
</table>
</div>
</div>
<%--顯示分頁資訊--%>
<div class="row">
<%--分頁文字資訊--%>
<div class="col-md-6">
目前第${pageInfo.pageNum}頁,總${pageInfo.pages}頁,總${pageInfo.total}條記錄
</div>
<%--分頁條資訊--%>
<div class="col-md-6">
<nav aria-label="Page navigation">
<ul class="pagination">
<li><a href="${APP_PATH}/emps?pageNo=1" target="_blank" rel="external nofollow" >首頁</a></li>
<c:if test="${pageInfo.hasPreviousPage}">
<li>
<a href="${APP_PATH}/emps?pageNo=${pageInfo.pageNum-1}" target="_blank" rel="external nofollow" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
</c:if>
<c:forEach items="${pageInfo.navigatepageNums}" var="page_Num">
<c:if test="${page_Num == pageInfo.pageNum}">
<li class="active"><a href="#" target="_blank" rel="external nofollow" >${page_Num}</a></li>
</c:if>
<c:if test="${page_Num != pageInfo.pageNum}">
<li><a href="${APP_PATH}/emps?pageNo=${page_Num}" target="_blank" rel="external nofollow" >${page_Num}</a></li>
</c:if>
</c:forEach>
<c:if test="${pageInfo.hasNextPage}">
<li>
<a href="${APP_PATH}/emps?pageNo=${pageInfo.pageNum+1}" target="_blank" rel="external nofollow" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</c:if>
<li><a href="${APP_PATH}/emps?pageNo=${pageInfo.pages}" target="_blank" rel="external nofollow" >末頁</a></li>
</ul>
</nav>
</div>
</div>
</div>
</body>
</html>
展示效果
查詢-ajax
- index.jsp頁面直接發送Ajax請求進行員工分頁資料的查詢
- 伺服器将查出的資料,以json字元串的形式傳回給浏覽器
- 浏覽器收到json字元串。可以使用js對json進行解析,使用js通過dom增删改改變頁面
- 傳回json。實作用戶端的無關性
-
可以使用@ResponseBody注解将資料以json形式傳回到頁面
需要導入jackson支援json包
<[email protected]将資料轉為json需要包--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.3</version> </dependency>
- 編寫一個通用的傳回json的類
package com.qykhhr.crud.bean; import java.util.HashMap; import java.util.Map; /** * 通用的傳回json的類 */ public class Msg { private int code;//狀态碼:100-成功 200-失敗 private String msg;//提示資訊 private Map<String,Object> extend = new HashMap<>();//裝載要發送到頁面的json資料 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);//将擷取到的資料添加到map中 return this; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public Map<String, Object> getExtend() { return extend; } public void setExtend(Map<String, Object> extend) { this.extend = extend; } }
- 在控制器中将資料以json形式發送到前端頁面
/** * 将資料以json的形式傳到頁面 * 需要導入jackson包 * @param pageNo * @param model * @return */ @RequestMapping("/emps") @ResponseBody public Msg getEmpWithJson(@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, Model model){ //引入PageHelper分頁插件 //在查詢之前隻需要調用:傳入頁碼以及每頁的大小 PageHelper.startPage(pageNo,5); //startPage後面緊跟的這個查詢就是一個分頁查詢 List<Employee> emps = employeeService.getAll(); //使用PageInfo包裝查詢後的結果,隻需要将pageInfo交給頁面就行了 //封裝了詳細的分頁資訊,包括我們查詢出來的資料,傳入連續顯示的頁數 PageInfo page = new PageInfo(emps,5); return Msg.success().add("pageInfo",page); }
- 前端對資料進行處理
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%-- Created by IntelliJ IDEA. User: 雨林 Date: 2021/1/12 Time: 13:16 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>員工清單</title> <% pageContext.setAttribute("APP_PATH",request.getContextPath()); %> <%-- 不以/開始的相對路徑,找資源,以目前資源的路徑為準,經常容易出現問題 以/開始的相對路徑,找資源,以伺服器的路徑為标準(http://localhost:8080/)需要加上項目名 http://localhost:8080/ssm_crud --%> <link type="text/css" rel="stylesheet" href="${APP_PATH}/static/bootstrap/css/bootstrap.css" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" > <%--引入jquery--%> <script src="${APP_PATH}/static/js/jquery-3.5.1.js"></script> <script src="${APP_PATH}/static/bootstrap/js/bootstrap.js"></script> </head> <body> <%--搭建顯示頁面--%> <div class="container"> <%--标題SSM-CRUD--%> <div class="row"> <div class="col-md-12"> <h1>SSM-CRUD</h1> </div> </div> <%--按鈕--%> <div class="row"> <div class="col-md-4 col-md-offset-8"> <button class="btn btn-primary">新增</button> <button class="btn btn-danger">删除</button> </div> </div> <%--顯示表格資料--%> <div class="row"> <div class="col-md-12"> <table class="table table-hover" id="emps_table"> <thead> <tr> <th>#</th> <th>empName</th> <th>gender</th> <th>email</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> <script type="text/javascript"> //頁面加載完成之後直接去第1頁 //1、頁面加載完成以後,直接去發送ajax請求,要到分頁資料 $(function(){ $.ajax({ url:"${APP_PATH}/emps", data:"pageNo=1", type:"GET", success:function (result) { //console.log(result); //1.解析并顯示員工資料 build_emps_table(result); //2.解析并顯示分頁資訊 build_page_info(result); //3、解析顯示分頁條 build_emps_nav(result); } }); }); //跳轉到指定頁面 function to_page(pageNo) { $.ajax({ url:"${APP_PATH}/emps", data:"pageNo="+pageNo, type:"GET", success:function (result) { //console.log(result); //1.解析并顯示員工資料 build_emps_table(result); //2.解析并顯示分頁資訊 build_page_info(result); //3、解析顯示分頁條 build_emps_nav(result); } }); } /*解析顯示分頁資料*/ function build_emps_table(result){ //在發送每個Ajax請求的時候都清空表格内容 $("#emps_table tbody").empty(); var emps = result.extend.pageInfo.list;//分頁的員工的資訊 $.each(emps,function (index,item) { var empIdTd = $("<td></td>").append(item.empId); var empNameTd = $("<td></td>").append(item.empName); var genderTd = $("<td></td>").append(item.gender=='M'?"男":"女"); var emailTd = $("<td></td>").append(item.email); var deptNameTd = $("<td></td>").append(item.department.deptName); var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm") .append($("<span></span>").addClass("glyphicon glyphicon-pencil")).append("編輯"); var delBtn = $("<button></button>").addClass("btn btn-danger btn-sm") .append($("<span></span>").addClass("glyphicon glyphicon-trash")).append("删除"); var btnTd = $("<td></td>").append(editBtn).append(" ").append(delBtn); //append方法執行完成以後還是傳回原來的元素,這裡每次append都會産生新的<tr></tr> $("<tr></tr>").append(empIdTd).append(empNameTd) .append(genderTd).append(emailTd).append(deptNameTd) .append(btnTd) .appendTo("#emps_table tbody"); }) } /*解析顯示分頁資訊*/ function build_page_info(result){ //在發送Ajax的請求時要清空裡面的内容,要不然就會追加内容 $("#page_info_area").empty(); $("#page_info_area").append("目前第"+result.extend.pageInfo.pageNum+"頁,總" +result.extend.pageInfo.pages+"頁,總"+result.extend.pageInfo.total+"條記錄") } /*解析顯示分頁條*/ function build_emps_nav(result){ $("#page_nav_area").empty(); //$("#page_nav_area") var ul = $("<ul></ul>").addClass("pagination"); //建構元素 var firstPageLi = $("<li></li>").append($("<a></a>").append("首頁").attr("href","#")); var prePageLi = $("<li></li>").append($("<a></a>").append("«")); //判斷如果沒有上一頁,就不能點選 if(result.extend.pageInfo.hasPreviousPage == false){ firstPageLi.addClass("disabled"); prePageLi.addClass("disabled"); }else{ //為元素添加點選翻頁的事件 firstPageLi.click(function(){ to_page(1); }); prePageLi.click(function(){ to_page(result.extend.pageInfo.pageNum-1) }); } var nextPageLi = $("<li></li>").append($("<a></a>").append("»")); var lastPageLi = $("<li></li>").append($("<a></a>").append("末頁").attr("href","#")); //判斷如果沒有下一頁,就不能點選 if(result.extend.pageInfo.hasNextPage == false){ nextPageLi.addClass("disabled"); lastPageLi.addClass("disabled"); }else{ lastPageLi.click(function(){ to_page(result.extend.pageInfo.pages); }); nextPageLi.click(function(){ to_page(result.extend.pageInfo.pageNum+1) }); } //添加首頁和前一頁的提示 ul.append(firstPageLi).append(prePageLi); //周遊給ul中添加頁碼提示 $.each(result.extend.pageInfo.navigatepageNums,function(index,item){ var numLi = $("<li></li>").append($("<a></a>").append(item)); if(result.extend.pageInfo.pageNum == item){ numLi.addClass("active"); } numLi.click(function(){ to_page(item); }); ul.append(numLi); }) //添加末頁的提示 ul.append(nextPageLi).append(lastPageLi); //把ul加入到nav var navEle = $("<nav></nav>").append(ul); navEle.appendTo("#page_nav_area"); } </script> </body> </html>
:分頁合理化參數,預設值為reasonable
。當該參數設定為false
時,true
時會查詢第一頁,pageNum<=0
(超過總數時),會查詢最後一頁。預設pageNum>pages
時,直接根據參數進行查詢。false
<!--注冊分頁插件--> <plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"> <!--分頁參數合理化,--> <property name="reasonable" value="true"/> </plugin> </plugins>
新增
- 在index.jsp頁面點選“新增”
- 彈出新增對話框
- 去資料庫查詢部門清單,顯示在對話框中
- 使用者輸入資料,并進行校驗
-
建立員工添加模态框
員工資訊添加的表單
<%--員工添加的模态框--%> <!-- Modal --> <div class="modal fade" id="empAddModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myModalLabel">員工添加</h4> </div> <div class="modal-body"> <form class="form-horizontal"> <div class="form-group"> <label class="col-sm-2 control-label">empName</label> <div class="col-sm-10"> <input type="text" name="empName" class="form-control" id="empName_add_input" placeholder="empName"> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">email</label> <div class="col-sm-10"> <input type="email" name="email" class="form-control" id="email_add_input" placeholder="[email protected]"> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">gender</label> <div class="col-sm-10"> <label class="radio-inline"> <input type="radio" name="gender" id="gender1_add_input" value="M" checked="checked"> 男 </label> <label class="radio-inline"> <input type="radio" name="gender" id="gender2_add_input" value="F"> 女 </label> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">deptName</label> <div class="col-sm-4"> <%--部門送出部門id即可--%> <select name="dId" class="form-control" id="dept_add_select"> </select> </div> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">關閉</button> <button type="button" class="btn btn-primary" id="emp_save_btn">儲存</button> </div> </div> </div> </div>
<script> $("#emp_add_modal_btn").click(function(){ $("#empAddModal").modal({ backdrop:"static" }); }); </script>
- 從資料庫中擷取部門資訊,顯示到添加員工的模态框中
- 先建立一個service
import com.qykhhr.crud.bean.Department; import com.qykhhr.crud.dao.DepartmentMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class DepartmentService { @Autowired private DepartmentMapper departmentMapper; public List<Department> getDepts() { List<Department> departments = departmentMapper.selectByExample(null); return departments; } }
- 再建立一個Controller
import com.qykhhr.crud.bean.Department; import com.qykhhr.crud.bean.Msg; import com.qykhhr.crud.service.DepartmentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.util.List; /** * 處理和部門有關的請求 */ @Controller public class DepartmentController { @Autowired private DepartmentService departmentService; /** * 傳回所有的部門資訊 */ @RequestMapping("/depts") @ResponseBody public Msg getDepts(){ //查出的所有部門資訊 List<Department> list = departmentService.getDepts(); return Msg.success().add("depts",list); } }
- 在index.jsp發送Ajax請求
<script> //點選新增按鈕彈出模态框 $("#emp_add_modal_btn").click(function(){ $("#dept_add_select").empty(); //發送Ajax請求,查出部門資訊,顯示在下拉清單中 getDepts(); //彈出模态框 $("#empAddModal").modal({ backdrop:"static" }); }); //查出所有的部門資訊并顯示在下拉清單中 function getDepts(){ $.ajax({ url:"${APP_PATH}/depts", type:"GET", success:function (result) { //console.log(result); $.each(result.extend.depts,function(){ var optionEle = $("<option></option>").append(this.deptName).attr("value",this.deptId); optionEle.appendTo("#dept_add_select"); }); } }); } </script>
URI:
/emp/{id} GET 查詢員工
/emp POST 儲存員工
/emp/{id} PUT 修改員工
/emp/{id} DELETE 删除員工
儲存員工資訊
在index.jsp中發送Ajax請求
<script>
$("#emp_save_btn").click(function(){
//1、模态框中填寫的表單資料送出給伺服器進行儲存
//2、發送Ajax請求儲存員工
$.ajax({
url:"${APP_PATH}/emp",
type:"POST",
data:$("#empAddModal form").serialize(),
success:function () {
//員工儲存之後
//1、關閉模态框
$("#empAddModal").modal('hide');
// $("#empAddModal input").empty();
//2、來到最後一頁,顯示剛才儲存的資料
//發送Ajax請求顯示最後一頁資料即可
to_page(totalRecord);
}
})
});
</script>
在EmployeeController中儲存員工資訊
/**
* 定義員工傳回
* @return
*/
@RequestMapping(value = "/emp",method = RequestMethod.POST)
public String saveEmp(Employee employee){
employeeService.saveEmp(employee);
return "/**
* 定義員工傳回
* @return
*/
@ResponseBody
@RequestMapping(value = "/emp",method = RequestMethod.POST)
public Msg saveEmp(Employee employee){
employeeService.saveEmp(employee);
// return "lastPage";
return Msg.success();
}lastPage";
}
對輸入的員工資訊進行正規表達式校驗
- 進行校驗,并以彈窗的形式輸出錯誤資訊
//校驗表單資料
function validate_add_form(){
//1、拿到要校驗的資料,使用正規表達式進行校驗
var empName = $("#empName_add_input").val();
var regName = /(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;
if(!regName.test(empName)){//如果校驗失敗,提示
alert("使用者名可以是2-5位中文或者6-16位英文和數字的組合");
return false;
}
//校驗郵箱格式
var email = $("#email_add_input").val();
var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
if(!regEmail.test(email)){
alert("郵箱格式不正确");
return false;
}
return true;
}
//點選儲存員工的Ajax請求
$("#emp_save_btn").click(function(){
//1、模态框中填寫的表單資料送出給伺服器進行儲存
//還需要對将要送出給伺服器的資料進行校驗
if( !validate_add_form()){
return false;
}
//2、發送Ajax請求儲存員工
$.ajax({
url:"${APP_PATH}/emp",
type:"POST",
data:$("#empAddModal form").serialize(),
success:function () {
//員工儲存之後
//1、關閉模态框
$("#empAddModal").modal('hide');
// $("#empAddModal input").empty();
//2、來到最後一頁,顯示剛才儲存的資料
//發送Ajax請求顯示最後一頁資料即可
to_page(totalRecord);
}
})
});
- 使用正規表達式校驗資訊,将錯誤資訊放到輸入框下面,并将輸入框變成紅色
//校驗表單資料
function validate_add_form(){
//1、拿到要校驗的資料,使用正規表達式進行校驗
var empName = $("#empName_add_input").val();
var regName = /(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;
if(!regName.test(empName)){//如果校驗失敗,提示
// alert("使用者名可以是2-5位中文或者6-16位英文和數字的組合");
show_validate_msg("#empName_add_input","error","使用者名可以是2-5位中文或者6-16位英文和數字的組合");
// $("#empName_add_input").parent().addClass("has-error");
// $("#empName_add_input").next("span").text("使用者名可以是2-5位中文或者6-16位英文和數字的組合");
return false;
}else {
// $("#empName_add_input").parent().addClass("has-success");
// $("#empName_add_input").next("span").text("");
show_validate_msg("#empName_add_input","success","");
}
//校驗郵箱格式
var email = $("#email_add_input").val();
var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
if(!regEmail.test(email)){
//alert("郵箱格式不正确");
// $("#email_add_input").parent().addClass("has-error");
// $("#email_add_input").next("span").text("郵箱格式不正确");
show_validate_msg("#email_add_input","error","郵箱格式不正确");
return false;
}else {
// $("#email_add_input").parent().addClass("has-success");
// $("#email_add_input").next("span").text("");
show_validate_msg("#email_add_input","success","");
}
return true;
}
//顯示校驗結果的提示資訊
function show_validate_msg(ele,status,msg){
//清除目前元素的校驗狀态
$(ele).parent().removeClass("has-success has-error");
$(ele).next("span").text("");
if("success"==status){
$(ele).parent().addClass("has-success");
$(ele).next("span").text(msg);
}else if("error"==status){
$(ele).parent().addClass("has-error");
$(ele).next("span").text(msg);
}
}
- 使用Ajax校驗使用者名是否重複,從資料庫中查詢
使用$("#empAddModal form")[0].reset();//清除表單資料(表單重置)
- 在index.jsp頁面當輸入框發生變化,就發送Ajax請求,到資料庫中檢視新增使用者名是否可用
//當使用者名輸入框發生變化,發送Ajax請求校驗新增使用者名是否可用 $("#empName_add_input").change(function(){ //發送Ajax請求校驗使用者名是否可用 var empName = this.value; $.ajax({ url:"${APP_PATH}/checkuser", data:"empName="+empName, type:"POST", success:function (result) { if(result.code==100){ show_validate_msg("#empName_add_input","success","使用者名可用"); $("#emp_save_btn").attr("ajax-va","success"); }else{ show_validate_msg("#empName_add_input","error",result.extend.va_msg); $("#emp_save_btn").attr("ajax-va","error"); } } }); })
- Controller接收/checkuser請求,去service層調用方法
/** * 用于檢視使用者名是否重複 * @param empName * @return */ @ResponseBody @RequestMapping("/checkuser") public Msg checkuser(String empName){ //先判斷使用者名是否是合法的表達式 String regx = "(^[a-zA-Z0-9_-]{6,16}$)|(^[\\u2E80-\\u9FFF]{2,5})"; if(!empName.matches(regx)){ return Msg.fail().add("va_msg","使用者必須是6-16位數字和字母的組合或者2-5位中文"); } //資料庫使用者名重複校驗 boolean b = employeeService.checkUser(empName); if(b){ return Msg.success(); }else{ return Msg.fail().add("va_msg","使用者名不可用"); } }
- 在Service層建立一個方法,用于檢視資料庫中是否有該使用者名
/** * 校驗使用者名是否可用 * @param empName * @return true 表示可用 false 表示不可用 */ public boolean checkUser(String empName) { EmployeeExample employeeExample = new EmployeeExample(); EmployeeExample.Criteria criteria = employeeExample.createCriteria(); criteria.andEmpNameEqualTo(empName); long count = employeeMapper.countByExample(employeeExample); return count == 0;//如果count == 0 表示可用 }
清除表單樣式
//清除表單資料(表單完整重置(表單的資料,表單的樣式))
function reset_form(ele){
$(ele)[0].reset();
//清空表單樣式
$(ele).find("*").removeClass("has-error has-success");
$(ele).find(".help-block").text("");
}
//點選新增按鈕彈出模态框
$("#emp_add_modal_btn").click(function(){
$("#dept_add_select").empty();
//清除表單資料(表單重置)
reset_form("#empAddModal form");
// $("#empAddModal form").reset();
//發送Ajax請求,查出部門資訊,顯示在下拉清單中
getDepts();
//彈出模态框
$("#empAddModal").modal({
backdrop:"static"
});
});
問題
前端校驗可以通過修改頁面内容或者通過禁用js功能,跳過js校驗,是以我們需要進行後端校驗
重要資料(後端校驗(JSR303),唯一限制)
通過修改頁面内容,實作跳過前端校驗
使用JSR303校驗
- 導包,導入Hibernate-Validator
<!--JSR303校驗支援:tomcat7及以上的伺服器 tomcat7及以下的伺服器:el表達式。額外給伺服器的lib包中替換新的标準的el --> <!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator --> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>7.0.0.Final</version> </dependency>
- 在bean中修改屬性
@Pattern(regexp = "(^[a-zA-Z0-9_-]{6,16}$)|(^[\\u2E80-\\u9FFF]{2,5})" ,message = "使用者名必須是2-5位中文或者6-16位英文和數字的組合") private String empName; //@Email @Pattern(regexp = "^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$" ,message = "郵箱格式不正确") private String email;
- 對前端傳來的資料進行JSR303校驗
@Valid Employee employee, BindingResult result
/** * 員工儲存 * 1、支援JSR303校驗 * 2、導入Hibernate-Validator * @return */ @ResponseBody @RequestMapping(value = "/emp",method = RequestMethod.POST) public Msg saveEmp(@Valid Employee employee, BindingResult result){ if(result.hasErrors()){ Map<String,Object> map = new HashMap<>(); //校驗失敗,在模态框中顯示校驗失敗的錯誤資訊 List<FieldError> fieldErrors = result.getFieldErrors(); for (FieldError fieldError : fieldErrors){ System.out.println("錯誤的字段名:" + fieldError.getField()); System.out.println("錯誤資訊:" + fieldError.getDefaultMessage()); map.put(fieldError.getField(),fieldError.getDefaultMessage()); } return Msg.fail().add("errorFields",map); }else{ employeeService.saveEmp(employee); // return "lastPage"; return Msg.success(); } }
- 進行校驗,判斷是否有效
//點選儲存員工的Ajax請求 $("#emp_save_btn").click(function(){ //1、模态框中填寫的表單資料送出給伺服器進行儲存 //還需要對将要送出給伺服器的資料進行校驗 if( !validate_add_form()){ return false; } //判斷之前的Ajax使用者名校驗是否成功,如果成功 if($(this).attr("ajax-va") == "error"){ return false; } //2、發送Ajax請求儲存員工 $.ajax({ url:"${APP_PATH}/emp", type:"POST", data:$("#empAddModal form").serialize(), success:function (result) { //員工儲存之後 if(result.code == 100){ //1、關閉模态框 $("#empAddModal").modal('hide'); // $("#empAddModal input").empty(); //2、來到最後一頁,顯示剛才儲存的資料 //發送Ajax請求顯示最後一頁資料即可 to_page(totalRecord); }else{ //顯示失敗資訊 // console.log(result); //有哪個字段的錯誤就顯示哪個字段的 if(undefined != result.extend.errorFields.email){ //顯示郵箱錯誤資訊 show_validate_msg("#email_add_input","error",result.extend.errorFields.email); } if(undefined != result.extend.errorFields.empName){ //顯示員工名字的錯誤資訊 show_validate_msg("#empName_add_input","error",result.extend.errorFields.empName); } } } })
修改員工資訊
- 點選編輯
- 彈出使用者修改的模态框(顯示使用者資訊)
- 點選更新,完成使用者修改
- 點選編輯,彈出使用者模态框
//我們是按鈕建立之前就綁定了click,是以綁定不上 //1、可以在建立按鈕的時候綁定 2、綁定點選.live() //jquery新版沒有live,使用on方法替代 $(document).on("click",".edit_btn",function(){ // alert("edit"); //1、查出員工資訊,顯示員工資訊 getDepts("#empUpdateModal select"); //2、查出部門資訊,并顯示部門清單 getEmp($(this).attr("edit-id")); //把員工id傳遞給模态框的更新按鈕 $("#emp_update_btn").attr("edit-id",$(this).attr("edit-id")); //3、彈出模态框 $("#empUpdateModal").modal({ backdrop: "static" }); }) //根據id查詢員工資料 function getEmp(id){ $.ajax({ url:"${APP_PATH}/emp/"+id, type:"GET", success:function (result) { // console.log(result); var empData = result.extend.emp; $("#empName_update_static").text(empData.empName); $("#email_update_input").val(empData.email); $("#empUpdateModal input[name=gender]").val([empData.gender]); $("#empUpdateModal select").val([empData.dId]); } }); }
- Controller根據id查詢員工
/** * 根據id查詢員工 * @param id * @return */ @RequestMapping(value = "/emp/{id}",method = RequestMethod.GET) @ResponseBody public Msg getEmp(@PathVariable("id") Integer id){ Employee employee = employeeService.getEmp(id);// return Msg.success().add("emp",employee); }
- Service層從資料庫查詢員工
/** * 安裝員工ID查詢員工資訊 * @param id * @return */ public Employee getEmp(Integer id) { return employeeMapper.selectByPrimaryKey(id); }
- 點選更新,更新資料
//點選更新,更新員工資料 $("#emp_update_btn").click(function(){ //驗證郵箱是否合法 //校驗郵箱格式 var email = $("#email_update_input").val(); var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/; if(!regEmail.test(email)){ show_validate_msg("#email_update_input","error","郵箱格式不正确"); return false; }else { show_validate_msg("#email_update_input","success",""); } //發送Ajax請求儲存更新的員工資料 $.ajax({ url:"${APP_PATH}/emp/"+$(this).attr("edit-id"), type:"PUT", // data:$("#empUpdateModal form").serialize()+"&_method=PUT",//type可以用POST送出 data:$("#empUpdateModal form").serialize(),//直接使用Ajax發送PUT請求 success:function (result) { // alert(result.msg); //1、關閉模态框 $("#empUpdateModal").modal("hide"); //2、回到本頁面 to_page(currentPage); } }) })
- Controller封裝前端傳來的資料封裝成Employee對象
/** * 員工更新方法 * 如果直接發ajax=PUT形式的請求 * 封裝的資料 * Employee * [empId=1014,empName=null,gender=null,email=null,dId=null] * * 問題: * 請求體中有資料,但是Employee對象封裝不上 * sql拼串就發産生異常 update tbl_emp where emp_id = 1014; * * 原因: * Tomcat: * 1、将請求體中的資料,封裝成一個map * 2、request.getParameter("empName")就會從這個map中取值 * 3、SpringMVC封裝POJO對象的時候 * 會把POJO中每個屬性的值:request.getParameter("email"); * Ajax發送PUT請求引發的問題 * PUT請求,請求體中的資料,request.getParameter("empName");拿不到資料 * Tomcat一看是PUT,不會封裝請求體中的資料為map,隻有POST形式的請求才封裝請求體為map * * 解決方案 * 1、我們要能支援直接發送PUT之類的請求還要封裝請求體中的資料 * 2、配置上HttpPutFormContentFilter * 3、它的作用:将請求體中的資料解析包裝成一個map,request被重新包裝 * request.getParameter()被重寫,就會從自己封裝的map中取資料 * @param employee * @return */ @RequestMapping(value = "/emp/{empId}",method = RequestMethod.PUT) @ResponseBody public Msg saveEmp(Employee employee){ System.out.println("将要更新的員工資料:" + employee); employeeService.updateEmmp(employee); return Msg.success(); }
- Service層更新資料資料
public void updateEmmp(Employee employee) { employeeMapper.updateByPrimaryKeySelective(employee); }
-
配置HttpPutFormContentFilter
在web.xml中進行配置
<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封裝前端傳來的資料封裝成Employee對象
删除單一員工
發送/emp/id,請求類型是DELETE
//單個删除
$(document).on("click",".delete_btn",function(){
//1、彈出是否确認删除對話框
// alert($(this).parents("tr").find("td:eq(1)").text());//目前元素父元素的tr下的第二個td标簽中的内容
var empName = $(this).parents("tr").find("td:eq(1)").text();
var empId = $(this).attr("del-id");
if(confirm("确認删除【"+empName+"】嗎?")){
//确認,發送Ajax請求删除即可
$.ajax({
url:"${APP_PATH}/emp/" + empId,
type:"DELETE",
success:function (result) {
alert(result.msg);
//回到本頁
to_page(currentPage);
}
})
}
})
Controller接收該請求,調用Service層的方法
@RequestMapping(value = "/emp/{id}",method = RequestMethod.DELETE)
@ResponseBody
public Msg deleteEmpById(@PathVariable("id") Integer id){
employeeService.deleteEmp(id);
return Msg.success();
}
Service層調用方法,從資料庫中删除資料
/**
* 删除員工
* @param id
*/
public void deleteEmp(Integer id) {
employeeMapper.deleteByPrimaryKey(id);
}
删除批量資料
全選和全不選
- 先将表格樣式改變
<tr> <th> <input type="checkbox" id="check_all" /> </th> <th>#</th> <th>empName</th> <th>gender</th> <th>email</th> <th>deptName</th> <th>操作</th> </tr>
- 顯示分頁資料的時候加上checkbox,單選框這一項
/*解析顯示分頁資料*/ function build_emps_table(result){ $.each(emps,function (index,item) { var checkBoxTd = $("<td><input type='checkbox' class='check_item'/></td>"); //append方法執行完成以後還是傳回原來的元素,這裡每次append都會産生新的<tr></tr> $("<tr></tr>").append(checkBoxTd) .append(empIdTd).append(empNameTd) .append(genderTd).append(emailTd).append(deptNameTd) .append(btnTd) .appendTo("#emps_table tbody"); }) }
- 完成全選和全不選
//完成全選/全不選 $("#check_all").click(function(){ //attr擷取checked是undefined //我們這些dom原生的屬性,attr擷取自定義屬性的值 //prop修改和讀取dom原生屬性的值 // alert($(this).attr("checked")); // alert($(this).prop("checked")); // $(this).prop("checked"); $(".check_item").prop("checked",$(this).prop("checked")); }) //check_item, $(document).on("click",".check_item",function () { //判斷目前選中的元素是否5個 // alert($(".check_item:checked").length); var flag = $(".check_item:checked").length == $(".check_item").length; $("#check_all").prop("checked",flag); })
- 點選删除按鈕,删除多個員工資訊
//點選全部删除,就批量删除 $("#emp_delete_all_btn").click(function () { var empNames = ""; var del_idstr = ""; $.each($(".check_item:checked"),function(){ // alert($(this).parents("tr").find("td:eq(2)").text()); //組裝員工名字字元串 empNames += $(this).parents("tr").find("td:eq(2)").text() + ","; //組裝員工id字元串 del_idstr += $(this).parents("tr").find("td:eq(1)").text() + "-" }); empNames = empNames.substring(0,empNames.length-1); del_idstr = del_idstr.substring(0,del_idstr.length-1); if(confirm("确認删除【"+empNames+"】嗎?")){ $.ajax({ url:"${APP_PATH}/emp/" + del_idstr, type:"DELETE", success:function (result) { alert(result.msg); //回到目前頁面 to_page(currentPage); } }) } });
- Controller接收請求,将字元串進行區分,并進行類型轉換
/** * 單個批量二合一 * 批量删除:1-2-3 * 單個删除:1 * @param * @return */ @RequestMapping(value = "/emp/{ids}",method = RequestMethod.DELETE) @ResponseBody public Msg deleteEmp(@PathVariable("ids") String ids){ if(ids.contains("-")){ //批量删除 String[] str_ids = ids.split("-"); List<Integer> del_ids = new ArrayList<>(); //組裝id的集合 for (String id : str_ids){ del_ids.add(Integer.parseInt(id)); } employeeService.deleteBatch(del_ids); }else{ //單個删除 Integer id = Integer.parseInt(ids); employeeService.deleteEmp(id); } return Msg.success(); }
- Service層進行批量删除
/** * 批量删除 * @param ids */ public void deleteBatch(List<Integer> ids) { EmployeeExample employeeExample = new EmployeeExample(); EmployeeExample.Criteria criteria = employeeExample.createCriteria(); criteria.andEmpIdIn(ids); //delete from xxx where emp_id in (1,2,3); employeeMapper.deleteByExample(employeeExample); }
all_btn").click(function () {
var empNames = “”;
var del_idstr = “”;
. e a c h ( .each( .each((".check_item:checked"),function(){
// alert($(this).parents(“tr”).find(“td:eq(2)”).text());
//組裝員工名字字元串
empNames += $(this).parents(“tr”).find(“td:eq(2)”).text() + “,”;
//組裝員工id字元串
del_idstr += $(this).parents(“tr”).find(“td:eq(1)”).text() + “-”
});
empNames = empNames.substring(0,empNames.length-1);
del_idstr = del_idstr.substring(0,del_idstr.length-1);
if(confirm(“确認删除【”+empNames+"】嗎?")){
KaTeX parse error: Expected '}', got 'EOF' at end of input: … url:"{APP_PATH}/emp/" + del_idstr,
type:“DELETE”,
success:function (result) {
alert(result.msg);
//回到目前頁面
to_page(currentPage);
}
})
}
});
- Controller接收請求,将字元串進行區分,并進行類型轉換
```java
/**
* 單個批量二合一
* 批量删除:1-2-3
* 單個删除:1
* @param
* @return
*/
@RequestMapping(value = "/emp/{ids}",method = RequestMethod.DELETE)
@ResponseBody
public Msg deleteEmp(@PathVariable("ids") String ids){
if(ids.contains("-")){
//批量删除
String[] str_ids = ids.split("-");
List<Integer> del_ids = new ArrayList<>();
//組裝id的集合
for (String id : str_ids){
del_ids.add(Integer.parseInt(id));
}
employeeService.deleteBatch(del_ids);
}else{
//單個删除
Integer id = Integer.parseInt(ids);
employeeService.deleteEmp(id);
}
return Msg.success();
}
- Service層進行批量删除
/** * 批量删除 * @param ids */ public void deleteBatch(List<Integer> ids) { EmployeeExample employeeExample = new EmployeeExample(); EmployeeExample.Criteria criteria = employeeExample.createCriteria(); criteria.andEmpIdIn(ids); //delete from xxx where emp_id in (1,2,3); employeeMapper.deleteByExample(employeeExample); }
[外鍊圖檔轉存中…(img-lcUnSKjP-1611281390431)]
至此,SSM整合結束