近期完成了layui模版下的监管后台的部分功能,整理回顾一下其中遇到的部分问题和解决的办法:
1."视频监控"功能
说明:是对数据库中主播的视频的管理搜索
效果图:
ftl页面代码:
<link rel="stylesheet" href="../../static/layui/css/layui.css"> <div class="demoTable"> 搜索主播FID: <div class="layui-inline"> <input class="layui-input" name="id" id="FIDReload" autocomplete="off"> </div> <button class="layui-btn" data-type="reload">搜索</button> </div> <table class="layui-hide" id="MessageVideo" lay-filter="user"></table> <script src="../../static/layui/layui.js"></script> <script src="//code.jquery.com/jquery-2.1.1.min.js"></script> <script> layui.use('table', function () { var table = layui.table; //第一个实例 table.render({ elem: '#MessageVideo' , url: '/Message/MessageVideoPage' //数据接口 , page: true //开启分页 ,initSort: { field: 'createTime' //排序字段,对应 cols 设定的各字段名 ,type: 'desc' //排序方式 asc: 升序、desc: 降序、null: 默认排序 } , cols: [[ //表头 {field: 'fid', title: '主播FID', width: 90, sort: true, fixed: 'left'} , {field: 'chatId', title: '主播云信账号', width: 200} , {field: 'createTime', title: '时间', width: 200,sort: true} , {field: 'url', title: '播放地址', width: 600} ]] , id: 'message' }); var $ = layui.$, active = { reload: function(){ var FIDReload = $('#FIDReload'); //执行重载 table.reload('message', { page: { curr: 1 //重新从第 1 页开始 } ,where: { fid: FIDReload.val() } }); } }; $('.demoTable .layui-btn').on('click', function(){ var type = $(this).data('type'); active[type] ? active[type].call(this) : ''; }); }); </script>
在完成搜索主播FID的时候因为点击搜索完成页面重载这个代码是参考layui母版去码的,码完之后发现并没有产生重载的效果也发生了报错,检查后发现
还有一点:在layui模版中是where:{key:{需要传输的参数}},这样在后台接收的其实是一个key[fid],而不是直接的fid,在网上查询的解决办法中,大部分的博主建议去掉key,直接写参数,我也是这么去做的.
后台controller层接收前端参数后传递给service层
service层代码:
/** * @Author: Lukizzz * @Date: 2018/8/2 15:21 * @Description: */ @Service public class MessageVideoFileService { @Autowired private MessageVideoFileDAO messageVideoFileDAO; public ResultDTO videoMessagePage(String fid,Integer page,Integer limit){ Page<MessageVideofile> data; PageRequest pageRequest = PageRequest.of(page-1,limit); if(fid==null){ data = messageVideoFileDAO.findAll(pageRequest); }else { data = messageVideoFileDAO.findAllByFid(fid,pageRequest); } return ResultDTO.builder().withData(data.getContent()).withCount((int) data.getTotalElements()); } }
刚开始做的时候我用了List而不是Page,但List有一个问题就是一旦数据量变大,一直都是列表的形式没有分页的话看起来的感官很差而且很容易产生混乱和错误,所有后来用Page分页.
在完成这个视频监控功能期间,多次出现空指针异常的报错,通过Debugger调试,打断点然后一层层往下执行查看哪个参数没有得到数据或者在哪块的代码中出现了问题,再有针对性的解决,这让我发现了测试和调试的重要性,在接下来的开发中要开始熟练地运用这些办法.
在创建类名的时候也要注意,实体类名要和数据库中的表名一致,然后通过yml里的配置信息连接数据库,不然无法检索到该数据表
2.主播违规投诉功能
说明:通过对主播uid或者违规时间的输入搜索符合条件的数据
效果图:
附上ftl页面代码:
<link rel="stylesheet" href="../../static/layui/css/layui.css"> <div class="layui-btn-group"> <button class="layui-btn" id="addbtn" data-type="add" onclick="complain();">投诉</button> </div> <div class="demoTable"> 主播UID: <div class="layui-inline"> <input class="layui-input" name="uid" id="uidReload" autocomplete="off"> </div> 违规时间: <div class="layui-inline"> <input class="layui-input" name="date" id="dateReload" autocomplete="off" placeholder="yyyy-MM-dd" type="text"> </div> <button class="layui-btn" data-type="reload">搜索</button> </div> <table id="complainTb" lay-filter="test" lay-data="{initSort: {field:'createTime', type:'desc'}, height: 'full-200'}"></table> <script src="../../static/layui/layui.js"></script> <script src="//code.jquery.com/jquery-2.1.1.min.js"></script> <script> var lock = true; layui.use('laydate', function(){ var laydate = layui.laydate; //执行一个laydate实例 laydate.render({ elem: '#dateReload', //指定元素 value: getNowFormatDate() }); }); var imagesUrl = ""; layui.use('table', function () { var table = layui.table; //第一个实例 table.render({ elem: '#complainTb' , url: '/complain/complainAnchorList' //数据接口 , page: true //开启分页 ,where:{ date:getNowFormatDate() } , initSort: { field: 'offenceTime' //排序字段,对应 cols 设定的各字段名 , type: 'desc' //排序方式 asc: 升序、desc: 降序、null: 默认排序 } , cols: [[ //表头 {field: 'uid', title: '主播UID', width: 90, fixed: 'left'} , {field: 'fid', title: '用户FID', width: 120} , {field: 'offenceTime', title: '违规时间', width: 180, sort: true} , {field: 'offenceContent', title: '违规内容', width: 120} , {field: 'offenceTag', title: '标签', width: 150} , {field: 'feibiAmount', title: '主播当前钻石', width: 120} , {field: 'anchorChange', title: '处罚钻石数', width: 120} , {field: 'starAmount', title: '星星数', width: 120} , {field: 'offenceAmount', title: '违规次数', width: 120, sort: true} , {field: 'operator', title: '操作员', width: 80} , {field: 'ipAddress', title: 'IP', width: 120} ]] , id: 'complainTb' }); var $ = layui.$, active = { reload: function(){console.log("00"); var uidReload = $('#uidReload'); var dateReload = $('#dateReload'); //执行重载 table.reload('complainTb', { page: { curr: 1 //重新从第 1 页开始 } ,where: { uid: uidReload.val(), date:dateReload.val() } }); } }; $('.demoTable .layui-btn').on('click', function(){ var type = $(this).data('type'); active[type] ? active[type].call(this) : ''; }); layui.use('form', function () { var form = layui.form; //监听提交 form.on('submit(anchorComplain)', function (f) { if (!lock){ return false; } lock = false; var fields = $(f.form).serialize(); var jhxhr = $.ajax({ "url": f.form.action, "data": fields, "type": "POST" }); jhxhr.done(function (re) { console.log(re); if (re.code == 0) { layer.closeAll(); //配置一个透明的询问框 layer.msg('投诉成功', { time: 1000, //2s后自动关闭 btn: ['知道了'] }); table.reload('complainTb', {}); setTimeout(function(){lock = true;},1000); } else { layer.msg(re.msg + '<br>请思考O(∩_∩)O', { time: -1, //20s后自动关闭 btn: ['知道了'] }); } }); return false; }); layui.use('laydate', function() { var laydate = layui.laydate; laydate.render({ elem: '#test5' ,type: 'datetime' }); }); }); }); function getNowFormatDate() { var date = new Date(); var seperator1 = "-"; var year = date.getFullYear(); var month = date.getMonth() + 1; var strDate = date.getDate(); if (month >= 1 && month <= 9) { month = "0" + month; } if (strDate >= 0 && strDate <= 9) { strDate = "0" + strDate; } var currentdate = year + seperator1 + month + seperator1 + strDate; return currentdate; } layui.use('upload', function () { var $ = layui.jquery , upload = layui.upload; //多图片上传 upload.render({ elem: '#images' , url: '/complain/uploadImages' , acceptMime: 'image/*' , multiple: true , before: function (obj) { //预读本地文件示例,不支持ie8 obj.preview(function (index, file, result) { $('#demo2').append('<img height="100px" width="100px" src="' + result + '" alt="' + file.name + '" class="layui-upload-img">') }); } , done: function (res) { console.log(res); imagesUrl += (res.data + ";"); } , accept: 'images' }); }); </script> <script> function complain() { //示范一个公告层 var $ = layui.$; var content = $("#complainDIV"); var index = layer.open({ type: 1 , title: false //不显示标题栏 , closeBtn: true , area: ['800px', '600px'] , shade: 0.8 , id: 'LAY_layuipro' //设定一个id,防止重复弹出 , btnAlign: 'c' , shadeClose: true , moveType: 1 //拖拽模式,0或者1 , content: content , success: function (layero) { } }); } </script> <div class="layui-field-box" id="complainDIV" style="display: none;padding: 10px"> <form id="fm" class="layui-form" action="/complain/anchorComplain" method="post"> <#--action="/user/addChannelUser" method="post"--> <div class="layui-form-item"> <div class="layui-inline"> <label class="layui-form-label">主播UID</label> <div class="layui-input-inline"> <input type="text" id="uid" name="uid" lay-verify="required" autocomplete="off" class="layui-input"> </div> </div> <div class="layui-inline"> <label class="layui-form-label">用户FID</label> <div class="layui-input-inline"> <input type="text" id="fid" name="fid" lay-verify="required" autocomplete="off" class="layui-input"> </div> </div> <div class="layui-inline"> <label class="layui-form-label">违规内容</label> <div class="layui-input-inline"> <input type="text" name="offenceContent" lay-verify="required" autocomplete="off" class="layui-input"> </div> </div> <div class="layui-inline"> <label class="layui-form-label">标签</label> <div class="layui-input-inline"> <input type="text" name="offenceTag" lay-verify="required" autocomplete="off" class="layui-input"> </div> </div> <div class="layui-inline"> <label class="layui-form-label">星星数</label> <div class="layui-input-inline"> <input type="text" name="starAmount" lay-verify="required|number" autocomplete="off" class="layui-input"> </div> </div> <div class="layui-inline"> <label class="layui-form-label">违规次数</label> <div class="layui-input-inline"> <input type="text" name="offenceAmount" lay-verify="required|number" autocomplete="off" class="layui-input"> </div> </div> <div class="layui-inline"> <label class="layui-form-label">违规日期</label> <div class="layui-input-inline"> <input type="text" name="offenceTime" class="layui-input" lay-verify="required" id="test5" placeholder="yyyy-MM-dd HH:mm:ss"> </div> </div> <div class="layui-inline"> <label class="layui-form-label">惩罚钻石数</label> <div class="layui-input-inline"> <input type="text" name="anchorChange" lay-verify="required|number" autocomplete="off" class="layui-input"> </div> </div> </div> <div class="layui-form-item"> <div class="layui-input-block"> <button class="layui-btn" lay-submit lay-filter="anchorComplain" >保存 </button> <button type="reset" class="layui-btn layui-btn-primary">重置</button> </div> </div> </form> </div>
其他操作都是一样,只是在传参的时候需要传递两个参数
通过 getNowFormatDate(),设置默认的当前时间,让输入框不为空
ComplainService:
public ResultDTO getAnchorList(Integer page,Integer limit,Integer uid,String date){ Page<ComplainAnchorRecord> pageData; PageRequest pageRequest = PageRequest.of(page-1,limit); if (uid==null){ pageData = complainAnchorRecordDAO.findAllByOffenceTimeBetween(DateUtil.getDate(date),DateUtil.getLastDate(date),pageRequest); }else { pageData = complainAnchorRecordDAO.findAllByUidAndOffenceTimeBetween(uid,DateUtil.getDate(date),DateUtil.getLastDate(date),pageRequest); } return ResultDTO.builder().withData(pageData.getContent()).withCount((int) pageData.getTotalElements()); }
一开始我写的是这样:
但是运行之后显示数据接口异常,并报了空指针异常的错误,通过调试发现在第二个else if中应该写成offenceTime!=null,但如果写成这样运行的话,搜索框中如果没有任何输入的情况下点击搜索,出来的一条数据都没有,通过Debugger调试发现是因为在没设置搜索条件的情况下在最后一个else if的判断中执行了return语句而没有判断执行到最后一个return.当时到底怎么把格式统一难住了我,直到请教大佬,大佬告诉我可以设置一个默认的当前时间在输入框中,这样只需要判断uid就可以了,于是我按照他给的模版做了DateUtil.
DateUtil代码:
package com.yz.vipcz.util; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Date; /** * @Author zq * @Date 2018/8/3 15:02 */ public class DateUtil { public static String getDate(String dateStr){ LocalDate localDate = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")); ZoneId zoneId = ZoneId.systemDefault(); ZonedDateTime zdt = localDate.atStartOfDay(zoneId); Date date = Date.from(zdt.toInstant()); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); return simpleDateFormat.format(date); } public static String getLastDate(String dateStr){ LocalDate localDate = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")); localDate = localDate.plusDays(1); ZoneId zoneId = ZoneId.systemDefault(); ZonedDateTime zdt = localDate.atStartOfDay(zoneId); Date date = Date.from(zdt.toInstant()); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); return simpleDateFormat.format(date); } }
声明了两个方法:getDate()和getLastDate(),因为我查询的这个数据表中将offenceTime设置成了varchar,因此,这里的时间也要转换成字符串格式
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); return simpleDateFormat.format(date);
上文中service层通过DateUtil获取当前时间和最后时间,在通过dao查询数据库中改时间范围内的数据
DAO层代码:
@Repository public interface ComplainAnchorRecordDAO extends JpaRepository<ComplainAnchorRecord,Integer> { Page<ComplainAnchorRecord>findAllByOffenceTimeBetween(String startDate, String endDate, Pageable pageable); Page<ComplainAnchorRecord>findAllByUidAndOffenceTimeBetween(Integer uid, String startDate, String endDate, Pageable pageable); }
3.修改名字
说明:修改类名,接口名,包名和config
在修改的时候要注意红色框内的勾选,会修改相同名字的字符串之类的,导致有些前端表单提交和后端接收参数的地址被改掉,参数无法传输