完成标签维护功能

This commit is contained in:
2023-04-18 17:36:27 +08:00
parent 5a85e0c29f
commit 27b71b1cc2
9 changed files with 450 additions and 0 deletions
@@ -0,0 +1,13 @@
package com.adc.da.report.constant;
/**
* @author Caihaohan
*/
public class TreeLabelConstants {
public static final Integer DELETED = 1;
public static final Integer UNDELETE = 0;
public static final String ROOT_TAG_PARENT_ID = "0";
}
@@ -0,0 +1,76 @@
package com.adc.da.report.controller;
import cn.hutool.core.convert.Convert;
import com.adc.da.report.eo.TreeLabelEntity;
import com.adc.da.report.service.ITreeLabelService;
import com.adc.da.report.vo.TreeLabelVo;
import com.adc.da.util.http.ResponseMessage;
import com.adc.da.util.http.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.subject.ExecutionException;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Caihaohan
*/
@Slf4j
@RestController
@Api(tags = "树型标签管理")
@RequestMapping("/${restPath}/tree-label")
public class TreeLabelManagerController {
@Resource
private ITreeLabelService iTreeLabelService;
/**
* 新增或编辑标签
*
* @param treeLabelVo
* @return
*/
@ApiOperation("新增或编辑标签")
@PostMapping("/add")
public ResponseMessage add(@Valid @RequestBody TreeLabelVo treeLabelVo) {
TreeLabelEntity treeLabelEntity = Convert.convert(TreeLabelEntity.class, treeLabelVo);
iTreeLabelService.saveOrUpdateTag(treeLabelEntity);
return Result.success();
}
/**
* 标签列表
*
* @return
* @throws ExecutionException
* @throws InterruptedException
*/
@ApiOperation("标签列表")
@GetMapping("/list")
public ResponseMessage list(@RequestParam(value = "like", required = false) String like
) throws ExecutionException, InterruptedException {
List<TreeLabelVo> rootLabel = iTreeLabelService.getTreeLabellist(like);
return Result.success(rootLabel);
}
@ApiOperation("标签删除|单个")
@PostMapping("/delete/{id}")
public ResponseMessage delete(@PathVariable("id") String id) {
Map<String, Object> map = new HashMap<>();
String status = "0";
boolean isDelete = iTreeLabelService.deleteById(id);
if (!isDelete) {
status = "1";
}
map.put("status", status);
return Result.success(map);
}
}
@@ -0,0 +1,24 @@
package com.adc.da.report.dao.mysql;
import com.adc.da.report.eo.TreeLabelEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author ThinkBook
* @description 针对表【ts_tree_label】的数据库操作Mapper
* @createDate 2023-04-18 10:18:44
* @Entity com.adc.da.report.eo.TreeLabelEntity
*/
public interface TreeLabelDao extends BaseMapper<TreeLabelEntity> {
/**
* 获取当前层级标签中最大的orderNum
* @param parentId
* @return
*/
int getMaxNum(String parentId);
}
@@ -0,0 +1,59 @@
package com.adc.da.report.eo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
*
* @author Caihaohan
* @TableName ts_tree_label
*/
@TableName(value ="ts_tree_label")
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class TreeLabelEntity implements Serializable {
/**
*
*/
@TableId(value = "id",type = IdType.INPUT)
private String id;
/**
*
*/
private String name;
/**
*
*/
private String parentId;
/**
*
*/
private String createDate;
/**
*
*/
private Integer orderNum;
/**
* 0代表未删除,1代表已删除
*/
private Integer delFlag;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}
@@ -0,0 +1,41 @@
package com.adc.da.report.service;
import com.adc.da.report.eo.TreeLabelEntity;
import com.adc.da.report.vo.TreeLabelVo;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* @author ThinkBook
* @description 针对表【ts_tree_label】的数据库操作Service
* @createDate 2023-04-18 10:18:44
*/
public interface ITreeLabelService extends IService<TreeLabelEntity> {
/**
* 返回树形结构
*
* @return
*/
List<TreeLabelVo> getTreeLabellist(String like);
/**
* 插入或更新标签
* @param treeLabelEntity
*/
void saveOrUpdateTag(TreeLabelEntity treeLabelEntity);
/**
* 自动维护顺序的删除标签方法
*/
boolean deleteByIdAutoOrder(String id);
/**
* 删除标签
* @param id
* @return
*/
boolean deleteById(String id);
}
@@ -0,0 +1,165 @@
package com.adc.da.report.service.impl;
import cn.hutool.core.convert.Convert;
import com.adc.da.report.constant.TreeLabelConstants;
import com.adc.da.report.vo.TreeLabelVo;
import com.adc.da.util.exception.AdcDaBaseException;
import com.adc.da.util.utils.StringUtils;
import com.adc.da.util.utils.UUID;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.adc.da.report.eo.TreeLabelEntity;
import com.adc.da.report.service.ITreeLabelService;
import com.adc.da.report.dao.mysql.TreeLabelDao;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author ThinkBook
* @description 针对表【ts_tree_label】的数据库操作Service实现
* @createDate 2023-04-18 10:18:44
*/
@Service
public class ITreeLabelServiceImpl extends ServiceImpl<TreeLabelDao, TreeLabelEntity>
implements ITreeLabelService {
@Resource
private TreeLabelDao treeLabelDao;
@Override
public List<TreeLabelVo> getTreeLabellist(String like) {
//查询所有未删除的标签
LambdaQueryWrapper<TreeLabelEntity> treeLabelEntityWrapper = new LambdaQueryWrapper<>();
treeLabelEntityWrapper.eq(TreeLabelEntity::getDelFlag, TreeLabelConstants.UNDELETE);
List<TreeLabelEntity> treeLabelEntities = treeLabelDao.selectList(treeLabelEntityWrapper);
//找出根节点
TreeLabelEntity rootTag = treeLabelEntities.stream().
filter(treeLabelEntity ->
TreeLabelConstants.ROOT_TAG_PARENT_ID.equals(treeLabelEntity.getParentId()))
.collect(Collectors.toList()).get(0);
List<TreeLabelVo> treeLabelVos = Convert.toList(TreeLabelVo.class, treeLabelEntities);
//分组排序
Map<String, List<TreeLabelVo>> groupedLabelVos = treeLabelVos.stream()
.collect(Collectors.groupingBy(TreeLabelVo::getParentId));
//排序
Map<String, List<TreeLabelVo>> sortedGroupedLabelVos = groupedLabelVos.entrySet().stream()
.map(entry -> {
List<TreeLabelVo> sortedList = entry.getValue();
sortedList.sort(Comparator.comparing(TreeLabelVo::getOrderNum));
return new AbstractMap.SimpleEntry<>(entry.getKey(), sortedList);
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
//合并
List<TreeLabelVo> labelVoList = sortedGroupedLabelVos.values().stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
//组装成树形结构
List<TreeLabelVo> tree = createTree(rootTag.getParentId(), labelVoList);
//模糊查询
if (StringUtils.isNoneBlank(like)) {
TreeLabelVo treeLabelVo = filterByName(tree.get(0), like);
if (Objects.nonNull(treeLabelVo)) {
return Collections.singletonList(treeLabelVo);
}
return Collections.singletonList(Convert.convert(TreeLabelVo.class, rootTag));
}
return tree;
}
@Override
public void saveOrUpdateTag(TreeLabelEntity entity) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//不能和根节点的父ID相同
if (TreeLabelConstants.ROOT_TAG_PARENT_ID.equals(entity.getParentId())) {
throw new AdcDaBaseException("不能和根节点的上级标签相同");
}
int count = treeLabelDao.selectCount(new QueryWrapper<TreeLabelEntity>()
.eq("id", entity.getParentId()));
if (count == 0) {
throw new AdcDaBaseException("上级标签不存在");
}
//新增标签
if (StringUtils.isEmpty(entity.getId())) {
entity.setId(UUID.randomUUID10());
entity.setCreateDate(format.format(new Date()));
treeLabelDao.insert(entity);
} else {
//编辑标签
treeLabelDao.updateById(entity);
}
}
@Override
public boolean deleteByIdAutoOrder(String id) {
TreeLabelEntity labelEntity = treeLabelDao.selectById(id);
String parentId = labelEntity.getParentId();
int currentNum = labelEntity.getOrderNum();
int maxNum = treeLabelDao.getMaxNum(parentId);
//删除标签
treeLabelDao.delete(new QueryWrapper<TreeLabelEntity>().eq("id", id));
//如果删除的不是最后一个标签,需要移动前面的标签
if (currentNum != maxNum) {
LambdaQueryWrapper<TreeLabelEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.gt(TreeLabelEntity::getOrderNum, currentNum)
.le(TreeLabelEntity::getOrderNum, maxNum)
.eq(TreeLabelEntity::getParentId, parentId);
List<TreeLabelEntity> labelList = treeLabelDao.selectList(wrapper);
for (TreeLabelEntity entity : labelList) {
entity.setOrderNum(entity.getOrderNum() - 1);
treeLabelDao.updateById(entity);
}
}
return true;
}
@Override
public boolean deleteById(String id) {
int i = treeLabelDao.deleteById(id);
return i != 0;
}
private List<TreeLabelVo> createTree(String rootParentId, List<TreeLabelVo> treeLabelVos) {
List<TreeLabelVo> tree = new ArrayList<>();
for (TreeLabelVo label : treeLabelVos) {
if (label.getParentId().equals(rootParentId)) {
label.setChildLabel(createTree(label.getId(), treeLabelVos));
tree.add(label);
}
}
return tree;
}
public static TreeLabelVo filterByName(TreeLabelVo root, String name) {
TreeLabelVo newRoot = new TreeLabelVo();
newRoot.setId(root.getId());
newRoot.setName(root.getName());
newRoot.setParentId(root.getParentId());
newRoot.setOrderNum(root.getOrderNum());
List<TreeLabelVo> childLabel = new ArrayList<>();
if (root.getChildLabel() != null) {
for (TreeLabelVo child : root.getChildLabel()) {
TreeLabelVo newChild = filterByName(child, name);
if (newChild != null) {
childLabel.add(newChild);
}
}
}
newRoot.setChildLabel(childLabel.isEmpty() ? null : childLabel);
return root.getName().contains(name) || !childLabel.isEmpty() ? newRoot : null;
}
}
@@ -0,0 +1,51 @@
package com.adc.da.report.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;
/**
* @author ThinkBook
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class TreeLabelVo {
/**
* id
*/
private String id;
/**
* 标签名称
*/
@NotBlank(message = "名称不能为空")
private String name;
/**
* 父id
*/
private String parentId;
/**
*
*/
private Integer orderNum;
/**
* 子标签
*/
private List<TreeLabelVo> childLabel;
public TreeLabelVo(String parentId) {
this.parentId = parentId;
this.childLabel = new ArrayList<>();
}
}
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.adc.da.report.dao.mysql.TreeLabelDao">
<resultMap id="BaseResultMap" type="com.adc.da.report.eo.TreeLabelEntity">
<id property="id" column="id" jdbcType="VARCHAR"/>
<result property="name" column="name" jdbcType="VARCHAR"/>
<result property="parentid" column="parentId" jdbcType="VARCHAR"/>
<result property="createdate" column="createDate" jdbcType="TIMESTAMP"/>
<result property="ordernum" column="orderNum" jdbcType="INTEGER"/>
<result property="delFlag" column="del_flag" jdbcType="TINYINT"/>
</resultMap>
<select id="getMaxNum" parameterType="string" resultType="int">
select max(t.orderNum)
from TS_TREE_LABEL t
where parentid = #{parentId}
</select>
</mapper>