踩坑记录_八月篇_2

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 &lt; #{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>
            &nbsp;
            <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>

猜你喜欢

转载自blog.csdn.net/Nerver_77/article/details/82380900