背景
工作过部分软件开发公司,大部分软件的开发步骤都是框架搭建后,配置代码生成器生成出controller、service、mapper,虽然大部分开源框架service与mapper都生成好了,但是controller中还遗留冗余代码,我的想法是能不能把基本的单表CRUD抽出来,提供一个公共的Controller控制器。
利用java语言的特性可以实现,也会存在一些问题。
实现思路
- 创建父控制器BaseController
- 一个Model(表实体Model)对应一个service,service作为泛型为BaseController的属性
- 通过注入的方式注入service属性(表不可能重复,因此service不存在重复注入Spring容器)
- 提取增删改查Mapping
service接口需要提供通用增删改查接口,对持久层框架没有限制
具体步骤
我是用的是mybatis-plus框架,service泛型需要继承自IService
接口,这个接口是MybatisPlus提供的公共service层接口,基本的增删改查方法接口已经提供好了,需要传递一个Model
泛型
1 2 3 4 5 6
| public abstract class BaseController<S extends IService<M>, M> {
@Autowired protected S service; }
|
接着提取出公共的增删改查Mapping
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| public abstract class BaseController<S extends IService<M>, M> {
@Autowired protected S service;
@ResponseBody @GetMapping("/baseQueryById/{id}") @ApiOperation(value = "基础功能-通过ID查询单条记录", notes = "基础功能-通过ID查询单条记录", httpMethod = "GET", response = Result.class) @ApiOperationSupport(order = 1) protected Result baseQueryById(@PathVariable("id") Long id) { if (ObjectUtil.isNull(id) || id <= 0L) { return Result.fail("id不能为空!"); } M m = service.getById(id); return Result.success(m); }
@ResponseBody @PostMapping("/baseQueryByParam") @ApiOperation(value = "基础功能-条件查询", httpMethod = "POST", response = Result.class) @ApiOperationSupport(order = 2) protected Result baseQueryByParam(@RequestBody(required = false) M param) { if (ObjectUtil.isNull(param)) { param = service.modelInstance(); } List<M> list = service.listByParam(param); return Result.success(list); }
@ResponseBody @PostMapping("/baseQueryPageByParam") @ApiOperation(value = "基础功能-条件查询分页", httpMethod = "POST", response = Result.class) @ApiOperationSupport(order = 3) protected Result baseQueryPageByParam(@RequestBody(required = false) M param) { if (ObjectUtil.isNull(param)) { param = service.modelInstance(); } IPage<M> page = PageUtil.pageBean(param); return Result.success(service.listPageByParam(page, param)); }
@Log(title = "基础新增") @ResponseBody @PostMapping("/baseAdd") @ApiOperation(value = "基础功能-新增", httpMethod = "POST", response = Result.class) @ApiOperationSupport(order = 4) protected <DTO> Result baseAdd(@RequestBody DTO m) { M param = JSON.parseObject(JSON.toJSONString(m), service.getModelClass()); if (!service.save(param)) { return Result.fail(ResultEnum.FAIL_INSERT); } return Result.success(ResultEnum.SUCCESS_INSERT); }
@Log(title = "基础编辑") @ResponseBody @PutMapping("/baseEdit") @ApiOperation(value = "基础功能-修改", httpMethod = "PUT", response = Result.class) @ApiOperationSupport(order = 5) protected <DTO> Result baseEdit(@RequestBody @Validated(value = {Update.class}) DTO m) { M param = JSON.parseObject(JSON.toJSONString(m), service.getModelClass()); if (!service.updateById(param)) { return Result.fail(ResultEnum.FAIL_UPDATE); } return Result.success(ResultEnum.SUCCESS_UPDATE); }
@Log(title = "基础删除") @ResponseBody @DeleteMapping("/baseDeleteByIds/{ids}") @ApiOperation(value = "基础功能-根据主键id删除(多个id根据,分隔)", httpMethod = "DELETE", response = Result.class) @ApiOperationSupport(order = 6) protected Result baseDeleteByIds(@PathVariable("ids") String ids) { if (StrUtil.isEmpty(ids)) { return Result.fail("删除条件id不能为空"); } String[] idsArr = ids.split(StringPool.COMMA); if (idsArr.length > 1000) { return Result.fail("不能批量删除超过1000个数据"); } List<Long> idList = StringUtils.splitToList(ids, Long::valueOf); if (service.removeByIds(idList)) { return Result.success(ResultEnum.SUCCESS_DELETE); } return Result.success(ResultEnum.FAIL_DELETE); } }
|
其中Result
为公共的返回实体,Log
是我在项目中封装的日志注解,还用到了SwaggerUi接口文档框架
遇到的问题
1、引入swaggerUi后,接口文档的请求参数不能友好的定制化设置,如下图
参数因为是泛型,不好定制化处理,必须重写BaseController的方法,然后重新再方法中添加swaggerUI注解
2、如果需要扩展参数进行crud,必须重写父类BaseController中的方法,并且如果是扩展类型(DTO,VO)需要进行一次转换,不过这种转换的效率应该可以忽略不计
1 2 3 4 5 6 7
| @Log(title = "字典类型新增") @Override protected <DTO> Result baseAdd(@RequestBody DTO m) { BaseDictTypeModel param = MapperUtil.convert(m, BaseDictTypeModel.class); return Result.successBoolean(service.insertByParam(param)); }
|
重写注意要添加@RequestBody注解
总结
实际开发过程中并没有想象中的那么简化代码,但是提供了一个规则,使代码编写思路变的清晰,也减少了单表业务的代码量
项目的源码地址:
gitee源码地址
github源码地址