init: 信创文件安全传输系统内外网本地 Docker 部署

包含 s-file 后端、React 前端、MeshSafe 安全检测对接,以及内外网两套
compose/nginx/配置(仅前端 28180/28280 对外发布,其余端口不暴露)。

说明:deploy/config/application-iw.yml 与 application-ow.yml 按维护者
明确要求原样入库,其中含本机 Docker 用的库口令、RabbitMQ 口令与 JWT
密钥;上生产前需替换。
This commit is contained in:
KodouWZF
2026-11-02 10:59:03 +08:00
commit 47273ae3fd
2190 changed files with 305040 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
package com.senmesh;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* @author sr on 2020-04-16
*/
@SpringBootApplication(scanBasePackages = {"com.senmesh"})
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
@EnableScheduling
public class SFileApplication {
public static void main(String[] args) {
SpringApplication.run(SFileApplication.class, args);
}
}

View File

@@ -0,0 +1,67 @@
package com.senmesh.codegenerator.config;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.senmesh.codegenerator.service.CodeService;
import com.senmesh.codegenerator.service.SnowflakeIdWorker;
import com.senmesh.codegenerator.service.generator.SnowFlakeCodeGenerator;
import com.senmesh.codegenerator.service.impl.CodeServiceImpl;
import com.senmesh.codegenerator.util.CodeUtils;
import com.senmesh.common.CommonConfiguration;
import com.senmesh.common.constant.CommonConstants;
import com.senmesh.common.util.EnvironmentUtils;
import com.senmesh.common.util.RequestUtils;
import lombok.extern.slf4j.Slf4j;
/**
* 发号器配置类
* @author sr on 2021-03-23
*/
//@Configuration
@AutoConfigureAfter(CommonConfiguration.class)
@Slf4j
public class CodeConfiguration {
public static final String PROP_WORID_PREFIX = "code.snowflake.workid";
/**
* 默认编号生成器
* @return
* @author sr on 2021-03-23
*/
@Bean
public SnowFlakeCodeGenerator snowFlakeCodeGenerator() {
// 机器id
String hostIp = RequestUtils.getHostIp();
log.info("hostIp:" + hostIp);
String workIdStr = EnvironmentUtils.getProperty(
String.join(CommonConstants.POINT, PROP_WORID_PREFIX, hostIp));
Long workId = 99l;
try {
if (StringUtils.isNoneBlank(workIdStr)) {
workId = Long.valueOf(workIdStr);
}
} catch (Exception e) {
}
SnowflakeIdWorker idWorker = new SnowflakeIdWorker(workId, 0);
return new SnowFlakeCodeGenerator(idWorker);
}
/**
* 编号service(根据类型分发不同的生成器)
* @return
* @author sr on 2021-03-23
*/
@Bean
public CodeService codeService() {
CodeService codeService = new CodeServiceImpl();
CodeUtils.setCodeService(codeService);
return codeService;
}
}

View File

@@ -0,0 +1,26 @@
package com.senmesh.codegenerator.constant;
/**
* 编号常量类
* @author sr on 2019-09-15
*/
public class CodeConstants {
/** 生成器类型:默认(不可用) **/
// public static final String GENERATOR_TYPE_DEFAULT = "DEFAULT";
public static final String GENERATOR_TYPE_SNOW_FLAKE = "SnowFlake";
/** id默认长度 **/
public static final int ID_DEFAULT_LENGTH = 5;
/** id默认补位字符 **/
public static final char ID_DEFAULT_PAD = '0';
/** id默认日期格式化 **/
public static final DateFormatterEnum ID_DEFAULT_FORMATTER = DateFormatterEnum.YEAR;
/** -----异常信息----- **/
public static final String CODE_GENERATE_ERROR = "编号生成失败";
/** -----异常信息----- **/
}

View File

@@ -0,0 +1,32 @@
package com.senmesh.codegenerator.constant;
import java.time.format.DateTimeFormatter;
/**
* 日期formatter枚举
* @author sr on 2019-12-03
*/
public enum DateFormatterEnum {
/** 年:yyyy **/
YEAR(DateTimeFormatter.ofPattern("yyyy")),
/** 年月:yyyyMM **/
YM(DateTimeFormatter.ofPattern("yyyyMM")),
/** 年月:yyMM **/
YM2(DateTimeFormatter.ofPattern("yyMM")),
/** 年月日:yyyyMMdd **/
YMD(DateTimeFormatter.ofPattern("yyyyMMdd")),
/** 年月日:yyMMdd **/
YMD2(DateTimeFormatter.ofPattern("yyMMdd"));
private DateTimeFormatter formatter;
private DateFormatterEnum(DateTimeFormatter formatter){
this.formatter = formatter;
}
public DateTimeFormatter getDateTimeFormatter() {
return this.formatter;
}
}

View File

@@ -0,0 +1,26 @@
package com.senmesh.codegenerator.exception;
/**
* 编号生成器异常
* @author sr on 2019-12-03
*/
public class CodeGeneratorException extends RuntimeException{
/** **/
private static final long serialVersionUID = 3558280270933232655L;
public CodeGeneratorException() {}
public CodeGeneratorException(String message) {
super(message);
}
public CodeGeneratorException(String message, Throwable cause) {
super(message, cause);
}
public CodeGeneratorException(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,25 @@
package com.senmesh.codegenerator.pojo;
import com.senmesh.codegenerator.constant.CodeConstants;
import lombok.Builder;
import lombok.Data;
import lombok.Builder.Default;
/**
* 编码生成参数对象
* @author sr on 2019-12-05
*/
@Data
@Builder
public class CodeParam {
/** 生成器类型 **/
@Default
private String generatorType = CodeConstants.GENERATOR_TYPE_SNOW_FLAKE;
/** 编码类型 **/
private String type;
}

View File

@@ -0,0 +1,42 @@
package com.senmesh.codegenerator.service;
import java.util.List;
import com.senmesh.codegenerator.pojo.CodeParam;
/**
* 编号生成器 默认一套实现,如需重定义中间时间format和id长度,重写规则 重写规则,注意去发号器对应的数据库表(leaf_alloc)中添加对应type+时间(biz_tag)的记录
*
* @author sr on 2019-09-15
*/
public interface CodeGenerator<T extends CodeParam> {
/**
* 自定义特定业务类型,即前缀
*
* @return
* @author sr on 2019-09-19
*/
String getType();
/**
* 根据生成规则获取编号
*
* @param codeParam
* @return
* @author sr on 2020-07-13
*/
String getCode(T codeParam);
/**
* 批量根据生成规则获取编号
*
* @param codeParam
* @return
* @author sr on 2020-07-13
*/
List<String> batchCode(T codeParam, Integer batchNum);
}

View File

@@ -0,0 +1,33 @@
package com.senmesh.codegenerator.service;
import java.util.List;
import com.senmesh.codegenerator.pojo.CodeParam;
/**
* 编号service(根据类型分发不同的生成器)
*
* @author sr on 2019-09-15
*/
public interface CodeService {
/**
* 根据生成规则获取编号
*
* @param codeParam
* @return
* @author sr on 2020-07-13
*/
String getCode(CodeParam codeParam);
/**
* 批量根据生成规则获取编号
*
* @param codeParam
* @param batchNum 批次数(1-1000)
* @return
* @author sr on 2020-07-13
*/
List<String> batchCode(CodeParam codeParam, Integer batchNum);
}

View File

@@ -0,0 +1,160 @@
package com.senmesh.codegenerator.service;
/**
* Twitter_Snowflake<br>
* SnowFlake的结构如下(每部分用-分开):<br>
* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 <br>
* 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0<br>
* 41位时间戳(毫秒级),注意,41位时间戳不是存储当前时间的时间戳,而是存储时间戳的差值(当前时间戳 - 开始时间戳) 得到的值),这里的的开始时间戳,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。41位的时间戳,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69<br>
* 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId<br>
* 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间戳)产生4096个ID序号<br>
* 加起来刚好64位,为一个Long型。<br>
* SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右。
*/
public class SnowflakeIdWorker {
// ==============================Fields===========================================
/** 开始时间戳 (2015-01-01) */
private final long twepoch = 1420041600000L;
/** 能容忍的系统时钟回拨时间(2秒) */
private final long timeOffset = 2000L;
/** 机器id所占的位数 */
private final long workerIdBits = 5L;
/** 数据标识id所占的位数 */
private final long datacenterIdBits = 5L;
/** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
/** 支持的最大数据标识id,结果是31 */
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
/** 序列在id中占的位数 */
private final long sequenceBits = 12L;
/** 机器ID向左移12位 */
private final long workerIdShift = sequenceBits;
/** 数据标识id向左移17位(12+5) */
private final long datacenterIdShift = sequenceBits + workerIdBits;
/** 时间戳向左移22位(5+5+12) */
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
/** 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) */
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
/** 工作机器ID(0~31) */
private long workerId;
/** 数据中心ID(0~31) */
private long datacenterId;
/** 毫秒内序列(0~4095) */
private long sequence = 0L;
/** 上次生成ID的时间戳 */
private long lastTimestamp = -1L;
// ==============================Constructors=====================================
/**
* 构造函数
* @param workerId 工作ID (0~31)
* @param datacenterId 数据中心ID (0~31)
*/
public SnowflakeIdWorker(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(
String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(
String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
// ==============================Methods==========================================
/**
* 获得下一个ID (该方法是线程安全的)
* @return SnowflakeId
*/
public synchronized long nextId() {
long timestamp = timeGen();
// 当前时间戳小于上一次ID生成的时间戳
if (timestamp < lastTimestamp) {
long offset = lastTimestamp - timestamp;
// 系统时钟回退在容忍范围内,例如出现过闰秒
if (offset < timeOffset) {
timestamp = lastTimestamp;
}
// 系统时钟回退超出容忍范围,抛出异常
else {
throw new RuntimeException(String
.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset));
}
}
// 如果是同一时间生成的,则进行毫秒内序列
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
// 毫秒内序列溢出
if (sequence == 0) {
// 阻塞到下一个毫秒,获得新的时间戳
timestamp = tilNextMillis(lastTimestamp);
}
}
// 时间戳改变,毫秒内序列重置
else {
sequence = 0L;
}
// 上次生成ID的时间戳
lastTimestamp = timestamp;
// 移位并通过或运算拼到一起组成64位的ID
return ((timestamp - twepoch) << timestampLeftShift) //
| (datacenterId << datacenterIdShift) //
| (workerId << workerIdShift) //
| sequence;
}
/**
* 阻塞到下一个毫秒,直到获得新的时间戳
* @param lastTimestamp 上次生成ID的时间戳
* @return 当前时间戳
*/
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
/**
* 返回以毫秒为单位的当前时间
* @return 当前时间(毫秒)
*/
protected long timeGen() {
return System.currentTimeMillis();
}
// ==============================Test=============================================
/** 测试 */
public static void main(String[] args) {
System.out.println("1000011111010000000111110011100110011110000000000000000001100".length());
// SnowflakeIdWorker idWorker = new SnowflakeIdWorker(0, 0);
// for (int i = 0; i < 1000; i++) {
// long id = idWorker.nextId();
// System.out.println(Long.toBinaryString(id));
// System.out.println(id);
// }
}
}

View File

@@ -0,0 +1,47 @@
package com.senmesh.codegenerator.service.generator;
import java.util.List;
import com.google.common.collect.Lists;
import com.senmesh.codegenerator.constant.CodeConstants;
import com.senmesh.codegenerator.pojo.CodeParam;
import com.senmesh.codegenerator.service.CodeGenerator;
import com.senmesh.codegenerator.service.SnowflakeIdWorker;
import lombok.extern.slf4j.Slf4j;
/**
* 默认编号生成器
*
* @author sr on 2019-09-15
*/
@Slf4j
public class SnowFlakeCodeGenerator implements CodeGenerator<CodeParam> {
private SnowflakeIdWorker snowflakeIdWorker;
public SnowFlakeCodeGenerator(SnowflakeIdWorker snowflakeIdWorker) {
this.snowflakeIdWorker = snowflakeIdWorker;
}
@Override
public String getType() {
return CodeConstants.GENERATOR_TYPE_SNOW_FLAKE;
}
@Override
public String getCode(CodeParam codeParam) {
return codeParam.getType() + snowflakeIdWorker.nextId();
}
@Override
public List<String> batchCode(CodeParam codeParam, Integer batchNum) {
List<String> ids = Lists.newArrayListWithCapacity(batchNum);
for (int i = 0; i < batchNum; i++) {
ids.add(this.getCode(codeParam));
}
return ids;
}
}

View File

@@ -0,0 +1,48 @@
package com.senmesh.codegenerator.service.impl;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import com.google.common.collect.Maps;
import com.senmesh.codegenerator.constant.CodeConstants;
import com.senmesh.codegenerator.pojo.CodeParam;
import com.senmesh.codegenerator.service.CodeGenerator;
import com.senmesh.codegenerator.service.CodeService;
/**
* 编号service实现类
*
* @author sr on 2019-09-15
*/
public class CodeServiceImpl implements CodeService {
private Map<String, CodeGenerator<CodeParam>> codeGenerators = Maps.newHashMap();
@SuppressWarnings({"unchecked", "rawtypes"})
@Autowired
private void codeGenerateResolver(List<CodeGenerator> resolvers) {
resolvers.forEach(resolver -> codeGenerators.put(resolver.getType(), resolver));
}
private CodeGenerator<CodeParam> getResolver(String type) {
CodeGenerator<CodeParam> resolver = codeGenerators.get(type);
if (resolver == null) {
resolver = codeGenerators.get(CodeConstants.GENERATOR_TYPE_SNOW_FLAKE);
}
return resolver;
}
@Override
public String getCode(CodeParam codeParam) {
return getResolver(codeParam.getGeneratorType()).getCode(codeParam);
}
@Override
public List<String> batchCode(CodeParam codeParam, Integer batchNum) {
return getResolver(codeParam.getGeneratorType()).batchCode(codeParam, batchNum);
}
}

View File

@@ -0,0 +1,48 @@
package com.senmesh.codegenerator.util;
import java.util.List;
import com.senmesh.codegenerator.pojo.CodeParam;
import com.senmesh.codegenerator.service.CodeService;
import com.senmesh.component.constants.CodeTypeEnum;
/**
* 发号器工具类
* @author sr on 2021-03-23
*/
public abstract class CodeUtils {
private static CodeService codeService;
public static void setCodeService(CodeService codeService) {
CodeUtils.codeService = codeService;
}
public static String getCode(CodeTypeEnum codeTypeEnum) {
return codeService.getCode(codeTypeEnum.getCodeParam());
}
/**
* 根据生成规则获取编号
*
* @param codeParam
* @return
* @author sr on 2021-03-23
*/
public static String getCode(CodeParam codeParam) {
return codeService.getCode(codeParam);
}
/**
* 批量根据生成规则获取编号
*
* @param codeParam
* @param batchNum
* @return
* @author sr on 2021-03-23
*/
public static List<String> batchCode(CodeParam codeParam, Integer batchNum) {
return codeService.batchCode(codeParam, batchNum);
}
}

View File

@@ -0,0 +1,37 @@
package com.senmesh.codesetting.constant;
public interface CodeSettingConstants {
/**
* 编码配置数据类型
*/
public static final String CODE_SETTING_DATA_TYPE = "code_setting_data_type";
public class CodeSettingDataType {
public static final String STRING = "1";
public static final String NUMBER = "2";
public static final String DATE = "3";
public static final String BOOL = "4";
public static final String RADIO = "5";
public static final String CHECKBOX = "6";
public static final String FILE = "7";
}
/**
* 编码配置模块:机构配置
**/
public static final String CODE_SETTING_TYPE_CONFIG = "1";
/**
* 编码配置默认级别
**/
public static final String CODE_SETTING_LEVEL_DEFAULT = "1,2,3,4";
}

View File

@@ -0,0 +1,67 @@
package com.senmesh.codesetting.controller;
import com.senmesh.codesetting.dto.CodeSettingDTO;
import com.senmesh.codesetting.dto.CodeSettingOperatorDTO;
import com.senmesh.codesetting.dto.CodeSettingPageQueryDTO;
import com.senmesh.codesetting.dto.CodeSettingQueryDTO;
import com.senmesh.codesetting.service.CodeSettingService;
import com.senmesh.common.AlitaResult;
import com.senmesh.tkmybatis.pojo.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 编码表
*
* @author chenyun chenyun.home@outlook.com
* @since 1.0.0 2023-01-04
*/
@Api(tags = "编码表")
@RestController
@RequestMapping("code_setting")
public class CodeSettingController {
@Autowired
private CodeSettingService codeSettingService;
@PostMapping
@ApiOperation("编码表-创建")
public AlitaResult<CodeSettingDTO> create(@RequestBody CodeSettingOperatorDTO operatorDTO) {
return AlitaResult.success(codeSettingService.create(operatorDTO));
}
@PutMapping
@ApiOperation("编码表-修改")
public AlitaResult<CodeSettingDTO> modify(@RequestBody CodeSettingOperatorDTO operatorDTO) {
return AlitaResult.success(codeSettingService.modify(operatorDTO));
}
@DeleteMapping("{id}")
@ApiOperation("编码表-删除")
public AlitaResult<CodeSettingDTO> delete(@PathVariable("id") Long id) {
return AlitaResult.success(codeSettingService.delete(id));
}
@GetMapping("{id}")
@ApiOperation("编码表-查询单个")
public AlitaResult<CodeSettingDTO> findById(@PathVariable("id") Long id) {
return AlitaResult.success(codeSettingService.findById(id));
}
@GetMapping("list")
@ApiOperation("编码表-列表查询")
public AlitaResult<List<CodeSettingDTO>> list(CodeSettingQueryDTO queryDTO) {
return AlitaResult.success(codeSettingService.list(queryDTO));
}
@GetMapping("page")
@ApiOperation("编码表-分页查询")
public AlitaResult<Page<CodeSettingDTO>> page(CodeSettingPageQueryDTO queryDTO) {
codeSettingService.page(queryDTO);
return AlitaResult.success(queryDTO.getPageResult());
}
}

View File

@@ -0,0 +1,25 @@
package com.senmesh.codesetting.convert;
import com.senmesh.codesetting.dto.CodeSettingDTO;
import com.senmesh.codesetting.dto.CodeSettingOperatorDTO;
import com.senmesh.codesetting.entity.CodeSetting;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* 编码表
*
* @author chenyun chenyun.home@outlook.com
* @since 1.0.0 2023-01-04
*/
@Mapper
public interface CodeSettingConvert {
CodeSettingConvert INSTANCE = Mappers.getMapper(CodeSettingConvert.class);
CodeSetting convert(CodeSettingDTO dto);
CodeSettingDTO convert(CodeSetting entity);
CodeSetting convert(CodeSettingOperatorDTO dto);
}

View File

@@ -0,0 +1,35 @@
package com.senmesh.codesetting.dao;
import com.senmesh.codesetting.dto.CodeSettingDTO;
import com.senmesh.codesetting.dto.CodeSettingPageQueryDTO;
import com.senmesh.codesetting.dto.CodeSettingQueryDTO;
import com.senmesh.codesetting.entity.CodeSetting;
import com.senmesh.tkmybatis.mybatis.MyMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* 编码表
*
* @author chenyun chenyun.home@outlook.com
* @since 1.0.0 2023-01-04
*/
@Mapper
public interface CodeSettingMapper extends MyMapper<CodeSetting> {
List<CodeSettingDTO> page(@Param("param") CodeSettingPageQueryDTO queryDTO);
List<CodeSettingDTO> list(@Param("param") CodeSettingQueryDTO queryDTO);
/**
* 根据类型查询
*
* @param type
* @return
*/
@Select("select * from xs_code_setting where type = #{type} and deleted = 0")
List<CodeSetting> queryByType(String type);
}

View File

@@ -0,0 +1,45 @@
package com.senmesh.codesetting.dto;
import com.senmesh.common.dto.BaseDTO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import lombok.experimental.SuperBuilder;
/**
* 编码表
*
* @author chenyun chenyun.home@outlook.com
* @since 1.0.0 2023-01-04
*/
@ApiModel("编码表")
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class CodeSettingDTO extends BaseDTO {
private static final long serialVersionUID = 1L;
@ApiModelProperty("编码")
private String code;
@ApiModelProperty("名称")
private String name;
@ApiModelProperty("备注")
private String remark;
@ApiModelProperty("类型 模板编码、配置编码")
private String type;
@ApiModelProperty("数据类型")
private String dataType;
@ApiModelProperty("级别 平台、渠道、定制机构、普通机构")
private String level;
@ApiModelProperty("数据值")
private String dataFormat;
}

View File

@@ -0,0 +1,60 @@
package com.senmesh.codesetting.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotEmpty;
import java.io.Serializable;
/**
* 编码表
*
* @author chenyun chenyun.home@outlook.com
* @since 1.0.0 2023-01-04
*/
@ApiModel("编码表")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CodeSettingOperatorDTO implements Serializable {
private static final long serialVersionUID = 8836210011277521607L;
private Long id;
@ApiModelProperty("编码")
@NotEmpty(message = "配置项编码不能为空")
@Length(min = 1, max = 64, message = "配置项编码长度超限")
private String code;
@ApiModelProperty("名称")
@NotEmpty(message = "配置项名称不能为空")
@Length(min = 1, max = 128, message = "配置项名称长度超限")
private String name;
@ApiModelProperty("备注")
// @NotEmpty(message = "备注不能为空")
private String remark;
@ApiModelProperty("数据值")
private String dataFormat;
@ApiModelProperty("类型 模板编码、配置编码")
@NotEmpty(message = "配置类型不能为空")
private String type;
@ApiModelProperty("数据类型")
@NotEmpty(message = "配置参数类型不能为空")
private String dataType;
@ApiModelProperty("级别 平台、渠道、定制机构、普通机构")
@NotEmpty(message = "配置应用级别不能为空")
private String level;
}

View File

@@ -0,0 +1,77 @@
package com.senmesh.codesetting.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.senmesh.common.annotation.trimAndUpper.TrimAndUpper;
import com.senmesh.common.dto.PageQueryDTO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
/**
* 编码表
*
* @author chenyun chenyun.home@outlook.com
* @since 1.0.0 2023-01-04
*/
@ApiModel("编码表")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class CodeSettingPageQueryDTO extends PageQueryDTO<CodeSettingDTO> {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主键ID")
private Long id;
@ApiModelProperty("编码")
private String code;
@ApiModelProperty("编码 (模糊匹配)")
@TrimAndUpper(TrimAndUpper.ExecuteType.TRIM)
private String codeLike;
@ApiModelProperty("名称 (模糊匹配)")
@TrimAndUpper(TrimAndUpper.ExecuteType.TRIM)
private String nameLike;
@ApiModelProperty("备注")
private String remark;
@ApiModelProperty("类型 模板编码、配置编码")
@TrimAndUpper(TrimAndUpper.ExecuteType.TRIM)
private String type;
@ApiModelProperty("数据类型")
private String dataType;
@ApiModelProperty("级别 平台、渠道、定制机构、普通机构")
private String level;
@ApiModelProperty("创建时间起,格式 (yyyy-MM-dd HH:mm:ss)")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTimeStart;
@ApiModelProperty("创建时间止,格式 (yyyy-MM-dd HH:mm:ss)")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTimeEnd;
@ApiModelProperty("修改时间起,格式 (yyyy-MM-dd HH:mm:ss)")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTimeStart;
@ApiModelProperty("修改时间止,格式 (yyyy-MM-dd HH:mm:ss)")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTimeEnd;
}

View File

@@ -0,0 +1,74 @@
package com.senmesh.codesetting.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.util.Date;
/**
* 编码表
*
* @author chenyun chenyun.home@outlook.com
* @since 1.0.0 2023-01-04
*/
@ApiModel("编码表")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CodeSettingQueryDTO implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主键ID")
private Long id;
@ApiModelProperty("编码")
private String code;
@ApiModelProperty("编码 (模糊匹配)")
private String codeLike;
@ApiModelProperty("名称 (模糊匹配)")
private String nameLike;
@ApiModelProperty("备注")
private String remark;
@ApiModelProperty("类型 模板编码、配置编码")
private String type;
@ApiModelProperty("数据类型")
private String dataType;
@ApiModelProperty("级别 平台、渠道、定制机构、普通机构")
private String level;
@ApiModelProperty("创建时间起,格式 (yyyy-MM-dd HH:mm:ss)")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTimeStart;
@ApiModelProperty("创建时间止,格式 (yyyy-MM-dd HH:mm:ss)")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTimeEnd;
@ApiModelProperty("修改时间起,格式 (yyyy-MM-dd HH:mm:ss)")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTimeStart;
@ApiModelProperty("修改时间止,格式 (yyyy-MM-dd HH:mm:ss)")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTimeEnd;
}

View File

@@ -0,0 +1,56 @@
package com.senmesh.codesetting.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.senmesh.common.entity.BaseEntity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* 编码表
*
* @author chenyun chenyun.home@outlook.com
* @since 1.0.0 2023-01-04
*/
@TableName("xs_code_setting")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class CodeSetting extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 编码
*/
private String code;
/**
* 名称
*/
private String name;
/**
* 备注
*/
private String remark;
/**
* 类型 模板编码、配置编码
*/
private String type;
/**
* 数据类型
*/
private String dataType;
/**
* 数据格式编号
*/
private String dataFormat;
/**
* 级别 平台、渠道、定制机构、普通机构
*/
private String level;
}

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.senmesh.codesetting.dao.CodeSettingMapper">
<select id="list" resultType="com.senmesh.codesetting.dto.CodeSettingDTO">
SELECT t.*
<include refid="queryFromSql"></include>
</select>
<select id="page" resultType="com.senmesh.codesetting.dto.CodeSettingDTO">
SELECT t.*
<include refid="queryFromSql"></include>
</select>
<sql id="queryFromSql">
FROM
xs_code_setting t
WHERE t.deleted = FALSE
<if test='param.id != null'>
AND t.id = #{param.id}
</if>
<if test='param.code != null and param.code.trim() != ""'>
AND t.code = #{param.code}
</if>
<if test='param.codeLike != null and param.codeLike.trim() != ""'>
<bind name="codeLike" value="'%' + param.codeLike + '%'"/>
AND t.code like #{codeLike}
</if>
<if test='param.nameLike != null and param.nameLike.trim() != ""'>
<bind name="nameLike" value="'%' + param.nameLike + '%'"/>
AND t.name like #{nameLike}
</if>
<if test='param.remark != null and param.remark.trim() != ""'>
AND t.remark = #{param.remark}
</if>
<if test='param.type != null and param.type.trim() != ""'>
AND t.type = #{param.type}
</if>
<if test='param.dataType != null and param.dataType.trim() != ""'>
AND t.data_type = #{param.dataType}
</if>
<if test='param.level != null and param.level.trim() != ""'>
AND FIND_IN_SET(CONCAT(#{param.level},""),t.level)
</if>
<if test='param.createTimeStart != null'>
AND t.create_time &gt;= #{param.createTimeStart}
</if>
<if test='param.createTimeEnd != null'>
AND t.create_time &lt;= #{param.createTimeEnd}
</if>
<if test='param.updateTimeStart != null'>
AND t.update_time &gt;= #{param.updateTimeStart}
</if>
<if test='param.updateTimeEnd != null'>
AND t.update_time &lt;= #{param.updateTimeEnd}
</if>
ORDER BY t.id DESC
</sql>
</mapper>

View File

@@ -0,0 +1,95 @@
package com.senmesh.codesetting.service;
import com.senmesh.codesetting.dto.CodeSettingDTO;
import com.senmesh.codesetting.dto.CodeSettingOperatorDTO;
import com.senmesh.codesetting.dto.CodeSettingPageQueryDTO;
import com.senmesh.codesetting.dto.CodeSettingQueryDTO;
import org.springframework.validation.annotation.Validated;
import javax.validation.Valid;
import javax.validation.groups.Default;
import java.util.List;
/**
* 编码表
*
* @author chenyun chenyun.home@outlook.com
* @since 1.0.0 2023-01-04
*/
@Validated(Default.class)
public interface CodeSettingService {
/**
* 编码表 - 创建
*
* @param operatorDto 操作dto
* @return {@link CodeSettingDTO}
*/
CodeSettingDTO create(@Valid CodeSettingOperatorDTO operatorDto);
/**
* 校验编码是否存在
*
* @param code 代码
* @param codeSettingId 编码ID
* @return boolean true: 存在重复编码
*/
boolean checkCode(String code, Long codeSettingId);
/**
* 编码表 - 修改
*
* @param operatorDto 操作dto
* @return {@link CodeSettingDTO}
*/
CodeSettingDTO modify(@Valid CodeSettingOperatorDTO operatorDto);
/**
* 编码表 - 删除
*
* @param id id
* @return {@link CodeSettingDTO}
*/
CodeSettingDTO delete(Long id);
/**
* 编码表 - 根据ID查询单个
*
* @param id id
* @return {@link CodeSettingDTO}
*/
CodeSettingDTO findById(Long id);
/**
* 编码表 - 列表查询
*
* @param queryDTO 列表查询dto
* @return {@link List}<{@link CodeSettingDTO}>
*/
List<CodeSettingDTO> list(CodeSettingQueryDTO queryDTO);
/**
* 编码表 - 分页查询
*
* @param queryDTO 分页查询dto
* @return {@link CodeSettingDTO}
*/
List<CodeSettingDTO> page(CodeSettingPageQueryDTO queryDTO);
/**
* 根据type和code查询
*
* @param codeSettingType
* @param orgType
* @return
*/
List<com.senmesh.codesetting.dto.CodeSettingDTO> queryCode(String codeSettingType, String orgType);
/**
* 根据code查询
*
* @param code
* @return
*/
CodeSettingDTO getByCode(String code);
}

View File

@@ -0,0 +1,119 @@
package com.senmesh.codesetting.service.impl;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.stereotype.Service;
import com.senmesh.codesetting.convert.CodeSettingConvert;
import com.senmesh.codesetting.dao.CodeSettingMapper;
import com.senmesh.codesetting.dto.CodeSettingDTO;
import com.senmesh.codesetting.dto.CodeSettingOperatorDTO;
import com.senmesh.codesetting.dto.CodeSettingPageQueryDTO;
import com.senmesh.codesetting.dto.CodeSettingQueryDTO;
import com.senmesh.codesetting.entity.CodeSetting;
import com.senmesh.codesetting.service.CodeSettingService;
import com.senmesh.common.constant.CommonConstants;
import com.senmesh.common.exception.util.Assert;
import com.senmesh.common.util.UserContextHolder;
import com.senmesh.config.dao.ConfigMapper;
import lombok.extern.slf4j.Slf4j;
/**
* 编码表
*
* @author chenyun chenyun.home@outlook.com
* @since 1.0.0 2023-01-04
*/
@Slf4j
@Service
public class CodeSettingServiceImpl implements CodeSettingService {
@Resource
private CodeSettingMapper codeSettingMapper;
@Resource
private ConfigMapper configMapper;
@Override
public CodeSettingDTO create(CodeSettingOperatorDTO operatorDto) {
Assert.isTrue(!checkCode(operatorDto.getCode(), null), "配置项编码已存在");
CodeSetting codeSetting = CodeSettingConvert.INSTANCE.convert(operatorDto);
codeSettingMapper.saveEntity(codeSetting);
return CodeSettingConvert.INSTANCE.convert(codeSetting);
}
@Override
public boolean checkCode(String code, Long codeSettingId) {
return codeSettingMapper.existsEntity(CodeSetting.builder().code(code).build());
}
@Override
public CodeSettingDTO modify(CodeSettingOperatorDTO operatorDto) {
CodeSettingDTO codeSettingDto = this.findById(operatorDto.getId());
if (Objects.isNull(codeSettingDto)) {
return null;
}
Assert.isTrue(!checkCode(operatorDto.getCode(), operatorDto.getId()), "配置项编码已存在");
CodeSetting codeSetting = CodeSettingConvert.INSTANCE.convert(operatorDto);
codeSettingMapper.updateEntity(codeSetting);
return this.findById(operatorDto.getId());
}
@Override
public CodeSettingDTO delete(Long id) {
CodeSettingDTO codeSettingDto = this.findById(id);
if (Objects.isNull(codeSettingDto)) {
return null;
}
CodeSetting codeSetting = CodeSetting.builder().build();
codeSetting.setId(id);
codeSettingMapper.deleteEntity(codeSetting, UserContextHolder.getLoginUserId());
// 删除配置项的时候,同步删除配置项下的配置
configMapper.batchDelete(codeSettingDto.getCode(), UserContextHolder.getExistLoginUserId());
return codeSettingDto;
}
@Override
public CodeSettingDTO findById(Long id) {
CodeSetting codeSetting = codeSettingMapper.getById(id);
if (Objects.isNull(codeSetting)) {
return null;
}
return CodeSettingConvert.INSTANCE.convert(codeSetting);
}
@Override
public List<CodeSettingDTO> list(CodeSettingQueryDTO queryDTO) {
return codeSettingMapper.list(queryDTO);
}
@Override
public List<CodeSettingDTO> page(CodeSettingPageQueryDTO queryDTO) {
return codeSettingMapper.page(queryDTO);
}
@Override
public List<CodeSettingDTO> queryCode(String codeSettingType, String orgType) {
List<CodeSetting> codeSettings = codeSettingMapper.queryByType(codeSettingType);
return codeSettings.stream()
.filter(codeSetting -> ArrayUtils
.contains(codeSetting.getLevel().split(CommonConstants.COMMA), orgType))
.map(CodeSettingConvert.INSTANCE::convert).collect(Collectors.toList());
}
@Override
public CodeSettingDTO getByCode(String code) {
List<CodeSettingDTO> list = this.list(CodeSettingQueryDTO.builder().code(code).build());
if (CollectionUtils.isEmpty(list)) {
return null;
}
return list.get(0);
}
}

View File

@@ -0,0 +1,253 @@
package com.senmesh.common;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.senmesh.sdk.common.constant.SdkConstants;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 用于 ajax 请求的响应工具类
*
* @author guhong
* @date 2019/8/19
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AlitaResult<T> implements Serializable {
/** */
private static final long serialVersionUID = 5933105804003541576L;
/** 未登录 * */
public static final String UN_LOGIN_CODE = "401";
/** 无权限 * */
public static final String NO_AUTHORITY_CODE = "402";
/** 无查询信息 * */
public static final String NO_RESULT_CODE = "405";
/** 登录用户多机构 * */
public static final String DUPLICATE_ORG_CODE = "600";
/** 登录用户多用户 * */
public static final String DUPLICATE_USER_CODE = "601";
/** 用户未实名 * */
public static final String UN_AUTH_CODE = "602";
/** 用户更换token **/
public static final String CHANGE_TOKEN_CODE = "603";
/** 用户未绑定手机号 **/
public static final String UN_BINDING_PHONE = "604";
/** 登录用户相关异常 **/
public static final String LOGIN_ERROR_CODE = "666";
/** 系统异常 * */
public static final String SYSTEM_ERROR_CODE = "999";
/** 业务异常 **/
public static final String BUSINESS_ERROR_CODE = "700";
/** 校验异常 * */
public static final String VALIDATION_ERROR_CODE = "555";
/** 操作成功 * */
public static final String SUCCESS_CODE = "200";
public static final String CHANG_TOKEN_MSG = "token变更";
/** 链路id **/
private String requestId;
/** 响应信息 */
private String msg;
/** 响应code */
private String code;
/** 是否成功 */
private Boolean success;
/** 操作成功,响应数据 */
private T data;
/** 操作失败结果 **/
private Object errorData;
/** 临时json **/
@JsonIgnore
private String tempJson;
public AlitaResult(String code, String msg, boolean success, T data) {
this.msg = msg;
this.code = code;
this.success = success;
this.data = data;
}
public AlitaResult(String code, String msg, Serializable errorData) {
this.msg = msg;
this.code = code;
this.success = false;
this.errorData = errorData;
}
/**
* 创建一个成功的响应对象
*
* @return
*/
public static <T> AlitaResult<T> success() {
return success(null);
}
/**
* 创建一个成功的响应对象
*
* @param data
* @return
*/
public static <T> AlitaResult<T> success(T data) {
return new AlitaResult<T>(SUCCESS_CODE, "请求成功", true, data);
}
/**
* 创建一个成功的响应对象
*
* @param msg
* @return
*/
public static <T> AlitaResult<T> success(String msg, T data) {
return new AlitaResult<T>(SUCCESS_CODE, msg, true, data);
}
/**
* 创建一个失败的响应对象
*
* @param msg
* @return
*/
public static <T> AlitaResult<T> error(String msg) {
return new AlitaResult<T>(SYSTEM_ERROR_CODE, msg, false, null);
}
/**
* 创建一个失败的响应对象
*
* @param code
* @param msg
* @return
*/
public static <T> AlitaResult<T> error(String code, String msg) {
return new AlitaResult<T>(code, msg, false, null);
}
/**
* 创建一个失败的响应对象
*
* @param code
* @param msg
* @return
*/
public static <T> AlitaResult<T> error(String code, String msg, T data) {
return new AlitaResult<T>(code, msg, false, data);
}
/**
* 创建一个失败的响应对象
*
* @param msg
* @return
*/
public static <T> AlitaResult<T> error(String msg, T data) {
return new AlitaResult<T>(SYSTEM_ERROR_CODE, msg, false, data);
}
/**
* 创建业务异常对象
*
* @param <T>
* @param msg
* @return
* @author sr on 2020-07-02
*/
public static <T> AlitaResult<T> bizError(String msg) {
return new AlitaResult<T>(BUSINESS_ERROR_CODE, msg, false, null);
}
/**
* 创建一个未登录响应对象
*
* @return
*/
public static <T> AlitaResult<T> unLogin() {
return new AlitaResult<T>(UN_LOGIN_CODE, "请先登录", false, null);
}
/**
* 创建未实名响应对象
* @param <T>
* @return
* @author sr on 2021-06-30
*/
public static <T> AlitaResult<T> unAuth() {
return new AlitaResult<T>(UN_AUTH_CODE, "请先实名", false, null);
}
/**
* 创建未绑定手机号响应对象
* @param <T>
* @return
* @author sr on 2021-06-30
*/
public static <T> AlitaResult<T> unBinding() {
return new AlitaResult<T>(UN_BINDING_PHONE, "请先绑定手机号", false, null);
}
/**
* 创建一个未登录响应对象
*
* @param loginUrl 登录地址
* @return
* @author sr on 2019-12-29
*/
public static AlitaResult<String> unLogin(String loginUrl) {
return new AlitaResult<String>(UN_LOGIN_CODE, "请先登录", false, loginUrl);
}
/**
* 更换token
* @param <T>
* @param token
* @return
* @author sr on 2021-08-02
*/
public static <T> AlitaResult<T> changeToken(Serializable token) {
return new AlitaResult<T>(AlitaResult.CHANGE_TOKEN_CODE, CHANG_TOKEN_MSG, token);
}
/**
* 创建一个未登录响应对象
*
* @return
* @author sr on 2019-12-29
*/
public static <T> AlitaResult<T> noResult() {
return new AlitaResult<T>(NO_RESULT_CODE, "无查询信息", false, null);
}
/**
* 接口调用失败,未能拿到返回对象
*
* @param <T>
* @param msg
* @return
* @author sr on 2020-04-10
*/
public static <T> AlitaResult<T> sdkInvokeNotReachError(String msg) {
return new AlitaResult<T>(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, msg, false, null);
}
@SuppressWarnings({"hiding", "unchecked"})
public <T> AlitaResult<T> setRequestId(String requestId){
this.requestId = requestId;
return (AlitaResult<T>) this;
}
public <T> AlitaResult<T> setTempJson(String tempJson){
this.tempJson = tempJson;
return (AlitaResult<T>) this;
}
}

View File

@@ -0,0 +1,110 @@
package com.senmesh.common;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.senmesh.common.cache.DefaultCacheProvider;
import com.senmesh.common.cache.ICacheProvider;
import com.senmesh.common.log.ILogProvider;
import com.senmesh.common.log.provider.Slf4jLogProvider;
import com.senmesh.common.log.util.LogUtils;
import com.senmesh.common.service.IMockProvider;
import com.senmesh.common.service.IMockProvider.DefaultMockProvider;
import com.senmesh.common.util.EnvironmentUtils;
import com.senmesh.common.util.MockUtils;
import com.senmesh.component.file.service.IFileStorage;
import com.senmesh.component.file.service.storage.LocalFileStorage;
import com.senmesh.component.file.util.FileStorageUtils;
import lombok.var;
/**
* @author sr on 2020-07-24
*/
@Configuration
public class CommonConfiguration {
@Bean
EnvironmentUtils environmentUtils(Environment environment) {
return new EnvironmentUtils(environment);
}
@Bean
@ConditionalOnMissingBean(ICacheProvider.class)
@Order(100)
DefaultCacheProvider defauCacheProvider() {
return new DefaultCacheProvider();
}
@Bean
@Order(100)
@ConditionalOnMissingBean(ILogProvider.class)
Slf4jLogProvider slf4jLogProvider() {
return new Slf4jLogProvider();
}
@Bean
@Order(200)
LogUtils logUtils(ILogProvider iLogProvider) {
LogUtils logUtils = new LogUtils();
logUtils.setLogProvider(iLogProvider);
return logUtils;
}
@Bean
@ConditionalOnMissingBean(IFileStorage.class)
public LocalFileStorage localFileStorage() {
return new LocalFileStorage();
}
@Bean
public FileStorageUtils fileStorageUtils(IFileStorage fileStorage) {
return new FileStorageUtils(fileStorage);
}
@Bean
@ConditionalOnMissingBean(IMockProvider.class)
public IMockProvider defaultMockProvider() {
return new DefaultMockProvider();
}
@Bean
public MockUtils mockUtils(IMockProvider mockProvider) {
return new MockUtils(mockProvider);
}
/**
* requestbody string trim
* @return
* @author sr on 2024-04-19
*/
@Bean
public SimpleModule stringDeserializerModule() {
final var module = new SimpleModule();
module.addDeserializer(String.class, new StringDeserializer() {
@Override
public String deserialize(JsonParser p, DeserializationContext ctx) throws java.io.IOException {
final var value = super.deserialize(p, ctx);
if (value == null) {
return null;
}
final var trimmed = value.trim();
if (trimmed.isEmpty()) {
return null;
}
return trimmed;
}
});
return module;
}
}

View File

@@ -0,0 +1,26 @@
package com.senmesh.common;
import org.jasypt.encryption.StringEncryptor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.senmesh.common.trace.DefaultTracer;
import com.senmesh.common.trace.ITracer;
import com.senmesh.common.util.JasyptUtils;
@Configuration
public class CoreConfiguration {
@Bean
JasyptUtils jasyptUtils(StringEncryptor stringEncryptor) {
return new JasyptUtils(stringEncryptor);
}
@Bean
@ConditionalOnMissingBean(value = ITracer.class)
ITracer defaultTracer() {
return new DefaultTracer();
}
}

View File

@@ -0,0 +1,24 @@
package com.senmesh.common.actuate.health.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 监控健康信息
*
* @author sr on 2020-07-08
* @param <T>
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class HealthDTO<T> {
private String status;
private T details;
}

View File

@@ -0,0 +1,14 @@
package com.senmesh.common.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AlitaStopWatch {
}

View File

@@ -0,0 +1,56 @@
package com.senmesh.common.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.senmesh.common.constant.ProjectProfileEnum;
/**
* 校验并mock
*
* @author sr on 2020-05-20
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CheckAndMock {
/**
* 属性前缀
*
* @return
* @author sr on 2020-05-20
*/
String propertyPrefix() default "";
/**
* 属性配置类
*
* @return
* @author sr on 2020-05-20
*/
Class<ICheckAndMockPropertity> checkAndMockPropertity() default ICheckAndMockPropertity.class;
/**
* mock实现类(需注入spring上下文,提供与原方法方法名/参数/返回对象一致的方法)
*
* @return
* @author sr on 2020-05-20
*/
Class<?> mockClass();
// String mockBeanId();
/**
* 指定环境直接mock
*
* @return
* @author sr on 2020-05-21
*/
ProjectProfileEnum[] mockIfInProfile() default {};
}

View File

@@ -0,0 +1,27 @@
package com.senmesh.common.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 校验定时任务是否开启
*
* @author sr on 2020-05-19
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CheckJob {
/**
* 配置文件是否开启的key,明确指定为false时才关闭
*
* @return
* @author sr on 2020-05-19
*/
String value();
}

View File

@@ -0,0 +1,34 @@
package com.senmesh.common.annotation;
/**
* 需要校验后mock的配置
*
* @author sr on 2020-05-20
*/
public interface ICheckAndMockPropertity {
/**
* 是否开启
*
* @return
* @author sr on 2020-05-21
*/
Boolean getEnable();
/**
* 次数限制
*
* @return
* @author sr on 2020-05-21
*/
Long getNumLimit();
/**
* 属性前缀
*
* @return
* @author sr on 2020-05-21
*/
String getPropertityPrefix();
}

View File

@@ -0,0 +1,19 @@
package com.senmesh.common.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
/**
* 掩码
* @author sr on 2021-11-25
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
@JacksonAnnotationsInside
public @interface Mask {
}

View File

@@ -0,0 +1,32 @@
package com.senmesh.common.annotation;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
/**
* @author sr on 2021-11-25
*/
public class MaskAnontationIntrospector extends JacksonAnnotationIntrospector {
private static final long serialVersionUID = 1L;
@Override
public Object findSerializer(Annotated a) {
Mask mask = a.getAnnotation(Mask.class);
if (mask != null) {
return MaskSerializer.class;
}
return super.findSerializer(a);
}
@Override
public boolean hasIgnoreMarker(AnnotatedMember m) {
// 直接不打印该字段,则置为true
/*if (m.hasAnnotation(Mask.class)) {
return true;
}*/
return super.hasIgnoreMarker(m);
}
}

View File

@@ -0,0 +1,37 @@
package com.senmesh.common.annotation;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
/**
* @author sr on 2021-11-25
*/
public class MaskSerializer extends StdSerializer<Object> {
private static final long serialVersionUID = 1L;
private String mask = "***";
public MaskSerializer() {
super(Object.class);
}
public MaskSerializer(String mask, int count) {
this();
}
public MaskSerializer(MaskSerializer src) {
super(src);
}
@Override
public void serialize(Object s, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(mask);
}
}

View File

@@ -0,0 +1,49 @@
package com.senmesh.common.annotation.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import com.senmesh.common.annotation.AlitaStopWatch;
import com.senmesh.common.exception.util.DevopsUtils;
import com.senmesh.common.util.EnvironmentUtils;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Aspect
@Component
public class AlitaStopWatchAspect {
public static final String DEVOPS_TIME_KEY = "devops.usetime";
/** 默认十分钟 **/
public static final Long DEFAULT_DEVOPS_TIME = 10 * 60L;
@Around("@annotation(alitaStopWatch)")
public Object around(ProceedingJoinPoint joinPoint, AlitaStopWatch alitaStopWatch) throws Throwable {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
try {
return joinPoint.proceed();
} finally {
stopWatch.stop();
String useTimeStr = EnvironmentUtils.getProperty(DEVOPS_TIME_KEY);
Long maxUseTime = DEFAULT_DEVOPS_TIME;
try {
maxUseTime = Long.parseLong(useTimeStr);
} catch (Exception e) {
}
maxUseTime = 1000 * maxUseTime;
Long actualTime = stopWatch.getTotalTimeMillis();
String logMsg = joinPoint.getSignature().toShortString() + ",use(ms): " + actualTime;
if (actualTime > maxUseTime) {
DevopsUtils.deal(logMsg);
}
log.info(logMsg);
}
}
}

View File

@@ -0,0 +1,129 @@
package com.senmesh.common.annotation.aspect;
import com.senmesh.common.annotation.CheckAndMock;
import com.senmesh.common.annotation.ICheckAndMockPropertity;
import com.senmesh.common.cache.ICacheProvider;
import com.senmesh.common.constant.CommonConstants;
import com.senmesh.common.constant.ProjectProfileEnum;
import com.senmesh.common.util.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* 校验并mock
*
* @author sr on 2020-05-19
*/
@Aspect
@Component
@Slf4j
@Order(200)
public class CheckAndMockAspect {
/** 是否开启属性 **/
public static final String ENABLE_KEY = "enable";
/** 次数限制属性 **/
public static final String NUM_LIMIT_KEY = "numLimit";
/** 默认次数 **/
public static final Long DEFALUT_NUM_LIMIT = 3L;
@Autowired
private Environment environment;
@Autowired
private ICacheProvider iCacheProvider;
@Around("@annotation(checkAndMock)")
public Object around(ProceedingJoinPoint joinPoint, CheckAndMock checkAndMock) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
ProjectProfileEnum[] profileEnums = checkAndMock.mockIfInProfile();
Class<?> mockClass = checkAndMock.mockClass();
String currentProfile = environment.getProperty(CommonConstants.PROFILE_KEY);
Object[] args = joinPoint.getArgs();
// 只要配置环境mock,就不校验开关和次数限制
if (profileEnums.length > 0) {
for (ProjectProfileEnum profileEnum : profileEnums) {
if (profileEnum.getValue().equals(currentProfile)) {
return mock(mockClass, method, args);
}
}
return joinPoint.proceed();
}
// 获取属性配置
String propertyPrefix = checkAndMock.propertyPrefix();
boolean enable = true;
Long numLimit = null;
if (StringUtils.isNotBlank(propertyPrefix)) {
enable = BooleanUtils.toBoolean(
environment.getProperty(String.join(CommonConstants.POINT, propertyPrefix, ENABLE_KEY)));
try {
numLimit = enable ? Long.parseLong(environment
.getProperty(String.join(CommonConstants.POINT, propertyPrefix, NUM_LIMIT_KEY))) : 0L;
} catch (NumberFormatException e) {
log.info("{} numLimit not right, use default numLimit", propertyPrefix);
}
} else {
try {
ICheckAndMockPropertity properties =
SpringContextHolder.getBean(checkAndMock.checkAndMockPropertity());
enable = properties.getEnable();
numLimit = properties.getNumLimit();
propertyPrefix = properties.getPropertityPrefix();
} catch (Exception e) {
log.info("ICheckAndMockPropertity not found...");
enable = false;
}
}
// 开关关闭,都走mock
if (!enable) {
return mock(mockClass, method, args);
}
// 开关开启,生产无次数限制,本地测试根据配置/默认次数控制
boolean isProd = ProjectProfileEnum.PROD.getValue().equals(currentProfile);
if (isProd) {
return joinPoint.proceed();
}
numLimit = numLimit == null ? DEFALUT_NUM_LIMIT : numLimit;
String key = String.join(CommonConstants.POINT, propertyPrefix, NUM_LIMIT_KEY);
if (iCacheProvider.outLimit(key, numLimit)) {
// 超限,mock
return mock(mockClass, method, args);
}
// 次数限制
return joinPoint.proceed();
}
/**
* mock调用
*
* @param clazz
* @param method
* @param objects
* @return
* @throws Throwable
* @author sr on 2020-05-21
*/
private Object mock(Class<?> clazz, Method method, Object[] objects) throws Throwable {
Object mockBean = SpringContextHolder.getBean(clazz);
Method mockMethod = mockBean.getClass().getMethod(method.getName(), method.getParameterTypes());
return mockMethod.invoke(mockBean, objects);
}
}

View File

@@ -0,0 +1,46 @@
package com.senmesh.common.annotation.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import com.senmesh.common.annotation.CheckJob;
import com.senmesh.common.constant.CommonConstants;
import lombok.extern.slf4j.Slf4j;
/**
* 校验定时任务是否开启
*
* @author sr on 2020-05-19
*/
@Aspect
@Component
@Slf4j
public class CheckJobAspect {
/** 配置无效识别符(只有配置false才失效) **/
private String falseValue = "false";
/** 定时任务配置前缀 **/
public static final String JOB_PROPERTY_PREFIX = "job";
@Autowired
private Environment environment;
@Around("@annotation(checkJob)")
public Object around(ProceedingJoinPoint joinPoint, CheckJob checkJob) throws Throwable {
String propertityKey = checkJob.value();
boolean disable = falseValue.equals(environment
.getProperty(String.join(CommonConstants.POINT, JOB_PROPERTY_PREFIX, propertityKey)));
if (disable) {
log.info("job:{} not enable...", propertityKey);
return null;
}
return joinPoint.proceed();
}
}

View File

@@ -0,0 +1,31 @@
package com.senmesh.common.annotation.trimAndUpper;
import java.lang.annotation.*;
/**
* 用于字符串去空格以及大写
*
* @author Carlye
* @date 2022/02/16
*/
@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TrimAndUpper {
/**
* 执行类型
* ALL: (所有类型都包含)
* TRIM: (去两边的空格)
* REPLACE_ALL: (去所有的空格)
* UPPER_CASE: (转大写)
*
* @author Carlye
* @date 2022/02/16
*/
public static enum ExecuteType {
ALL, TRIM, REPLACE_ALL, UPPER_CASE;
}
ExecuteType value() default ExecuteType.ALL;
}

View File

@@ -0,0 +1,27 @@
package com.senmesh.common.annotation.trimAndUpper;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair;
/**
* @author sr on 2021-11-25
*/
public class TrimAndUpperAnontationIntrospector extends AnnotationIntrospectorPair {
private static final long serialVersionUID = -1755768596246088917L;
public TrimAndUpperAnontationIntrospector(AnnotationIntrospector p,
AnnotationIntrospector s) {
super(p, s);
}
@Override
public Object findDeserializer(Annotated a) {
TrimAndUpper trim = a.getAnnotation(TrimAndUpper.class);
if (trim != null) {
return TrimAndUpperDeserializer.class;
}
return super.findDeserializer(a);
}
}

View File

@@ -0,0 +1,59 @@
package com.senmesh.common.annotation.trimAndUpper;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.cfg.BaseSettings;
import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair;
import java.lang.reflect.Field;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
@Configuration
public class TrimAndUpperConfig {
@Autowired
public void addFormatters(FormatterRegistry registry) {
TrimAndUpperFormatterFactory trimAndUpperCaseFormatterFactory = new TrimAndUpperFormatterFactory();
registry.addFormatterForFieldAnnotation(trimAndUpperCaseFormatterFactory);
}
@Autowired
public void init(RequestMappingHandlerAdapter handlerAdapter){
for (HttpMessageConverter<?> messageConverter : handlerAdapter.getMessageConverters()) {
try {
if (messageConverter instanceof MappingJackson2HttpMessageConverter){
MappingJackson2HttpMessageConverter converter1 = (MappingJackson2HttpMessageConverter)messageConverter;
ObjectMapper objectMapper = converter1.getObjectMapper();
DeserializationConfig deserializationConfig = objectMapper.getDeserializationConfig();
Field _base = ReflectionUtils.findField(DeserializationConfig.class, "_base");
ReflectionUtils.makeAccessible(_base);
BaseSettings baseSettings = (BaseSettings)ReflectionUtils.getField(_base, deserializationConfig);
AnnotationIntrospector annotationIntrospector = baseSettings.getAnnotationIntrospector();
if (annotationIntrospector instanceof AnnotationIntrospectorPair){
AnnotationIntrospectorPair annotationIntrospectorOld = (AnnotationIntrospectorPair)baseSettings.getAnnotationIntrospector();
Field _primary = ReflectionUtils.findField(AnnotationIntrospectorPair.class, "_primary");
ReflectionUtils.makeAccessible(_primary);
AnnotationIntrospector _primaryObj = (AnnotationIntrospector)ReflectionUtils.getField(_primary, annotationIntrospectorOld);
Field _secondary = ReflectionUtils.findField(AnnotationIntrospectorPair.class, "_secondary");
ReflectionUtils.makeAccessible(_secondary);
AnnotationIntrospector _secondaryObj = (AnnotationIntrospector)ReflectionUtils.getField(_secondary, annotationIntrospectorOld);
converter1.getObjectMapper().setAnnotationIntrospector(new TrimAndUpperAnontationIntrospector(_primaryObj,_secondaryObj));
}
}
} catch (Exception e) {
//doNothing
}
}
}
}

View File

@@ -0,0 +1,66 @@
package com.senmesh.common.annotation.trimAndUpper;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.google.common.collect.Maps;
import com.senmesh.common.annotation.trimAndUpper.TrimAndUpper.ExecuteType;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import org.apache.commons.lang3.StringUtils;
public class TrimAndUpperDeserializer extends StdDeserializer<String> implements ContextualDeserializer {
private static final Map<ExecuteType, TrimAndUpperDeserializer> INSTANCE_MAP = Maps.newHashMap();
private static final long serialVersionUID = 3463447204376923373L;
static {
for (ExecuteType value : ExecuteType.values()) {
INSTANCE_MAP.put(value,new TrimAndUpperDeserializer(value));
}
}
private ExecuteType executeType;
public TrimAndUpperDeserializer(){
super(String.class);
}
public TrimAndUpperDeserializer(ExecuteType executeType){
super(String.class);
this.executeType = executeType;
}
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
String s = jsonParser.getText();
if (!(StringUtils.isEmpty(s) || Objects.isNull(executeType))) {
if (ExecuteType.ALL == executeType || ExecuteType.TRIM == executeType) {
s = StringUtils.replace(StringUtils.trim(s)," ","");
}
if (ExecuteType.ALL == executeType || ExecuteType.TRIM == executeType) {
s = StringUtils.upperCase(s);
}
}
return s;
}
@Override
public JsonDeserializer<?> createContextual(DeserializationContext prov, BeanProperty property) throws JsonMappingException {
ExecuteType executeType = null;
TrimAndUpper ann = null;
if (property != null) {
ann = property.getAnnotation(TrimAndUpper.class);
}
if (ann != null) {
executeType = ann.value();
}
return INSTANCE_MAP.get(executeType);
}
}

View File

@@ -0,0 +1,77 @@
package com.senmesh.common.annotation.trimAndUpper;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.senmesh.common.annotation.trimAndUpper.TrimAndUpper.ExecuteType;
import org.apache.commons.lang3.StringUtils;
import org.springframework.format.AnnotationFormatterFactory;
import org.springframework.format.Formatter;
import org.springframework.format.Parser;
import org.springframework.format.Printer;
import java.text.ParseException;
import java.util.*;
public class TrimAndUpperFormatterFactory implements
AnnotationFormatterFactory<TrimAndUpper> {
private static final Map<ExecuteType, TrimAndUpperCaseFormatter> TRIMMER_FORMATTER_MAP;
static {
ExecuteType[] values = ExecuteType.values();
Map<ExecuteType, TrimAndUpperCaseFormatter> map = Maps.newHashMap();
for (ExecuteType type : values) {
map.put(type, new TrimAndUpperCaseFormatter(type));
}
TRIMMER_FORMATTER_MAP = Collections.unmodifiableMap(map);
}
@Override
public Set<Class<?>> getFieldTypes() {
return Sets.newHashSet(String.class);
}
@Override
public Printer<?> getPrinter(TrimAndUpper trimAndUpper, Class<?> aClass) {
return TRIMMER_FORMATTER_MAP.get(trimAndUpper.value());
}
@Override
public Parser<?> getParser(TrimAndUpper trimAndUpper, Class<?> aClass) {
return TRIMMER_FORMATTER_MAP.get(trimAndUpper.value());
}
private static class TrimAndUpperCaseFormatter implements Formatter<String> {
private TrimAndUpper.ExecuteType executeType;
public TrimAndUpperCaseFormatter(TrimAndUpper.ExecuteType executeType) {
this.executeType = executeType;
}
@Override
public String parse(String value, Locale locale) throws ParseException {
if (StringUtils.isEmpty(value) || Objects.isNull(executeType)) {
return value;
}
// 去所有空格
if (ExecuteType.ALL == executeType || ExecuteType.REPLACE_ALL == executeType) {
value = StringUtils.replace(value, " ", "");
}
// 转大写
if (ExecuteType.ALL == executeType || ExecuteType.UPPER_CASE == executeType) {
value = StringUtils.upperCase(value);
}
//去两边空格
if (ExecuteType.ALL == executeType || ExecuteType.TRIM == executeType) {
value = StringUtils.trim(value);
}
return value;
}
@Override
public String print(String value, Locale locale) {
return value;
}
}
}

View File

@@ -0,0 +1,31 @@
package com.senmesh.common.cache;
import java.util.Map;
import org.apache.commons.collections.MapUtils;
import com.google.common.collect.Maps;
/**
* @author sr on 2020-07-07
*/
public class DefaultCacheProvider implements ICacheProvider {
private Map<String, Long> numLimitMap = Maps.newConcurrentMap();
@Override
public boolean outLimit(final String key, Long maxNumLimit) {
Long currentNumLimit = null;
final Object lockKey = key.intern();
synchronized (lockKey) {
currentNumLimit = MapUtils.getLong(numLimitMap, key, 0L);
if (currentNumLimit >= maxNumLimit) {
return true;
}
currentNumLimit++;
numLimitMap.put(key, currentNumLimit);
}
return false;
}
}

View File

@@ -0,0 +1,18 @@
package com.senmesh.common.cache;
/**
* @author sr on 2020-07-07
*/
public interface ICacheProvider {
/**
* 是否超限
*
* @param key
* @param maxNumLimit
* @return
* @author sr on 2020-07-07
*/
boolean outLimit(String key, Long maxNumLimit);
}

View File

@@ -0,0 +1,32 @@
package com.senmesh.common.cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
/**
* @author sr on 2020-07-07
*/
@Service
@ConditionalOnClass(RedisTemplate.class)
@Order(1)
public class RedisCacheProvier implements ICacheProvider{
@SuppressWarnings("rawtypes")
@Autowired(required = false)
private RedisTemplate redisTemplate;
@SuppressWarnings("unchecked")
@Override
public boolean outLimit(String key, Long maxNumLimit) {
Long currentNumLimit = redisTemplate.opsForValue().increment(key);
if (currentNumLimit > maxNumLimit) {
redisTemplate.opsForValue().decrement(key);
return true;
}
return false;
}
}

View File

@@ -0,0 +1,48 @@
package com.senmesh.common.constant;
/**
* 系统枚举
*
* @author sr on 2020-06-02
*/
public enum AuthStatusEnum {
/**
* 待认证
**/
NOT_AUTH(1, "待认证"),
/**
* 认证中
**/
AUTHING(2, "认证中"),
/**
* 认证成功
**/
AUTH_SUCCESS(3, "认证成功"),
/**
* 认证失败
**/
AUTH_FAIL(4, "认证失败");
/**
* 状态类型
*/
private Integer type;
/**
* 状态名称
*/
private String name;
AuthStatusEnum(Integer type, String name) {
this.type = type;
this.name = name;
}
public Integer getType() {
return type;
}
public String getName() {
return name;
}
}

View File

@@ -0,0 +1,12 @@
package com.senmesh.common.constant;
/**
* 缓存常量
*
* @author sr on 2020-04-03
*/
public interface CacheConstants {
String CACHE_NAME_DICT = "dict";
}

View File

@@ -0,0 +1,70 @@
package com.senmesh.common.constant;
/**
* 公共常量
* @author sr on 2019-12-03
*/
public interface CommonConstants {
/** _(下划线) **/
String UNDERLINE = "_";
/** # **/
String POUND = "#";
/** & **/
String AND = "&";
/** ,(逗号) **/
String COMMA = ",";
/** :(冒号) **/
String COLON = ":";
/** ;(分号) **/
String SEMICOLON = ";";
/** . **/
String POINT = ".";
/** = **/
String EQUAL = "=";
/** ? **/
String QUESTION = "?";
/** -(连字号) **/
String HYPHEN = "-";
/** ...(省略号) **/
String ELLIPSIS = "...";
/** 金额精度:两位 **/
int AMOUNT_SCALE = 2;
/** 金额小数位 **/
int AMOUNT_FRACTION = 2;
/** 金额整数位 **/
int AMOUNT_INTEGER = 14;
/** 项目环境配置key **/
String PROFILE_KEY = "spring.profiles.active";
/** 项目名称 **/
String APPLICATION_NAME_KEY = "spring.application.name";
String SYSTEM_CODE_KEY = "system.code";
/** security是否使用本地方法 **/
String USELOCAL_KEY = "security.useLocal";
/**
* 表字段去空格
*/
String TRIM_TABLE_FIELDS_ENBALE_KEY = "trim.table.fields";
/** 开关键 **/
String ENABLE_KEY = "enable";
String FALSE_STR = "false";
/** 配置值:是 **/
String CONFIG_TRUE = "1";
/** 配置值:否 **/
String CONFIG_FALSE = "0";
/** 平台机构id **/
Long PLATFORM_ORG_ID = 1L;
/** 用户禁用/注销登录态黑名单key前缀(存Redis,值存在期间该用户已发放的token视为无效) **/
String USER_DISABLED_KEY = "user:disabled:";
}

View File

@@ -0,0 +1,6 @@
package com.senmesh.common.constant;
public interface CommonMqConstants {
}

View File

@@ -0,0 +1,18 @@
package com.senmesh.common.constant;
/**
* @author Jerry.li
* @description Cookie相关常量
* @date 2020/5/11
*/
public class CookieConstants {
/**
* 登录Cookie名称前缀
*/
public static final String LOGIN_COOKIE_NAME_PREFIX = "xs_ck_";
/** 属性配置键:cookie域名 **/
public static final String PROP_KEY_COOKIE_DOMAIN = "cookie.domain";
}

View File

@@ -0,0 +1,21 @@
package com.senmesh.common.constant;
/**
* 异常错误信息
*
* @author on 2019-11-05
*/
public interface ExceptionMsgs {
String ENTITY_HAS_EXISTS = "数据已存在";
String ENTITY_NONE_EXISTS = "数据不存在";
String ENTITY_MULTIPLE_EXISTS = "数据存在多条";
String UPDATE_DATA_NOT_EXIST = "操作失败,请检查数据";
}

View File

@@ -0,0 +1,10 @@
package com.senmesh.common.constant;
public interface ExceptionRecordConstants {
/**
* 接口记录系统类型
*/
String SOURCE_HYG = "1";
String SOURCE_XINPAI = "2";
}

View File

@@ -0,0 +1,48 @@
package com.senmesh.common.constant;
/**
* 性别枚举
*
*/
public enum GenderEnum {
MALE(1, "男"),
FEMALE(2, "女"),
OTHER(3, "其它");
private final Integer type;
private final String desc;
GenderEnum(Integer type, String desc) {
this.type = type;
this.desc = desc;
}
public Integer getType() {
return type;
}
public String getDesc() {
return desc;
}
public static Integer formatFemale(Integer value){
// 通过sql 身份证号处理性别条件:0女,1男
if(GenderEnum.FEMALE.getType().equals(value)){
return 0;
}
return value;
}
public static String getVal(Integer val){
if(GenderEnum.MALE.getType().equals(val)){
return GenderEnum.MALE.desc;
} else if(GenderEnum.FEMALE.getType().equals(val)){
return GenderEnum.FEMALE.desc;
}
return GenderEnum.OTHER.desc;
}
}

View File

@@ -0,0 +1,30 @@
package com.senmesh.common.constant;
/**
* 项目环境枚举
* @author sr on 2020-05-20
*/
public enum ProjectProfileEnum {
/** 开发 **/
DEV("dev"),
/** 测试 **/
TEST("test"),
/** 测试 * */
UAT("uat"),
/** 生产 **/
PROD("prod"),
/** 福安 **/
FUAN("fuan");
private String value;
ProjectProfileEnum(String value){
this.value = value;
}
public String getValue() {
return this.value;
}
}

View File

@@ -0,0 +1,69 @@
package com.senmesh.common.constant;
import java.util.Arrays;
import java.util.Objects;
/**
* 交易账户类型常量
* @author sr on 2020-08-19
*/
public interface TradeAccountTypeConstants {
/** 交易账号类型:银行卡 **/
String TRADE_ACCOUNT_TYPE_BANK = TradeAccountTypeEnum.BANK.getType().toString();
/** 交易账号类型:子账号 **/
String TRADE_ACCOUNT_TYPE_SUB_ACCOUNT = TradeAccountTypeEnum.SUB_ACCOUNT.getType().toString();
/** 交易账号类型:支付宝账号 **/
String TRADE_ACCOUNT_TYPE_ALIPAY_ACCOUNT = TradeAccountTypeEnum.ALIPAY_ACCOUNT.getType().toString();
/** 交易账号类型:支付宝用户ID **/
String TRADE_ACCOUNT_TYPE_ALIPAY_USERID = TradeAccountTypeEnum.ALIPAY_USERID.getType().toString();
/** 交易账号类型:微信OPENID **/
String TRADE_ACCOUNT_TYPE_WECHAT_OPENID = TradeAccountTypeEnum.WECHAT_OPENID.getType().toString();
/** 交易账号类型:平台机构 **/
String TRADE_ACCOUNT_TYPE_PLATFORM_ORG = TradeAccountTypeEnum.PLATFORM_ORG.getType().toString();
/**
* 交易账号类型:其他
*/
String TRADE_ACCOUNT_TYPE_OTHER = TradeAccountTypeEnum.OTHER.getType().toString();
/**
* 帐户类型枚举
*
* @author Carlye
* @date 2021/08/17
*/
public enum TradeAccountTypeEnum{
BANK(1,"银行卡"),
SUB_ACCOUNT(2,"内部子账户"),
ALIPAY_ACCOUNT(3,"支付宝账号"),
ALIPAY_USERID(4,"支付宝用户ID"),
WECHAT_OPENID(5,"微信支付"),
PLATFORM_ORG(6,"平台机构"),
OTHER(99,"其他");
private final Integer type;
private final String desc;
TradeAccountTypeEnum(Integer type,String desc){
this.type = type;
this.desc = desc;
}
public Integer getType() {
return type;
}
public String getDesc() {
return desc;
}
public static TradeAccountTypeEnum find(Integer type){
if (Objects.isNull(type)){
return null;
}
return Arrays.stream(TradeAccountTypeEnum.values()).filter(e->e.getType().equals(type)).findFirst().orElse(null);
}
}
}

View File

@@ -0,0 +1,41 @@
package com.senmesh.common.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.senmesh.common.AlitaResult;
import com.senmesh.common.util.JsonUtils;
import com.senmesh.common.util.RequestUtils;
import com.senmesh.commonexport.service.ExportService;
import com.senmesh.usercenter.user.dto.UserDTO;
@RestController
public class TestController {
@Autowired
private ExportService exportService;
@GetMapping("anon/hostIp")
public AlitaResult<String> hostIp() {
return AlitaResult.success(RequestUtils.getHostIp());
}
@GetMapping("anon/trim")
public AlitaResult<String> gettrim(UserDTO userDTO) {
return AlitaResult.success(JsonUtils.toJsonString(userDTO));
}
@PostMapping("anon/trim")
public AlitaResult<String> posttrim(@RequestBody UserDTO userDTO) {
return AlitaResult.success(JsonUtils.toJsonString(userDTO));
}
}

View File

@@ -0,0 +1,56 @@
package com.senmesh.common.dto;
import java.io.Serializable;
import java.util.Date;
import javax.validation.constraints.NotNull;
import org.springframework.format.annotation.DateTimeFormat;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonFormat.Shape;
import com.senmesh.common.validation.Update;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
/**
* 基础dto
*
* @author sr on 2019-12-07
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
public class BaseDTO implements Serializable,IBaseDTO {
/** **/
private static final long serialVersionUID = 3305990673475531178L;
@ApiModelProperty("id")
@NotNull(message = "id不能为空", groups = {Update.class})
private Long id;
@ApiModelProperty("是否逻辑删除(0否1是)")
private Boolean deleted;
@ApiModelProperty("创建人")
private Long createBy;
@ApiModelProperty("创建时间")
// requestparam
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
// requestbody+serial
@JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
@ApiModelProperty("修改人")
private Long updateBy;
@ApiModelProperty("修改时间")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
private Long proxyBy;
}

View File

@@ -0,0 +1,41 @@
package com.senmesh.common.dto;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.senmesh.common.util.UserContextHolder;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 基础操作对象
*
* @author sr on 2020-08-26
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BaseOperateDTO implements Serializable, IOperateDTO{
/** **/
private static final long serialVersionUID = -3075506470200622050L;
/** 操作机构ID **/
@JsonIgnore
private Long operateOrgId;
/** 操作用户ID **/
@JsonIgnore
private Long operateUserId;
public Long getOperateOrgId() {
return operateOrgId == null ? UserContextHolder.getLoginOrgId() : operateOrgId;
}
public Long getOperateUserId() {
return operateUserId == null ? UserContextHolder.getLoginUserId() : operateUserId;
}
}

View File

@@ -0,0 +1,13 @@
package com.senmesh.common.dto;
import java.io.Serializable;
/**
* @author sr on 2020-04-22
*/
public class ButtonDTO implements Serializable{
/** **/
private static final long serialVersionUID = -8606784819452806185L;
}

View File

@@ -0,0 +1,27 @@
package com.senmesh.common.dto;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class CasTokenDTO implements Serializable{
/** **/
private static final long serialVersionUID = -6818144396647084889L;
private String token;
/** 当前token用户id **/
private Long userId;
/** 是否新注册 **/
private Boolean register;
}

View File

@@ -0,0 +1,37 @@
package com.senmesh.common.dto;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Builder.Default;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author sr on 2020-04-22
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ColumnDTO implements Serializable{
/** **/
private static final long serialVersionUID = 1L;
private static final int DEFAULT_WIDTH = 160;
/** 标题,如:总条数 **/
private String title;
/** 下标(同key),如:totalCount **/
private String dataIndex;
/** 属性,如:totalCount **/
private String key;
/** 宽度 **/
@Default
private int width = DEFAULT_WIDTH;
/** 对齐方式 **/
@Default
private String align = "center";
}

View File

@@ -0,0 +1,32 @@
package com.senmesh.common.dto;
import java.io.Serializable;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 展示定制的组件
*
* @author sr on 2020-04-22
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DisplayedComponentDTO<T> implements Serializable{
/** **/
private static final long serialVersionUID = 1L;
/** 消息 **/
private MessageDTO message;
/** 列配置 **/
private List<ColumnDTO> columns;
/** 展示数据 **/
private List<T> data;
/** 按钮 **/
private List<ButtonDTO> buttons;
}

View File

@@ -0,0 +1,31 @@
package com.senmesh.common.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ExceptionRecordDTO implements Serializable {
/**
* 入参json
*/
private String paramJson;
/**
* 响应json
*/
private String resultJson;
/**
* 调用接口地址
*/
private String url;
/**
* 系统 1 慧用工、2、3、4待定
*/
private String sys;
}

View File

@@ -0,0 +1,27 @@
package com.senmesh.common.dto;
import java.io.Serializable;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class ExportHeadDetailInfoDTO implements Serializable {
private static final long serialVersionUID = 2399902503017038944L;
/**
* 表头
*/
private String head;
/**
* 下拉列表
*/
private List<String> explicitList;
}

View File

@@ -0,0 +1,59 @@
package com.senmesh.common.dto;
import org.apache.commons.compress.utils.Lists;
import java.io.Serializable;
import java.util.List;
import java.util.Objects;
import cn.hutool.core.date.DateUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class ExportHeadInfoDTO implements Serializable {
private static final long serialVersionUID = -3123297330700623056L;
/**
* 文件名称
*/
private String fileName;
/**
* 表头
*/
private List<ExportHeadDetailInfoDTO> heads;
/**
* 数据列
*/
private List<List> datas;
public String getFileName() {
if (Objects.isNull(fileName)){
fileName = DateUtil.today() + "_动态模板";
}
return fileName;
}
public List<ExportHeadDetailInfoDTO> getHeads() {
if (Objects.isNull(heads)){
heads = Lists.newArrayList();
}
return heads;
}
public List<List> getDatas() {
if (Objects.isNull(datas)){
datas = Lists.newArrayList();
}
return datas;
}
}

View File

@@ -0,0 +1,12 @@
package com.senmesh.common.dto;
/**
* 基础对象
* @author sr on 2024-04-18
*/
public interface IBaseDTO {
Long getId();
}

View File

@@ -0,0 +1,23 @@
package com.senmesh.common.dto;
/**
* 展示信息
*
* @author sr on 2020-07-14
*/
public interface IDisplayed{
/**
* 是否展示
* @return
* @author sr on 2020-07-14
*/
Boolean getDisplayed();
/**
* 展示组件
* @return
* @author sr on 2020-07-14
*/
DisplayedComponentDTO<?> getDisplayedComponentDto();
}

View File

@@ -0,0 +1,26 @@
package com.senmesh.common.dto;
/**
* 操作对象
*
* @author sr on 2020-08-26
*/
public interface IOperateDTO {
/**
* 设置操作机构id
*
* @param orgId
* @author sr on 2020-08-31
*/
void setOperateOrgId(Long orgId);
/**
* 设置操作用户id
*
* @param userId
* @author sr on 2020-08-31
*/
void setOperateUserId(Long userId);
}

View File

@@ -0,0 +1,43 @@
package com.senmesh.common.dto;
import java.util.List;
/**
* 分页对象
*
* @author sr on 2020-08-26
*/
public interface IPage<T> {
/**
* 第几页
*
* @return
* @author sr on 2020-08-26
*/
Integer getPageNo();
/**
* 页宽
*
* @return
* @author sr on 2020-08-26
*/
Integer getPageSize();
/**
* 获取是否需要分页属性
*
* @return {@link Boolean}
*/
Boolean getNeedPage();
/**
* 设置分页结果
*
* @author sr on 2020-08-26
*/
void setPageResult(int totalCount, List<T> results);
}

View File

@@ -0,0 +1,28 @@
package com.senmesh.common.dto;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.Builder.Default;
/**
* @author sr on 2020-04-22
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MessageDTO implements Serializable{
/** **/
private static final long serialVersionUID = 3623225038987713421L;
/** 类型:success/info/warning/error **/
@Default
private String type = "info";
/** 内容 **/
private String content;
}

View File

@@ -0,0 +1,24 @@
package com.senmesh.common.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
/**
* 机构基础
*
* @author sr on 2019-12-22
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@SuperBuilder
public class OrgBaseDTO extends BaseDTO {
/** **/
private static final long serialVersionUID = -2595043832455614748L;
private Long orgId;
}

View File

@@ -0,0 +1,98 @@
package com.senmesh.common.dto;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.senmesh.tkmybatis.pojo.Page;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
import java.util.Optional;
/**
* 分页查询对象
*
* @author sr on 2020-08-03
*/
@AllArgsConstructor
@NoArgsConstructor
public class PageQueryDTO<T> extends BaseOperateDTO implements Serializable, IPage<T> {
/**
*
**/
private static final long serialVersionUID = -6370476082571087349L;
/**
* 第几页
**/
private Integer pageNo = 1;
/**
* 页宽
**/
private Integer pageSize = 20;
/**
* 是否需要分页
**/
private Boolean needPage = Boolean.TRUE;
/**
* 分页结果
**/
@JsonIgnore
private Page<T> pageResult;
@Override
public Integer getPageNo() {
return Optional.ofNullable(pageNo).orElse(1);
}
@Override
public Integer getPageSize() {
return Optional.ofNullable(pageSize).orElse(20);
}
@Override
public Boolean getNeedPage() {
return Optional.ofNullable(this.needPage).orElse(Boolean.TRUE);
}
@Override
public void setPageResult(int totalCount, List<T> results) {
pageResult = new Page<T>(getPageNo(), getPageSize());
pageResult.setPageResult(totalCount, results);
}
public void setPageNo(Integer pageNo) {
this.pageNo = pageNo;
}
public void setPageSize(Integer pageSize) {
if (pageSize != null && pageSize >1000) {
this.pageSize = 1000;
} else {
this.pageSize = pageSize;
}
}
public void setNeedPage(Boolean needPage) {
this.needPage = needPage;
}
public Page<T> getPageResult() {
return pageResult;
}
public void setPageResult(Page<T> pageResult) {
this.pageResult = pageResult;
}
public PageQueryDTO<T> disablePage() {
this.setNeedPage(Boolean.FALSE);
return this;
}
public Integer getStartPage() {
return (getPageNo() - 1) * getPageSize();
}
}

View File

@@ -0,0 +1,156 @@
package com.senmesh.common.easyexcel;
import com.google.common.collect.Maps;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.AbstractCellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.senmesh.common.dto.ExportHeadDetailInfoDTO;
import com.senmesh.common.dto.ExportHeadInfoDTO;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Name;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFDataValidation;
import java.awt.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import cn.hutool.core.collection.CollUtil;
public class DynamicExportTemplateCellWriteHandler extends AbstractCellWriteHandler {
private Map<Integer, ExportHeadDetailInfoDTO> exportHeadIndexMap = null;
private Integer hiddenSheetIndex = 1;
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
super.afterCellDispose(writeSheetHolder, writeTableHolder, cellDataList, cell, head, relativeRowIndex, isHead);
int rowIndex = cell.getRowIndex();
int columnIndex = cell.getColumnIndex();
Workbook workbook = writeSheetHolder.getParentWriteWorkbookHolder().getWorkbook();
Sheet sheet = writeSheetHolder.getSheet();
if (rowIndex == 0) {
Row row = cell.getRow();
row.setHeight((short) (33 * 20));
ExportHeadInfoDTO exportInfo = (ExportHeadInfoDTO) ImportDataContext.get("exportInfo");
XSSFCellStyle cellStyle = (XSSFCellStyle) workbook.createCellStyle();
cellStyle.setBorderBottom(BorderStyle.THIN); //下边框
cellStyle.setBottomBorderColor(IndexedColors.BLACK.index);
cellStyle.setBorderLeft(BorderStyle.THIN);//左边框
cellStyle.setLeftBorderColor(IndexedColors.BLACK.index);
cellStyle.setBorderTop(BorderStyle.THIN);//上边框
cellStyle.setTopBorderColor(IndexedColors.BLACK.index);
cellStyle.setBorderRight(BorderStyle.THIN);//右边框
cellStyle.setRightBorderColor(IndexedColors.BLACK.index);
cellStyle.setAlignment(HorizontalAlignment.CENTER);
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
Color color = new Color(91, 155, 213);
cellStyle.setFillForegroundColor(new XSSFColor(color,null));
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
Font font = workbook.createFont();
cellStyle.setFont(font);
font.setFontName("Calibri");
font.setColor(HSSFColor.HSSFColorPredefined.WHITE.getIndex());
cell.setCellStyle(cellStyle);
if (Objects.isNull(exportHeadIndexMap)) {
List<ExportHeadDetailInfoDTO> heads = exportInfo.getHeads();
exportHeadIndexMap = Maps.newHashMap();
for (int i = 0; i < heads.size(); i++) {
ExportHeadDetailInfoDTO exportHead = heads.get(i);
exportHeadIndexMap.put(i, exportHead);
}
}
ExportHeadDetailInfoDTO exportHeadDetailInfoDTO = exportHeadIndexMap.get(columnIndex);
String name;
if (Objects.isNull(exportHeadDetailInfoDTO)) {
name = cell.getStringCellValue();
} else {
name = exportHeadDetailInfoDTO.getHead();
}
int length = ((name.getBytes(StandardCharsets.UTF_8).length + cell.toString().length()) * 3) / 5 + 5;
sheet.setColumnWidth(columnIndex, length * 290);
List<String> explicitList = Objects.isNull(exportHeadDetailInfoDTO) ? null : exportHeadDetailInfoDTO.getExplicitList();
// 设置下拉属性
// if (CollUtil.isNotEmpty(explicitList)) {
// DataValidationHelper helper = sheet.getDataValidationHelper();
// DataValidationConstraint constraint = helper.createExplicitListConstraint(explicitList.toArray(new String[]{}));
// //设置生效的起始行、终止行、起始列、终止列
// CellRangeAddressList cellAddressList = new CellRangeAddressList(1,
// 65535, columnIndex, columnIndex);
// DataValidation validation = helper.createValidation(constraint, cellAddressList);
// //适配xls和xlsx
// if (validation instanceof HSSFDataValidation) {
// validation.setSuppressDropDownArrow(false);
// } else {
// validation.setSuppressDropDownArrow(true);
// validation.setShowErrorBox(true);
// }
// sheet.addValidationData(validation);
// }
if (CollUtil.isNotEmpty(explicitList)){
String hiddenName = "hidden" + hiddenSheetIndex;
//1.创建隐藏的sheet页。 起个名字吧!叫"hidden"!
Sheet hiddenSheet = workbook.createSheet(hiddenName);
//2.循环赋值(为了防止下拉框的行数与隐藏域的行数相对应,将隐藏域加到结束行之后)
for (int i = 0; i < explicitList.size(); i++) {
hiddenSheet.createRow(65535 + i).createCell(columnIndex).setCellValue(explicitList.get(i));
}
Name category1Name = workbook.createName();
category1Name.setNameName(hiddenName);
//3 A1:A代表隐藏域创建第N列createCell(N)时。以A1列开始A行数据获取下拉数组
category1Name.setRefersToFormula(hiddenName + "!A1:A" + (explicitList.size() + 65535));
//
DataValidationHelper helper = sheet.getDataValidationHelper();
DataValidationConstraint constraint = helper.createFormulaListConstraint(hiddenName);
CellRangeAddressList addressList = new CellRangeAddressList(1, 65535, columnIndex, columnIndex);
DataValidation dataValidation = helper.createValidation(constraint, addressList);
if (dataValidation instanceof XSSFDataValidation) {
// 数据校验
dataValidation.setSuppressDropDownArrow(true);
dataValidation.setShowErrorBox(true);
} else {
dataValidation.setSuppressDropDownArrow(false);
}
// 作用在目标sheet上
sheet.addValidationData(dataValidation);
// 设置hiddenSheet隐藏
workbook.setSheetHidden(hiddenSheetIndex, true);
hiddenSheetIndex++;
}
}
}
}

View File

@@ -0,0 +1,77 @@
package com.senmesh.common.easyexcel;
import com.google.common.collect.Lists;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.senmesh.common.dto.ExportHeadDetailInfoDTO;
import com.senmesh.common.dto.ExportHeadInfoDTO;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
public class ExcelUtil {
private ExcelUtil() {
}
/**
* 动态导出excel模板
*
* @param reqDto 点播dto
*/
public static void dynamicExportTemplate(ExportHeadInfoDTO reqDto) {
if (CollUtil.isEmpty(reqDto.getHeads())) {
return;
}
ImportDataContext.set("exportInfo", reqDto);
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletResponse response = attr.getResponse();
if (Objects.isNull(response)) {
return;
}
String fileName = reqDto.getFileName() + ".xlsx";
response.setContentType("application/vnd.ms-excel;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
String fileNamePrefix = StrUtil.subBefore(fileName, ".", true);
String fileNameSuffix = StrUtil.subAfter(fileName, ".", true);
try {
String fileNamePrefix2 = URLEncoder.encode(fileNamePrefix, "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-Disposition", "attachment;" + fileNamePrefix2 + "." + fileNameSuffix);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new IllegalArgumentException("下载文件异常");
}
response.addHeader("Param", "no-cache");
response.addHeader("Cache-Control", "no-cache");
try (OutputStream out = response.getOutputStream();) {
ExcelWriter writer = EasyExcel.write(out).registerWriteHandler(new DynamicExportTemplateCellWriteHandler()).build();
List<List> objects = Lists.newArrayList();
objects.add(reqDto.getHeads().stream().map(ExportHeadDetailInfoDTO::getHead).collect(Collectors.toList()));
objects.addAll(reqDto.getDatas());
writer.write(objects, EasyExcel.writerSheet("sheet").build());
writer.finish();
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,35 @@
package com.senmesh.common.easyexcel;
import com.google.common.collect.Maps;
import java.util.Map;
import java.util.Objects;
public class ImportDataContext {
public static final ThreadLocal<Map<String, Object>> THREAD_LOCAL_MAP = new ThreadLocal<>();
public static Object get(String key) {
Map<String, Object> stringObjectMap = THREAD_LOCAL_MAP.get();
if (Objects.isNull(stringObjectMap)) {
THREAD_LOCAL_MAP.set(Maps.newHashMap());
return null;
}
return stringObjectMap.get(key);
}
public static void set(String key,Object value) {
Map<String, Object> stringObjectMap = THREAD_LOCAL_MAP.get();
if (Objects.isNull(stringObjectMap)) {
THREAD_LOCAL_MAP.set(Maps.newHashMap());
}
THREAD_LOCAL_MAP.get().put(key,value);
}
public static void putAll(Map<String, Object> extraInfoMap){
Map<String, Object> stringObjectMap = THREAD_LOCAL_MAP.get();
if (Objects.isNull(stringObjectMap)) {
THREAD_LOCAL_MAP.set(Maps.newHashMap());
}
THREAD_LOCAL_MAP.get().putAll(extraInfoMap);
}
}

View File

@@ -0,0 +1,64 @@
package com.senmesh.common.entity;
import java.io.Serializable;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.senmesh.common.dto.IBaseDTO;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
public abstract class BaseEntity implements Serializable, Cloneable, IBaseDTO {
private static final long serialVersionUID = -723338960662087915L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 是否逻辑删除(0否1是)
*/
@TableField(value = "deleted", fill = FieldFill.INSERT)
@Builder.Default
private Boolean deleted = Boolean.FALSE;
/**
* 创建人
*/
@TableField(value = "create_by", fill = FieldFill.INSERT)
private Long createBy;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Date createTime;
/**
* 修改人
*/
@TableField(value = "update_by", fill = FieldFill.UPDATE)
private Long updateBy;
/**
* 修改时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField(value = "update_time", fill = FieldFill.UPDATE)
private Date updateTime;
/**
* 代理人
*/
private Long proxyBy;
}

View File

@@ -0,0 +1,27 @@
package com.senmesh.common.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
/**
* 机构基础实体
* @author sr on 2019-10-19
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
public class OrgBaseEntity extends BaseEntity {
/** **/
private static final long serialVersionUID = 2559571969035017003L;
/** 机构id **/
private Long orgId;
}

View File

@@ -0,0 +1,30 @@
package com.senmesh.common.exception;
/**
* 项目所有自定义异常父类
*
* @author guhong
*/
public class AlitaException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 3121871576733025786L;
public AlitaException() {}
public AlitaException(String message) {
super(message);
}
public AlitaException(String message, Throwable cause) {
super(message, cause);
}
public AlitaException(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,30 @@
package com.senmesh.common.exception;
/**
* 业务异常
*
* @author guhong
* @date 2019/8/19
*/
public class BusinessException extends AlitaException {
/**
*
*/
private static final long serialVersionUID = -3097174055942519169L;
public BusinessException() {}
public BusinessException(String message) {
super(message);
}
public BusinessException(String message, Throwable cause) {
super(message, cause);
}
public BusinessException(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,24 @@
package com.senmesh.common.exception;
import com.senmesh.common.AlitaResult;
import com.senmesh.common.dto.CasTokenDTO;
/**
* 更新token
* @author sr on 2021-07-05
*/
public class ChangeTokenException extends WithResultException{
/** **/
private static final long serialVersionUID = -8897274199463229506L;
public ChangeTokenException(CasTokenDTO casTokenDTO) {
super(AlitaResult.changeToken(casTokenDTO));
}
public CasTokenDTO getCasTokenDTO(){
return (CasTokenDTO) getResult().getErrorData();
}
}

View File

@@ -0,0 +1,24 @@
package com.senmesh.common.exception;
import com.senmesh.common.exception.util.DevopsUtils;
/**
* 运维业务异常
* @author sr on 2022-03-01
*/
public class DevopsException extends BusinessException{
/** **/
private static final long serialVersionUID = 1L;
public DevopsException(String message) {
super(message);
DevopsUtils.deal(message);
}
public DevopsException(String message, Throwable cause) {
super(message, cause);
DevopsUtils.deal(message);
}
}

View File

@@ -0,0 +1,24 @@
package com.senmesh.common.exception;
/**
* 已存在业务异常
* @author sr on 2022-03-01
*/
public class ExistException extends BusinessException{
/** **/
private static final long serialVersionUID = 1L;
public ExistException() {
super();
}
public ExistException(String message) {
super(message);
}
public ExistException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,7 @@
package com.senmesh.common.exception;
public interface IDevopsProvider {
void deal(String msg);
}

View File

@@ -0,0 +1,26 @@
package com.senmesh.common.exception;
/**
* 用户未登录异常
*
* @author guhong
* @date 2019/8/19
*/
public class NoneLoginException extends AlitaException {
public static final String ERROR_MSG = "用户未登录";
/**
*
*/
private static final long serialVersionUID = -7013134475760472324L;
public NoneLoginException(String msg, Throwable t) {
super(msg, t);
}
public NoneLoginException() {
super(ERROR_MSG);
}
}

View File

@@ -0,0 +1,30 @@
package com.senmesh.common.exception;
import com.senmesh.common.AlitaResult;
/**
* 更新token
* @author sr on 2021-07-05
*/
public class WithResultException extends AlitaException{
/** **/
private static final long serialVersionUID = -8897274199463229506L;
private AlitaResult<?> result;
public WithResultException(AlitaResult<?> result) {
super(result.getMsg());
this.result = result;
}
public WithResultException(AlitaResult<?> result, Throwable cause) {
super(result.getMsg(), cause);
this.result = result;
}
public AlitaResult<?> getResult(){
return result;
}
}

View File

@@ -0,0 +1,33 @@
package com.senmesh.common.exception.controller;
import com.senmesh.common.exception.dao.ExceptionLogMapper;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 异常日志查看
*
* @author on 2019-11-05
*/
@RestController
@RequestMapping("/anon/exception")
@Api(tags = "异常日志查看")
public class ExceptionLogController {
@Autowired
private ExceptionLogMapper exceptionLogMapper;
@GetMapping("/{id}")
public String getExceptionMsg(@PathVariable Long id) {
try {
return exceptionLogMapper.selectById(id).getMsg();
} catch (Exception e) {
return "未找到对应id错误";
}
}
}

View File

@@ -0,0 +1,13 @@
package com.senmesh.common.exception.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.senmesh.common.exception.entity.ExceptionLog;
/**
* 异常日志
*
* @author on 2019-11-05
*/
public interface ExceptionLogMapper extends BaseMapper<ExceptionLog> {
}

View File

@@ -0,0 +1,41 @@
package com.senmesh.common.exception.entity;
import java.io.Serializable;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 错误日志
* @author sr on 2019-10-28
*/
@TableName("xs_exception_log")
@Data
@NoArgsConstructor
public class ExceptionLog implements Serializable{
/** **/
private static final long serialVersionUID = 3730091070919812549L;
/** 主键 **/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/** 创建时间 **/
private Date createTime;
/** 错误信息 **/
private String msg;
public ExceptionLog(Date createTime, String msg) {
super();
this.createTime = createTime;
this.msg = msg;
}
}

View File

@@ -0,0 +1,188 @@
package com.senmesh.common.exception.handle;
import com.senmesh.common.util.EnvironmentUtils;
import java.util.List;
import java.util.Set;
import java.util.StringJoiner;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import com.senmesh.common.AlitaResult;
import com.senmesh.common.constant.CommonConstants;
import com.senmesh.common.exception.BusinessException;
import com.senmesh.common.exception.NoneLoginException;
import com.senmesh.common.exception.WithResultException;
import com.senmesh.common.log.dto.ExceptionLogDTO;
import com.senmesh.common.log.util.LogUtils;
import com.senmesh.common.util.SpringContextHolder;
import com.senmesh.common.util.TracerUtils;
/**
* 全局异常处理
*
* @author guhong
* @date 2019/8/19
*/
@RestControllerAdvice
public class GlobalControllerExceptionHandler {
private static final Logger LOGGER = LoggerFactory
.getLogger(GlobalControllerExceptionHandler.class);
@Value("${spring.application.name:}")
private String applicationName;
/**
* 业务异常
*
* @param ex
*/
@ExceptionHandler(value = {BusinessException.class})
public AlitaResult<String> handleBusinessException(BusinessException ex) {
String traceId = TracerUtils.getTraceId();
String msg;
if (StringUtils.isNotBlank(ex.getMessage()) && ex.getMessage().contains(traceId)) {
msg = ex.getMessage();
}else {
msg = String.format("[%s]操作失败:%s", traceId, ex.getMessage());
}
LOGGER.debug(msg, ex);
AlitaResult<String> alitaResult = AlitaResult.error(AlitaResult.BUSINESS_ERROR_CODE, msg);
alitaResult.setRequestId(traceId);
return alitaResult;
}
/**
* 处理未登录异常
*
* @param ex
*/
@ExceptionHandler(value = {NoneLoginException.class})
public AlitaResult<String> handleNoneLoginException(NoneLoginException ex) {
AlitaResult<String> alitaResult = AlitaResult.unLogin();
alitaResult.setRequestId(TracerUtils.getTraceId());
return alitaResult;
}
/**
* 处理更换token
*
* @param ex
*/
@ExceptionHandler(value = {WithResultException.class})
public AlitaResult<?> handleChangeTokenException(WithResultException ex) {
AlitaResult<?> result = ex.getResult();
result.setRequestId(TracerUtils.getTraceId());
return result;
}
/**
* 处理校验异常
*
* @param ex
*/
@ExceptionHandler(value = {
MethodArgumentNotValidException.class,
BindException.class})
public AlitaResult<String> handleValidationException(Exception ex) {
BindingResult result;
if (ex instanceof MethodArgumentNotValidException) {
result = ((MethodArgumentNotValidException) ex).getBindingResult();
} else {
result = ((BindException) ex).getBindingResult();
}
if (!result.hasErrors()) {
return AlitaResult.error("操作失败");
}
StringJoiner joiner = new StringJoiner(",");
List<ObjectError> errors = result.getAllErrors();
errors.forEach(error -> {
if (error instanceof FieldError) {
joiner.add(((FieldError) error).getField() + "-" + error.getDefaultMessage());
} else {
joiner.add(error.getDefaultMessage());
}
});
String msg = String.format("数据异常:%s", joiner.toString());
LOGGER.error(msg);
AlitaResult<String> alitaResult = AlitaResult.error(AlitaResult.VALIDATION_ERROR_CODE, msg);
alitaResult.setRequestId(TracerUtils.getTraceId());
return alitaResult;
}
/**
* 处理未知的错误
*
* @param ex
*/
@ExceptionHandler(value = {ConstraintViolationException.class})
@Transactional(rollbackFor = RuntimeException.class)
public AlitaResult<String> handleConstraintViolationException(ConstraintViolationException ex) {
Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
StringJoiner joiner = new StringJoiner(CommonConstants.COMMA);
constraintViolations.stream().forEach(error -> joiner.add(error.getMessage()));
String msg = String.format("数据异常:%s", joiner.toString());
LOGGER.error(msg);
AlitaResult<String> alitaResult = AlitaResult.error(AlitaResult.VALIDATION_ERROR_CODE, msg);
alitaResult.setRequestId(TracerUtils.getTraceId());
return alitaResult;
}
/**
* 处理未知的错误
*
* @param ex
*/
@ExceptionHandler(value = {Exception.class})
@Transactional(rollbackFor = RuntimeException.class)
public AlitaResult<String> handleUnknownException(Exception ex) {
String msg = null;
if (ex instanceof HttpRequestMethodNotSupportedException) {
msg = "请求错误:" + ((HttpRequestMethodNotSupportedException) ex).getSupportedMethods()[0]
+ SpringContextHolder.getRequest().getRequestURI();
} else {
LOGGER.error("",ex);
ExceptionLogDTO exceptionLogDTO = ExceptionLogDTO.builder().traceId(TracerUtils.getTraceId())
.msg(ExceptionUtils.getStackTrace(ex)).build();
LogUtils.log(exceptionLogDTO);
msg = String.format("系统异常[%s#%s],请稍后重试.",
EnvironmentUtils.getSystemCode(), exceptionLogDTO.getErrNo()
);
LOGGER.error("系统异常,错误号:{}", exceptionLogDTO.getErrNo());
}
AlitaResult<String> alitaResult = AlitaResult.error(msg);
alitaResult.setRequestId(TracerUtils.getTraceId());
return alitaResult;
}
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(String.class, new StringTrimmerEditor(" \t\r\n\f", true));
}
}

View File

@@ -0,0 +1,133 @@
package com.senmesh.common.exception.util;
import com.google.common.base.Supplier;
import com.senmesh.common.constant.CommonConstants;
import com.senmesh.common.exception.BusinessException;
import com.senmesh.common.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import java.util.Collection;
import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
/**
* 断言
*
* @author sr on 2020-09-02
*/
@Slf4j
public class Assert {
private Assert() {
}
private static void dealLog(String message, Object... logData) {
if (logData.length > 0) {
log.info(new StringBuilder().append(message).append(CommonConstants.COLON)
.append(JsonUtils.toJsonString(logData)).toString());
}
}
/**
* true正常,fasle抛BusinessException
*
* @param expression
* @param message
* @author sr on 2020-09-02
*/
public static void isTrue(boolean expression, String message, Object... logData) {
if (!expression) {
dealLog(message, logData);
throw new BusinessException(message);
}
}
/**
* true正常,fasle抛BusinessException
*
* @param expression 表达式
* @param message 消息
*/
public static void isTrue(boolean expression, Supplier<String> message) {
if (!expression) {
throw new BusinessException(message.get());
}
}
/**
* true正常,fasle抛指定异常
* @param expression
* @param e
* @author sr on 2021-06-18
*/
public static void isTrue(boolean expression, RuntimeException e) {
if (!expression) {
throw e;
}
}
/**
* null正常,notNull抛BusinessException
*
* @param object
* @param message
* @author sr on 2020-09-02
*/
public static void isNull(@Nullable Object object, String message, Object... logData) {
if (object != null) {
dealLog(message, logData);
throw new BusinessException(message);
}
}
/**
* notNull正常,null抛BusinessException
*
* @param object
* @param message
* @author sr on 2020-09-02
*/
public static void notNull(@Nullable Object object, String message, Object... logData) {
if (object == null) {
dealLog(message, logData);
throw new BusinessException(message);
}
}
/**
* notNull正常,null抛BusinessException
*
* @param object 对象
* @param message 消息
*/
public static void notNull(@Nullable Object object, Supplier<String> message) {
if (object == null) {
throw new BusinessException(message.get());
}
}
/**
* notBlank正常,blank抛BusinessException
*
* @param str
* @param message
* @author sr on 2021-01-06
*/
public static void notBlank(String str, String message, Object... logData) {
if (StringUtils.isBlank(str)) {
dealLog(message, logData);
throw new BusinessException(message);
}
}
public static void notEmpty(@Nullable Collection<?> collection, String message) {
if (CollectionUtils.isEmpty(collection)) {
throw new BusinessException(message);
}
}
}

View File

@@ -0,0 +1,33 @@
package com.senmesh.common.exception.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.senmesh.common.exception.IDevopsProvider;
import lombok.extern.slf4j.Slf4j;
/**
* 运维工具类
* @author sr on 2022-03-01
*/
@Component
@Slf4j
public class DevopsUtils {
private static IDevopsProvider devopsProvider;
@Autowired(required = false)
public void setDevopsProvider(IDevopsProvider devopsProvider) {
DevopsUtils.devopsProvider = devopsProvider;
}
public static void deal(String msg) {
if (devopsProvider == null) {
log.error("no devops provider, error:{}", msg);
return ;
}
devopsProvider.deal(msg);
}
}

View File

@@ -0,0 +1,48 @@
package com.senmesh.common.exception.util;
import com.senmesh.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
/**
* 异常工具类
* @author sr on 2019-10-14
*/
@Slf4j
public class ExceptionUtils {
/**
* @Description 抛异常
* @Author chenyun.huang
* @Date 2020/3/27 15:06
**/
public static void throwBusinessException(String msg) {
ExceptionUtils.throwBusinessException(true,msg);
}
/**
* 根据判断抛异常
* @param isThrow
* @param msg 异常信息
* @author sr on 2019-10-14
*/
public static void throwBusinessException(boolean isThrow, String msg) {
if (isThrow) {
throw new BusinessException(msg);
}
}
/**
* 根据判断抛异常
* @param isThrow
* @param errorMsg 异常信息
* @param logMsg 日志信息(info级)
* @author sr on 2019-12-18
*/
public static void throwBusinessException(boolean isThrow, String errorMsg, String logMsg) {
if (isThrow) {
log.info(logMsg);
throw new BusinessException(errorMsg);
}
}
}

View File

@@ -0,0 +1,22 @@
package com.senmesh.common.exception.util;
import com.senmesh.common.util.RandomUtils;
/**
* uuid工具类
* {@link RandomUtils}
* @author sr on 2019-12-10
*/
@Deprecated
public class UUIDUtils {
/**
* 生成uuid,去掉-
* @return
* @author sr on 2019-12-10
*/
public static String generateUUID() {
return RandomUtils.generateUUID();
}
}

View File

@@ -0,0 +1,60 @@
package com.senmesh.common.freemarker.constant;
/**
* @author sr on 2020-04-13
*/
public enum BusinessModelFileEnum {
/** 常量 **/
CONSTANT("Constants.java", "constant", "Constant.ftl"),
/** 控制层 **/
CONTROLLER_FILE_SUFFIX("Controller.java", "controller", "Controller.ftl"),
/** dao **/
DAO_FILE_SUFFIX("Mapper.java", "dao", "Dao.ftl"),
/** dto **/
DTO_FILE_SUFFIX("DTO.java", "dto", "DTO.ftl"),
/** operateDto **/
OPERATE_DTO_FILE_SUFFIX("OperateDTO.java", "dto", "OperateDTO.ftl"),
/** queryDto **/
QUERY_DTO_FILE_SUFFIX("QueryDTO.java", "dto", "QueryDTO.ftl"),
/** entity **/
ENTITY_FILE_SUFFIX(".java", "entity", "entity.ftl"),
/** mapper **/
MAPPER_FILE_SUFFIX("Mapper.xml", "mapper", "Mapper.ftl"),
/** mapstruct **/
MAPSTRUCT_FILE_SUFFIX("MapMapper.java", "mapstruct", "MapMapper.ftl"),
/** service **/
SERVICE_FILE_SUFFIX("Service.java", "service", "Service.ftl"),
/** serviceImpl **/
SERVICE_IMPL_FILE_SUFFIX("ServiceImpl.java", "service.impl", "ServiceImpl.ftl"),
/** util **/
UTIL_FILE_SUFFIX("Utils.java", "util", "Util.ftl");
/** 生成文件后缀 **/
private String generatefileSuffix;
/** 包名 **/
private String packageName;
/** 模版文件后缀 **/
private String ftlFile;
private BusinessModelFileEnum(String fileSuffix, String packageName, String ftlFile) {
this.generatefileSuffix = fileSuffix;
this.packageName = packageName;
this.ftlFile = ftlFile;
}
public String getGeneratefileSuffix() {
return generatefileSuffix;
}
public String getPackageName() {
return packageName;
}
public String getFtlFile() {
return ftlFile;
}
}

View File

@@ -0,0 +1,11 @@
package com.senmesh.common.freemarker.constant;
/**
* @author sr on 2020-04-10
*/
public interface FreemarkerConstants {
/** 数据库表名前缀 **/
String TABLE_PREFIX = "xs_";
}

View File

@@ -0,0 +1,39 @@
package com.senmesh.common.freemarker.dto;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author sr on 2020-04-10
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class BusinessModelCreateDTO implements Serializable {
/** **/
private static final long serialVersionUID = 3962743989033667188L;
/**
* 文件输出路径-绝对路径,如/work/eclipse/workspace/alita-base/common/src/main/java/com/xxx/common/freemarker/
**/
private String exportDir;
/** 包路径,如com.xxx.dict **/
private String packageName;
/** 是否创建业务路径,默认创建 **/
private Boolean createBusinessPath;
/** 数据库表名:为空,则默认xs_entityName(snake小写) **/
private String tableName;
/** 作者名 **/
private String author;
/** 实体名,如Dict **/
private String entityName;
/** 实体名描述,如数据字典 **/
private String entityNameDescription;
}

View File

@@ -0,0 +1,88 @@
package com.senmesh.common.freemarker.util;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import com.senmesh.common.constant.CommonConstants;
import com.senmesh.common.freemarker.constant.BusinessModelFileEnum;
import com.senmesh.common.freemarker.constant.FreemarkerConstants;
import com.senmesh.common.freemarker.dto.BusinessModelCreateDTO;
import com.senmesh.common.util.StrUtils;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
/**
* @author sr on 2020-04-13
*/
@Slf4j
public class CodeGenerateUtils {
public static void generateModelFile(BusinessModelCreateDTO businessModelCreateDto) {
for (BusinessModelFileEnum businessModelFileEnum : BusinessModelFileEnum.values()) {
generateModelFile(businessModelCreateDto, businessModelFileEnum);
}
}
public static boolean generateModelFile(BusinessModelCreateDTO businessModelCreateDto,
BusinessModelFileEnum businessModelFileEnum) {
// 文件输出路径/包名路径/实体名+文件后缀
String entityName = businessModelCreateDto.getEntityName();
String entityNameLowerCase = StrUtils.toLowerCamel(entityName);
String entityNameSnake = StrUtils.toSnake(entityNameLowerCase);
String packageName = businessModelCreateDto.getPackageName();
String tableName = businessModelCreateDto.getTableName();
String path = String.join(StringUtils.EMPTY,
packageNameToPath(businessModelFileEnum.getPackageName()), File.separator,
entityName, businessModelFileEnum.getGeneratefileSuffix());
if (!Boolean.FALSE.equals(businessModelCreateDto.getCreateBusinessPath())) {
path = String.join(StringUtils.EMPTY, entityName.toLowerCase(), File.separator, path);
packageName = String.join(CommonConstants.POINT, packageName, entityName.toLowerCase());
}
final String templateName = businessModelFileEnum.getFtlFile();
File file = new File(businessModelCreateDto.getExportDir(), path);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
Map<String, Object> dataMap = new HashMap<>();
try {
dataMap.put("packageName", packageName);
dataMap.put("author", businessModelCreateDto.getAuthor());
dataMap.put("entityName", entityName);
dataMap.put("entityNameLowerCamel", entityNameLowerCase);
dataMap.put("entityNameSnake", entityNameSnake);
dataMap.put("entityNameDescription", businessModelCreateDto.getEntityNameDescription());
dataMap.put("tableName",
StringUtils.isBlank(tableName) ? FreemarkerConstants.TABLE_PREFIX + entityNameSnake
: tableName);
generateFileByTemplate(templateName, file, dataMap);
} catch (Exception e) {
e.printStackTrace();
log.info("generateFile fail:{}", e.getMessage());
return false;
}
log.info("generateFile suc:{}", file.getPath());
return true;
}
public static void generateFileByTemplate(final String templateName, File file,
Map<String, Object> dataMap) throws Exception {
Template template = FreeMarkerTemplateUtils.getTemplate(templateName);
FileOutputStream fos = new FileOutputStream(file);
Writer out = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"), 10240);
template.process(dataMap, out);
}
public static String packageNameToPath(String packageName) {
return packageName.replace('.', File.separatorChar);
}
}

View File

@@ -0,0 +1,67 @@
package com.senmesh.common.freemarker.util;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Map;
import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.NullCacheStorage;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import lombok.extern.slf4j.Slf4j;
/**
* @author sr on 2020-04-13
*/
@Slf4j
public class FreeMarkerTemplateUtils {
private FreeMarkerTemplateUtils() {}
private static final Configuration CONFIGURATION = new Configuration(Configuration.VERSION_2_3_22);
static {
//这里比较重要,用来指定加载模板所在的路径
CONFIGURATION
.setTemplateLoader(new ClassTemplateLoader(FreeMarkerTemplateUtils.class, "/ftls"));
CONFIGURATION.setDefaultEncoding("UTF-8");
CONFIGURATION.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
CONFIGURATION.setCacheStorage(NullCacheStorage.INSTANCE);
CONFIGURATION.setClassicCompatible(true);
}
public static Template getTemplate(String templateName) throws IOException {
try {
return CONFIGURATION.getTemplate(templateName);
} catch (IOException e) {
throw e;
}
}
/**
* 字符串模版占位符替换
* @param templateStr
* @param params
* @return
* @author sr on 2020-12-21
*/
public static String formatString(String templateStr, Map<String, Object> params) {
try {
Template template = new Template("formatString", templateStr, FreeMarkerTemplateUtils.CONFIGURATION);
StringWriter result = new StringWriter();
template.process(params, result);
return result.toString();
} catch (IOException | TemplateException e) {
log.error("内容占位符替换失败:{}", e.getMessage());
}
return null;
}
public static void clearCache() {
CONFIGURATION.clearTemplateCache();
}
}

View File

@@ -0,0 +1,38 @@
package com.senmesh.common.function;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
@FunctionalInterface
public interface TransactionAfterCommit {
void afterCommit();
/**
* 事务提交后的回调操作
*
* @param transactionAfterCommit 事务提交后
*/
static void doSomeThingAfterCommit(TransactionAfterCommit transactionAfterCommit) {
TransactionSynchronizationManager
.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
transactionAfterCommit.afterCommit();
}
});
}
static void doSomeThingAfterCompletion(TransactionAfterCommit transactionAfterCommit) {
TransactionSynchronizationManager
.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCompletion(int status) {
transactionAfterCommit.afterCommit();
}
});
}
}

Some files were not shown because too many files have changed in this diff Show More