Finish Task #4531 Cost:4h  修复复制合同开票单位错误

This commit is contained in:
时间淡忘一切
2023-11-14 12:08:21 +08:00
commit 61ff9d75ec
26 changed files with 1892 additions and 0 deletions

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
// 设置序列化
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置redisTemplate
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
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;
}
}

View File

@@ -0,0 +1,5 @@
package com.blueland.common.core.constan;
public class RedisConstan {
public static final String I18N = "i18n:";
}

View File

@@ -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";
}

View File

@@ -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<Boolean> save(@RequestBody International international) {
return AjaxResult.operates(internationalService.insert(international));
}
/**
* 根据主键删除国际化
*
* @return {@code true} 删除成功,{@code false} 删除失败
*/
@PostMapping("/remove")
@ApiOperation(value = "根据主键删除国际化", notes = "根据主键删除国际化")
public AjaxResult<Boolean> 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<Boolean> update(@RequestBody International international) {
return AjaxResult.operates(internationalService.updateInternational(international));
}
/**
* 查询所有国际化
*
* @return 所有数据
*/
@GetMapping("/list")
@ApiOperation(value = "查询所有国际化(根据租户)", notes = "查询所有国际化(根据租户)")
public AjaxResult<List<International>> 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<International> getInfo(@PathVariable Serializable id) {
return AjaxResult.success(internationalService.getById(id));
}
/**
* 分页查询国际化
*
* @return 分页对象
*/
@PostMapping("/page")
@ApiOperation(value = "分页查询国际化", notes = "分页查询国际化")
public AjaxResult<Page<International>> 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<Boolean> 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<Boolean> 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<Boolean> tenantIdCopy(@RequestParam("sourceLang") String sourceLang,
String tenantId) {
return AjaxResult.operates(internationalService.tenantIdCopy(sourceLang, tenantId));
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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<Map> getList(String dict) {
if (SysConstan.TYPE.equals(dict)) {
return type();
} else if (SysConstan.LANG.equals(dict)) {
return lang();
}
throw new RuntimeException("字典名称不正确");
}
public List<Map> lang() {
List<Map> list = new ArrayList<>();
Map<String, String> 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<Map> type() {
List<Map> list = new ArrayList<>();
Map<String, String> 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("字典名称不正确");
}
}

View File

@@ -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());
}
}

View File

@@ -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());
}
}

View File

@@ -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<International> {
}

View File

@@ -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<T> {
@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();
}
}

View File

@@ -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<International> {
/**
* 插入
*
* @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<International> listAll(International international);
/**
* 根据语言查询
*
* @param lang 语言
* @param tenantId
* @return {@link List}<{@link International}>
*/
List<International> listByLang(String lang, String tenantId,String type);
/**
* @param international
* @return {@link List}<{@link International}>
*/
Page<List<International>> 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<String, Map<String, String>> findLangPackage(String type);
/**
* 租户ID副本
*
* @param sourceLang 源语言
* @param tenantId 保持ID
* @return {@link Boolean}
*/
Boolean tenantIdCopy(String sourceLang, String tenantId);
}

View File

@@ -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<InternationalMapper, International> 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<International> 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<International> 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<List<International>> 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<International> sourceLangList = listByLang(sourceLang, tenantId, "");
List<String> nameList = sourceLangList.stream()
.map(International::getName)
.collect(Collectors.toList());
Map<String, String> tranfer = new ConcurrentHashMap<>();
ArrayList<CompletableFuture> futures = new ArrayList<>();
for (List<String> list : CollUtil.split(nameList, 400)) {
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
tranfer.putAll(TranslateUtil.translate(list, sourceLang, targetLang));
});
futures.add(future);
}
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
List<International> 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<InternationalExport> 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<InternationalExport> 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<String, International> 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<International> 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<String, Map<String, String>> findLangPackage(String type) {
List<International> 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<International> 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<String, International> list(List<InternationalExport> 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<International> 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()));
}
}

View File

@@ -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<International> list) {
Map<String, International> 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());
}
}

View File

@@ -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<String, String> translate(List<String> query, String from, String to) {
Map<String, String> 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;
}
}

View File

@@ -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();
}
}

View File

@@ -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

View File

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 日志存放路径 -->
<springProperty source="log.path" name="log.path" scope="context" />
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.blueland" level="info" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />
<root level="info">
<appender-ref ref="console" />
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="file_error" />
</root>
</configuration>

View File

@@ -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() {
}
}