refactor(admin): 重构管理模块VO包结构并新增标签管理功能
- 将分类相关VO移至com.hanserwei.admin.model.vo.category包下,用户相关VO移至user包 - 新增标签管理相关VO,包括AddTagReqVO、DeleteTagReqVO、FindTagPageListReqVO、FindTagPageListRspVO、SearchTagReqVO - 增加AdminTagController,实现标签的增删查和分页查询接口 - 实现AdminTagService及其Impl,完成标签的增删查分页功能 - 新增Tag实体及TagRepository,支持标签数据的持久化及模糊查询 - 优化AdminCategoryServiceImpl分页查询逻辑,提取公共分页查询工具类PageHelper - 修改CategoryRepository继承JpaSpecificationExecutor,支持动态查询 - 修改TokenAuthenticationFilter,限制JWT认证仅校验/admin路径请求 - 修改Category实体删除注解,调整逻辑删除实现 - 新增数据库脚本,创建t_tag标签表及相关索引和触发器 - 更新ResponseCodeEnum,增加TAG_NOT_EXIST和CATEGORY_NOT_EXIST错误码 - 调整.gitignore,忽略.idea下Apifox相关缓存文件
This commit is contained in:
@@ -27,7 +27,6 @@ import java.time.Instant;
|
||||
@Index(name = "idx_create_time", columnList = "create_time")
|
||||
})
|
||||
@SQLRestriction("is_deleted = false")
|
||||
@SQLDelete(sql = "UPDATE t_category SET is_deleted = true WHERE id = ?")
|
||||
public class Category implements Serializable {
|
||||
|
||||
@Serial
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.hanserwei.common.domain.dataobject;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
import org.hibernate.annotations.SQLRestriction;
|
||||
import org.hibernate.annotations.UpdateTimestamp;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Entity
|
||||
@Table(name = "t_tag", indexes = {
|
||||
@Index(name = "idx_tag_create_time", columnList = "create_time")
|
||||
})
|
||||
@SQLRestriction("is_deleted = false")
|
||||
public class Tag implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false, length = 60, unique = true)
|
||||
private String name;
|
||||
|
||||
@CreationTimestamp
|
||||
@Column(name = "create_time", nullable = false, updatable = false)
|
||||
private Instant createTime;
|
||||
|
||||
@UpdateTimestamp
|
||||
@Column(name = "update_time", nullable = false)
|
||||
private Instant updateTime;
|
||||
|
||||
@Column(name = "is_deleted", nullable = false)
|
||||
@Builder.Default
|
||||
private Boolean isDeleted = false;
|
||||
}
|
||||
@@ -5,8 +5,9 @@ import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
public interface CategoryRepository extends JpaRepository<Category, Long> {
|
||||
public interface CategoryRepository extends JpaRepository<Category, Long>, JpaSpecificationExecutor<Category> {
|
||||
boolean existsCategoryByName(String name);
|
||||
|
||||
Page<Category> findAll(Specification<Category> specification, Pageable pageable);
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.hanserwei.common.domain.repository;
|
||||
|
||||
import com.hanserwei.common.domain.dataobject.Tag;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface TagRepository extends JpaRepository<Tag, Long>, JpaSpecificationExecutor<Tag> {
|
||||
Collection<Tag> findByNameIn(List<String> names);
|
||||
|
||||
Page<Tag> findAll(Specification<Tag> specification, Pageable pageable);
|
||||
|
||||
/**
|
||||
* 根据标签名称模糊查询
|
||||
* @param name 标签名称关键词
|
||||
* @return 标签列表
|
||||
*/
|
||||
List<Tag> findByNameContaining(String name);
|
||||
|
||||
}
|
||||
@@ -18,8 +18,9 @@ public enum ResponseCodeEnum implements BaseExceptionInterface {
|
||||
UNAUTHORIZED("20002", "无访问权限,请先登录!"),
|
||||
FORBIDDEN("20004", "演示账号仅支持查询操作!"),
|
||||
USER_NOT_EXIST("2005", "有户不存在!"),
|
||||
CATEGORY_NAME_IS_EXISTED("20005", "该分类已存在,请勿重复添加!")
|
||||
;
|
||||
CATEGORY_NAME_IS_EXISTED("20005", "该分类已存在,请勿重复添加!"),
|
||||
TAG_NOT_EXIST("20006", "标签不存在!"),
|
||||
CATEGORY_NOT_EXIST("20007", "分类不存在!" );
|
||||
|
||||
// 异常码
|
||||
private final String errorCode;
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.hanserwei.common.utils;
|
||||
|
||||
import com.hanserwei.common.model.BasePageQuery;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 分页查询工具类
|
||||
* 用于抽取通用的分页查询逻辑
|
||||
*/
|
||||
public class PageHelper {
|
||||
|
||||
/**
|
||||
* 执行带条件的分页查询
|
||||
*
|
||||
* @param repository JPA Repository
|
||||
* @param pageQuery 分页查询参数
|
||||
* @param name 名称(用于模糊查询)
|
||||
* @param startDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @param converter DO 到 VO 的转换函数
|
||||
* @param <T> 实体类型
|
||||
* @param <R> 响应VO类型
|
||||
* @return 分页响应
|
||||
*/
|
||||
public static <T, R> PageResponse<R> findPageList(
|
||||
JpaSpecificationExecutor<T> repository,
|
||||
BasePageQuery pageQuery,
|
||||
String name,
|
||||
LocalDate startDate,
|
||||
LocalDate endDate,
|
||||
Function<T, R> converter) {
|
||||
|
||||
// 构建分页参数
|
||||
Pageable pageable = PageRequest.of(
|
||||
pageQuery.getCurrent().intValue() - 1,
|
||||
pageQuery.getSize().intValue(),
|
||||
Sort.by(Sort.Direction.DESC, "createTime")
|
||||
);
|
||||
|
||||
// 构建查询条件
|
||||
Specification<T> specification = (root, query, criteriaBuilder) -> {
|
||||
List<Predicate> predicates = new ArrayList<>();
|
||||
|
||||
// 名称模糊查询
|
||||
if (StringUtils.hasText(name)) {
|
||||
predicates.add(
|
||||
criteriaBuilder.like(root.get("name"), "%" + name.trim() + "%")
|
||||
);
|
||||
}
|
||||
|
||||
// 开始日期查询
|
||||
if (Objects.nonNull(startDate)) {
|
||||
predicates.add(
|
||||
criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), startDate)
|
||||
);
|
||||
}
|
||||
|
||||
// 结束日期查询
|
||||
if (Objects.nonNull(endDate)) {
|
||||
predicates.add(
|
||||
criteriaBuilder.lessThan(root.get("createTime"), endDate.plusDays(1).atStartOfDay())
|
||||
);
|
||||
}
|
||||
|
||||
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
|
||||
};
|
||||
|
||||
// 执行查询
|
||||
Page<T> page = repository.findAll(specification, pageable);
|
||||
|
||||
// DO 转 VO
|
||||
List<R> vos = page.getContent().stream()
|
||||
.map(converter)
|
||||
.toList();
|
||||
|
||||
return PageResponse.success(page, vos);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user