package com.yunhai.userbase.controller.api; import com.yunhai.platform.utils.model.BoaUser; import com.yunhai.userbase.config.Config; import com.yunhai.userbase.enums.*; import com.yunhai.userbase.utils.*; import com.bestsch.utils.DException; import org.springframework.web.multipart.MultipartFile; import lombok.var; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.view.RedirectView; import java.util.*; import java.util.function.Supplier; @RestController @RequestMapping(value = Config.API_PATH +"/base/") public class BaseController { @Autowired private RedisUtil redisUtil; /** * 一般hashMap初始化大小 */ public static final int initialCapacity = 6; /** * 通用上传允许的子目录(与 MyWebAppConfigurer.addResourceHandlers 的资源映射一一对应)。
* 注:html 因 FileUtil 的危险后缀黑名单被禁止通过此接口上传,故未列入,避免存储可被浏览器执行的 HTML 引发 XSS。 */ private static final Set ALLOWED_UPLOAD_TYPES = new HashSet<>(Arrays.asList("image", "file", "icon", "word")); @GetMapping("GetUserInfo") public Object getUserInfo(BoaUser authUserWithDept){ return authUserWithDept; } //返回系统枚举2 @GetMapping("GetSysDict") public Map getSysDict(BoaUser authUserWithDept){ Map resultMap = new HashMap<>(7); resultMap.put("grouptype", IEnum.toSimpleMapList(GroupTypeEnum.class, "k", "v")); resultMap.put("gender", IEnum.toSimpleMapList(GenderEnum.class, "k", "v")); resultMap.put("client", IEnum.toSimpleMapList(ClientEnum.class, "k", "v")); resultMap.put("integ", IEnum.toSimpleMapList(IntegEnum.class, "k", "v")); resultMap.put("status", IEnum.toSimpleMapList(StatusEnum.class, "k", "v")); resultMap.put("sysrole", IEnum.toSimpleMapList(SysRoleEnum.class, "k", "v")); resultMap.put("mode", IEnum.toSimpleMapList(SysModeEnum.class, "k", "v")); return resultMap; } /** * 手动管理 Redis Hash 缓存的示例(@Cacheable 注解无法满足的场景)。
* 适用场景:需要把一个对象的多个字段按 Hash 结构存储,
* 可单独读写/更新某个字段,而不像 @Cacheable 那样把整个对象序列化成一个大 value。
* 访问路径:GET {Config.API_PATH}/base/ManualHashCacheDemo。
* 注:手动缓存依赖 Redis;Redis 不可用时 RedisUtil 已内部捕获异常,操作失败但不影响接口本身。 * * @return 本次演示各步骤的结果快照 */ @GetMapping("ManualHashCacheDemo") public Map manualHashCacheDemo() { Map result = new HashMap<>(8); String hashKey = "demo:user:1001"; // 1) 写入整张 hash(带 TTL):适合一次性缓存一个对象的多个属性 Map profile = new HashMap<>(4); profile.put("name", "yunhai"); profile.put("age", 18); profile.put("role", "admin"); redisUtil.hmset(hashKey, profile, 300); // 2) 只更新其中一个字段,无需整体覆盖 redisUtil.hset(hashKey, "role", "superadmin"); // 3) 读取单个字段 result.put("roleAfterUpdate", redisUtil.hget(hashKey, "role")); // 4) 读取整张 hash result.put("wholeHash", redisUtil.hmget(hashKey)); // 5) 判断字段是否存在 result.put("hasAgeField", redisUtil.hHasKey(hashKey, "age")); // 6) Cache-Aside(复用下方私有方法):字段不存在时回源并写回 Hash Object nickname = getHashFieldWithFallback(hashKey, "nickname", () -> "yunhai-nick"); result.put("nickname", nickname); // 7) 删除某个字段 redisUtil.hdel(hashKey, "age"); result.put("afterDelAge", redisUtil.hmget(hashKey)); return result; } @GetMapping("RedirectTo/{id}") public RedirectView RedirectTo(BoaUser authUserWithDept, @PathVariable(name = "id") String id) { String url= OtherUtil.hexToString(id); return new RedirectView(url,true); } /** * 通用文件上传接口(一个接口覆盖所有类型,无需按类型拆分)。
* type 决定存储子目录,与 MyWebAppConfigurer.addResourceHandlers 的 /upload/{type}/** 映射一一对应,
* 上传成功后可直接用返回的 URL 访问,无需再改资源映射配置。
* 访问路径:POST {Config.API_PATH}/base/UploadFile(multipart/form-data)。
* 支持 type:image / file / icon / word(html 被 FileUtil 黑名单禁止上传)。
* * @param file 上传文件(必填,单文件上限 50MB,见 application.yml 的 multipart 配置) * @param type 存储子目录类型,默认 image * @return 文件对外可访问的 Web URL */ @PostMapping("UploadFile") public String uploadFile(@RequestParam("file") MultipartFile file, @RequestParam(value = "type", defaultValue = "image") String type) { if (!ALLOWED_UPLOAD_TYPES.contains(type)) { throw new DException("不支持的上传类型: " + type + ",可选: image/file/icon/word"); } // FileUtil.upload 内部已处理空文件校验、危险后缀黑名单、目录创建与访问 URL 拼接 return FileUtil.upload(file, type); } /** * 私有方法(可复用):演示 Hash 结构的 Cache-Aside(缓存旁路)模式。
* 先从 Redis Hash 读字段;读不到则回源(此处用 fallback 模拟数据库查询),再把结果写回 Hash。
* * @param hashKey hash 键 * @param field 字段名 * @param fallback 回源加载器(真实场景替换为查数据库/远程调用) * @return 字段值 */ private Object getHashFieldWithFallback(String hashKey, String field, Supplier fallback) { if (redisUtil.hHasKey(hashKey, field)) { return redisUtil.hget(hashKey, field); } Object value = fallback.get(); if (value != null) { redisUtil.hset(hashKey, field, value); } return value; } }