springboot 入门教程(5) 基于ssm框架的crud操作(前端部分-附源码)
2017-09-18 21:54
716 查看
摘要: 本文接上一篇,主要是前端的内容Bootstrap table+jquery通过ajax调用后台rest接口实现CRUD操作。
上一篇介绍了spring boot整合mybatis实现了后端的CRUD的查询部分,本文主要是完善修改、删除和添加操作的后端,实现前端页面的调用。
源码链接(上一篇的源码有bug建议大家就看最新的)
这个版本里面加了分页,service中的方法有的些变化,我也贴出来供大家参考,分页的类在源码中有这里就不贴了。
UserController.java
UserServiceImpl.java
直接贴出html和js,懂点前端的朋友都能看懂,BootStrap Table不好理解的地方全部加了注释,我的前端很烂的,写得不好还请见谅了。
userList.html
userList.js
总结:
其实这个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有很多细节没有做处理(异常处理、单元测试、返回结果封装、数据加密、接口权限等等,太多了就不一一列举了,以后有机会用专题文章来介绍)
上一篇介绍了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有很多细节没有做处理(异常处理、单元测试、返回结果封装、数据加密、接口权限等等,太多了就不一一列举了,以后有机会用专题文章来介绍)
相关文章推荐
- springboot 入门教程(5) 基于ssm框架的crud操作(后台部分-附源码)
- springboot 入门教程(6)--- 整合Spring data JPA实现CRUD(附源码)
- MongoDB最简单的入门教程之四:使用Spring Boot操作MongoDB
- Spring Boot入门教程(7)---整合jpa,Shiro进行权限管理(附源码)
- [置顶] 使用IDEA基于springboot开发ssm框架(undertow代替tomcat以及其他功能)
- 第一个基于Spring-Boot框架的项目以及Java8新特新之stream流操作的简单细说
- 【超详细图文教程】用SpringBoot+Maven搭建SSM框架
- 基于springboot+bootstrap+mysql+redis搭建一套完整的权限架构【六】【引入bootstrap前端框架】
- SSM(Spring+SpringMVC+MyBatis)框架快速整合入门教程
- 基于redux的前端框架dva入门教程
- Java - Struts框架教程 Hibernate框架教程 Spring框架入门教程(新版) sping mvc spring boot spring cloud Mybatis
- SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)
- SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)
- SSM框架——具体整合教程(Spring+SpringMVC+MyBatis)
- SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)
- SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)
- 基于Springboot使用MongoDB进行简单Gis操作
- Java框架spring Boot学习笔记(四):Spring Boot操作MySQL数据库
- 微服务开发的入门级框架Spring Boot详解:集成Mybatis
- 基于SpringBoot的Environment源码理解实现分散配置