2018-8-20 星期一
1.交易管理:产品信息查询的动态SQL实现。注意:在XML元素中,”<” 和 “&” 是非法的。
<select id="getProductInfoList" resultType="com.quant.qdvp.common.persistence.model.ProductInfo">
select <include refid="Base_Column_List"/> from ProductInfo
<where>
<if test="condition != null and condition != ''">
ProductID like CONCAT('%',#{condition},'%') or ProductNameSTD like CONCAT('%',#{condition},'%')
</if>
<if test="beginTime != null and beginTime != ''">
and StartDate >= #{beginTime}
</if>
<if test="endTime != null and endTime != ''">
and EndDate < #{endTime}
</if>
</where>
</select>
2.字典管理:产品信息状态字段整合字典管理。
1. 这里采用了自定义的warpper:DealCustomWrapper
/**
* description: 自定义产品信息包装类
* author:jiangyanfei
* date:2018/8/20
* time:10:43
*/
@Component
@DependsOn("springContextHolder")
public class DealCustomWrapper {
private List<ProductInfo> list;
private DictMapper dictMapper = SpringContextHolder.getBean(DictMapper.class);
public DealCustomWrapper(List<ProductInfo> list) {
this.list = list;
}
public DealCustomWrapper() {
}
/**
* @Author jiangyanfei
* @Description 自定义包装类
* @Date 2018/8/20
* @Param [dictName, val]
* @return java.lang.Object
**/
public List<ProductInfo> warpObject(String dictName){
Dict temp = new Dict();
temp.setName(dictName);
Dict dict = dictMapper.selectOne(temp);
if (null == dict) {
return null;
} else {
EntityWrapper entityWrapper = new EntityWrapper();
//字典下的子结构依赖父模块的Id
entityWrapper.where("pid", dict.getId());
List<Dict> dictList = dictMapper.selectList(entityWrapper);
for (ProductInfo productInfo : this.list) {
for (Dict item : dictList) {
if (item.getNum() == productInfo.getStatus()) {
productInfo.setStatus_c(item.getName());
}
}
}
}
return list;
}
}
2. controller:return new DealCustomWrapper(resultList).warpObject("产品信息状态");
3.搜索条件重置:重置按钮事件。
坐标:deal.js
/*
* 清空搜索条件
* */
Deal.resetSearch = function () {
$("#condition").val("");
$("#beginTime").val("");
$("#endTime").val("");
Deal.search();
}
4.产品信息ID检查:针对产品信息中的ProductID字段进行是否为数字的检查。
坐标:deal_info.js
/*
* 验证产品编号是否为数字
* */
DealInfoDlg.checkProductID = function () {
var productId = $('#productID').val();
var regPos = /^\d+(\.\d+)?$/; //非负浮点数
var regNeg = /^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/; //负浮点数
if(regPos.test(productId) || regNeg.test(productId)){
return true;
}else{
return false;
}
}
添加、修改提交时加入检查逻辑:
if (!this.checkProductID()) {
Feng.error("请输入有效的产品编号");
return;
}
2018-8-21 星期二
1.@Lazy、@DependOn
@Lazy:延迟初始化 -- 懒加载,项目启动时不初始化,使用时才进行初始化
@DependOn:控制bean的加载顺序,被标注的类的初始化依赖另一个类的初始化。即:另一个类初始化后,该类才会初始化。
当我们想指定某个bean进行初始化时,可以这样:
@DependsOn("springContextHolder") 直接加载spring容器
在下文中指定bean的初始化:private DictMapper dictMapper = SpringContextHolder.getBean(DictMapper.class);
2.ReservedWordsHandle:针对SqlServer数据库构建的保留字处理工具类。
/**
* description: SQL保留字自定义处理类
* author:jiangyanfei
* date:2018/8/21
* time:16:51
*/
public class ReservedWordsHandle{
/**
* @Author jiangyanfei
* @Description 自定义需要处理的SQL关键字
* @Date 2018/8/21
* @Param
* @return
**/
public static void removeReservedWords(){
List<String> reservedWordsList = new ArrayList<String>(
Arrays.asList("STATUS","POSITION")
);
SqlReservedWords.RESERVED_WORDS.removeAll(reservedWordsList);
}
}
2018-8-23 星期三
**1.Ant通配符:**URL映射
Ant路径表达式:Ant用符号"*"来表示匹配任意字符,用"**"来表示匹配任意路径,用"?"来匹配单个字符。
比如:
/user/*.html,匹配/use/1.html 、/user/2.html等。
/**/l.html,匹配/1.htm l ,也匹配/user/1.html,还匹配/user/add/1.html。
/user/?.html时,匹配/user/l.html,但不匹配/user/11.html。
如果一个请求有多个@RequestMapping能够匹配,通常是更具体的匹配会作为处理此请求的方法。
有通配符的低于没有通配符的,如:/user/add.json比/user/*.json优先匹配。
有"**"通配符的低于有"*"通配符的。
2.DIP平台模块重构
目录结构第二版:
0 通知
1 信息管理
2 交易管理
3 策略管理
4 产品管理
5 市场管理
6 --
7 --
8 通知管理
9 系统管理
10 日志管理
3.信息管理模块构建:之前的productInfo进行迁移重构
2018-8-24 星期五
1.模块完善:根据需求文档,对模块进行完善。
2.通知管理分层:即时通知 + 展示通知
即时通知:用户会通过单独的"即时通知"按钮,对即时通知进行编辑。
编辑完成后,会弹出通知人列表,勾选需要被通知的用户点击发送按钮即可。
功能实现步骤:
1. 坐标:notice.html 添加即时通知按钮,添加点击事件,设定权限。
@if(shiro.hasPermission("/notice/quickNotice")){
<#button name="即时通知" icon="fa-comment" clickFun="Notice.quickNotice()" space="true"/>
@}
2. 坐标:notice.js点击事件。
/**
* 即时通知
*/
Notice.quickNotice = function () {
var index = layer.open({
type: 2,
title: '添加通知',
area: ['800px', '450px'], //宽高
fix: false, //不固定
maxmin: true,
content: Feng.ctxPath + '/notice/notice_quickNotice_add'
});
this.layerIndex = index;
};
3. 坐标:NoticeController.java
/**
* 跳转到添加即时通知
*/
@RequestMapping("/notice_quickNotice_add")
public String quickNoticeAdd() {
return PREFIX + "notice_quickNotice_add.html";
}
4. 坐标:notice_quickNotice_add.html 类比 notice_add.html
这里就是提交按钮进行更改:
<#button btnCss="info" name="提交" id="ensureQuick" icon="fa-check" clickFun="NoticeInfoDlg.addQuickNoticeSubmit()"/>
5. 坐标:notice_info.js
/**
* 添加即时通知
*/
NoticeInfoDlg.addQuickNoticeSubmit = function (e,value,row,index) {
this.clearData();
this.collectData();
if (!this.validate()) {
return;
}
//提交信息
var ajax = new $ax(Feng.ctxPath + "/notice/quickNotice", function (data) {
// Feng.success("添加成功!");
window.parent.Notice.table.refresh();
NoticeInfoDlg.close();
}, function (data) {
// Feng.error("添加失败!" + data.responseJSON.message + "!");
});
ajax.set(this.noticeInfoData);
ajax.start();
NoticeInfoDlg.seItem = row;
var index = layer.open({
type: 2,
title: '通知人列表',
area: ['300px', '400px'], //宽高
fix: false, //不固定
maxmin: true,
content: Feng.ctxPath + '/notice/quickNoticeSend'
});
NoticeInfoDlg.layerIndex = index;
}
6. 坐标:NoticeController.java
/**
* @Author jiangyanfei
* @Description 获取即时通知标题、内容
* @Date 2018/8/24
* @Param
* @return
**/
@RequestMapping(value = "/quickNotice")
public void quickNotice(@RequestParam(value = "content", required = false) String content, @RequestParam(value = "title", required = false) String title){
TITLE = title;
CONTENT = content;
}
/*
* @Author jiangyanfei
* @Description 即时通知发送
* @Date 2018/8/24
* @Param
* @return
**/
@RequestMapping(value = "/quickNoticeSend")
@BussinessLog(value = "即时通知",key = "title",dict = Dict.NoticeMap)
public String quickNoticeSend(Model model){
model.addAttribute("noticeTitle",TITLE);
return PREFIX + "notice_assign.html";
}
7. 坐标:notice_assign.html
<script type="text/javascript">
$(function () {
var index = parent.layer.getFrameIndex(window.name); //获取窗口索引
$("#btn_close").bind("click", function () {
parent.layer.close(index);
});
$("#btn_save").bind("click", function () {
//取出ZTree中选中的部门信息 + 用户信息
var ids = Feng.zTreeCheckedNodes("zTree");
var names = Feng.zTreeCheckNodesValues("zTree");
var ajax = new $ax(Feng.ctxPath + "/notice/sendNotices", function (data) {
Feng.success("通知发送成功!");
window.parent.Notice.table.refresh();
parent.layer.close(index);
}, function (data) {
Feng.error("通知发送失败!"
+ data.responseJSON.message + "!");
});
ajax.set("ids", ids);
ajax.set("names",names);
ajax.start();
});
initZtree();
});
function initZtree() {
var setting = {
check: {
enable: true,
chkboxType: { "Y": "ps", "N": "ps" }
},
data: {
simpleData: {
enable: true
}
}
};
var ztree = new $ZTree("zTree", "/notice/noticeReciversList");
ztree.setSettings(setting);
ztree.init();
function onNodeClick(e,pid,treeNode,s,d){
var ztree = $.fn.zTree.getZTreeObj("zTree")
ztree.expandNode(treeNode)
}
}
</script>
<!-- 配置grid -->
<div class="container" style="padding: 0px 10px !important;margin-top: -10px;text-align: center !important;">
<div class="row">
<div class="ibox float-e-margins" id="noticeAssign">
<div class="ibox-title">
<h5>${noticeTitle}</h5>
</div>
<div class="ibox-content">
<ul id="zTree" class="ztree"></ul>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<button class="btn btn-sm btn-info" type="button" id="btn_save">
<i class="ace-icon fa fa-check bigger-110"></i>发送
</button>
<button class="btn btn-sm btn-danger" type="button" id="btn_close">
<i class="ace-icon fa fa-close bigger-110"></i>取消
</button>
</div>
</div>
</div>
7. 坐标:NoticeController.java
/**
* 发送通知给微信端用户
*/
@RequestMapping("/sendNotices")
@BussinessLog(value = "发送通知给微信端", key = "noticeId,ids", dict = Dict.NoticeMap)
@Permission(Const.ADMIN_NAME)
@ResponseBody
public Tip sendNotices(@RequestParam("ids")String ids, @Param("names") String names) {
//对ZTree中获得id进行分类,区分开部门id和用户id
String [] idsTemp = ids.split(",");
String [] namesTemp = names.split(",");
StringBuffer tempStr = new StringBuffer();
for (int i = 0; i < idsTemp.length; i++ ) {
if (idsTemp[i].indexOf('d') == -1) {
tempStr.append(namesTemp[i]+",");
}
}
boolean result = this.noticeService.sendNoticeToReceiversByName(tempStr.toString(),CONTENT);
if (result)
return SUCCESS_TIP;
else
return new ErrorTip(404,"发送失败!");
}
/**
* 获取通知人的列表
* @return
*/
@RequestMapping(value = "/noticeReciversList")
@ResponseBody
public List<ZTreeNode> noticeReciversList(){
List<ZTreeNode> userTreeList = this.userMgrDao.receiverTreeList();
return userTreeList;
}
8. 坐标:NoticeServiceImpl.java
@Override
public boolean sendNoticeToReceiversByName(String receiverNames, String content) {
try {
receiverNames = PingYinUtil.getAllPinYinStr(receiverNames, PingYinUtil.Type.LOWERCASE);
} catch (BadHanyuPinyinOutputFormatCombination e) {
throw new RuntimeException("汉字转换拼音失败");
}
//发送消息给用户的企业微信
String[] nameArray = receiverNames.split(",");
int status = 200;
for (int i = 0; i < nameArray.length; i++) {
Map<String, Object> map = new HashMap<>();
map.put("msg", "通知内容:" + content + "\n" + "发送人:" + ShiroKit.getUser().getName());
//设置topic对应用户组,nameArray[i] -- 测试用
map.put("topic", "jiangyanfei");
status = HttpKit.sendPostJson("http://192.168.1.11:5555/send", map);
if (status != 200) {
break;
}
}
if (status == 200){
return true;
}
return false;
}
9. 发送http后即可在微信服务中受到发送的信息
3.首页模板变更
问题:mysql数据库中datetime类型的时间取出来展示会多出.0
在MySQL数据库中datatime精度要高于date,取出后会精确到毫秒,解决的入口有三个:
1: sql查询的时候,date字段转型、格式化
2: 查询出的bean里的getDate方法里做格式化
3: 页面渲染的时候格式化
这里采用了第一种解决方案,目的是降低运行时的业务操作,对SQL语句进行优化。
<!-- 通用查询结果列 解决datetime类型数据显示.0的问题,SQL语句中进行了格式化-->
<sql id="Base_Column_List">
id, title, type, content, DATE_FORMAT(createtime, '%Y-%m-%d %k:%i:%s') as createtime, creater, DATE_FORMAT(updatetime, '%Y-%m-%d %k:%i:%s')
as updatetime
</sql>
<select id="list" resultType="map">
select <include refid="Base_Column_List"/> from notice
<if test="condition != null and condition != ''">
where title like CONCAT('%',#{condition},'%') or content like CONCAT('%',#{condition},'%')
</if>
order by createtime DESC
</select>