diff --git a/src/main/java/com/zsc/edu/gateway/common/enums/EnableState.java b/src/main/java/com/zsc/edu/gateway/common/enums/EnableState.java new file mode 100644 index 0000000..06c6151 --- /dev/null +++ b/src/main/java/com/zsc/edu/gateway/common/enums/EnableState.java @@ -0,0 +1,23 @@ +package com.zsc.edu.gateway.common.enums; + +import com.baomidou.mybatisplus.annotation.IEnum; + +public enum EnableState implements IEnum { + ENABLE(Boolean.TRUE), + DISABLE(Boolean.FALSE); + + private boolean value; + + EnableState(Boolean value) { + this.value = value; + } + + @Override + public Boolean getValue() { + return this.value; + } + + public EnableState reverse() { + return this == ENABLE ? DISABLE : ENABLE; + } +} diff --git a/src/main/java/com/zsc/edu/gateway/common/enums/IState.java b/src/main/java/com/zsc/edu/gateway/common/enums/IState.java new file mode 100644 index 0000000..7d63a58 --- /dev/null +++ b/src/main/java/com/zsc/edu/gateway/common/enums/IState.java @@ -0,0 +1,36 @@ +package com.zsc.edu.gateway.common.enums; + + +import com.zsc.edu.gateway.exception.StateException; + +import java.util.EnumSet; + +/** + * @author harry_yao + */ +public interface IState> { + + /** + * 用于检查对象当前状态是否等于correctStatus + * + * @param correctState 正确状态 + */ + default void checkStatus(T correctState) { + if (this != correctState) { + throw new StateException(correctState.getClass(), this, correctState); + } + } + + /** + * 用于检查对象当前状态是否在集合correctStates中 + * + * @param correctStates 正确状态集合 + */ + @SuppressWarnings("SuspiciousMethodCalls") + default void checkStatus(EnumSet correctStates) { + if (!correctStates.contains(this)) { + throw new StateException(this.getClass(), this, correctStates); + } + } + +} diff --git a/src/main/java/com/zsc/edu/gateway/common/mapstruct/BaseMapper.java b/src/main/java/com/zsc/edu/gateway/common/mapstruct/BaseMapper.java new file mode 100644 index 0000000..e7109e6 --- /dev/null +++ b/src/main/java/com/zsc/edu/gateway/common/mapstruct/BaseMapper.java @@ -0,0 +1,23 @@ +package com.zsc.edu.gateway.common.mapstruct; + +import org.mapstruct.MappingTarget; + +import java.util.List; + +public interface BaseMapper { + D toDto(E entity); + + E toEntity(D dto); + + List toDto(List entityList); + + List toEntity(List dtoList); + + /** + * 更新实体类 + * + * @param dto + * @param entity + */ + void convert(D dto, @MappingTarget E entity); +} diff --git a/src/main/java/com/zsc/edu/gateway/common/util/TreeUtil.java b/src/main/java/com/zsc/edu/gateway/common/util/TreeUtil.java new file mode 100644 index 0000000..312f984 --- /dev/null +++ b/src/main/java/com/zsc/edu/gateway/common/util/TreeUtil.java @@ -0,0 +1,130 @@ +package com.zsc.edu.gateway.common.util; + +import java.util.*; +import java.util.function.*; +import java.util.stream.Collectors; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; + +/** + * @Description: 树操作方法工具类 + * @Copyright: Copyright (c) 赵侠客 + * @Date: 2024-07-22 10:42 + * @Version: 1.0 + */ +public class TreeUtil { + + /** + * 将list合成树 + * + * @param list 需要合成树的List + * @param rootCheck 判断E中为根节点的条件,如:x->x.getPId()==-1L , x->x.getParentId()==null,x->x.getParentMenuId()==0 + * @param parentCheck 判断E中为父节点条件,如:(x,y)->x.getId().equals(y.getPId()) + * @param setSubChildren E中设置下级数据方法,如:Menu::setSubMenus + * @param 泛型实体对象 + * @return 合成好的树 + */ + public static List makeTree(List list, Predicate rootCheck, BiFunction parentCheck, BiConsumer> setSubChildren) { + return list.stream().filter(rootCheck).peek(x -> setSubChildren.accept(x, makeChildren(x, list, parentCheck, setSubChildren))).collect(Collectors.toList()); + } + + /** + * 将树打平成tree + * + * @param tree 需要打平的树 + * @param getSubChildren 设置下级数据方法,如:Menu::getSubMenus,x->x.setSubMenus(null) + * @param setSubChildren 将下级数据置空方法,如:x->x.setSubMenus(null) + * @param 泛型实体对象 + * @return 打平后的数据 + */ + public static List flat(List tree, Function> getSubChildren, Consumer setSubChildren) { + List res = new ArrayList<>(); + forPostOrder(tree, item -> { + setSubChildren.accept(item); + res.add(item); + }, getSubChildren); + return res; + } + + /** + * 前序遍历 + * + * @param tree 需要遍历的树 + * @param consumer 遍历后对单个元素的处理方法,如:x-> System.out.println(x)、 System.out::println打印元素 + * @param setSubChildren 设置下级数据方法,如:Menu::getSubMenus,x->x.setSubMenus(null) + * @param 泛型实体对象 + */ + public static void forPreOrder(List tree, Consumer consumer, Function> setSubChildren) { + for (E l : tree) { + consumer.accept(l); + List es = setSubChildren.apply(l); + if (es != null && es.size() > 0) { + forPreOrder(es, consumer, setSubChildren); + } + } + } + + /** + * 层序遍历 + * + * @param tree 需要遍历的树 + * @param consumer 遍历后对单个元素的处理方法,如:x-> System.out.println(x)、 System.out::println打印元素 + * @param setSubChildren 设置下级数据方法,如:Menu::getSubMenus,x->x.setSubMenus(null) + * @param 泛型实体对象 + */ + public static void forLevelOrder(List tree, Consumer consumer, Function> setSubChildren) { + Queue queue = new LinkedList<>(tree); + while (!queue.isEmpty()) { + E item = queue.poll(); + consumer.accept(item); + List childList = setSubChildren.apply(item); + if (childList != null && !childList.isEmpty()) { + queue.addAll(childList); + } + } + } + + /** + * 后序遍历 + * + * @param tree 需要遍历的树 + * @param consumer 遍历后对单个元素的处理方法,如:x-> System.out.println(x)、 System.out::println打印元素 + * @param setSubChildren 设置下级数据方法,如:Menu::getSubMenus,x->x.setSubMenus(null) + * @param 泛型实体对象 + */ + public static void forPostOrder(List tree, Consumer consumer, Function> setSubChildren) { + for (E item : tree) { + List childList = setSubChildren.apply(item); + if (childList != null && !childList.isEmpty()) { + forPostOrder(childList, consumer, setSubChildren); + } + consumer.accept(item); + } + } + + /** + * 对树所有子节点按comparator排序 + * + * @param tree 需要排序的树 + * @param comparator 排序规则Comparator,如:Comparator.comparing(MenuVo::getRank)按Rank正序 ,(x,y)->y.getRank().compareTo(x.getRank()),按Rank倒序 + * @param getChildren 获取下级数据方法,如:MenuVo::getSubMenus + * @param 泛型实体对象 + * @return 排序好的树 + */ + public static List sort(List tree, Comparator comparator, Function> getChildren) { + for (E item : tree) { + List childList = getChildren.apply(item); + if (childList != null && !childList.isEmpty()) { + sort(childList, comparator, getChildren); + } + } + tree.sort(comparator); + return tree; + } + + private static List makeChildren(E parent, List allData, BiFunction parentCheck, BiConsumer> children) { + return allData.stream().filter(x -> parentCheck.apply(parent, x)).peek(x -> children.accept(x, makeChildren(x, allData, parentCheck, children))).collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/zsc/edu/gateway/framework/DeptTreeUtil.java b/src/main/java/com/zsc/edu/gateway/framework/DeptTreeUtil.java new file mode 100644 index 0000000..544aaef --- /dev/null +++ b/src/main/java/com/zsc/edu/gateway/framework/DeptTreeUtil.java @@ -0,0 +1,69 @@ +package com.zsc.edu.gateway.framework; + +import com.zsc.edu.gateway.modules.system.entity.Dept; +import com.zsc.edu.gateway.modules.system.entity.User; +import com.zsc.edu.gateway.modules.system.vo.DeptTree; +import com.zsc.edu.gateway.modules.system.vo.UserTree; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +/** + * @author zhuang + */ +@Component +public class DeptTreeUtil { + + public static List makeTree(List list, Predicate rootCheck, BiFunction parentCheck, BiConsumer> setSubChildren) { + return list.stream() + .filter(rootCheck) + .peek(x -> setSubChildren.accept(x, makeChildren(x, list, parentCheck, setSubChildren))) + .collect(Collectors.toList()); + } + + private static List makeChildren(E parent, List allData, BiFunction parentCheck, BiConsumer> setSubChildren) { + return allData.stream() + .filter(x -> parentCheck.apply(parent, x)) + .peek(x -> setSubChildren.accept(x, makeChildren(x, allData, parentCheck, setSubChildren))) + .collect(Collectors.toList()); + } + + public static List buildDeptTree(List depots, Map> userMap) { + List deptTrees = depots.stream() + .map(DeptTreeUtil::convertToDeptTree) + .collect(Collectors.toList()); + + deptTrees.forEach(deptTree -> { + List users = userMap.getOrDefault(deptTree.getId(), Collections.emptyList()); + deptTree.setMembers(users.stream() + .map(DeptTreeUtil::convertToUserTree) + .collect(Collectors.toList())); + }); + + return makeTree( + deptTrees, + deptTree -> deptTree.getPid() == null || deptTree.getPid() == 0L, + (parent, child) -> parent.getId().equals(child.getPid()), + DeptTree::setChildren + ); + } + + private static DeptTree convertToDeptTree(Dept dept) { + DeptTree deptTree = new DeptTree(); + deptTree.setId(dept.getId()); + deptTree.setPid(dept.getPid()); + deptTree.setName(dept.getName()); + return deptTree; + } + + private static UserTree convertToUserTree(User user) { + UserTree userTree = new UserTree(); + userTree.setId(user.getId()); + userTree.setName(user.getName()); + return userTree; + } +} diff --git a/src/main/java/com/zsc/edu/gateway/framework/JsonExceptionUtil.java b/src/main/java/com/zsc/edu/gateway/framework/JsonExceptionUtil.java new file mode 100644 index 0000000..2bb5042 --- /dev/null +++ b/src/main/java/com/zsc/edu/gateway/framework/JsonExceptionUtil.java @@ -0,0 +1,21 @@ +package com.zsc.edu.gateway.framework; + +import org.springframework.http.HttpStatus; + +import java.util.Calendar; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author harry yao + */ +public class JsonExceptionUtil { + public static Map jsonExceptionResult(HttpStatus code, String message, String path) { + Map exceptionMap = new LinkedHashMap<>(); + exceptionMap.put("timestamp", Calendar.getInstance().getTime()); + exceptionMap.put("message", message); + exceptionMap.put("path", path); + exceptionMap.put("code", code.value()); + return exceptionMap; + } +} diff --git a/src/main/java/com/zsc/edu/gateway/framework/TreeUtil.java b/src/main/java/com/zsc/edu/gateway/framework/TreeUtil.java new file mode 100644 index 0000000..2fb31cb --- /dev/null +++ b/src/main/java/com/zsc/edu/gateway/framework/TreeUtil.java @@ -0,0 +1,130 @@ +package com.zsc.edu.gateway.framework; + +import java.util.*; +import java.util.function.*; +import java.util.stream.Collectors; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; + +/** + * @Description: 树操作方法工具类 + * @Copyright: Copyright (c) 赵侠客 + * @Date: 2024-07-22 10:42 + * @Version: 1.0 + */ +public class TreeUtil { + + /** + * 将list合成树 + * + * @param list 需要合成树的List + * @param rootCheck 判断E中为根节点的条件,如:x->x.getPId()==-1L , x->x.getParentId()==null,x->x.getParentMenuId()==0 + * @param parentCheck 判断E中为父节点条件,如:(x,y)->x.getId().equals(y.getPId()) + * @param setSubChildren E中设置下级数据方法,如:Menu::setSubMenus + * @param 泛型实体对象 + * @return 合成好的树 + */ + public static List makeTree(List list, Predicate rootCheck, BiFunction parentCheck, BiConsumer> setSubChildren) { + return list.stream().filter(rootCheck).peek(x -> setSubChildren.accept(x, makeChildren(x, list, parentCheck, setSubChildren))).collect(Collectors.toList()); + } + + /** + * 将树打平成tree + * + * @param tree 需要打平的树 + * @param getSubChildren 设置下级数据方法,如:Menu::getSubMenus,x->x.setSubMenus(null) + * @param setSubChildren 将下级数据置空方法,如:x->x.setSubMenus(null) + * @param 泛型实体对象 + * @return 打平后的数据 + */ + public static List flat(List tree, Function> getSubChildren, Consumer setSubChildren) { + List res = new ArrayList<>(); + forPostOrder(tree, item -> { + setSubChildren.accept(item); + res.add(item); + }, getSubChildren); + return res; + } + + /** + * 前序遍历 + * + * @param tree 需要遍历的树 + * @param consumer 遍历后对单个元素的处理方法,如:x-> System.out.println(x)、 System.out::println打印元素 + * @param setSubChildren 设置下级数据方法,如:Menu::getSubMenus,x->x.setSubMenus(null) + * @param 泛型实体对象 + */ + public static void forPreOrder(List tree, Consumer consumer, Function> setSubChildren) { + for (E l : tree) { + consumer.accept(l); + List es = setSubChildren.apply(l); + if (es != null && es.size() > 0) { + forPreOrder(es, consumer, setSubChildren); + } + } + } + + /** + * 层序遍历 + * + * @param tree 需要遍历的树 + * @param consumer 遍历后对单个元素的处理方法,如:x-> System.out.println(x)、 System.out::println打印元素 + * @param setSubChildren 设置下级数据方法,如:Menu::getSubMenus,x->x.setSubMenus(null) + * @param 泛型实体对象 + */ + public static void forLevelOrder(List tree, Consumer consumer, Function> setSubChildren) { + Queue queue = new LinkedList<>(tree); + while (!queue.isEmpty()) { + E item = queue.poll(); + consumer.accept(item); + List childList = setSubChildren.apply(item); + if (childList != null && !childList.isEmpty()) { + queue.addAll(childList); + } + } + } + + /** + * 后序遍历 + * + * @param tree 需要遍历的树 + * @param consumer 遍历后对单个元素的处理方法,如:x-> System.out.println(x)、 System.out::println打印元素 + * @param setSubChildren 设置下级数据方法,如:Menu::getSubMenus,x->x.setSubMenus(null) + * @param 泛型实体对象 + */ + public static void forPostOrder(List tree, Consumer consumer, Function> setSubChildren) { + for (E item : tree) { + List childList = setSubChildren.apply(item); + if (childList != null && !childList.isEmpty()) { + forPostOrder(childList, consumer, setSubChildren); + } + consumer.accept(item); + } + } + + /** + * 对树所有子节点按comparator排序 + * + * @param tree 需要排序的树 + * @param comparator 排序规则Comparator,如:Comparator.comparing(MenuVo::getRank)按Rank正序 ,(x,y)->y.getRank().compareTo(x.getRank()),按Rank倒序 + * @param getChildren 获取下级数据方法,如:MenuVo::getSubMenus + * @param 泛型实体对象 + * @return 排序好的树 + */ + public static List sort(List tree, Comparator comparator, Function> getChildren) { + for (E item : tree) { + List childList = getChildren.apply(item); + if (childList != null && !childList.isEmpty()) { + sort(childList, comparator, getChildren); + } + } + tree.sort(comparator); + return tree; + } + + private static List makeChildren(E parent, List allData, BiFunction parentCheck, BiConsumer> children) { + return allData.stream().filter(x -> parentCheck.apply(parent, x)).peek(x -> children.accept(x, makeChildren(x, allData, parentCheck, children))).collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/zsc/edu/gateway/modules/notice/entity/BulletinUser.java b/src/main/java/com/zsc/edu/gateway/modules/notice/entity/BulletinUser.java new file mode 100644 index 0000000..16c3f19 --- /dev/null +++ b/src/main/java/com/zsc/edu/gateway/modules/notice/entity/BulletinUser.java @@ -0,0 +1,31 @@ +package com.zsc.edu.gateway.modules.notice.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * @author zhuang + */ +@Setter +@Getter +@NoArgsConstructor +@AllArgsConstructor +@TableName("sys_bulletin_user") +public class BulletinUser { + + /** + * 公告ID + */ + public Long bulletinId; + /** + * 用户ID + */ + public Long userId; + /** + * 是否已读 + */ + public Boolean isRead = true; +} diff --git a/src/main/java/com/zsc/edu/gateway/modules/notice/mapper/BulletinAttachmentMapper.java b/src/main/java/com/zsc/edu/gateway/modules/notice/mapper/BulletinAttachmentMapper.java new file mode 100644 index 0000000..e3b4d0e --- /dev/null +++ b/src/main/java/com/zsc/edu/gateway/modules/notice/mapper/BulletinAttachmentMapper.java @@ -0,0 +1,15 @@ +package com.zsc.edu.gateway.modules.notice.mapper; + +import com.zsc.edu.gateway.common.mapstruct.BaseMapper; +import com.zsc.edu.gateway.modules.notice.dto.BulletinAttachmentDto; +import com.zsc.edu.gateway.modules.notice.entity.BulletinAttachment; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** + * @author zhuang + */ +@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface BulletinAttachmentMapper extends BaseMapper { + +} diff --git a/src/main/java/com/zsc/edu/gateway/modules/notice/repo/BulletinUserRepository.java b/src/main/java/com/zsc/edu/gateway/modules/notice/repo/BulletinUserRepository.java new file mode 100644 index 0000000..79d8b52 --- /dev/null +++ b/src/main/java/com/zsc/edu/gateway/modules/notice/repo/BulletinUserRepository.java @@ -0,0 +1,16 @@ +package com.zsc.edu.gateway.modules.notice.repo; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.zsc.edu.gateway.modules.notice.entity.BulletinUser; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +/** + * @author zhuang + */ +public interface BulletinUserRepository extends BaseMapper { + +// @Select("select * from sys_bulletin_user sbu where sbu.bulletin_id=#{bulletinId} and sbu.user_id=#{userId}") +// Boolean selectByBulletinIdAndUserId(@Param("bulletinId") Long bulletinId, @Param("userId") Long userId); +} diff --git a/src/main/java/com/zsc/edu/gateway/modules/notice/service/BulletinUserService.java b/src/main/java/com/zsc/edu/gateway/modules/notice/service/BulletinUserService.java new file mode 100644 index 0000000..23a6996 --- /dev/null +++ b/src/main/java/com/zsc/edu/gateway/modules/notice/service/BulletinUserService.java @@ -0,0 +1,16 @@ +package com.zsc.edu.gateway.modules.notice.service; + + +import com.baomidou.mybatisplus.extension.service.IService; +import com.zsc.edu.gateway.framework.security.UserDetailsImpl; +import com.zsc.edu.gateway.modules.notice.entity.BulletinUser; + +/** + * @author zhuang + */ +public interface BulletinUserService extends IService { + + Boolean isRead(UserDetailsImpl userDetails, Long id); + + void toggleIsRead(Long id); +} diff --git a/src/main/java/com/zsc/edu/gateway/modules/notice/service/impl/BulletinUserServiceImpl.java b/src/main/java/com/zsc/edu/gateway/modules/notice/service/impl/BulletinUserServiceImpl.java new file mode 100644 index 0000000..4ecd28b --- /dev/null +++ b/src/main/java/com/zsc/edu/gateway/modules/notice/service/impl/BulletinUserServiceImpl.java @@ -0,0 +1,61 @@ +package com.zsc.edu.gateway.modules.notice.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.zsc.edu.gateway.framework.security.UserDetailsImpl; +import com.zsc.edu.gateway.modules.notice.entity.BulletinUser; +import com.zsc.edu.gateway.modules.notice.repo.BulletinUserRepository; +import com.zsc.edu.gateway.modules.notice.service.BulletinUserService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + + +/** + * @author zhuang + */ +@AllArgsConstructor +@Service +public class BulletinUserServiceImpl extends ServiceImpl implements BulletinUserService { + + /** + * 已读公告,每次已读自动获取用户id与公告id加入联表 + * + * @param userDetails userDetails + * @param id id + * return true + */ + @Override + public Boolean isRead(UserDetailsImpl userDetails, Long id) { + if (id == null || userDetails.getId() == null) { + throw new IllegalArgumentException("Bulletin ID and User ID cannot be null"); + } + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("bulletin_id", id) + .eq("user_id", userDetails.getId()); + BulletinUser existingUser = getOne(queryWrapper); + if (existingUser == null) { + BulletinUser newUser = new BulletinUser(); + newUser.setBulletinId(id); + newUser.setUserId(userDetails.getId()); + newUser.setIsRead(false); + save(newUser); + } else { + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.eq("bulletin_id", id).eq("user_id", userDetails.getId()).set("is_read", false); + } + return true; + } + + /** + * 更新公告后修改已读状态 + * + * @param id id + */ + @Override + public void toggleIsRead(Long id) { + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.eq("bulletin_id", id).set("is_read", true); + } + +} diff --git a/src/main/java/com/zsc/edu/gateway/modules/system/vo/DeptTree.java b/src/main/java/com/zsc/edu/gateway/modules/system/vo/DeptTree.java new file mode 100644 index 0000000..93a3657 --- /dev/null +++ b/src/main/java/com/zsc/edu/gateway/modules/system/vo/DeptTree.java @@ -0,0 +1,26 @@ +package com.zsc.edu.gateway.modules.system.vo; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.zsc.edu.gateway.modules.system.entity.User; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author zhuang + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DeptTree { + + private Long id; + @JsonIgnore + private Long pid; + private String name; + List children = new ArrayList<>(); + List members = new ArrayList<>(); +} diff --git a/src/main/java/com/zsc/edu/gateway/modules/system/vo/UserTree.java b/src/main/java/com/zsc/edu/gateway/modules/system/vo/UserTree.java new file mode 100644 index 0000000..7a35ea4 --- /dev/null +++ b/src/main/java/com/zsc/edu/gateway/modules/system/vo/UserTree.java @@ -0,0 +1,16 @@ +package com.zsc.edu.gateway.modules.system.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author zhuang + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UserTree { + private Long id; + private String name; +}