♻️ 重构 i18n 功能,新增 common-i18n,ballcat-i18n,移除原先的 extend-i18n,以及 i18n-starter
This commit is contained in:
@@ -16,10 +16,6 @@
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-common-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-spring-boot-starter-i18n</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-spring-boot-starter-web</artifactId>
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
package com.hccake.ballcat.admin.i18n.config;
|
||||
|
||||
import com.hccake.ballcat.autoconfigure.web.exception.resolver.GlobalHandlerExceptionResolver;
|
||||
import com.hccake.ballcat.common.core.constant.GlobalConstants;
|
||||
import com.hccake.ballcat.common.core.exception.BusinessException;
|
||||
import com.hccake.ballcat.common.core.exception.handler.GlobalExceptionHandler;
|
||||
import com.hccake.ballcat.common.model.result.R;
|
||||
import com.hccake.ballcat.common.model.result.SystemResultCode;
|
||||
import com.hccake.common.i18n.execute.TranslateExecuteWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.HttpMediaTypeNotSupportedException;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
|
||||
|
||||
import javax.validation.ValidationException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 国际化全局异常处理器
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@Slf4j
|
||||
@RestControllerAdvice
|
||||
public class I18NGlobalException extends GlobalHandlerExceptionResolver {
|
||||
|
||||
private final GlobalExceptionHandler globalExceptionHandler;
|
||||
|
||||
public I18NGlobalException(GlobalExceptionHandler globalExceptionHandler) {
|
||||
super(globalExceptionHandler);
|
||||
this.globalExceptionHandler = globalExceptionHandler;
|
||||
|
||||
}
|
||||
|
||||
@Value("${spring.profiles.active:prod}")
|
||||
private String profile;
|
||||
|
||||
/**
|
||||
* 异常业务key
|
||||
*/
|
||||
@Value("${ballcat.i18n.exceptionKey:exception}")
|
||||
private String exceptionCode;
|
||||
|
||||
public static final String PROD_ERR_MSG = "系统异常,请联系管理员";
|
||||
|
||||
public static final String NLP_MSG = "空指针异常!";
|
||||
|
||||
/**
|
||||
* 全局异常捕获
|
||||
* @param e the e
|
||||
* @return R
|
||||
*/
|
||||
@Override
|
||||
@ExceptionHandler(Exception.class)
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public R<String> handleGlobalException(Exception e) {
|
||||
log.error("全局异常信息 ex={}", e.getMessage(), e);
|
||||
globalExceptionHandler.handle(e);
|
||||
// 当为生产环境, 不适合把具体的异常信息展示给用户, 比如数据库异常信息.
|
||||
String errorMsg = GlobalConstants.ENV_PROD.equals(profile) ? PROD_ERR_MSG
|
||||
: (e instanceof NullPointerException ? NLP_MSG : e.getLocalizedMessage());
|
||||
String exceptionMsg = executeTranslate("global.exception", SystemResultCode.BAD_REQUEST.getCode(), errorMsg);
|
||||
return R.failed(SystemResultCode.SERVER_ERROR, exceptionMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* MethodArgumentTypeMismatchException 参数类型转换异常
|
||||
* @param e the e
|
||||
* @return R
|
||||
*/
|
||||
@Override
|
||||
@ExceptionHandler({ MethodArgumentTypeMismatchException.class })
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R<String> handleMethodArgumentTypeMismatchException(Exception e) {
|
||||
log.error("请求入参异常 ex={}", e.getMessage());
|
||||
globalExceptionHandler.handle(e);
|
||||
String message = GlobalConstants.ENV_PROD.equals(profile) ? PROD_ERR_MSG : e.getMessage();
|
||||
|
||||
String exceptionMsg = executeTranslate("method.argument.type.exception", SystemResultCode.BAD_REQUEST.getCode(),
|
||||
message);
|
||||
|
||||
return R.failed(SystemResultCode.BAD_REQUEST, exceptionMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求方式有问题 - MediaType 异常 - Method 异常
|
||||
* @return R
|
||||
*/
|
||||
@Override
|
||||
@ExceptionHandler({ HttpMediaTypeNotSupportedException.class, HttpRequestMethodNotSupportedException.class })
|
||||
public R<String> requestNotSupportedException(Exception e) {
|
||||
log.error("请求方式异常 ex={}", e.getMessage());
|
||||
globalExceptionHandler.handle(e);
|
||||
String exceptionMsg = executeTranslate("request.not.support.exception", SystemResultCode.BAD_REQUEST.getCode(),
|
||||
e.getLocalizedMessage());
|
||||
return R.failed(SystemResultCode.BAD_REQUEST, exceptionMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* IllegalArgumentException 异常捕获,主要用于Assert
|
||||
* @param e the e
|
||||
* @return R
|
||||
*/
|
||||
@Override
|
||||
@ExceptionHandler(IllegalArgumentException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R<String> handleIllegalArgumentException(IllegalArgumentException e) {
|
||||
log.error("非法数据输入 ex={}", e.getMessage());
|
||||
globalExceptionHandler.handle(e);
|
||||
String exceptionMsg = executeTranslate("illegal.argument.exception", SystemResultCode.BAD_REQUEST.getCode(),
|
||||
e.getMessage());
|
||||
return R.failed(SystemResultCode.BAD_REQUEST, exceptionMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* validation Exception
|
||||
* @param exception e
|
||||
* @return R
|
||||
*/
|
||||
@Override
|
||||
@ExceptionHandler({ MethodArgumentNotValidException.class, BindException.class })
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R<String> handleBodyValidException(BindException exception) {
|
||||
BindingResult bindingResult = exception.getBindingResult();
|
||||
String errorMsg = bindingResult.getErrorCount() > 0 ? bindingResult.getAllErrors().get(0).getDefaultMessage()
|
||||
: "未获取到错误信息!";
|
||||
|
||||
log.error("参数绑定异常,ex = {}", errorMsg);
|
||||
globalExceptionHandler.handle(exception);
|
||||
String exceptionMsg = executeTranslate("body.valid.exception", SystemResultCode.BAD_REQUEST.getCode(),
|
||||
errorMsg);
|
||||
return R.failed(SystemResultCode.BAD_REQUEST, exceptionMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 单体参数校验异常 validation Exception
|
||||
* @param e the e
|
||||
* @return R
|
||||
*/
|
||||
@Override
|
||||
@ExceptionHandler(ValidationException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R<String> handleValidationException(ValidationException e) {
|
||||
log.error("参数绑定异常 ex={}", e.getMessage());
|
||||
globalExceptionHandler.handle(e);
|
||||
String exceptionMsg = executeTranslate("valid.exception", SystemResultCode.BAD_REQUEST.getCode(),
|
||||
e.getLocalizedMessage());
|
||||
return R.failed(SystemResultCode.BAD_REQUEST, exceptionMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义业务异常捕获 业务异常响应码推荐使用200 用 result 结构中的code做为业务错误码标识
|
||||
* @param e the e
|
||||
* @return R
|
||||
*/
|
||||
@Override
|
||||
@ExceptionHandler(BusinessException.class)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public R<String> handleBallCatException(BusinessException e) {
|
||||
log.error("业务异常信息 ex={}", e.getMessage());
|
||||
globalExceptionHandler.handle(e);
|
||||
String exceptionMsg = executeTranslate("ballcat.exception", e.getCode(), e.getMessage());
|
||||
return R.failed(e.getCode(), exceptionMsg);
|
||||
}
|
||||
|
||||
private String executeTranslate(String code, Integer statusCode, String exceptionMsg) {
|
||||
return TranslateExecuteWrapper.translateText(exceptionCode, code, prodI18nErrorParam(statusCode, exceptionMsg));
|
||||
}
|
||||
|
||||
private Map<String, String> prodI18nErrorParam(Integer code, String exceptionMsg) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("code", String.valueOf(code));
|
||||
params.put("msg", exceptionMsg);
|
||||
return params;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.hccake.ballcat.admin.i18n.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* i18n admin properties
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@Component
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "ballcat.i18n")
|
||||
public class I18nAdminProperties {
|
||||
|
||||
/**
|
||||
* 请求头指定语言key
|
||||
*/
|
||||
private String langHeader = "lang";
|
||||
|
||||
/**
|
||||
* msg响应key code
|
||||
*/
|
||||
private String responseMsgKey = "response_msg";
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package com.hccake.ballcat.admin.i18n.config;
|
||||
|
||||
import com.hccake.ballcat.common.model.result.R;
|
||||
import com.hccake.common.i18n.execute.TranslateExecuteWrapper;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
||||
|
||||
/**
|
||||
* 只针对R的msg进行国际化处理
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@RestControllerAdvice
|
||||
public class I18nResponseAdvice implements ResponseBodyAdvice<R> {
|
||||
|
||||
private final I18nAdminProperties i18nAdminProperties;
|
||||
|
||||
@Override
|
||||
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
|
||||
return isSupport(methodParameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R beforeBodyWrite(R r, MethodParameter methodParameter, MediaType mediaType,
|
||||
Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest,
|
||||
ServerHttpResponse serverHttpResponse) {
|
||||
String responseMsg = TranslateExecuteWrapper.translateText(i18nAdminProperties.getResponseMsgKey(),
|
||||
r.getMessage());
|
||||
r.setMessage(responseMsg);
|
||||
TranslateExecuteWrapper.translateObject(r.getData());
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* 仅支持返回值类型为R 与不为错误处理器返回过来的类型
|
||||
* @param methodParameter 方法参数
|
||||
* @return true 支持 false 不支持
|
||||
*/
|
||||
private boolean isSupport(MethodParameter methodParameter) {
|
||||
return methodParameter.getMethod().getAnnotation(ExceptionHandler.class) == null
|
||||
&& methodParameter.getParameterType().isAssignableFrom(R.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package com.hccake.ballcat.admin.i18n.config;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.LocaleResolver;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 语言解析器 主要负责从头提取语言环境
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Configuration
|
||||
public class LocaleConfig {
|
||||
|
||||
private final I18nAdminProperties i18nAdminProperties;
|
||||
|
||||
/**
|
||||
* 区域解析器
|
||||
* @return @{link LocaleResolver}
|
||||
*/
|
||||
@Bean
|
||||
public LocaleResolver localeResolver() {
|
||||
MyLocaleResolver localeResolver = new MyLocaleResolver();
|
||||
return localeResolver;
|
||||
}
|
||||
|
||||
class MyLocaleResolver implements LocaleResolver {
|
||||
|
||||
@Override
|
||||
public Locale resolveLocale(HttpServletRequest request) {
|
||||
String language = request.getHeader(i18nAdminProperties.getLangHeader());
|
||||
if (StrUtil.isEmpty(language)) {
|
||||
// 路径上没有国际化语言参数,采用默认的(从请求头中获取)
|
||||
return request.getLocale();
|
||||
}
|
||||
else {
|
||||
// 格式语言_国家 en_US
|
||||
return StringUtils.parseLocale(language);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
|
||||
Locale locale) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
44
ballcat-common/ballcat-common-i18n/pom.xml
Normal file
44
ballcat-common/ballcat-common-i18n/pom.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ballcat-common</artifactId>
|
||||
<groupId>com.hccake</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ballcat-common-i18n</artifactId>
|
||||
<dependencies>
|
||||
<!-- slf4j日志 -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.annotation</groupId>
|
||||
<artifactId>jakarta.annotation-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.hccake.ballcat.common.i18n;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.support.AbstractMessageSource;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 动态获取的 MessageSource,比如从数据库 或者 redis 中获取 message 信息
|
||||
*
|
||||
* @author hccake
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class DynamicMessageSource extends AbstractMessageSource {
|
||||
|
||||
public static final String DYNAMIC_MESSAGE_SOURCE_BEAN_NAME = "dynamicMessageSource";
|
||||
|
||||
private final I18nMessageProvider i18nMessageProvider;
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected MessageFormat resolveCode(String code, Locale locale) {
|
||||
I18nMessage i18nMessage = i18nMessageProvider.getI18nMessage(code, locale);
|
||||
if (i18nMessage != null) {
|
||||
return createMessageFormat(i18nMessage.getMessage(), locale);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.hccake.ballcat.common.i18n;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 标注于需要国际化处理的类上, 配合 {@link I18nField} 使用,在响应时进行国际化处理
|
||||
* @see I18nResponseAdvice
|
||||
* @author hccake
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface I18nClass {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.hccake.ballcat.common.i18n;
|
||||
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 用于标注在需要国际化的 String 类型的属性上,用于标记其需要国际化。 必须在拥有 {@link I18nClass} 注解标记的类上
|
||||
* @author hccake
|
||||
*/
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface I18nField {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This is an alias for {@link #code}
|
||||
* </p>
|
||||
* @return String
|
||||
*/
|
||||
@AliasFor("code")
|
||||
String value() default "";
|
||||
|
||||
/**
|
||||
* 国际化的唯一标识, 当不传值时,则使用被标注的元素的值作为 code
|
||||
* @return String
|
||||
*/
|
||||
@AliasFor("value")
|
||||
String code() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.hccake.ballcat.common.i18n;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 对标于 message bundle 的文件消息的抽象
|
||||
*
|
||||
* @author hccake
|
||||
*/
|
||||
@Data
|
||||
public class I18nMessage {
|
||||
|
||||
/**
|
||||
* 唯一标识
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 消息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 地区语言标签
|
||||
*/
|
||||
private String languageTag;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.hccake.ballcat.common.i18n;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 国际化信息的提供者,使用者实现此接口,用于从数据库或者缓存中读取数据
|
||||
*
|
||||
* @author hccake
|
||||
*/
|
||||
public interface I18nMessageProvider {
|
||||
|
||||
/**
|
||||
* 获取 I18nMessage 对象
|
||||
* @param code 国际化唯一标识
|
||||
* @param locale 语言
|
||||
* @return 国际化消息
|
||||
*/
|
||||
I18nMessage getI18nMessage(String code, Locale locale);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package com.hccake.ballcat.common.i18n;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.NoSuchMessageException;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 利用 ResponseBodyAdvice 对返回结果进行国际化处理
|
||||
*
|
||||
* @author Yakir
|
||||
* @author hccake
|
||||
*/
|
||||
@Slf4j
|
||||
@RestControllerAdvice
|
||||
@RequiredArgsConstructor
|
||||
public class I18nResponseAdvice implements ResponseBodyAdvice<Object> {
|
||||
|
||||
private final MessageSource messageSource;
|
||||
|
||||
// todo 配置文件
|
||||
private Locale defaultLocal = Locale.SIMPLIFIED_CHINESE;
|
||||
|
||||
/**
|
||||
* supports all type
|
||||
* @param returnType MethodParameter
|
||||
* @param converterType 消息转换器
|
||||
* @return always true
|
||||
*/
|
||||
@Override
|
||||
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
|
||||
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
|
||||
ServerHttpResponse response) {
|
||||
switchLanguage(body);
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 对提供了 {@link I18nClass} 注解的类进行国际化处理,递归检查所有属性。
|
||||
* </p>
|
||||
* ps: 仅处理 String 类型,且注解了 {@link I18nField} 的属性
|
||||
* @param source 当前待处理的对象
|
||||
*/
|
||||
public void switchLanguage(Object source) {
|
||||
if (source == null) {
|
||||
return;
|
||||
}
|
||||
Class<?> sourceClass = source.getClass();
|
||||
// 只对添加了 I18nClass 注解的类进行处理
|
||||
I18nClass i18nClass = sourceClass.getAnnotation(I18nClass.class);
|
||||
if (i18nClass == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Field field : ReflectUtil.getFields(sourceClass)) {
|
||||
Class<?> fieldType = field.getType();
|
||||
Object fieldValue = ReflectUtil.getFieldValue(source, field);
|
||||
|
||||
if (fieldValue instanceof String) {
|
||||
// 若不存在国际化注解 直接跳过
|
||||
I18nField i18nField = field.getAnnotation(I18nField.class);
|
||||
if (i18nField == null) {
|
||||
continue;
|
||||
}
|
||||
// 获取国际化的唯一标识
|
||||
String annotationCode = i18nField.code();
|
||||
String code = StrUtil.isNotEmpty(annotationCode) ? annotationCode : (String) fieldValue;
|
||||
if (StrUtil.isEmpty(code)) {
|
||||
continue;
|
||||
}
|
||||
// 把当前 field 的值更新为国际化后的属性
|
||||
Locale locale = LocaleContextHolder.getLocale();
|
||||
String message;
|
||||
try {
|
||||
message = messageSource.getMessage(code, null, locale);
|
||||
}
|
||||
catch (NoSuchMessageException e) {
|
||||
log.warn("[switchLanguage]未找到对应的国际化配置,code: {}, local: {}.切换到默认的语言:{}", code, locale, defaultLocal);
|
||||
message = messageSource.getMessage(code, null, defaultLocal);
|
||||
}
|
||||
ReflectUtil.setFieldValue(source, field, message);
|
||||
}
|
||||
else if (fieldValue instanceof Collection) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<Object> elements = (Collection<Object>) fieldValue;
|
||||
if (CollectionUtil.isEmpty(elements)) {
|
||||
continue;
|
||||
}
|
||||
// 集合属性 递归处理
|
||||
for (Object element : elements) {
|
||||
switchLanguage(element);
|
||||
}
|
||||
}
|
||||
else if (fieldType.isArray()) {
|
||||
Object[] elements = (Object[]) fieldValue;
|
||||
if (elements == null || elements.length == 0) {
|
||||
continue;
|
||||
}
|
||||
// 数组 递归处理
|
||||
for (Object element : elements) {
|
||||
switchLanguage(element);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 其他类型的属性,递归判断处理
|
||||
switchLanguage(fieldValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.hccake.ballcat.common.i18n;
|
||||
|
||||
import org.springframework.context.HierarchicalMessageSource;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 用于修改 MessageSource 的层级关系,保证 DynamicMessageSource 在父级位置,减少开销
|
||||
*
|
||||
* @author hccake
|
||||
*/
|
||||
public class MessageSourceHierarchicalChanger {
|
||||
|
||||
@Resource(name = AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME)
|
||||
private MessageSource messageSource;
|
||||
|
||||
@Resource(name = DynamicMessageSource.DYNAMIC_MESSAGE_SOURCE_BEAN_NAME)
|
||||
private DynamicMessageSource dynamicMessageSource;
|
||||
|
||||
/**
|
||||
* 将 dynamicMessageSource 置为 messageSource 的父级<br/>
|
||||
* 若 messageSource 非层级,则将 messageSource 置为 dynamicMessageSource 的父级
|
||||
*/
|
||||
@PostConstruct
|
||||
public void changeMessageSourceParent() {
|
||||
// 优先走 messageSource,从资源文件中查找
|
||||
if (messageSource instanceof HierarchicalMessageSource) {
|
||||
HierarchicalMessageSource hierarchicalMessageSource = (HierarchicalMessageSource) messageSource;
|
||||
MessageSource parentMessageSource = hierarchicalMessageSource.getParentMessageSource();
|
||||
dynamicMessageSource.setParentMessageSource(parentMessageSource);
|
||||
hierarchicalMessageSource.setParentMessageSource(dynamicMessageSource);
|
||||
}
|
||||
else {
|
||||
dynamicMessageSource.setParentMessageSource(messageSource);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.hccake.ballcat.common.i18n;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 国际化信息的提供者,使用者实现此接口,用于从数据库或者缓存中读取数据
|
||||
*
|
||||
* @author hccake
|
||||
*/
|
||||
public class DefautlI18nMessageProvider {
|
||||
|
||||
private static final Map<String, I18nMessage> map = new ConcurrentHashMap<>();
|
||||
static {
|
||||
I18nMessage i18nMessage = new I18nMessage();
|
||||
i18nMessage.setMessage("你好啊");
|
||||
i18nMessage.setCode("test");
|
||||
i18nMessage.setLanguageTag("zh-CN");
|
||||
map.put("test:zh-CN", i18nMessage);
|
||||
|
||||
I18nMessage i18nMessage2 = new I18nMessage();
|
||||
i18nMessage2.setMessage("Hello");
|
||||
i18nMessage2.setCode("test");
|
||||
i18nMessage2.setLanguageTag("en-US");
|
||||
map.put("test:en-US", i18nMessage2);
|
||||
}
|
||||
|
||||
public I18nMessage getI18nMessage(String code, Locale locale) {
|
||||
String languageTag = locale.toLanguageTag();
|
||||
return map.get(code + ":" + languageTag);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,10 +7,15 @@
|
||||
<groupId>com.hccake</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>ballcat-common-model</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-common-i18n</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
@@ -23,16 +28,6 @@
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-extend-i18n-annotation</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.hccake.ballcat.common.model.result;
|
||||
|
||||
import com.hccake.common.i18n.annotation.I18nField;
|
||||
import com.hccake.ballcat.common.i18n.I18nClass;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.*;
|
||||
@@ -14,6 +14,7 @@ import java.io.Serializable;
|
||||
* @param <T>
|
||||
* @author Hccake
|
||||
*/
|
||||
@I18nClass
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
<module>ballcat-common-idempotent</module>
|
||||
<module>ballcat-common-log</module>
|
||||
<module>ballcat-common-redis</module>
|
||||
</modules>
|
||||
<module>ballcat-common-i18n</module>
|
||||
</modules>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -124,6 +124,11 @@
|
||||
<artifactId>ballcat-common-desensitize</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-common-i18n</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-common-idempotent</artifactId>
|
||||
@@ -235,21 +240,6 @@
|
||||
<artifactId>ballcat-spring-boot-starter-xss</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-extend-i18n-annotation</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-extend-i18n-core</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-spring-boot-starter-i18n</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-admin-i18n</artifactId>
|
||||
@@ -350,6 +340,22 @@
|
||||
<artifactId>ballcat-log-model</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<!-- i18n 国际化模块 -->
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-i18n-controller</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-i18n-biz</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-i18n-model</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!--swagger注解-->
|
||||
<dependency>
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.hccake.common.i18n.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* i18n field annotation
|
||||
* @author Yakir
|
||||
*/
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface I18nField {
|
||||
|
||||
/**
|
||||
* 业务
|
||||
* @return 业务码
|
||||
*/
|
||||
String businessCode();
|
||||
|
||||
/**
|
||||
* 范围值 若指定 则对此范围内的值进行国际化 不在范围的则使用默认值
|
||||
* @return 范围值
|
||||
*/
|
||||
String[] rangeValue() default {};
|
||||
|
||||
/**
|
||||
* 默认值
|
||||
*/
|
||||
String defaultValue() default "";
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.hccake.common.i18n;
|
||||
|
||||
import com.hccake.common.i18n.model.I18nItem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* i18n 数据提供 主要负责从数据库中提取数据
|
||||
*
|
||||
* @author Yakir
|
||||
* @since 2021/3/30
|
||||
*/
|
||||
public interface I18nDataProvider {
|
||||
|
||||
/**
|
||||
* 指定业务 业务码 语言环境
|
||||
* @param systemName
|
||||
* @param businessCode
|
||||
* @param code
|
||||
* @param language
|
||||
* @return
|
||||
*/
|
||||
I18nItem selectOne(String systemName, String businessCode, String code, String language);
|
||||
|
||||
/**
|
||||
* 查询列表 指定code 查询出所有语言环境
|
||||
* @param systemName
|
||||
* @param businessCode
|
||||
* @param code
|
||||
* @return
|
||||
*/
|
||||
List<I18nItem> selectListByCode(String systemName, String businessCode, String code);
|
||||
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package com.hccake.common.i18n;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* i18n properties
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "ballcat.i18n")
|
||||
public class I18nProperties {
|
||||
|
||||
/**
|
||||
* 系统名称
|
||||
*/
|
||||
private String systemName = "test-item";
|
||||
|
||||
/**
|
||||
* 缓存空值标记
|
||||
*/
|
||||
private String nullValue = "N_V";
|
||||
|
||||
/**
|
||||
* 执行器 主要用来对数据做附加操作
|
||||
*/
|
||||
private String executor = "simple";
|
||||
|
||||
/**
|
||||
* 生成器
|
||||
*/
|
||||
private Generate generate = new Generate();
|
||||
|
||||
/**
|
||||
* 缓存设置
|
||||
*/
|
||||
private Cache cache = new Cache();
|
||||
|
||||
@Data
|
||||
public class Generate {
|
||||
|
||||
/**
|
||||
* 生成器定界符
|
||||
*/
|
||||
private String delimiter = ":";
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public class Cache {
|
||||
|
||||
/**
|
||||
* 缓存类型
|
||||
*/
|
||||
private String type = "local";
|
||||
|
||||
/**
|
||||
* 过期时间(s) -1 表示永不过期
|
||||
*/
|
||||
private Long expire = -1L;
|
||||
|
||||
}
|
||||
|
||||
public boolean isNullValue(String val) {
|
||||
return this.nullValue.equals(val);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.hccake.common.i18n.cache;
|
||||
|
||||
/**
|
||||
* 缓存服务 规范国际化的缓存
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
public interface CacheService {
|
||||
|
||||
/**
|
||||
* 设置过期时间永不过期
|
||||
* @param cacheKey
|
||||
* @param cacheValue
|
||||
*/
|
||||
void put(String cacheKey, String cacheValue);
|
||||
|
||||
/**
|
||||
* 设置缓存
|
||||
* @param cacheKey 缓存key
|
||||
* @param cacheValue 值
|
||||
* @param expireTime 秒(S)为单位
|
||||
*/
|
||||
void put(String cacheKey, String cacheValue, Long expireTime);
|
||||
|
||||
/**
|
||||
* 根据key 得到数据
|
||||
* @param cacheKey 缓存key
|
||||
* @return string
|
||||
*/
|
||||
String get(String cacheKey);
|
||||
|
||||
/**
|
||||
* 根据key删除
|
||||
* @param cacheKey 缓存key
|
||||
*/
|
||||
void del(String cacheKey);
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.hccake.common.i18n.cache;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* local cache
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
public class LocalCacheService implements CacheService {
|
||||
|
||||
/**
|
||||
* 本地缓存 map
|
||||
*/
|
||||
private static final Map<String, String> CACHE_MAP = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void put(String cacheKey, String cacheValue) {
|
||||
put(cacheKey, cacheValue, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String cacheKey, String cacheValue, Long expireTime) {
|
||||
CACHE_MAP.put(cacheKey, cacheValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String cacheKey) {
|
||||
return CACHE_MAP.get(cacheKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void del(String cacheKey) {
|
||||
CACHE_MAP.remove(cacheKey);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.hccake.common.i18n.cache;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* redis 缓存
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class RedisCacheService implements CacheService {
|
||||
|
||||
private final StringRedisTemplate redisTemplate;
|
||||
|
||||
@Override
|
||||
public void put(String cacheKey, String cacheValue) {
|
||||
redisTemplate.opsForValue().set(cacheKey, cacheValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String cacheKey, String cacheValue, Long expireTime) {
|
||||
if (expireTime <= 0) {
|
||||
this.put(cacheKey, cacheValue);
|
||||
}
|
||||
else {
|
||||
redisTemplate.opsForValue().set(cacheKey, cacheValue, expireTime, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String cacheKey) {
|
||||
return redisTemplate.opsForValue().get(cacheKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void del(String cacheKey) {
|
||||
redisTemplate.delete(cacheKey);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
package com.hccake.common.i18n.execute;
|
||||
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* abstract translate execute
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
public abstract class AbstractTranslateExecute implements TranslateExecute {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void translateObject(Object source) {
|
||||
if (source == null) {
|
||||
return;
|
||||
}
|
||||
// 获取本地语言环境
|
||||
Locale locale = LocaleContextHolder.getLocale();
|
||||
String language = locale.toString();
|
||||
if (source instanceof List) {
|
||||
processObjects((List<Object>) source, language);
|
||||
}
|
||||
else if (source instanceof Set) {
|
||||
processObjects((Set) source, language);
|
||||
}
|
||||
else {
|
||||
processObject(source, language);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void translateObject(Object source, Map<String, String> params) {
|
||||
if (source == null) {
|
||||
return;
|
||||
}
|
||||
// 获取本地语言环境
|
||||
Locale locale = LocaleContextHolder.getLocale();
|
||||
String language = locale.toString();
|
||||
if (source instanceof List) {
|
||||
processObjects((List<Object>) source, language, params);
|
||||
}
|
||||
else if (source instanceof Set) {
|
||||
processObjects((Set<Object>) source, language, params);
|
||||
}
|
||||
else {
|
||||
processObject(source, language, params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理对象 不带参数的
|
||||
* @param object 处理数据对象
|
||||
* @param language 语言环境
|
||||
*/
|
||||
public abstract void processObject(Object object, String language);
|
||||
|
||||
/**
|
||||
* 处理对象 不带参数
|
||||
* @param sources 元对象集合
|
||||
* @param language 语言环境
|
||||
*/
|
||||
public abstract <T extends Collection> void processObjects(T sources, String language);
|
||||
|
||||
/**
|
||||
* 处理对象带参数 一批对象公用一份参数
|
||||
* @param sources 元对象集合
|
||||
* @param language 语言环境
|
||||
* @param params 参数
|
||||
*/
|
||||
public abstract <T extends Collection> void processObjects(T sources, String language, Map<String, String> params);
|
||||
|
||||
/**
|
||||
* 处理对象单个 带参数
|
||||
* @param source 元对象
|
||||
* @param language 语言环境
|
||||
* @param params 参数
|
||||
*/
|
||||
public abstract void processObject(Object source, String language, Map<String, String> params);
|
||||
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
package com.hccake.common.i18n.execute;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ClassUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.hccake.common.i18n.annotation.I18nField;
|
||||
import com.hccake.common.i18n.executor.ExecutorWrapper;
|
||||
import com.hccake.common.i18n.handler.TranslateHandler;
|
||||
import com.hccake.common.i18n.handler.TranslateHandlerHolder;
|
||||
import com.hccake.common.i18n.model.I18nValueItem;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 翻译执行器
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class DefaultTranslateExecute extends AbstractTranslateExecute {
|
||||
|
||||
private final ExecutorWrapper executorWrapper;
|
||||
|
||||
@Override
|
||||
public String translateText(String businessCode, String code) {
|
||||
String languageName = LocaleContextHolder.getLocale().toString();
|
||||
return translateText(businessCode, code, languageName, null, code);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String translateText(String businessCode, String code, String languageName) {
|
||||
return translateText(businessCode, code, languageName, null, code);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String translateText(String businessCode, String code, Map<String, String> params) {
|
||||
String languageName = LocaleContextHolder.getLocale().toString();
|
||||
return translateText(businessCode, code, languageName, params, code);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String translateText(String businessCode, String code, String languageName,
|
||||
Map<String, String> paramValues) {
|
||||
return translateText(businessCode, code, languageName, paramValues, code);
|
||||
}
|
||||
|
||||
public String translateText(String businessCode, String code, String languageName, Map<String, String> paramValues,
|
||||
String defaultValue) {
|
||||
I18nValueItem i18nValueItem = executorWrapper.selectLocaleLanguage(businessCode, code, languageName);
|
||||
if (i18nValueItem == null) {
|
||||
return code;
|
||||
}
|
||||
Integer type = i18nValueItem.getType();
|
||||
String tplValue = i18nValueItem.getTplValue();
|
||||
TranslateHandler translateHandler = TranslateHandlerHolder.getTranslateHandler(type);
|
||||
Assert.notNull(translateHandler, "translateHandler can not be Null");
|
||||
String resultValue = translateHandler.translateText(tplValue, paramValues);
|
||||
return StrUtil.isNotEmpty(resultValue) ? resultValue : defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Collection> void processObjects(T sources, String language, Map<String, String> params) {
|
||||
if (CollectionUtil.isEmpty(sources)) {
|
||||
return;
|
||||
}
|
||||
for (Object source : sources) {
|
||||
processObject(source, language, params);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Collection> void processObjects(T sources, String language) {
|
||||
this.processObjects(sources, language, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processObject(Object source, String language) {
|
||||
this.processObject(source, language, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processObject(Object source, String language, Map<String, String> params) {
|
||||
if (source == null) {
|
||||
return;
|
||||
}
|
||||
Class<?> sourceClass = source.getClass();
|
||||
// 若为基本类型 或string类中直接跳过
|
||||
if (isBaseTypeOrString(sourceClass)) {
|
||||
return;
|
||||
}
|
||||
for (Field field : sourceClass.getDeclaredFields()) {
|
||||
Class<?> fieldType = field.getType();
|
||||
// 若为排除类型直接跳过
|
||||
if (isExcludeFieldType(fieldType)) {
|
||||
continue;
|
||||
}
|
||||
if (List.class.isAssignableFrom(fieldType)) {
|
||||
// 防止实体对象里面防止list属性
|
||||
List<Object> elementsList = getFieldValue(field, source);
|
||||
if (CollectionUtil.isEmpty(elementsList)) {
|
||||
continue;
|
||||
}
|
||||
processObjects(elementsList, language);
|
||||
continue;
|
||||
}
|
||||
else if (Set.class.isAssignableFrom(fieldType)) {
|
||||
Set elementSet = getFieldValue(field, source);
|
||||
if (CollectionUtil.isEmpty(elementSet)) {
|
||||
continue;
|
||||
}
|
||||
processObjects(new ArrayList<>(elementSet), language);
|
||||
continue;
|
||||
}
|
||||
// 若不存在国际化注解 直接跳过
|
||||
if (!field.isAnnotationPresent(I18nField.class)) {
|
||||
continue;
|
||||
}
|
||||
// 设置字段为可进入
|
||||
String fieldValue = getFieldValue(field, source);
|
||||
// 若字段值为空 则直接跳过
|
||||
if (StrUtil.isEmpty(fieldValue)) {
|
||||
continue;
|
||||
}
|
||||
I18nField annotation = field.getAnnotation(I18nField.class);
|
||||
String[] rangeValue = annotation.rangeValue();
|
||||
String defaultValue = annotation.defaultValue();
|
||||
// rangeValue 不为空 并且当前元素 不在范围值内 直接跳过
|
||||
if (ArrayUtil.isNotEmpty(rangeValue) && !ArrayUtil.contains(rangeValue, fieldValue)) {
|
||||
continue;
|
||||
}
|
||||
String businessCode = annotation.businessCode();
|
||||
I18nValueItem i18nValueItem = executorWrapper.selectLocaleLanguage(businessCode, fieldValue, language);
|
||||
if (i18nValueItem == null) {
|
||||
continue;
|
||||
}
|
||||
String tplValue = i18nValueItem.getTplValue();
|
||||
Integer type = i18nValueItem.getType();
|
||||
TranslateHandler translateHandler = TranslateHandlerHolder.getTranslateHandler(type);
|
||||
if (translateHandler == null) {
|
||||
continue;
|
||||
}
|
||||
String afterValue = translateHandler.translateText(tplValue, params);
|
||||
if (StrUtil.isEmpty(afterValue)) {
|
||||
if (StrUtil.isEmpty(defaultValue)) {
|
||||
continue;
|
||||
}
|
||||
afterValue = defaultValue;
|
||||
}
|
||||
// 设置进字段
|
||||
setFieldValue(field, source, afterValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为基础类型 或String 类型
|
||||
* @param sourceClass
|
||||
* @return
|
||||
*/
|
||||
private boolean isBaseTypeOrString(Class<?> sourceClass) {
|
||||
return ClassUtil.isBasicType(sourceClass) || String.class.isAssignableFrom(sourceClass);
|
||||
}
|
||||
|
||||
private <T> T getFieldValue(Field field, Object obj) {
|
||||
try {
|
||||
if (!field.isAccessible()) {
|
||||
field.setAccessible(true);
|
||||
}
|
||||
return (T) field.get(obj);
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
log.error("字段值获取失败", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置字段值
|
||||
* @param field 字段
|
||||
* @param obj 对象
|
||||
* @param val 新值
|
||||
*/
|
||||
private void setFieldValue(Field field, Object obj, String val) {
|
||||
try {
|
||||
if (!field.isAccessible()) {
|
||||
field.setAccessible(true);
|
||||
}
|
||||
field.set(obj, val);
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
log.error("国际化处理结果回填失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为排除字段类型
|
||||
* @param clazz string List map 保留
|
||||
* @return true 排除 false 进行翻译
|
||||
*/
|
||||
public boolean isExcludeFieldType(Class clazz) {
|
||||
if (String.class.isAssignableFrom(clazz) || List.class.isAssignableFrom(clazz)
|
||||
|| Set.class.isAssignableFrom(clazz)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.hccake.common.i18n.execute;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface TranslateExecute {
|
||||
|
||||
/**
|
||||
* 翻译文本使用默认语言环境
|
||||
* @param businessCode
|
||||
* @param code
|
||||
* @return
|
||||
*/
|
||||
String translateText(String businessCode, String code);
|
||||
|
||||
/**
|
||||
* 翻译文本 指定语言环境
|
||||
* @param businessCode
|
||||
* @param code
|
||||
* @param language
|
||||
* @return
|
||||
*/
|
||||
String translateText(String businessCode, String code, String language);
|
||||
|
||||
/**
|
||||
* 翻译文本使用当前语言环境
|
||||
* @param businessCode
|
||||
* @param code
|
||||
* @param params
|
||||
* @return
|
||||
*/
|
||||
String translateText(String businessCode, String code, Map<String, String> params);
|
||||
|
||||
/**
|
||||
* 翻译文本 指定语言环境
|
||||
* @param businessCode
|
||||
* @param code
|
||||
* @param language
|
||||
* @param params
|
||||
* @return
|
||||
*/
|
||||
String translateText(String businessCode, String code, String language, Map<String, String> params);
|
||||
|
||||
/**
|
||||
* 翻译对象 直接进行字段值更新
|
||||
* @param source
|
||||
*/
|
||||
void translateObject(Object source);
|
||||
|
||||
/**
|
||||
* 翻译单个对象 可以指定参数
|
||||
* @param source
|
||||
* @param params
|
||||
*/
|
||||
void translateObject(Object source, Map<String, String> params);
|
||||
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package com.hccake.common.i18n.execute;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 翻译执行包装器
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
public class TranslateExecuteWrapper {
|
||||
|
||||
private static TranslateExecute translateExecute;
|
||||
|
||||
public static String translateText(String businessCode, String code) {
|
||||
return translateExecute.translateText(businessCode, code);
|
||||
}
|
||||
|
||||
public static String translateText(String businessCode, String code, String language) {
|
||||
return translateExecute.translateText(businessCode, code, language);
|
||||
}
|
||||
|
||||
public static String translateText(String businessCode, String code, Map<String, String> params) {
|
||||
return translateExecute.translateText(businessCode, code, params);
|
||||
}
|
||||
|
||||
public static String translateText(String businessCode, String code, String language, Map<String, String> params) {
|
||||
return translateExecute.translateText(businessCode, code, language, params);
|
||||
}
|
||||
|
||||
public static void translateObject(Object source) {
|
||||
translateExecute.translateObject(source);
|
||||
}
|
||||
|
||||
public static void translateObject(Object source, Map<String, String> params) {
|
||||
translateExecute.translateObject(source, params);
|
||||
}
|
||||
|
||||
public void setTranslateExecute(TranslateExecute translateExecute) {
|
||||
TranslateExecuteWrapper.translateExecute = translateExecute;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package com.hccake.common.i18n.executor;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.hccake.ballcat.common.util.JsonUtils;
|
||||
import com.hccake.common.i18n.I18nDataProvider;
|
||||
import com.hccake.common.i18n.I18nProperties;
|
||||
import com.hccake.common.i18n.cache.CacheService;
|
||||
import com.hccake.common.i18n.generate.KeyGenerate;
|
||||
import com.hccake.common.i18n.model.I18nItem;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 简单执行器 主要负责数据提取与缓存
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class CacheExecutor implements Executor {
|
||||
|
||||
private final I18nDataProvider i18nDataProvider;
|
||||
|
||||
private final I18nProperties i18nProperties;
|
||||
|
||||
private final KeyGenerate keyGenerate;
|
||||
|
||||
private final CacheService cacheService;
|
||||
|
||||
@Override
|
||||
public I18nItem selectOne(String systemName, String businessCode, String code, String language) {
|
||||
String key = keyGenerate.generateKey(systemName, businessCode, code, language);
|
||||
String cacheValue = cacheService.get(key);
|
||||
// 若为空值标记 则直接返回
|
||||
if (i18nProperties.isNullValue(cacheValue)) {
|
||||
return null;
|
||||
}
|
||||
if (StrUtil.isNotEmpty(cacheValue)) {
|
||||
return JsonUtils.toObj(cacheValue, I18nItem.class);
|
||||
}
|
||||
I18nItem i18nItem = i18nDataProvider.selectOne(systemName, businessCode, code, language);
|
||||
|
||||
cacheService.put(key,
|
||||
ObjectUtil.isNotEmpty(i18nItem) ? JsonUtils.toJson(i18nItem) : i18nProperties.getNullValue(),
|
||||
i18nProperties.getCache().getExpire());
|
||||
|
||||
return i18nItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<I18nItem> selectListByCode(String systemName, String businessCode, String code) {
|
||||
String key = keyGenerate.generateKey(systemName, businessCode, code);
|
||||
String cacheValue = cacheService.get(key);
|
||||
// 若为空值标记 则直接返回
|
||||
if (i18nProperties.isNullValue(cacheValue)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
if (StrUtil.isNotEmpty(cacheValue)) {
|
||||
return JsonUtils.toObj(cacheValue, List.class);
|
||||
}
|
||||
List<I18nItem> i18nItems = i18nDataProvider.selectListByCode(systemName, businessCode, code);
|
||||
|
||||
cacheService.put(key,
|
||||
ObjectUtil.isNotEmpty(i18nItems) ? JsonUtils.toJson(i18nItems) : i18nProperties.getNullValue(),
|
||||
i18nProperties.getCache().getExpire());
|
||||
|
||||
return i18nItems;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.hccake.common.i18n.executor;
|
||||
|
||||
import com.hccake.common.i18n.model.I18nItem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 执行器 主要负责数据提取与附加操作
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
public interface Executor {
|
||||
|
||||
/**
|
||||
* 指定业务 业务码 语言环境
|
||||
* @param systemName 系统名称
|
||||
* @param businessCode 业务
|
||||
* @param code key
|
||||
* @param language 语言环境
|
||||
* @return 值
|
||||
*/
|
||||
I18nItem selectOne(String systemName, String businessCode, String code, String language);
|
||||
|
||||
/**
|
||||
* 查询列表 指定code 查询出所有语言环境
|
||||
* @param systemName 系统名称
|
||||
* @param businessCode 业务码
|
||||
* @param code key
|
||||
* @return 值列表
|
||||
*/
|
||||
List<I18nItem> selectListByCode(String systemName, String businessCode, String code);
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package com.hccake.common.i18n.executor;
|
||||
|
||||
import com.hccake.common.i18n.I18nProperties;
|
||||
import com.hccake.common.i18n.model.I18nItem;
|
||||
import com.hccake.common.i18n.model.I18nValueItem;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* 执行者包装类 主要负责数据的处理转换
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class ExecutorWrapper {
|
||||
|
||||
private final I18nProperties i18nProperties;
|
||||
|
||||
private final Executor executor;
|
||||
|
||||
/**
|
||||
* 获取系统名
|
||||
* @return
|
||||
*/
|
||||
private String getSystemName() {
|
||||
return i18nProperties.getSystemName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询区域项 语言
|
||||
* @param businessCode
|
||||
* @param code
|
||||
* @param language
|
||||
* @return {@link I18nValueItem} 对应处理后的国际化值
|
||||
*/
|
||||
public I18nValueItem selectLocaleLanguage(String businessCode, String code, String language) {
|
||||
I18nItem i18nItem = executor.selectOne(getSystemName(), businessCode, code, language);
|
||||
if (i18nItem == null) {
|
||||
return null;
|
||||
}
|
||||
return convertI18nValueItem(i18nItem);
|
||||
}
|
||||
|
||||
private I18nValueItem convertI18nValueItem(I18nItem e) {
|
||||
return new I18nValueItem().setTplValue(e.getValue()).setType(e.getType());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.hccake.common.i18n.executor;
|
||||
|
||||
import com.hccake.common.i18n.I18nDataProvider;
|
||||
import com.hccake.common.i18n.model.I18nItem;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 简单执行器 主要负责数据提取与缓存
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class SimpleExecutor implements Executor {
|
||||
|
||||
private final I18nDataProvider i18nDataProvider;
|
||||
|
||||
@Override
|
||||
public I18nItem selectOne(String systemName, String businessCode, String code, String language) {
|
||||
return i18nDataProvider.selectOne(systemName, businessCode, code, language);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<I18nItem> selectListByCode(String systemName, String businessCode, String code) {
|
||||
return i18nDataProvider.selectListByCode(systemName, businessCode, code);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.hccake.common.i18n.generate;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import com.hccake.common.i18n.I18nProperties;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* 默认key生成
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class DefaultKeyGenerate implements KeyGenerate {
|
||||
|
||||
private final I18nProperties i18nProperties;
|
||||
|
||||
@Override
|
||||
public String generateKey(String... params) {
|
||||
Assert.noNullElements(params, "params size must be greater than 0 ");
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
I18nProperties.Generate generate = i18nProperties.getGenerate();
|
||||
for (String param : params) {
|
||||
stringBuilder.append(param).append(generate.getDelimiter());
|
||||
}
|
||||
return stringBuilder.deleteCharAt(stringBuilder.length() - 1).toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.hccake.common.i18n.generate;
|
||||
|
||||
/**
|
||||
* 缓存key生成器
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
public interface KeyGenerate {
|
||||
|
||||
/**
|
||||
* 缓存 key 生成
|
||||
* @param params 参数数组
|
||||
* @return 指定分隔符字符串
|
||||
*/
|
||||
String generateKey(String... params);
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.hccake.common.i18n.handler;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* simple translate handler
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class SimpleTranslateHandler implements TranslateHandler {
|
||||
|
||||
@Override
|
||||
public String translateText(String originalText, Map<String, String> paramValues) {
|
||||
return originalText;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.hccake.common.i18n.handler;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* template translate handler
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class TemplateTranslateHandler implements TranslateHandler {
|
||||
|
||||
@Override
|
||||
public String translateText(String originalText, Map<String, String> paramValues) {
|
||||
return StrUtil.format(originalText, paramValues);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.hccake.common.i18n.handler;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 翻译处理器 具体执行处理逻辑
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
public interface TranslateHandler {
|
||||
|
||||
/**
|
||||
* 翻译文本
|
||||
* @param originalText 原始文本
|
||||
* @param paramValues 参数值
|
||||
* @return 翻译后的值
|
||||
*/
|
||||
String translateText(String originalText, Map<String, String> paramValues);
|
||||
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
package com.hccake.common.i18n.handler;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* translate handler holder
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class TranslateHandlerHolder {
|
||||
|
||||
/**
|
||||
* 处理器map元素
|
||||
*/
|
||||
private static final Map<Class<? extends TranslateHandler>, TranslateHandler> HANDLER_MAP = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 枚举类型type标记 与类型的映射
|
||||
*/
|
||||
private static final Map<Integer, Class<? extends TranslateHandler>> TYPE_CLASS_MAP = new HashMap<>();
|
||||
|
||||
static {
|
||||
|
||||
TYPE_CLASS_MAP.put(1, SimpleTranslateHandler.class);
|
||||
TYPE_CLASS_MAP.put(2, TemplateTranslateHandler.class);
|
||||
|
||||
HANDLER_MAP.put(SimpleTranslateHandler.class, new SimpleTranslateHandler());
|
||||
HANDLER_MAP.put(TemplateTranslateHandler.class, new TemplateTranslateHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到处理器
|
||||
* @param clazz TranslateHandler的Class
|
||||
* @return @{code TranslateHandler实现}
|
||||
*/
|
||||
public static TranslateHandler getTranslateHandler(Class<? extends TranslateHandler> clazz) {
|
||||
return HANDLER_MAP.get(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加处理器
|
||||
* @param clazz TranslateHandler的Class
|
||||
* @param translateHandler TranslateHandler实现
|
||||
* @return @{code TranslateHandler实现}
|
||||
*/
|
||||
public static TranslateHandler addTranslateHandler(Class<? extends TranslateHandler> clazz,
|
||||
TranslateHandler translateHandler) {
|
||||
return HANDLER_MAP.put(clazz, translateHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到处理器 主要拓展 绑定type 与类的映射
|
||||
* @param type type
|
||||
* @return @{code TranslateHandler实现}
|
||||
*/
|
||||
public static TranslateHandler getTranslateHandler(Integer type) {
|
||||
return HANDLER_MAP.get(TYPE_CLASS_MAP.get(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加处理器 主要拓展 绑定type 与类的映射
|
||||
* @param type 类型1.明文 2.模板
|
||||
* @param clazz TranslateHandler的Class
|
||||
* @param translateHandler TranslateHandler实现
|
||||
* @return @{code TranslateHandler实现}
|
||||
*/
|
||||
public static TranslateHandler addTranslateHandler(Integer type, Class<? extends TranslateHandler> clazz,
|
||||
TranslateHandler translateHandler) {
|
||||
TYPE_CLASS_MAP.put(type, clazz);
|
||||
return HANDLER_MAP.put(clazz, translateHandler);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package com.hccake.common.i18n.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* i18n item
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
public class I18nItem {
|
||||
|
||||
/**
|
||||
* 系统名称
|
||||
*/
|
||||
private String systemName;
|
||||
|
||||
/**
|
||||
* 业务码
|
||||
*/
|
||||
private String businessCode;
|
||||
|
||||
/**
|
||||
* 分组code
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 语言环境
|
||||
*/
|
||||
private String language;
|
||||
|
||||
/**
|
||||
* 值
|
||||
*/
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.hccake.common.i18n.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* i18n
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class I18nValueItem {
|
||||
|
||||
/**
|
||||
* 模板值
|
||||
*/
|
||||
private String tplValue;
|
||||
|
||||
/**
|
||||
* 类型 1.明文 2.模板
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ballcat-extends</artifactId>
|
||||
<groupId>com.hccake</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ballcat-extend-i18n</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>ballcat-extend-i18n-annotation</module>
|
||||
<module>ballcat-extend-i18n-core</module>
|
||||
</modules>
|
||||
</project>
|
||||
@@ -19,7 +19,6 @@
|
||||
<module>ballcat-extend-pay-virtual</module>
|
||||
<module>ballcat-extend-pay-ali</module>
|
||||
<module>ballcat-extend-pay-wx</module>
|
||||
<module>ballcat-extend-i18n</module>
|
||||
<module>ballcat-extend-redis-module</module>
|
||||
</modules>
|
||||
</project>
|
||||
25
ballcat-i18n/ballcat-i18n-biz/pom.xml
Normal file
25
ballcat-i18n/ballcat-i18n-biz/pom.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ballcat-i18n</artifactId>
|
||||
<groupId>com.hccake</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ballcat-i18n-biz</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-i18n-model</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-extend-mybatis-plus</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.hccake.ballcat.i18n.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.hccake.ballcat.i18n.converter.I18nDataConverter;
|
||||
import com.hccake.ballcat.i18n.model.entity.I18nData;
|
||||
import com.hccake.ballcat.i18n.model.qo.I18nDataQO;
|
||||
import com.hccake.ballcat.i18n.model.vo.I18nDataPageVO;
|
||||
import com.hccake.ballcat.common.model.domain.PageParam;
|
||||
import com.hccake.ballcat.common.model.domain.PageResult;
|
||||
import com.hccake.extend.mybatis.plus.conditions.query.LambdaQueryWrapperX;
|
||||
import com.hccake.extend.mybatis.plus.mapper.ExtendMapper;
|
||||
import com.hccake.extend.mybatis.plus.toolkit.WrappersX;
|
||||
|
||||
/**
|
||||
* 国际化信息
|
||||
*
|
||||
* @author hccake 2021-08-04 11:31:49
|
||||
*/
|
||||
public interface I18nDataMapper extends ExtendMapper<I18nData> {
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
* @param pageParam 分页参数
|
||||
* @param qo 查询参数
|
||||
* @return PageResult<I18nDataPageVO> VO分页数据
|
||||
*/
|
||||
default PageResult<I18nDataPageVO> queryPage(PageParam pageParam, I18nDataQO qo) {
|
||||
IPage<I18nData> page = this.prodPage(pageParam);
|
||||
LambdaQueryWrapperX<I18nData> wrapper = WrappersX.lambdaQueryX(I18nData.class);
|
||||
this.selectPage(page, wrapper);
|
||||
IPage<I18nDataPageVO> voPage = page.convert(I18nDataConverter.INSTANCE::poToPageVo);
|
||||
return new PageResult<>(voPage.getRecords(), voPage.getTotal());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 code 和 languageTag 查询指定的 I18nData
|
||||
* @param code 唯一标识
|
||||
* @param languageTag 语言标识
|
||||
* @return I18nData
|
||||
*/
|
||||
default I18nData selectByCodeAndLanguageTag(String code, String languageTag) {
|
||||
LambdaQueryWrapper<I18nData> wrapper = Wrappers.lambdaQuery(I18nData.class).eq(I18nData::getCode, code)
|
||||
.eq(I18nData::getLanguageTag, languageTag);
|
||||
return this.selectOne(wrapper);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.hccake.ballcat.i18n.provider;
|
||||
|
||||
import com.hccake.ballcat.common.i18n.I18nMessage;
|
||||
import com.hccake.ballcat.common.i18n.I18nMessageProvider;
|
||||
import com.hccake.ballcat.i18n.model.entity.I18nData;
|
||||
import com.hccake.ballcat.i18n.service.I18nDataService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author hccake
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class CustomI18nMessageProvider implements I18nMessageProvider {
|
||||
|
||||
private final I18nDataService i18nDataService;
|
||||
|
||||
@Override
|
||||
public I18nMessage getI18nMessage(String code, Locale locale) {
|
||||
String languageTag = locale.toLanguageTag();
|
||||
I18nData i18nData = i18nDataService.getByCodeAndLanguageTag(code, languageTag);
|
||||
if (i18nData == null) {
|
||||
return null;
|
||||
}
|
||||
I18nMessage i18nMessage = new I18nMessage();
|
||||
i18nMessage.setMessage(i18nData.getMessage());
|
||||
i18nMessage.setCode(i18nData.getCode());
|
||||
i18nMessage.setLanguageTag(i18nData.getCode());
|
||||
return i18nMessage;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.hccake.ballcat.i18n.service;
|
||||
|
||||
import com.hccake.ballcat.i18n.model.entity.I18nData;
|
||||
import com.hccake.ballcat.i18n.model.vo.I18nDataPageVO;
|
||||
import com.hccake.ballcat.i18n.model.qo.I18nDataQO;
|
||||
import com.hccake.ballcat.common.model.domain.PageParam;
|
||||
import com.hccake.ballcat.common.model.domain.PageResult;
|
||||
import com.hccake.extend.mybatis.plus.service.ExtendService;
|
||||
|
||||
/**
|
||||
* 国际化信息
|
||||
*
|
||||
* @author hccake 2021-08-04 11:31:49
|
||||
*/
|
||||
public interface I18nDataService extends ExtendService<I18nData> {
|
||||
|
||||
/**
|
||||
* 根据QueryObeject查询分页数据
|
||||
* @param pageParam 分页参数
|
||||
* @param qo 查询参数对象
|
||||
* @return PageResult<I18nDataPageVO> 分页数据
|
||||
*/
|
||||
PageResult<I18nDataPageVO> queryPage(PageParam pageParam, I18nDataQO qo);
|
||||
|
||||
/**
|
||||
* 根据 code 和 languageTag 查询指定的 I18nData
|
||||
* @param code 唯一标识
|
||||
* @param languageTag 语言标识
|
||||
* @return I18nData
|
||||
*/
|
||||
I18nData getByCodeAndLanguageTag(String code, String languageTag);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.hccake.ballcat.i18n.service.impl;
|
||||
|
||||
import com.hccake.ballcat.i18n.model.entity.I18nData;
|
||||
import com.hccake.ballcat.i18n.model.vo.I18nDataPageVO;
|
||||
import com.hccake.ballcat.i18n.model.qo.I18nDataQO;
|
||||
import com.hccake.ballcat.i18n.mapper.I18nDataMapper;
|
||||
import com.hccake.ballcat.i18n.service.I18nDataService;
|
||||
import com.hccake.ballcat.common.model.domain.PageParam;
|
||||
import com.hccake.ballcat.common.model.domain.PageResult;
|
||||
import com.hccake.extend.mybatis.plus.service.impl.ExtendServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 国际化信息
|
||||
*
|
||||
* @author hccake 2021-08-04 11:31:49
|
||||
*/
|
||||
@Service
|
||||
public class I18nDataServiceImpl extends ExtendServiceImpl<I18nDataMapper, I18nData> implements I18nDataService {
|
||||
|
||||
/**
|
||||
* 根据QueryObeject查询分页数据
|
||||
* @param pageParam 分页参数
|
||||
* @param qo 查询参数对象
|
||||
* @return PageResult<I18nDataPageVO> 分页数据
|
||||
*/
|
||||
@Override
|
||||
public PageResult<I18nDataPageVO> queryPage(PageParam pageParam, I18nDataQO qo) {
|
||||
return baseMapper.queryPage(pageParam, qo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 code 和 languageTag 查询指定的 I18nData
|
||||
* @param code 唯一标识
|
||||
* @param languageTag 语言标识
|
||||
* @return I18nData
|
||||
*/
|
||||
@Override
|
||||
public I18nData getByCodeAndLanguageTag(String code, String languageTag) {
|
||||
return baseMapper.selectByCodeAndLanguageTag(code, languageTag);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.hccake.ballcat.i18n.mapper.I18nDataMapper">
|
||||
|
||||
<resultMap id="i18nDataMap" type="com.hccake.ballcat.i18n.model.entity.I18nData">
|
||||
<id property="id" column="id"/>
|
||||
<result property="business" column="business"/>
|
||||
<result property="messageKey" column="message_key"/>
|
||||
<result property="code" column="code"/>
|
||||
<result property="message" column="message"/>
|
||||
<result property="languageTag" column="language_tag"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id,
|
||||
business,
|
||||
message_key,
|
||||
code,
|
||||
message,
|
||||
language_tag,
|
||||
remark,
|
||||
create_time,
|
||||
update_time
|
||||
</sql>
|
||||
|
||||
<sql id="Base_Alias_Column_List">
|
||||
id.id,
|
||||
id.business,
|
||||
id.message_key,
|
||||
id.code,
|
||||
id.message,
|
||||
id.language_tag,
|
||||
id.remark,
|
||||
id.create_time,
|
||||
id.update_time
|
||||
</sql>
|
||||
</mapper>
|
||||
@@ -3,28 +3,31 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ballcat-extend-i18n</artifactId>
|
||||
<artifactId>ballcat-i18n</artifactId>
|
||||
<groupId>com.hccake</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ballcat-extend-i18n-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>ballcat-i18n-controller</artifactId>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-extend-i18n-annotation</artifactId>
|
||||
<artifactId>ballcat-i18n-biz</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-common-core</artifactId>
|
||||
<artifactId>ballcat-common-log</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-spring-boot-starter-redis</artifactId>
|
||||
<artifactId>ballcat-common-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.hccake.ballcat.i18n.controller;
|
||||
|
||||
import com.hccake.ballcat.common.log.operation.annotation.CreateOperationLogging;
|
||||
import com.hccake.ballcat.common.log.operation.annotation.DeleteOperationLogging;
|
||||
import com.hccake.ballcat.common.log.operation.annotation.UpdateOperationLogging;
|
||||
import com.hccake.ballcat.common.model.domain.PageParam;
|
||||
import com.hccake.ballcat.common.model.domain.PageResult;
|
||||
import com.hccake.ballcat.common.model.result.BaseResultCode;
|
||||
import com.hccake.ballcat.common.model.result.R;
|
||||
import com.hccake.ballcat.i18n.model.entity.I18nData;
|
||||
import com.hccake.ballcat.i18n.model.qo.I18nDataQO;
|
||||
import com.hccake.ballcat.i18n.model.vo.I18nDataPageVO;
|
||||
import com.hccake.ballcat.i18n.service.I18nDataService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* 国际化信息
|
||||
*
|
||||
* @author hccake 2021-08-04 11:31:49
|
||||
*/
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/i18n/data")
|
||||
@Api(value = "i18n-data", tags = "国际化信息管理")
|
||||
public class I18nDataController {
|
||||
|
||||
private final I18nDataService i18nDataService;
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
* @param pageParam 分页参数
|
||||
* @param i18nDataQO 国际化信息查询对象
|
||||
* @return R 通用返回体
|
||||
*/
|
||||
@ApiOperation(value = "分页查询", notes = "分页查询")
|
||||
@GetMapping("/page")
|
||||
@PreAuthorize("@per.hasPermission('i18n:data:read')")
|
||||
public R<PageResult<I18nDataPageVO>> getI18nDataPage(PageParam pageParam, I18nDataQO i18nDataQO) {
|
||||
return R.ok(i18nDataService.queryPage(pageParam, i18nDataQO));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增国际化信息
|
||||
* @param i18nData 国际化信息
|
||||
* @return R 通用返回体
|
||||
*/
|
||||
@ApiOperation(value = "新增国际化信息", notes = "新增国际化信息")
|
||||
@CreateOperationLogging(msg = "新增国际化信息")
|
||||
@PostMapping
|
||||
@PreAuthorize("@per.hasPermission('i18n:data:add')")
|
||||
public R save(@RequestBody I18nData i18nData) {
|
||||
return i18nDataService.save(i18nData) ? R.ok() : R.failed(BaseResultCode.UPDATE_DATABASE_ERROR, "新增国际化信息失败");
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改国际化信息
|
||||
* @param i18nData 国际化信息
|
||||
* @return R 通用返回体
|
||||
*/
|
||||
@ApiOperation(value = "修改国际化信息", notes = "修改国际化信息")
|
||||
@UpdateOperationLogging(msg = "修改国际化信息")
|
||||
@PutMapping
|
||||
@PreAuthorize("@per.hasPermission('i18n:data:edit')")
|
||||
public R updateById(@RequestBody I18nData i18nData) {
|
||||
return i18nDataService.updateById(i18nData) ? R.ok()
|
||||
: R.failed(BaseResultCode.UPDATE_DATABASE_ERROR, "修改国际化信息失败");
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过id删除国际化信息
|
||||
* @param id id
|
||||
* @return R 通用返回体
|
||||
*/
|
||||
@ApiOperation(value = "通过id删除国际化信息", notes = "通过id删除国际化信息")
|
||||
@DeleteOperationLogging(msg = "通过id删除国际化信息")
|
||||
@DeleteMapping("/{id}")
|
||||
@PreAuthorize("@per.hasPermission('i18n:data:del')")
|
||||
public R removeById(@PathVariable("id") Integer id) {
|
||||
return i18nDataService.removeById(id) ? R.ok()
|
||||
: R.failed(BaseResultCode.UPDATE_DATABASE_ERROR, "通过id删除国际化信息失败");
|
||||
}
|
||||
|
||||
}
|
||||
25
ballcat-i18n/ballcat-i18n-model/pom.xml
Normal file
25
ballcat-i18n/ballcat-i18n-model/pom.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ballcat-i18n</artifactId>
|
||||
<groupId>com.hccake</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ballcat-i18n-model</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-annotation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.hccake.ballcat.i18n.converter;
|
||||
|
||||
import com.hccake.ballcat.i18n.model.entity.I18nData;
|
||||
import com.hccake.ballcat.i18n.model.vo.I18nDataPageVO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* 国际化信息模型转换器
|
||||
*
|
||||
* @author hccake 2021-08-04 11:31:49
|
||||
*/
|
||||
@Mapper
|
||||
public interface I18nDataConverter {
|
||||
|
||||
I18nDataConverter INSTANCE = Mappers.getMapper(I18nDataConverter.class);
|
||||
|
||||
/**
|
||||
* PO 转 PageVO
|
||||
* @param i18nData 国际化信息
|
||||
* @return I18nDataPageVO 国际化信息PageVO
|
||||
*/
|
||||
I18nDataPageVO poToPageVo(I18nData i18nData);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.hccake.ballcat.i18n.model.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 国际化信息
|
||||
*
|
||||
* @author hccake 2021-08-04 11:31:49
|
||||
*/
|
||||
@Data
|
||||
@TableName("i18n_data")
|
||||
@ApiModel(value = "国际化信息")
|
||||
public class I18nData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@TableId
|
||||
@ApiModelProperty(value = "ID")
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
* 业务
|
||||
*/
|
||||
@ApiModelProperty(value = "业务")
|
||||
private String business;
|
||||
|
||||
/**
|
||||
* 关键词
|
||||
*/
|
||||
@ApiModelProperty(value = "关键词")
|
||||
private String messageKey;
|
||||
|
||||
/**
|
||||
* 唯一标识 = 业务:关键词
|
||||
*/
|
||||
@ApiModelProperty(value = "唯一标识 = 业务:关键词")
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 文本值,可以使用 { } 加角标,作为占位符
|
||||
*/
|
||||
@ApiModelProperty(value = "文本值,可以使用 { } 加角标,作为占位符")
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 语言标识
|
||||
*/
|
||||
@ApiModelProperty(value = "语言标识")
|
||||
private String languageTag;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ApiModelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
@ApiModelProperty(value = "修改时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.hccake.ballcat.i18n.model.qo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 国际化信息 查询对象
|
||||
*
|
||||
* @author hccake 2021-08-04 11:31:49
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(value = "国际化信息查询对象")
|
||||
public class I18nDataQO {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@ApiModelProperty(value = "ID")
|
||||
private Integer id;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.hccake.ballcat.i18n.model.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 国际化信息分页视图对象
|
||||
*
|
||||
* @author hccake 2021-08-04 11:31:49
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(value = "国际化信息分页视图对象")
|
||||
public class I18nDataPageVO {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@ApiModelProperty(value = "ID")
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
* 业务
|
||||
*/
|
||||
@ApiModelProperty(value = "业务")
|
||||
private String business;
|
||||
|
||||
/**
|
||||
* 关键词
|
||||
*/
|
||||
@ApiModelProperty(value = "关键词")
|
||||
private String messageKey;
|
||||
|
||||
/**
|
||||
* 唯一标识 = 业务:关键词
|
||||
*/
|
||||
@ApiModelProperty(value = "唯一标识 = 业务:关键词")
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 文本值,可以使用 { } 加角标,作为占位符
|
||||
*/
|
||||
@ApiModelProperty(value = "文本值,可以使用 { } 加角标,作为占位符")
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 语言标识
|
||||
*/
|
||||
@ApiModelProperty(value = "语言标识")
|
||||
private String languageTag;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ApiModelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
@ApiModelProperty(value = "修改时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
}
|
||||
@@ -3,16 +3,18 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ballcat-extend-i18n</artifactId>
|
||||
<artifactId>ballcat</artifactId>
|
||||
<groupId>com.hccake</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ballcat-extend-i18n-annotation</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>ballcat-i18n</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>ballcat-i18n-model</module>
|
||||
<module>ballcat-i18n-biz</module>
|
||||
<module>ballcat-i18n-controller</module>
|
||||
</modules>
|
||||
|
||||
<dependencies>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,32 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<artifactId>ballcat-starters</artifactId>
|
||||
<groupId>com.hccake</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ballcat-spring-boot-starter-i18n</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-extend-i18n-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
||||
@@ -1,89 +0,0 @@
|
||||
package com.hccake.common.i18n;
|
||||
|
||||
import com.hccake.common.i18n.cache.CacheService;
|
||||
import com.hccake.common.i18n.cache.LocalCacheService;
|
||||
import com.hccake.common.i18n.cache.RedisCacheService;
|
||||
import com.hccake.common.i18n.execute.DefaultTranslateExecute;
|
||||
import com.hccake.common.i18n.execute.TranslateExecute;
|
||||
import com.hccake.common.i18n.execute.TranslateExecuteWrapper;
|
||||
import com.hccake.common.i18n.executor.CacheExecutor;
|
||||
import com.hccake.common.i18n.executor.Executor;
|
||||
import com.hccake.common.i18n.executor.ExecutorWrapper;
|
||||
import com.hccake.common.i18n.executor.SimpleExecutor;
|
||||
import com.hccake.common.i18n.generate.DefaultKeyGenerate;
|
||||
import com.hccake.common.i18n.generate.KeyGenerate;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
|
||||
/**
|
||||
* i18n auto configuration
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@EnableConfigurationProperties(I18nProperties.class)
|
||||
public class I18nAutoConfiguration {
|
||||
|
||||
private final I18nProperties i18nProperties;
|
||||
|
||||
private final I18nDataProvider i18nDataProvider;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public KeyGenerate keyGenerate() {
|
||||
return new DefaultKeyGenerate(i18nProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(prefix = "ballcat.i18n.cache", name = "type", havingValue = "local", matchIfMissing = true)
|
||||
public CacheService localCacheService() {
|
||||
return new LocalCacheService();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@DependsOn("redisTemplate")
|
||||
@ConditionalOnProperty(prefix = "ballcat.i18n.cache", name = "type", havingValue = "redis")
|
||||
public CacheService redisCacheService(StringRedisTemplate stringRedisTemplate) {
|
||||
return new RedisCacheService(stringRedisTemplate);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(Executor.class)
|
||||
@ConditionalOnProperty(prefix = "ballcat.i18n", name = "executor", havingValue = "simple", matchIfMissing = true)
|
||||
public Executor simpleExecutor() {
|
||||
return new SimpleExecutor(i18nDataProvider);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(CacheService.class)
|
||||
@ConditionalOnMissingBean(Executor.class)
|
||||
@ConditionalOnProperty(prefix = "ballcat.i18n", name = "executor", havingValue = "cache")
|
||||
public Executor cacheExecutor(KeyGenerate keyGenerate, CacheService cacheService) {
|
||||
return new CacheExecutor(i18nDataProvider, i18nProperties, keyGenerate, cacheService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(Executor.class)
|
||||
@ConditionalOnMissingBean
|
||||
public TranslateExecute translateExecute(Executor executor) {
|
||||
return new DefaultTranslateExecute(new ExecutorWrapper(i18nProperties, executor));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean({ Executor.class, TranslateExecute.class })
|
||||
@ConditionalOnMissingBean
|
||||
public TranslateExecuteWrapper translateExecuteWrapper(TranslateExecute translateExecute) {
|
||||
TranslateExecuteWrapper translateExecuteWrapper = new TranslateExecuteWrapper();
|
||||
translateExecuteWrapper.setTranslateExecute(translateExecute);
|
||||
return translateExecuteWrapper;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.hccake.common.i18n.I18nAutoConfiguration
|
||||
@@ -28,7 +28,6 @@
|
||||
<module>ballcat-spring-boot-starter-websocket</module>
|
||||
<module>ballcat-spring-boot-starter-pay</module>
|
||||
<module>ballcat-spring-boot-starter-xss</module>
|
||||
<module>ballcat-spring-boot-starter-i18n</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
@@ -11,6 +11,10 @@
|
||||
|
||||
<artifactId>ballcat-system-model</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-common-i18n</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-common-desensitize</artifactId>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.hccake.ballcat.system.model.vo;
|
||||
|
||||
import com.hccake.ballcat.common.i18n.I18nClass;
|
||||
import com.hccake.ballcat.common.i18n.I18nField;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
@@ -11,6 +13,7 @@ import java.time.LocalDateTime;
|
||||
*
|
||||
* @author hccake 2021-04-06 17:59:51
|
||||
*/
|
||||
@I18nClass
|
||||
@Data
|
||||
@ApiModel(value = "菜单权限分页视图对象")
|
||||
public class SysMenuPageVO {
|
||||
@@ -32,6 +35,8 @@ public class SysMenuPageVO {
|
||||
/**
|
||||
* 菜单名称
|
||||
*/
|
||||
// TODO 原始 title 也返回,方便前端回显和修改
|
||||
@I18nField
|
||||
@ApiModelProperty(value = "菜单名称")
|
||||
private String title;
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.hccake.ballcat.system.model.vo;
|
||||
|
||||
import com.hccake.ballcat.common.i18n.I18nClass;
|
||||
import com.hccake.ballcat.common.i18n.I18nField;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
@@ -10,6 +12,7 @@ import lombok.Data;
|
||||
* @author hccake 2021-04-06 17:59:51
|
||||
*/
|
||||
@Data
|
||||
@I18nClass
|
||||
@ApiModel(value = "菜单权限视图对象")
|
||||
public class SysMenuRouterVO {
|
||||
|
||||
@@ -30,6 +33,7 @@ public class SysMenuRouterVO {
|
||||
/**
|
||||
* 菜单名称
|
||||
*/
|
||||
@I18nField
|
||||
@ApiModelProperty(value = "菜单名称")
|
||||
private String title;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user