上一篇介绍了spring boot整合mybatis实现了后端的CRUD的查询部分,本文主要是完善修改、删除和添加操作的后端,实现前端页面的调用。
源码链接(上一篇的源码有bug建议大家就看最新的)
1、完善添加、修改、删除后台
接口上篇已经定义号了,mapper也写完了,接下来就是完善conntroller,并测试。直接上conntroller的代码吧,里面注释进行了说明。
这个版本里面加了分页,service中的方法有的些变化,我也贴出来供大家参考,分页的类在源码中有这里就不贴了。
UserController.java
package com.pxk.springboot.conntroller;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.pxk.springboot.domain.User;
import com.pxk.springboot.helper.PageInfo;
import com.pxk.springboot.serivce.UserService;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired // 依赖注入service
UserService userService;
@RequestMapping("/getUser/{name}") // 定义requestMapping rest风格
protected User getUser(@PathVariable(value = "name") String name) {
return userService.getUser(name);
}
@RequestMapping("/getUserByName/{name}")
protected String getUserByName(@PathVariable(value = "name") String name, Model model) {
User user = userService.getUser(name);
model.addAttribute(user);
return "user";
}
/**================分割线==================*/
@RequestMapping("/findUserByPage")
@ResponseBody
public PageInfo<User> getStudents(PageInfo<User> pageInfo) {
return userService.findUserByPage(pageInfo);
}
@RequestMapping("/getUserById")
protected User getUserById(int id) {
return userService.getUserById(id);
}
@RequestMapping("/deleteUser")
protected int deleteUser(int id) {
User user = new User();
user.setId(id);
return userService.deleteUser(user);
}
@RequestMapping(value="/addUser", method = RequestMethod.POST)
protected int addUser(User user) {
if(user.getId()!=null&&user.getId()!=0){
return userService.updateUser(user);
}else{
user.setRegestDate(new Date());
return userService.addUser(user);
}
}
}
UserServiceImpl.java
package com.pxk.springboot.serivce.imp;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.pxk.springboot.dao.UserMapper;
import com.pxk.springboot.domain.User;
import com.pxk.springboot.helper.Page;
import com.pxk.springboot.helper.PageInfo;
import com.pxk.springboot.serivce.UserService;
@Service//注入成service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User getUser(String name) {
return new User(name);
}
//这里实现了分页,看着有点复杂,是因为我原来习惯使用分页插件包(pageHelper),这里为了方便理解直接省略了插件包
//简化使用了这个包里面的两个类Page和PageInfo
@Override
public PageInfo<User> findUserByPage(PageInfo<User> pageInfo) {
long count =userMapper.findCount();
List<User> list=userMapper.findUserByPage((pageInfo.getPageNum()-1)*pageInfo.getPageSize(), pageInfo.getPageSize());
Page<User> page=new Page<>(pageInfo.getPageNum(), pageInfo.getPageSize());
page.setTotal(count);
PageInfo<User> rpg = new PageInfo<User>(page);
rpg.setList(list);
return rpg;
}
@Override
public User getUserById(int id) {
return userMapper.getUserById(id);
}
@Override
public int updateUser(User user) {
return userMapper.updateUser(user);
}
@Override
public int deleteUser(User user) {
return userMapper.deleteUser(user);
}
@Override
public int addUser(User user) {
return userMapper.addUser(user);
}
}
2、整合前端Bootstap Table + jquery
前端其实很简单,只有一个核心的html页面和一个js,有很多细节这里就不做过多介绍,比如表单中包括附件,处理方式肯定不同了哈。多选删除我本来已经实现了,但是为了简化又删了。分页是借助了BootStrap分页的参数(这个参数会自动带到后台,Bootstap table源码的参数和后台我用PageInfo属性名不一致,我改过Bootstap源码,目的就是为了不改pagehelper那个分页插件,也就是我选择改前端来适应后端,就目前这个例子而言改前后都不会有影响。注意:直接在官网下载的BootStrap Table分页和这个例子的后台不能兼容)
直接贴出html和js,懂点前端的朋友都能看懂,BootStrap Table不好理解的地方全部加了注释,我的前端很烂的,写得不好还请见谅了。
userList.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>用户列表</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<link rel="stylesheet" type="text/css" href="../css/userList.css">
<link rel="stylesheet" type="text/css"
href="../css/bootstrap/css/bootstrap.css">
<link rel="stylesheet" type="text/css"
href="../css/bootstrap-select.min.css">
<script type="text/javascript" src="../js/jquery-1.12.0.js"></script>
<script type="text/javascript" src="../js/common.js"></script>
<script type="text/javascript" src="../js/bootstrap-table.js"></script>
<script type="text/javascript" src="../js/bootstrap-table-zh-CN.min.js"></script>
<script type="text/javascript" src="../css/bootstrap/js/bootstrap.js"></script>
<script type="text/javascript" src="js/userList.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<form class="form-horizontal" role="form">
<div class="from-group">
<div class="col-sm-1">
<input type="button" class="btn btn-primary" value="新增"
onclick="addUser()" />
</div>
</div>
</form>
</div>
<div class="">
<table id="mytab" class="table table-hover"></table>
</div>
</div>
<!-- 编辑用户信息 模态窗口-->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog"
aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">修改用户信息</h4>
</div>
<div class="modal-body">
<input type="hidden" id="sid" name="sid" />
<div class="form-group">
<label class="control-label">姓名:</label><input name="name"
id="usernameTextE" type="text" class="form-control" />
</div>
<div class="form-group">
<label class="control-label">性别:</label> <input
id="gederTextM" value="M" name="gender" type="radio" /> 男 <input
id="gederTextF" name="gender" value="F" type="radio" /> 女
</div>
<div class="form-group">
<label class="control-label">年龄:</label><input name="age"
id="ageTextE" type="text" class="form-control" />
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" onclick="saveUser()">保存</button>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->
</body>
</html>
userList.js
var myrow = {};
$(function() {
$('#mytab').bootstrapTable({
url : "../user/findUserByPage",// 数据源
dataField : "list",// 服务端返回数据键值 就是说记录放的键值是rows,分页时使用总记录数的键值为total
// search: true,//是否搜索
totalField : "total",// 接收总页数的参数
pagination : true,// 是否分页
pageSize : 5,// 单页记录数
pageList : [ 5, 10, 20, 50 ],// 分页步进值
sidePagination : "server",// 服务端分页
// contentType: "application/x-www-form-urlencoded",//请求数据内容格式 默认是
// application/json 自己根据格式自行服务端处理
dataType : "json",// 期待返回数据类型
method : "get",// 请求方式
searchAlign : "left",// 查询框对齐方式
queryParamsType : "other",// 查询参数组织方式 为limit时候传的参数是 offset和limit,否则为
// pageSize和pageNumber
// 可以带查询参数
// queryParams : function getParams(params) {
// params.name = $('#usernameText').val();
// return params;
// },
searchOnEnterKey : false,// 回车搜索
columns : [
// {
// title : "全选",
// // field : "select",
// checkbox : true,
// width : 20,// 宽度
// align : "center",// 水平
// valign : "middle"// 垂直
// },
{
title : "用户名",// 标题
field : "name"// 键名
// sortable: true,//是否可排序
// order: "desc"//默认排序方式
}, {
field : "gender",
title : "性别",
formatter : function(value, row, index) {
if (value == "F") {
return "女";
} else {
return "男";
}
}
},{
title : "注册时间",// 标题
field : "regestDate"// 键名
}, {
title : "操作",
field : "control",
width : 70,
align : "center",
valign : "middle",
formatter : operateFormatter,
events : "operateEvents"
} ],
locale : "zh-CN", // 中文支持,
detailView : false
// 是否显示详情折叠
});
});
window.operateEvents = {
'click .remove' : function(e, value, row) {
deleteSudentsById(row.id);
},
'click .edite' : function(e, value, row) {
$("#myModal").modal('show');
$("#sid").val(row.id);
// 为输入框赋值
$("#usernameTextE").val(row.name);
$("#ageTextE").val(row.age);
$("#regestDateE").val(row.regestDate);
row.gender == "F" ? $("#gederTextF").prop("checked", "checked") : $(
"#gederTextM").prop("checked", "checked");
}
};
function operateFormatter(value, row, index) {
return [
'<div class="pull-center">',
'<a class="edite" href="javascript:void(0)" title="编辑" href="#"><span class="glyphicon glyphicon-expand"></span></a>',
' <a class="remove" href="javascript:void(0)" title="删除">',
'<i class="glyphicon glyphicon-remove"></i>', '</a>', '</div>' ]
.join('');
}
// 新增用户
function addUser() {
$("#sid").val("");
// 情况信息编辑窗口(编辑和新增公用了一个窗口需要清空)
$("#usernameTextE").val("");
$("#gederTextM").attr("checked", "checked");// 性别默认为男
$("#dd").html("");// 清空头像
// 弹出信息编辑模态窗口
$("#myModal").modal('show');
}
// 保存用户信息
function saveUser() {
// 调用后台方法进行保存
$.ajax({
url : '../user/addUser',
type : 'POST',
data : {
id : $("#sid").val(),
// 为输入框赋值
name : $("#usernameTextE").val(),
age : $("#ageTextE").val(),
gender : $('#gederTextM:checked').val()
},
async : false,
cache : false,
success : function(returndata) {
// 关闭模态窗口
$("#myModal").modal('hide');
// 刷新列表
$('#mytab').bootstrapTable('refresh');
},
error : function(returndata) {
alert("添加失败!");
},
dataType : "json"
});
}
function deleteSudentsById(id) {
var r = confirm("确认要删除该数据吗!");
if (r == true) {
$.get("../user/deleteUser", {
id : id
}, function(data) {
alert("删除成功!");
// 刷新列表
$('#mytab').bootstrapTable('refresh');
}, "json");
} else {
alert("删除失败!")
}
}
// 下面用于多图片上传预览功能
function setImagePreviews(avalue) {
var docObj = document.getElementById("upload-file");
var dd = document.getElementById("dd");
dd.innerHTML = "";
var fileList = docObj.files;
for (var i = 0; i < fileList.length; i++) {
dd.innerHTML += "<img id='img" + i + "' />";
var imgObjPreview = document.getElementById("img" + i);
if (docObj.files && docObj.files[i]) {
// 火狐下,直接设img属性
imgObjPreview.style.display = 'block';
imgObjPreview.style.width = '150px';
imgObjPreview.style.height = '180px';
// imgObjPreview.src = docObj.files[0].getAsDataURL();
// 火狐7以上版本不能用上面的getAsDataURL()方式获取,需要一下方式
imgObjPreview.src = window.URL.createObjectURL(docObj.files[i]);
} else {
// IE下,使用滤镜
docObj.select();
var imgSrc = document.selection.createRange().text;
alert(imgSrc)
var localImagId = document.getElementById("img" + i);
// 必须设置初始大小
localImagId.style.width = "150px";
localImagId.style.height = "180px";
// 图片异常的捕捉,防止用户修改后缀来伪造图片
try {
localImagId.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale)";
localImagId.filters
.item("DXImageTransform.Microsoft.AlphaImageLoader").src = imgSrc;
} catch (e) {
alert("您上传的图片格式不正确,请重新选择!");
return false;
}
imgObjPreview.style.display = 'none';
document.selection.empty();
}
}
return true;
}
总结:
其实这个demo前端大家可能会陌生一些,如果大家不习惯用BootStrap Table那就随便换,后台都实现了而且是rest接口 前端随便你怎么换,参数给对了就行了。
坑:
1、遇到乱码问题,如果是数据传到后台没乱码,那一定就是数据库的问题,设置下数据库服务端编码搞定,如果是前端传到后端出现乱码,那springboot 提供了直接在application.properties中设置编码(参见源码)
2、实体属性和数据库属性对应不上的时候要注意了,比如数据库用的下划线隔开,实体类中用的驼峰。
3、日期的格式,spring mvc rest方式接口会自动转json格式返回,但是如果是日期格式默认直接转换成毫秒,需要在实体属性上加上注解@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")。
4、mybatis语法上的一些细节,这个只能靠多用多练了。
一个完整项目要用到的技术点太多,这只是个demo有很多细节没有做处理(异常处理、单元测试、返回结果封装、数据加密、接口权限等等,太多了就不一一列举了,以后有机会用专题文章来介绍)