最近连续一周多没有更新状态了,主要还是接近接近年底了,各种事情赶进度,需求,设计,开发,开会。。。,闲来就把这段时间开发实现的功能需要注意的点做一些归纳和总结,主要讲的是配置篇。
关于后台内部系统配置开发,其实也是属于业务开发的,业务开发离不开增删改查导入导出,本篇将归纳出一些原则上需要注意的内容和实现需要思考的点,希望自己以后开发的时候,能够多一点心,跳过这些坑,提高开发的效率。
原则上的问题
开发之前
需要反复看文档思考开发时相关联的内容,需要注意的点.最好能够列出整合出一些点,这个功能的实现,需要涉及到我们自己的系统提供接口,什么应用场景下,会需要这个接口,把所有的需要实现的接口整理出来以后,1可以适当的根据使用场景进一步整理,看能不能进一步减少一些不必要的接口实现,把两个接口整合在一起就可以了。
注意点:
系统内部的配置管理,需要先确定数据源,表结构,各个表之间的关联。
内部配置,需要展示和条件过滤时,需要外部的那些表的数据进行关联,这些最好在开发之前确定。
类、方法注释,一般是使用统一的公司内部规定,提前定义好,省的开发到一半,
部门内部突然改了,很麻烦。注释方面,一般类都需要注释,一般使用java开发时,controller层、service层接口类、mapper接口必备,service、mapper实现类就不再注释了。
4.是否打印异常、业务日志
原则上,按照公司规定,不过配置方面的基本就是普通的增删改查,一般不需要,而且如果是自己内部使用,更加不需要了。
5.事务方面
读事务以及写事务。根据执行的读事务,如果是单表,基本不需要,如果是业务涉及到两张表及以上,建议添加备注。写事务根据具体条件。
- 代码规约提交方面
这方面的话,我是建议开发完一个模块(未提测),在代码逻辑方面设计没问题了,在提交之前每次都需要使用阿里代码插件,以及pmd(有的公司有要求,自己定义的规范)进行扫描。开发的时候,因为可能频繁的改动,每次都去修改这些的话,可能还是会花不少时间的。
7.确认跟前端交互需要的一些入参,出参(配置方面,我们都是前后台自己开发的,搭建vue,全栈,所以在文档下开发,一些细节可以在测试的时候,再更改),必要的字段必须展示。
- VO定义
这个也是根据公司部门要求来就好,只是需要先确认好,不然后期修改,维护,代码可读性方面会有影响。比如请求进来接收vo,需要专门定义一个接收VO,查询时,map中的数据,根据是否有其他字段不同,阿里规约是建议使用Do,数据库操作对象。
9.用户登录、数据权限控制!!
这块建议写一个公众类,必须,用户需要验证登录权限,才能查询对应的某些数据权限比如(城市、门店、车型举例自己公司的),类似拦截器,验证是否登录,将具备的权限提前构造进去。基本的配置操作,看业务要求,一般都需要这些数据,不建议每个接口都去判断一次。
10.分页(继承共用类,降低代码侵入性)!!
分页方面,我们的处理是继承一个pageVO,包含currentPage、pageSize等,编写一个拦截器,使用特定的查询命名,在查询时能够降低代码的侵入性,只需要查询的vo,具有currentPage、pageSize这两个属性就可以了。实现是在mybatis运行时,每个查询都会进行分页处理,嵌入修改sql。对普通开发者来说,只需要实现sql语句,查询全部就可以了。
原先,使用的是mybatis pagehelper,构建一个pageInfo的,这样的做法,虽然很快,但是每个人还是需要写构建一次分页,太麻烦了。
- // TODO : 待办事件补充
开发的时候,可能某些数据没有条件获取,又需要进行设置,加入数据库,或者测试时需要先走大概流程,可以加一个 // todo 注释, 后续比较方便找到需要修改的地方
增删改查导出入
新增、修改(与导入)
关于配置信息的新增、修改(两个根据需要是否考虑事务)以及导入,其实是可以整合成一个接口进行关联的,我说的是业务方法,根据是否存在主键id,判断执行新增或者更新业务。
新增时,考虑是否加事务,后台需要根据条件判断是否已存在该记录,因为是配置,基本都需要保证唯一性,如果已经存在,一般是返回已经存在,抛异常,不存在则新增(业务方面也可能要求,存在就更新进去)。
修改时,考虑是否加事务,执行修改,考虑修改如果涉及到多表的情况处理,同步更新。
导入时,与新增不同的是,基本都是使用excel格式,导入,分为单表导入,多表导入,大致的流程都是如下(我们系统的处理):
1.前端方面,我是使用vue+elementUI,前端方面,会有有一篇专门的更新,这里不做细说,需要运行提交文件:
this.$refs.upload.submit() ,传入一个importBeanId: 'cityModelRadiusExcelServiceImpl'
这个id是对应的业务层的springbeanid
2.后台会抽离出一些公用的excel验证方法(导出格式化,导入时数据验证,excel编码格式转化,导出数据组装,基础校验,获取cell信息等等),我们实现时会继承该方法,并重写导入导出方法,具体的字段验证需要自己实现。
3.导入导出会根据自己的需求去编写,一般需要进行非空等校验,其次需要判断是否存在对应的属性名,比如导入城市,门店,需要判断这些门店是否存在,等等信息,然后构建。
4.构建后,需要根据不同情况进行不同的操作:
这块建议使用开源的框架,公司的用的封装一般,一直被一个高级的开发吐槽的。
单表导入处理,excel数据方面需要验证哪些字段,导入的数据量过大,进行批量导入sql执行,数据过滤后,同样需要考虑,导入的数据重复的问题:
目前处理:
导入前,需要查询原表是否已存在该数据,我的唯一性判断涉及到两个条件,比如 城市id+门店id。看代码逻辑:
@Transactional(value = "mysqlTransactionManager", readOnly = false, rollbackFor = Throwable.class)
public void insertOrUpdateSupplyVehicleTimeExcel(List<InvCityDeptConfigFormVo> cityDeptConfigList) {
// 过滤已存在的重复的城市和门店id
Set<Long> cityIds = cityDeptConfigList.stream().map(InvCityDeptConfigFormVo::getCityId).collect(Collectors.toSet());
Set<Long> deptIds = cityDeptConfigList.stream().map(InvCityDeptConfigFormVo::getDeptId).collect(Collectors.toSet());
User user = RequestUtil.getUser();
List<InvCityDeptConfigFormVo> insertVos = new ArrayList<>();
List<InvCityDeptConfigFormVo> updateVos = new ArrayList<>();
InvCityDeptConfigFormVo cityDeptConfigFormVo = new InvCityDeptConfigFormVo();
String cityIdsStr = cityIds.toString();
String deptIdsStr = deptIds.toString();
cityDeptConfigFormVo.setCityIds(cityIdsStr.substring(1,cityIdsStr.length()-1));
cityDeptConfigFormVo.setDeptIds(deptIdsStr.substring(1,deptIdsStr.length()-1));
// 执行查询
List<String> reList = cityDeptConfigMapper.getCityDeptConfigStringList(cityDeptConfigFormVo);
// 查询出的结果与重复的执行过滤
cityDeptConfigList.forEach(vo -> {
String s = vo.getCityId() + "_" + vo.getDeptId();
if(reList.contains(s)){
vo.setModifyEmp(Long.parseLong(user.getUserId()));
vo.setModifyTime(new Date());
updateVos.add(vo);
} else {
insertVos.add(vo);
}
});
// 批量更新
updateVos.forEach(vo->{
cityDeptConfigMapper.updateInvCityDeptConfigVo(vo);
});
// 批量插入
if(insertVos.size() > 0) {
cityDeptConfigMapper.insertBatchCityDeptConfigVo(insertVos);
}
return ;
}
查询重复的sql语句如下:
select
concat(city_id,'_',dept_id)
FROM
t_inv_city_dept ticd
where 1 = 1
<if test="null != cityIds and cityIds != ''">
and ticd.city_id in (${cityIds})
</if>
<if test="null != deptIds and deptIds != ''">
and ticd.dept_id in (${deptIds})
</if>
order by id
因为我是涉及到多个条件id的处理。
第二种实现:
l利用mysql语法中的批量执行插入,如果存在就执行更新。需要做的实现:
以上面的为例: 需要加城市和门店的索引。(因为涉及到业务id,按照sql规范是不能加所以的,也就是说 这条行不通,但是要加也可以的)
如果执行查询的是唯一的条件,比如其他主键,那么可以直接查询出来后,去重。
多表导入处理(一定要考虑事务回滚),这个意思是指,有些配置是包括普通配置主表和对应的配置详情表的,一条主表记录,可能需要一条甚至多条详情表,在进行excel数据字段进行条件判断过滤后,需要构建对应的数据结构,才能执行插入数据库。
举个例子:比如详情表是根据主表中的两个字段进行分辨的,可以构建一个vo对象,里面包含主表的信息,同时需要再构建一条甚至多条详情表的信息,设置字段为info,这里还需要考虑下是否需要根据某些字段排序,便于查询时展示,因为导入是需要一条记录同时导入成功,才算成功的,需要做写事务控制。
至于为什么不执行批量导入,是因为连接到多张表。
查询
单表配置表查询,单表查询的话,也可能需要关联其他表来获取对应展示字段信息的,本表是否有逻辑删除字段,是否有效status等等条件,在写sql条件时,需要确定好,思考下,是否需要构建索引,减少join的表数。
多表查询,跟单表差不多,后续有其他再更新。
查询方面,基本都要考虑是否需要数据权限控制。
其他的主要是sql方面的优化,如果有实际数据,可以自测下,能够进行优化的点。
删除
两块,逻辑删除(软删),或者物理删除,开发之前要确认好,这块也可能跟查询关联的。isdeleted字段。逻辑删除,建议命名deleted、del,物理删除为remove。。个人建议,软删就是命名删除,真正执行的是修改isDeleted字段操作。
增删改查考虑点:
1.事务
2.异常处理
3.尽量少些接口复用
4.分页优化,减少代码侵入性
5.权限优化
。。。。
有更好的解决方案,欢迎留言或评论,一起进步,促进。。。
待续更新