1、需求
实现一个影像资料库的功能,用树结构对资料进行分类
2、数据结构
通过id、pid表示父子关系
通过code表示层级关系
通过layer表示层级
通过sort进行排序
3、实体类
package org.jeecg.modules.image.entity;
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 com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.jeecg.common.system.base.entity.BaseSearchDTO;
import org.jeecg.common.system.base.support.Condition;
import org.jeecg.common.system.base.support.Match;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.springframework.data.annotation.Transient;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* @Description: 影像资料分类
* @Author: jeecg-boot
* @Date: 2024-05-28
* @Version: V1.0
*/
@Data
@TableName("img_classification")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@ApiModel(value = "img_classification对象", description = "影像资料分类")
public class ImgClassification extends BaseSearchDTO {
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_ID)
@ApiModelProperty(value = "主键")
private String id;
/**
* 创建人
*/
@ApiModelProperty(value = "创建人")
private String createBy;
/**
* 创建日期
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "创建日期")
private Date createTime;
/**
* 更新人
*/
@ApiModelProperty(value = "更新人")
private String updateBy;
/**
* 更新日期
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "更新日期")
private Date updateTime;
/**
* 所属部门
*/
@ApiModelProperty(value = "所属部门")
private String sysOrgCode;
/**
* 父id
*/
@Excel(name = "父id", width = 15)
@ApiModelProperty(value = "父id")
private String pid;
/**
* 分类编码
*/
@Excel(name = "分类编码", width = 15)
@ApiModelProperty(value = "分类编码")
@Condition(match = Match.LLIKE)
private String code;
/**
* 分类名称
*/
@Excel(name = "分类名称", width = 15)
@ApiModelProperty(value = "分类名称")
@Condition(match = Match.LIKE)
private String name;
/**
* 层级
*/
@Excel(name = "层级", width = 15)
@ApiModelProperty(value = "层级")
private Integer layer;
/**
* 排序
*/
@Excel(name = "排序", width = 15)
@ApiModelProperty(value = "排序")
private Integer sort;
/**
* 是否有子节点
*/
@Excel(name = "是否有子节点", width = 15)
@ApiModelProperty(value = "是否有子节点")
private Boolean hasChildren;
不在库里
/**
* 父级名称
*/
@TableField(exist = false)
@ApiModelProperty(value = "父级名称")
private String parentName;
/**
* 子集
*/
@Transient
@TableField(exist = false)
@ApiModelProperty(value = "子集")
private List<ImgClassification> children = new ArrayList<>();
}
4、控制器
package org.jeecg.modules.image.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.base.service.BaseService;
import org.jeecg.modules.image.entity.ImgClassification;
import org.jeecg.modules.image.service.IImgClassificationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* @Description: 影像资料分类
* @Author: jeecg-boot
* @Date: 2024-05-28
* @Version: V1.0
*/
@Api(tags = "1.0.1.0 影像资料分类")
@RestController
@RequestMapping("/image/imgClassification")
@Slf4j
public class ImgClassificationController extends JeecgController<ImgClassification, IImgClassificationService> {
@Autowired
private IImgClassificationService imgClassificationService;
@Autowired
private BaseService<ImgClassification> baseService;
// /**
// * 分页列表查询
// *
// * @param imgClassification
// * @param pageNo
// * @param pageSize
// * @param req
// * @return
// */
// //@AutoLog(value = "影像资料分类-分页列表查询")
// @ApiOperation(value = "影像资料分类-分页列表查询", notes = "影像资料分类-分页列表查询")
// @GetMapping(value = "/list")
// public Result<IPage<ImgClassification>> queryPageList(ImgClassification imgClassification,
// @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
// @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
// HttpServletRequest req) {
// QueryWrapper<ImgClassification> queryWrapper = QueryGenerator.initQueryWrapper(imgClassification, req.getParameterMap());
// Page<ImgClassification> page = new Page<ImgClassification>(pageNo, pageSize);
// IPage<ImgClassification> pageList = imgClassificationService.page(page, queryWrapper);
// return Result.OK(pageList);
// }
/**
* 分页列表查询
*
* @param imgClassification
* @return
*/
//@AutoLog(value = "影像资料分类-分页列表查询")
@ApiOperation(value = "影像资料分类-分页列表查询", notes = "影像资料分类-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<ImgClassification>> queryPageList(ImgClassification imgClassification) {
IPage<ImgClassification> pageList = baseService.selectPageByDTO(imgClassification);
return Result.OK(pageList);
}
/**
* 列表查询
*
* @param imgClassification
* @return
*/
@ApiOperation(value = "影像资料分类-列表查询", notes = "影像资料分类-列表查询")
@GetMapping(value = "/listAll")
public Result<List<ImgClassification>> listAll(ImgClassification imgClassification) {
List<ImgClassification> list = baseService.selectlistByDto(imgClassification);
return Result.OK(list);
}
/**
* 添加
*
* @param imgClassification
* @return
*/
@AutoLog(value = "影像资料分类-添加")
@ApiOperation(value = "影像资料分类-添加", notes = "影像资料分类-添加")
//@RequiresPermissions("image:img_classification:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody ImgClassification imgClassification) {
// imgClassificationService.save(imgClassification);
imgClassificationService.add(imgClassification);
return Result.OK("添加成功!");
}
/**
* 批量添加
*
* @param imgClassifications
* @return
*/
@AutoLog(value = "影像资料分类-批量添加")
@ApiOperation(value = "影像资料分类-批量添加", notes = "影像资料分类-批量添加")
@PostMapping(value = "/addBatch")
public Result<String> addBatch(@RequestBody List<ImgClassification> imgClassifications) {
// imgClassificationService.save(imgClassification);
imgClassificationService.addBatch(imgClassifications);
return Result.OK("添加成功!");
}
/**
* 编辑
*
* @param imgClassification
* @return
*/
@AutoLog(value = "影像资料分类-编辑")
@ApiOperation(value = "影像资料分类-编辑", notes = "影像资料分类-编辑")
//@RequiresPermissions("image:img_classification:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
public Result<String> edit(@RequestBody ImgClassification imgClassification) {
imgClassificationService.updateById(imgClassification);
return Result.OK("编辑成功!");
}
/**
* 通过id删除
*
* @param id
* @return
*/
@AutoLog(value = "影像资料分类-通过id删除")
@ApiOperation(value = "影像资料分类-通过id删除", notes = "影像资料分类-通过id删除")
//@RequiresPermissions("image:img_classification:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
// imgClassificationService.removeById(id);
imgClassificationService.delete(id);
return Result.OK("删除成功!");
}
/**
* 批量删除
*
* @param ids
* @return
*/
@AutoLog(value = "影像资料分类-批量删除")
@ApiOperation(value = "影像资料分类-批量删除", notes = "影像资料分类-批量删除")
//@RequiresPermissions("image:img_classification:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
// this.imgClassificationService.removeByIds(Arrays.asList(ids.split(",")));
imgClassificationService.deleteBatch(ids);
return Result.OK("批量删除成功!");
}
/**
* 通过id查询
*
* @param id
* @return
*/
//@AutoLog(value = "影像资料分类-通过id查询")
@ApiOperation(value = "影像资料分类-通过id查询", notes = "影像资料分类-通过id查询")
@GetMapping(value = "/queryById")
public Result<ImgClassification> queryById(@RequestParam(name = "id", required = true) String id) {
// ImgClassification imgClassification = imgClassificationService.getById(id);
ImgClassification imgClassification = imgClassificationService.queryById(id);
if (imgClassification == null) {
return Result.error("未找到对应数据");
}
return Result.OK(imgClassification);
}
/**
* 导出excel
*
* @param request
* @param imgClassification
*/
//@RequiresPermissions("image:img_classification:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, ImgClassification imgClassification) {
return super.exportXls(request, imgClassification, ImgClassification.class, "影像资料分类");
}
/**
* 通过excel导入数据
*
* @param request
* @param response
* @return
*/
//@RequiresPermissions("image:img_classification:importExcel")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
return super.importExcel(request, response, ImgClassification.class);
}
/**
* 获取树结构
*
* @param dto
* @return
*/
@PostMapping("/getTree")
@ApiOperation(value = "获取树结构")
public Result<?> getTree(@ApiParam(value = "查询条件")
@RequestBody ImgClassification dto) {
List<ImgClassification> tree = imgClassificationService.getTree(dto);
return Result.OK(tree);
}
/**
* 设置innercode码
*/
@ApiOperation(value = "设置innercode码", notes = "设置innercode码")
@GetMapping(value = "/initCode")
public Result<?> initCode() {
imgClassificationService.initCode();
return Result.OK("处理完成");
}
}
5、service层
package org.jeecg.modules.image.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.jeecg.modules.image.entity.ImgClassification;
import java.util.List;
/**
* @Description: 影像资料分类
* @Author: jeecg-boot
* @Date: 2024-05-28
* @Version: V1.0
*/
public interface IImgClassificationService extends IService<ImgClassification> {
List<ImgClassification> selectTree(ImgClassification dto);
List<ImgClassification> getTree(ImgClassification dto);
void initCode();
void add(ImgClassification imgClassification);
void delete(String id);
void addBatch(List<ImgClassification> imgClassifications);
void deleteBatch(String ids);
ImgClassification queryById(String id);
}
package org.jeecg.modules.image.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jeecg.common.exception.BusinessException;
import org.jeecg.common.system.base.service.BaseService;
import org.jeecg.common.util.StringUtil;
import org.jeecg.modules.image.entity.ImgClassification;
import org.jeecg.modules.image.entity.ImgLibrary;
import org.jeecg.modules.image.mapper.ImgClassificationMapper;
import org.jeecg.modules.image.service.IImgClassificationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
/**
* @Description: 影像资料分类
* @Author: jeecg-boot
* @Date: 2024-05-28
* @Version: V1.0
*/
@Service
public class ImgClassificationServiceImpl extends ServiceImpl<ImgClassificationMapper, ImgClassification> implements IImgClassificationService {
@Resource
ImgClassificationMapper mapper;
@Autowired
private BaseService<ImgClassification> baseService;
@Autowired
private BaseService<ImgLibrary> imgLibraryService;
@Override
public List<ImgClassification> selectTree(ImgClassification dto) {
return mapper.selectTree(dto);
}
@Override
public List<ImgClassification> getTree(ImgClassification dto) {
List<ImgClassification> returndemo = this.selectTree(dto);
List<ImgClassification> tree = Collections.synchronizedList(new ArrayList<>());
String id = "1";
if (StringUtil.isNotEmpty(dto.getId())) {
id = dto.getId();
}
if (StringUtil.isNotEmpty(returndemo)) {
String finalId = id;
returndemo.parallelStream().forEach(x -> {
if (finalId.equals(x.getId())) {
//现在做全局递归,之后更改
tree.add(findChildren(x, returndemo));
}
});
}
//根据日期进行升序排序
for (ImgClassification e : tree) {
e.setChildren(sort(e.getChildren()));
}
List<ImgClassification> treeAsce = sort(tree);
return treeAsce;
}
private List<ImgClassification> sort(List<ImgClassification> source) {
List<ImgClassification> treeAsce
= source.stream().sorted(Comparator.comparing(ImgClassification::getSort))
.collect(Collectors.toList());
for (ImgClassification e : source) {
if (e.getChildren().size() > 0) {
e.setChildren(sort(e.getChildren()));
}
}
return treeAsce;
}
/**
* @param node .
* @param lists .
* @return .
*/
private static ImgClassification findChildren(ImgClassification node, List<ImgClassification> lists) {
lists.parallelStream().forEach(y -> {
if (node.getId().equals(y.getPid())) {
if (node.getChildren() == null) {
node.setChildren(new ArrayList<ImgClassification>());
}
node.getChildren().add(findChildren(y, lists));
}
});
return node;
}
@Override
public void initCode() {
ImgClassification dto = new ImgClassification();
List<ImgClassification> treeList = getTree(dto);
dealInnerCode(treeList, true);
}
@Override
public void addBatch(List<ImgClassification> imgClassifications) {
for (ImgClassification imgClassification : imgClassifications) {
this.add(imgClassification);
}
}
@Override
public void add(ImgClassification imgClassification) {
//更新父节点的hasChildren
ImgClassification parent = this.queryById(imgClassification.getPid());
if (StringUtil.isEmpty(parent)) {
throw new BusinessException("未找到父节点");
}
parent.setHasChildren(true);
this.updateById(parent);
//更新本节点的层级、编码、排序
imgClassification = this.reDoEntity(parent, imgClassification);
//新增
this.save(imgClassification);
}
/**
* 获取分类的 层级layer、 编码code、 排序sort
*/
private ImgClassification reDoEntity(ImgClassification parent, ImgClassification imgClassification) {
String code = null;
//当前父节点有几个子节点
List<ImgClassification> childrenList = parent.getChildren();
int lastNumber = 1;
if (StringUtil.isEmpty(childrenList)) {
// 列表为空或null,处理这种情况
code = parent.getCode() + "-1";
} else {
//查询父节点下最新的一条记录
ImgClassification latestItem = childrenList.get(0); // 假设第一个元素是最新的
String latestCode = latestItem.getCode();
// 按 "-" 分割字符串
String[] parts = latestCode.split("-");
// 检查是否至少有一个部分
if (parts.length == 0) {
System.out.println("没有分隔符,找不到数值");
}
// 找到最后一个编号,并转换为整数
lastNumber = Integer.parseInt(parts[parts.length - 1]);
// 将最后一个编号加1
lastNumber++;
// 将加1后的整数转换回字符串
String lastNumberStr = String.valueOf(lastNumber);
// 替换原来的最后一个编号,并用 "-" 重新连接所有编号
// 如果只有一个部分,则不需要"-"
StringBuilder newS = new StringBuilder();
for (int i = 0; i < parts.length - 1; i++) {
newS.append(parts[i]).append("-");
}
newS.append(lastNumberStr);
code = newS.toString();
}
imgClassification.setCode(code);
imgClassification.setLayer(parent.getLayer() + 1);
if (StringUtil.isEmpty(imgClassification.getSort())) {
imgClassification.setSort(lastNumber + 1);
}
//更新本节点的hasChildren
imgClassification.setHasChildren(false);
return imgClassification;
}
@Override
public void deleteBatch(String ids) {
List<String> idList = Arrays.asList(ids.split(","));
if (StringUtil.isNotEmpty(idList)) {
for (String id : idList) {
this.delete(id);
}
}
}
@Override
public ImgClassification queryById(String id) {
ImgClassification imgClassification = this.getById(id);
//获取子节点
ImgClassification dto = new ImgClassification();
dto.setPid(id);
dto.setOrderby("create_time desc");
List<ImgClassification> childrenList = baseService.selectlistByDto(dto);
imgClassification.setChildren(childrenList);
return imgClassification;
}
/**
* 删除分类
* 1.根节点不允许删除
* 2.节点下挂了资料,不能删除
* 3.更新父节点的hasChildren
* 4.删除本节点
*
* @param id
*/
@Override
public void delete(String id) {
ImgClassification imgClassification = this.getById(id);
//根节点不允许删除
if (id.equals("1")) {
throw new BusinessException("根节点不允许删除。");
}
//判断分类下是否有资料,如果有,则不能删除
if (hasData(imgClassification)) {
throw new BusinessException(imgClassification.getName() + "分类下存在资料,不能删除。" + imgClassification.getCode() + ":" + imgClassification.getId());
}
//更新父节点的hasChildren
if (imgClassification != null) { //如果删除的是顶级节点,则父节点的hasChildren置为false
ImgClassification parent = this.queryById(imgClassification.getPid());
if (parent != null) {
List<ImgClassification> childrenList = parent.getChildren();
if (StringUtil.isNotEmpty(childrenList) && childrenList.size() == 1) {
parent.setHasChildren(false);
this.updateById(parent);
}
}
}
//删除本节点
this.removeById(id);
}
private Boolean hasData(ImgClassification imgClassification) {
ImgLibrary dto = new ImgLibrary();
dto.setClsCode(imgClassification.getCode());
List<ImgLibrary> imgLibraryList = imgLibraryService.selectlistByDto(dto);
if (imgLibraryList != null && !imgLibraryList.isEmpty()) {
return true;
}
return false;
}
public void dealInnerCode(List<ImgClassification> treeList, Boolean isTop) {
for (int i = 0; i < treeList.size(); i++) {
String thisId = treeList.get(i).getId();
String pId = treeList.get(i).getPid();
ImgClassification imgClassification = this.getById(thisId);
if (isTop) {
imgClassification.setCode("0");
} else {
imgClassification.setCode(getCodeById(pId) + (i + 1));
}
//更新
this.updateById(imgClassification);
List<ImgClassification> childrenList = treeList.get(i).getChildren();
if (StringUtil.isNotEmpty(childrenList)) {
dealInnerCode(childrenList, false);
}
}
}
public String getCodeById(String id) {
ImgClassification imgClassification = this.getById(id);
return imgClassification.getCode();
}
}
6、dao层
package org.jeecg.modules.image.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.jeecg.modules.image.entity.ImgClassification;
import java.util.List;
/**
* @Description: 影像资料分类
* @Author: jeecg-boot
* @Date: 2024-05-28
* @Version: V1.0
*/
public interface ImgClassificationMapper extends BaseMapper<ImgClassification> {
List<ImgClassification> selectTree(@Param("dto") ImgClassification dto);
}
7、xml层
<?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="org.jeecg.modules.image.mapper.ImgClassificationMapper">
<!-- 树结构-查父节点的名字 -->
<select id="selectTree"
parameterType="Object"
resultType="org.jeecg.modules.image.entity.ImgClassification">
SELECT t1.name AS parent_name,
t.*
FROM IMG_CLASSIFICATION t
LEFT JOIN IMG_CLASSIFICATION t1 ON t.pid = t1.id
WHERE 1 = 1
<if test="dto.name !=null and dto.name != ''">
AND t.name like concat(concat('%',#{dto.name}),'%')
</if>
ORDER BY
t1.CREATE_TIME,t.CREATE_TIME
</select>
</mapper>