Files
UserclassService/src/main/java/com/yunhai/bschclassmanage/service/impl/SchDicCampusService.java
T
2026-08-14 09:04:58 +08:00

246 lines
9.9 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.yunhai.bschclassmanage.service.impl;
import com.alibaba.fastjson.JSON;
import com.yunhai.bschclassmanage.Repository.SchClassRepository;
import com.yunhai.bschclassmanage.Repository.SchDicCampusRepository;
import com.yunhai.bschclassmanage.annotation.OperationLog;
import com.yunhai.bschclassmanage.entity.SchDicCampus;
import com.yunhai.bschclassmanage.model.constant.LogModule;
import com.yunhai.bschclassmanage.model.entityField.EntityFieldNames;
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
import com.yunhai.bschclassmanage.service.ISchDicCampusService;
import com.yunhai.bschclassmanage.utils.*;
import com.yunhai.platform.utils.exception.DException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.criteria.Predicate;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@Slf4j
@Service
public class SchDicCampusService implements ISchDicCampusService {
@Autowired
private SchDicCampusRepository schDicCampusRepository;
@Autowired
private SchClassRepository schClassRepository;
@Autowired
private RedisUtil redisUtil;
public List<SchDicCampus> getSchDicCampusList(Integer schId) {
Specification<SchDicCampus> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
predicates.add(cb.equal(root.get(EntityFieldNames.schId), schId));
return cb.and(predicates.toArray(new Predicate[0]));
};
return schDicCampusRepository.findAll(spec);
}
// 获取学校院校列表(带缓存)
public List<SchDicCampus> getSchDicCampusCacheList(Integer schId) {
String cacheKey = RedisConstants.SCHOOL_CAMPUS + "_" + schId;
if (redisUtil.hasKey(cacheKey)) {
// 注意:返回副本或不可变列表,避免外部修改影响缓存
return redisUtil.getList(cacheKey,SchDicCampus.class);
}
// 同步查询数据库,防止缓存击穿
synchronized (this) {
if (redisUtil.hasKey(cacheKey)) {
return redisUtil.getList(cacheKey,SchDicCampus.class);
}
List<SchDicCampus> list = getSchDicCampusList(schId);
// 根据 sort 字段升序排序,null 值排在最后
list.sort(Comparator.comparing(SchDicCampus::getSort,
Comparator.nullsLast(Comparator.naturalOrder())));
redisUtil.set(cacheKey, new ArrayList<>(list), RedisConstants.CACHE_EXPIRE_30D);
return list;
}
}
@OperationLog(module = LogModule.CAMPUS)
@Transactional(rollbackFor = Exception.class)
public void saveSchCampus(UserContext.UserInfo user, SchDicCampus entity) {
Integer schId=user.getSchId();
boolean isNew=entity.getId() == null || entity.getId() == 0;
// 参数校验
if (entity.getName() == null || entity.getName().trim().isEmpty())
throw new DException("校区名称不能为空");
boolean nameExists;
SchDicCampus oldEntity=null;
if (isNew) {
// 新增:检查同名校区
nameExists = schDicCampusRepository.existsBySchIdAndName(schId, entity.getName());
if (nameExists) {
throw new DException("校区名称已存在:" + entity.getName());
}
OtherUtil.setBaseEntityValue(user, entity);
schDicCampusRepository.save(entity);
} else {
// 更新:排除自身,检查其他校区同名
nameExists = schDicCampusRepository.existsBySchIdAndNameAndIdNot(schId, entity.getName(), entity.getId());
if (nameExists) {
throw new DException("校区名称已存在:" + entity.getName());
}
Integer entityId=entity.getId();
SchDicCampus existing = schDicCampusRepository.findById(entityId)
.orElseThrow(() -> new DException("校区不存在,ID=" + entityId));
oldEntity=OtherUtil.deepCopy(existing,SchDicCampus.class);
OtherUtil.setBaseEntityValue(user, entity);
BeanUtils.copyProperties(entity, existing,
EntityFieldNames.id,
EntityFieldNames.schId,
EntityFieldNames.code,
EntityFieldNames.createDate,
EntityFieldNames.createUserId);
entity=schDicCampusRepository.save(existing);
}
// 清除缓存
String cacheKey = RedisConstants.SCHOOL_CAMPUS + "_" + schId;
redisUtil.del(cacheKey);
{
String description = buildCampusLogDescription(entity,isNew,oldEntity);
LogContextHolder.setDescription(description);
}
}
/**
* 构建学部操作的详细日志描述
*/
private String buildCampusLogDescription(SchDicCampus newEntity,boolean isNew,SchDicCampus oldEntity) {
if (isNew) {
return String.format("新增校区:%s(序号:%d)",
newEntity.getName(),
newEntity.getSort() != null ? newEntity.getSort() : 0);
} else {
List<String> changes = new ArrayList<>();
if (!Objects.equals(oldEntity.getName(), newEntity.getName())) {
changes.add(String.format("名称从 '%s' 修改为 '%s'", oldEntity.getName(), newEntity.getName()));
}
if (!Objects.equals(oldEntity.getSort(), newEntity.getSort())) {
changes.add(String.format("序号从 %d 修改为 %d", oldEntity.getSort(), newEntity.getSort()));
}
if (changes.isEmpty()) {
return "更新校区:无实际变更";
}
return "更新校区:" + String.join(";", changes);
}
}
@OperationLog(module = LogModule.CAMPUS)
@Transactional(rollbackFor = Exception.class)
public void sortSchCampus(UserContext.UserInfo user,List<Integer> ids)
{
List<SchDicCampus> campusList = getSchDicCampusCacheList(user.getSchId());
Map<Integer, SchDicCampus> campusMap = campusList.stream()
.collect(Collectors.toMap(SchDicCampus::getId, Function.identity()));
Date now = new Date();
// 1. 按传入顺序更新 sort 值
int sortOrder = 1;
for (Integer id : ids) {
SchDicCampus campus = campusMap.get(id);
if (campus != null) {
campus.setSort(sortOrder++);
campus.setUpdateDate(now);
campus.setUpdateUserId(user.getUserId());
}
}
// 2. 处理未出现在排序列表中的校区(设置 sort = null 或一个大值)
for (SchDicCampus campus : campusList) {
if (!ids.contains(campus.getId())) {
campus.setSort(null); // 或者设置一个最大值,比如 999
campus.setUpdateDate(now);
campus.setUpdateUserId(user.getUserId());
}
}
// 批量保存
schDicCampusRepository.saveAll(campusList);
String cacheKey = RedisConstants.SCHOOL_CAMPUS + "_" + user.getSchId();
redisUtil.del(cacheKey);
{
String names = ids.stream()
.map(id -> {
SchDicCampus m = campusMap.get(id);
return m != null ? m.getName() : String.valueOf(id);
})
.collect(Collectors.joining("、"));
String description = String.format("调整校区排序:共 %d 个专业(列表:%s)", ids.size(), names);
LogContextHolder.setDescription(description);
}
}
/**
* 删除校区
* 1. 参数非空校验
* 2. 校验校区是否存在(匹配学校+校区ID,防止跨学校删除)
* 3. 校验校区是否绑定班级,存在关联则禁止删除
* 4. 删除数据库数据 + 清除对应学校校区缓存
* @param id 校区ID
*/
@OperationLog(module = LogModule.CAMPUS)
@Transactional(rollbackFor = Exception.class)
public void delete(UserContext.UserInfo user, Integer id) {
// 1. 参数合法性校验
if (user.getSchId() == null || id == null) {
throw new DException("学校ID、校区ID不能为空");
}
// 2. 校验当前学校下该校区是否存在,防止越权删除其他学校校区
SchDicCampus campus = schDicCampusRepository.findByIdAndSchId(id, user.getSchId())
.orElseThrow(() -> new DException("校区不存在,无法删除"));
// 3. 业务校验:判断校区是否关联班级,有班级则禁止删除
long bindClassCount = schClassRepository.countByCampusId(id);
if (bindClassCount > 0) {
throw new DException(String.format("该校区下存在%s个班级,不可删除,请先移除班级关联", bindClassCount));
}
// 4. 删除数据
schDicCampusRepository.delete(campus);
// 5. 清除当前学校校区缓存
String cacheKey = RedisConstants.SCHOOL_CAMPUS + "_" + user.getSchId();
redisUtil.del(cacheKey);
LogContextHolder.setDescription("删除校区:"+campus.getName());
log.debug("操作人:{},删除校区日志:{}", user.getUserName(), JSON.toJSONString(campus));
}
public List<SelectIntVO> select(Integer schId) {
List<SchDicCampus> list = getSchDicCampusCacheList(schId);
return ModelMapperUtil.toSelectIntVOList(list, SchDicCampus::getId, SchDicCampus::getName);
}
public Map<Integer, String> toIdAndNameMap(Integer schId) {
List<SchDicCampus> list = getSchDicCampusCacheList(schId);
return ModelMapperUtil.toMap(list, SchDicCampus::getId, SchDicCampus::getName);
}
}