SSM强化学习:从零到部署
本次是一次对SSM高级整合的练手,主要加强基本使用SSM做增删改查操作。项目内容是对员工数据的增删改查。
在项目开始之前先建两张表分别为员工表Employee和部门表dept:
-- ----------------------------
-- Table structure for tbl_dept
-- ----------------------------
DROP TABLE IF EXISTS `tbl_dept`;
CREATE TABLE `tbl_dept` (
`deot_id` int(11) NOT NULL AUTO_INCREMENT,
`dept_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
PRIMARY KEY (`deot_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Table structure for tbl_emp
-- ----------------------------
DROP TABLE IF EXISTS `tbl_emp`;
CREATE TABLE `tbl_emp` (
`emp_id` int(11) NOT NULL AUTO_INCREMENT,
`emp_name` varchar(235) NOT NULL,
`gender` char(1) DEFAULT NULL,
`emil` varchar(255) DEFAULT NULL,
`d_id` int(11) DEFAULT NULL,
PRIMARY KEY (`emp_id`),
KEY `fk_emp_deptt` (`d_id`),
CONSTRAINT `fk_emp_dept` FOREIGN KEY (`d_id`) REFERENCES `tbl_dept` (`deot_id`),
CONSTRAINT `fk_emp_deptt` FOREIGN KEY (`d_id`) REFERENCES `tbl_dept` (`deot_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
SET FOREIGN_KEY_CHECKS = 1;
一、基础环境的搭建
1、创建一个maven工程
2、引入项目依赖的jar包
4.0.0
com.qroxy
ssm
0.0.1-SNAPSHOT
war
org.springframework
spring-webmvc
4.3.7.RELEASE
org.springframework
spring-jdbc
4.3.7.RELEASE
org.springframework
spring-aspects
4.3.7.RELEASE
org.mybatis
mybatis
3.4.2
org.mybatis
mybatis-spring
1.3.1
org.springframework
spring-test
4.3.7.RELEASE
test
c3p0
c3p0
0.9.1.2
mysql
mysql-connector-java
8.0.11
jstl
jstl
1.2
javax.servlet
javax.servlet-api
3.1.0
provided
junit
junit
4.12
test
二、引入bootstrap前端框架
为了快速搭建前端页面,使用了bootstrap框架。在WEB-INF下新建一个static文件夹存放bootstrap和js。
三、编写SSM整合的关键配置文件
1、首先是web.xml
contextConfigLocation
classpath:applicationContext.xml
org.springframework.web.context.ContextLoaderListener
dispatcherServlet
org.springframework.web.servlet.DispatcherServlet
1
dispatcherServlet
/
CharacterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
utf-8
forceRequestEncoding
true
forceResponseEncoding
true
CharacterEncodingFilter
/*
HiddenHttpMethodFilter
org.springframework.web.filter.HiddenHttpMethodFilter
HiddenHttpMethodFilter
/*
HttpPutFormContentFilter
org.springframework.web.filter.HttpPutFormContentFilter
HttpPutFormContentFilter
/*
需要注意的是使用rest风格uri时需要添加一个拦截PUT的拦截器,具体实现看HttpPutFormContentFilter这个类。
2、spring核心配置文件
该文件需放在resource下
主要是对事务和mybatis整合的配置,其中:
只是用来批量生成数据的sqlseesion。
在整合完成且逆向生成文件后,测试其实现方式如下:
EmployeeMapper mapper=SqlSession.getMapper(EmployeeMapper.class);
for (int i = 0; i < 1000; i++) {
String uuid=UUID.randomUUID().toString().substring(0, 5)+""+i;
mapper.insertSelective(new Employee(null, uuid, "W", uuid+"@qroxy.cn", 2));
}
3、配置mybatis文件
文件位置与spring配置文件位置一致
4、SpringMVC文件的配置
该文件放在WEB_IN目录下
以上就是对SSM的一个初步整合,要对员工数据进行增删改查还得需要使用mybatis的逆向工程生成对应的bean以 及mapper。
四、mybatis的逆向工程
可去mybatis官网看下相关文档,根据需要配置。
运行配置文件,官方提供了java文件运行和maven运行两种方式,这里采用java方式,在test包下新建一个类,点开Running MyBatis Generator选项,选择java运行模版如下:
package com.atguigu.crud.test;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
public class MBGTest {
public static void main(String[] args) throws Exception {
List warnings = new ArrayList();
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);
}
}
右键运行就会生成对于javabean和xml等文件。
五、用传统的方式做一个简单的查询
具体实现过程:
• 1、访问index.jsp页面
项目运行进入首页
• 2、index.jsp页面发送出查询员工列表请求
在inde.jsp页面做一个跳转:
• 3、EmployeeController来接受请求,查出员工数据
简单写一个控制器:
@RequestMapping("/emps")
public String getEmps(@RequestParam(value = "pn", defaultValue = "1") Integer pn,Model model){
// 这不是一个分页查询
// 引入PageHelper插件
// 在查询之前只需要调用,传入页码以及页码大小
PageHelper.startPage(pn, 10);
// startPage后面紧跟的这个查询就是分页查询
List emps = employeeService.getAll();
// 使用pageInfo包装查询结果,只需要把pageInfo交给页面就行
// 封装了详细的分页信息,包括查询出来数据,连续显示的页数譬如5
PageInfo page = new PageInfo(emps,5);
model.addAttribute("PageInfo",page);
return "list";
}
因为要做分页处理,还得引入PageHelper相关依赖,并进行配置。
依赖
!--引入PageHelper分页插件 -->
com.github.pagehelper
pagehelper
5.0.0
并在mybatis配置文件做一个配置。(已配置)
• 4、来到list.jsp页面进行展示
在WEB_INF下新建一个views文件再里面建一个list.jsp文件:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
员工列表
<%
pageContext.setAttribute("APP_PATH", request.getContextPath());
%>
SSM_CRUD
#
empName
gender
email
deptName
操作
${emp.empId }
${emp.empName }
${emp.gender=="M"?"男":"女" }
${emp.email }
${emp.department.deptName }
当前第${PageInfo.pageNum }页,总${PageInfo.pages }页,总${PageInfo.total }记录
• 5、pageHelper分页插件完成分页查询功能
六、利用ajax来请求数据渲染前端页面
前面使用传统的渲染页面,不但效率差,还对服务器性能有影响,并且这种方式只能在浏览器实现,终端耦合高,而使用ajax来请求数据的话就相对来说没有以上的缺点或者影响更小。
主要实现过程如下(以查询员工为例):
•1、index.jsp页面直接发送ajax请求进行员工分页数据的查询
$(function() {
//去首页
to_page(1)
});
//抽离方法
function to_page(pn) {
$.ajax({
url : "${APP_PATH}/emps",
data : "pn=" + pn,
type : "GET",
success : function(result) {
//console.log(result)
//1、解析并显示员工数据
build_emps_table(result);
//2、解析并显示分页信息
build_page_info(result);
//3、解析分页条信息
build_page_nav(result);
}
});
}
function build_emps_table(result) {
//请空表格
$("#emps_tables tbody").empty();
var emps = result.extend.PageInfo.list;
$.each(emps, function(index, item) {
var empIdTd = $(" ").append(item.empId);
var empIdNameTd = $(" ").append(item.empName);
var genderTd = $(" ").append(
item.gender == 'M' ? "男" : "女");
var emailTd = $(" ").append(item.email);
var departmentTd = $(" ").append(
item.department.deptName);
var editBtn = $("").addClass(
"btn-primary btn-sm btn_edit").attr("id","btn_edit").append(
$("").addClass(
"glyphicon glyphicon-pencil")).append("编辑");
//添加一个属性value是id值
editBtn.attr("edit_id",item.empId);
var deletBtn = $("").addClass(
"btn-danger btn-sm").attr("id","btn_delet").append(
$("")
.addClass("glyphicon glyphicon-trash")).append(
"删除");
deletBtn.attr("delet_id",item.empId);
var butnTd = $(" ").append(editBtn).add(deletBtn);
/* append方法执行完成以后还是返回原来的元素*/
$(" ").append(empIdTd).append(empIdNameTd).append(
empIdNameTd).append(genderTd).append(emailTd)
.append(departmentTd).append(butnTd)
.appendTo("#emps_tables tbody");
})
}
//解析显示分页信息
function build_page_info(result) {
$("#page_info").empty();
$("#page_info").append(
"当前第" + result.extend.PageInfo.pageNum + "页,总"
+ result.extend.PageInfo.pages + "页,总"
+ result.extend.PageInfo.total + "条记录")
currentPage=result.extend.PageInfo.pageNum;
}
//解析显示分条信息,点击分页有跳转动作
function build_page_nav(result) {
$("#page_nav").empty();
//page_nav
var ul = $("
").addClass("pagination");
//构建元素
var firstPage = $("").append(
$("").append("首页").attr("href", "#"));
var prePage = $("").append($("").append("«"));
if (result.extend.PageInfo.hasPreviousPage == false) {
prePage.addClass("disabled");
firstPage.addClass("disabled");
} else {
//首页
firstPage.click(function() {
to_page(1);
});
//点击上一页跳转动作
prePage.click(function() {
to_page(result.extend.PageInfo.pageNum - 1);
});
}
var nextPage = $("")
.append($("").append("»"));
var lastPage = $("").append(
$("").append("末页").attr("href", "#"));
if (result.extend.PageInfo.hasNextPage == false) {
nextPage.addClass("disabled");
lastPage.addClass("disabled");
} else {
//点击下一页跳转动作
nextPage.click(function() {
to_page(result.extend.PageInfo.pageNum + 1);
});
//末页
lastPage.click(function() {
to_page(result.extend.PageInfo.pages);
});
}
ul.append(firstPage).append(prePage);
//添加首页和前一页
//1,2,3,,4,5添加页码提示
$.each(result.extend.PageInfo.navigatepageNums, function(index,
item) {
var numLi = $("").append($("").append(item));
if (result.extend.PageInfo.pageNum == item) {
numLi.addClass("active");
}
//点击上一页跳转动作
numLi.click(function() {
to_page(item);
});
ul.append(numLi);
});
//全部添加完后,再添加最后一页和下一页提示
ul.append(nextPage).append(lastPage);
var navEle = $("").append(ul);
navEle.appendTo("#page_nav");
numLi.click(function() {
to_page(item);
});
}
function reset_form(ele){
$(ele)[0].reset();
//清空表单样式
$(ele).find("*").removeClass("has-error has-success");
$(ele).find(".help-block").text("");
}
• 2、服务器将查出的数据,以json字符串的形式返回给浏览器
要服务器能json的方式返回数据,还要引入json包
com.fasterxml.jackson.core
jackson-databind
2.8.8
java实现:
/*
* 用responseBody生成json数据,必须先导入jackson包
*/
@RequestMapping("/emps")
@ResponseBody
public Msg getEmpWithJson(@RequestParam(value = "pn", defaultValue = "1") Integer pn) {
// 这不是一个分页查询
// 引入PageHelper插件
// 在查询之前只需要调用,传入页码以及页码大小
PageHelper.startPage(pn, 10);
// startPage后面紧跟的这个查询就是分页查询
List emps = employeeService.getAll();
// 使用pageInfo包装查询结果,只需要把pageInfo交给页面就行
// 封装了详细的分页信息,包括查询出来数据,连续显示的页数譬如5
PageInfo page = new PageInfo(emps,5);
return Msg.success().add("PageInfo", page);
}
• 3、浏览器收到js字符串。可以使用js对json进行解析,使用js通过 dom增删改改变页面。
进而实现了实现客户端的无关性。
七、数据校验
在添加员工和修改员工时为了更好的交互体验和防止数据臃肿,必须对提交数据进行校验。
1、前端校验
利用正则表达式对提交数据校验,方法如下:
function validate_add_from() {
//1、拿到要校验的数据
var empName = $("#empName_add").val();
//数字字母中文
var regName = /(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;
//校验邮箱信息
var email = $("#email").val();
var regemail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
if (regName.test(empName) == false) {
show_validate_msg("#empName_add", "error", "用户名不规则!!");
return false;
} else {
show_validate_msg("#empName_add", "success", "");
}
if (regemail.test(email) == false) {
show_validate_msg("#email", "error", "邮箱格式不对!!");
return false;
} else {
show_validate_msg("#email", "success", "");
}
return true;
}
2、后端校验
当有人改了前端判断依据时,前端校验规则就会失效,此时就需要后端对数据重复校验。
引入校验依赖
org.hibernate.validator
hibernate-validator
6.0.7.Final
并在SpringMVC配置文件做好相关配置。
在Employee.java对相关需要校验的字段进行注解校验:
....
// JSR数据校验
@Pattern(regexp="^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$",message="邮箱格式不对")
private String email;
@Pattern(regexp="(^[a-zA-Z0-9_-]{6,16}$)|(^[\\u2E80-\\u9FFF]{2,5})",message="用户名不规则")
private String empName;
...
在控制器中写一个校验接口:
/*
* 校验用户名是否可用
*/
@RequestMapping("/checkuser")
@ResponseBody
public Msg checkUser(@RequestParam("empName")String empName) {
//先判断用户名是否合法的
String regx="(^[a-zA-Z0-9_-]{6,16}$)|(^[\\u2E80-\\u9FFF]{2,5})";
if (!empName.matches(regx)) {
return Msg.fail().add("va_msg", "用户名不规则");
}
boolean b= employeeService.checkUser(empName);
if (b) {
return Msg.success();
}else {
return Msg.fail().add("va_msg", "用户名不可用");
}
}
其对应的service实现类中的方法:
public Boolean checkUser(String empName) {
EmployeeExample example = new EmployeeExample();
Criteria criteria = example.createCriteria();
criteria.andEmpNameEqualTo(empName);
long count = mapper.countByExample(example);
if (count == 0) {
return true;
} else {
return false;
}
}
八、生成war部署Tomcat
完成项目后,就是部署项目项目。操作如下:
成功后就会看到war包:
复杂粘贴到tomcat的webapp目录下启动,就会生成对应的目录。
打开目录会发现maven已经把所有需要的依赖都打包好了。
然后也可以访问到该服务器,此时已经不是镜像服务器了,而是实际服务器了。
九、总结
本次学习过程让我觉得对Spring实现原理的理解非常重要,SSM最让新手畏惧就是其繁琐的配置,在本次学习过程出现错误最多都是跟配置文件配置有关,且如果对SSM它的实现过程没有一个比较清晰的理解的话,即使出现错误也不能找出原因。做数据处理的时候也经常出错,这个原因是因为对jquery还不够熟悉,因此接下来对juquery和javascript的学习也是尤为重要。