upgrade:国际化多语言
This commit is contained in:
@@ -51,9 +51,11 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
|
||||
|
||||
protected final String COOL_PAGE_OP = "COOL_PAGE_OP";
|
||||
protected final String COOL_LIST_OP = "COOL_LIST_OP";
|
||||
protected final String COOL_INFO_OP = "COOL_INFO_OP";
|
||||
|
||||
private final ThreadLocal<CrudOption<T>> pageOption = new ThreadLocal<>();
|
||||
private final ThreadLocal<CrudOption<T>> listOption = new ThreadLocal<>();
|
||||
private final ThreadLocal<CrudOption<T>> infoOption = new ThreadLocal<>();
|
||||
private final ThreadLocal<JSONObject> requestParams = new ThreadLocal<>();
|
||||
|
||||
@ModelAttribute
|
||||
@@ -61,16 +63,20 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
|
||||
@RequestAttribute JSONObject requestParams) {
|
||||
String requestPath = ((ServletRequestAttributes) Objects.requireNonNull(
|
||||
RequestContextHolder.getRequestAttributes())).getRequest().getRequestURI();
|
||||
if (!requestPath.endsWith("/page") && !requestPath.endsWith("/list")) {
|
||||
if (!requestPath.endsWith("/page") && !requestPath.endsWith("/list")
|
||||
&& !requestPath.endsWith("/info")) {
|
||||
// 非page或list不执行
|
||||
return;
|
||||
}
|
||||
this.pageOption.set(new CrudOption<>(requestParams));
|
||||
this.listOption.set(new CrudOption<>(requestParams));
|
||||
this.infoOption.set(new CrudOption<>(requestParams));
|
||||
this.requestParams.set(requestParams);
|
||||
init(request, requestParams);
|
||||
request.setAttribute(COOL_PAGE_OP, this.pageOption.get());
|
||||
request.setAttribute(COOL_LIST_OP, this.listOption.get());
|
||||
request.setAttribute(COOL_INFO_OP, this.infoOption.get());
|
||||
|
||||
removeThreadLocal();
|
||||
}
|
||||
|
||||
@@ -87,6 +93,10 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
|
||||
return new CrudOption<>(this.requestParams.get());
|
||||
}
|
||||
|
||||
public void setInfoOption(CrudOption<T> infoOption) {
|
||||
this.infoOption.set(infoOption);
|
||||
}
|
||||
|
||||
public void setListOption(CrudOption<T> listOption) {
|
||||
this.listOption.set(listOption);
|
||||
}
|
||||
@@ -153,8 +163,11 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
|
||||
@Operation(summary = "信息", description = "根据ID查询单个信息")
|
||||
@GetMapping("/info")
|
||||
protected R<T> info(@RequestAttribute() JSONObject requestParams,
|
||||
@RequestParam() Long id) {
|
||||
return R.ok((T) service.info(requestParams, id));
|
||||
@RequestParam() Long id,
|
||||
@RequestAttribute(COOL_INFO_OP) CrudOption<T> option) {
|
||||
T info = (T) service.info(requestParams, id);
|
||||
invokerTransform(option, info);
|
||||
return R.ok(info);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,7 +232,7 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
|
||||
* @param page 分页返回数据
|
||||
*/
|
||||
protected PageResult<T> pageResult(Page<T> page) {
|
||||
return PageResult.of( page );
|
||||
return PageResult.of(page);
|
||||
}
|
||||
|
||||
public Class<T> currentEntityClass() {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.cool.core.exception;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.cool.core.util.I18nUtil;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import lombok.Getter;
|
||||
@@ -69,6 +70,7 @@ public class CoolPreconditions {
|
||||
}
|
||||
|
||||
private static String formatMessage(String messagePattern, Object... arguments) {
|
||||
messagePattern = I18nUtil.getI18nMsg(messagePattern);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int argumentIndex = 0;
|
||||
int placeholderIndex = messagePattern.indexOf("{}");
|
||||
|
||||
219
src/main/java/com/cool/core/i18n/I18nGenerator.java
Normal file
219
src/main/java/com/cool/core/i18n/I18nGenerator.java
Normal file
@@ -0,0 +1,219 @@
|
||||
package com.cool.core.i18n;
|
||||
|
||||
import static com.cool.core.util.I18nUtil.*;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.cool.core.lock.CoolLock;
|
||||
import com.cool.core.util.CoolPluginInvokers;
|
||||
import com.cool.core.util.I18nUtil;
|
||||
import com.cool.core.util.PathUtils;
|
||||
import com.cool.modules.base.entity.sys.BaseSysMenuEntity;
|
||||
import com.cool.modules.base.service.sys.BaseSysMenuService;
|
||||
import com.cool.modules.dict.entity.DictInfoEntity;
|
||||
import com.cool.modules.dict.entity.DictTypeEntity;
|
||||
import com.cool.modules.dict.service.DictInfoService;
|
||||
import com.cool.modules.dict.service.DictTypeService;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class I18nGenerator {
|
||||
private final BaseSysMenuService baseSysMenuService;
|
||||
private final DictTypeService dictTypeService;
|
||||
private final DictInfoService dictInfoService;
|
||||
private final CoolLock coolLock;
|
||||
private final I18nUtil i18nUtil;
|
||||
|
||||
private List<String> languages;
|
||||
private static final Duration DURATION = Duration.ofSeconds(30);
|
||||
public void run(Map<String, Object> map) {
|
||||
log.info("国际化 翻译...");
|
||||
languages = (List<String>) map.getOrDefault("languages", List.of("zh-cn", "zh-tw", "en"));
|
||||
path = (String) map.getOrDefault("path", "assets/i18n");
|
||||
init();
|
||||
log.info("✅国际化 翻译 成功!!!");
|
||||
enable = true;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
// 四个任务并发执行
|
||||
CompletableFuture<Void> futureMsg = CompletableFuture.runAsync(this::genBaseMsg);
|
||||
CompletableFuture<Void> futureMenu = CompletableFuture.runAsync(this::genBaseMenu);
|
||||
CompletableFuture<Void> futureDictInfo = CompletableFuture.runAsync(this::genBaseDictInfo);
|
||||
CompletableFuture<Void> futureDictType = CompletableFuture.runAsync(this::genBaseDictType);
|
||||
|
||||
// 等待全部执行完成
|
||||
CompletableFuture.allOf(futureMsg, futureMenu, futureDictInfo, futureDictType).join();
|
||||
}
|
||||
|
||||
private void genBaseMsg() {
|
||||
try {
|
||||
Map<String, String> msgMap = new HashMap<>();
|
||||
// 从idea本地启动时,从项目目录中读取
|
||||
Files.walk(Paths.get(System.getProperty("user.dir")))
|
||||
.filter(Files::isRegularFile)
|
||||
.filter(path -> path.toString().endsWith(".java"))
|
||||
.filter(path -> !path.toString().contains("/target/") && !path.toString().contains("/.git/"))
|
||||
.forEach(path -> msgMap.putAll(processFile(path)));
|
||||
if (ObjUtil.isNotEmpty(msgMap)) {
|
||||
// 系统异常信息,输出到resources/i18n 文件夹下,只有本地运行会生成
|
||||
File msgfile = FileUtil.file(PathUtils.getUserDir(),
|
||||
"src", "main", "resources", "cool", "i18n", "msg", "template.json");
|
||||
// 确保父目录存在
|
||||
FileUtil.mkParentDirs(msgfile);
|
||||
// 写入内容
|
||||
FileUtil.writeUtf8String(JSONUtil.toJsonStr(msgMap), msgfile);
|
||||
} else {
|
||||
try {
|
||||
// jar启动时,从jar包中读取
|
||||
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
||||
Resource resource = resolver.getResource("classpath:cool/i18n/msg/template.json");
|
||||
String content = FileUtil.readUtf8String(resource.getFile());
|
||||
msgMap.putAll(JSONUtil.toBean(content, Map.class));
|
||||
} catch (Exception e) {
|
||||
log.error("获取系统异常信息失败", e);
|
||||
}
|
||||
}
|
||||
extracted(MSG_PREFIX, msgMap);
|
||||
} catch (Exception e) {
|
||||
log.error("国际化系统异常信息失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成菜单信息国际化
|
||||
*/
|
||||
@Async
|
||||
public void asyncGenBaseMenu() {
|
||||
if (coolLock.tryLock(MENU_PREFIX, DURATION)) {
|
||||
genBaseMenu();
|
||||
coolLock.unlock(MENU_PREFIX);
|
||||
}
|
||||
}
|
||||
private void genBaseMenu() {
|
||||
try {
|
||||
Map<String, String> menuMap = baseSysMenuService.list(QueryWrapper.create().select(BaseSysMenuEntity::getName))
|
||||
.stream()
|
||||
.collect(Collectors.toMap(
|
||||
BaseSysMenuEntity::getName,
|
||||
BaseSysMenuEntity::getName,
|
||||
(oldValue, newValue) -> oldValue
|
||||
));
|
||||
extracted(MENU_PREFIX, menuMap);
|
||||
} catch (Exception e) {
|
||||
log.error("国际化菜单信息失败", e);
|
||||
}
|
||||
}
|
||||
@Async
|
||||
public void asyncGenBaseDictType() {
|
||||
if (coolLock.tryLock(DICT_TYPE_PREFIX, DURATION)) {
|
||||
genBaseDictType();
|
||||
coolLock.unlock(DICT_TYPE_PREFIX);
|
||||
}
|
||||
}
|
||||
private void genBaseDictType() {
|
||||
try {
|
||||
Map<String, String> dataMap = dictTypeService.list(QueryWrapper.create().select(DictTypeEntity::getName))
|
||||
.stream()
|
||||
.collect(Collectors.toMap(
|
||||
DictTypeEntity::getName,
|
||||
DictTypeEntity::getName,
|
||||
(oldValue, newValue) -> oldValue
|
||||
));
|
||||
extracted(DICT_TYPE_PREFIX, dataMap);
|
||||
} catch (Exception e) {
|
||||
log.error("国际化字段类型信息失败", e);
|
||||
}
|
||||
}
|
||||
@Async
|
||||
public void asyncGenBaseDictInfo() {
|
||||
if (coolLock.tryLock(DICT_INFO_PREFIX, DURATION)) {
|
||||
genBaseDictInfo();
|
||||
coolLock.unlock(DICT_INFO_PREFIX);
|
||||
}
|
||||
}
|
||||
private void genBaseDictInfo() {
|
||||
try {
|
||||
Map<String, String> dataMap = dictInfoService.list(QueryWrapper.create().select(DictInfoEntity::getName))
|
||||
.stream()
|
||||
.collect(Collectors.toMap(
|
||||
DictInfoEntity::getName,
|
||||
DictInfoEntity::getName,
|
||||
(oldValue, newValue) -> oldValue
|
||||
));
|
||||
extracted(DICT_INFO_PREFIX, dataMap);
|
||||
} catch (Exception e) {
|
||||
log.error("国际化字段类型信息失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void extracted(String prefix, Map<String, String> dataMap) {
|
||||
languages.forEach(language -> {
|
||||
String key = prefix + language;
|
||||
if (!i18nUtil.exist(key)) {
|
||||
JSONObject jsonObject = invokeTranslate(dataMap, language);
|
||||
if (ObjUtil.isNotNull(jsonObject)) {
|
||||
i18nUtil.update(key, jsonObject);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private JSONObject invokeTranslate(Map<String, String> map, String language) {
|
||||
return (JSONObject) CoolPluginInvokers.invoke("i18n", "invokeTranslate", map, language);
|
||||
}
|
||||
|
||||
// 匹配 CoolPreconditions 抛异常语句中的中文字符串
|
||||
private static final Pattern EXCEPTION_PATTERN = Pattern.compile(
|
||||
"CoolPreconditions\\.(\\w+)\\s*\\([^;]*?\"([^\"]*[\u4e00-\u9fa5]+[^\"]*)\"", Pattern.MULTILINE
|
||||
);
|
||||
|
||||
private static Map<String, String> processFile(Path path) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
try {
|
||||
String content = Files.readString(path, StandardCharsets.UTF_8);
|
||||
// 去掉注释
|
||||
content = removeComments(content);
|
||||
|
||||
// 仅查找方法体内的 CoolPreconditions 调用
|
||||
Matcher matcher = EXCEPTION_PATTERN.matcher(content);
|
||||
while (matcher.find()) {
|
||||
String chineseText = matcher.group(2).trim();
|
||||
map.put(chineseText, chineseText);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// 移除注释(单行与多行)
|
||||
private static String removeComments(String code) {
|
||||
String noMultiLine = code.replaceAll("/\\*.*?\\*/", ""); // 多行注释
|
||||
return noMultiLine.replaceAll("//.*", ""); // 单行注释
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
package com.cool.core.plugin;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class I18nGenerator {
|
||||
public static void main(String[] args) {
|
||||
new I18nGenerator().run();
|
||||
}
|
||||
public void run() {
|
||||
System.out.println("i18n translate ...");
|
||||
// 要生成的文件路径
|
||||
File msgfile = FileUtil.file(System.getProperty("user.dir"),
|
||||
"src", "main", "resources", "cool", "i18n", "msg", "en.json");
|
||||
if (!msgfile.exists()) {
|
||||
JSONObject jsonObject = genExceptionMsg();
|
||||
|
||||
// 确保父目录存在
|
||||
FileUtil.mkParentDirs(msgfile);
|
||||
// 写入内容
|
||||
FileUtil.writeUtf8String(JSONUtil.toJsonStr(jsonObject), msgfile);
|
||||
}
|
||||
// 要生成的文件路径
|
||||
File menufile = FileUtil.file(System.getProperty("user.dir"),
|
||||
"src", "main", "resources", "cool", "i18n", "menu", "en.json");
|
||||
if (!menufile.exists()) {
|
||||
JSONObject jsonObject = genBaseMenu();
|
||||
// 确保父目录存在
|
||||
FileUtil.mkParentDirs(menufile);
|
||||
// 写入内容
|
||||
FileUtil.writeUtf8String(JSONUtil.toJsonStr(jsonObject), menufile);
|
||||
}
|
||||
System.out.println("✅i18n translate success !!!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成菜单信息国际化
|
||||
*/
|
||||
private JSONObject genBaseMenu() {
|
||||
try {
|
||||
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
||||
Resource[] resources = resolver.getResources("classpath:cool/data/menu/*.json");
|
||||
Map<String, String> map = new HashMap<>();
|
||||
List<String> list = new ArrayList<>();
|
||||
// 遍历所有.json文件
|
||||
for (Resource resource : resources) {
|
||||
String jsonStr = IoUtil.read(resource.getInputStream(), StandardCharsets.UTF_8);
|
||||
// 使用 解析 JSON 字符串
|
||||
JSONArray jsonArray = JSONUtil.parseArray(jsonStr);
|
||||
// 遍历 JSON 数组
|
||||
for (Object obj : jsonArray) {
|
||||
JSONObject jsonObj = (JSONObject) obj;
|
||||
parseMenu(jsonObj, list);
|
||||
}
|
||||
}
|
||||
for (String value : list) {
|
||||
map.put(value, value);
|
||||
}
|
||||
return invokeTranslate(map, "en");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void parseMenu(JSONObject jsonObj, List<String> list) {
|
||||
list.add(jsonObj.getStr("name"));
|
||||
// 递归处理子菜单
|
||||
JSONArray childMenus = jsonObj.getJSONArray("childMenus");
|
||||
if (childMenus != null) {
|
||||
for (Object obj : childMenus) {
|
||||
JSONObject childObj = (JSONObject) obj;
|
||||
parseMenu(childObj, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成异常信息国际化
|
||||
*/
|
||||
private JSONObject genExceptionMsg() {
|
||||
Path rootPath = Paths.get(System.getProperty("user.dir"));
|
||||
try {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
Files.walk(rootPath)
|
||||
.filter(Files::isRegularFile)
|
||||
.filter(path -> path.toString().endsWith(".java"))
|
||||
.filter(path -> !path.toString().contains("/target/") && !path.toString().contains("/.git/"))
|
||||
.forEach(path -> map.putAll(processFile(path)));
|
||||
return invokeTranslate(map, "en");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private JSONObject invokeTranslate(Map<String, String> map, String language) {
|
||||
if (map.isEmpty()) {
|
||||
return new JSONObject();
|
||||
}
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("label", "i18n-node");
|
||||
data.put("params", Map.of("text", JSONUtil.toJsonStr(map), "language", language));
|
||||
data.put("stream", false);
|
||||
String res = HttpUtil.post("https://service.cool-js.com/api/open/flow/run/invoke", JSONUtil.toJsonStr(data));
|
||||
JSONObject jsonObject = JSONUtil.parseObj(res);
|
||||
return jsonObject.getJSONObject("data").getJSONObject("result").getJSONObject("data");
|
||||
}
|
||||
|
||||
// 匹配 CoolPreconditions 抛异常语句中的中文字符串
|
||||
private static final Pattern EXCEPTION_PATTERN = Pattern.compile(
|
||||
"CoolPreconditions\\.(\\w+)\\s*\\([^;]*?\"([^\"]*[\u4e00-\u9fa5]+[^\"]*)\"", Pattern.MULTILINE
|
||||
);
|
||||
|
||||
private static Map<String, String> processFile(Path path) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
try {
|
||||
String content = Files.readString(path, StandardCharsets.UTF_8);
|
||||
// 去掉注释
|
||||
content = removeComments(content);
|
||||
|
||||
// 仅查找方法体内的 CoolPreconditions 调用
|
||||
Matcher matcher = EXCEPTION_PATTERN.matcher(content);
|
||||
while (matcher.find()) {
|
||||
String chineseText = matcher.group(2).trim();
|
||||
map.put(chineseText, chineseText);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// 移除注释(单行与多行)
|
||||
private static String removeComments(String code) {
|
||||
String noMultiLine = code.replaceAll("/\\*.*?\\*/", ""); // 多行注释
|
||||
return noMultiLine.replaceAll("//.*", ""); // 单行注释
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,10 @@ package com.cool.core.plugin.consts;
|
||||
* 常量工具
|
||||
*/
|
||||
public interface PluginConsts {
|
||||
|
||||
/**
|
||||
* 国际化插件
|
||||
*/
|
||||
String i18n = "i18n";
|
||||
/**
|
||||
* 上传文件hook
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.cool.core.plugin.event;
|
||||
|
||||
public enum PluginActionEnum {
|
||||
INSTALL,
|
||||
UNINSTALL,
|
||||
UPDATE,
|
||||
}
|
||||
26
src/main/java/com/cool/core/plugin/event/PluginEvent.java
Normal file
26
src/main/java/com/cool/core/plugin/event/PluginEvent.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package com.cool.core.plugin.event;
|
||||
|
||||
import com.cool.modules.plugin.entity.PluginInfoEntity;
|
||||
import java.time.Clock;
|
||||
import lombok.Getter;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
public class PluginEvent extends ApplicationEvent {
|
||||
@Getter
|
||||
private String key;
|
||||
@Getter
|
||||
private PluginActionEnum actionEnum;
|
||||
@Getter
|
||||
private PluginInfoEntity pluginInfoEntity;
|
||||
public PluginEvent(Object source, String key, PluginActionEnum actionEnum, PluginInfoEntity data) {
|
||||
super(source);
|
||||
this.key = key;
|
||||
this.actionEnum = actionEnum;
|
||||
this.pluginInfoEntity = data;
|
||||
}
|
||||
|
||||
public PluginEvent(Object source, Clock clock) {
|
||||
super(source, clock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.cool.core.plugin.event;
|
||||
|
||||
import static com.cool.core.plugin.consts.PluginConsts.i18n;
|
||||
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import com.cool.core.i18n.I18nGenerator;
|
||||
import com.cool.core.util.I18nUtil;
|
||||
import com.cool.modules.plugin.entity.PluginInfoEntity;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class PluginEventListener implements ApplicationListener<PluginEvent> {
|
||||
private final I18nGenerator i18nGenerator;
|
||||
private final I18nUtil i18nUtil;
|
||||
@Async
|
||||
@Override
|
||||
public void onApplicationEvent(PluginEvent event) {
|
||||
if (ObjUtil.equals(event.getKey(), i18n)) {
|
||||
// 国际化插件变更
|
||||
PluginActionEnum actionEnum = event.getActionEnum();
|
||||
PluginInfoEntity pluginInfoEntity = event.getPluginInfoEntity();
|
||||
|
||||
if (ObjUtil.equals(actionEnum, PluginActionEnum.INSTALL) && ObjUtil.equals(pluginInfoEntity.getStatus(), 1)) {
|
||||
// 安装插件后,如果插件状态为启用,则生成国际化文件
|
||||
i18nGenerator.run((Map<String, Object>) pluginInfoEntity.getConfig());
|
||||
} else if (ObjUtil.equals(actionEnum, PluginActionEnum.UPDATE)) {
|
||||
if (ObjUtil.equals(pluginInfoEntity.getStatus(), 1)) {
|
||||
// 更新插件配置
|
||||
i18nGenerator.run((Map<String, Object>) pluginInfoEntity.getConfig());
|
||||
} else {
|
||||
// 停用
|
||||
I18nUtil.enable = false;
|
||||
}
|
||||
} else if (ObjUtil.equals(actionEnum, PluginActionEnum.UNINSTALL)) {
|
||||
// 卸载国际化插件,则删除国际化文件
|
||||
i18nUtil.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.cool.core.plugin.event;
|
||||
|
||||
import com.cool.modules.plugin.entity.PluginInfoEntity;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class PluginEventPublisher {
|
||||
private final ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
public void publish(String key, PluginActionEnum actionEnum, PluginInfoEntity data) {
|
||||
PluginEvent event = new PluginEvent(this, key, actionEnum, data);
|
||||
applicationEventPublisher.publishEvent(event);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -11,6 +11,8 @@ import com.cool.core.config.PluginJson;
|
||||
import com.cool.core.exception.CoolException;
|
||||
import com.cool.core.exception.CoolPreconditions;
|
||||
import com.cool.core.plugin.config.DynamicJarClassLoader;
|
||||
import com.cool.core.plugin.event.PluginActionEnum;
|
||||
import com.cool.core.plugin.event.PluginEventPublisher;
|
||||
import com.cool.core.util.CoolPluginInvokers;
|
||||
import com.cool.core.util.MapExtUtil;
|
||||
import com.cool.core.util.PathUtils;
|
||||
@@ -24,6 +26,7 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.exceptions.PersistenceException;
|
||||
@@ -43,14 +46,15 @@ public class CoolPluginService {
|
||||
|
||||
final private PluginInfoService pluginInfoService;
|
||||
|
||||
final private PluginEventPublisher pluginEventPublisher;
|
||||
|
||||
@Value("${cool.plugin.path}")
|
||||
private String pluginPath;
|
||||
|
||||
public void init() {
|
||||
List<PluginInfoEntity> list = pluginInfoService
|
||||
.list(QueryWrapper
|
||||
.create().select(PluginInfoEntity::getId, PluginInfoEntity::getPluginJson,
|
||||
PluginInfoEntity::getKey, PluginInfoEntity::getName)
|
||||
.create()
|
||||
.eq(PluginInfoEntity::getStatus, 1));
|
||||
if (ObjUtil.isEmpty(list)) {
|
||||
log.info("没有可初始化的插件");
|
||||
@@ -77,6 +81,7 @@ public class CoolPluginService {
|
||||
dynamicJarLoaderService.install(pluginJson.getJarPath(), true);
|
||||
// 设置配置
|
||||
CoolPluginInvokers.setPluginJson(entity.getKey(), entity);
|
||||
pluginEventPublisher.publish(entity.getKey(), PluginActionEnum.INSTALL, entity);
|
||||
} catch (Exception e) {
|
||||
log.error("初始化{}插件失败", entity.getName(), e);
|
||||
} finally {
|
||||
@@ -100,9 +105,10 @@ public class CoolPluginService {
|
||||
PluginJson pluginJson = dynamicJarLoaderService.install(jarFilePath, force);
|
||||
key = pluginJson.getKey();
|
||||
// 保存插件信息入库
|
||||
savePluginInfo(pluginJson, jarFilePath, jarFile, force);
|
||||
PluginInfoEntity pluginInfoEntity = savePluginInfo(pluginJson, jarFilePath, jarFile, force);
|
||||
// 把 ApplicationContext 对象传递打插件类中,使其在插件中也能正常使用spring bean对象
|
||||
CoolPluginInvokers.setApplicationContext(pluginJson.getKey());
|
||||
pluginEventPublisher.publish(pluginJson.getKey(), PluginActionEnum.INSTALL, pluginInfoEntity);
|
||||
} catch (PersistenceException persistenceException) {
|
||||
extractedAfterErr(jarFile, key);
|
||||
if (persistenceException.getMessage().contains("Duplicate entry")) {
|
||||
@@ -165,13 +171,14 @@ public class CoolPluginService {
|
||||
boolean flag = pluginInfoEntity.removeById();
|
||||
if (flag) {
|
||||
FileUtil.del(pluginInfoEntity.getPluginJson().getJarPath());
|
||||
pluginEventPublisher.publish(pluginInfoEntity.getKey(), PluginActionEnum.UNINSTALL, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存插件信息
|
||||
*/
|
||||
private void savePluginInfo(PluginJson pluginJson, String jarFilePath ,
|
||||
private PluginInfoEntity savePluginInfo(PluginJson pluginJson, String jarFilePath ,
|
||||
File jarFile,
|
||||
boolean force) {
|
||||
CoolPreconditions.checkEmpty(pluginJson, "插件安装失败");
|
||||
@@ -186,9 +193,11 @@ public class CoolPluginService {
|
||||
closeSameNamePlugin(pluginJson);
|
||||
// 覆盖插件
|
||||
coverPlugin(pluginJson, pluginInfo);
|
||||
return;
|
||||
return pluginInfo;
|
||||
}
|
||||
pluginInfo.setStatus(1);
|
||||
pluginInfo.save();
|
||||
return pluginInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,7 +210,7 @@ public class CoolPluginService {
|
||||
String oldJarPath = one.getPluginJson().getJarPath();
|
||||
// 重新加载配置不更新
|
||||
pluginInfo.setConfig(one.getConfig());
|
||||
pluginInfo.getPluginJson().setConfig(one.getConfig());
|
||||
pluginInfo.getPluginJson().setConfig((Map<String, Object>) one.getConfig());
|
||||
// 设置插件配置
|
||||
CoolPluginInvokers.setPluginJson(pluginInfo.getKey(), pluginInfo);
|
||||
CopyOptions options = CopyOptions.create().setIgnoreNullValue(true);
|
||||
@@ -274,10 +283,11 @@ public class CoolPluginService {
|
||||
entity.getId());
|
||||
// 调用插件更新配置标识
|
||||
boolean invokePluginConfig = false;
|
||||
if (!MapExtUtil.compareMaps(entity.getConfig(), dbPluginInfoEntity.getConfig())) {
|
||||
if (!MapExtUtil.compareMaps((Map<String, Object>) entity.getConfig(),
|
||||
(Map<String, Object>) dbPluginInfoEntity.getConfig())) {
|
||||
// 不一致,说明更新了配置
|
||||
entity.setPluginJson(dbPluginInfoEntity.getPluginJson());
|
||||
entity.getPluginJson().setConfig(entity.getConfig());
|
||||
entity.getPluginJson().setConfig((Map<String, Object>) entity.getConfig());
|
||||
// 更新了配置, 且插件是开启状态
|
||||
invokePluginConfig = ObjUtil.equals(dbPluginInfoEntity.getStatus(), 1);
|
||||
}
|
||||
@@ -290,6 +300,8 @@ public class CoolPluginService {
|
||||
CoolPluginInvokers.setPluginJson(dbPluginInfoEntity.getKey(), entity);
|
||||
}
|
||||
pluginInfoService.update(entity);
|
||||
pluginEventPublisher.publish(dbPluginInfoEntity.getKey(), PluginActionEnum.UPDATE, pluginInfoService.getPluginInfoEntityById(
|
||||
entity.getId()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,12 +31,14 @@ public class RequestParamsFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
|
||||
throws IOException, ServletException {
|
||||
throws IOException, ServletException {
|
||||
// 防止流读取一次后就没有了, 所以需要将流继续写出去
|
||||
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
JSONObject requestParams = new JSONObject();
|
||||
String language = request.getHeader("language");
|
||||
if (StrUtil.isNotEmpty(request.getContentType()) && request.getContentType().contains("multipart/form-data")) {
|
||||
servletRequest.setAttribute("requestParams", requestParams);
|
||||
servletRequest.setAttribute("cool-language", language);
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
} else {
|
||||
BodyReaderHttpServletRequestWrapper requestWrapper = new BodyReaderHttpServletRequestWrapper(request);
|
||||
@@ -57,7 +59,7 @@ public class RequestParamsFilter implements Filter {
|
||||
requestParams.set("tokenInfo", ((JWT) jwtObj).getPayload().getClaimsJson());
|
||||
}
|
||||
requestWrapper.setAttribute("requestParams", requestParams);
|
||||
|
||||
requestWrapper.setAttribute("cool-language", language);
|
||||
filterChain.doFilter(requestWrapper, servletResponse);
|
||||
}
|
||||
}
|
||||
|
||||
136
src/main/java/com/cool/core/util/I18nUtil.java
Normal file
136
src/main/java/com/cool/core/util/I18nUtil.java
Normal file
@@ -0,0 +1,136 @@
|
||||
package com.cool.core.util;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class I18nUtil {
|
||||
|
||||
public static final String MSG_PREFIX = "msg_";
|
||||
public static final String MENU_PREFIX = "menu_";
|
||||
public static final String DICT_INFO_PREFIX = "dictInfo_";
|
||||
public static final String DICT_TYPE_PREFIX = "dictType_";
|
||||
|
||||
public static boolean enable = false;
|
||||
|
||||
public static String path;
|
||||
public static String getLanguage() {
|
||||
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
|
||||
if (attributes == null) {
|
||||
return null;
|
||||
}
|
||||
return (String) attributes.getAttribute("cool-language", RequestAttributes.SCOPE_REQUEST);
|
||||
}
|
||||
|
||||
private static final Map<String, JSONObject> data = new ConcurrentHashMap<>();
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (!enable) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// 获取该目录下所有的 .json 文件
|
||||
List<File> jsonFiles = FileUtil.loopFiles(getPath(), file ->
|
||||
file.isFile() && file.getName().endsWith(".json")
|
||||
);
|
||||
jsonFiles.forEach(file -> {
|
||||
String parentName = file.getParentFile().getName();
|
||||
String content = FileUtil.readUtf8String(file);
|
||||
String key = parentName + "_" + file.getName().replace(".json", "");
|
||||
data.put(key, JSONUtil.parseObj(content));
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error("读取国际化文件失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean exist(String name) {
|
||||
// 获取该目录下所有的 .json 文件
|
||||
List<File> jsonFiles = FileUtil.loopFiles(getPath(), file ->
|
||||
file.isFile() && file.getName().endsWith(".json")
|
||||
);
|
||||
AtomicReference<Boolean> flag = new AtomicReference<>(false);
|
||||
jsonFiles.forEach(file -> {
|
||||
String parentName = file.getParentFile().getName();
|
||||
String key = parentName + "_" + file.getName().replace(".json", "");
|
||||
if (key.equals(name)) {
|
||||
flag.set(true);
|
||||
}
|
||||
});
|
||||
return flag.get();
|
||||
}
|
||||
|
||||
public static String getI18nMenu(String name) {
|
||||
return getI18n(name, MENU_PREFIX);
|
||||
}
|
||||
|
||||
public static String getI18nMsg(String name) {
|
||||
return getI18n(name, MSG_PREFIX);
|
||||
}
|
||||
|
||||
public static String getI18nDictInfo(String name) {
|
||||
return getI18n(name, DICT_INFO_PREFIX);
|
||||
}
|
||||
public static String getI18nDictType(String name) {
|
||||
return getI18n(name, DICT_TYPE_PREFIX);
|
||||
}
|
||||
private static String getI18n(String name, String prefix) {
|
||||
if (!enable) {
|
||||
return name;
|
||||
}
|
||||
String language = I18nUtil.getLanguage();
|
||||
if (language == null) {
|
||||
return name;
|
||||
}
|
||||
JSONObject jsonObject = data.get(prefix + language);
|
||||
if (jsonObject == null) {
|
||||
return name;
|
||||
}
|
||||
String str = jsonObject.getStr(name);
|
||||
if (str == null) {
|
||||
return name;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public void update(String key, JSONObject object) {
|
||||
data.put(key, object);
|
||||
String[] split = key.split("_");
|
||||
String absolutePath = getPath();
|
||||
File file = FileUtil.file(absolutePath, split[0], split[1] + ".json");
|
||||
// 确保父目录存在
|
||||
FileUtil.mkParentDirs(file);
|
||||
// 写入内容
|
||||
FileUtil.writeUtf8String(JSONUtil.toJsonStr(object), file);
|
||||
}
|
||||
|
||||
private String getPath() {
|
||||
String absolutePath = path;
|
||||
if (!PathUtils.isAbsolutePath(absolutePath)) {
|
||||
absolutePath = PathUtils.getUserDir() + File.separator + absolutePath;
|
||||
}
|
||||
return absolutePath;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
data.clear();
|
||||
List<File> jsonFiles = FileUtil.loopFiles(getPath(), file ->
|
||||
file.isFile() && file.getName().endsWith(".json")
|
||||
);
|
||||
jsonFiles.forEach(File::delete);
|
||||
enable = false;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import com.cool.core.annotation.TokenIgnore;
|
||||
import com.cool.core.eps.CoolEps;
|
||||
import com.cool.core.file.FileUploadStrategyFactory;
|
||||
import com.cool.core.request.R;
|
||||
import com.cool.core.util.I18nUtil;
|
||||
import com.cool.modules.base.entity.sys.BaseSysMenuEntity;
|
||||
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
|
||||
import com.cool.modules.base.service.sys.BaseSysLoginService;
|
||||
import com.cool.modules.base.service.sys.BaseSysPermsService;
|
||||
@@ -14,6 +16,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -67,7 +70,10 @@ public class AdminBaseCommController {
|
||||
@Operation(summary = "权限与菜单")
|
||||
@GetMapping("/permmenu")
|
||||
public R permmenu(@RequestAttribute() Long adminUserId) {
|
||||
return R.ok(baseSysPermsService.permmenu(adminUserId));
|
||||
Dict permmenu = baseSysPermsService.permmenu(adminUserId);
|
||||
List<BaseSysMenuEntity> list = (List<BaseSysMenuEntity>) permmenu.getObj("menus");
|
||||
list.forEach(o -> o.setName(I18nUtil.getI18nMenu(o.getName())));
|
||||
return R.ok(permmenu);
|
||||
}
|
||||
|
||||
@Operation(summary = "文件上传")
|
||||
|
||||
@@ -4,7 +4,9 @@ import cn.hutool.json.JSONObject;
|
||||
import com.cool.core.annotation.CoolRestController;
|
||||
import com.cool.core.base.BaseController;
|
||||
import com.cool.core.exception.CoolPreconditions;
|
||||
import com.cool.core.request.CrudOption;
|
||||
import com.cool.core.request.R;
|
||||
import com.cool.core.util.I18nUtil;
|
||||
import com.cool.modules.base.entity.sys.BaseSysMenuEntity;
|
||||
import com.cool.modules.base.service.sys.BaseSysMenuService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@@ -25,6 +27,14 @@ public class AdminBaseSysMenuController extends
|
||||
|
||||
@Override
|
||||
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
||||
CrudOption<BaseSysMenuEntity> transform = createOp()
|
||||
.transform(o -> {
|
||||
BaseSysMenuEntity entity = (BaseSysMenuEntity) o;
|
||||
entity.setName(I18nUtil.getI18nMenu(entity.getName()));
|
||||
});
|
||||
setPageOption(transform);
|
||||
setListOption(transform);
|
||||
setInfoOption(transform);
|
||||
}
|
||||
|
||||
@Operation(summary = "创建代码", description = "创建代码")
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.cool.modules.base.service.sys;
|
||||
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import com.cool.modules.base.entity.sys.BaseSysMenuEntity;
|
||||
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -117,7 +117,7 @@ public interface BaseSysPermsService {
|
||||
* @param adminUserId 登录的用户
|
||||
* @return 权限菜单
|
||||
*/
|
||||
Object permmenu(Long adminUserId);
|
||||
Dict permmenu(Long adminUserId);
|
||||
|
||||
/**
|
||||
* 更新角色权限
|
||||
|
||||
@@ -3,11 +3,13 @@ package com.cool.modules.base.service.sys.impl;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.cool.CoolApplication;
|
||||
import com.cool.core.base.BaseServiceImpl;
|
||||
import com.cool.core.base.ModifyEnum;
|
||||
import com.cool.core.eps.CoolEps;
|
||||
import com.cool.core.i18n.I18nGenerator;
|
||||
import com.cool.core.util.CompilerUtils;
|
||||
import com.cool.core.util.CoolSecurityUtil;
|
||||
import com.cool.core.util.PathUtils;
|
||||
@@ -62,6 +64,9 @@ public class BaseSysMenuServiceImpl extends BaseServiceImpl<BaseSysMenuMapper, B
|
||||
baseSysPermsService.refreshPermsByMenuId(id);
|
||||
}
|
||||
}
|
||||
if (ModifyEnum.ADD.equals(type) || ModifyEnum.UPDATE.equals(type)) {
|
||||
SpringUtil.getBean(I18nGenerator.class).asyncGenBaseMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -126,6 +131,7 @@ public class BaseSysMenuServiceImpl extends BaseServiceImpl<BaseSysMenuMapper, B
|
||||
@Override
|
||||
public boolean importMenu(List<BaseSysMenuEntity> menus) {
|
||||
menus.forEach(this::importMenu);
|
||||
SpringUtil.getBean(I18nGenerator.class).asyncGenBaseMenu();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -168,7 +168,7 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object permmenu(Long adminUserId) {
|
||||
public Dict permmenu(Long adminUserId) {
|
||||
return Dict.create().set("menus", getMenus(adminUserId)).set("perms", getPerms(adminUserId));
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,9 @@ import cn.hutool.json.JSONObject;
|
||||
import com.cool.core.annotation.CoolRestController;
|
||||
import com.cool.core.annotation.TokenIgnore;
|
||||
import com.cool.core.base.BaseController;
|
||||
import com.cool.core.request.CrudOption;
|
||||
import com.cool.core.request.R;
|
||||
import com.cool.core.util.I18nUtil;
|
||||
import com.cool.modules.dict.entity.DictInfoEntity;
|
||||
import com.cool.modules.dict.entity.table.DictInfoEntityTableDef;
|
||||
import com.cool.modules.dict.service.DictInfoService;
|
||||
@@ -26,8 +28,18 @@ public class AdminDictInfoController extends BaseController<DictInfoService, Dic
|
||||
@Override
|
||||
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
||||
setListOption(createOp().fieldEq(DictInfoEntityTableDef.DICT_INFO_ENTITY.TYPE_ID)
|
||||
.keyWordLikeFields(DictInfoEntityTableDef.DICT_INFO_ENTITY.NAME)
|
||||
.queryWrapper(QueryWrapper.create().orderBy(DictInfoEntityTableDef.DICT_INFO_ENTITY.CREATE_TIME, false)));
|
||||
.keyWordLikeFields(DictInfoEntityTableDef.DICT_INFO_ENTITY.NAME)
|
||||
.queryWrapper(QueryWrapper.create().orderBy(DictInfoEntityTableDef.DICT_INFO_ENTITY.CREATE_TIME, false))
|
||||
.transform(o -> {
|
||||
DictInfoEntity entity = (DictInfoEntity) o;
|
||||
entity.setName(I18nUtil.getI18nDictInfo(entity.getName()));
|
||||
}));
|
||||
CrudOption<DictInfoEntity> transform = createOp().transform(o -> {
|
||||
DictInfoEntity entity = (DictInfoEntity) o;
|
||||
entity.setName(I18nUtil.getI18nDictInfo(entity.getName()));
|
||||
});
|
||||
setPageOption(transform);
|
||||
setInfoOption(transform);
|
||||
}
|
||||
|
||||
@Operation(summary = "获得字典数据", description = "获得字典数据信息")
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
package com.cool.modules.dict.controller.admin;
|
||||
|
||||
import static com.cool.modules.dict.entity.table.DictTypeEntityTableDef.DICT_TYPE_ENTITY;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.cool.core.annotation.CoolRestController;
|
||||
import com.cool.core.base.BaseController;
|
||||
import com.cool.core.request.CrudOption;
|
||||
import com.cool.core.util.I18nUtil;
|
||||
import com.cool.modules.dict.entity.DictTypeEntity;
|
||||
import com.cool.modules.dict.service.DictTypeService;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import static com.cool.modules.dict.entity.table.DictTypeEntityTableDef.DICT_TYPE_ENTITY;
|
||||
|
||||
/**
|
||||
* 字典类型
|
||||
*/
|
||||
@@ -20,6 +22,15 @@ public class AdminDictTypeController extends BaseController<DictTypeService, Dic
|
||||
@Override
|
||||
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
||||
setPageOption(
|
||||
createOp().select(DICT_TYPE_ENTITY.ID, DICT_TYPE_ENTITY.KEY, DICT_TYPE_ENTITY.NAME));
|
||||
createOp().select(DICT_TYPE_ENTITY.ID, DICT_TYPE_ENTITY.KEY, DICT_TYPE_ENTITY.NAME).transform(o -> {
|
||||
DictTypeEntity entity = (DictTypeEntity) o;
|
||||
entity.setName(I18nUtil.getI18nDictType(entity.getName()));
|
||||
}));
|
||||
CrudOption<DictTypeEntity> transform = createOp().transform(o -> {
|
||||
DictTypeEntity entity = (DictTypeEntity) o;
|
||||
entity.setName(I18nUtil.getI18nDictType(entity.getName()));
|
||||
});
|
||||
setPageOption(transform);
|
||||
setInfoOption(transform);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,11 @@ import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.cool.core.base.BaseServiceImpl;
|
||||
import com.cool.core.base.ModifyEnum;
|
||||
import com.cool.core.i18n.I18nGenerator;
|
||||
import com.cool.modules.dict.entity.DictInfoEntity;
|
||||
import com.cool.modules.dict.entity.DictTypeEntity;
|
||||
import com.cool.modules.dict.mapper.DictInfoMapper;
|
||||
@@ -121,4 +125,10 @@ public class DictInfoServiceImpl extends BaseServiceImpl<DictInfoMapper, DictInf
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void modifyAfter(JSONObject requestParams, DictInfoEntity entity, ModifyEnum type) {
|
||||
if (ModifyEnum.ADD.equals(type) || ModifyEnum.UPDATE.equals(type)) {
|
||||
SpringUtil.getBean(I18nGenerator.class).asyncGenBaseDictInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,11 @@ package com.cool.modules.dict.service.impl;
|
||||
import static com.cool.modules.dict.entity.table.DictInfoEntityTableDef.DICT_INFO_ENTITY;
|
||||
import static com.cool.modules.dict.entity.table.DictTypeEntityTableDef.DICT_TYPE_ENTITY;
|
||||
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.cool.core.base.BaseServiceImpl;
|
||||
import com.cool.core.base.ModifyEnum;
|
||||
import com.cool.core.i18n.I18nGenerator;
|
||||
import com.cool.modules.dict.entity.DictTypeEntity;
|
||||
import com.cool.modules.dict.mapper.DictInfoMapper;
|
||||
import com.cool.modules.dict.mapper.DictTypeMapper;
|
||||
@@ -36,4 +40,11 @@ public class DictTypeServiceImpl extends BaseServiceImpl<DictTypeMapper, DictTyp
|
||||
return dictInfoMapper.deleteByQuery(
|
||||
QueryWrapper.create().and(DICT_INFO_ENTITY.TYPE_ID.in((Object) ids))) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyBefore(JSONObject requestParams, DictTypeEntity t, ModifyEnum type) {
|
||||
if (ModifyEnum.ADD.equals(type) || ModifyEnum.UPDATE.equals(type)) {
|
||||
SpringUtil.getBean(I18nGenerator.class).asyncGenBaseDictType();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,9 @@ package com.cool.modules.plugin.controller.admin;
|
||||
import static com.cool.modules.plugin.entity.table.PluginInfoEntityTableDef.PLUGIN_INFO_ENTITY;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.cool.core.annotation.CoolRestController;
|
||||
import com.cool.core.annotation.IgnoreRecycleData;
|
||||
import com.cool.core.base.BaseController;
|
||||
@@ -16,6 +18,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -45,6 +48,11 @@ public class AdminPluginInfoController extends BaseController<PluginInfoService,
|
||||
@PostMapping("/update")
|
||||
protected R update(@RequestBody PluginInfoEntity t,
|
||||
@RequestAttribute() JSONObject requestParams) {
|
||||
if (ObjUtil.isNotEmpty(t.getConfig())) {
|
||||
t.setConfig(JSONUtil.parseObj(t.getConfig()));
|
||||
} else {
|
||||
t.setConfig(new HashMap<>());
|
||||
}
|
||||
coolPluginService.updatePlugin(t);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import com.mybatisflex.core.handler.Fastjson2TypeHandler;
|
||||
import com.mybatisflex.core.handler.JacksonTypeHandler;
|
||||
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
|
||||
import com.tangzc.mybatisflex.autotable.annotation.UniIndex;
|
||||
import java.util.Map;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.dromara.autotable.annotation.Ignore;
|
||||
@@ -54,7 +53,7 @@ public class PluginInfoEntity extends BaseEntity<PluginInfoEntity> {
|
||||
|
||||
@ColumnDefine(comment = "配置", type = "json")
|
||||
@Column(typeHandler = JacksonTypeHandler.class)
|
||||
private Map<String, Object> config;
|
||||
private Object config;
|
||||
|
||||
@Ignore
|
||||
@Column(ignore = true)
|
||||
|
||||
Reference in New Issue
Block a user