项目场景:
这次的业务场景是以前的同事写的"假代码",业务接口就没有实现,没实现也就算了,还搞一条假数据,好像实现了一样。这都是欠的业务债啊。
最近,公司也是各种狗血啊。什么加班的调休有效期是一个月,然后,如果调休了就没有项目奖金;然后上班时间调整,中午你猜有多长时间吃饭休息?12:45-13:30,这是遇到的最短的中场休息了,扎扎实实日工作时间是8个小时啊,其实很多公司实际上都只7.5个小时。。。
问题描述
用户一直看到这个假消息。。。。
接口跟踪看源码,原来是这么玩的。。。。
原因分析:
还有啥好分析的啊,就是没有实现呗。
产品重新设计,这块要显示工单信息、APP通知。APP通知的还好说就一个入口,工单这块有几类,而且工单节点处理了,这边也是要有新的信息的(节点处理了产生新的信息,产品没有提,我想应该是需要的,也不想后面再调,所以一次性想到了要设计)。
工单这块的入口、节点处理、那可是太多地方了,我可不想一个个找入口,况且,现在已经是交付期,大改危险,而且前期的工单也非我处理设计,那要找费劲啊。
最后想到了一个主动拉取自己的工单到消息模块的方案,感觉还不错就分享给大家。
这里分享给大家的其实是想让大家感受下逆向思维。既然入口不好处理,那我们就在出口做处理,一样也是可行的。
解决方案:
1、先看流程图:
2、思路说明:
其实就是逆向处理,既然在工单的多个入口处不好增加消息信息,那么在用户点击消息模块的出口这里人为的先去查询自己提的工单数据,经过转换处理后入库,然后再做查询自己的工单的消息。这里要注意的:
A、判断页码,只在第一页才去同步工单转换(另外一个原因是每页都同步会影响分页数据)
B、已存在的就注意判断更新时间字段比我这条信息的阅读时间是否晚,如果晚,那肯定是要更新读取状态为未读的(正向的入口逻辑是工单处理了需要产生一条消息记录的)
C、要注意数据量、注意不要太影响查询数据的接口速度
3、看核心代码
@Override
public Result<?> pullAndQueryList(Map<String, String> param) {
//参数校验
Result<?> res = SuggestionUtil.checkPullAndQueryParam(param);
if (res != null){
return res;
}
//参数拆解
Integer userId = Integer.parseInt(param.get("userId"));
Integer subjectId = Integer.parseInt(param.get("subjectId"));
Integer page = Integer.parseInt(param.get("page"));
Integer size = Integer.parseInt(param.get("size"));
//查询用户信息
UserInfo userInfo = userInfoMapper.selectByPrimaryKey(userId);
if (userInfo == null){
return ResultGenerator.genFailResult(ResponseCodeI18n.USER_NOT_EXIST.getMsg());
}
if (page.intValue() == 1){
//pull工单数据
pullWorkOrderInfo(userInfo,subjectId);
}
//查询数据
PageHelper.startPage(page,size);
List<SuggestionInfoDto> ls = suggestionInfoMapper.querySuggestionDtoList(param);
PageInfo<SuggestionInfoDto> pageInfo = new PageInfo<>(ls);
return ResultGenerator.genSuccessResult(pageInfo);
}
/**
* 拉取用户最新的工单信息
* @param userInfo 用户信息
* @param subjectId 项目id
*/
private void pullWorkOrderInfo(UserInfo userInfo, Integer subjectId) {
//suggestioninfo基础信息
SuggestionInfo si = new SuggestionInfo();
si.setIsDeleted(BusinessConstant.NO_DELETE);
si.setSubjectId(subjectId);
si.setOrgId(userInfo.getOrgId());
//组织pull工单信息参数
WorkOrderInfo woRecord = new WorkOrderInfo();
//前端创建的来源=99
woRecord.setCreateSource(99);
//前端创建的workType=1
woRecord.setWorkType(1);
woRecord.setIsDeleted(BusinessConstant.NO_DELETE);
woRecord.setOrgId(userInfo.getOrgId());
woRecord.setSubjectId(subjectId);
woRecord.setCreateBy(userInfo.getId());
woRecord.setCreateTime(null);
List<WorkOrderInfo> odList = workOrderInfoMapper.select(woRecord);
if (CollectionUtil.isNotEmpty(odList)){
odList.stream().forEach(d->{
//转换为suggestioninfo信息
SuggestionInfo tmp = new SuggestionInfo();
BeanUtil.copyProperties(si,tmp,CopyOptions.create().setIgnoreNullValue(Boolean.TRUE));
tmp.setMsgId(d.getId());
tmp.setMsgType(1);
//先查询是否存在
List<SuggestionInfo> sgLs = suggestionInfoMapper.select(tmp);
if (CollectionUtil.isEmpty(sgLs)){
tmp.setDescription(d.getWorkTitle());
tmp.setContent(d.getWorkContent());
tmp.setIsRead(0);
tmp.setMobile(userInfo.getMobile());
tmp.setCreateTime(d.getCreateTime());
tmp.setUpdateTime(si.getCreateTime());
tmp.setUserId(userInfo.getId());
suggestionInfoMapper.insert(tmp);
}else {
SuggestionInfo sg = sgLs.get(0);
Integer re = sg.getIsRead();
if (re.intValue() == 1){
//已读需要根据更新时间判定
Date sgReadTime = sg.getReadTime();
Date odUpTime = d.getUpdateTime();
if (sgReadTime != null && odUpTime.after(sgReadTime)){
sg.setIsRead(0);
}
sg.setUpdateTime(d.getUpdateTime());
suggestionInfoMapper.updateByPrimaryKeySelective(sg);
}
}
});
}
}
总结:
1、逆向思维还是很有必要的
2、要注意数据量、处理好优化,否在会影响查询数据接口的性能
3、做之前一定一定要多想想设计,想多了,你就会事半功倍
4、code review很重要,要是之前就有这样的机制,这种问题其实应该不会发生,这里奇怪的是测试居然也过了。。。。
5、The debt owed by the team will always be repaid
好了,就写道这里,希望能开拓大家处理问题的思路。