开发技巧之标签管理

我爱海鲸 2022-08-29 17:48:22 暂无标签

简介给某一个模块事物打上标签以及进行相关的标签管理,这里以用户标签为例

1、创建表,这里主要创建三张表user_label(用户标签表)、user_label_group(用户标签分组表)、user_label_relation(用户标签关系表)

ddl语句如下:

CREATE TABLE `user_label` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `create_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '创建人',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_id` bigint(64) NOT NULL DEFAULT '-1' COMMENT '修改人',
  `update_time` datetime DEFAULT NULL COMMENT '修改时间',
  `label_name` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '标签名称',
  `group_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '标签分组id',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=118 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='用户标签表';
CREATE TABLE `user_label_group` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `create_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '创建人',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '修改人',
  `update_time` datetime DEFAULT NULL COMMENT '修改时间',
  `group_name` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '分组名称',
  `default_group` int(11) NOT NULL DEFAULT '0' COMMENT '是否默认分组(0:否,1:是)',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='用户标签分组表';
CREATE TABLE `user_label_relation` (
  `user_id` bigint(20) NOT NULL COMMENT '用户id',
  `label_id` bigint(20) NOT NULL COMMENT '标签id',
  PRIMARY KEY (`user_id`,`label_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='用户标签关系表';

2、用户标签分组相关接口

@RestController
@RequestMapping("/userLabelGroup")
@AllArgsConstructor
@Slf4j
@Api(value = "用户标签分组相关接口", tags = "用户标签分组相关接口")
public class UserLabelGroupController {

    private final IUserLabelGroupService iUserLabelGroupService;

    /**
     * 默认 用户标签分组接口
     * @return ignore
     */
    @ApiOperation(value = "默认 用户标签分组接口",notes = "默认 用户标签分组接口")
    @RequestMapping(value = "/defaultGroup",method = RequestMethod.GET)
    public Result defaultGroup() {
        UserLabelGroupPageVO defaultGroupDetail = iUserLabelGroupService.defaultGroup();
        return Result .success(defaultGroupDetail);
    }

    /**
     *  分页 用户标签分组接口
     * @return ignore
     */
    @ApiOperation(value = "分页 用户标签分组接口", notes = "分页 用户标签分组接口")
    @RequestMapping(value = "/page", method = RequestMethod.GET)
    public Result page(PageInfo pageInfo) {
        PageBean<UserLabelGroupPageVO> pageBean = iUserLabelGroupService.page(pageInfo);
        return Result .success(pageBean);
    }

    /**
     *  列表 用户标签分组接口
     * @return ignore
     */
    @ApiOperation(value = "列表 用户标签分组接口", notes = "列表 用户标签分组接口")
    @RequestMapping(value = "/listLabel", method = RequestMethod.GET)
    public Result list() {
        List<UserLabelGroupPageVO> list = iUserLabelGroupService.listLabel();
        return Result .success(list);
    }

    /**
     * 新增 用户标签分组接口
     * @param userLabelGroupAddDTO 用户标签分组新增请求对象
     * @return ignore
     */
    @ApiOperation(value = "新增 用户标签分组接口", notes = "新增 用户标签分组接口")
    @PostMapping(value = "/add")
    public Result add(@Valid @RequestBody UserLabelGroupAddDTO userLabelGroupAddDTO) {
        log.info("新增 用户标签分组接口入参:【{}】",userLabelGroupAddDTO);
        iUserLabelGroupService.add(userLabelGroupAddDTO);
        return Result .success();
    }

    /**
     * 删除 用户标签分组接口
     * @param userLabelGroupDeleteDTO 用户标签分组删除请求对象
     * @return ignore
     */
    @ApiOperation(value = "删除 用户标签分组接口", notes = "删除 用户标签分组接口")
    @PostMapping(value = "/delete")
    public Result delete(@Valid @RequestBody UserLabelGroupDeleteDTO userLabelGroupDeleteDTO) {
        log.info("删除 用户标签分组接口入参:【{}】",userLabelGroupDeleteDTO);
        iUserLabelGroupService.delete(userLabelGroupDeleteDTO.getIds());
        return Result .success();
    }

    /**
     * 修改 用户标签分组接口
     * @param userLabelGroupUpdateDTO 用户标签分组修改请求对象
     * @return ignore
     */
    @ApiOperation(value = "修改 用户标签分组接口", notes = "修改 用户标签分组接口")
    @PostMapping(value = "/update")
    public Result update(@Valid @RequestBody UserLabelGroupUpdateDTO userLabelGroupUpdateDTO) {
        log.info("修改 用户标签分组接口入参:【{}】",userLabelGroupUpdateDTO);
        iUserLabelGroupService.update(userLabelGroupUpdateDTO);
        return Result .success();
    }

    /**
     * 移动 用户标签至对应的分组中
     * @param userLabelGroupMoveDTO 移动 用户标签至对应的分组中
     * @return ignore
     */
    @ApiOperation(value = "移动 用户标签至对应的分组中", notes = "移动 用户标签至对应的分组中")
    @PostMapping(value = "/move")
    public Result move(@Valid @RequestBody UserLabelGroupMoveDTO userLabelGroupMoveDTO) {
        log.info("移动 用户标签至对应的分组中接口入参:【{}】",userLabelGroupMoveDTO);
        iUserLabelGroupService.move(userLabelGroupMoveDTO);
        return Result .success();
    }

}

3、用户标签分组业务处理

@Service
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class UserLabelGroupServiceImpl extends ServiceImpl<UserLabelGroupMapper, UserLabelGroup> implements IUserLabelGroupService {

    private final IUserLabelService userLabelService;

    /**
     * 默认分组的名称
     */
    private static final String DEFAULT_GROUP_NAME = "默认分组";

    /**
     * 默认分组的id
     */
    private static final Long DEFAULT_GROUP_ID = -1L;

    @Override
    @SuppressWarnings({"unchecked"})
    public PageBean<UserLabelGroupPageVO> page(PageInfo pageInfo) {
        Page<UserLabelGroup> page = this.page(Condition.getPage(pageInfo), Wrappers.<UserLabelGroup>lambdaQuery()
                .orderByDesc(UserLabelGroup::getDefaultGroup,UserLabelGroup::getCreateTime)
        );
        return UserLabelGroupPageWrapper.build(userLabelService).pageVO(page);
    }

    @Override
    public List<UserLabelGroupPageVO> listLabel() {
        List<UserLabelGroupPageVO> result = new ArrayList<>();
        List<UserLabelGroup> list = this.list();
        if (CollectionUtil.isEmpty(list)) {
            return null;
        }
        for (UserLabelGroup userLabelGroup : list) {
            UserLabelGroupPageVO userLabelGroupPageVO = UserLabelGroupPageWrapper.build(userLabelService).entityVO(userLabelGroup);
            result.add(userLabelGroupPageVO);
        }
        return result;
    }

    @Override
    public UserLabelGroupPageVO defaultGroup() {
        List<UserLabel> list = userLabelService.list(Wrappers.<UserLabel>lambdaQuery()
                .eq(UserLabel::getGroupId, DEFAULT_GROUP_ID)
        );
        List<UserLabelDetailVO> userLabelDetails = null;
        if (CollectionUtil.isNotEmpty(list)) {
            userLabelDetails = BeanUtils.copyList(list, UserLabelDetailVO.class);
        }
        return UserLabelGroupPageVO.builder()
                .groupName(DEFAULT_GROUP_NAME)
                .id(DEFAULT_GROUP_ID)
                .labels(userLabelDetails)
                .build();
    }

    @Override
    public boolean add(UserLabelGroupAddDTO userLabelGroupAddDTO) {
        int count = this.count(Wrappers.<UserLabelGroup>lambdaQuery()
                .eq(UserLabelGroup::getGroupName, userLabelGroupAddDTO.getGroupName())
        );
        if (count > 0) {
            throw new ServiceException("error.labelNameGroupRepeat.exit");
        }
        UserLabelGroup userLabelGroup = new UserLabelGroup();
        BeanUtils.copyBeanProp(userLabelGroup,userLabelGroupAddDTO);
        this.save(userLabelGroup);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(List<Long> ids) {
        if (ids.contains(DEFAULT_GROUP_ID)) {
            throw new ServiceException("error.defaultGroup.operation");
        }
        // 将当前属于该分组的用户标签设置为默认分组
        boolean labelGroupFlag = userLabelService.updateDefaultLabelGroup(ids);
        if (labelGroupFlag) {
            // 删除当前分组
            this.removeByIds(ids);
        }
        return true;
    }

    @Override
    public boolean update(UserLabelGroupUpdateDTO userLabelGroupUpdateDTO) {
        int count = this.count(Wrappers.<UserLabelGroup>lambdaQuery()
                .eq(UserLabelGroup::getGroupName, userLabelGroupUpdateDTO.getGroupName())
        );
        if (count > 0) {
            throw new ServiceException("error.labelNameGroupRepeat.exit");
        }
        this.update(Wrappers.<UserLabelGroup>lambdaUpdate()
            .set(UserLabelGroup::getGroupName,userLabelGroupUpdateDTO.getGroupName())
                .eq(UserLabelGroup::getId,userLabelGroupUpdateDTO.getId())
        );
        return true;
    }

    @Override
    public boolean move(UserLabelGroupMoveDTO userLabelGroupMoveDTO) {
        List<Long> labelIds = userLabelGroupMoveDTO.getLabelIds();
        userLabelService.update(Wrappers.<UserLabel>lambdaUpdate()
            .set(UserLabel::getGroupId,userLabelGroupMoveDTO.getGroupId())
            .in(UserLabel::getId,labelIds)
        );
        return true;
    }

}

4、用户标签相关接口

@RestController
@RequestMapping("/userLabel")
@AllArgsConstructor
@Slf4j
@Api(value = "用户标签相关接口", tags = "用户标签相关接口")
public class UserLabelController {

    private final  IUserLabelService iUserLabelService;

    /**
     * 新增 用户标签接口
     * @param userLabelAddDTO 用户标签接口 新增 请求对象
     * @return ignore
     */
    @ApiOperation(value = "新增 用户标签接口", notes = "新增 用户标签接口")
    @PostMapping(value = "/add")
    public Result add(@Valid @RequestBody UserLabelAddDTO userLabelAddDTO) {
        log.info("新增 用户标签接口 入参:【{}】",userLabelAddDTO);
        iUserLabelService.add(userLabelAddDTO);
        return Result .success();
    }

    /**
     * 修改 用户标签接口
     * @param userLabelUpdateDTO 用户标签接口 修改 请求对象
     * @return ignore
     */
    @ApiOperation(value = "修改 用户标签接口", notes = "修改 用户标签接口")
    @PostMapping(value = "/update")
    public Result update(@Valid @RequestBody UserLabelUpdateDTO userLabelUpdateDTO) {
        log.info("修改 用户标签接口 入参:【{}】",userLabelUpdateDTO);
        iUserLabelService.update(userLabelUpdateDTO);
        return Result .success();
    }


    /**
     * 删除 用户标签接口
     * @param userLabelDeleteDTO 用户标签删除请求对象
     * @return ignore
     */
    @ApiOperation(value = "删除 用户标签接口", notes = "删除 用户标签接口")
    @PostMapping(value = "/delete")
    public Result delete(@Valid @RequestBody UserLabelDeleteDTO userLabelDeleteDTO) {
        log.info("删除 用户标签接口入参:【{}】",userLabelDeleteDTO);
        iUserLabelService.delete(userLabelDeleteDTO);
        return Result .success();
    }

}

5、用户标签相关业务处理

@Service
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class UserLabelServiceImpl extends ServiceImpl<UserLabelMapper, UserLabel> implements IUserLabelService {

    private final IUserLabelRelationService userLabelRelationService;

    /**
     * 默认分组的id
     */
    private static final Long DEFAULT_GROUP_ID = -1L;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateDefaultLabelGroup(List<Long> groupIds) {
        for (Long groupId : groupIds) {
            this.update(Wrappers.<UserLabel>lambdaUpdate()
                    .set(UserLabel::getGroupId,DEFAULT_GROUP_ID)
                    .eq(UserLabel::getGroupId,groupId)
            );
        }
        return true;
    }

    @Override
    public boolean add(UserLabelAddDTO userLabelAddDTO) {
        int count = this.count(Wrappers.<UserLabel>lambdaQuery()
                .eq(UserLabel::getLabelName, userLabelAddDTO.getLabelName())
        );
        if (count > 0) {
            throw new ServiceException("error.labelNameRepeat.exited");
        }
        UserLabel userLabel = new UserLabel();
        BeanUtils.copyBeanProp(userLabel,userLabelAddDTO);
        this.save(userLabel);
        return true;
    }

    @Override
    public boolean update(UserLabelUpdateDTO userLabelUpdateDTO) {
        this.update(Wrappers.<UserLabel>lambdaUpdate()
            .set(UserLabel::getLabelName,userLabelUpdateDTO.getLabelName())
            .set(ObjectUtil.isNotEmpty(userLabelUpdateDTO.getGroupId()),UserLabel::getGroupId,userLabelUpdateDTO.getGroupId())
            .eq(UserLabel::getId,userLabelUpdateDTO.getId())
        );
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(UserLabelDeleteDTO userLabelDeleteDTO) {
        this.removeById(userLabelDeleteDTO.getId());
        userLabelRelationService.removeByLabelId(userLabelDeleteDTO.getId());
        return true;
    }

}

6、相关实体类:

@Data
@ApiModel(value = "用户标签 新增请求对象", description = "用户标签 新增请求对象")
public class UserLabelAddDTO {

    /**
     * 用户标签名称
     */
    @ApiModelProperty(value = "用户标签名称",required = true)
    @NotBlank(message = "error.labelName.blank")
    @Size(min = 1,max = 15,message = "用户标签名称长度在1到15位")
    private String labelName;

    /**
     * 用户标签分组id
     */
    @ApiModelProperty(value = "用户标签分组id",required = true)
    @NotNull(message = "用户标签分组id不能位空")
    private Long groupId;

}
@Data
@ApiModel(value = "用户标签删除请求对象", description = "用户标签删除请求对象")
public class UserLabelDeleteDTO {

    /**
     * 用户标签id
     */
    @ApiModelProperty(value = "用户标签id",required = true)
    @NotNull(message = "用户标签id不能为空")
    private Long id;

}
@Data
@ApiModel(value = "用户标签分组新增请求对象", description = "用户标签分组新增请求对象")
public class UserLabelGroupAddDTO {

    /**
     * 用户标签分组名称
     */
    @ApiModelProperty(value = "用户标签分组名称",required = true)
    @NotBlank(message = "用户标签分组名称不能为空")
    @Size(min = 1,max = 15,message = "用户标签分组名称长度为1到15位")
    private String groupName;

}
@Data
@ApiModel(value = "用户标签分组删除请求对象", description = "用户标签分组删除请求对象")
public class UserLabelGroupDeleteDTO {

    /**
     * 用户标签分组ids
     */
    @ApiModelProperty(value = "用户标签分组ids",required = true)
    @NotNull(message = "用户标签分组ids不能为空")
    private List<Long> ids;

}
@Data
@ApiModel(value = "用户标签移动至分组请求对象", description = "用户标签移动至分组请求对象")
public class UserLabelGroupMoveDTO {

    /**
     * 用户标签ids
     */
    @ApiModelProperty(value = "用户标签ids",required = true)
    @NotNull(message = "用户标签id不能为空")
    private List<Long> labelIds;

    /**
     * 用户标签分组id
     */
    @ApiModelProperty(value = "用户标签分组id",required = true)
    @NotNull(message = "用户标签分组id")
    private Long groupId;

}
@Data
@ApiModel(value = "用户标签分组修改请求对象", description = "用户标签分组修改请求对象")
public class UserLabelGroupUpdateDTO {

    /**
     * 用户标签分组id
     */
    @ApiModelProperty(value = "用户标签分组id",required = true)
    @NotNull(message = "用户标签分组id不能为空")
    private Long id;

    /**
     * 用户标签分组名称
     */
    @ApiModelProperty(value = "用户标签分组名称",required = true)
    @NotBlank(message = "用户标签分组名称不能为空")
    @Size(min = 1,max = 15,message = "业务类型名称长度在1到15之间")
    private String groupName;

}
@Data
@ApiModel(value = "用户标签修改请求对象", description = "用户标签修改请求对象")
public class UserLabelUpdateDTO {

    /**
     * 用户标签id
     */
    @ApiModelProperty(value = "用户标签id",required = true)
    @NotNull(message = "用户标签id不能位空")
    private Long id;


    /**
     * 用户标签名称
     */
    @ApiModelProperty(value = "用户标签名称",required = true)
    @NotBlank(message = "用户标签名称不能位空")
    @Size(min = 1,max = 15,message = "用户标签名称长度位1到15位")
    private String labelName;

    /**
     * 用户标签分组id
     */
    @ApiModelProperty(value = "用户标签分组id",required = true)
    @NotNull(message = "用户标签分组id不能为空")
    private Long groupId;

}
@Data
@ApiModel(value = "用户标签管理详情返回对象", description = "用户标签管理详情返回对象")
public class UserLabelDetailVO {

    /**
     * 标签id
     */
    @ApiModelProperty(value = "标签id")
    private Long id;

    /**
     * 标签名称
     */
    @ApiModelProperty(value = "标签名称")
    private String labelName;

}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(value = "用户标签组管理分页返回对象", description = "用户标签组管理分页返回对象")
public class UserLabelGroupPageVO {


    /**
     * id
     */
    @ApiModelProperty(value = "id")
    private Long id;


    /**
     * 分组名称
     */
    @ApiModelProperty(value = "分组名称")
    private String groupName;

    /**
     * 标签数据
     */
    @ApiModelProperty(value = "标签数据")
    private List<UserLabelDetailVO> labels;

}

你好:我的2025