diff --git a/docker/application-prod.yml b/docker/application-prod.yml index c1d799a..1717aaa 100644 --- a/docker/application-prod.yml +++ b/docker/application-prod.yml @@ -52,8 +52,6 @@ yh: FILE_PATH: /data/upload FILE_WEB_PATH: http://home.yunhaixingtong.com/userhome/upload/ UPLOAD_WEB_PATH_HTTP: http://home.yunhaixingtong.com/userhome/upload/file/ -# 学校配置接口基址(prod 由 Nacos 覆盖) -SCH_CONF_URL: "" logging: level: diff --git a/src/main/java/com/yunhai/userhome/config/WebMvcConfig.java b/src/main/java/com/yunhai/userhome/config/WebMvcConfig.java index 1574063..a101bfc 100644 --- a/src/main/java/com/yunhai/userhome/config/WebMvcConfig.java +++ b/src/main/java/com/yunhai/userhome/config/WebMvcConfig.java @@ -42,5 +42,9 @@ public class WebMvcConfig implements WebMvcConfigurer { // logo 子目录:/upload/logo/** → ${FILE_PATH}/logo/ registry.addResourceHandler("/upload/logo/**") .addResourceLocations("file:" + basePath + "logo/"); + + // tempUpload 子目录(应用模板):/upload/tempUpload/** → ${FILE_PATH}/tempUpload/ + registry.addResourceHandler("/upload/tempUpload/**") + .addResourceLocations("file:" + basePath + "tempUpload/"); } } diff --git a/src/main/java/com/yunhai/userhome/controller/api/AppSettingController.java b/src/main/java/com/yunhai/userhome/controller/api/AppSettingController.java new file mode 100644 index 0000000..7dbdd43 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/controller/api/AppSettingController.java @@ -0,0 +1,243 @@ +package com.yunhai.userhome.controller.api; + +import com.yunhai.platform.apistd.BizException; +import com.yunhai.platform.utils.exception.ErrorCode; +import com.yunhai.platform.utils.model.BoaUser; +import com.yunhai.userhome.config.Config; +import com.yunhai.userhome.entity.AppCategory; +import com.yunhai.userhome.entity.UserCurrentRole; +import com.yunhai.userhome.service.IAppCategoryService; +import com.yunhai.userhome.service.IUserCurrentRoleService; +import com.yunhai.userhome.utils.FileUtil; +import com.yunhai.userhome.utils.OtherUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.InputStreamResource; +import org.springframework.data.domain.Page; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +/** + * 应用设置控制器(自 systemsetting AppSettingController + SysController 迁移,1:1 对齐)。 + * + *

与原版差异点:写操作(应用 CRUD / UpdateResDate / 模板上传保存)校验调用者 + * 为超管(type==1)或校管理员(roleId∈{2,5,7})——原版任何登录用户可写,因新入口仅管理员可见,收紧。 + * 查询(分页列表 / FindAppCategory / GetTempList / downloadTemp)登录即可。 + */ +@RestController +@RequestMapping(Config.API_PATH) +public class AppSettingController { + + @Value("${FILE_PATH:./upload/}") + private String FILE_PATH; + + @Value("${FILE_WEB_PATH:}") + private String FILE_WEB_PATH; + + @Autowired + private IAppCategoryService appCategoryService; + + @Autowired + private IUserCurrentRoleService userCurrentRoleService; + + // ==================== 应用类别 CRUD ==================== + + /** 新增/编辑应用(JSON body,1:1 对齐原 SaveAppCategory) */ + @PostMapping(value = "SaveAppCategory", produces = "application/json") + public void saveAppCategory(BoaUser authUserWithDept, @RequestBody AppCategory appCategory) { + checkAdmin(authUserWithDept); + if (appCategory.getCDate() == null) appCategory.setCDate(new Date()); + if (appCategory.getResDate() == null) appCategory.setResDate(new Date()); + appCategory.setCId(authUserWithDept.getId()); + appCategoryService.save(appCategory); + } + + @PostMapping(value = "DelAppCategory", produces = "application/json") + public void delAppCategory(BoaUser authUserWithDept, Integer id) { + checkAdmin(authUserWithDept); + appCategoryService.deleteById(id); + } + + @GetMapping(value = "GetAppCategoryList") + public Map getAppCategoryList(BoaUser authUserWithDept, Integer page, Integer count, + @RequestParam(value = "roleType") Integer roleType, + @RequestParam(value = "name", required = false) String name) { + Page data = appCategoryService.findPageList(page, count, roleType, name); + Map map = new HashMap(); + map.put("total", data.getTotalElements()); + map.put("list", data.getContent()); + return map; + } + + @GetMapping(value = "FindAppCategory") + public Optional findAppCategory(BoaUser authUserWithDept, Integer id) { + return appCategoryService.findById(id); + } + + @PostMapping(value = "UpdateResDate", produces = "application/json") + public void updateResDate(BoaUser authUserWithDept, Integer id) { + checkAdmin(authUserWithDept); + appCategoryService.updateResDate(id); + } + + // ==================== 模板管理(对齐原 SysController) ==================== + + /** 上传模板压缩包(zip/rar),解压覆盖到 tempUpload/<appModId>/,删除压缩包 */ + @PostMapping(value = "tempUpload", produces = "application/json") + public void tempUpload(BoaUser authUserWithDept, @RequestParam("file") MultipartFile file, Integer appModId) { + checkAdmin(authUserWithDept); + if (file == null || file.isEmpty()) { + throw new BizException(ErrorCode.CUSTOM, "请选择上传文件"); + } + String originalName = file.getOriginalFilename(); + String ext = originalName == null ? "" : originalName.substring(originalName.lastIndexOf(".")).toLowerCase(Locale.ROOT); + if (!".zip".equals(ext) && !".rar".equals(ext)) { + throw new BizException(ErrorCode.CUSTOM, "仅支持 zip/rar 格式"); + } + // 不走图片 5MB 校验(模板包允许更大,依赖 multipart 配置),存到 tempUpload 子目录 + String uploadPath = FILE_PATH + "/tempUpload/"; + File fl = new File(uploadPath); + if (!fl.exists()) fl.mkdirs(); + String fileName = FileUtil.uploadFile(file, uploadPath); + String filePath = "/upload/tempUpload/" + fileName; + + File unzipFiles = new File(FILE_PATH + "/tempUpload/" + appModId); + if (!unzipFiles.exists()) unzipFiles.mkdirs(); + else FileUtil.delAllFile(unzipFiles.getPath()); + File zipFile = new File(filePath.replace("/upload", FILE_PATH)); + try { + FileUtil.zipDecompress(zipFile, unzipFiles); + } catch (Exception e) { + throw new BizException(ErrorCode.CUSTOM, e.getMessage()); + } finally { + zipFile.delete(); + } + } + + /** 模板文件列表(name + 访问 path) */ + @GetMapping(value = "GetTempList") + public List getTempList(BoaUser authUserWithDept, Integer appModId) { + File sourceFile = new File(FILE_PATH + "/tempUpload/" + appModId); + List result = new ArrayList<>(); + if (sourceFile.exists() && sourceFile.isDirectory() && sourceFile.listFiles() != null) { + Arrays.stream(sourceFile.listFiles()).forEach(file -> { + Map map = new HashMap(); + map.put("name", file.getName()); + map.put("path", FILE_WEB_PATH + "/tempUpload/" + appModId + "/" + file.getName()); + result.add(map); + }); + } + return result; + } + + /** 保存模板文件内容(新增 fileName 路径穿越校验,原版没有;content 走 JSON body 避免 URL 长度限制) */ + @PostMapping(value = "SaveTempFile", produces = "application/json") + public void saveTempFile(BoaUser authUserWithDept, @RequestBody Map body) { + checkAdmin(authUserWithDept); + Object appModIdObj = body.get("appModId"); + String fileName = body.get("fileName") == null ? null : body.get("fileName").toString(); + String content = body.get("content") == null ? "" : body.get("content").toString(); + if (appModIdObj == null) { + throw new BizException(ErrorCode.CUSTOM, "缺少appModId"); + } + Integer appModId; + try { + appModId = Integer.parseInt(appModIdObj.toString()); + } catch (NumberFormatException e) { + throw new BizException(ErrorCode.CUSTOM, "非法appModId"); + } + if (fileName == null || fileName.contains("/") || fileName.contains("\\") || fileName.contains("..")) { + throw new BizException(ErrorCode.CUSTOM, "非法文件名"); + } + File dir = new File(FILE_PATH + "/tempUpload/" + appModId); + if (!dir.exists()) dir.mkdirs(); + File file = new File(FILE_PATH + "/tempUpload/" + appModId + "/" + fileName); + try { + if (!file.exists()) { + file.createNewFile(); + } + FileOutputStream fos = new FileOutputStream(file); + fos.write(content.getBytes()); + fos.flush(); + fos.close(); + } catch (IOException e) { + throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR, "保存失败"); + } + } + + /** 打包下载模板目录(zip 流式下载,临时 zip 关闭即删) */ + @GetMapping(value = "downloadTemp", produces = "application/json;charset=UTF-8") + public ResponseEntity downloadTemp(BoaUser authUserWithDept, Integer appModId, String name) { + File zipFilePath = new File(FILE_PATH + "/tempUpload/" + appModId); + if (!zipFilePath.exists() || !zipFilePath.isDirectory()) { + throw new BizException(ErrorCode.CUSTOM, "模板不存在"); + } + String zipName = UUID.randomUUID().toString().substring(0, 8) + ".zip"; + File zipFile = new File(FILE_PATH + "/tempUpload/" + zipName); + try { + FileUtil.zipCompress(zipFilePath, zipFile); + } catch (Exception e) { + throw new BizException(ErrorCode.CUSTOM, e.getMessage()); + } + String downloadName = (name == null || name.trim().isEmpty()) ? "template" : name; + try { + InputStream inputStream = new FileInputStream(zipFile) { + @Override + public void close() throws IOException { + super.close(); + zipFile.delete(); + } + }; + HttpHeaders headers = new HttpHeaders(); + headers.add("Cache-Control", "no-cache, no-store, must-revalidate"); + headers.add("Content-Disposition", + "attachment; filename=" + new String((downloadName + ".zip").getBytes("gbk"), "iso8859-1")); + headers.add("Pragma", "no-cache"); + headers.add("Expires", "0"); + return ResponseEntity.ok().headers(headers) + .contentType(MediaType.parseMediaType("application/octet-stream")) + .body(new InputStreamResource(inputStream)); + } catch (IOException e) { + zipFile.delete(); + throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR, "下载失败"); + } + } + + // ==================== 私有方法 ==================== + + /** + * 写操作权限校验:超管(type==1) 或 校管理员(roleId∈{2,5,7}),其余 403。 + */ + private void checkAdmin(BoaUser authUserWithDept) { + if (authUserWithDept.getType() == 1) { + return; + } + Optional currentRoleOpt = userCurrentRoleService.findById(authUserWithDept.getId()); + if (!currentRoleOpt.isPresent() || !OtherUtil.isAdminById(currentRoleOpt.get().getRoleId())) { + throw new BizException(ErrorCode.FORBIDDEN); + } + } +} diff --git a/src/main/java/com/yunhai/userhome/controller/api/SchSettingsController.java b/src/main/java/com/yunhai/userhome/controller/api/SchSettingsController.java index a5daffd..3a5d9d0 100644 --- a/src/main/java/com/yunhai/userhome/controller/api/SchSettingsController.java +++ b/src/main/java/com/yunhai/userhome/controller/api/SchSettingsController.java @@ -16,8 +16,8 @@ import java.util.Optional; /** * 学校设置接口(CAS 登录态,路径 {@code /{platform}/}),对齐旧 UserHome SchSettingsController。 - *

getSchSettings 实际跨仓调用 schConfig(见 SchSettingsServiceImpl); - * saveSchTheme/saveSchLogo(P1)本期写入本地 sch_settings 表(跨仓回写可后续对接)。

+ *

getSchSettings 查本地 sch_settings 表(不再依赖跨仓 schConfig); + * saveSchTheme/saveSchLogo 写本地 sch_settings 表。

*/ @RestController @RequestMapping(value = Config.API_PATH) diff --git a/src/main/java/com/yunhai/userhome/controller/api/UserSettingsController.java b/src/main/java/com/yunhai/userhome/controller/api/UserSettingsController.java index 25072f1..5d4c92c 100644 --- a/src/main/java/com/yunhai/userhome/controller/api/UserSettingsController.java +++ b/src/main/java/com/yunhai/userhome/controller/api/UserSettingsController.java @@ -1,13 +1,12 @@ package com.yunhai.userhome.controller.api; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import com.yunhai.platform.apistd.BizException; import com.yunhai.platform.openapi.client.YschBaseOpenApi; import com.yunhai.platform.utils.enums.ClientEnum; import com.yunhai.platform.utils.exception.ErrorCode; import com.yunhai.platform.utils.model.BoaApp; import com.yunhai.platform.utils.model.BoaAppType; +import com.yunhai.platform.utils.model.BoaGroup; import com.yunhai.platform.utils.model.BoaUser; import com.yunhai.userhome.config.Config; import com.yunhai.userhome.entity.*; @@ -23,7 +22,6 @@ import com.yunhai.userhome.utils.OtherUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*; -import org.springframework.web.client.RestTemplate; import org.springframework.web.multipart.MultipartFile; import java.io.File; @@ -36,7 +34,6 @@ import java.util.stream.Collectors; *

待确认接口(已写入待确认清单): *

*/ @RestController @@ -49,9 +46,6 @@ public class UserSettingsController { @Value("${FILE_WEB_PATH:}") private String FILE_WEB_PATH; - @Value("${SCH_CONF_URL:}") - private String SCH_CONF_URL; - @Autowired private IUserSettingsService userSettingsService; @@ -61,21 +55,38 @@ public class UserSettingsController { @Autowired private UsedAppService usedAppService; - private final RestTemplate restTemplate = new RestTemplate(); - private final ObjectMapper objectMapper = new ObjectMapper(); - // ==================== 壁纸 ==================== + /** + * 上传壁纸(Header 弹窗与系统设置页共用)。 + * + *

超管:可选 schId 参数——传 schId>0 归属该校(type=1),不传/0 维持系统级(type=0); + * 校管理员:忽略入参固定本校(type=1);普通用户维持个人壁纸(type=2)。

+ */ @PostMapping(value = "wallpaperUpload", produces = "application/json") - public void wallpaperUpload(BoaUser authUserWithDept, @RequestParam("file") MultipartFile file) { + public void wallpaperUpload(BoaUser authUserWithDept, @RequestParam("file") MultipartFile file, + @RequestParam(value = "schId", required = false) Integer schId) { checkFile(file); String uploadUrl = this.upload(file, "wallpaper"); UserCurrentRole currentRole = userCurrentRoleService.findById(authUserWithDept.getId()) .orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR)); - Integer type = authUserWithDept.getType() == 1 ? 0 : OtherUtil.isAdminById(currentRole.getRoleId()) ? 1 : 2; + Integer type; + Integer targetSchId; + if (authUserWithDept.getType() == 1) { + if (schId != null && schId > 0) { + type = 1; + targetSchId = schId; + } else { + // 超管上传的系统壁纸 schId 强制 0,避免切学校身份后产生孤儿数据 + type = 0; + targetSchId = 0; + } + } else { + type = OtherUtil.isAdminById(currentRole.getRoleId()) ? 1 : 2; + targetSchId = currentRole.getSchId(); + } Wallpaper wallpaper = new Wallpaper(); - // 超管上传的系统壁纸 schId 强制 0,避免切学校身份后产生孤儿数据 - wallpaper.setSchId(type == 0 ? 0 : currentRole.getSchId()); + wallpaper.setSchId(targetSchId); wallpaper.setWallpaperUrl(uploadUrl); wallpaper.setUserId(authUserWithDept.getId()); wallpaper.setType(type); @@ -98,16 +109,11 @@ public class UserSettingsController { @PostMapping(value = "checkWallpaper", produces = "application/json") public void checkWallpaper(BoaUser authUserWithDept, @RequestBody Map res) { String wallpaperUrl = res.get("wallpaperUrl").toString(); - // 校验 URL 属于该用户可见壁纸集合,防止设置任意字符串 + // 校验 URL 属于该用户可见壁纸集合(本地 wallpaper 表),防止设置任意字符串 String normalized = normalizeWallpaperUrl(wallpaperUrl); Set visible = new HashSet<>(); userSettingsService.findWallList(authUserWithDept.getId()) .forEach(w -> visible.add(w.getWallpaperUrl())); - Optional currentRoleOpt = userCurrentRoleService.findById(authUserWithDept.getId()); - Integer schId = currentRoleOpt.isPresent() ? currentRoleOpt.get().getSchId() : null; - if (schId != null) { - getSchSettingsWallpaper(schId).forEach(visible::add); - } if (!visible.contains(normalized)) { throw new BizException(ErrorCode.FORBIDDEN, "壁纸不存在或无权使用"); } @@ -127,35 +133,25 @@ public class UserSettingsController { map.put("isEdit", model.getIsEdit()); result.add(map); }); - if (authUserWithDept.getType() != 1 && !list.stream().anyMatch(x -> x.getType() == 1)) { - // schId 以当前激活角色为准,忽略前端传参(防传他校 id 看他校壁纸) - Optional currentRoleOpt = userCurrentRoleService.findById(authUserWithDept.getId()); - Integer curSchId = currentRoleOpt.isPresent() ? currentRoleOpt.get().getSchId() : null; - if (curSchId != null) { - List schList = getSchSettingsWallpaper(curSchId); - for (String schWall : schList) { - Map map = new HashMap(); - map.put("id", null); - map.put("type", 1); - map.put("url", schWall); - map.put("isEdit", false); - result.add(map); - } - } - } return result; } // ==================== Logo ==================== @PostMapping(value = "logoUpload", produces = "application/json") - public void logoUpload(BoaUser authUserWithDept, @RequestParam("file") MultipartFile file) { - // 仅超管(系统默认)与校管理员(本校)可上传,普通用户无权设置 Logo + public void logoUpload(BoaUser authUserWithDept, @RequestParam("file") MultipartFile file, + @RequestParam(value = "schId", required = false) Integer schId) { + // 仅超管(系统默认/指定学校)与校管理员(本校)可上传,普通用户无权设置 Logo Integer type; - Integer schId; + Integer targetSchId; if (authUserWithDept.getType() == 1) { - type = 0; - schId = 0; + if (schId != null && schId > 0) { + type = 1; + targetSchId = schId; + } else { + type = 0; + targetSchId = 0; + } } else { UserCurrentRole currentRole = userCurrentRoleService.findById(authUserWithDept.getId()) .orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR)); @@ -163,13 +159,13 @@ public class UserSettingsController { throw new BizException(ErrorCode.FORBIDDEN, "无权设置Logo"); } type = 1; - schId = currentRole.getSchId(); + targetSchId = currentRole.getSchId(); } checkFile(file); String uploadUrl = this.upload(file, "logo"); Logo logo = new Logo(); logo.setType(type); - logo.setSchId(schId); + logo.setSchId(targetSchId); logo.setLogoUrl(uploadUrl); logo.setUserId(authUserWithDept.getId()); userSettingsService.saveLogo(logo); @@ -195,6 +191,82 @@ public class UserSettingsController { userSettingsService.deleteLogoById(id, authUserWithDept); } + // ==================== 系统设置(学校维度管理视图) ==================== + + /** + * 机构树(仅超管,403 兜底):YschBaseOpenApi.getGroupTree() → 递归裁剪到学校层 + * (对齐原 systemsetting SysController.RecursionGroup:type==1 普通组跳过、type==2 学校组置叶子)。 + */ + @GetMapping(value = "getSchTree") + public BoaGroup getSchTree(BoaUser authUserWithDept) { + if (authUserWithDept.getType() != 1) { + throw new BizException(ErrorCode.FORBIDDEN); + } + BoaGroup group = YschBaseOpenApi.getGroupTree(); + return recursionGroup(group); + } + + /** + * 壁纸管理列表(系统设置页):系统壁纸(type=0) + 目标学校壁纸(type=1),不含个人壁纸(type=2)。 + *

超管可传任意 schId(不传按 0 即平台默认);校管理员忽略入参固定本校,系统壁纸仅超管可删。

+ */ + @GetMapping(value = "getSchWallpaperManageList") + public List getSchWallpaperManageList(BoaUser authUserWithDept, Integer schId) { + List result = new ArrayList<>(); + userSettingsService.findSchWallpaperManageList(authUserWithDept, schId).forEach(model -> { + Map map = new HashMap(); + map.put("id", model.getId()); + map.put("url", FILE_WEB_PATH + model.getWallpaperUrl().replace("/upload", "")); + map.put("type", model.getType()); + map.put("isEdit", model.getIsEdit()); + result.add(map); + }); + return result; + } + + /** + * Logo 管理列表(系统设置页):系统默认(type=0) + 目标学校(type=1)。 + *

同 getSchWallpaperManageList 权限语义;logo 单张,前端取第一张显示,上传即覆盖。

+ */ + @GetMapping(value = "getSchLogoManageList") + public List getSchLogoManageList(BoaUser authUserWithDept, Integer schId) { + List result = new ArrayList<>(); + userSettingsService.findSchLogoManageList(authUserWithDept, schId).forEach(model -> { + Map map = new HashMap(); + map.put("id", model.getId()); + map.put("url", FILE_WEB_PATH + model.getLogoUrl().replace("/upload", "")); + map.put("type", model.getType()); + map.put("isEdit", model.getIsEdit()); + result.add(map); + }); + return result; + } + + /** + * 递归裁剪机构树到学校层(对齐原 systemsetting SysController.RecursionGroup)。 + */ + private BoaGroup recursionGroup(BoaGroup group) { + // 组类型:1 普通组 2 学校组 3 年级组 4 班级组 5 区域组 6 学段组 7 教师组 8 学生组 + List list = new ArrayList<>(); + List children = group.getChildren(); + if (children == null) { + return group; + } + for (BoaGroup boaGroup : children) { + if (boaGroup.getType() == null) continue; + if (boaGroup.getType() == 1) continue; + if (boaGroup.getType() == 2) { + boaGroup.setChildren(null); + list.add(boaGroup); + } else { + BoaGroup model = this.recursionGroup(boaGroup); + list.add(model); + } + } + group.setChildren(list); + return group; + } + // ==================== 用户设置 ==================== @GetMapping(value = "getUserSettings") @@ -207,9 +279,8 @@ public class UserSettingsController { // List appPageList = bschBaseOpenApi.getPcGrzxPage(authUserWithDept.getId(), schId); List appPageList = Collections.emptyList(); if (optional.isPresent()) model = optional.get(); - if ((model.getWallpaperUrl() == null || model.getWallpaperUrl().isEmpty()) && schId != null) { - List schList = getSchSettingsWallpaper(schId); - if (schList.size() > 0) model.setWallpaperUrl(schList.get(0)); + if (model.getWallpaperUrl() == null || model.getWallpaperUrl().isEmpty()) { + model.setWallpaperUrl(resolveFallbackWallpaper(authUserWithDept, schId)); } List mapList = appPageList.stream().map(boaApp -> { Map map = new HashMap<>(); @@ -224,6 +295,32 @@ public class UserSettingsController { return model; } + /** + * 兜底壁纸(用户未设置时):本地学校壁纸第一张 → 超管全局壁纸第一张。 + *

学校壁纸完全本地管理(wallpaper 表 type=1),不再依赖跨仓 schConfig。

+ */ + private String resolveFallbackWallpaper(BoaUser authUserWithDept, Integer schId) { + List wallList = userSettingsService.findWallList(authUserWithDept.getId()); + if (schId != null) { + // 1. 本地学校壁纸第一张(type=1,取最新) + Optional schWall = wallList.stream() + .filter(w -> w.getType() != null && w.getType() == 1 + && w.getSchId() != null && w.getSchId().equals(schId)) + .max(Comparator.comparing(Wallpaper::getId)); + if (schWall.isPresent()) { + return FILE_WEB_PATH + schWall.get().getWallpaperUrl().replace("/upload", ""); + } + } + // 2. 超管全局壁纸第一张(type=0,取最新) + Optional sysWall = wallList.stream() + .filter(w -> w.getType() != null && w.getType() == 0) + .max(Comparator.comparing(Wallpaper::getId)); + if (sysWall.isPresent()) { + return FILE_WEB_PATH + sysWall.get().getWallpaperUrl().replace("/upload", ""); + } + return null; + } + @GetMapping(value = "getUserDesktopAppList") public List getUserDesktopAppList(BoaUser authUserWithDept) { Optional currentRoleOpt = userCurrentRoleService.findById(authUserWithDept.getId()); @@ -465,37 +562,6 @@ public class UserSettingsController { return u; } - /** - * 获取学校设置的壁纸集合(对齐旧 UserHome GetSchSettingsWallpaper,fastjson → Jackson)。 - */ - private List getSchSettingsWallpaper(Integer schId) { - if (SCH_CONF_URL == null || SCH_CONF_URL.isEmpty()) return Collections.emptyList(); - String apiPath = SCH_CONF_URL + "/oapi/getSchSetting?schId=" + schId; - List result = new ArrayList<>(); - try { - String resultStr = restTemplate.getForObject(apiPath, String.class); - if (resultStr == null || resultStr.isEmpty()) return result; - JsonNode root = objectMapper.readTree(resultStr); - JsonNode dataNode = root.get("data"); - if (root.has("code") && "0".equals(root.get("code").asText()) && dataNode != null && !dataNode.isNull()) { - JsonNode appBgUrlNode = dataNode.get("appBackgroundUrl"); - if (appBgUrlNode == null) appBgUrlNode = dataNode.get("appBgUrl"); - String appBgUrlStr = appBgUrlNode != null ? appBgUrlNode.asText("") : ""; - if (appBgUrlStr.isEmpty()) return result; - String[] imgUrls = appBgUrlStr.split(","); - for (String imgUrl : imgUrls) { - if (!imgUrl.contains(SCH_CONF_URL)) - result.add(SCH_CONF_URL + imgUrl); - else - result.add(imgUrl); - } - } - } catch (Exception e) { - // 跨仓调用失败时返回空列表 - } - return result; - } - /** * 将某个人常用应用转化为桌面应用 */ diff --git a/src/main/java/com/yunhai/userhome/entity/AppCategory.java b/src/main/java/com/yunhai/userhome/entity/AppCategory.java new file mode 100644 index 0000000..2b994ff --- /dev/null +++ b/src/main/java/com/yunhai/userhome/entity/AppCategory.java @@ -0,0 +1,60 @@ +package com.yunhai.userhome.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.validation.constraints.NotNull; +import java.util.Date; + +/** + * 桌面应用类别(自 systemsetting.app_category 1:1 迁移)。 + * + *

roleType:1 校管理员 | 2 教师 | 3 学生(见 {@code enums.RoleType}); + * resDate 为资源更新时间戳,前端上传模板后经 UpdateResDate 刷新缓存。

+ */ +@AllArgsConstructor +@NoArgsConstructor +@Data +@Entity +@Table(name = "app_category") +public class AppCategory { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @NotNull(groups = Update.class) + private Integer id; + + private String name; + + @Column(name = "api_url", length = 500) + private String apiUrl; + + @Column(name = "data_key") + private String dataKey; + + /** 接口参数 JSON 数组字符串([{k,v,type}]) */ + @Column(name = "params_key", columnDefinition = "TEXT") + private String paramsKey; + + @Column(name = "role_type") + private Integer roleType; + + @Column(name = "c_id") + private Integer cId; + + @Column(name = "c_date") + private Date cDate = new Date(); + + /** 资源更新时间戳 */ + @Column(name = "res_date") + private Date resDate = new Date(); + + public @interface Update {} +} diff --git a/src/main/java/com/yunhai/userhome/entity/SchSettings.java b/src/main/java/com/yunhai/userhome/entity/SchSettings.java index c8e3dad..8be3da1 100644 --- a/src/main/java/com/yunhai/userhome/entity/SchSettings.java +++ b/src/main/java/com/yunhai/userhome/entity/SchSettings.java @@ -13,8 +13,8 @@ import javax.persistence.Table; /** * 学校设置(sch_settings 表,字段名/表名对齐旧 UserHome model.SchSettings)。 - *

注意:旧版 {@code SchSettingsService.getSchSettings} 并不查本地表,而是跨仓调用 - * {@code SCH_CONF_URL/oapi/getSchSetting},返回结构经 fastjson 映射为此实体。本工程保持同一行为。

+ *

本工程学校设置完全本地化:saveSchTheme/saveSchLogo 写入本地表,getSchSettings 直接查本地表, + * 不再依赖旧版跨仓 {@code SCH_CONF_URL/oapi/getSchSetting}。

*/ @AllArgsConstructor @NoArgsConstructor diff --git a/src/main/java/com/yunhai/userhome/enums/RoleType.java b/src/main/java/com/yunhai/userhome/enums/RoleType.java new file mode 100644 index 0000000..bb449e1 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/enums/RoleType.java @@ -0,0 +1,22 @@ +package com.yunhai.userhome.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * 桌面应用角色枚举(替代原 GetBaseDict 字典接口,前端本地枚举)。 + */ +@Getter +@NoArgsConstructor +@AllArgsConstructor +public enum RoleType { + + SCHOOL_ADMIN(1, "校管理员"), + TEACHER(2, "教师"), + STUDENT(3, "学生"), + ; + + private Integer key; + private String value; +} diff --git a/src/main/java/com/yunhai/userhome/repository/AppCategoryRepository.java b/src/main/java/com/yunhai/userhome/repository/AppCategoryRepository.java new file mode 100644 index 0000000..abc95c8 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/repository/AppCategoryRepository.java @@ -0,0 +1,12 @@ +package com.yunhai.userhome.repository; + +import com.yunhai.userhome.entity.AppCategory; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +public interface AppCategoryRepository extends JpaRepository, JpaSpecificationExecutor { + + List findAllByRoleType(Integer roleType); +} diff --git a/src/main/java/com/yunhai/userhome/service/IAppCategoryService.java b/src/main/java/com/yunhai/userhome/service/IAppCategoryService.java new file mode 100644 index 0000000..c3cbd79 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/service/IAppCategoryService.java @@ -0,0 +1,22 @@ +package com.yunhai.userhome.service; + +import com.yunhai.userhome.entity.AppCategory; +import org.springframework.data.domain.Page; + +import java.util.List; +import java.util.Optional; + +public interface IAppCategoryService { + + void save(AppCategory appCategory); + + void deleteById(Integer id); + + Optional findById(Integer id); + + List findByRoleType(Integer roleType); + + Page findPageList(Integer page, Integer count, Integer roleType, String name); + + void updateResDate(Integer id); +} diff --git a/src/main/java/com/yunhai/userhome/service/IUserSettingsService.java b/src/main/java/com/yunhai/userhome/service/IUserSettingsService.java index 04c56a7..472ebfd 100644 --- a/src/main/java/com/yunhai/userhome/service/IUserSettingsService.java +++ b/src/main/java/com/yunhai/userhome/service/IUserSettingsService.java @@ -14,6 +14,12 @@ public interface IUserSettingsService { List findWallList(Integer userId); + /** 管理视角壁纸列表(系统设置页):系统 + 目标学校,不含个人壁纸;isEdit 按调用者权限标记 */ + List findSchWallpaperManageList(BoaUser user, Integer targetSchId); + + /** 管理视角 Logo 列表(系统设置页):系统 + 目标学校 */ + List findSchLogoManageList(BoaUser user, Integer targetSchId); + void deleteWallById(Integer id, BoaUser user); void saveWallpaper(Wallpaper wallpaper); diff --git a/src/main/java/com/yunhai/userhome/service/impl/AppCategoryServiceImpl.java b/src/main/java/com/yunhai/userhome/service/impl/AppCategoryServiceImpl.java new file mode 100644 index 0000000..e9bd7d8 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/service/impl/AppCategoryServiceImpl.java @@ -0,0 +1,82 @@ +package com.yunhai.userhome.service.impl; + +import com.yunhai.platform.apistd.BizException; +import com.yunhai.platform.utils.exception.ErrorCode; +import com.yunhai.userhome.entity.AppCategory; +import com.yunhai.userhome.repository.AppCategoryRepository; +import com.yunhai.userhome.service.IAppCategoryService; +import org.springframework.beans.factory.annotation.Autowired; +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.stereotype.Service; + +import javax.persistence.criteria.Predicate; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Optional; + +/** + * 应用类别服务(自 systemsetting AppCategoryService 1:1 迁移,GetAppCategorySel/getTimestampByIds 无消费方不迁)。 + */ +@Service +public class AppCategoryServiceImpl implements IAppCategoryService { + + @Autowired + private AppCategoryRepository appCategoryRepository; + + @Override + public void save(AppCategory appCategory) { + appCategoryRepository.save(appCategory); + } + + @Override + public void deleteById(Integer id) { + if (!appCategoryRepository.existsById(id)) { + throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR); + } + appCategoryRepository.deleteById(id); + } + + @Override + public Optional findById(Integer id) { + return appCategoryRepository.findById(id); + } + + @Override + public List findByRoleType(Integer roleType) { + return appCategoryRepository.findAllByRoleType(roleType); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public Page findPageList(Integer page, Integer count, Integer roleType, String name) { + Sort sort = Sort.by(Sort.Direction.DESC, "id"); + Pageable pageable = PageRequest.of(page - 1, count, sort); + Specification specification = (Specification) (root, criteriaQuery, criteriaBuilder) -> { + List predicates = new ArrayList<>(); + if (roleType != null) { + predicates.add(criteriaBuilder.equal(root.get("roleType"), roleType)); + } + if (name != null && !name.trim().isEmpty()) { + predicates.add(criteriaBuilder.like(root.get("name"), "%" + name + "%")); + } + return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()])); + }; + return appCategoryRepository.findAll(specification, pageable); + } + + @Override + public void updateResDate(Integer id) { + Optional optionalAppCategory = findById(id); + if (!optionalAppCategory.isPresent()) { + throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR); + } + AppCategory model = optionalAppCategory.get(); + model.setResDate(new Date()); + appCategoryRepository.save(model); + } +} diff --git a/src/main/java/com/yunhai/userhome/service/impl/SchSettingsServiceImpl.java b/src/main/java/com/yunhai/userhome/service/impl/SchSettingsServiceImpl.java index fe3e853..d36243e 100644 --- a/src/main/java/com/yunhai/userhome/service/impl/SchSettingsServiceImpl.java +++ b/src/main/java/com/yunhai/userhome/service/impl/SchSettingsServiceImpl.java @@ -1,22 +1,16 @@ package com.yunhai.userhome.service.impl; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import com.yunhai.userhome.entity.SchSettings; import com.yunhai.userhome.repository.SchSettingsRepository; import com.yunhai.userhome.service.ISchSettingsService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; import java.util.Optional; /** - * 学校设置服务:行为对齐旧 UserHome SchSettingsService。 - *

关键:{@code findBySchId} 不查本地表,而是跨仓调用 {@code SCH_CONF_URL/oapi/getSchSetting}, - * 旧版如此(schConfig 服务为 homeImgUrl/isEnableDesktop/isLinkDesktop 等字段的权威来源), - * 因此本地 sch_settings 表变更类能力(saveSchTheme/saveSchLogo)本期仅保留 P1 占位写入本地表。

+ * 学校设置服务:学校设置完全本地化(sch_settings 表),不再依赖跨仓 schConfig。 + *

findBySchId 直接查本地表,查不到兜底默认主题;saveSchTheme/saveSchLogo 写本地表即可闭环。

*/ @Service public class SchSettingsServiceImpl implements ISchSettingsService { @@ -24,12 +18,6 @@ public class SchSettingsServiceImpl implements ISchSettingsService { @Autowired private SchSettingsRepository schSettingsRepository; - @Value("${SCH_CONF_URL:}") - private String schConfUrl; - - private final RestTemplate restTemplate = new RestTemplate(); - private final ObjectMapper objectMapper = new ObjectMapper(); - @Override public void save(SchSettings schSettings) { schSettingsRepository.save(schSettings); @@ -37,41 +25,16 @@ public class SchSettingsServiceImpl implements ISchSettingsService { @Override public Optional findBySchId(Integer schId) { - SchSettings model = new SchSettings(); - try { - if (schConfUrl == null || schConfUrl.isEmpty()) { - return Optional.of(localFallbackBySchId(schId)); - } - String apiPath = schConfUrl + "/oapi/getSchSetting?schId=" + schId; - String resultStr = restTemplate.getForObject(apiPath, String.class); - if (resultStr == null || resultStr.isEmpty()) { - return Optional.of(localFallbackBySchId(schId)); - } - JsonNode root = objectMapper.readTree(resultStr); - JsonNode dataNode = root.get("data"); - if (root.has("code") && "0".equals(root.get("code").asText()) && dataNode != null && !dataNode.isNull()) { - model = objectMapper.convertValue(dataNode, SchSettings.class); - } else { - return Optional.of(localFallbackBySchId(schId)); - } - } catch (Exception e) { - return Optional.of(localFallbackBySchId(schId)); - } - return Optional.of(model); - } - - /** 跨仓不通时先查本地表,再兜底默认主题(对齐旧版异常分支)。 */ - private SchSettings localFallbackBySchId(Integer schId) { Optional local = schSettingsRepository.findFirstBySchId(schId); if (local.isPresent()) { - return local.get(); + return local; } SchSettings def = new SchSettings(); def.setSchId(schId); def.setThemeName("default-theme"); def.setAppBgUrl(""); def.setLogoUrl(""); - return def; + return Optional.of(def); } @Override diff --git a/src/main/java/com/yunhai/userhome/service/impl/UserSettingsServiceImpl.java b/src/main/java/com/yunhai/userhome/service/impl/UserSettingsServiceImpl.java index 1f40fd9..f39dd37 100644 --- a/src/main/java/com/yunhai/userhome/service/impl/UserSettingsServiceImpl.java +++ b/src/main/java/com/yunhai/userhome/service/impl/UserSettingsServiceImpl.java @@ -73,6 +73,52 @@ public class UserSettingsServiceImpl implements IUserSettingsService { return resultList; } + @Override + public List findSchWallpaperManageList(BoaUser user, Integer targetSchId) { + UserCurrentRole currentRole = userCurrentRoleService.findById(user.getId()) + .orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR)); + boolean superAdmin = user.getType() == 1; + if (!superAdmin && !OtherUtil.isAdminById(currentRole.getRoleId())) { + throw new BizException(ErrorCode.FORBIDDEN); + } + Integer schId = superAdmin ? (targetSchId == null ? 0 : targetSchId) : currentRole.getSchId(); + List resultList = new ArrayList<>(); + List baseList = wallpaperRepository.findBySchIdAndType(0, 0); + List schList = wallpaperRepository.findBySchIdAndType(schId, 1); + if (superAdmin) { + baseList.forEach(x -> x.setIsEdit(true)); + schList.forEach(x -> x.setIsEdit(true)); + } else { + schList.forEach(x -> x.setIsEdit(true)); + } + resultList.addAll(baseList); + resultList.addAll(schList); + return resultList; + } + + @Override + public List findSchLogoManageList(BoaUser user, Integer targetSchId) { + UserCurrentRole currentRole = userCurrentRoleService.findById(user.getId()) + .orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR)); + boolean superAdmin = user.getType() == 1; + if (!superAdmin && !OtherUtil.isAdminById(currentRole.getRoleId())) { + throw new BizException(ErrorCode.FORBIDDEN); + } + Integer schId = superAdmin ? (targetSchId == null ? 0 : targetSchId) : currentRole.getSchId(); + List resultList = new ArrayList<>(); + List baseList = logoRepository.findBySchIdAndType(0, 0); + List schList = logoRepository.findBySchIdAndType(schId, 1); + if (superAdmin) { + baseList.forEach(x -> x.setIsEdit(true)); + schList.forEach(x -> x.setIsEdit(true)); + } else { + schList.forEach(x -> x.setIsEdit(true)); + } + resultList.addAll(baseList); + resultList.addAll(schList); + return resultList; + } + @Override @Transactional public void deleteWallById(Integer id, BoaUser user) { diff --git a/src/main/java/com/yunhai/userhome/utils/FileUtil.java b/src/main/java/com/yunhai/userhome/utils/FileUtil.java index 27e21cd..6e00c8f 100644 --- a/src/main/java/com/yunhai/userhome/utils/FileUtil.java +++ b/src/main/java/com/yunhai/userhome/utils/FileUtil.java @@ -6,13 +6,20 @@ import com.yunhai.platform.utils.exception.ErrorCode; import org.springframework.web.multipart.MultipartFile; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.nio.file.attribute.FileTime; +import java.time.Instant; import java.util.Arrays; import java.util.HashSet; import java.util.Locale; import java.util.Set; import java.util.UUID; +import java.util.zip.Deflater; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; /** * File工具类(对齐旧 UserHome utils.FileUtil,仅保留 uploadImg 方法——本期迁移实际使用的唯一方法)。 @@ -95,4 +102,156 @@ public class FileUtil { file.delete(); } } + + /** + * 通用文件上传(MultipartFile 版),保留原始扩展名,返回生成的文件名。 + *

与 {@link #uploadImg(MultipartFile, String)} 的区别:不做图片扩展名白名单校验, + * 供模板上传(zip/rar)等非图片场景使用,扩展名合法性由调用方自行校验。

+ */ + public static String uploadFile(MultipartFile file, String pathName) { + String imgName = null; + String path = null; + File floorFile = null; + try { + byte[] fileData = file.getBytes(); + String fileName = file.getOriginalFilename(); + int index = fileName == null ? -1 : fileName.lastIndexOf("."); + String ext = ""; + if (index > 0) { + ext = fileName.substring(index).toLowerCase(Locale.ROOT); + } + for (int i = 0; i < 100; i++) { + imgName = UUID.randomUUID().toString().substring(0, 8) + ext; + path = pathName + imgName; + floorFile = new File(path); + if (floorFile.exists()) continue; + else break; + } + FileOutputStream fos = new FileOutputStream(floorFile); + fos.write(fileData); + fos.close(); + } catch (IOException e) { + throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR, "上传失败"); + } + return imgName; + } + + /** + * 解压缩 ZIP 文件到目标目录(覆盖同名文件,防 zip-slip 路径穿越)。 + * + * @param zipFile 压缩包 + * @param destDir 目标目录 + */ + public static void zipDecompress(File zipFile, File destDir) { + byte[] buffer = new byte[1024]; + try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) { + ZipEntry entry = zis.getNextEntry(); + while (entry != null) { + File file = new File(destDir, entry.getName()); + String destPath = destDir.getCanonicalPath(); + String childPath = file.getCanonicalPath(); + if (!childPath.startsWith(destPath + File.separator)) { + throw new BizException(ErrorCode.CUSTOM, "压缩包内存在非法路径"); + } + if (entry.isDirectory()) { + file.mkdirs(); + } else { + File parent = file.getParentFile(); + if (!parent.exists()) { + parent.mkdirs(); + } + try (FileOutputStream fos = new FileOutputStream(file)) { + int len; + while ((len = zis.read(buffer)) > 0) { + fos.write(buffer, 0, len); + } + } + } + entry = zis.getNextEntry(); + } + } catch (IOException e) { + throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR, "解压失败"); + } + } + + /** + * 压缩文件/文件夹为 ZIP。 + * + * @param sourceFile 被压缩文件/文件夹 + * @param zipFile Zip 文件 + */ + public static void zipCompress(File sourceFile, File zipFile) { + try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))) { + zos.setMethod(ZipOutputStream.DEFLATED); + zos.setLevel(Deflater.BEST_COMPRESSION); + if (sourceFile.exists() && sourceFile.isDirectory() && sourceFile.listFiles() != null) { + Arrays.stream(sourceFile.listFiles()).forEach(file -> addZipFile(file, zos)); + } else { + addZipFile(sourceFile, zos); + } + } catch (IOException e) { + throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR, "压缩失败"); + } + } + + /** + * 向 ZIP 中添加单个文件(zipCompress 辅助)。 + */ + private static void addZipFile(File file, ZipOutputStream zos) { + if (!file.exists() || file.isDirectory()) { + throw new RuntimeException("文件不存在或该文件为文件夹,请检查"); + } + try (FileInputStream fis = new FileInputStream(file)) { + ZipEntry entry = new ZipEntry(file.getName()); + entry.setMethod(ZipEntry.DEFLATED); + entry.setSize(file.length()); + entry.setCreationTime(FileTime.from(Instant.now())); + entry.setLastAccessTime(FileTime.from(Instant.now())); + entry.setLastModifiedTime(FileTime.from(Instant.now())); + zos.putNextEntry(entry); + byte[] buf = new byte[1024]; + int len; + while ((len = fis.read(buf)) > 0) { + zos.write(buf, 0, len); + } + zos.closeEntry(); + } catch (IOException e) { + throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR, "压缩失败"); + } + } + + /** + * 删除文件夹(含内容)。 + */ + public static void delFolder(String folderPath) { + delAllFile(folderPath); + new File(folderPath).delete(); + } + + /** + * 删除指定文件夹下所有文件(保留目录本身)。 + */ + public static boolean delAllFile(String path) { + boolean flag = false; + File file = new File(path); + if (!file.exists() || !file.isDirectory()) { + return flag; + } + String[] tempList = file.list(); + if (tempList == null) { + return flag; + } + for (String s : tempList) { + File temp = new File(path, s); + if (temp.isFile()) { + temp.delete(); + } + if (temp.isDirectory()) { + delAllFile(temp.getPath()); + delFolder(temp.getPath()); + flag = true; + } + } + return flag; + } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index a632cb4..1bbbe9f 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -30,6 +30,11 @@ spring: hibernate: jdbc: time_zone: Asia/Shanghai + servlet: + multipart: + # 模板上传(zip/rar)等大文件支持,对齐 Nacos prod 配置 + max-file-size: 50MB + max-request-size: 200MB redis: host: localhost port: 6379 @@ -70,9 +75,7 @@ logging: # ===== 文件上传与学校配置 ===== # 文件存储根目录(UserSettingsController 壁纸/图标上传使用) # 本地默认 ./upload/(相对工作目录);生产由 Nacos 覆盖为 /data/upload(容器卷挂载到宿主机) -FILE_PATH: ./upload/ +FILE_PATH: D:/bsch/userhome/upload/ # 文件 Web 访问前缀(拼接壁纸完整 URL 用,见 UserSettingsController.getUserWallpaperList) # 本地 http://localhost:8070/upload/;生产由 Nacos 覆盖为 http://home.yunhaixingtong.com/userhome/upload/ FILE_WEB_PATH: http://localhost:8070/upload/ -# 学校配置接口基址(SchSettingsController 使用,prod 由 Nacos 覆盖) -SCH_CONF_URL: "" diff --git a/upload/icon/50b99d97.svg b/upload/icon/50b99d97.svg deleted file mode 100644 index aa19b16..0000000 --- a/upload/icon/50b99d97.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/upload/icon/6e322d2d.svg b/upload/icon/6e322d2d.svg deleted file mode 100644 index aa19b16..0000000 --- a/upload/icon/6e322d2d.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/upload/icon/763ef0ee.svg b/upload/icon/763ef0ee.svg deleted file mode 100644 index 6dab515..0000000 --- a/upload/icon/763ef0ee.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/upload/icon/76b68c06.svg b/upload/icon/76b68c06.svg deleted file mode 100644 index 6dab515..0000000 --- a/upload/icon/76b68c06.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/upload/icon/7e5e5cd7.svg b/upload/icon/7e5e5cd7.svg deleted file mode 100644 index aa19b16..0000000 --- a/upload/icon/7e5e5cd7.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/upload/wallpaper/3dabd97c.png b/upload/wallpaper/3dabd97c.png deleted file mode 100644 index 56a1b8e..0000000 Binary files a/upload/wallpaper/3dabd97c.png and /dev/null differ