关于博客中使用的Guns版本问题请先阅读 Guns二次开发目录
测试的时候发现Guns v5.1-final 这个版本的字典管理模块有bug,然后便借此修改bug的机会来带领大家加深对Guns的理解,所谓万事开头难啊,同志们,有了这第一步,以后修改Guns和新增业务功能的时候,你心中的抗(恐)拒(惧)感应该就没有这么强烈了吧?不废话了,让我们开始吧。
需求一:解决字典包装类显示错误的问题
1、先确定问题是出现在后端接口还是前端页面
页面显示已经修改过来了:
查看数据库,发现也修改过来了:
发现bug所在:
分析:
我们可以发现数据库里的字典表中的记录是修改成功的,说明字典修改功能那一块是没有问题的。但是用户模块这边却显示出错的性别,此时查看用户列表的接口“/dict/list” 返回的数据,sex 字段(在sys_user表)表示的是性别,此时该字段的值是 1,这个是没有错的;因为一开始的接口返回的也是 1 ,可以查看前面的截图。然后看sexName这个字段,此时返回的是【男】,说明对性别字段sex的解释是由后台接口完成的,所有此时我们可以判定,问题应该是出现在后端接口 “/dict/list”中。
2、定位后端出问题的接口的代码位置
3、debug模式下浏览数据查询以及封装的过程
好了,接口对应的代码找到了,此时就要开启debug模式了:
4、修改代码
好吧,此处终于发现问题所在了,原来是字典包装的时候,用错了字段,下面是修改后的代码:
/**
* 根据字典名称和字典中的值获取对应的名称
*/
@Override
public String getDictsByName(String name, Integer val) {
//判断是否为null
if(val == null){
return "";
}
Dict temp = new Dict();
temp.setName(name);
Dict dict = dictMapper.selectOne(temp);
if (dict == null) {
return "";
} else {
Wrapper<Dict> wrapper = new EntityWrapper<>();
// wrapper = wrapper.eq("pid", dict.getId());
// List<Dict> dicts = dictMapper.selectList(wrapper);
// for (Dict item : dicts) {
// if (item.getNum() != null && item.getNum().equals(val)) {
// return item.getName();
// }
// }
//遍历操作太过耗费内存资源,不如直接查结果
wrapper.eq("pid", dict.getId()).eq("code",val.toString());//注意,要转换成字符串后再传入参数
//有可能会查询到多条记录,因为添加的时候没有做code的唯一判断
List<Dict> dicts = dictMapper.selectList(wrapper);
//mybatis-plus返回的list不会为null,如果没有查到结果,会返回空集合
if(!dicts.isEmpty()){
return dicts.get(0).getName();
}
return "";
}
}
重启idea,测试结果:
需求二:给添加/修改字典功能加上【排序】字段的设置
好吧,前面的字典包装类排查bug的过程还不够过瘾,于是又给自己加了一个需求,我们查看字典表 sys_dict 时发现,字典类型的num字段没有利用上:
1、找到相应的前端页面并修改
比如我要在添加和修改页面,添加排序字段的文本框,允许用户设置和修改这个字段的值,此时就要先找到【添加字典】和【修改字典】页面对应的Html页面:
以下是完整的前端代码:
设计到的页面有:
dict_info.js
/**
* 初始化字典详情对话框
*/
var DictInfoDlg = {
count: $("#itemSize").val(),
dictName: '', //字典的名称
dictCode: '',//字典类型编码
dictTips: '',//字典备注
dictNum: '',//字典排序备注
mutiString: '', //拼接字符串内容(拼接字典条目)
itemTemplate: $("#itemTemplate").html()
};
/**
* item获取新的id
*/
DictInfoDlg.newId = function () {
if(this.count == undefined){
this.count = 0;
}
this.count = this.count + 1;
return "dictItem" + this.count;
};
/**
* 关闭此对话框
*/
DictInfoDlg.close = function () {
parent.layer.close(window.parent.Dict.layerIndex);
};
/**
* 添加条目
*/
DictInfoDlg.addItem = function () {
$("#itemsArea").append(this.itemTemplate);
$("#dictItem").attr("id", this.newId());
};
/**
* 删除item
*/
DictInfoDlg.deleteItem = function (event) {
var obj = Feng.eventParseObject(event);
obj = obj.is('button') ? obj : obj.parent();
obj.parent().parent().remove();
};
/**
* 清除为空的item Dom
*/
DictInfoDlg.clearNullDom = function(){
$("[name='dictItem']").each(function(){
var num = $(this).find("[name='itemNum']").val();
var name = $(this).find("[name='itemName']").val();
if(num == '' || name == ''){
$(this).remove();
}
});
};
/**
* 收集添加字典的数据
*/
DictInfoDlg.collectData = function () {
this.clearNullDom();
var mutiString = "";
$("[name='dictItem']").each(function(){
var code = $(this).find("[name='itemCode']").val();
var name = $(this).find("[name='itemName']").val();
var num = $(this).find("[name='itemNum']").val();
mutiString = mutiString + (code + ":" + name + ":"+ num+";");
});
this.dictName = $("#dictName").val();
this.dictNum = $("#dictNum").val();//新增的类型序号字段
this.dictCode = $("#dictCode").val();
this.dictTips = $("#dictTips").val();
this.mutiString = mutiString;
};
/**
* 提交添加字典
*/
DictInfoDlg.addSubmit = function () {
this.collectData();
//提交信息
var ajax = new $ax(Feng.ctxPath + "/dict/add", function (data) {
Feng.success("添加成功!");
window.parent.Dict.table.refresh();
DictInfoDlg.close();
}, function (data) {
Feng.error("添加失败!" + data.responseJSON.message + "!");
});
ajax.set('dictName',this.dictName);
ajax.set('dictCode',this.dictCode);
ajax.set('dictTips',this.dictTips);
ajax.set('dictNum',this.dictNum);//新增的类型序号字段
ajax.set('dictValues',this.mutiString);
ajax.start();
};
/**
* 提交修改
*/
DictInfoDlg.editSubmit = function () {
this.collectData();
var ajax = new $ax(Feng.ctxPath + "/dict/update", function (data) {
Feng.success("修改成功!");
window.parent.Dict.table.refresh();
DictInfoDlg.close();
}, function (data) {
Feng.error("修改失败!" + data.responseJSON.message + "!");
});
ajax.set('dictId',$("#dictId").val());
ajax.set('dictName',this.dictName);
ajax.set('dictCode',this.dictCode);
ajax.set('dictNum',this.dictNum);//新增的类型序号字段
ajax.set('dictTips',this.dictTips);
ajax.set('dictValues',this.mutiString);
ajax.start();
};
dict_add.html
@layout("/common/_container.html"){
<div class="ibox float-e-margins">
<div class="ibox-content">
<div class="form-horizontal">
<input type="hidden" id="id" value="">
<div class="row">
<div class="col-sm-12" id="itemsArea">
<div class="form-group">
<label class="col-sm-2 control-label">类型编码</label>
<div class="col-sm-2">
<input class="form-control" id="dictCode" type="text">
</div>
<label class="col-sm-2 control-label">类型名称</label>
<div class="col-sm-2">
<input class="form-control" id="dictName" type="text">
</div>
<label class="col-sm-2 control-label">类型序号</label>
<div class="col-sm-2">
<input class="form-control" id="dictNum" type="text">
</div>
<div class="col-sm-2">
<#button btnCss="info" name="增加" icon="fa-plus" clickFun="DictInfoDlg.addItem()"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">备注</label>
<div class="col-sm-8">
<input class="form-control" id="dictTips" type="text">
</div>
</div>
<div class="hr-line-dashed"></div>
</div>
</div>
<div class="row btn-group-m-t">
<div class="col-sm-10">
<#button btnCss="info" name="提交" id="ensure" icon="fa-check" clickFun="DictInfoDlg.addSubmit()"/>
<#button btnCss="danger" name="取消" id="cancel" icon="fa-eraser" clickFun="DictInfoDlg.close()"/>
</div>
</div>
</div>
</div>
</div>
<script type="text/template" id="itemTemplate">
<div class="form-group" name="dictItem" id="dictItem">
<label class="col-sm-1 control-label">值</label>
<div class="col-sm-2">
<input class="form-control" type="text" name="itemCode">
</div>
<label class="col-sm-1 control-label" >名称</label>
<div class="col-sm-2">
<input class="form-control" type="text" name="itemName">
</div>
<label class="col-sm-1 control-label" >序号</label>
<div class="col-sm-2">
<input class="form-control" type="text" name="itemNum">
</div>
<div class="col-sm-2">
<#button btnCss="danger" name="删除" id="cancel" icon="fa-remove" clickFun="DictInfoDlg.deleteItem(event)"/>
</div>
</div>
</script>
<script src="${ctxPath}/static/modular/system/dict/dict_info.js"></script>
@}
dict_edit.html
@layout("/common/_container.html"){
<div class="ibox float-e-margins">
<div class="ibox-content">
<div class="form-horizontal">
<input type="hidden" id="id" value="">
<div class="row">
<div class="col-sm-12" id="itemsArea">
<input type="hidden" id="itemSize" value="${subDicts.~size!0}" />
<div class="form-group">
<label class="col-sm-2 control-label">类型编码</label>
<div class="col-sm-2">
<input class="form-control" id="dictCode" type="text" value="${dict.code}">
</div>
<label class="col-sm-2 control-label">类型名称</label>
<div class="col-sm-2">
<input class="form-control" id="dictName" type="text" value="${dict.name}">
<input type="hidden" id="dictId" value="${dict.id}">
</div>
<label class="col-sm-2 control-label">类型序号</label>
<div class="col-sm-2">
<input class="form-control" id="dictNum" type="text" value="${dict.num}">
</div>
<div class="col-sm-2">
<#button btnCss="info" name="增加" icon="fa-plus" clickFun="DictInfoDlg.addItem()"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">备注</label>
<div class="col-sm-8">
<input class="form-control" id="dictTips" type="text" value="${dict.tips}">
</div>
</div>
<div class="hr-line-dashed"></div>
@for(item in subDicts){
<div class="form-group" name="dictItem" id="dictItem${itemLP.index}">
<label class="col-sm-1 control-label">值</label>
<div class="col-sm-2">
<input class="form-control" type="text" name="itemCode" value="${item.code}">
</div>
<label class="col-sm-1 control-label" >名称</label>
<div class="col-sm-2">
<input class="form-control" type="text" name="itemName" value="${item.name}">
</div>
<label class="col-sm-1 control-label" >序号</label>
<div class="col-sm-2">
<input class="form-control" type="text" name="itemNum" value="${item.num}">
</div>
<div class="col-sm-2">
<#button btnCss="danger" name="删除" id="cancel" icon="fa-remove" clickFun="DictInfoDlg.deleteItem(event)"/>
</div>
</div>
@}
</input>
</div>
<div class="row btn-group-m-t">
<div class="col-sm-10">
<#button btnCss="info" name="提交" id="ensure" icon="fa-check" clickFun="DictInfoDlg.editSubmit()"/>
<#button btnCss="danger" name="取消" id="cancel" icon="fa-eraser" clickFun="DictInfoDlg.close()"/>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/template" id="itemTemplate">
<div class="form-group" name="dictItem" id="dictItem">
<label class="col-sm-1 control-label">值</label>
<div class="col-sm-2">
<input class="form-control" type="text" name="itemCode">
</div>
<label class="col-sm-1 control-label" >名称</label>
<div class="col-sm-2">
<input class="form-control" type="text" name="itemName">
</div>
<label class="col-sm-1 control-label" >序号</label>
<div class="col-sm-2">
<input class="form-control" type="text" name="itemNum">
</div>
<div class="col-sm-2">
<#button btnCss="danger" name="删除" id="cancel" icon="fa-remove" clickFun="DictInfoDlg.deleteItem(event)"/>
</div>
</div>
</script>
<script src="${ctxPath}/static/modular/system/dict/dict_info.js"></script>
@}
好了,前端页面都改好了,下面开始修改后端接口的代码
2、找到相应的后端接口并修改
上面那张图我们看到了添加字典的接口,按照需求一的方式去找也能找到对应代码的位置。但是其实Guns项目的代码结构层次很分明,我们可以直接去Controller层找代码。
要修改的就是这三个文件:
这三个方法都只贴需要修改的方法,便于查看:
DictController.java 两个接口(添加和修改),添加参数 dictNum:
/**
* 新增字典
*
* @param dictValues 格式例如 "1:启用;2:禁用;3:冻结"
*/
@BussinessLog(value = "添加字典记录", key = "dictName,dictValues", dict = DictMap.class)
@RequestMapping(value = "/add")
@Permission(Const.ADMIN_NAME)
@ResponseBody
public Object add(@RequestParam(required = false,defaultValue = "0",value = "dictNum")Integer dictNum,
String dictCode, String dictTips, String dictName, String dictValues) {
if (ToolUtil.isOneEmpty(dictCode, dictValues,dictName)) {
throw new ServiceException(BizExceptionEnum.REQUEST_NULL);
}
this.dictService.addDict(dictCode, dictName, dictTips, dictValues,dictNum);
return SUCCESS_TIP;
}
/**
* 修改字典
*/
@BussinessLog(value = "修改字典", key = "dictName,dictValues", dict = DictMap.class)
@RequestMapping(value = "/update")
@Permission(Const.ADMIN_NAME)
@ResponseBody
public Object update(@RequestParam(required = false,defaultValue = "0",value = "dictNum")Integer dictNum,
Integer dictId, String dictCode, String dictName, String dictTips, String dictValues) {
if (ToolUtil.isOneEmpty(dictId, dictCode, dictName, dictValues)) {
throw new ServiceException(BizExceptionEnum.REQUEST_NULL);
}
dictService.editDict(dictId, dictCode, dictName, dictTips, dictValues,dictNum);
return SUCCESS_TIP;
}
IDictService.java 两个方法也要新增参数 dictNum:
/**
* 添加字典
*/
void addDict(String dictCode, String dictName, String dictTips, String dictValues, Integer dictNum);
/**
* 编辑字典
*/
void editDict(Integer dictId, String dictCode, String dictName, String dictTips, String dicts, Integer dictNum);
DictServiceImpl.java 实现方法也要新增参数dictNum:
@Override
@Transactional
public void addDict(String dictCode, String dictName, String dictTips, String dictValues, Integer dictNum) {
//判断有没有该字典
List<Dict> dicts = dictMapper.selectList(new EntityWrapper<Dict>().eq("code", dictCode).and().eq("pid", 0));
if (dicts != null && dicts.size() > 0) {
throw new ServiceException(BizExceptionEnum.DICT_EXISTED);
}
//解析dictValues
List<Map<String, String>> items = parseKeyValue(dictValues);
//添加字典
Dict dict = new Dict();
dict.setName(dictName);
dict.setCode(dictCode);
dict.setTips(dictTips);
dict.setNum(dictNum);//此处传入设置的num
dict.setPid(0);
this.dictMapper.insert(dict);
//添加字典条目
for (Map<String, String> item : items) {
String code = item.get(MUTI_STR_CODE);
String name = item.get(MUTI_STR_NAME);
String num = item.get(MUTI_STR_NUM);
Dict itemDict = new Dict();
itemDict.setPid(dict.getId());
itemDict.setCode(code);
itemDict.setName(name);
try {
itemDict.setNum(Integer.valueOf(num));
} catch (NumberFormatException e) {
throw new ServiceException(BizExceptionEnum.DICT_MUST_BE_NUMBER);
}
this.dictMapper.insert(itemDict);
}
}
@Override
@Transactional
public void editDict(Integer dictId, String dictCode, String dictName, String dictTips, String dicts,Integer dictNum) {
//删除之前的字典
this.delteDict(dictId);
//重新添加新的字典
this.addDict(dictCode, dictName, dictTips, dicts, dictNum);
}
@Override
public List<Map<String, Object>> list(String conditiion) {
//###魔改点
// return baseMapper.list(conditiion);
Wrapper<Dict> wrapper = new EntityWrapper<>();
if(StringUtils.isNoneBlank(conditiion)){
wrapper.like("name",conditiion.trim());
}
//此处添加按num字段顺序排序
wrapper.eq("pid",0).orderBy("num",true);
return dictMapper.selectMaps(wrapper);
}
我们重启项目后,测试一下,先测试添加:
然后测试修改:
可以看到,修改成功了
通过以上两个需求的实现,我们对Guns已经不是那么陌生了吧。
该系列更多文章请前往 Guns二次开发目录