PigUserDetailsService 代码地址与接口文档看总目录:【学习笔记】记录冷冷-pig项目的学习过程,大概包括Authorization Server、springcloud、Mybatis Plus~~~_清晨敲代码的博客-CSDN博客
终于结束从零搭建springcloud的部分了,目前也仅仅是学习了最最基本的逻辑,同时包含了开发系统的一些基本的逻辑。接下来就按照 pig 文档将其余基本的内容再熟悉一下,看一遍和写一遍真的不一样呐~~~
那接下来就一小模块一小模块的学习啦,加油吧少年!
本文及以后的文章还是基于前面的No6系列文章开发的,可以看之前文章顶部的内容总结,简单了解详情~
目录
字典,又分为字典和字典项,每个字典项属于某一个字典,每个字典有多个字典项。这样前端就可以根据字典拿到字典项。
获取到的字典的属性,要尽可能适用于前端的组件,方便前端使用。
首先,我们需要提供一个字典的增删改查功能,然后再提供一个字典项的增删改查功能,同时字典项必须要关联一个字典,并且字典项要有值和标签,值对应业务操作,标签对应用户展示。

由于没有复杂业务,所以不需要关联表操作,不需要写 mapper 语句~
确定好数据结构之后,一定要先写接口文档,梳理编码逻辑!
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
{ - }
-
- @Mapper
- public interface SysDictItemMapper extends BaseMapper
{ - }
- //4.新建 service 接口及实现类,继承 mps 的 IService、IServiceImpl ;
-
- public class SysDictServiceImpl extends ServiceImpl
implements SysDictService { - }
-
- public class SysDictItemServiceImpl extends ServiceImpl
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
- **/
- @SysLog("添加字典")
- @PostMapping
- @PreAuthorize("@pms.hasPermission('sys_dict_add')")
- public R
save(@RequestBody SysDict dict) { -
- //标签必须唯一,先判断是否已存在
- SysDict sysDict = sysDictService.getOne(Wrappers.
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
> - **/
- @SysLog("分页查询字典")
- @GetMapping("/page")
- @PreAuthorize("@pms.hasPermission('sys_dict_list')")
- public R
> getPage(Page page, SysDict dict) { -
- LambdaQueryWrapper
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
- **/
- @SysLog("通过ID查询字典")
- @GetMapping("/{id}")
- public R
getById(@PathVariable Long id) { - return R.ok(sysDictService.getById(id));
- }
-
- /**
- * @Description: 添加
- * @param: [dictItem]
- * @return: com.pig4cloud.pig.common.core.util.R
- **/
- @SysLog("添加字典项")
- @PostMapping("/item")
- public R
save(@RequestBody SysDictItem dictItem) { -
- //value 必须唯一,先判断当前字典中是否已存在该 value
- SysDictItem sysDictItem = sysDictItemService.getOne(
- Wrappers.
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
> - **/
- @SysLog("分页查询某个字典的字典项")
- @GetMapping("/item/page")
- @PreAuthorize("@pms.hasPermission('sys_dictItem_list')")
- public R
> getDictItemPage(Page page, SysDictItem dictItem) { - return R.ok(sysDictItemService.page(page,
- Wrappers.
lambdaQuery().eq(SysDictItem::getDictType, dictItem.getDictType()) - .eq(SysDictItem::getDelFlag, CommonConstants.NOT_DELETE)));
- }
-
- /**
- * @Description: 通过ID查询字典项
- * @param: [id]
- * @return: com.pig4cloud.pig.common.core.util.R
- **/
- @SysLog("通过ID查询字典项")
- @GetMapping("/item/{id}")
- public R
getDictItemById(@PathVariable Long id) { - return R.ok(sysDictItemService.getById(id));
- }
-
- /**
- * @Description: 通过字典标识查找字典项
- * @param: [type]
- * @return: com.pig4cloud.pig.common.core.util.R
> - **/
- @GetMapping("/dictType/{dictType}")
- public R
> getDictByType(@PathVariable String dictType) {
- return R.ok(sysDictItemService.list(
- Wrappers.
query().lambda().eq(SysDictItem::getDictType, dictType).eq(SysDictItem::getDelFlag, CommonConstants.NOT_DELETE))); - }
- }
- //6.有些复杂的业务需要增加业务方法,所以修改 service 类,编写 controller 需要的方法;
-
- @Service
- @RequiredArgsConstructor
- public class SysDictServiceImpl extends ServiceImpl
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.
lambdaQuery().eq(SysDictItem::getDictId, id)); -
- return Boolean.TRUE;
- }
-
-
- }
-
- @Service
- @RequiredArgsConstructor
- public class SysDictItemServiceImpl extends ServiceImpl
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
- **/
- @SysLog("修改字典")
- @PutMapping
- @PreAuthorize("@pms.hasPermission('sys_dict_update')")
- public R
update(@RequestBody SysDict dict) { -
- //标签必须唯一,先判断是否已存在未删除的、该标签
- SysDict sysDict = sysDictService.getOne(Wrappers.
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
- **/
- @SysLog("删除字典")
- @DeleteMapping("/{id:\\d+}")
- @PreAuthorize("@pms.hasPermission('sys_dict_del')")
- public R
deleteDictById(@PathVariable Long id) { - return R.ok(sysDictService.deleteDict(id));
- }
-
-
- /**
- * @Description: 修改
- * @param: [dictItem]
- * @return: com.pig4cloud.pig.common.core.util.R
- **/
- @SysLog("修改字典项")
- @PutMapping("/item")
- public R
update(@RequestBody SysDictItem dictItem) { -
- //value 必须唯一,先判断当前字典中是否已存在该 value
- SysDictItem sysDictItem = sysDictItemService.getOne(
- Wrappers.
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
- **/
- @SysLog("删除字典项")
- @DeleteMapping("/item/{id:\\d+}")
- public R
deleteDictItemById(@PathVariable Long id) { - return R.ok(sysDictItemService.deleteDictItem(id));
- }
-
- }
然后就按照 api 接口测试吧,后面要学一下 api 自动化测试~

对于普通的单表,增删改查的业务中,如果遇到非正常操作怎么办?
例如,单表中有唯一数据时,改中要校验唯一数据是否存在(自己本身包含不算)。如果入参的 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 了
写这一块儿的时候,总是修修改改,写某个接口时总感觉逻辑缺少,所以,整理一个基础的单表增删改查逻辑,方便开发理解。
开个新文章,到时粘个链接~