@@ -49,4 +49,6 @@ yh:
|
|||||||
100617: 2a3b4c5d6e7f8091a2b3c4d5e6f70819
|
100617: 2a3b4c5d6e7f8091a2b3c4d5e6f70819
|
||||||
|
|
||||||
# 上传文件落容器卷,compose 里挂到宿主机 ./upload-data
|
# 上传文件落容器卷,compose 里挂到宿主机 ./upload-data
|
||||||
FILE_PATH: /data/upload
|
# 键名必须是 file.upload-path(Java 端 @Value 按此读取;旧 FILE_PATH 顶层键不生效)
|
||||||
|
file:
|
||||||
|
upload-path: /data/upload
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ public class BaseApiController {
|
|||||||
public List<Map<String, Object>> getUserMod(BoaUser authUserWithDept) {
|
public List<Map<String, Object>> getUserMod(BoaUser authUserWithDept) {
|
||||||
Integer schId = authUserWithDept.getCurrentRole() != null
|
Integer schId = authUserWithDept.getCurrentRole() != null
|
||||||
? authUserWithDept.getCurrentRole().getSchId() : null;
|
? authUserWithDept.getCurrentRole().getSchId() : null;
|
||||||
|
|
||||||
return userCenterService.getUserModuleTree(authUserWithDept.getId(), schId);
|
return userCenterService.getUserModuleTree(authUserWithDept.getId(), schId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 班级管理接口-教师(bschclass {@code /oapi/DbClass/GetSchteaList} 响应项)。
|
* 班级管理接口-教师(userclass {@code /oapi/DbClass/GetSchteaList} 响应项)。
|
||||||
* 对应 C# BestSchool.Entity.Model.SchTeaList。
|
* 对应 C# BestSchool.Entity.Model.SchTeaList。
|
||||||
*/
|
*/
|
||||||
public class SchTeaList {
|
public class SchTeaList {
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ import com.yunhai.notice.model.SchTeaList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 班级管理(bschclass)开放接口客户端。
|
* 班级管理(userclass)开放接口客户端。
|
||||||
* 基址取配置 {@code yh.open.bschclass},当前仅提供教师查询,后续班级/年级等接口按需追加。
|
* 基址取配置 {@code yh.open.userclass},当前仅提供教师查询,后续班级/年级等接口按需追加。
|
||||||
*/
|
*/
|
||||||
public interface IClassService {
|
public interface IClassService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取指定学校全部教师(含所属组 GroupIds)。
|
* 获取指定学校全部教师(含所属组 GroupIds)。
|
||||||
* 对应 bschclass 开放接口:GET {@code {bschclass}/oapi/DbClass/GetSchteaList?Group={schId}}
|
* 对应 userclass 开放接口:GET {@code {userclass}/oapi/DbClass/GetSchteaList?Group={schId}}
|
||||||
*
|
*
|
||||||
* @param schId 学校ID(即用户当前身份的 schId)
|
* @param schId 学校ID(即用户当前身份的 schId)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public interface IUserCenterService {
|
|||||||
* <p>组装规则(从原 BaseApiController.getSchoolAll 下沉):</p>
|
* <p>组装规则(从原 BaseApiController.getSchoolAll 下沉):</p>
|
||||||
* <ol>
|
* <ol>
|
||||||
* <li>userbase 读取当前学校整棵组树(getGroupById(schId, withSub=true)),剔除学生组(type=8)及其子组;</li>
|
* <li>userbase 读取当前学校整棵组树(getGroupById(schId, withSub=true)),剔除学生组(type=8)及其子组;</li>
|
||||||
* <li>bschclass 获取该校全部教师(/oapi/DbClass/GetSchteaList?Group=schId),按 GroupIds 挂到对应组下,
|
* <li>userclass(班级管理)获取该校全部教师(/oapi/DbClass/GetSchteaList?Group=schId),按 GroupIds 挂到对应组下,
|
||||||
* 无有效组(如所属组全被剔除)的教师兜底挂学校根节点;</li>
|
* 无有效组(如所属组全被剔除)的教师兜底挂学校根节点;</li>
|
||||||
* <li>扁平节点按 pid 递归组装为树(空组剔除,同 C# FormatUserTree)。</li>
|
* <li>扁平节点按 pid 递归组装为树(空组剔除,同 C# FormatUserTree)。</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
|
|||||||
@@ -20,17 +20,17 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 班级管理(bschclass)开放接口实现。
|
* 班级管理(userclass)开放接口实现。
|
||||||
* bschclass 为开放接口(无需应用签名),使用独立 RestTemplate 直连。
|
* userclass 为开放接口(无需应用签名),使用独立 RestTemplate 直连。
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class ClassService implements IClassService {
|
public class ClassService implements IClassService {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(ClassService.class);
|
private static final Logger log = LoggerFactory.getLogger(ClassService.class);
|
||||||
|
|
||||||
/** 班级管理服务基址,如 http://base.yunhaixingtong.com/bschclass */
|
/** 班级管理服务基址,如 http://base.yunhaixingtong.com/userclass */
|
||||||
@Value("${yh.open.bschclass:}")
|
@Value("${yh.open.userclass:}")
|
||||||
private String bschClassHost;
|
private String userClassHost;
|
||||||
|
|
||||||
private final RestTemplate restTemplate;
|
private final RestTemplate restTemplate;
|
||||||
|
|
||||||
@@ -43,10 +43,10 @@ public class ClassService implements IClassService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<SchTeaList> getSchTeaList(int schId) {
|
public List<SchTeaList> getSchTeaList(int schId) {
|
||||||
if (!StringUtils.hasText(bschClassHost)) {
|
if (!StringUtils.hasText(userClassHost)) {
|
||||||
throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR, "班级管理接口未配置(yh.open.bschclass)");
|
throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR, "班级管理接口未配置(yh.open.userclass)");
|
||||||
}
|
}
|
||||||
String url = bschClassHost + "/oapi/DbClass/GetSchteaList?Group=" + schId;
|
String url = userClassHost + "/oapi/DbClass/GetSchteaList?Group=" + schId;
|
||||||
try {
|
try {
|
||||||
ResponseEntity<List<SchTeaList>> resp = restTemplate.exchange(
|
ResponseEntity<List<SchTeaList>> resp = restTemplate.exchange(
|
||||||
url, HttpMethod.GET, null,
|
url, HttpMethod.GET, null,
|
||||||
|
|||||||
@@ -58,6 +58,15 @@ public class FileService implements IFileService {
|
|||||||
|
|
||||||
private static final String DEFAULT_APP_TYPE = "notice";
|
private static final String DEFAULT_APP_TYPE = "notice";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析存储绝对路径。uploadPath 需以绝对路径配置(生产容器内 /data/upload);
|
||||||
|
* 若误配为相对路径,此处统一锚定到进程工作目录——否则 MultipartFile.transferTo
|
||||||
|
* 会把相对目标解析到 Tomcat multipart 临时目录,与后续读取(按工作目录解析)分裂。
|
||||||
|
*/
|
||||||
|
private Path resolvePath(String relative) {
|
||||||
|
return Paths.get(uploadPath, relative).toAbsolutePath().normalize();
|
||||||
|
}
|
||||||
|
|
||||||
// ============================ 上传 ============================
|
// ============================ 上传 ============================
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -83,7 +92,7 @@ public class FileService implements IFileService {
|
|||||||
String relativePath = (appType == null ? DEFAULT_APP_TYPE : appType) + "/" + dateDir + "/" + savedName;
|
String relativePath = (appType == null ? DEFAULT_APP_TYPE : appType) + "/" + dateDir + "/" + savedName;
|
||||||
|
|
||||||
// 物理写入
|
// 物理写入
|
||||||
Path fullPath = Paths.get(uploadPath, relativePath);
|
Path fullPath = resolvePath(relativePath);
|
||||||
try {
|
try {
|
||||||
Files.createDirectories(fullPath.getParent());
|
Files.createDirectories(fullPath.getParent());
|
||||||
file.transferTo(fullPath.toFile());
|
file.transferTo(fullPath.toFile());
|
||||||
@@ -150,7 +159,7 @@ public class FileService implements IFileService {
|
|||||||
private void writeFile(Integer fileId, HttpServletResponse response, boolean inline) {
|
private void writeFile(Integer fileId, HttpServletResponse response, boolean inline) {
|
||||||
UpFile file = upFileRepository.findById(fileId)
|
UpFile file = upFileRepository.findById(fileId)
|
||||||
.orElseThrow(() -> new BizException(ErrorCode.FORBIDDEN, "文件不存在: " + fileId));
|
.orElseThrow(() -> new BizException(ErrorCode.FORBIDDEN, "文件不存在: " + fileId));
|
||||||
Path fullPath = Paths.get(uploadPath, file.getFileName());
|
Path fullPath = resolvePath(file.getFileName());
|
||||||
if (!Files.exists(fullPath)) {
|
if (!Files.exists(fullPath)) {
|
||||||
throw new BizException(ErrorCode.FORBIDDEN, "物理文件不存在: " + file.getFileName());
|
throw new BizException(ErrorCode.FORBIDDEN, "物理文件不存在: " + file.getFileName());
|
||||||
}
|
}
|
||||||
@@ -218,7 +227,7 @@ public class FileService implements IFileService {
|
|||||||
UpFile file = upFileRepository.findById(fileId)
|
UpFile file = upFileRepository.findById(fileId)
|
||||||
.orElseThrow(() -> new BizException(ErrorCode.FORBIDDEN, "文件不存在: " + fileId));
|
.orElseThrow(() -> new BizException(ErrorCode.FORBIDDEN, "文件不存在: " + fileId));
|
||||||
// 删物理文件
|
// 删物理文件
|
||||||
Path fullPath = Paths.get(uploadPath, file.getFileName());
|
Path fullPath = resolvePath(file.getFileName());
|
||||||
try {
|
try {
|
||||||
Files.deleteIfExists(fullPath);
|
Files.deleteIfExists(fullPath);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -243,7 +252,7 @@ public class FileService implements IFileService {
|
|||||||
try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
|
try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
|
||||||
Set<String> used = new HashSet<>();
|
Set<String> used = new HashSet<>();
|
||||||
for (UpFile f : files) {
|
for (UpFile f : files) {
|
||||||
Path p = Paths.get(uploadPath, f.getFileName());
|
Path p = resolvePath(f.getFileName());
|
||||||
if (!Files.exists(p)) {
|
if (!Files.exists(p)) {
|
||||||
log.warn("[downloadZip] 物理文件缺失,跳过: {}", f.getFileName());
|
log.warn("[downloadZip] 物理文件缺失,跳过: {}", f.getFileName());
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public class UserCenterService implements IUserCenterService {
|
|||||||
}
|
}
|
||||||
flattenGroup(root, 0, flatNodes);
|
flattenGroup(root, 0, flatNodes);
|
||||||
|
|
||||||
// 2. bschclass 全部教师,按 GroupIds 挂到对应组下;无有效组的兜底挂学校根节点
|
// 2. userclass(班级管理)全部教师,按 GroupIds 挂到对应组下;无有效组的兜底挂学校根节点
|
||||||
Set<Integer> treeGroupIds = new HashSet<>();
|
Set<Integer> treeGroupIds = new HashSet<>();
|
||||||
for (Map<String, Object> node : flatNodes) {
|
for (Map<String, Object> node : flatNodes) {
|
||||||
treeGroupIds.add((Integer) node.get("id"));
|
treeGroupIds.add((Integer) node.get("id"));
|
||||||
|
|||||||
@@ -68,5 +68,5 @@ yh:
|
|||||||
enabled: true
|
enabled: true
|
||||||
base-host: http://base.yunhaixingtong.com
|
base-host: http://base.yunhaixingtong.com
|
||||||
user-center-url: http://base.yunhaixingtong.com/userbase
|
user-center-url: http://base.yunhaixingtong.com/userbase
|
||||||
# 班级管理(bschclass)服务基址
|
# 班级管理(userclass)服务基址(原 bschclass 路由已下线)
|
||||||
bschclass: http://base.yunhaixingtong.com/bschclass
|
userclass: http://base.yunhaixingtong.com/userclass
|
||||||
|
|||||||
Reference in New Issue
Block a user