实习笔记
这是实习水了好几天来第一次被安排的任务,写一个个人用户中心模块的增删改查,我大概花了三天写完,离谱。。这里做一些笔记吧。 首先公司项目的技术是,springboot,前端用的springboot的内置模板Freemarker,但不是jsp页面,全是html和ftl页面,前后端交互的数据通过ajax请求来交互,前端ui用的layui框架 后端的话使用的是原生的jdbc对应的springtemplate来进行增删改查,分别controller,service,dao三层,并且将接口省去了,确实方便很多。。。。 我的任务就是对一个页面进行增删改查,如下图:
layui的官方网站
- 引入layui:https://www.layuicdn.com/#Layui
- layui开发文档:https://www.layui.site/doc/index.htm
- 在线演示layui组件:https://www.layui.site/demo/index.htm
layui的cdn引入模板
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 引入 layui.css -->
<link rel="stylesheet" href="https://www.layuicdn.com/layui-v2.6.8/css/layui.css">
<!-- 引入 layui.js -->
<script src="https://www.layuicdn.com/layui-v2.6.8/layui.js">
</head>
<body>
</body>
</html>
因为在一个页面中,有子页面,因此前端有两个页面,一个主页面person,一个提交页面personSub
整体页面逻
主页面person的js逻辑
代码语言:javascript复制 var fwqxsqdata;
var perCenTable;
var isFirst = true;
// 应用权限表格
var YYQXSQtable;
//服务权限申请
layui.use(['table', 'element', 'laypage', 'form'], function () {
var table = layui.table,
$ = layui.jquery,
element = layui.element
, page = layui.laypage
, form = layui.form; //Tab的切换功能,切换事件监听等,需要依赖element模块
var height = $(window).height();
var heightStr = 'full-300';
if (height > 500 && height < 900) {
heightStr = 'full-180';
}
var lbParmas = {
page: 1,
limit: 10,
scenceIds: $("#scenceIds").val()
};
// 获取数据服务列表
var getList = function () {
lbParmas = {
pageNo: 1,
pageSize: 10,
moudleName: $("#MoudleName").val()
};
postAjax(requestUrl "/perCenterApi/selectGrzxXmMKList", lbParmas, function (data) {
console.log(data)
page.render({
elem: 'layuipage',
count: data.count,
contentType: "application/json;charset=UTF-8",
curr: lbParmas.pageNo,
limit: lbParmas.pageSize,
first: "首页",
last: "尾页",
layout: ['count', 'prev', 'page', 'next', 'limit', 'skip'],
jump: function (obj, first) {
if (!first) {
lbParmas.pageNo = obj.curr;
lbParmas.pageSize = obj.limit;
lbParmas.scenceIds=$("#scenceIds").val();
getAjax(requestUrl "/perCenterApi/selectGrzxXmMKList", lbParmas,function (data) {
perCenTable.reload({
data: data.list
});
$('#perCenTable').parent().find('.layui-table-header').find('.layui-form-checkbox').hide();
})
}
}
});
perCenTable = table.render({
elem: '#perCenTable',
id: 'perCenTable'
, cols: [
[ //标题栏
{type: 'checkbox'},
{field: 'id', title: 'id',hide:true},
{field: 'moduleName', title: '模块名称'},
{field: 'dispSn', title: '排序'},
{field: 'bz', title: '备注'},
]
]
, even: true
, height: heightStr
, data: data.list
, page: false //是否显示分页
, limit: Number.MAX_VALUE
});
$('#perCenTable').parent().find('.layui-table-header').find('.layui-form-checkbox').hide();
}, function (res) {
});
};
table.on('checkbox(perCenTable)',function(obj){
$('#perCenTable').parent().find('.layui-table-header').find('.layui-form-checkbox').hide();
if(obj.checked) {
fwqxsqdata = obj;
} else {
fwqxsqdata = null;
$(obj.tr).find('td div.laytable-cell-checkbox div.layui-form-checkbox').attr('class','layui-unselect layui-form-checkbox');
}
});
getList('');
//查询
$("#Fsearch").click(function () {
getList(lbParmas);
});
//重置
$("#Freset").click(function () {
$("#MoudleName").val("");
getList();
});
function init(){
lbParmas.scenceIds = $('#scenceIds').val();
getList();
}
$("#mqSearchBtn").click(function () {
init();
})
//新增
$('#insertBtn').click(function () {
var width = $(window).width();
var height = $(window).height();
var index = layer.open({
type: 2,
title: '新增',
// area: [width 'px', height 'px'],
area: ['75%', '70%'],
content: 'personalCenterSubApi.html?flag=add',
end: function () {
location.reload();
}
});
// layer.full(index);
});
//编辑
$('#updateBtn').click(function () {
if (!fwqxsqdata) {
layer.alert('请选择一条数据!');
return;
}
var title = fwqxsqdata.data.serverName;
var width = $(window).width();
var height = $(window).height();
console.log(fwqxsqdata.data.id);
var index = layer.open({
type: 2,
title: title,
// area: [width 'px', height 'px'],
area: ['85%', '70%'],
content: 'personalCenterSubApi.html?flag=update&id=' fwqxsqdata.data.id,
end: function () {
location.reload();
}
});
// layer.full(index);
});
//查看
$('#chaKanBtn').click(function () {
if (!fwqxsqdata) {
layer.alert('请选择一条数据!');
return;
}
var title = fwqxsqdata.data.serverName;
var width = $(window).width();
var height = $(window).height();
var index = layer.open({
type: 2,
title: title,
// area: [width 'px', height 'px'],
area: ['85%', '70%'],
content: 'personalCenterSubApi.html?flag=chakan&id=' fwqxsqdata.data.id
});
// layer.full(index);
});
//删除
$('#delBtn').click(function () {
if (!fwqxsqdata) {
layer.alert('请选择一条数据!');
return;
}
console.log(fwqxsqdata.data.id)
var parmas = {
id: fwqxsqdata.data.id
};
postAjax(requestUrl "/perCenterApi/deleteGrzxMK?" , parmas, function (data) {
if (data.msg == '删除成功') {
layer.alert('删除成功!');
fwqxsqdata = null;
$("#scenceIds").val("");
getList();
} else {
layer.alert('删除失败!');
}
});
});
})
子页面personSub页面的js逻辑
代码语言:javascript复制layui.use(['table', 'element', 'laypage', 'form'], function () {
var table = layui.table,
$ = layui.jquery,
element = layui.element
, upload = layui.upload
, page = layui.laypage
, form = layui.form; //Tab的切换功能,切换事件监听等,需要依赖element模块
var flag = getUrlParam('flag');
$('#id').val(getUrlParam('id'));//id
//跳转页面动态
if (flag == 'update') {
var param = {
id: getUrlParam ('id')
};
//下拉框加载
postAjax(requestUrl "/perCenterApi/getModuleByParCode", param, function (data) {
$.each(data, function(index, value) {
$("#moduleCode").append('<option value=' value.code '>' value.name '</option>');
});
layui.form.render("select");
postAjax(requestUrl "/perCenterApi/selectGrzxXm", param, function (data) {
$('#showPic').show()
$('#showPic').unbind()
$('#showPic').click(function () {
layer.open({
type: 2,
area :['70%','70%'],
content: requestUrl '/perCenterApi/getPicUrl?id=' getUrlParam('id')
});
})
$('#moduleCode').find("option:selected").text(data.data.moduleName)//模块名称
form.render('select');
$('#dispSn').val(data.data.dispSn);//排序
$('#remark').val(data.data.bz);//备注
});
$('select').attr('disabled', 'disabled');
});
} else if (flag == 'chakan') {
$('#saveBtn').hide();
var param = {
id: getUrlParam('id')
};
postAjax(requestUrl "/perCenter/getModuleByParCode", param, function (data) {
$.each(data, function (index, value) {
$("#moduleCode").append('<option value=' value.code '>' value.name '</option>');
});
layui.form.render("select");
postAjax(requestUrl "/perCenterApi/selectGrzxXm", param, function (data) {
console.log(data)
// $('#moduleCode').val(data.data.moduleName);//模块名称
//下拉框设置值得这么写
$('#moduleCode').find("option:selected").text(data.data.moduleName)
$('#dispSn').val(data.data.dispSn);//排序
$('#remark').val(data.data.bz);//备注
form.render('select');
});
$('input,textarea,select').attr('disabled', 'disabled');
});
}else{
postAjax(requestUrl "/perCenterApi/getModuleByParCode", param, function (data) {
$.each(data, function(index, value) {
$("#moduleCode").append('<option value=' value.code '>' value.name '</option>');
});
layui.form.render("select");
});
}
// 提交
$('#saveBtn').click(function (data) {
var moduleCode = $('#moduleCode').val();
if (moduleCode == '') {
layer.alert('模块名称不能为空');
return;
}
let moduleName = $("#moduleCode").find("option:selected").text();
$('#moduleName').val(moduleName)
var dispSn = $('#dispSn').val();//排序
if (dispSn == '') {
layer.alert('排序不能为空');
return;
}
var bz = $('#remark').val();//排序
$('#bz').val(bz);
var datas = new FormData(document.getElementById('perCenSub'));
if (flag == 'update') {
postAjaxForm(requestUrl "/perCenterApi/updateGrzxMK", datas, function (res) {
if (res.msg == '修改成功') {
layer.alert('修改成功!',function () {
colseWindow();
});
} else {
layer.alert('修改失败!');
}
});
} else if (flag == 'add') {
let moduleName = $("#moduleCode").find("option:selected").text();
//先进行判断
console.log(moduleName)
var param = {
moduleName: moduleName
};
var a = false;
postAjax(requestUrl "/perCenterApi/selectGrzxXmByName", param, function (data) {
console.log(moduleName)
console.log(data)
if(data.data==null){
a=false
}else{
if(moduleName == data.data.moduleName)
a = true
}
console.log(a)
if(a==false){
postAjaxForm(requestUrl "/perCenterApi/addGrzxMk", datas, function (res) {
console.log("log:" res.msg)
if (res.msg == '新增成功') {
layer.alert('新增成功!',function () {
colseWindow();
});
} else {
layer.alert('新增失败!');
}
});
}else{
layer.alert('新增失败!');
}
});
}
});
// 关闭页面
$('#closeBtn').click(function () {
colseWindow();
});
//关闭子页面跳转父页面
function colseWindow() {
var index = parent.layer.getFrameIndex(window.name);
parent.layer.close(index);
}
});
下面演示一个功能的全部代码
前面已经知道了,逻辑代码中,使用layui.use方面进行页面刷新,用户进入页面后,处于观看状态,这时为用户准备了很多按钮,每一个按钮都绑定一个事件,这里介绍一两个功能。
新增一条数据
主页面绑定的按钮新增事件
代码语言:javascript复制 //新增
$('#insertBtn').click(function () {
var width = $(window).width();
var height = $(window).height();
var index = layer.open({
type: 2,
title: '新增',
// area: [width 'px', height 'px'],
area: ['75%', '70%'],
content: 'personalCenterSubApi.html?flag=add',
end: function () {
location.reload();
}
});
// layer.full(index);
});
通过绑定id为insertBtn的按钮点击事件,然后利用layui框架的open函数打开一个页面内置窗口(为什么要这么做?因为你新增,你得新增数据啊,当然数据就填写在这个新增的窗口中)
新开窗口的页面逻辑
可以看到,这里没有页面加载函数,事实上,也不需要,通过前面首页传来的参数flag,分别调用新增,修改,查看函数。并且,绑定了两个按钮。下面看下这个新增的详细代码
代码语言:javascript复制else{
postAjax(requestUrl "/perCenterApi/getModuleByParCode", param, function (data) {
$.each(data, function(index, value) {
$("#moduleCode").append('<option value=' value.code '>' value.name '</option>');
});
layui.form.render("select");
});
}
你可能会好奇,为什么新增有两端代码(下面一段),前面一段是什么?其实,是加载下拉框。这里我不能再访问那个页面路径了,因此选个效果图看看:
$.each(data, function(index, value)则是一个jq中的遍历函数,将其渲染到下拉框中,通过css中的id选择,选择到下拉框
代码语言:javascript复制<select id="moduleCode" name="moduleCode" lay-filter="moduleCode">
<option value="" id="option">请选择</option>
<#-- <option value="1">QUICK</option>-->
<#-- <option value="2">TEST</option>-->
</select>
此时,用户再次处于查看状态,再写前端逻辑时,一定要注意到用户的状态!下面我把这种状态称为停滞状态,方便记忆。停滞状态的用户需要通过点击等事件来响应操作,这时就能想到了这个页面只有两个绑定事件,一个提交按钮,一个关闭按钮,因此,新增就在提交按钮里!但是提交按钮,不都是让你新增的,还有修改,因此需要一个flag判断,还记得首页我们请求发送到这个页面带了一个参数flag=add吗?
代码语言:javascript复制else if (flag == 'add') {
let moduleName = $("#moduleCode").find("option:selected").text();
//先进行判断
console.log(moduleName)
var param = {
moduleName: moduleName
};
var a = false;
postAjax(requestUrl "/perCenterApi/selectGrzxXmByName", param, function (data) {
console.log(moduleName)
console.log(data)
if(data.data==null){
a=false
}else{
if(moduleName == data.data.moduleName)
a = true
}
console.log(a)
if(a==false){
postAjaxForm(requestUrl "/perCenterApi/addGrzxMk", datas, function (res) {
console.log("log:" res.msg)
if (res.msg == '新增成功') {
layer.alert('新增成功!',function () {
colseWindow();
});
} else {
layer.alert('新增失败!');
}
});
}else{
layer.alert('新增失败!');
}
});
}
这里有个业务需求就是不能新增重复的名称,因此再新增之前,进行了一次查询,这个先不看了,可以看到新增直接发送请求来到了/perCenterApi/addGrzxMk这里,接下来看下controller代码之前,看下提交的参数datas,这个参数datas在前面的代码中声明是这样的
代码语言:javascript复制var datas = new FormData(document.getElementById('perCenSub'));
因为,datas的类型是object,并且是一个类似。而这里用到了FormData函数,需要传入一个表单对象,会将表单中的值全部映射到datas,并且postajax提交时,注明一下postajaxForm,
代码语言:javascript复制//这里的讲下formdata对象,其实就是一个map键值对集合,可以通过formdata函数将表单中的对象转为集合通过ajax方便传值
//我们可以通过name来访问表单中的字段
formdata.get("username"); //获取username的值
formdata.get("pwd"); //获取pwd的值
//我们也可以添加数据
formdata.append("token","fegahgag54")
后端controller层代码
代码语言:javascript复制 @RequestMapping(value = "/addGrzxMk",name = "新增模块信息")
@ResponseBody
public ResultModel addGrzxMk(String bz,
String moduleName,
String dispSn,
HttpServletResponse response,
HttpServletRequest request ){
ResultModel resultModel = new ResultModel();
String msg = "";
boolean success = true;
UserInfo userInfo = WebUtil.getCurrUserInfo(request,response);
GarzaXmas garzaXmas = new GarzaXmas();
garzaXmas.setBz(bz);
garzaXmas.setModuleName(moduleName);
garzaXmas.setDispSn(dispSn);
garzaXmas.setRyId(userInfo.getUserId());
msg = personalCenterService.addGrzxMk(garzaXmas);
resultModel.setSuccess(success);
resultModel.setMsg(msg);
return resultModel;
}
这里用到了springmvc的知识点:
为什么提交的url来到了controller对应的这个addGrzxMk这里?
这里是可以说是springmvc的原理,其实老大哥tomcat本来也有这个原理,不就是servlet吗?通过注解配置WebServlet(“/hello”)实现,至于这些:
- tomcat中如何实现url输入路径,配置注解@WebServlet就找到对应的servlet方法?
- 那为什么现在改了@requestmapping注解,或者说为什么要用springmvc?springmvc的底层原理路由是怎么样的
- spring在当中是扮演了怎么样的角色,和tomcat的关系,和springmvc的关系?
这里开一个新文章来说说这些问题
spring,tomcat,springmvc之间的关系
那么继续,既然获得了ajax请求过来的数据,那么就好办, 新增嘛,肯定是声明一个新增的这个类对象来封装这些数据。代码中该对象变量是garzaXmas。这里为什么不是用对象来接收?很简单,因为前端传来的值并不是这个对象的所有字段都包含了。另外一点就是,如果是查询,删除,修改这些需求的话,是根据id或者名称来的,那么函数之间传参直接用一个string类型的字符串可以吗?可以,但不建议,因为习惯都是通过对象在逻辑之间传递,并且后续你查询,如果是加where条件呢?你又得改代码,加参数。
下面来看下service层的代码吧
代码语言:javascript复制public String addGrzxMk(GarzaXmas grzxXmry) {
int i = 0 ;
try {
i = personalCenterDao.addGrzxMk(grzxXmry);
if (i >0){
return "新增成功";
}
} catch (Exception e) {
e.printStackTrace();
}
return "新增失败";
}
没啥好说的
下面是dao层的代码
代码语言:javascript复制 public int addGrzxMk(GarzaXmas grzxXmry) {
String uuid = UUID.randomUUID().toString();
String sql ="Insert into t_grzx_mk(id,ry_id,module_name,disp_sn,bz) values(?,?,?,?,?)";
LobHandler handler = new DefaultLobHandler();
Integer execute = jt.execute(sql, new AbstractLobCreatingPreparedStatementCallback(handler) {
@Override
protected void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException, DataAccessException {
int index = 1;
ps.setObject(index , uuid);
ps.setObject(index , grzxXmry.getRyId());
ps.setObject(index , grzxXmry.getModuleName());
ps.setObject(index , grzxXmry.getDispSn());
ps.setObject(index , grzxXmry.getBz());
}
}
);
this.close();
return execute;
}
这里也没啥好说的,唯一点就是使用了DefaultLobHandler这个类,来实现插入一些BLOB(二进制大型对象)和 CLOB(字符大型对象)数据,参考链接:
https://www.cnblogs.com/dalianpai/p/13725105.html
至此,插入功能就结束了,其他删改查的功能我不会重复写,但这里列出一些需要注意的细节
查删改中的细节
既然新增不能插入重复的数据,那么修改也需要先进行一次判断吗?不用,可以直接将下面列表进行固定,锁住。
input文本框渲染值和下拉框如何渲染值
代码语言:javascript复制postAjax(requestUrl "/perCenter/getModuleByParCode", param, function (data) {
$.each(data, function (index, value) {
$("#moduleCode").append('<option value=' value.code '>' value.name '</option>');
});
layui.form.render("select");
postAjax(requestUrl "/perCenterApi/selectGrzxXm", param, function (data) {
console.log(data)
// $('#moduleCode').val(data.data.moduleName);//模块名称
//下拉框设置值得这么写
$('#moduleCode').find("option:selected").text(data.data.moduleName)
$('#dispSn').val(data.data.dispSn);//排序
$('#remark').val(data.data.bz);//备注
form.render('select');
});
$('input,textarea,select').attr('disabled', 'disabled');
});
这里是查看ajax请求返回的数据并渲染到前端的代码,至于前面的下拉框锁住就是最后一句代码: $(‘input,textarea,select’).attr(‘disabled’, ‘disabled’);不过这里是全部锁住了,因为是查看嘛。
最顶层的查询和重置
这个模块涉及的知识点是;分页和模糊查询
代码语言:javascript复制 //查询
$("#Fsearch").click(function () {
getList(lbParmas);
});
//重置
$("#Freset").click(function () {
$("#MoudleName").val("");
getList();
});
实现的代码简单,关键还是之前写了刷新页面列表的函数getList,这个函数的查询可不是返回一个对象或者对象列表,而是返回一个页面对象。对的也就是分页功能。这里用到了layui的分页助手。下面看下这个函数吧
前端代码
代码语言:javascript复制 postAjax(requestUrl "/perCenterApi/selectGrzxXmMKList", lbParmas, function (data) {
console.log(data)
page.render({
elem: 'layuipage',
count: data.count,
contentType: "application/json;charset=UTF-8",
curr: lbParmas.pageNo,
limit: lbParmas.pageSize,
first: "首页",
last: "尾页",
layout: ['count', 'prev', 'page', 'next', 'limit', 'skip'],
jump: function (obj, first) {
if (!first) {
lbParmas.pageNo = obj.curr;
lbParmas.pageSize = obj.limit;
lbParmas.scenceIds=$("#scenceIds").val();
getAjax(requestUrl "/perCenterApi/selectGrzxXmMKList", lbParmas,function (data) {
perCenTable.reload({
data: data.list
});
$('#perCenTable').parent().find('.layui-table-header').find('.layui-form-checkbox').hide();
})
}
}
});
controller层代码
代码语言:javascript复制 @RequestMapping(value = "/selectGrzxXmMKList",name = "查询个人拥有的模块信息")
@ResponseBody
public Map<String,Object> selectGrzxXmMK(HttpServletRequest request, HttpServletResponse response, Integer pageNo,
Integer pageSize,String moudleName,String id){
UserInfo userInfo= WebUtil.getCurrUserInfo(request, response);
Map map = new HashMap<String,Object>();
List<GarzaXmas> garzaXmasList = personalCenterService.selectGrzxXmMK(id,userInfo,moudleName,pageNo,pageSize);
int count = personalCenterService.selectGrzxXmMKCount(userInfo);
map.put("list",garzaXmasList);
map.put("count",count);
return map;
}
从controller可以看到,查询数据库需要的参数是pageSize,pageNo。如果没有模糊查询的话是不需要moudleName这个参数的,id参数多余的别用看。事实上也正是如此,分页查询使用limit正是需要pageSize和pageNo,模块名称则是用来where,看下面sql:
代码语言:javascript复制sb.append("select id,MODULE_NAME moduleName,BZ bz,DISP_SN dispSnn"
" from t_grzx_mk where RY_ID = ? ");
if (Utils.availableStr(moduleName)){
sb.append(" and MODULE_NAME like '%" moduleName "%'");
}
sb.append("LIMIT " (pageNo-1 ) * pageSize "," pageSize);
总结
到此,这个小页面的增删改查笔记就写完了。如果文章有不对的地方,欢迎大佬们评论留言指出!
废江博客 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 转载请注明原文链接:实习笔记:java页面的增删改查,分页,模糊查询