一. 项目结构
本项目中包含一对多数据表的增删改查,模糊查询,分页。
前端部分内容需要layui
二. 数据库
-- grade 班级表
DROP TABLE IF EXISTS `grade`;
CREATE TABLE `grade` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`address` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`create_date` datetime(0) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Compact;
-- student 学生表
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`age` int(11) NULL DEFAULT NULL,
`phone` varchar(11) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`home` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`g_id` int(11) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `student_ibfk_1`(`g_id`) USING BTREE,
CONSTRAINT `student_ibfk_1` FOREIGN KEY (`g_id`) REFERENCES `grade` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 15 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Compact;
-- 数据
INSERT INTO `grade` VALUES (1, 'A1', '一教', '2020-01-01 07:00:00');
INSERT INTO `grade` VALUES (2, 'A2', '二教', '2020-01-02 08:00:00');
INSERT INTO `grade` VALUES (3, 'A3', '三机', '2020-01-10 12:00:00');
INSERT INTO `grade` VALUES (4, 'A4', '三教', '2020-05-01 07:30:00');
INSERT INTO `grade` VALUES (8, 'test1', 'test1', '2020-07-11 14:37:00');
INSERT INTO `student` VALUES (1, '张三', 18, '15122221112', '郑州', 1);
INSERT INTO `student` VALUES (2, '李四', 19, '15829392182', '洛阳', 1);
INSERT INTO `student` VALUES (3, '王五', 20, '15923239992', '南阳', 2);
INSERT INTO `student` VALUES (4, '韩六', 22, '13598929384', '北京', 2);
INSERT INTO `student` VALUES (5, '赵七', 20, '13922912231', '南京', 1);
INSERT INTO `student` VALUES (9, '阿狗', 18, '15122223333', '东北', 1);
INSERT INTO `student` VALUES (14, '2737110', 80, '15111111111', '123', 8);
三. 配置文件
配置文件见SSM框架配置文件
四. 基础模板
后端模板
-
需要fastjson插件,在pom文件中有坐标,建议使用1.2.72版本
-
mybatis的mapper文件在resources文件夹下的mapper中,若需要更改为其他位置需要在spring-dao.xml文件中更改sqlSessionFactory下的mapperLocations指定的路径。
-
日期处理:后端接收前端时需要在实体类中的加入
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm")
注解,后端向前端发送数据时需要加入@JSONField (format="yyyy-MM-dd'T'HH:mm")
。注:
@DataTimeFormat
注解需要在spring-web.xml中加入<mvc:annotation-driven />
开启注解驱动,
@JSONField
注解需要fastjson支持,要在pom.xml中引入fastjson的坐标。 -
分页使用LayuiPageHelper进行分页辅助
1. BaseController
针对layui的Controller层模板
import com.aaa.service.BaseService;
import com.aaa.util.LayuiPageHelper;
import com.alibaba.fastjson.support.spring.FastJsonJsonView;
import org.springframework.web.servlet.ModelAndView;
/**
* 对于layui的Controller层模板<br>
* code:layui接收的唯一验证<br>
* status:用于业务判断<br>
* msg:向页面发送信息<br>
* icon:页面图标<br>
* data: 传输数据<br>
* @author 淮南King
*/
public class BaseController {
private BaseService service = null;
public void init(BaseService service) {
this.service = service;
}
/**
* 添加模板
* 传入继承BaseService的类
*
* @param entity 传入实体类
* @param <T>
* @return
*/
public <T> ModelAndView add(T entity) {
// 创建一个用于格式化json数据的对象,方便向前台发送json数据
FastJsonJsonView view = new FastJsonJsonView();
// 进行持久层操作
int status = service.insert(entity);
// 向view对象中添加数据
view.addStaticAttribute("code", 0);
if (status > 0) {
view.addStaticAttribute("status", status);
view.addStaticAttribute("icon", 1);
view.addStaticAttribute("msg", "添加成功");
} else {
view.addStaticAttribute("status", status);
view.addStaticAttribute("icon", 2);
view.addStaticAttribute("msg", "添加失败");
}
// 返回json数据
return new ModelAndView(view);
}
/**
* 修改模板
*
* @param entity
* @param <T>
* @return
*/
public <T> ModelAndView update(T entity) {
// 创建一个用于格式化json数据的对象,方便向前台发送json数据
FastJsonJsonView view = new FastJsonJsonView();
// 进行持久层操作
int status = service.update(entity);
// 向view对象中添加数据
view.addStaticAttribute("code", 0);
if (status > 0) {
view.addStaticAttribute("status", status);
view.addStaticAttribute("icon", 1);
view.addStaticAttribute("msg", "修改成功");
} else {
view.addStaticAttribute("status", status);
view.addStaticAttribute("icon", 2);
view.addStaticAttribute("msg", "修改失败");
}
// 返回json数据
return new ModelAndView(view);
}
/**
* 删除模板
*
* @param entity
* @param <T>
* @return
*/
public <T> ModelAndView delete(T entity) {
// 创建一个用于格式化json数据的对象,方便向前台发送json数据
FastJsonJsonView view = new FastJsonJsonView();
// 进行持久层操作
int status = 0;
// 规避删除时一对多时删除父表内容时删除失败
try {
status = service.delete(entity);
} catch (Exception e) {
status = 0;
}
// 向view对象中添加数据
view.addStaticAttribute("code", 0);
if (status > 0) {
view.addStaticAttribute("status", status);
view.addStaticAttribute("icon", 1);
view.addStaticAttribute("msg", "删除成功!");
} else {
view.addStaticAttribute("status", status);
view.addStaticAttribute("icon", 2);
view.addStaticAttribute("msg", "删除失败!");
}
// 返回json数据
return new ModelAndView(view);
}
/**
* 查询一条数据
*
* @param entity
* @param <T>
* @return
*/
public <T> ModelAndView findOne(T entity) {
// 去查询
Object one = service.findOne(entity);
// 创建一个用于格式化json数据的对象,方便向前台发送json数据
FastJsonJsonView view = new FastJsonJsonView();
// 向view对象中添加数据
view.addStaticAttribute("code", 0);
view.addStaticAttribute("status", 1);
view.addStaticAttribute("data", one);
// 返回json数据
return new ModelAndView(view);
}
/**
* 分页查询方法
*
* @param page
* @param entity
* @param objects
* @param <T>
* @return
*/
public <T> ModelAndView findPage(LayuiPageHelper page, T entity, Object... objects) {
// 创建一个用于格式化json数据的对象,方便向前台发送json数据
FastJsonJsonView view = new FastJsonJsonView();
// 创建pageHelper对象,用于分页
LayuiPageHelper pages = new LayuiPageHelper();
// 从数据库查询总数
pages.setCount(service.dataCount(entity, objects));
// 设置当前页
pages.setPageNow(page.getPageNow() == 0 ? 1 : Integer.valueOf(page.getPageNow()));
// 设置页大小
pages.setPageSize(page.getPageSize() == 0 ? 5 : Integer.valueOf(page.getPageSize()));
// 向view对象中添加数据
view.addStaticAttribute("code", 0);
view.addStaticAttribute("message", "查询成功");
view.addStaticAttribute("count", pages.getCount());
// -----------------------------------从数据查询数据信息
view.addStaticAttribute("data", service.findPage(entity, pages, objects));
// 返回json数据
return new ModelAndView(view);
}
}
2. BaseMapper
用于mybatis的mapper接口,可直接进行继承
package com.aaa.mapper;
import com.aaa.util.LayuiPageHelper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* Mapper模板
* @author 淮南King
* @date 2020-07-04
*/
public interface BaseMapper<T> {
int insert(@Param("beans") T t);
int update(@Param("beans") T t);
int delete(@Param("beans") T t);
List<T> findPage(@Param("beans") T t, @Param("page") LayuiPageHelper page, @Param("obj") Object... objects);
int dataCount(@Param("beans") T t, @Param("obj") Object... objects);
T findOne(@Param("beans") T t);
}
3. BaseService
Service层模板
package com.aaa.service;
import com.aaa.mapper.BaseMapper;
import com.aaa.util.LayuiPageHelper;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* Service层模板
* @author 淮南King
* @date 2020-07-04
*/
@Service
public abstract class BaseService<T> {
/**
* 用于获取Mapper
* @return
*/
public abstract BaseMapper<T> getDao();
public int insert(T entity) {
return getDao().insert(entity);
}
public int update(T entity) {
return getDao().update(entity);
}
public int delete(T entity) {
return getDao().delete(entity);
}
public List<T> findPage(T t, LayuiPageHelper page, Object... objects) {
return getDao().findPage(t, page, objects);
}
public T findOne(T entity) {
return getDao().findOne(entity);
}
public int dataCount(T entity, Object... objects) {
return getDao().dataCount(entity, objects);
}
}
4. LayuiPageHelper
适用于layui中的分页插件
package com.aaa.util;
/**
* 适用于layui中的分页插件
* @author 淮南King
* @date 2020-07-04
*/
public class LayuiPageHelper {
private int begin = 0;
private int pageSize = 10;
private int count = 0;
private int pageNow = 1;
private int pageTotal = 0;
/** 用于接受layui发送的当前页 */
private int page = 1;
/** 用于接受layui发送的页大小 */
private int limit = 5;
public LayuiPageHelper() {
}
public LayuiPageHelper(int page, int limit) {
this.page = page;
this.limit = limit;
}
public int getPage() {
return pageNow;
}
public void setPage(int page) {
this.page = page;
this.pageNow = page;
}
public int getLimit() {
return pageSize;
}
public void setLimit(int limit) {
this.pageSize = limit;
this.limit = limit;
}
public int getBegin() {
this.begin = (this.pageNow - 1) * this.pageSize;
return begin;
}
public void setBegin(int begin) {
this.begin = begin;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public int getPageNow() {
return pageNow;
}
public void setPageNow(int pageNow) {
this.pageNow = pageNow;
}
public int getPageTotal() {
this.pageTotal = this.count % this.pageSize == 0 ? this.count / this.pageSize : this.count / this.pageSize + 1;
return pageTotal;
}
public void setPageTotal(int pageTotal) {
this.pageTotal = pageTotal;
}
}
前端模板
- 使用layui进行页面美化,layui官网传送门
- 前端使用Ajax向后端发送请求
- list为显示表格页面,form为添加和修改的页面,通过url带参数让form页面进行动态改变
1. list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%request.setAttribute("pn", pageContext.getServletContext().getContextPath());%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>展示信息</title>
<link rel="stylesheet" href="${pn}/static/layui/css/layui.css">
</head>
<body>
<!-- layui-card 包括整个页面 -->
<div class="layui-card">
<!-- 表头搜索部分 -->
<div class="layui-form">
<div class="layui-form-item">
<!-- 文本输入框,用于模糊查询 -->
<div class="layui-inline">
<input type="text" id="entityName" placeholder="请输入内容" autocomplete="off"
class="layui-input">
</div>
<!-- 搜索按钮 -->
<div class="layui-inline">
<button class="layui-btn layui-btn-radius layui-btn-normal" id="entity_search">
<i class="layui-icon layui-icon-search"></i>
</button>
</div>
<!-- 新增按钮 -->
<div class="layui-inline">
<button class="layui-btn layui-btn-radius layui-btn-normal"
onclick="windowOpen('form.jsp?url=/grade/add')">添加
</button>
</div>
<!-- 查看学生信息列表 -->
<div class="layui-inline">
<a class="layui-btn layui-btn-radius layui-btn-normal" href="../StudentAndGrade/list.jsp">查看学生信息</a>
</div>
</div>
</div>
<!-- table部分 -->
<div class="layui-card-body">
<table id="datatable" lay-filter="datatable"></table>
</div>
</div>
<script src="${pn}/static/layui/layui.js"></script>
<!-- table表格尾部的按钮元素 -->
<script type="text/html" id="table_bar">
<div class="layui-btn-container">
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
</div>
</script>
<script type="text/javascript">
// layui 部分
layui.use(['table', 'util'], function () {
var $ = layui.$,
table = layui.table,
util = layui.util;
//表格配置
table.render({
elem: '#datatable'
, height: 400
, url: '/grade/findAll' //数据接口
, page: true //开启分页
, limits: [3, 5, 10, 20]
, cols: [[ //表头
{field: 'gId', title: 'ID', width: 80, fixed: 'left'}
, {field: 'gName', title: '班级名称'}
, {field: 'address', title: '教室'}
, {
field: 'createDate', title: '班级创建日期',
templet: function (d) {
return util.toDateString(d.createDate, 'yyyy-MM-dd HH:mm:ss')
}
}
, {fixed: 'right', title: '操作', align: 'center', toolbar: '#table_bar'}
]]
, where: {'gName': $("#entityName").val()}
});
//监听搜索按钮
$("#entity_search").on('click', function (data) {
//刷新表格中的内容
table.reload('datatable', {
method: 'post'
, where: {'gName': $("#entityName").val()}
, page: {curr: 1}
});
});
//监听行工具事件
table.on('tool(datatable)', function (obj) { //注:tool 是工具条事件名,zq_table 是 table 原始容器的属性 lay-filter="对应的值"
const data = obj.data //获得当前行数据
, layEvent = obj.event; //获得 lay-event 对应的值(也可以是表头的 event 参数对应的值)
const tr = obj.tr; //获得当前行 tr 的DOM对象
switch (layEvent) {
case 'del':
layer.confirm('您确定删除id:' + data.gId + '的数据吗?', function (index) {
$.post("/grade/delete", {gId: data.gId}, function (ret) {
layer.msg(ret.msg);
if (ret.status == 1) {//删除成功,刷新当前页表格
$("#entity_search").click();
layer.close(index);
}
});
});
break;
case 'edit':
windowOpen("form.jsp?url=/grade/update&gId=" + data.gId);
break;
}
});
});
var windowsOpen = {};//定义全局变量
//开启一个窗口
function windowOpen(url) {
const l = (screen.availWidth - 375) / 2;
const t = (screen.availHeight - 667) / 2;
windowsOpen = window.open(url, '', 'height=500, width=600, top=' + t + ', left=' + l + ', toolbar=no, ' +
'menubar=no, scrollbars=no, resizable=no,location=no, status=no');
}
</script>
</body>
</html>
2. form.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%request.setAttribute("pn", pageContext.getServletContext().getContextPath());%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>表单数据</title>
<link rel="stylesheet" href="${pn}/static/layui/css/layui.css">
</head>
<body>
<div class="layui-card">
<div class="layui-form">
<input type="hidden" id="gId" value="0"/>
<div class="layui-form-item">
<label class="layui-form-label">班级名称</label>
<div class="layui-input-inline">
<input type="text" id="gName" lay-verify="required" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">教室</label>
<div class="layui-input-block">
<input type="text" id="address" lay-verify="required" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">创建日期</label>
<div class="layui-input-block">
<input type="datetime-local" id="createDate" lay-verify="required" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<input class="layui-btn layui-btn-radius layui-btn-normal" type="button" id="submit"
value="添加">
<input class="layui-btn layui-btn-radius layui-btn-primary" type="button" id="reset"
onclick="closeSelf()" value="取消">
</div>
</div>
</div>
<script src="${pn}/static/layui/layui.js" charset="UTF-8"></script>
<script src="${pn}/static/jquery-1.8.3.min.js" charset="UTF-8"></script>
<script>
//获取URL中的参数id
function getQueryVariable(variable) {
const query = window.location.search.substring(1);
const vars = query.split("&");
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
if (pair[0] == variable) {
return pair[1];
}
}
return (false);
}
//获取当前URL中的提交链接
const elemUrl = getQueryVariable('url')
//判断是否需要修改链接,若是修改链接则向后台请求当前数据详情
if(elemUrl.indexOf("update") != -1){
$.ajax({
url: "/grade/findOne",
type: 'post',
dataType: 'json',
async: false,//设置阻断
data: {
"gId": getQueryVariable('gId'),
},
success: function (data) {
$("#gId").val(data.data.gId);
$("#gName").val(data.data.gName)
$("#address").val(data.data.address)
$("#createDate").val(data.data.createDate)
}
});
}
layui.use(['layer','form'], function () {
var $ = layui.$,
form = layui.form,
layer = layui.layer;
//监听提交
$("#submit").on('click', function (data) {
$.ajax({
url: elemUrl,
type: 'post',
dataType: 'json',
async: false,//设置阻断
data: {
"gId":$("#gId").val(),
"gName": $("#gName").val(),
"address": $("#address").val(),
"createDate": $("#createDate").val()
},
success: function (data) {
layer.msg(data.msg);
//父窗口刷新
window.opener.location.reload();
//关闭当前窗口
window.close()
}
});
});
})
</script>
</body>
</html>