init: UserBaseService (backend + deploy + scripts)
ci-userbase-service / build-and-push (push) Successful in 40s
ci-userbase-service / build-and-push (push) Successful in 40s
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
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 的资源映射一一对应)。<br>
|
||||
* 注:html 因 FileUtil 的危险后缀黑名单被禁止通过此接口上传,故未列入,避免存储可被浏览器执行的 HTML 引发 XSS。
|
||||
*/
|
||||
private static final Set<String> ALLOWED_UPLOAD_TYPES = new HashSet<>(Arrays.asList("image", "file", "icon", "word"));
|
||||
|
||||
@GetMapping("GetUserInfo")
|
||||
public Object getUserInfo(BoaUser authUserWithDept){
|
||||
return authUserWithDept;
|
||||
}
|
||||
|
||||
//返回系统枚举
|
||||
@GetMapping("GetSysDict")
|
||||
public Map getSysDict(BoaUser authUserWithDept){
|
||||
Map<String, List> 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 注解无法满足的场景)。<br>
|
||||
* 适用场景:需要把一个对象的多个字段按 Hash 结构存储,<br>
|
||||
* 可单独读写/更新某个字段,而不像 @Cacheable 那样把整个对象序列化成一个大 value。<br>
|
||||
* 访问路径:GET {Config.API_PATH}/base/ManualHashCacheDemo。<br>
|
||||
* 注:手动缓存依赖 Redis;Redis 不可用时 RedisUtil 已内部捕获异常,操作失败但不影响接口本身。
|
||||
*
|
||||
* @return 本次演示各步骤的结果快照
|
||||
*/
|
||||
@GetMapping("ManualHashCacheDemo")
|
||||
public Map<String, Object> manualHashCacheDemo() {
|
||||
Map<String, Object> result = new HashMap<>(8);
|
||||
String hashKey = "demo:user:1001";
|
||||
// 1) 写入整张 hash(带 TTL):适合一次性缓存一个对象的多个属性
|
||||
Map<String, Object> 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用文件上传接口(一个接口覆盖所有类型,无需按类型拆分)。<br>
|
||||
* type 决定存储子目录,与 MyWebAppConfigurer.addResourceHandlers 的 /upload/{type}/** 映射一一对应,<br>
|
||||
* 上传成功后可直接用返回的 URL 访问,无需再改资源映射配置。<br>
|
||||
* 访问路径:POST {Config.API_PATH}/base/UploadFile(multipart/form-data)。<br>
|
||||
* 支持 type:image / file / icon / word(html 被 FileUtil 黑名单禁止上传)。<br>
|
||||
*
|
||||
* @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(缓存旁路)模式。<br>
|
||||
* 先从 Redis Hash 读字段;读不到则回源(此处用 fallback 模拟数据库查询),再把结果写回 Hash。<br>
|
||||
*
|
||||
* @param hashKey hash 键
|
||||
* @param field 字段名
|
||||
* @param fallback 回源加载器(真实场景替换为查数据库/远程调用)
|
||||
* @return 字段值
|
||||
*/
|
||||
private Object getHashFieldWithFallback(String hashKey, String field, Supplier<Object> 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;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user