No9.【spring-cloud-alibaba】添加字典业务,这一模块就是纯业务

No9.【spring-cloud-alibaba】添加字典业务,这一模块就是纯业务PigUserDetai 代码地址与接口文档看总目录 学习笔记 记录冷冷 pig 项目的学习过程 大概包括 Authorizatio Server springcloud Mybatis Plus 清晨敲代码的博客 CSDN 博客 终于结束从零搭建 springcloud 的部分了

大家好,我是讯享网,很高兴认识大家。

PigUserDetailsService  代码地址与接口文档看总目录:【学习笔记】记录冷冷-pig项目的学习过程,大概包括Authorization Server、springcloud、Mybatis Plus~~~_清晨敲代码的博客-CSDN博客


终于结束从零搭建springcloud的部分了,目前也仅仅是学习了最最基本的逻辑,同时包含了开发系统的一些基本的逻辑。接下来就按照 pig 文档将其余基本的内容再熟悉一下,看一遍和写一遍真的不一样呐~~~

那接下来就一小模块一小模块的学习啦,加油吧少年!

本文及以后的文章还是基于前面的No6系列文章开发的,可以看之前文章顶部的内容总结,简单了解详情~

目录

A1.添加字典功能

B1.步骤

B2.编码

B3.测试

遇到的问题:

1.基础增删改查需要判断是否存在

2.增删改查业务添加一个同意逻辑处理模块


A1.添加字典功能

字典,又分为字典和字典项,每个字典项属于某一个字典,每个字典有多个字典项。这样前端就可以根据字典拿到字典项。

获取到的字典的属性,要尽可能适用于前端的组件,方便前端使用。

B1.步骤

首先,我们需要提供一个字典的增删改查功能,然后再提供一个字典项的增删改查功能,同时字典项必须要关联一个字典,并且字典项要有值和标签,值对应业务操作,标签对应用户展示。


讯享网

 由于没有复杂业务,所以不需要关联表操作,不需要写 mapper 语句~

B2.编码

确定好数据结构之后,一定要先写接口文档,梳理编码逻辑!

1.新建两个数据表,一个字典sys_dict,一个字典项sys_dict_item,设置 id 自增;

2.新建表对应的实体类,要设置 mps 的id自增,和逻辑删除注解;

3.新建 mapper 接口,继承 mps 的 BaseMapper ,不需要新增方法;

4.新建 service 接口及实现类,继承 mps 的 IService、IServiceImpl ;

5.新建 controller 类,编写接口端点方法,并确定好需要调用的 service 方法;

【我习惯了解数据接口和接口文档后,就针对他们编写 controller 中的接口端点,然后再编写 service 业务方法】

6.有些复杂的业务需要增加业务方法,所以修改 service 类,编写 controller 需要的方法;

-- 1.新建两个数据表,一个字典sys_dict,一个字典项sys_dict_item,设置 id 自增; CREATE TABLE `sys_dict` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `dict_type` varchar(100) DEFAULT NULL COMMENT '标识', `description` varchar(100) DEFAULT NULL COMMENT '描述', `remark` varchar(255) DEFAULT NULL COMMENT '备注', `system_flag` char(1) DEFAULT '0' COMMENT '是否是系统内置', `del_flag` char(1) DEFAULT '0' COMMENT '删除标记', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `create_by` varchar(64) DEFAULT NULL COMMENT '创建人', `update_by` varchar(64) DEFAULT NULL COMMENT '更新人', `update_time` datetime DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`) USING BTREE, KEY `sys_dict_del_flag` (`del_flag`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COMMENT='字典表' CREATE TABLE `sys_dict_item` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `dict_id` bigint(20) NOT NULL COMMENT '字典ID', `dict_type` varchar(100) DEFAULT NULL COMMENT '字典标识', `value` varchar(100) DEFAULT NULL COMMENT '值', `label` varchar(100) DEFAULT NULL COMMENT '标签', `description` varchar(100) DEFAULT NULL COMMENT '描述', `sort_order` int(11) NOT NULL DEFAULT '0' COMMENT '排序(升序)', `remark` varchar(255) DEFAULT ' ' COMMENT '备注', `del_flag` char(1) DEFAULT '0' COMMENT '删除标记', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `create_by` varchar(64) DEFAULT NULL COMMENT '创建人', `update_by` varchar(64) DEFAULT NULL COMMENT '修改人', `update_time` datetime DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`) USING BTREE, KEY `sys_dict_value` (`value`) USING BTREE, KEY `sys_dict_label` (`label`) USING BTREE, KEY `sys_dict_del_flag` (`del_flag`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8mb4 COMMENT='字典项'

讯享网
讯享网//2.新建表对应的实体类,要设置 mps 的id自增,和逻辑删除注解; //新增 com.pig4cloud.pig.admin.api.entity.SysDict extends BaseEntity com.pig4cloud.pig.admin.api.entity.SysDictItem extends BaseEntity
//3.新建 mapper 接口,继承 mps 的 BaseMapper ,不需要新增方法; @Mapper public interface SysDictMapper extends BaseMapper<SysDict> { } @Mapper public interface SysDictItemMapper extends BaseMapper<SysDictItem> { } 
讯享网//4.新建 service 接口及实现类,继承 mps 的 IService、IServiceImpl ; public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> implements SysDictService { } public class SysDictItemServiceImpl extends ServiceImpl<SysDictItemMapper, SysDictItem> implements SysDictItemService { }
//5.新建 controller 类,编写接口端点方法,并确定好需要调用的 service 方法; //其中只有两个更新和两个删除的需要重写对应的 service 方法,因为需要判断是否能删除,并且涉及到关联删除~ //其余的使用 mps 提供的 service 方法就行 @RestController @RequestMapping("/dict") @RequiredArgsConstructor public class DictController { private final SysDictService sysDictService; private final SysDictItemService sysDictItemService; / * @Description: 添加 * @param: [dict] * @return: com.pig4cloud.pig.common.core.util.R<java.lang.Boolean> / @SysLog("添加字典") @PostMapping @PreAuthorize("@pms.hasPermission('sys_dict_add')") public R<Boolean> save(@RequestBody SysDict dict) { //标签必须唯一,先判断是否已存在 SysDict sysDict = sysDictService.getOne(Wrappers.<SysDict>lambdaQuery().eq(SysDict::getDictType, dict.getDictType())); if ( sysDict != null){ return R.failed("标签已存在"); } return R.ok(sysDictService.save(dict)); } / * @Description: 分页查询字典 * @param: [page, dict] * @return: com.pig4cloud.pig.common.core.util.R<com.baomidou.mybatisplus.core.metadata.IPage<com.pig4cloud.pig.admin.api.entity.SysDict>> / @SysLog("分页查询字典") @GetMapping("/page") @PreAuthorize("@pms.hasPermission('sys_dict_list')") public R<IPage<SysDict>> getPage(Page page, SysDict dict) { LambdaQueryWrapper<SysDict> wrapper = Wrappers.lambdaQuery(); wrapper.eq(SysDict::getDelFlag, CommonConstants.NOT_DELETE); if(StrUtil.isNotBlank(dict.getDictType())){ wrapper.like(SysDict::getDictType, dict.getDictType()); } if(StrUtil.isNotBlank(dict.getDictType())){ wrapper.like(SysDict::getSystemFlag, dict.getSystemFlag()); } return R.ok(sysDictService.page(page, wrapper)); } / * @Description: 通过ID查询字典 * @param: [id] * @return: com.pig4cloud.pig.common.core.util.R<com.pig4cloud.pig.admin.api.entity.SysDict> / @SysLog("通过ID查询字典") @GetMapping("/{id}") public R<SysDict> getById(@PathVariable Long id) { return R.ok(sysDictService.getById(id)); } / * @Description: 添加 * @param: [dictItem] * @return: com.pig4cloud.pig.common.core.util.R<java.lang.Boolean> / @SysLog("添加字典项") @PostMapping("/item") public R<Boolean> save(@RequestBody SysDictItem dictItem) { //value 必须唯一,先判断当前字典中是否已存在该 value SysDictItem sysDictItem = sysDictItemService.getOne( Wrappers.<SysDictItem>lambdaQuery().eq(SysDictItem::getDictType, dictItem.getDictType()).eq(SysDictItem::getValue, dictItem.getValue())); if ( sysDictItem != null){ return R.failed("值已存在"); } return R.ok(sysDictItemService.save(dictItem)); } / * @Description: 分页查询某个字典的字典项 * @param: [page, dictItem] * @return: com.pig4cloud.pig.common.core.util.R<com.baomidou.mybatisplus.core.metadata.IPage<com.pig4cloud.pig.admin.api.entity.SysDictItem>> / @SysLog("分页查询某个字典的字典项") @GetMapping("/item/page") @PreAuthorize("@pms.hasPermission('sys_dictItem_list')") public R<IPage<SysDictItem>> getDictItemPage(Page page, SysDictItem dictItem) { return R.ok(sysDictItemService.page(page, Wrappers.<SysDictItem>lambdaQuery().eq(SysDictItem::getDictType, dictItem.getDictType()) .eq(SysDictItem::getDelFlag, CommonConstants.NOT_DELETE))); } / * @Description: 通过ID查询字典项 * @param: [id] * @return: com.pig4cloud.pig.common.core.util.R<com.pig4cloud.pig.admin.api.entity.SysDictItem> / @SysLog("通过ID查询字典项") @GetMapping("/item/{id}") public R<SysDictItem> getDictItemById(@PathVariable Long id) { return R.ok(sysDictItemService.getById(id)); } / * @Description: 通过字典标识查找字典项 * @param: [type] * @return: com.pig4cloud.pig.common.core.util.R<java.util.List<com.pig4cloud.pig.admin.api.entity.SysDictItem>> / @GetMapping("/dictType/{dictType}") public R<List<SysDictItem>> getDictByType(@PathVariable String dictType) { return R.ok(sysDictItemService.list( Wrappers.<SysDictItem>query().lambda().eq(SysDictItem::getDictType, dictType).eq(SysDictItem::getDelFlag, CommonConstants.NOT_DELETE))); } }
讯享网//6.有些复杂的业务需要增加业务方法,所以修改 service 类,编写 controller 需要的方法; @Service @RequiredArgsConstructor public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> implements SysDictService { private final SysDictItemMapper dictItemMapper; @Override public Boolean updateDict(SysDict sysDict) { //1.先拿到对应的存储的信息 SysDict dict = this.getById(sysDict.getId()); // 判断是不是系统内置的,如果是则抛异常不能修改 if(!DictTypeEnum.SYSTEM.getType().equals(dict.getSystemFlag())){ throw new RuntimeException("系统内置字典不能修改"); } //不是系统内置,则进行修改 this.updateById(sysDict); return Boolean.TRUE; } @Override public Boolean deleteDict(Long id) { //先拿到对应的存储的信息 SysDict dict = this.getById(id); // 判断是不是系统内置的,如果是则抛异常不能删除 if(!DictTypeEnum.SYSTEM.getType().equals(dict.getSystemFlag())){ throw new RuntimeException("系统内置字典不允许删除"); } //不是系统内置,则进行修改 baseMapper.deleteById(id); //同时删除字典项 dictItemMapper.delete(Wrappers.<SysDictItem>lambdaQuery().eq(SysDictItem::getDictId, id)); return Boolean.TRUE; } } @Service @RequiredArgsConstructor public class SysDictItemServiceImpl extends ServiceImpl<SysDictItemMapper, SysDictItem> implements SysDictItemService { private final SysDictService dictService; @Override public Boolean updateDictItem(SysDictItem dictItem) { //先获取字典的系统内置信息 SysDict dict = dictService.getById(dictItem.getDictId()); // 判断是不是系统内置的,如果是则抛异常不能修改 if(!DictTypeEnum.SYSTEM.getType().equals(dict.getSystemFlag())){ throw new RuntimeException("系统内置字典不能修改"); } //不是系统内置,则进行修改 this.updateById(dictItem); return Boolean.TRUE; } @Override public Boolean deleteDictItem(Long id) { // 先根据ID查询字典ID SysDictItem dictItem = this.getById(id); //再获取字典的系统内置信息 SysDict dict = dictService.getById(dictItem.getDictId()); // 判断是不是系统内置的,如果是则抛异常不能修改 if(!DictTypeEnum.SYSTEM.getType().equals(dict.getSystemFlag())){ throw new RuntimeException("系统内置字典不允许删除"); } this.removeById(id); return Boolean.TRUE; } } @RestController @RequestMapping("/dict") @RequiredArgsConstructor public class DictController { private final SysDictService sysDictService; private final SysDictItemService sysDictItemService; / * @Description: 修改 * @param: [dict] * @return: com.pig4cloud.pig.common.core.util.R<java.lang.Boolean> / @SysLog("修改字典") @PutMapping @PreAuthorize("@pms.hasPermission('sys_dict_update')") public R<Boolean> update(@RequestBody SysDict dict) { //标签必须唯一,先判断是否已存在未删除的、该标签 SysDict sysDict = sysDictService.getOne(Wrappers.<SysDict>lambdaQuery().eq(SysDict::getDictType, dict.getDictType()).ne(SysDict::getId, dict.getId())); if ( sysDict != null){ return R.failed("标签已存在"); } return R.ok(sysDictService.updateDict(dict)); } / * @Description: 删除 * @param: [dict] * @return: com.pig4cloud.pig.common.core.util.R<java.lang.Boolean> / @SysLog("删除字典") @DeleteMapping("/{id:\\d+}") @PreAuthorize("@pms.hasPermission('sys_dict_del')") public R<Boolean> deleteDictById(@PathVariable Long id) { return R.ok(sysDictService.deleteDict(id)); } / * @Description: 修改 * @param: [dictItem] * @return: com.pig4cloud.pig.common.core.util.R<java.lang.Boolean> / @SysLog("修改字典项") @PutMapping("/item") public R<Boolean> update(@RequestBody SysDictItem dictItem) { //value 必须唯一,先判断当前字典中是否已存在该 value SysDictItem sysDictItem = sysDictItemService.getOne( Wrappers.<SysDictItem>lambdaQuery().eq(SysDictItem::getDictType, dictItem.getDictType()).eq(SysDictItem::getValue, dictItem.getValue()).ne(SysDictItem::getId, dictItem.getId())); if ( sysDictItem != null){ return R.failed("值已存在"); } return R.ok(sysDictItemService.updateDictItem(dictItem)); } / * @Description: 删除 * @param: [id] * @return: com.pig4cloud.pig.common.core.util.R<java.lang.Boolean> / @SysLog("删除字典项") @DeleteMapping("/item/{id:\\d+}") public R<Boolean> deleteDictItemById(@PathVariable Long id) { return R.ok(sysDictItemService.deleteDictItem(id)); } } 

B3.测试

然后就按照 api 接口测试吧,后面要学一下 api 自动化测试~ 

遇到的问题:

1.基础增删改查需要判断是否存在

对于普通的单表,增删改查的业务中,如果遇到非正常操作怎么办?

例如,单表中有唯一数据时,改中要校验唯一数据是否存在(自己本身包含不算)。如果入参的 id 不存在或者已删除怎么办?还需要修改么?

从单账号操作的设计上来说,不会出现这种情况,毕竟操作的数据一定是未删除的。但是如果是多账号使用时,就会多个帐号同时删除此条数据,总有一个人成功,而其余人会失败,失败的人也要收到反馈信息。

此时的反馈信息不应该是 500 报错的。

看下图,我用多个线程来调用删除字典的操作,就有一个报错了,虽然最终的数据是对的。

原因是 controller 里面的判断,他通过,但是 service 里面再获取时就获取到了 null。所以还是要处理一下该异常。

新建一个业务异常处理类,然后可以在此处用 try catch 异常并抛出新增的业务异常处理类。

@Slf4j @Order(10000) @RestControllerAdvice @ConditionalOnExpression("!'${security.oauth2.client.clientId}'.isEmpty()") public class GlobalBizExceptionHandler { / * 全局异常. * @param e the e * @return R */ @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public R handleGlobalException(Exception e) { log.error("全局异常信息 ex={}", e.getMessage(), e); // 业务异常交由 sentinel 记录 Tracer.trace(e); return R.failed(e.getLocalizedMessage()); } }

 这样就不会报错 500 了

 

2.增删改查业务添加一个同意逻辑处理模块

写这一块儿的时候,总是修修改改,写某个接口时总感觉逻辑缺少,所以,整理一个基础的单表增删改查逻辑,方便开发理解。

开个新文章,到时粘个链接~

小讯
上一篇 2025-04-01 11:20
下一篇 2025-03-14 17:52

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/51518.html