From 61ff9d75ec809ae0d73249c1e2170d85735cb6f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=97=B6=E9=97=B4=E6=B7=A1=E5=BF=98=E4=B8=80=E5=88=87?= <7990497@qq.com> Date: Tue, 14 Nov 2023 12:08:21 +0800 Subject: [PATCH] =?UTF-8?q?Finish=20Task=20#4531=20Cost:4h=C2=A0=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A4=8D=E5=88=B6=E5=90=88=E5=90=8C=E5=BC=80?= =?UTF-8?q?=E7=A5=A8=E5=8D=95=E4=BD=8D=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile_test | 7 + mvnw | 316 ++++++++++++++++++ pom.xml | 99 ++++++ .../common/core/InternationApplication.java | 15 + .../common/core/config/InternationConfig.java | 37 ++ .../core/config/MyBatisFlexConfiguration.java | 29 ++ .../common/core/config/RedisConfig.java | 73 ++++ .../common/core/constan/RedisConstan.java | 5 + .../common/core/constan/SysConstan.java | 6 + .../controller/InternationalController.java | 170 ++++++++++ .../common/core/domain/BaseEntity.java | 62 ++++ .../common/core/domain/International.java | 49 +++ .../domain/export/InternationalExport.java | 26 ++ .../common/core/handler/ExcelDicHandler.java | 84 +++++ .../core/handler/GlobalExcptionHandler.java | 14 + .../core/listener/FlexCommonListener.java | 27 ++ .../core/mapper/InternationalMapper.java | 17 + .../common/core/result/AjaxResult.java | 110 ++++++ .../core/service/InternationalService.java | 114 +++++++ .../impl/InternationalServiceImpl.java | 299 +++++++++++++++++ .../blueland/common/core/utils/RedisUtil.java | 61 ++++ .../common/core/utils/TranslateUtil.java | 53 +++ .../blueland/common/core/utils/UserUtils.java | 95 ++++++ src/main/resources/application.yml | 38 +++ src/main/resources/logback.xml | 73 ++++ .../core/InternationApplicationTests.java | 13 + 26 files changed, 1892 insertions(+) create mode 100644 Dockerfile_test create mode 100755 mvnw create mode 100644 pom.xml create mode 100644 src/main/java/com/blueland/common/core/InternationApplication.java create mode 100644 src/main/java/com/blueland/common/core/config/InternationConfig.java create mode 100644 src/main/java/com/blueland/common/core/config/MyBatisFlexConfiguration.java create mode 100644 src/main/java/com/blueland/common/core/config/RedisConfig.java create mode 100644 src/main/java/com/blueland/common/core/constan/RedisConstan.java create mode 100644 src/main/java/com/blueland/common/core/constan/SysConstan.java create mode 100644 src/main/java/com/blueland/common/core/controller/InternationalController.java create mode 100644 src/main/java/com/blueland/common/core/domain/BaseEntity.java create mode 100644 src/main/java/com/blueland/common/core/domain/International.java create mode 100644 src/main/java/com/blueland/common/core/domain/export/InternationalExport.java create mode 100644 src/main/java/com/blueland/common/core/handler/ExcelDicHandler.java create mode 100644 src/main/java/com/blueland/common/core/handler/GlobalExcptionHandler.java create mode 100644 src/main/java/com/blueland/common/core/listener/FlexCommonListener.java create mode 100644 src/main/java/com/blueland/common/core/mapper/InternationalMapper.java create mode 100644 src/main/java/com/blueland/common/core/result/AjaxResult.java create mode 100644 src/main/java/com/blueland/common/core/service/InternationalService.java create mode 100644 src/main/java/com/blueland/common/core/service/impl/InternationalServiceImpl.java create mode 100644 src/main/java/com/blueland/common/core/utils/RedisUtil.java create mode 100644 src/main/java/com/blueland/common/core/utils/TranslateUtil.java create mode 100644 src/main/java/com/blueland/common/core/utils/UserUtils.java create mode 100644 src/main/resources/application.yml create mode 100644 src/main/resources/logback.xml create mode 100644 src/test/java/com/blueland/common/core/InternationApplicationTests.java diff --git a/Dockerfile_test b/Dockerfile_test new file mode 100644 index 0000000..753ecf5 --- /dev/null +++ b/Dockerfile_test @@ -0,0 +1,7 @@ +FROM openjdk:8u181-jre-alpine + +RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone && apk add --no-cache curl +COPY ./target/crm-internation-0.0.1-SNAPSHOT.jar / +WORKDIR / +EXPOSE 8080 +CMD ["java","-jar","crm-internation-0.0.1-SNAPSHOT.jar"] \ No newline at end of file diff --git a/mvnw b/mvnw new file mode 100755 index 0000000..8a8fb22 --- /dev/null +++ b/mvnw @@ -0,0 +1,316 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`\\unset -f command; \\command -v java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..556de6b --- /dev/null +++ b/pom.xml @@ -0,0 +1,99 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.17 + + + net.rzdata + crm-internation + 0.0.1-SNAPSHOT + crm-internation + crm翻译 + + 1.8 + + + + com.github.xiaoymin + knife4j-openapi2-spring-boot-starter + 4.3.0 + + + cn.afterturn + easypoi-spring-boot-starter + 4.4.0 + + + cn.hutool + hutool-all + 5.8.22 + + + org.springframework.boot + spring-boot-starter-web + + + + com.mybatis-flex + mybatis-flex-spring-boot-starter + 1.7.3 + + + com.alibaba + druid-spring-boot-starter + 1.2.20 + + + com.mysql + mysql-connector-j + 8.0.32 + + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + com.alibaba + fastjson + 2.0.42 + + + com.tencentcloudapi + tencentcloud-sdk-java + 3.1.900 + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + diff --git a/src/main/java/com/blueland/common/core/InternationApplication.java b/src/main/java/com/blueland/common/core/InternationApplication.java new file mode 100644 index 0000000..1d546cd --- /dev/null +++ b/src/main/java/com/blueland/common/core/InternationApplication.java @@ -0,0 +1,15 @@ +package com.blueland.common.core; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@MapperScan("com.blueland.common.core.mapper") +public class InternationApplication { + + public static void main(String[] args) { + SpringApplication.run(InternationApplication.class, args); + } + +} diff --git a/src/main/java/com/blueland/common/core/config/InternationConfig.java b/src/main/java/com/blueland/common/core/config/InternationConfig.java new file mode 100644 index 0000000..90055e3 --- /dev/null +++ b/src/main/java/com/blueland/common/core/config/InternationConfig.java @@ -0,0 +1,37 @@ +package com.blueland.common.core.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 翻译配置类 + */ +@Component +@ConfigurationProperties(prefix = "tm") +public class InternationConfig { + /** + * 腾讯翻译ID + */ + private static String secretId; + + /** + * 腾讯翻译Key + */ + private static String secretKey; + + public static String getSecretId() { + return secretId; + } + + public void setSecretId(String secretId) { + InternationConfig.secretId = secretId; + } + + public static String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + InternationConfig.secretKey = secretKey; + } +} diff --git a/src/main/java/com/blueland/common/core/config/MyBatisFlexConfiguration.java b/src/main/java/com/blueland/common/core/config/MyBatisFlexConfiguration.java new file mode 100644 index 0000000..f732761 --- /dev/null +++ b/src/main/java/com/blueland/common/core/config/MyBatisFlexConfiguration.java @@ -0,0 +1,29 @@ +package com.blueland.common.core.config; + +import com.blueland.common.core.domain.BaseEntity; +import com.blueland.common.core.listener.FlexCommonListener; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.core.FlexGlobalConfig; +import com.mybatisflex.core.keygen.KeyGenerators; +import com.mybatisflex.spring.boot.MyBatisFlexCustomizer; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class MyBatisFlexConfiguration implements MyBatisFlexCustomizer { + + @Override + public void customize(FlexGlobalConfig globalConfig) { + // 我们可以在这里进行一些列的初始化配置 + FlexCommonListener flexCommonListener = new FlexCommonListener(); + globalConfig.registerInsertListener(flexCommonListener, BaseEntity.class); + globalConfig.registerUpdateListener(flexCommonListener, BaseEntity.class); + + FlexGlobalConfig.KeyConfig keyConfig = new FlexGlobalConfig.KeyConfig(); + keyConfig.setKeyType(KeyType.Generator); + keyConfig.setValue(KeyGenerators.snowFlakeId); + keyConfig.setBefore(true); + + globalConfig.setKeyConfig(keyConfig); + } + +} \ No newline at end of file diff --git a/src/main/java/com/blueland/common/core/config/RedisConfig.java b/src/main/java/com/blueland/common/core/config/RedisConfig.java new file mode 100644 index 0000000..522b522 --- /dev/null +++ b/src/main/java/com/blueland/common/core/config/RedisConfig.java @@ -0,0 +1,73 @@ +package com.blueland.common.core.config; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import org.springframework.cache.interceptor.KeyGenerator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import java.lang.reflect.Method; + +@Configuration +public class RedisConfig { + /** + * RedisTemplate配置 + * + * @param lettuceConnectionFactory + * @return + */ + @Bean + public KeyGenerator wiselyKeyGenerator() { + return new KeyGenerator() { + @Override + public Object generate(Object target, Method method, Object... params) { + StringBuilder sb = new StringBuilder(); + sb.append(target.getClass().getName()); + sb.append(method.getName()); + for (Object obj : params) { + sb.append(obj.toString()); + } + return sb.toString(); + } + }; + } + + + /** + * RedisTemplate配置 + * + * @param lettuceConnectionFactory + * @return + */ + @Bean + public RedisTemplate redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) { + // 设置序列化 + Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); + ObjectMapper om = new ObjectMapper(); + om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); + jackson2JsonRedisSerializer.setObjectMapper(om); + // 配置redisTemplate + RedisTemplate redisTemplate = new RedisTemplate(); + redisTemplate.setConnectionFactory(lettuceConnectionFactory); + RedisSerializer stringSerializer = new StringRedisSerializer(); + // key序列化 + redisTemplate.setKeySerializer(stringSerializer); + // value序列化 + redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); + // Hash key序列化 + redisTemplate.setHashKeySerializer(stringSerializer); + // Hash value序列化 + redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); + redisTemplate.afterPropertiesSet(); + return redisTemplate; + } +} diff --git a/src/main/java/com/blueland/common/core/constan/RedisConstan.java b/src/main/java/com/blueland/common/core/constan/RedisConstan.java new file mode 100644 index 0000000..974992e --- /dev/null +++ b/src/main/java/com/blueland/common/core/constan/RedisConstan.java @@ -0,0 +1,5 @@ +package com.blueland.common.core.constan; + +public class RedisConstan { + public static final String I18N = "i18n:"; +} diff --git a/src/main/java/com/blueland/common/core/constan/SysConstan.java b/src/main/java/com/blueland/common/core/constan/SysConstan.java new file mode 100644 index 0000000..2c7122b --- /dev/null +++ b/src/main/java/com/blueland/common/core/constan/SysConstan.java @@ -0,0 +1,6 @@ +package com.blueland.common.core.constan; + +public class SysConstan { + public static final String TYPE = "type"; + public static final String LANG = "lang"; +} diff --git a/src/main/java/com/blueland/common/core/controller/InternationalController.java b/src/main/java/com/blueland/common/core/controller/InternationalController.java new file mode 100644 index 0000000..ff7d8fa --- /dev/null +++ b/src/main/java/com/blueland/common/core/controller/InternationalController.java @@ -0,0 +1,170 @@ +package com.blueland.common.core.controller; + +import com.blueland.common.core.domain.International; +import com.mybatisflex.core.paginate.Page; +import io.swagger.annotations.*; +import com.blueland.common.core.result.AjaxResult; +import org.springframework.web.bind.annotation.*; +import org.springframework.beans.factory.annotation.Autowired; +import com.blueland.common.core.service.InternationalService; +import org.springframework.web.multipart.MultipartFile; + +import java.io.Serializable; +import java.util.List; + +/** + * 国际化 控制层。 + * + * @author mybatis-flex-helper automatic generation + * @since 1.0 + */ +@RestController +@RequestMapping("/international") +@Api(value = "国际化", tags = "国际化") +public class InternationalController { + + @Autowired + private InternationalService internationalService; + + /** + * 添加 国际化 + * + * @param international 国际化 + * @return {@code true} 添加成功,{@code false} 添加失败 + */ + @PostMapping("/save") + @ApiOperation(value = "添加国际化", notes = "添加国际化", httpMethod = "POST") + public AjaxResult save(@RequestBody International international) { + return AjaxResult.operates(internationalService.insert(international)); + } + + + /** + * 根据主键删除国际化 + * + * @return {@code true} 删除成功,{@code false} 删除失败 + */ + @PostMapping("/remove") + @ApiOperation(value = "根据主键删除国际化", notes = "根据主键删除国际化") + public AjaxResult remove(@RequestBody International international) { + return AjaxResult.operates(internationalService.deleteById(international.getId())); + } + + + /** + * 根据主键更新国际化 + * + * @param international 国际化 + * @return {@code true} 更新成功,{@code false} 更新失败 + */ + @PostMapping("/update") + @ApiOperation(value = "根据主键更新国际化", notes = "根据主键更新国际化") + public AjaxResult update(@RequestBody International international) { + return AjaxResult.operates(internationalService.updateInternational(international)); + } + + + /** + * 查询所有国际化 + * + * @return 所有数据 + */ + @GetMapping("/list") + @ApiOperation(value = "查询所有国际化(根据租户)", notes = "查询所有国际化(根据租户)") + public AjaxResult> list(@RequestBody International international) { + return AjaxResult.success(internationalService.listAll(international)); + } + + /** + * 返回对应的语言包 + * + * @return 所有数据 + */ + @GetMapping("/findLangPackage") + @ApiOperation(value = "返回对应的语言包", notes = "返回对应的语言包") + public AjaxResult findLangPackage(@RequestParam("type") @ApiParam("类型(前端:front,后端:back)") String type) { + return AjaxResult.success(internationalService.findLangPackage(type)); + } + + + /** + * 根据国际化主键获取详细信息。 + * + * @param id international主键 + * @return 国际化详情 + */ + @GetMapping("/getInfo/{id}") + @ApiOperation(value = "根据国际化主键获取详细信息", notes = "根据国际化主键获取详细信息") + public AjaxResult getInfo(@PathVariable Serializable id) { + return AjaxResult.success(internationalService.getById(id)); + } + + + /** + * 分页查询国际化 + * + * @return 分页对象 + */ + @PostMapping("/page") + @ApiOperation(value = "分页查询国际化", notes = "分页查询国际化") + public AjaxResult> page(@RequestBody International international) { + return AjaxResult.success(internationalService.pageList(international)); + } + + /** + * 一键复制 + * + * @param targetLang 目标语言 + * @param sourceLang 源语言 + * @return {@link AjaxResult}<{@link Boolean}> + */ + @GetMapping("/copy") + @ApiOperation(value = "一键复制", notes = "例如:数据库只有中文,要翻译成英文") + @ApiImplicitParams( + { + @ApiImplicitParam(name = "tenantId", value = "租户id", dataType = "String", paramType = "query", required = false), + @ApiImplicitParam(name = "targetLang", value = "目标语言", dataType = "String", paramType = "query", required = true), + @ApiImplicitParam(name = "sourceLang", value = "源语言", dataType = "String", paramType = "query", required = true) + } + ) + public AjaxResult copy(@RequestParam("targetLang") String targetLang, + @RequestParam("sourceLang") String sourceLang, + @RequestParam(value = "tenantId", required = false) String tenantId) { + return AjaxResult.operates(internationalService.copy(targetLang, sourceLang, tenantId)); + } + + @GetMapping("/dowloadTemplate") + @ApiOperation(value = "下载模板", notes = "下载模板") + public void dowloadTemplate() { + internationalService.dowloadTemplate(); + } + + /** + * 导入 + */ + @PostMapping("/importList") + @ApiOperation("导入数据") + public AjaxResult importList(@RequestParam("file") MultipartFile file) { + return AjaxResult.operates(internationalService.importList(file)); + } + + /** + * 一键复制(从其他租户复制) + * + * @param sourceLang 源语言 + * @return {@link AjaxResult}<{@link Boolean}> + */ + @GetMapping("/tenantIdCopy") + @ApiOperation(value = "一键复制(从其他租户复制)", notes = "例如:bio里面有en语言包,现在要复制到AHI里面") + @ApiImplicitParams( + { + @ApiImplicitParam(name = "tenantId", value = "租户id", dataType = "String", paramType = "query", required = true), + @ApiImplicitParam(name = "sourceLang", value = "源语言", dataType = "String", paramType = "query", required = true) + } + ) + public AjaxResult tenantIdCopy(@RequestParam("sourceLang") String sourceLang, + String tenantId) { + return AjaxResult.operates(internationalService.tenantIdCopy(sourceLang, tenantId)); + } + +} \ No newline at end of file diff --git a/src/main/java/com/blueland/common/core/domain/BaseEntity.java b/src/main/java/com/blueland/common/core/domain/BaseEntity.java new file mode 100644 index 0000000..d1cda3a --- /dev/null +++ b/src/main/java/com/blueland/common/core/domain/BaseEntity.java @@ -0,0 +1,62 @@ +package com.blueland.common.core.domain; + +import com.alibaba.fastjson2.annotation.JSONField; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.mybatisflex.annotation.Column; +import com.mybatisflex.core.paginate.Page; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +@Data +public class BaseEntity { + + /** + * 创建人 + */ + @Column(value = "create_by") + @ApiModelProperty(value = "创建人") + private String createBy; + + /** + * 创建时间 + */ + @Column(value = "create_time") + @JSONField(format = "yyyy-MM-dd HH:mm:ss") + @ApiModelProperty(value = "创建时间") + private Date createTime; + + /** + * 更新人 + */ + @Column(value = "update_by") + @ApiModelProperty(value = "更新人") + private String updateBy; + + /** + * 更新时间 + */ + @Column(value = "update_time") + @JSONField(format = "yyyy-MM-dd HH:mm:ss") + @ApiModelProperty(value = "更新时间") + private Date updateTime; + + @Column(ignore = true) + @JSONField(serialize = false) + @ApiModelProperty(value = "分页大小") + @JsonIgnore + private int pageSize; + + @Column(ignore = true) + @JSONField(serialize = false) + @ApiModelProperty(value = "分页页码") + @JsonIgnore + private int pageNum; + + @JsonIgnore + public Page getPage() { + return new Page(pageNum, pageSize); + } + +} diff --git a/src/main/java/com/blueland/common/core/domain/International.java b/src/main/java/com/blueland/common/core/domain/International.java new file mode 100644 index 0000000..3d087d7 --- /dev/null +++ b/src/main/java/com/blueland/common/core/domain/International.java @@ -0,0 +1,49 @@ +package com.blueland.common.core.domain; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import com.mybatisflex.core.keygen.KeyGenerators; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 国际化 实体类。 + * + * @author mybatis-flex-helper automatic generation + * @since 1.0 + */ +@Table(value = "t_international") +@Data +@ApiModel(value = "国际化") +public class International extends BaseEntity { + + + @Id(keyType = KeyType.Generator, value = KeyGenerators.uuid) + @ApiModelProperty(value = "主键") + private String id; + + @Column(value = "code") + @ApiModelProperty(value = "编码", required = true) + private String code; + + @Column(value = "name") + @ApiModelProperty(value = "名称", required = true) + private String name; + + @Column(value = "lang") + @ApiModelProperty(value = "语言", required = true) + private String lang; + + @Column(value = "type") + @ApiModelProperty(value = "类型(前端:front,后端:back)", required = true) + private String type; + + @Column(value = "tenant_id") + @ApiModelProperty(value = "租户id(后台赋值)") + private String tenantId; + + +} diff --git a/src/main/java/com/blueland/common/core/domain/export/InternationalExport.java b/src/main/java/com/blueland/common/core/domain/export/InternationalExport.java new file mode 100644 index 0000000..aa60b9b --- /dev/null +++ b/src/main/java/com/blueland/common/core/domain/export/InternationalExport.java @@ -0,0 +1,26 @@ +package com.blueland.common.core.domain.export; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; +import com.blueland.common.core.constan.SysConstan; + + +@Data +public class InternationalExport { + + @Excel(name = "编码", width = 20) + private String code; + + @Excel(name = "名称", width = 20) + private String name; + + @Excel(name = "语言", width = 20, addressList = true, dict = SysConstan.LANG) + private String lang; + + @Excel(name = "类型", width = 20, addressList = true, dict = SysConstan.TYPE) + private String type; + + @Excel(name = "", isColumnHidden = true) + private String tenantId; + +} diff --git a/src/main/java/com/blueland/common/core/handler/ExcelDicHandler.java b/src/main/java/com/blueland/common/core/handler/ExcelDicHandler.java new file mode 100644 index 0000000..86989df --- /dev/null +++ b/src/main/java/com/blueland/common/core/handler/ExcelDicHandler.java @@ -0,0 +1,84 @@ +package com.blueland.common.core.handler; + +import cn.afterturn.easypoi.handler.inter.IExcelDictHandler; +import com.blueland.common.core.constan.SysConstan; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ExcelDicHandler implements IExcelDictHandler { + @Override + public List getList(String dict) { + if (SysConstan.TYPE.equals(dict)) { + return type(); + } else if (SysConstan.LANG.equals(dict)) { + return lang(); + } + + throw new RuntimeException("字典名称不正确"); + } + + public List lang() { + List list = new ArrayList<>(); + Map dictMap = new HashMap<>(); + + dictMap.put("dictKey", "en"); + dictMap.put("dictValue", "英语"); + list.add(dictMap); + dictMap = new HashMap<>(); + + dictMap.put("dictKey", "zh"); + dictMap.put("dictValue", "中文"); + list.add(dictMap); + return list; + } + + public List type() { + List list = new ArrayList<>(); + Map dictMap = new HashMap<>(); + dictMap.put("dictKey", "front"); + dictMap.put("dictValue", "前端"); + list.add(dictMap); + dictMap = new HashMap<>(); + dictMap.put("dictKey", "black"); + dictMap.put("dictValue", "后端"); + list.add(dictMap); + return list; + } + + // 导出用到 + @Override + public String toName(String dict, Object obj, String name, Object value) { + if (SysConstan.TYPE.equals(dict)) { + if ("front".equals(String.valueOf(value))) { + return "前端"; + } + return "后端"; + } else if (SysConstan.LANG.equals(dict)) { + if ("zh".equals(String.valueOf(value))) { + return "中文"; + } + return "英文"; + } + throw new RuntimeException("字典名称不正确"); + } + + // 导入用到 + @Override + public String toValue(String dict, Object obj, String name, Object value) { + if (SysConstan.TYPE.equals(dict)) { + if ("前端".equals(String.valueOf(value))) { + return "front"; + } + return "black"; + } else if (SysConstan.LANG.equals(dict)) { + if ("中文".equals(String.valueOf(value))) { + return "zh"; + } + return "en"; + } + throw new RuntimeException("字典名称不正确"); + } +} diff --git a/src/main/java/com/blueland/common/core/handler/GlobalExcptionHandler.java b/src/main/java/com/blueland/common/core/handler/GlobalExcptionHandler.java new file mode 100644 index 0000000..7bf1127 --- /dev/null +++ b/src/main/java/com/blueland/common/core/handler/GlobalExcptionHandler.java @@ -0,0 +1,14 @@ +package com.blueland.common.core.handler; + +import com.blueland.common.core.result.AjaxResult; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class GlobalExcptionHandler { + @ExceptionHandler(Exception.class) + public AjaxResult handleException(Exception e) { + e.printStackTrace(); + return AjaxResult.failed(e.getMessage()); + } +} diff --git a/src/main/java/com/blueland/common/core/listener/FlexCommonListener.java b/src/main/java/com/blueland/common/core/listener/FlexCommonListener.java new file mode 100644 index 0000000..3002b54 --- /dev/null +++ b/src/main/java/com/blueland/common/core/listener/FlexCommonListener.java @@ -0,0 +1,27 @@ +package com.blueland.common.core.listener; + +import com.mybatisflex.annotation.InsertListener; +import com.mybatisflex.annotation.UpdateListener; +import com.blueland.common.core.domain.BaseEntity; +import com.blueland.common.core.utils.UserUtils; + + +import java.util.Date; + +public class FlexCommonListener implements InsertListener, UpdateListener { + @Override + public void onInsert(Object o) { + BaseEntity base = (BaseEntity) o; + base.setCreateBy(UserUtils.getStaffCode()); + base.setCreateTime(new Date()); + base.setUpdateBy(UserUtils.getStaffCode()); + base.setUpdateTime(new Date()); + } + + @Override + public void onUpdate(Object o) { + BaseEntity base = (BaseEntity) o; + base.setUpdateBy(UserUtils.getStaffCode()); + base.setUpdateTime(new Date()); + } +} diff --git a/src/main/java/com/blueland/common/core/mapper/InternationalMapper.java b/src/main/java/com/blueland/common/core/mapper/InternationalMapper.java new file mode 100644 index 0000000..f709c99 --- /dev/null +++ b/src/main/java/com/blueland/common/core/mapper/InternationalMapper.java @@ -0,0 +1,17 @@ +package com.blueland.common.core.mapper; + +import com.blueland.common.core.domain.International; +import com.mybatisflex.core.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * 国际化 映射层。 + * + * @author mybatis-flex-helper automatic generation + * @since 1.0 + */ +@Mapper +public interface InternationalMapper extends BaseMapper { + + +} diff --git a/src/main/java/com/blueland/common/core/result/AjaxResult.java b/src/main/java/com/blueland/common/core/result/AjaxResult.java new file mode 100644 index 0000000..9e36b65 --- /dev/null +++ b/src/main/java/com/blueland/common/core/result/AjaxResult.java @@ -0,0 +1,110 @@ +package com.blueland.common.core.result; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author bigtian + * @Description 返回对象封装类 + * @Date 2021/7/23 2:03 下午 + */ +@Data +@ApiModel(value = "统一返回对象") +public class AjaxResult { + + @ApiModelProperty("返回信息") + private String resultMsg; + @ApiModelProperty("返回码") + private int resultCode; + @ApiModelProperty("返回数据") + private T result; + + + public static AjaxResult success(String msg) { + AjaxResult result = new AjaxResult(); + result.setResultCode(200); + result.setResultMsg(msg); + return result; + } + + public static AjaxResult success(Object data, String msg) { + AjaxResult result = new AjaxResult(); + result.setResultCode(400); + result.setResultMsg(msg); + result.setResult(data); + return result; + } + + public static AjaxResult success() { + AjaxResult result = new AjaxResult(); + result.setResultCode(200); + result.setResultMsg("操作成功"); + return result; + } + + + public static AjaxResult success(Object data) { + AjaxResult result = new AjaxResult(); + result.setResultCode(200); + result.setResultMsg("操作成功"); + result.setResult(data); + return result; + } + + public static AjaxResult failed(Object data) { + AjaxResult result = new AjaxResult(); + result.setResultCode(400); + result.setResultMsg("操作失败"); + result.setResult(data); + return result; + } + + public static AjaxResult failed() { + AjaxResult result = new AjaxResult(); + result.setResultCode(400); + result.setResultMsg("操作失败"); + return result; + } + + public static AjaxResult failed(String msg) { + AjaxResult result = new AjaxResult(); + result.setResultCode(400); + result.setResultMsg(msg); + return result; + } + + public static AjaxResult failed(int code, String msg) { + AjaxResult result = new AjaxResult(); + result.setResultCode(code); + result.setResultMsg(msg); + return result; + } + + public static AjaxResult success(int code, String msg) { + AjaxResult result = new AjaxResult(); + result.setResultCode(code); + result.setResultMsg(msg); + return result; + } + + + public static AjaxResult operates(Boolean flag) { + if (flag) { + return success(); + } + return failed(); + } + + public static AjaxResult operates(Boolean flag, String msg, Object data) { + return flag ? success(data, msg) : failed(msg); + } + + public static AjaxResult operates(int rows) { + if (rows > 0) { + return success(); + } + return failed(); + } +} + diff --git a/src/main/java/com/blueland/common/core/service/InternationalService.java b/src/main/java/com/blueland/common/core/service/InternationalService.java new file mode 100644 index 0000000..d7d4976 --- /dev/null +++ b/src/main/java/com/blueland/common/core/service/InternationalService.java @@ -0,0 +1,114 @@ +package com.blueland.common.core.service; + + +import com.blueland.common.core.domain.International; +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.service.IService; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; +import java.util.Map; + +/** + * 国际化 服务层。 + * + * @author mybatis-flex-helper automatic generation + * @since 1.0 + */ +public interface InternationalService extends IService { + + /** + * 插入 + * + * @param international 国际 + * @return boolean + */ + boolean insert(International international); + + /** + * 是否存在 + * + * @param code 编码 + * @param lang 语言 + * @return boolean + */ + boolean exist(String code, String lang); + + /** + * @return {@link List}<{@link International}> + */ + List listAll(International international); + + /** + * 根据语言查询 + * + * @param lang 语言 + * @param tenantId + * @return {@link List}<{@link International}> + */ + List listByLang(String lang, String tenantId,String type); + + /** + * @param international + * @return {@link List}<{@link International}> + */ + Page> pageList(International international); + + /** + * 一键复制 + * + * @param targetLang 目标语言 + * @param sourceLang 源语言 + * @param tenantId + * @return boolean + */ + boolean copy(String targetLang, String sourceLang, String tenantId); + + + /** + * 更新 + * + * @param international + * @return boolean + */ + boolean updateInternational(International international); + + /** + * 根据id删除 + * + * @param id + * @return + */ + boolean deleteById(String id); + + + /** + * 下载模板 + */ + void dowloadTemplate(); + + + /** + * 导入数据 + * + * @param file + * @return {@link Boolean} + */ + Boolean importList(MultipartFile file); + + /** + * 返回对应的语言包 + * @return + */ + Map> findLangPackage(String type); + + /** + * 租户ID副本 + * + * @param sourceLang 源语言 + * @param tenantId 保持ID + * @return {@link Boolean} + */ + Boolean tenantIdCopy(String sourceLang, String tenantId); + +} \ No newline at end of file diff --git a/src/main/java/com/blueland/common/core/service/impl/InternationalServiceImpl.java b/src/main/java/com/blueland/common/core/service/impl/InternationalServiceImpl.java new file mode 100644 index 0000000..3353620 --- /dev/null +++ b/src/main/java/com/blueland/common/core/service/impl/InternationalServiceImpl.java @@ -0,0 +1,299 @@ +package com.blueland.common.core.service.impl; + + +import cn.afterturn.easypoi.excel.ExcelExportUtil; +import cn.afterturn.easypoi.excel.ExcelImportUtil; +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.ImportParams; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson2.JSON; +import com.blueland.common.core.domain.International; +import com.blueland.common.core.domain.export.InternationalExport; +import com.blueland.common.core.handler.ExcelDicHandler; +import com.blueland.common.core.utils.RedisUtil; +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.blueland.common.core.utils.TranslateUtil; +import com.blueland.common.core.utils.UserUtils; +import org.apache.poi.ss.usermodel.Workbook; +import org.springframework.stereotype.Service; +import com.blueland.common.core.service.InternationalService; +import com.blueland.common.core.mapper.InternationalMapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static com.blueland.common.core.domain.table.InternationalTableDef.INTERNATIONAL; + +/** + * 国际化 服务层实现。 + * + * @author mybatis-flex-helper automatic generation + * @since 1.0 + */ +@Service +public class InternationalServiceImpl extends ServiceImpl implements InternationalService { + + + /** + * 插入 + * + * @param international 国际 + * @return boolean + */ + @Override + public boolean insert(International international) { + TranslateUtil.translate(new ArrayList<>(), "", ""); + String code = international.getCode(); + String lang = international.getLang(); + Assert.isFalse(exist(code, lang), StrUtil.format("编码【{}】,语言【{}】已经存在", code, lang)); + international.setTenantId(UserUtils.getTenantId()); + boolean flag = save(international); + if (flag) { + RedisUtil.hashSet(international); + } + return flag; + } + + /** + * 是否存在 + * + * @param code 编码 + * @param lang 语言 + * @return boolean + */ + @Override + public boolean exist(String code, String lang) { + QueryWrapper queryWrapper = QueryWrapper.create() + .where(INTERNATIONAL.CODE.eq(code)) + .and(INTERNATIONAL.LANG.eq(lang)) + .and(INTERNATIONAL.TENANT_ID.eq(UserUtils.getTenantId())); + return exists(queryWrapper); + } + + @Override + public List listAll(International international) { + QueryWrapper wrapper = QueryWrapper.create() + .where(INTERNATIONAL.TENANT_ID.eq(UserUtils.getTenantId())) + .and(INTERNATIONAL.CODE.like(international.getCode(), StrUtil::isNotBlank)) + .and(INTERNATIONAL.NAME.like(international.getName(), StrUtil::isNotBlank)) + .and(INTERNATIONAL.LANG.like(UserUtils.getLang())) + .and(INTERNATIONAL.TYPE.like(international.getType(), StrUtil::isNotBlank)) + .orderBy(INTERNATIONAL.CREATE_TIME.desc()); + return list(wrapper); + } + + /** + * 根据语言查询 + * + * @param lang 语言 + * @param tenantId + * @return {@link List}<{@link International}> + */ + @Override + public List listByLang(String lang, String tenantId, String type) { + Assert.notBlank(lang, "语言不能为空"); + QueryWrapper wrapper = QueryWrapper.create() + .where(INTERNATIONAL.TENANT_ID.eq(tenantId, StrUtil::isNotBlank)) + .and(INTERNATIONAL.TYPE.eq(type, StrUtil::isNotBlank)) + .and(INTERNATIONAL.LANG.eq(lang)); + return list(wrapper); + } + + @Override + public Page> pageList(International international) { + QueryWrapper wrapper = QueryWrapper.create() + .where(INTERNATIONAL.TENANT_ID.eq(UserUtils.getTenantIdDefault(), StrUtil::isNotBlank)) + .and(INTERNATIONAL.CODE.like(international.getCode(), StrUtil::isNotBlank)) + .and(INTERNATIONAL.NAME.like(international.getName(), StrUtil::isNotBlank)) + .and(INTERNATIONAL.LANG.like(international.getLang(), StrUtil::isNotBlank)) + .and(INTERNATIONAL.TYPE.like(international.getType(), StrUtil::isNotBlank)) + .orderBy(INTERNATIONAL.CREATE_TIME.desc()); + return page(international.getPage(), wrapper); + } + + /** + * 一键复制 + * + * @param targetLang 目标语言 + * @param sourceLang 源语言 + * @param tenantId + * @return boolean + */ + @Override + public boolean copy(String targetLang, String sourceLang, String tenantId) { + List sourceLangList = listByLang(sourceLang, tenantId, ""); + + List nameList = sourceLangList.stream() + .map(International::getName) + .collect(Collectors.toList()); + + Map tranfer = new ConcurrentHashMap<>(); + ArrayList futures = new ArrayList<>(); + for (List list : CollUtil.split(nameList, 400)) { + CompletableFuture future = CompletableFuture.runAsync(() -> { + tranfer.putAll(TranslateUtil.translate(list, sourceLang, targetLang)); + }); + futures.add(future); + } + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); + + List targetLangList = sourceLangList.stream() + .map(el -> { + International international = new International(); + international.setCode(el.getCode()); + international.setName(tranfer.get(el.getName())); + international.setLang(targetLang); + international.setType(el.getType()); + international.setTenantId(UserUtils.getTenantId()); + return international; + }) + .collect(Collectors.toList()); + + boolean flag = saveBatch(targetLangList); + if (flag) { + RedisUtil.hashMultiSet(targetLang, targetLangList); + } + return flag; + } + + @Override + public boolean updateInternational(International international) { + boolean flag = updateById(international); + if (flag) { + RedisUtil.hashSet(international); + } + return flag; + } + + @Override + public boolean deleteById(String id) { + International international = getById(id); + boolean flag = removeById(id); + if (flag) { + RedisUtil.hashRemvoe(international); + } + return flag; + } + + @Override + public void dowloadTemplate() { + try { + ExportParams exportParams = new ExportParams("国际化导入导出模板", "国际化"); + exportParams.setDictHandler(new ExcelDicHandler()); + exportParams.setCreateHeadRows(true); + List list = new ArrayList<>(); + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, InternationalExport.class, list); + HttpServletResponse response = UserUtils.getResponse(); + response.setContentType("application/vnd.ms-excel"); + response.setHeader("Content-Disposition", "attachment;filename=" + new String(("template.xlsx").getBytes(), "ISO-8859-1")); + ServletOutputStream sos = response.getOutputStream(); + workbook.write(sos); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public Boolean importList(MultipartFile file) { + ImportParams params = new ImportParams(); + params.setTitleRows(1); + params.setDictHandler(new ExcelDicHandler()); + List importList; + try { + importList = ExcelImportUtil.importExcel(file.getInputStream(), InternationalExport.class, params); + + // 校验数据完整性 + for (InternationalExport export : importList) { + Assert.notBlank(export.getCode(), "编码不能为空"); + Assert.notBlank(export.getName(), "名称不能为空"); + Assert.notBlank(export.getLang(), "语言不能为空"); + Assert.notBlank(export.getType(), "类型不能为空"); + } + + // 校验数据是否已经存在 + Map map = list(importList); + if (CollUtil.isNotEmpty(map)) { + for (InternationalExport export : importList) { + Assert.isFalse(map.containsKey(export.getCode() + export.getLang() + export.getType()), + StrUtil.format("编码【{}】语言【{}】类型【{}】已存在", export.getCode(), export.getLang(), export.getType())); + } + } + + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException("导入失败"); + } + List list = BeanUtil.copyToList(importList, International.class); + boolean flag = saveBatch(list); + if (flag) { + list.stream() + .collect(Collectors.groupingBy(International::getLang)) + .forEach((k, v) -> { + RedisUtil.hashMultiSet(k, v); + }); + } + return flag; + } + + @Override + public Map> findLangPackage(String type) { + List list = listByLang(UserUtils.getLang(), UserUtils.getTenantId(), type); + return list.stream() + .collect(Collectors.groupingBy(el -> StrUtil.subBefore(el.getCode(), + ".", + false), Collectors.toMap(International::getCode, International::getName))); + } + + @Override + public Boolean tenantIdCopy(String sourceLang, String tenantId) { + List list = listByLang(sourceLang, tenantId, "").stream() + .map(el -> { + el.setTenantId(UserUtils.getTenantId()); + el.setId(null); + el.setCreateBy(null); + el.setCreateTime(null); + el.setUpdateBy(null); + el.setUpdateTime(null); + return el; + }) + .collect(Collectors.toList()); + boolean flag = saveBatch(list); + if(flag){ + RedisUtil.hashMultiSet(sourceLang, list); + } + return flag; + } + + + public Map list(List list) { + QueryWrapper wrapper = QueryWrapper.create(); + for (InternationalExport international : list) { + international.setTenantId(UserUtils.getTenantId()); + wrapper.or(INTERNATIONAL.CODE.eq(international.getCode()) + .and(INTERNATIONAL.NAME.eq(international.getName())) + .and(INTERNATIONAL.TYPE.eq(international.getType())) + .and(INTERNATIONAL.LANG.eq(international.getLang())) + .and(INTERNATIONAL.TENANT_ID.eq(UserUtils.getTenantId())) + ); + } + List dbList = list(wrapper); + if (CollUtil.isEmpty(dbList)) { + return new HashMap<>(); + } + return dbList + .stream() + .collect(Collectors.toMap(el -> el.getCode() + el.getLang() + el.getType(), Function.identity())); + } + +} \ No newline at end of file diff --git a/src/main/java/com/blueland/common/core/utils/RedisUtil.java b/src/main/java/com/blueland/common/core/utils/RedisUtil.java new file mode 100644 index 0000000..c587f93 --- /dev/null +++ b/src/main/java/com/blueland/common/core/utils/RedisUtil.java @@ -0,0 +1,61 @@ +package com.blueland.common.core.utils; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.blueland.common.core.constan.RedisConstan; +import com.blueland.common.core.domain.International; +import org.jetbrains.annotations.NotNull; +import org.springframework.data.redis.core.RedisTemplate; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class RedisUtil { + + /** + * 批量添加 + * + * @param lang + * @param list + */ + public static void hashMultiSet(String lang, List list) { + Map data = list.stream() + .collect(Collectors.toMap(el -> getHashKey(el), Function.identity())); + getRedisTemplate().opsForHash().putAll(getKey(lang), data); + } + + @NotNull + private static String getKey(String lang) { + return UserUtils.getTenantId() + ":" + RedisConstan.I18N + lang; + } + + + public static RedisTemplate getRedisTemplate() { + return SpringUtil.getBean("redisTemplate"); + } + + /** + * 单个添加 + * + * @param international + */ + public static void hashSet(International international) { + getRedisTemplate().opsForHash().put(getKey(international.getLang()), getHashKey(international), international); + } + + /** + * 单个删除 + * + * @param international + */ + public static void hashRemvoe(International international) { + getRedisTemplate().opsForHash().delete(getKey(international.getLang()), getHashKey(international)); + } + + public static String getHashKey(International international) { + return StrUtil.format("{}:{}", international.getCode(), international.getType()); + } + +} diff --git a/src/main/java/com/blueland/common/core/utils/TranslateUtil.java b/src/main/java/com/blueland/common/core/utils/TranslateUtil.java new file mode 100644 index 0000000..2e3876f --- /dev/null +++ b/src/main/java/com/blueland/common/core/utils/TranslateUtil.java @@ -0,0 +1,53 @@ +package com.blueland.common.core.utils; + +import com.blueland.common.core.config.InternationConfig; +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.common.exception.TencentCloudSDKException; +import com.tencentcloudapi.common.profile.ClientProfile; +import com.tencentcloudapi.common.profile.HttpProfile; +import com.tencentcloudapi.tmt.v20180321.TmtClient; +import com.tencentcloudapi.tmt.v20180321.models.TextTranslateBatchRequest; +import com.tencentcloudapi.tmt.v20180321.models.TextTranslateBatchResponse; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class TranslateUtil { + + private static Credential INSTANCE = new Credential(InternationConfig.getSecretId(), InternationConfig.getSecretKey()); + + /** + * 腾讯翻译 + * + * @param query 需要翻译的内容 {@link List}<{@link String}> + * @param from 源语言 + * @param to 目标语言 + * @return {@link Map}<{@link String}, {@link String}> + */ + public static Map translate(List query, String from, String to) { + Map infoMap = new HashMap<>(); + try { + TextTranslateBatchRequest req = new TextTranslateBatchRequest(); + req.setSourceTextList(query.toArray(new String[0])); + req.setSource(from); + req.setTarget(to); + req.setProjectId(0L); + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setEndpoint("tmt.tencentcloudapi.com"); + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + TmtClient client = new TmtClient(INSTANCE, "ap-beijing", clientProfile); + TextTranslateBatchResponse resp = client.TextTranslateBatch(req); + String[] targetTextList = resp.getTargetTextList(); + for (int i = 0; i < targetTextList.length; i++) { + infoMap.put(query.get(i), targetTextList[i]); + } + } catch (TencentCloudSDKException e) { + throw new RuntimeException(e); + } + return infoMap; + } + + +} diff --git a/src/main/java/com/blueland/common/core/utils/UserUtils.java b/src/main/java/com/blueland/common/core/utils/UserUtils.java new file mode 100644 index 0000000..eda3fd1 --- /dev/null +++ b/src/main/java/com/blueland/common/core/utils/UserUtils.java @@ -0,0 +1,95 @@ +package com.blueland.common.core.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.annotation.PostConstruct; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @Description 用户工具类 + * @Date 2021/7/22 1:30 下午 + * @Created BigTian + */ +@Component +public class UserUtils { + public static String getStaffCodeDefault(String staffCode) { + HttpServletRequest request = getRequest(); + return Optional.ofNullable(request) + .map(el -> el.getHeader("staffPostCode")) + .orElse(staffCode); + } + + public static String getStaffCode() { + HttpServletRequest request = getRequest(); + return Optional.ofNullable(request) + .map(el -> el.getHeader("staffPostCode")) + .orElseThrow(() -> new RuntimeException("请求头缺少任岗编码")); + } + + + /** + * 获取当前登录人的租户 + * + * @return String 租户编码 + * @author bigtian + * @createTime 2022/5/16 10:35 + * @since 6.0 + */ + public static String getTenantId() { + HttpServletRequest request = getRequest(); + String tenantid = Optional.ofNullable(request) + .map(el -> el.getHeader("tenantid")) + .orElseThrow(() -> new RuntimeException("请求头中没有租户")); + return tenantid; + } + public static String getTenantIdDefault() { + HttpServletRequest request = getRequest(); + String tenantid = Optional.ofNullable(request) + .map(el -> el.getHeader("tenantid")) + .orElse(""); + return tenantid; + } + + + /** + * 获取请求属性 + * + * @return + */ + public static ServletRequestAttributes getRequestAttr() { + + return (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + } + + /** + * 获取request + */ + public static HttpServletRequest getRequest() { + ServletRequestAttributes attributes = getRequestAttr(); + return Optional.ofNullable(attributes). + map(ServletRequestAttributes::getRequest) + .orElse(null); + } + + /** + * 获取response + */ + public static HttpServletResponse getResponse() { + ServletRequestAttributes attributes = getRequestAttr(); + return attributes.getResponse(); + } + + public static String getLang() { + return getRequest().getLocale().getLanguage(); + } + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..719a697 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,38 @@ +spring: + datasource: + type: com.alibaba.druid.pool.DruidDataSource + druid: + driver-class-name: com.mysql.cj.jdbc.Driver + username: crm + password: crm@123 + url: jdbc:mysql://192.168.1.13:3308/crm_usm?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8 +# redis: +# host: localhost +# port: 6379 + redis: + database: 9 + host: 192.168.1.169 + password: '' +tm: + secretId: AKIDVotjKflbCYjgOr53xb093h6FApFQN5Yl + secretKey: 1oMfqmSt52kDRYR4SaUAbmiOp1yf8MM7 + +logging: + level: + net.rzdata.internation: debug +mybatis-flex: + type-aliases-package: com.blueland.common.core.domain + +log: + path: ./logs/crm-internation + +knife4j: + enable: true + openapi: + title: 国际化接口文档 + group: + test1: + group-name: 国际化 + api-rule: package + api-rule-resources: + - com.blueland.common.core.controller \ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..2d00660 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + ${log.pattern} + + + + + + ${log.path}/sys-info.log + + + + ${log.path}/sys-info.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + INFO + + ACCEPT + + DENY + + + + + ${log.path}/sys-error.log + + + + ${log.path}/sys-error.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + ERROR + + ACCEPT + + DENY + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/com/blueland/common/core/InternationApplicationTests.java b/src/test/java/com/blueland/common/core/InternationApplicationTests.java new file mode 100644 index 0000000..a724e67 --- /dev/null +++ b/src/test/java/com/blueland/common/core/InternationApplicationTests.java @@ -0,0 +1,13 @@ +package com.blueland.common.core; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class InternationApplicationTests { + + @Test + void contextLoads() { + } + +}