feat: 代码一键生成类的引入

代码一键生成类的引入代码一键生成类的引入
This commit is contained in:
yangjiyu
2022-11-23 15:48:38 +08:00
parent 459b9be347
commit ad63d614cc
28 changed files with 4736 additions and 0 deletions
@@ -0,0 +1,178 @@
package com.aos.element.common.constant;
import com.aos.element.basic.basic.constant.ConfigDefaultValue;
import com.aos.element.basic.common.util.JustOnceLogger;
import com.aos.starter.core.util.SystemUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.experimental.UtilityClass;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 系统常量</p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.12.26 21:40
* @since 1.0.0
*/
@UtilityClass
public final class App {
/** 用于判断是否为 agent service 应用 */
public static final String IS_AGENT_SERVICE = "IS_AGENT_SERVICE";
/** FRAMEWORK_VERSION */
public static final String FRAMEWORK_VERSION_PREFIX = "V5_";
/** 基础包 */
public static final String BASE_PACKAGES = ConfigDefaultValue.BASE_PACKAGES;
/** 启动标识, 所有项目只能使用 FkhApplication 启动 */
public static final String START_FKH_APPLICATION = "start_fkh_application";
/** 依赖的 library */
public static final String LIBRARY_NAME = "used.librarys";
/** server.sh 中的启动参数, 用于获取配置文件路径 */
public static final String APP_CONFIG_PATH = "config.path";
/** 应用类型 {@link org.springframework.boot.WebApplicationType} */
public static final String APP_TYPE = "app.type";
/**
* 系统自定义应用类型, 比 {@link org.springframework.boot.WebApplicationType}
* 多了 SERVICE 类型 (com.fkhwl.starter.launcher.enums.ApplicationType)
*/
public static final String APPLICATION_TYPE = "APPLICATION_TYPE";
/** 启动方式, 用于区分是否通过 server.sh 脚本启动 */
public static final String START_TYPE = "start.type";
/** 通过 server.sh 启动的类型, 用于区分本地开发和服务端运行 */
public static final String START_SHELL = "shell";
/** 单元测试启动 */
public static final String START_JUNIT = "junit";
/** 本地开发时 idea 启动 */
public static final String START_IDEA = "idea";
/** rest 服务启动完成后将 url 写入到环境变量中, 用于其他组件获取此信息 */
public static final String START_URL = "start_url";
/** 用于打印 bean 信息 */
public static final String DEBUG_MODEL = "debug";
/** 以下是环境标识 */
public static final String ENV_LOCAL = "local";
/** ENV_DEV */
public static final String ENV_DEV = "dev";
/** ENV_TEST */
public static final String ENV_TEST = "test";
/** ENV_PREV */
public static final String ENV_PREV = "prev";
/** ENV_PROD */
public static final String ENV_PROD = "prod";
/** maven 三要素, 会从中获取应用名, 应用版本(不需要手动配置, 应用打包时会自动创建) */
public static final String APP_POM_PROP_NAME = "pom.properties";
/** 由 fkh-assist-maven-plugin 自动生成 */
public static final String APP_BULID_INFO_FILE_NAME = "build-info.properties";
/** GIT_CONFIG_FILE_NAME */
public static final String GIT_CONFIG_FILE_NAME = "git.properties";
/** WINDOWS_DEFAULT_USER_NAME */
private static final String WINDOWS_DEFAULT_USER_NAME = "Administrator";
/**
* <p>Company: 成都返空汇网络技术有限公司 </p>
* <p>Description: </p>
*
* @author dong4j
* @version 1.0.0
* @email "mailto:dongshijie@fkhwl.com"
* @date 2021.01.20 01:43
* @since 1.7.1
*/
@UtilityClass
public static final class BuildInfo {
/** VERSION */
public static final String VERSION = "build.version";
/** TIME */
public static final String TIME = "build.time";
/** USER_NAME */
public static final String USER_NAME = "build.user.name";
}
/**
* <p>Company: 成都返空汇网络技术有限公司 </p>
* <p>Description: </p>
*
* @author dong4j
* @version 1.0.0
* @email "mailto:dongshijie@fkhwl.com"
* @date 2021.01.20 01:50
* @since 1.7.1
*/
@UtilityClass
public static final class GitInfo {
/** VERSION */
public static final String BRANCH = "git.branch";
/** BUILD_VERSION */
public static final String BUILD_VERSION = "git.build.version";
/** 最后提交时间 */
public static final String BUILD_TIME = "git.build.time";
/** COMMIT_TIME */
public static final String COMMIT_TIME = "git.commit.time";
/** USER_NAME */
public static final String BUILD_USER_NAME = "git.build.user.name";
/** COMMIT_USER_NAME */
public static final String COMMIT_USER_NAME = "git.commit.user.name";
/** COMMIT_MESSAGE */
public static final String COMMIT_MESSAGE = "git.commit.message.short";
}
/**
* <p>Company: 成都返空汇网络技术有限公司 </p>
* <p>Description: 组件名常量 </p>
*
* @author dong4j
* @version 1.0.0
* @email "mailto:dongshijie@fkhwl.com"
* @date 2021.01.16 02:32
* @since 1.7.1
*/
@UtilityClass
public static class Components {
/** FKH_REST_SPRING_BOOT */
public static final String FKH_REST_SPRING_BOOT = "fkh-rest-spring-boot";
/** FKH_AGENT_SPRING_BOOT */
public static final String FKH_AGENT_SPRING_BOOT = "fkh-agent-spring-boot";
}
/**
* 本地开发时, 优先从 JVM 环境变量中读取 {@link SystemUtils#USER_NAMESPACE_VALUE}, 然后是 user.name,
* 如果 {@link SystemUtils#USER_NAME} 是 {@link App#WINDOWS_DEFAULT_USER_NAME}, 则读取系统环境变量 FKH_NAME_SPACE).
* 如果通过 shell 启动, 会自动设置 FKH_NAME_SPACE 为传入的 env 参数, 不会会加上 fkh- 前缀, 最终找到 fkh-{env} 的 nacos namespace.
*/
public static final String FKH_NAME_SPACE;
static {
// JVM 参数 user.namespace 优先级最高, 可通过 System.setProperty(SystemUtils.USER_NAMESPACE, "xxxx") 或 JVM 参数设置
String currentEnv = SystemUtils.USER_NAMESPACE_VALUE;
// 第二优先级是 FKH_NAME_SPACE
if (StringUtils.isBlank(currentEnv)) {
currentEnv = StringUtils.isBlank(SystemUtils.getProperty("FKH_NAME_SPACE"))
? StringPool.EMPTY
: SystemUtils.getProperty("FKH_NAME_SPACE");
}
// 第三优先级是 user.name, 如果在 windows 未设置计算机名, 此名称将是 Administrator
currentEnv = StringUtils.isBlank(currentEnv)
? SystemUtils.USER_NAME
: currentEnv;
// 如果是 Administrator 则获取 FKH_NAME_SPACE
if (WINDOWS_DEFAULT_USER_NAME.equalsIgnoreCase(currentEnv)) {
JustOnceLogger.printOnce(App.class.getName(), "请配置环境变量 「FKH_NAME_SPACE」 或修改本地的计算机名. "
+ "如果需要在本地开发时修改 namespace, 请设置 JVM 参数 「user.namespace」"
+ "或直接使用 System.setProperty(SystemUtils.USER_NAMESPACE, \"xxxx\"))");
currentEnv = "public";
}
FKH_NAME_SPACE = currentEnv;
}
}
@@ -0,0 +1,80 @@
package com.aos.starter.core.api;
import com.aos.element.basic.basic.Result;
import com.aos.element.basic.basic.annotation.BusinessLevel;
import com.aos.element.basic.basic.annotation.ModelSerial;
import com.aos.element.basic.basic.annotation.SystemLevel;
import com.aos.starter.core.CoreBundle;
import com.aos.starter.core.assertion.BaseExceptionAssert;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 通用返回结果 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.01.02 11:36
* @since 1.0.0
*/
@Getter
@AllArgsConstructor
@ModelSerial
public enum BaseCodes implements BaseExceptionAssert {
/** 成功 */
SUCCESS(Integer.parseInt(Result.SUCCESS_CODE), Result.SUCCESS_MESSAGE),
/** 默认没有数据响应 */
@SystemLevel
DEFAULT_NULL_DATA(2222, CoreBundle.message("code.default.null.data")),
/** 默认的失败响应 */
@SystemLevel
FAILURE(Integer.parseInt(Result.FAILURE_CODE), Result.FAILURE_MESSAGE),
/** 参数校验失败 */
@BusinessLevel
PARAM_VERIFY_ERROR(4100, CoreBundle.message("code.param.verify.error")),
/** 数据不存在 */
@SystemLevel
DATA_ERROR(4101, CoreBundle.message("code.data.error")),
/** 操作失败 */
@SystemLevel
OPTION_FAILURE(4102, CoreBundle.message("code.option.failure")),
/** Config error base codes */
@SystemLevel
CONFIG_ERROR(7000, CoreBundle.message("code.config.error")),
/** Server inner error base codes. */
@SystemLevel
SERVER_INNER_ERROR(5000, CoreBundle.message("code.server.inner.error")),
/** Service invoke error base codes */
@SystemLevel
SERVICE_INVOKE_ERROR(5001, CoreBundle.message("code.service.invoke.error")),
/** Agent exception */
@SystemLevel
AGENT_INVOKE_EXCEPTION(5002, CoreBundle.message("code.client.invoke.error")),
/** Agent enable exception base codes */
@SystemLevel
AGENT_DISABLE_EXCEPTION(5003, CoreBundle.message("code.agent.disable.error")),
/** Rpc error base codes */
@SystemLevel
RPC_ERROR(5004, CoreBundle.message("code.rpc.invoke.error")),
/** Gateway not fund instances error base codes */
GATEWAY_NOT_FUND_INSTANCES_ERROR(5005, CoreBundle.message("code.gateway.instances.error")),
/** 路由配置错误 */
GATEWAY_ROUTER_ERROR(5006, CoreBundle.message("code.gateway.router.error")),
/** Agent service not found error base codes */
@BusinessLevel
AGENT_SERVICE_NOT_FOUND_ERROR(5007, CoreBundle.message("code.agent.not.found.error")),
/** 服务器繁忙,请稍后重试 */
@SystemLevel
SERVER_BUSY(9998, CoreBundle.message("code.server.busy")),
/** 服务器异常,无法识别的异常,尽可能对通过判断减少未定义异常抛出 */
@SystemLevel
SERVER_ERROR(9999, CoreBundle.message("code.server.error"));
/** 返回码 */
private final Integer code;
/** 返回消息 */
private final String message;
}
@@ -0,0 +1,45 @@
package com.aos.starter.core.assertion;
import com.aos.starter.core.api.IResultCode;
import com.aos.starter.core.exception.BaseException;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 全局错误异常断言 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.12.24 12:20
* @since 1.0.0
*/
public interface BaseExceptionAssert extends IResultCode, IAssert {
/** serialVersionUID */
long serialVersionUID = 3077918845714343375L;
/**
* New exceptions base exception.
*
* @param args the args
* @return the base exception
* @since 1.0.0
*/
@Override
default BaseException newException(Object... args) {
return new BaseException(this, args, this.getMessage());
}
/**
* New exceptions base exception.
*
* @param t the t
* @param args the args
* @return the base exception
* @since 1.0.0
*/
@Override
default BaseException newException(Throwable t, Object... args) {
return new BaseException(this, args, this.getMessage(), t);
}
}
@@ -0,0 +1,228 @@
package com.aos.starter.core.exception;
import com.aos.element.basic.basic.exception.BasicException;
import com.aos.element.basic.basic.support.StrFormatter;
import com.aos.starter.core.api.BaseCodes;
import com.aos.starter.core.api.IResultCode;
import com.aos.starter.core.util.ResultCodeUtils;
import org.jetbrains.annotations.NotNull;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 基础异常类,所有自定义异常类都需要继承本类 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.11.26 23:45
* @since 1.0.0
*/
@Slf4j
@Getter
public class BaseException extends BasicException {
/** serialVersionUID */
private static final long serialVersionUID = 1L;
/** 返回码 */
protected IResultCode resultCode;
/** 异常消息参数 */
protected Object[] args;
/**
* Instantiates a new Base exception.
*
* @since 1.0.0
*/
public BaseException() {
super(BaseCodes.FAILURE.getMessage());
this.resultCode = BaseCodes.FAILURE;
}
/**
* Instantiates a new Base exception.
*
* @param msg the msg
* @since 1.0.0
*/
public BaseException(String msg) {
super(msg);
this.resultCode = BaseCodes.FAILURE;
}
/**
* Instantiates a new Base exception.
*
* @param code the code
* @param msg the msg
* @since 1.0.0
*/
public BaseException(int code, String msg) {
super(msg);
this.resultCode = new IResultCode() {
private static final long serialVersionUID = 2590640370242410124L;
@Override
public String getMessage() {
return msg;
}
@Override
public Integer getCode() {
return code;
}
};
}
public BaseException(String code, String msg) {
super(code, msg);
this.resultCode = new IResultCode() {
private static final long serialVersionUID = 2590640370242410124L;
/**
* Gets message *
*
* @return the message
* @since 1.6.0
*/
@Override
public String getMessage() {
return msg;
}
@Override
public Integer getCode() {
return ResultCodeUtils.convert(code);
}
};
}
/**
* msg 占位符替换
*
* @param msg msg
* @param args args
* @since 1.0.0
*/
public BaseException(String msg, Object... args) {
super(msg, args);
this.resultCode = BaseCodes.FAILURE;
}
/**
* Base exception
*
* @param cause cause
* @since 1.0.0
*/
public BaseException(Throwable cause) {
super(cause);
this.resultCode = BaseCodes.FAILURE;
}
/**
* Base exception
*
* @param msg msg
* @param cause cause
* @since 1.0.0
*/
public BaseException(String msg, Throwable cause) {
super(msg, cause);
this.resultCode = BaseCodes.FAILURE;
}
/**
* Instantiates a new Base exception.
*
* @param resultCode the response enum
* @since 1.0.0
*/
public BaseException(@NotNull IResultCode resultCode) {
super(resultCode.getMessage());
this.resultCode = resultCode;
}
/**
* Base exception
*
* @param resultCode result code
* @param cause cause
* @since 1.0.0
*/
public BaseException(@NotNull IResultCode resultCode, Throwable cause) {
super(resultCode.getMessage(), cause);
this.resultCode = resultCode;
}
/**
* Instantiates a new Base exception.
*
* @param code the code
* @param msg the msg
* @param cause cause
* @since 1.0.0
*/
public BaseException(int code, String msg, Throwable cause) {
super(msg, cause);
this.resultCode = new IResultCode() {
private static final long serialVersionUID = 2590640370242410124L;
@Override
public String getMessage() {
return msg;
}
@Override
public Integer getCode() {
return code;
}
};
}
/**
* Instantiates a new Base exception.
*
* @param resultCode the response enum
* @param args the args
* @param msg msg 替换占位符后的消息
* @since 1.0.0
*/
public BaseException(IResultCode resultCode, Object[] args, String msg) {
super(StrFormatter.mergeFormat(msg, args));
this.resultCode = resultCode;
this.args = args;
}
/**
* Instantiates a new Base exception.
*
* @param resultCode the response enum
* @param args the args
* @param msg msg
* @param cause the cause
* @since 1.0.0
*/
public BaseException(IResultCode resultCode, Object[] args, String msg, Throwable cause) {
super(StrFormatter.mergeFormat(msg, args), cause);
this.resultCode = resultCode;
this.args = args;
}
/**
* Get code
*
* @return the string
* @since 1.6.0
*/
@Override
public String getCode() {
return ResultCodeUtils.generateCode(this.resultCode);
}
}
@@ -0,0 +1,195 @@
package com.aos.starter.core.jackson;
import com.aos.element.basic.basic.util.Charsets;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.PrettyPrinter;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractGenericHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.util.TypeUtils;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.atomic.AtomicReference;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 分读写的 json 消息 处理器 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.12.26 21:38
* @since 1.0.0
*/
public abstract class AbstractReadWriteJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
/** DEFAULT_CHARSET */
private static final java.nio.charset.Charset DEFAULT_CHARSET = Charsets.UTF_8;
/** Write object mapper */
private final ObjectMapper writeObjectMapper;
/** Sse pretty printer */
@Nullable
private PrettyPrinter ssePrettyPrinter;
/**
* Instantiates a new Abstract read write jackson 2 http message converter.
*
* @param readObjectMapper the read object mapper
* @param writeObjectMapper the write object mapper
* @param supportedMediaType the supported media type
* @since 1.0.0
*/
protected AbstractReadWriteJackson2HttpMessageConverter(ObjectMapper readObjectMapper,
ObjectMapper writeObjectMapper,
MediaType supportedMediaType) {
this(readObjectMapper, writeObjectMapper);
this.setSupportedMediaTypes(Collections.singletonList(supportedMediaType));
this.initSsePrettyPrinter();
}
/**
* Instantiates a new Abstract read write jackson 2 http message converter.
*
* @param readObjectMapper the read object mapper
* @param writeObjectMapper the write object mapper
* @since 1.0.0
*/
protected AbstractReadWriteJackson2HttpMessageConverter(ObjectMapper readObjectMapper, ObjectMapper writeObjectMapper) {
super(readObjectMapper);
this.writeObjectMapper = writeObjectMapper;
this.initSsePrettyPrinter();
}
/**
* Init sse pretty printer
*
* @since 1.0.0
*/
private void initSsePrettyPrinter() {
this.setDefaultCharset(DEFAULT_CHARSET);
DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter();
prettyPrinter.indentObjectsWith(new DefaultIndenter(" ", "\ndata:"));
this.ssePrettyPrinter = prettyPrinter;
}
/**
* Instantiates a new Abstract read write jackson 2 http message converter.
*
* @param readObjectMapper the read object mapper
* @param writeObjectMapper the write object mapper
* @param supportedMediaTypes the supported media types
* @since 1.0.0
*/
protected AbstractReadWriteJackson2HttpMessageConverter(ObjectMapper readObjectMapper,
ObjectMapper writeObjectMapper,
MediaType... supportedMediaTypes) {
this(readObjectMapper, writeObjectMapper);
this.setSupportedMediaTypes(Arrays.asList(supportedMediaTypes));
}
/**
* Can write boolean
*
* @param clazz clazz
* @param mediaType media type
* @return the boolean
* @since 1.0.0
*/
@Override
public boolean canWrite(@NotNull Class<?> clazz, @Nullable MediaType mediaType) {
if (!this.canWrite(mediaType)) {
return false;
}
AtomicReference<Throwable> causeRef = new AtomicReference<>();
if (this.objectMapper.canSerialize(clazz, causeRef)) {
return true;
}
this.logWarningIfNecessary(clazz, causeRef.get());
return false;
}
/**
* 最终的序列化逻辑
*
* @param object object
* @param type type
* @param outputMessage output message
* @throws IOException io exception
* @throws HttpMessageNotWritableException http message not writable exception
* @see AbstractGenericHttpMessageConverter#write
* @since 1.0.0
*/
@Override
protected void writeInternal(@NotNull Object object, @Nullable Type type, @NotNull HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
MediaType contentType = outputMessage.getHeaders().getContentType();
JsonEncoding encoding = this.getJsonEncoding(contentType);
JsonGenerator generator = this.writeObjectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding);
try {
this.writePrefix(generator, object);
Object value = object;
Class<?> serializationView = null;
FilterProvider filters = null;
JavaType javaType = null;
if (object instanceof MappingJacksonValue) {
MappingJacksonValue container = (MappingJacksonValue) object;
value = container.getValue();
serializationView = container.getSerializationView();
filters = container.getFilters();
}
if (type != null && TypeUtils.isAssignable(type, value.getClass())) {
javaType = this.getJavaType(type, null);
}
ObjectWriter objectWriter = (serializationView != null
? this.writeObjectMapper.writerWithView(serializationView)
: this.writeObjectMapper.writer());
if (filters != null) {
objectWriter = objectWriter.with(filters);
}
if (javaType != null && javaType.isContainerType()) {
objectWriter = objectWriter.forType(javaType);
}
SerializationConfig config = objectWriter.getConfig();
if (contentType != null
&& contentType.isCompatibleWith(MediaType.TEXT_EVENT_STREAM)
&& config.isEnabled(SerializationFeature.INDENT_OUTPUT)) {
objectWriter = objectWriter.with(this.ssePrettyPrinter);
}
objectWriter.writeValue(generator, value);
this.writeSuffix(generator, object);
generator.flush();
} catch (InvalidDefinitionException ex) {
throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);
} catch (JsonProcessingException ex) {
throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getOriginalMessage(), ex);
}
}
}
@@ -0,0 +1,15 @@
package com.aos.starter.core.metadata;
/**
* <p>Company: 成都返空汇网络技术有限公司 </p>
* <p>Description: 自用常量集中管理 </p>
*
* @author dong4j
* @version 1.3.0
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.04.12 12:50
* @since 1.0.0
*/
public interface Constants {
}
@@ -0,0 +1,39 @@
package com.aos.starter.core.node;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.ArrayList;
import java.util.List;
import lombok.Data;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 节点基类</p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.01.27 14:52
* @since 1.0.0
*/
@Data
public class BaseNode implements INode {
/**
* 主键ID
*/
protected Integer id;
/**
* 父节点ID
*/
protected Integer parentId;
/**
* 子孙节点
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
protected List<INode> children = new ArrayList<>();
}
@@ -0,0 +1,48 @@
package com.aos.starter.core.reflection.invoker;
import com.aos.starter.core.reflection.ReflectionException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* <p>Company: 成都返空汇网络技术有限公司 </p>
* <p>Description: </p>
*
* @author dong4j
* @version 1.3.0
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.04.12 11:46
* @since 1.0.0
*/
public class AmbiguousMethodInvoker extends MethodInvoker {
/** Exception message */
private final String exceptionMessage;
/**
* Ambiguous method invoker
*
* @param method method
* @param exceptionMessage exception message
* @since 1.0.0
*/
public AmbiguousMethodInvoker(Method method, String exceptionMessage) {
super(method);
this.exceptionMessage = exceptionMessage;
}
/**
* Invoke object
*
* @param target target
* @param args args
* @return the object
* @throws IllegalAccessException illegal access exception
* @throws InvocationTargetException invocation target exception
* @since 1.0.0
*/
@Override
public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
throw new ReflectionException(this.exceptionMessage);
}
}
@@ -0,0 +1,137 @@
package com.aos.starter.core.reflection.wrapper;
import com.aos.starter.core.reflection.MetaObject;
import com.aos.starter.core.reflection.ReflectionException;
import com.aos.starter.core.reflection.property.PropertyTokenizer;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Map;
/**
* <p>Company: 成都返空汇网络技术有限公司 </p>
* <p>Description: </p>
*
* @author dong4j
* @version 1.3.0
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.04.12 11:50
* @since 1.0.0
*/
public abstract class BaseWrapper implements ObjectWrapper {
/** NO_ARGUMENTS */
protected static final Object[] NO_ARGUMENTS = new Object[0];
/** Meta object */
protected final MetaObject metaObject;
/**
* Base wrapper
*
* @param metaObject meta object
* @since 1.0.0
*/
@Contract(pure = true)
protected BaseWrapper(MetaObject metaObject) {
this.metaObject = metaObject;
}
/**
* Resolve collection object
*
* @param prop prop
* @param object object
* @return the object
* @since 1.0.0
*/
protected Object resolveCollection(@NotNull PropertyTokenizer prop, Object object) {
if ("".equals(prop.getName())) {
return object;
} else {
return this.metaObject.getValue(prop.getName());
}
}
/**
* Gets collection value *
*
* @param prop prop
* @param collection collection
* @return the collection value
* @since 1.0.0
*/
protected Object getCollectionValue(PropertyTokenizer prop, Object collection) {
if (collection instanceof Map) {
return ((Map<?, ?>) collection).get(prop.getIndex());
} else {
int i = Integer.parseInt(prop.getIndex());
if (collection instanceof List) {
return ((List<?>) collection).get(i);
} else if (collection instanceof Object[]) {
return ((Object[]) collection)[i];
} else if (collection instanceof char[]) {
return ((char[]) collection)[i];
} else if (collection instanceof boolean[]) {
return ((boolean[]) collection)[i];
} else if (collection instanceof byte[]) {
return ((byte[]) collection)[i];
} else if (collection instanceof double[]) {
return ((double[]) collection)[i];
} else if (collection instanceof float[]) {
return ((float[]) collection)[i];
} else if (collection instanceof int[]) {
return ((int[]) collection)[i];
} else if (collection instanceof long[]) {
return ((long[]) collection)[i];
} else if (collection instanceof short[]) {
return ((short[]) collection)[i];
} else {
throw new ReflectionException("The '{}' property of {} is not a List or Array.", prop.getName(), collection);
}
}
}
/**
* Sets collection value *
*
* @param prop prop
* @param collection collection
* @param value value
* @since 1.0.0
*/
@SuppressWarnings(value = {"unchecked", "rawtypes"})
protected void setCollectionValue(PropertyTokenizer prop, Object collection, Object value) {
if (collection instanceof Map) {
((Map) collection).put(prop.getIndex(), value);
} else {
int i = Integer.parseInt(prop.getIndex());
if (collection instanceof List) {
((List) collection).set(i, value);
} else if (collection instanceof Object[]) {
((Object[]) collection)[i] = value;
} else if (collection instanceof char[]) {
((char[]) collection)[i] = (Character) value;
} else if (collection instanceof boolean[]) {
((boolean[]) collection)[i] = (Boolean) value;
} else if (collection instanceof byte[]) {
((byte[]) collection)[i] = (Byte) value;
} else if (collection instanceof double[]) {
((double[]) collection)[i] = (Double) value;
} else if (collection instanceof float[]) {
((float[]) collection)[i] = (Float) value;
} else if (collection instanceof int[]) {
((int[]) collection)[i] = (Integer) value;
} else if (collection instanceof long[]) {
((long[]) collection)[i] = (Long) value;
} else if (collection instanceof short[]) {
((short[]) collection)[i] = (Short) value;
} else {
throw new ReflectionException("The '{}' property of {} is not a List or Array.", prop.getName(), collection);
}
}
}
}
@@ -0,0 +1,323 @@
package com.aos.starter.core.reflection.wrapper;
import com.aos.starter.core.reflection.DefaultMetaObject;
import com.aos.starter.core.reflection.MetaClass;
import com.aos.starter.core.reflection.MetaObject;
import com.aos.starter.core.reflection.ReflectionException;
import com.aos.starter.core.reflection.factory.ObjectFactory;
import com.aos.starter.core.reflection.invoker.Invoker;
import com.aos.starter.core.reflection.property.PropertyTokenizer;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import cn.hutool.core.exceptions.ExceptionUtil;
/**
* <p>Company: 成都返空汇网络技术有限公司 </p>
* <p>Description: </p>
*
* @author dong4j
* @version 1.3.0
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.04.12 11:52
* @since 1.0.0
*/
@SuppressWarnings("all")
public class BeanWrapper extends BaseWrapper {
/** Object */
private final Object object;
/** Meta class */
private final MetaClass metaClass;
/**
* Bean wrapper
*
* @param metaObject meta object
* @param object object
* @since 1.0.0
*/
public BeanWrapper(MetaObject metaObject, @NotNull Object object) {
super(metaObject);
this.object = object;
this.metaClass = MetaClass.forClass(object.getClass(), metaObject.getReflectorFactory());
}
/**
* Get object
*
* @param prop prop
* @return the object
* @since 1.0.0
*/
@Override
public Object get(@NotNull PropertyTokenizer prop) {
if (prop.getIndex() != null) {
Object collection = this.resolveCollection(prop, this.object);
return this.getCollectionValue(prop, collection);
} else {
return this.getBeanProperty(prop, this.object);
}
}
/**
* Set *
*
* @param prop prop
* @param value value
* @since 1.0.0
*/
@Override
public void set(@NotNull PropertyTokenizer prop, Object value) {
if (prop.getIndex() != null) {
Object collection = this.resolveCollection(prop, this.object);
this.setCollectionValue(prop, collection, value);
} else {
this.setBeanProperty(prop, this.object, value);
}
}
/**
* Find property string
*
* @param name name
* @param useCamelCaseMapping use camel case mapping
* @return the string
* @since 1.0.0
*/
@Override
public String findProperty(String name, boolean useCamelCaseMapping) {
return this.metaClass.findProperty(name, useCamelCaseMapping);
}
/**
* Get getter names string [ ]
*
* @return the string [ ]
* @since 1.0.0
*/
@Override
public String[] getGetterNames() {
return this.metaClass.getGetterNames();
}
/**
* Get setter names string [ ]
*
* @return the string [ ]
* @since 1.0.0
*/
@Override
public String[] getSetterNames() {
return this.metaClass.getSetterNames();
}
/**
* Gets setter type *
*
* @param name name
* @return the setter type
* @since 1.0.0
*/
@Override
public Class<?> getSetterType(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
MetaObject metaValue = this.metaObject.metaObjectForProperty(prop.getIndexedName());
if (metaValue == DefaultMetaObject.NULL_META_OBJECT) {
return this.metaClass.getSetterType(name);
} else {
return metaValue.getSetterType(prop.getChildren());
}
} else {
return this.metaClass.getSetterType(name);
}
}
/**
* Gets getter type *
*
* @param name name
* @return the getter type
* @since 1.0.0
*/
@Override
public Class<?> getGetterType(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
MetaObject metaValue = this.metaObject.metaObjectForProperty(prop.getIndexedName());
if (metaValue == DefaultMetaObject.NULL_META_OBJECT) {
return this.metaClass.getGetterType(name);
} else {
return metaValue.getGetterType(prop.getChildren());
}
} else {
return this.metaClass.getGetterType(name);
}
}
/**
* Has setter boolean
*
* @param name name
* @return the boolean
* @since 1.0.0
*/
@Override
public boolean hasSetter(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
if (this.metaClass.hasSetter(prop.getIndexedName())) {
MetaObject metaValue = this.metaObject.metaObjectForProperty(prop.getIndexedName());
if (metaValue == DefaultMetaObject.NULL_META_OBJECT) {
return this.metaClass.hasSetter(name);
} else {
return metaValue.hasSetter(prop.getChildren());
}
} else {
return false;
}
} else {
return this.metaClass.hasSetter(name);
}
}
/**
* Has getter boolean
*
* @param name name
* @return the boolean
* @since 1.0.0
*/
@Override
public boolean hasGetter(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
if (this.metaClass.hasGetter(prop.getIndexedName())) {
MetaObject metaValue = this.metaObject.metaObjectForProperty(prop.getIndexedName());
if (metaValue == DefaultMetaObject.NULL_META_OBJECT) {
return this.metaClass.hasGetter(name);
} else {
return metaValue.hasGetter(prop.getChildren());
}
} else {
return false;
}
} else {
return this.metaClass.hasGetter(name);
}
}
/**
* Instantiate property value meta object
*
* @param name name
* @param prop prop
* @param objectFactory object factory
* @return the meta object
* @since 1.0.0
*/
@Override
public MetaObject instantiatePropertyValue(String name, @NotNull PropertyTokenizer prop, ObjectFactory objectFactory) {
MetaObject metaValue;
Class<?> type = this.getSetterType(prop.getName());
try {
Object newObject = objectFactory.create(type);
metaValue = MetaObject.forObject(newObject,
this.metaObject.getObjectFactory(),
this.metaObject.getObjectWrapperFactory(),
this.metaObject.getReflectorFactory());
this.set(prop, newObject);
} catch (Exception e) {
throw new ReflectionException("Cannot set value of property '{}' because '{}' is null "
+ "and cannot be instantiated on instance of {}. Cause:", name, name, type.getName(),
e.toString(), e);
}
return metaValue;
}
/**
* Sets bean property *
*
* @param prop prop
* @param object object
* @param value value
* @since 1.0.0
*/
private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {
try {
Invoker method = this.metaClass.getSetInvoker(prop.getName());
Object[] params = {value};
try {
method.invoke(object, params);
} catch (Throwable t) {
throw ExceptionUtil.unwrap(t);
}
} catch (Throwable t) {
throw new ReflectionException("Could not set property ' of '{}' with value '{}' Cause: {}", prop.getName(), object.getClass(),
value, t.toString(), t);
}
}
/**
* Is collection boolean
*
* @return the boolean
* @since 1.0.0
*/
@Override
public boolean isCollection() {
return false;
}
/**
* Add *
*
* @param element element
* @since 1.0.0
*/
@Override
public void add(Object element) {
throw new UnsupportedOperationException();
}
/**
* Add all *
*
* @param <E> parameter
* @param list list
* @since 1.0.0
*/
@Override
public <E> void addAll(List<E> list) {
throw new UnsupportedOperationException();
}
/**
* Gets bean property *
*
* @param prop prop
* @param object object
* @return the bean property
* @since 1.0.0
*/
private Object getBeanProperty(PropertyTokenizer prop, Object object) {
try {
Invoker method = this.metaClass.getGetInvoker(prop.getName());
try {
return method.invoke(object, NO_ARGUMENTS);
} catch (Throwable t) {
throw ExceptionUtil.unwrap(t);
}
} catch (RuntimeException e) {
throw e;
} catch (Throwable t) {
throw new ReflectionException("Could not get property '{}' from {}. Cause: ", prop.getName(), object.getClass(),
t.toString(), t);
}
}
}
@@ -0,0 +1,194 @@
package com.aos.starter.core.reflection.wrapper;
import com.aos.starter.core.reflection.MetaObject;
import com.aos.starter.core.reflection.factory.ObjectFactory;
import com.aos.starter.core.reflection.property.PropertyTokenizer;
import org.jetbrains.annotations.Contract;
import java.util.Collection;
import java.util.List;
/**
* <p>Company: 成都返空汇网络技术有限公司 </p>
* <p>Description: </p>
*
* @author dong4j
* @version 1.3.0
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.04.12 11:52
* @since 1.0.0
*/
public class CollectionWrapper implements ObjectWrapper {
/** Object */
private final Collection<Object> object;
/**
* Collection wrapper
*
* @param metaObject meta object
* @param object object
* @since 1.0.0
*/
@Contract(pure = true)
public CollectionWrapper(MetaObject metaObject, Collection<Object> object) {
this.object = object;
}
/**
* Get object
*
* @param prop prop
* @return the object
* @since 1.0.0
*/
@Override
public Object get(PropertyTokenizer prop) {
throw new UnsupportedOperationException();
}
/**
* Set *
*
* @param prop prop
* @param value value
* @since 1.0.0
*/
@Override
public void set(PropertyTokenizer prop, Object value) {
throw new UnsupportedOperationException();
}
/**
* Find property string
*
* @param name name
* @param useCamelCaseMapping use camel case mapping
* @return the string
* @since 1.0.0
*/
@Override
public String findProperty(String name, boolean useCamelCaseMapping) {
throw new UnsupportedOperationException();
}
/**
* Get getter names string [ ]
*
* @return the string [ ]
* @since 1.0.0
*/
@Override
public String[] getGetterNames() {
throw new UnsupportedOperationException();
}
/**
* Get setter names string [ ]
*
* @return the string [ ]
* @since 1.0.0
*/
@Override
public String[] getSetterNames() {
throw new UnsupportedOperationException();
}
/**
* Gets setter type *
*
* @param name name
* @return the setter type
* @since 1.0.0
*/
@Override
public Class<?> getSetterType(String name) {
throw new UnsupportedOperationException();
}
/**
* Gets getter type *
*
* @param name name
* @return the getter type
* @since 1.0.0
*/
@Override
public Class<?> getGetterType(String name) {
throw new UnsupportedOperationException();
}
/**
* Has setter boolean
*
* @param name name
* @return the boolean
* @since 1.0.0
*/
@Override
public boolean hasSetter(String name) {
throw new UnsupportedOperationException();
}
/**
* Has getter boolean
*
* @param name name
* @return the boolean
* @since 1.0.0
*/
@Override
public boolean hasGetter(String name) {
throw new UnsupportedOperationException();
}
/**
* Instantiate property value meta object
*
* @param name name
* @param prop prop
* @param objectFactory object factory
* @return the meta object
* @since 1.0.0
*/
@Override
public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {
throw new UnsupportedOperationException();
}
/**
* Is collection boolean
*
* @return the boolean
* @since 1.0.0
*/
@Override
public boolean isCollection() {
return true;
}
/**
* Add *
*
* @param element element
* @since 1.0.0
*/
@Override
public void add(Object element) {
this.object.add(element);
}
/**
* Add all *
*
* @param <E> parameter
* @param element element
* @since 1.0.0
*/
@Override
public <E> void addAll(List<E> element) {
this.object.addAll(element);
}
}
@@ -0,0 +1,26 @@
package com.aos.starter.core.support;
import com.aos.element.basic.basic.asserts.Assertions;
import com.aos.starter.core.api.IResultCode;
import lombok.experimental.UtilityClass;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 扩展 {@link Assertions}, 添加 {@link IResultCode} 参数
* <code>
* AssertUtils.notEmpty(map, BaseCodes.DATA_ERROR);
* </code>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.12.26 21:42
* @since 1.2.3
* @deprecated 请使用 {@link Assertions} 或 ErrorCodes 的方式代替
*/
@UtilityClass
@Deprecated
public class AssertUtils {
}
@@ -0,0 +1,341 @@
package com.aos.starter.core.support;
import com.google.common.collect.Maps;
import com.aos.starter.core.util.BeanUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.asm.ClassVisitor;
import org.springframework.asm.Type;
import org.springframework.cglib.core.AbstractClassGenerator;
import org.springframework.cglib.core.ClassEmitter;
import org.springframework.cglib.core.CodeEmitter;
import org.springframework.cglib.core.Constants;
import org.springframework.cglib.core.Converter;
import org.springframework.cglib.core.EmitUtils;
import org.springframework.cglib.core.KeyFactory;
import org.springframework.cglib.core.Local;
import org.springframework.cglib.core.MethodInfo;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.cglib.core.Signature;
import org.springframework.cglib.core.TypeUtils;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain;
import java.util.Map;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: spring cglib 修改 </p>
* 1. 支持链式 bean
* 2. 自定义的 BeanCopier 解决 spring boot 和 cglib ClassLoader classLoader 不一致的问题
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.12.26 21:46
* @since 1.0.0
*/
@SuppressWarnings("all")
public abstract class BaseBeanCopier {
/** KEY_FACTORY */
private static final BeanCopierKey KEY_FACTORY = (BeanCopierKey) KeyFactory.create(BeanCopierKey.class);
/** CONVERTER */
private static final Type CONVERTER = TypeUtils.parseType("org.springframework.cglib.core.Converter");
/** BEAN_COPIER */
private static final Type BEAN_COPIER = TypeUtils.parseType(BaseBeanCopier.class.getName());
/** COPY */
private static final Signature COPY = new Signature("copy",
Type.VOID_TYPE,
new Type[] {Constants.TYPE_OBJECT, Constants.TYPE_OBJECT, CONVERTER});
/** CONVERT */
private static final Signature CONVERT = TypeUtils.parseSignature("Object convert(Object, Class, Object)");
/**
* Create base bean copier.
*
* @param source the source
* @param target the target
* @param useConverter the use converter
* @return the base bean copier
* @since 1.0.0
*/
public static BaseBeanCopier create(Class<?> source, Class<?> target, boolean useConverter) {
return BaseBeanCopier.create(source, target, null, useConverter);
}
/**
* Create base bean copier.
*
* @param source the source
* @param target the target
* @param classLoader the class loader
* @param useConverter the use converter
* @return the base bean copier
* @since 1.0.0
*/
public static BaseBeanCopier create(Class<?> source, Class<?> target, ClassLoader classLoader, boolean useConverter) {
Generator gen;
if (classLoader == null) {
gen = new Generator();
} else {
gen = new Generator(classLoader);
}
gen.setSource(source);
gen.setTarget(target);
gen.setUseConverter(useConverter);
return gen.create();
}
/**
* 拷贝
*
* @param from 源
* @param to 目标
* @param converter 转换器
* @since 1.0.0
*/
public abstract void copy(Object from, Object to, Converter converter);
/**
* The interface Bean copier key.
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.12.26 21:46
* @since 1.0.0
*/
interface BeanCopierKey {
/**
* 实例化
*
* @param source 源
* @param target 目标
* @param useConverter 是否使用转换
* @return object object
* @since 1.0.0
*/
Object newInstance(String source, String target, boolean useConverter);
}
/**
* The type Generator.
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.12.26 21:46
* @since 1.0.0
*/
public static class Generator extends AbstractClassGenerator<Object> {
/** SOURCE */
private static final Source SOURCE = new Source(BaseBeanCopier.class.getName());
/** Class loader */
private final ClassLoader classLoader;
/** Source */
private Class<?> source;
/** Target */
private Class<?> target;
/** Use converter */
private boolean useConverter;
/**
* Instantiates a new Generator.
*
* @since 1.0.0
*/
Generator() {
super(SOURCE);
this.classLoader = null;
}
/**
* Instantiates a new Generator.
*
* @param classLoader the class loader
* @since 1.0.0
*/
Generator(ClassLoader classLoader) {
super(SOURCE);
this.classLoader = classLoader;
}
/**
* Sets source.
*
* @param source the source
* @since 1.0.0
*/
public void setSource(@NotNull Class<?> source) {
if (!Modifier.isPublic(source.getModifiers())) {
this.setNamePrefix(source.getName());
}
this.source = source;
}
/**
* Sets target.
*
* @param target the target
* @since 1.0.0
*/
public void setTarget(@NotNull Class<?> target) {
if (!Modifier.isPublic(target.getModifiers())) {
this.setNamePrefix(target.getName());
}
this.target = target;
}
/**
* Sets use converter.
*
* @param useConverter the use converter
* @since 1.0.0
*/
public void setUseConverter(boolean useConverter) {
this.useConverter = useConverter;
}
/**
* Gets default class loader *
*
* @return the default class loader
* @since 1.0.0
*/
@Override
protected ClassLoader getDefaultClassLoader() {
return this.target.getClassLoader();
}
/**
* Gets protection domain *
*
* @return the protection domain
* @since 1.0.0
*/
@Override
protected ProtectionDomain getProtectionDomain() {
return ReflectUtils.getProtectionDomain(this.source);
}
/**
* First instance object
*
* @param type type
* @return the object
* @since 1.0.0
*/
@Override
protected Object firstInstance(Class type) {
return ReflectUtils.newInstance(type);
}
/**
* Next instance object
*
* @param instance instance
* @return the object
* @since 1.0.0
*/
@Override
protected Object nextInstance(Object instance) {
return instance;
}
/**
* Create base bean copier.
*
* @return the base bean copier
* @since 1.0.0
*/
public BaseBeanCopier create() {
Object key = KEY_FACTORY.newInstance(this.source.getName(), this.target.getName(), this.useConverter);
return (BaseBeanCopier) super.create(key);
}
/**
* Generate class *
*
* @param v v
* @since 1.0.0
*/
@Override
public void generateClass(ClassVisitor v) {
Type sourceType = Type.getType(this.source);
Type targetType = Type.getType(this.target);
ClassEmitter ce = new ClassEmitter(v);
ce.begin_class(Constants.V1_2,
Constants.ACC_PUBLIC,
this.getClassName(),
BEAN_COPIER,
null,
Constants.SOURCE_FILE);
EmitUtils.null_constructor(ce);
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, COPY, null);
// 支持链式 bean
PropertyDescriptor[] getters = BeanUtils.getBeanGetters(this.source);
PropertyDescriptor[] setters = BeanUtils.getBeanSetters(this.target);
Map<String, Object> names = Maps.newHashMapWithExpectedSize(16);
for (PropertyDescriptor getter : getters) {
names.put(getter.getName(), getter);
}
Local targetLocal = e.make_local();
Local sourceLocal = e.make_local();
e.load_arg(1);
e.checkcast(targetType);
e.store_local(targetLocal);
e.load_arg(0);
e.checkcast(sourceType);
e.store_local(sourceLocal);
for (PropertyDescriptor setter : setters) {
PropertyDescriptor getter = (PropertyDescriptor) names.get(setter.getName());
if (getter != null) {
MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod());
MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod());
if (this.useConverter) {
Type setterType = write.getSignature().getArgumentTypes()[0];
e.load_local(targetLocal);
e.load_arg(2);
e.load_local(sourceLocal);
e.invoke(read);
e.box(read.getSignature().getReturnType());
EmitUtils.load_class(e, setterType);
e.push(write.getSignature().getName());
e.invoke_interface(CONVERTER, CONVERT);
e.unbox_or_zero(setterType);
e.invoke(write);
} else if (compatible(getter, setter)) {
// 支持链式 bean
e.load_local(targetLocal);
e.load_local(sourceLocal);
e.invoke(read);
e.invoke(write);
}
}
}
e.return_value();
e.end_method();
ce.end_class();
}
/**
* Compatible boolean
*
* @param getter getter
* @param setter setter
* @return the boolean
* @since 1.0.0
*/
private static boolean compatible(@NotNull PropertyDescriptor getter, @NotNull PropertyDescriptor setter) {
return setter.getPropertyType().isAssignableFrom(getter.getPropertyType());
}
}
}
@@ -0,0 +1,23 @@
package com.aos.starter.core.support;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: Bean属性 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.01.27 18:10
* @since 1.0.0
*/
@Getter
@AllArgsConstructor
public class BeanProperty {
/** Name */
private final String name;
/** Type */
private final Class<?> type;
}
@@ -0,0 +1,264 @@
package com.aos.starter.core.support;
import com.aos.starter.core.util.Tools;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.springframework.util.LinkedCaseInsensitiveMap;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Date;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 链式 map (linkedmap) key 必须为 string </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.01.27 18:24
* @since 1.0.0
*/
@SuppressWarnings("all")
public final class ChainMap extends LinkedCaseInsensitiveMap<Object> {
/** serialVersionUID */
private static final long serialVersionUID = 3992810369797036508L;
/**
* Chain map
*
* @since 1.0.0
*/
private ChainMap() {
super();
}
/**
* Chain map
*
* @param size size
* @since 1.0.0
*/
private ChainMap(int size) {
super(Tools.capacity(size));
}
/**
* Build chain map.
*
* @return the chain map
* @since 1.0.0
*/
@NotNull
@Contract(" -> new")
public static ChainMap build() {
return new ChainMap();
}
/**
* Build chain map.
*
* @param size the size
* @return the chain map
* @since 1.0.0
*/
@NotNull
@Contract("_ -> new")
public static ChainMap build(int size) {
return new ChainMap(size);
}
/**
* 设置列,当键或值为null时忽略
*
* @param attr 属性
* @param value 值
* @return 本身 ignore null
* @since 1.0.0
*/
@Contract("null, _ -> this; !null, null -> this")
public ChainMap setIgnoreNull(String attr, Object value) {
if (null != attr && null != value) {
put(attr, value);
}
return this;
}
/**
* 存入 kv
*
* @param attr 属性
* @param value 值
* @return 本身 kv
* @since 1.0.0
*/
@Contract("_, _ -> this")
@NotNull
@Override
public ChainMap put(@NotNull String attr, Object value) {
super.put(attr, value);
return this;
}
/**
* Clone chain map
*
* @return the chain map
* @since 1.0.0
*/
@NotNull
@Override
public ChainMap clone() {
return (ChainMap) super.clone();
}
/**
* Gets obj.
*
* @param key the key
* @return the obj
* @since 1.0.0
*/
public Object getObj(String key) {
return super.get(key);
}
/**
* 获得特定类型值
*
* @param attr 字段名
* @return 字段值 str
* @since 1.0.0
*/
public String getStr(String attr) {
return Tools.toStr(get(attr), null);
}
/**
* 获得特定类型值
*
* @param attr 字段名
* @return 字段值 int
* @since 1.0.0
*/
@NotNull
public Integer getInt(String attr) {
return Tools.toInt(get(attr), -1);
}
/**
* 获得特定类型值
*
* @param attr 字段名
* @return 字段值 long
* @since 1.0.0
*/
@NotNull
public Long getLong(String attr) {
return Tools.toLong(get(attr), -1L);
}
/**
* 获得特定类型值
*
* @param attr 字段名
* @return 字段值 float
* @since 1.0.0
*/
public Float getFloat(String attr) {
return Tools.toFloat(get(attr), null);
}
/**
* Gets double.
*
* @param attr the attr
* @return the double
* @since 1.0.0
*/
public Double getDouble(String attr) {
return Tools.toDouble(get(attr), null);
}
/**
* 获得特定类型值
*
* @param attr 字段名
* @return 字段值 bool
* @since 1.0.0
*/
public Boolean getBool(String attr) {
return Tools.toBoolean(get(attr), null);
}
/**
* 获得特定类型值
*
* @param attr 字段名
* @return 字段值 byte [ ]
* @since 1.0.0
*/
public byte[] getBytes(String attr) {
return get(attr, null);
}
/**
* 获得特定类型值
*
* @param <T> 值类型
* @param attr 字段名
* @param defaultValue 默认值
* @return 字段值 t
* @since 1.0.0
*/
@SuppressWarnings("unchecked")
public <T> T get(String attr, T defaultValue) {
Object result = get(attr);
return (T) (result != null ? result : defaultValue);
}
/**
* 获得特定类型值
*
* @param attr 字段名
* @return 字段值 date
* @since 1.0.0
*/
public Date getDate(String attr) {
return get(attr, null);
}
/**
* 获得特定类型值
*
* @param attr 字段名
* @return 字段值 time
* @since 1.0.0
*/
public Time getTime(String attr) {
return get(attr, null);
}
/**
* 获得特定类型值
*
* @param attr 字段名
* @return 字段值 timestamp
* @since 1.0.0
*/
public Timestamp getTimestamp(String attr) {
return get(attr, null);
}
/**
* 获得特定类型值
*
* @param attr 字段名
* @return 字段值 number
* @since 1.0.0
*/
public Number getNumber(String attr) {
return get(attr, null);
}
}
@@ -0,0 +1,311 @@
package com.aos.starter.core.util;
import com.aos.element.basic.basic.util.Charsets;
import com.aos.element.basic.basic.util.Exceptions;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.springframework.util.Assert;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import lombok.experimental.UtilityClass;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* 完全兼容微信所使用的AES加密方式.
* aes的key必须是256byte长 (比如32个字符) ,可以使用AesKit.genAesKey()来生成一组key
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.12.26 21:39
* @since 1.0.0
*/
@UtilityClass
@SuppressWarnings("all")
public class AesUtils {
/** 默认 16 长度 */
private static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
/** MAXIMUM_CAPACITY */
private static final int MAXIMUM_CAPACITY = 1 << 30;
/**
* 返回 2 的整数倍
*
* @param cap cap
* @return the int
* @since 1.9.0
*/
private static final int relengh(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
/**
* Check power of 2
*
* @param n n
* @return the boolean
* @since 1.9.0
*/
private boolean checkPowerOf2(int n) {
if (n <= 0) {
return false;
}
int t = n & (n - 1);
return t == 0 ? true : false;
}
/**
* Gen aes key string.
*
* @return the string
* @since 1.0.0
*/
@NotNull
public static String genAesKey() {
return RandomUtils.random(DEFAULT_INITIAL_CAPACITY);
}
/**
* Gen aes key
*
* @param length length
* @return the string
* @since 1.9.0
*/
public static String genAesKey(int length) {
return RandomUtils.random(relengh(length));
}
/**
* Encrypt byte [ ].
*
* @param content the content
* @param aesTextKey the aes text key
* @return the byte [ ]
* @since 1.0.0
*/
public static byte[] encrypt(byte[] content, @NotNull String aesTextKey) {
return encrypt(content, aesTextKey.getBytes(Charsets.UTF_8));
}
/**
* Encrypt byte [ ].
*
* @param content the content
* @param aesKey the aes key
* @return the byte [ ]
* @since 1.0.0
*/
public static byte[] encrypt(byte[] content, byte[] aesKey) {
Assert.isTrue(aesKey.length >= DEFAULT_INITIAL_CAPACITY && checkPowerOf2(aesKey.length),
"密钥必须为 2 的幂次方且大于等于 16 位");
try {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
IvParameterSpec iv = new IvParameterSpec(aesKey, 0, DEFAULT_INITIAL_CAPACITY);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
return cipher.doFinal(Pkcs7Encoder.encode(content));
} catch (Exception e) {
throw Exceptions.unchecked(e);
}
}
/**
* Encrypt byte [ ].
*
* @param content the content
* @param aesTextKey the aes text key
* @return the byte [ ]
* @since 1.0.0
*/
public static byte[] encrypt(@NotNull String content, @NotNull String aesTextKey) {
return encrypt(content.getBytes(Charsets.UTF_8), aesTextKey.getBytes(Charsets.UTF_8));
}
/**
* Encrypt to str
*
* @param content content
* @param aesTextKey aes text key
* @return the string
* @since 1.9.0
*/
public static String encryptToStr(@NotNull String content, @NotNull String aesTextKey) {
return Base64Utils.encodeToString(encrypt(content, aesTextKey));
}
/**
* Encrypt byte [ ].
*
* @param content the content
* @param charset the charset
* @param aesTextKey the aes text key
* @return the byte [ ]
* @since 1.0.0
*/
public static byte[] encrypt(@NotNull String content, java.nio.charset.Charset charset, @NotNull String aesTextKey) {
return encrypt(content.getBytes(charset), aesTextKey.getBytes(Charsets.UTF_8));
}
/**
* Decrypt to str
*
* @param content content
* @param aesTextKey aes text key
* @return the string
* @since 1.9.0
*/
public static String decryptToStr(@NotNull String content, @NotNull String aesTextKey) {
return new String(decrypt(content, aesTextKey));
}
/**
* Decrypt
*
* @param content content
* @param aesTextKey aes text key
* @return the byte [ ]
* @since 1.9.0
*/
public static byte[] decrypt(@NotNull String content, @NotNull String aesTextKey) {
return decrypt(Base64Utils.decodeFromString(content), aesTextKey);
}
/**
* Decrypt byte [ ].
*
* @param content the content
* @param aesTextKey the aes text key
* @return the byte [ ]
* @since 1.0.0
*/
public static byte[] decrypt(byte[] content, @NotNull String aesTextKey) {
return decrypt(content, aesTextKey.getBytes(Charsets.UTF_8));
}
/**
* Decrypt byte [ ].
*
* @param encrypted the encrypted
* @param aesKey the aes key
* @return the byte [ ]
* @since 1.0.0
*/
public static byte[] decrypt(byte[] encrypted, byte[] aesKey) {
Assert.isTrue(aesKey.length >= DEFAULT_INITIAL_CAPACITY && checkPowerOf2(aesKey.length),
"密钥必须为 2 的幂次方且大于等于 16 位");
try {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, DEFAULT_INITIAL_CAPACITY));
cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
return Pkcs7Encoder.decode(cipher.doFinal(encrypted));
} catch (Exception e) {
throw Exceptions.unchecked(e);
}
}
/**
* Decrypt to str string.
*
* @param content the content
* @param aesTextKey the aes text key
* @return the string
* @since 1.0.0
*/
@NotNull
@Contract("_, _ -> new")
public static String decryptToStr(byte[] content, @NotNull String aesTextKey) {
return new String(decrypt(content, aesTextKey.getBytes(Charsets.UTF_8)), Charsets.UTF_8);
}
/**
* Decrypt to str string.
*
* @param content the content
* @param aesTextKey the aes text key
* @param charset the charset
* @return the string
* @since 1.0.0
*/
@NotNull
@Contract("_, _, _ -> new")
public static String decryptToStr(byte[] content, @NotNull String aesTextKey, java.nio.charset.Charset charset) {
return new String(decrypt(content, aesTextKey.getBytes(Charsets.UTF_8)), charset);
}
/**
* 提供基于PKCS7算法的加解密接口.
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.12.26 21:39
* @since 1.0.0
*/
@UtilityClass
static class Pkcs7Encoder {
/**
* The Block size.
*/
static final int BLOCK_SIZE = 32;
/**
* Encode byte [ ].
*
* @param src the src
* @return the byte [ ]
* @since 1.0.0
*/
static byte[] encode(byte[] src) {
int count = src.length;
// 计算需要填充的位数
int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
// 获得补位所用的字符
byte pad = (byte) (amountToPad & 0xFF);
byte[] pads = new byte[amountToPad];
for (int index = 0; index < amountToPad; index++) {
pads[index] = pad;
}
int length = count + amountToPad;
byte[] dest = new byte[length];
System.arraycopy(src, 0, dest, 0, count);
System.arraycopy(pads, 0, dest, count, amountToPad);
return dest;
}
/**
* Decode byte [ ].
*
* @param decrypted the decrypted
* @return the byte [ ]
* @since 1.0.0
*/
@Contract(pure = true)
static byte[] decode(byte[] decrypted) {
int pad = (int) decrypted[decrypted.length - 1];
if (pad < 1 || pad > BLOCK_SIZE) {
pad = 0;
}
if (pad > 0) {
return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
}
return decrypted;
}
}
}
@@ -0,0 +1,45 @@
package com.aos.starter.core.util;
import org.jetbrains.annotations.NotNull;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import java.io.File;
import java.io.FileFilter;
import java.io.Serializable;
import lombok.RequiredArgsConstructor;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: spring AntPath 规则文件过滤 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.12.26 21:40
* @since 1.0.0
*/
@RequiredArgsConstructor
public class AntPathFilter implements FileFilter, Serializable {
/** serialVersionUID */
private static final long serialVersionUID = 812598009067554612L;
/** PATH_MATCHER */
private static final PathMatcher PATH_MATCHER = new AntPathMatcher();
/** Pattern */
private final String pattern;
/**
* Accept boolean
*
* @param pathname pathname
* @return the boolean
* @since 1.0.0
*/
@Override
public boolean accept(@NotNull File pathname) {
String filePath = pathname.getAbsolutePath();
return PATH_MATCHER.match(pattern, filePath);
}
}
@@ -0,0 +1,132 @@
package com.aos.starter.core.util;
import com.aos.element.basic.basic.util.Charsets;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import lombok.experimental.UtilityClass;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: Base64工具 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.12.26 21:45
* @since 1.0.0
*/
@UtilityClass
@SuppressWarnings("all")
public class Base64Utils extends org.springframework.util.Base64Utils {
/**
* 编码
*
* @param value 字符串
* @return {String}
* @since 1.0.0
*/
@NotNull
public static String encode(String value) {
return Base64Utils.encode(value, Charsets.UTF_8);
}
/**
* 编码
*
* @param value 字符串
* @param charset 字符集
* @return {String}
* @since 1.0.0
*/
@NotNull
@Contract("_, _ -> new")
public static String encode(@NotNull String value, java.nio.charset.Charset charset) {
byte[] val = value.getBytes(charset);
return new String(Base64Utils.encode(val), charset);
}
/**
* 编码URL安全
*
* @param value 字符串
* @return {String}
* @since 1.0.0
*/
@NotNull
public static String encodeUrlSafe(String value) {
return Base64Utils.encodeUrlSafe(value, Charsets.UTF_8);
}
/**
* 编码URL安全
*
* @param value 字符串
* @param charset 字符集
* @return {String}
* @since 1.0.0
*/
@NotNull
@Contract("_, _ -> new")
public static String encodeUrlSafe(@NotNull String value, java.nio.charset.Charset charset) {
byte[] val = value.getBytes(charset);
return new String(Base64Utils.encodeUrlSafe(val), charset);
}
/**
* 解码
*
* @param value 字符串
* @return {String}
* @since 1.0.0
*/
@NotNull
public static String decode(String value) {
return Base64Utils.decode(value, Charsets.UTF_8);
}
/**
* 解码
*
* @param value 字符串
* @param charset 字符集
* @return {String}
* @since 1.0.0
*/
@NotNull
public static String decode(@NotNull String value, java.nio.charset.Charset charset) {
byte[] val = value.getBytes(charset);
byte[] decodedValue = Base64Utils.decode(val);
return new String(decodedValue, charset);
}
/**
* 解码URL安全
*
* @param value 字符串
* @return {String}
* @since 1.0.0
*/
@NotNull
public static String decodeUrlSafe(String value) {
return Base64Utils.decodeUrlSafe(value, Charsets.UTF_8);
}
/**
* 解码URL安全
*
* @param value 字符串
* @param charset 字符集
* @return {String}
* @since 1.0.0
*/
@NotNull
public static String decodeUrlSafe(@NotNull String value, java.nio.charset.Charset charset) {
byte[] val = value.getBytes(charset);
byte[] decodedValue = Base64Utils.decodeUrlSafe(val);
return new String(decodedValue, charset);
}
}
@@ -0,0 +1,473 @@
package com.aos.starter.core.util;
import com.google.common.collect.Maps;
import com.aos.starter.core.convert.CustomConverter;
import com.aos.starter.core.exception.BaseException;
import com.aos.starter.core.support.BaseBeanCopier;
import com.aos.starter.core.support.BeanProperty;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeansException;
import org.springframework.cglib.beans.BeanGenerator;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.cglib.core.CodeGenerationException;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import lombok.experimental.UtilityClass;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 实体工具类 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.12.11 18:47
* @since 1.0.0
*/
@SuppressWarnings("all")
@UtilityClass
public class BeanUtils extends org.springframework.beans.BeanUtils {
/**
* 实例化对象
*
* @param <T> 泛型标记
* @param clazzStr 类名
* @return 对象 t
* @since 1.0.0
*/
@NotNull
public static <T> T newInstance(String clazzStr) {
try {
Class<?> clazz = Class.forName(clazzStr);
return newInstance(clazz);
} catch (ClassNotFoundException e) {
throw new BaseException(e);
}
}
/**
* 实例化对象
*
* @param <T> 泛型标记
* @param clazz 类
* @return 对象 t
* @since 1.0.0
*/
@NotNull
public static <T> T newInstance(Class<?> clazz) {
return (T) instantiateClass(clazz);
}
/**
* 获取Bean的属性
*
* @param bean bean
* @param propertyName 属性名
* @return 属性值 property
* @since 1.0.0
*/
public static Object getProperty(Object bean, String propertyName) {
Assert.notNull(bean, "bean Could not null");
return BeanMap.create(bean).get(propertyName);
}
/**
* 设置Bean属性
*
* @param bean bean
* @param propertyName 属性名
* @param value 属性值
* @since 1.0.0
*/
public static void setProperty(Object bean, String propertyName, Object value) {
Assert.notNull(bean, "bean Could not null");
BeanMap.create(bean).put(propertyName, value);
}
/**
* 深复制
* 注意: 不支持链式Bean
*
* @param <T> 泛型标记
* @param source 源对象
* @return T t
* @since 1.0.0
*/
public static <T> T clone(T source) {
return (T) BeanUtils.copy(source, source.getClass());
}
/**
* copy 对象属性到另一个对象,默认不使用Convert
* 注意: 不支持链式Bean,链式用 copyProperties
*
* @param <T> 泛型标记
* @param source 源对象
* @param clazz 类名
* @return T t
* @since 1.0.0
*/
@Contract("null, _ -> null")
public static <T> T copy(Object source, Class<T> clazz) {
if (source == null) {
return null;
}
return BeanUtils.copy(source, source.getClass(), clazz);
}
/**
* copy 对象属性,默认不使用Convert
* <p>
* 支持 map bean copy
* </p>
*
* @param <T> 泛型标记
* @param source 源对象
* @param sourceClazz 源类型
* @param targetClazz 转换成的类型
* @return T t
* @since 1.0.0
*/
@Contract("null, _, _ -> null")
public static <T> T copy(Object source, Class<?> sourceClazz, Class<T> targetClazz) {
BaseBeanCopier copier = BaseBeanCopier.create(sourceClazz, targetClazz, false);
T to = newInstance(targetClazz);
copier.copy(source, to, null);
return to;
}
/**
* copy 列表对象,默认不使用Convert
* <p>
* 支持 map bean copy
* </p>
*
* @param <T> 泛型标记
* @param sourceList 源列表
* @param targetClazz 转换成的类型
* @return T list
* @since 1.0.0
*/
@Contract("null, _ -> !null")
public static <T> List<T> copy(@Nullable Collection<?> sourceList, Class<T> targetClazz) {
if (sourceList == null || sourceList.isEmpty()) {
return Collections.emptyList();
}
List<T> outList = new ArrayList<>(sourceList.size());
Class<?> sourceClazz = null;
for (Object source : sourceList) {
if (source == null) {
continue;
}
if (sourceClazz == null) {
sourceClazz = source.getClass();
}
T bean = BeanUtils.copy(source, sourceClazz, targetClazz);
outList.add(bean);
}
return outList;
}
/**
* 拷贝对象并对不同类型属性进行转换
* <p>
* 支持 map bean copy
* </p>
*
* @param <T> 泛型标记
* @param source 源对象
* @param targetClazz 转换成的类
* @return T t
* @since 1.0.0
*/
@Contract("null, _ -> null")
@Nullable
public static <T> T copyWithConvert(@Nullable Object source, Class<T> targetClazz) {
if (source == null) {
return null;
}
return BeanUtils.copyWithConvert(source, source.getClass(), targetClazz);
}
/**
* 拷贝对象并对不同类型属性进行转换
* <p>
* 支持 map bean copy
* </p>
*
* @param <T> 泛型标记
* @param source 源对象
* @param sourceClazz 源类
* @param targetClazz 转换成的类
* @return T t
* @since 1.0.0
*/
@Contract("null, _, _ -> null")
@Nullable
public static <T> T copyWithConvert(@Nullable Object source, Class<?> sourceClazz, Class<T> targetClazz) {
if (source == null) {
return null;
}
BaseBeanCopier copier = BaseBeanCopier.create(sourceClazz, targetClazz, true);
T to = newInstance(targetClazz);
copier.copy(source, to, new CustomConverter(sourceClazz, targetClazz));
return to;
}
/**
* 拷贝列表并对不同类型属性进行转换
* <p>
* 支持 map bean copy
* </p>
*
* @param <T> 泛型标记
* @param sourceList 源对象列表
* @param targetClazz 转换成的类
* @return List list
* @since 1.0.0
*/
@Contract("null, _ -> !null")
public static <T> List<T> copyWithConvert(@Nullable Collection<?> sourceList, Class<T> targetClazz) {
if (sourceList == null || sourceList.isEmpty()) {
return Collections.emptyList();
}
List<T> outList = new ArrayList<>(sourceList.size());
Class<?> sourceClazz = null;
for (Object source : sourceList) {
if (source == null) {
continue;
}
if (sourceClazz == null) {
sourceClazz = source.getClass();
}
T bean = BeanUtils.copyWithConvert(source, sourceClazz, targetClazz);
outList.add(bean);
}
return outList;
}
/**
* Copy the property values of the given source bean into the target class.
* <p>Note: The source and target classes do not have to match or even be derived
* from each other, as long as the properties match. Any bean properties that the
* source bean exposes but the target bean does not will silently be ignored.
* <p>This is just a convenience method. For more complex transfer needs,
*
* @param <T> 泛型标记
* @param sourceList the source list bean
* @param targetClazz the target bean class
* @return List list
* @throws BeansException if the copying failed
* @since 1.0.0
*/
@Contract("null, _ -> !null")
public static <T> List<T> copyProperties(@Nullable Collection<?> sourceList, Class<T> targetClazz) {
if (sourceList == null || sourceList.isEmpty()) {
return Collections.emptyList();
}
List<T> outList = new ArrayList<>(sourceList.size());
for (Object source : sourceList) {
if (source == null) {
continue;
}
T bean = BeanUtils.copyProperties(source, targetClazz);
outList.add(bean);
}
return outList;
}
/**
* Copy the property values of the given source bean into the target class.
* <p>Note: The source and target classes do not have to match or even be derived
* from each other, as long as the properties match. Any bean properties that the
* source bean exposes but the target bean does not will silently be ignored.
* <p>This is just a convenience method. For more complex transfer needs,
*
* @param <T> 泛型标记
* @param source the source bean
* @param targetClazz the target bean class
* @return T t
* @throws BeansException if the copying failed
* @since 1.0.0
*/
@Contract("null, _ -> null")
@Nullable
public static <T> T copyProperties(@Nullable Object source, Class<T> targetClazz) {
if (source == null) {
return null;
}
T to = newInstance(targetClazz);
BeanUtils.copyProperties(source, to);
return to;
}
/**
* 将对象装成 map 形式.
* 注意: 返回的 Map 不能使用 put 添加键值对, 因为 BeanMap 未做实现, 所以不会添加成功, 必须使用强转为 BeanMap 后才使用 put
*
* @param bean 源对象
* @return {Map}
* @since 1.0.0
*/
@Contract("null -> new")
@SuppressWarnings("unchecked")
public static Map<String, Object> toMap(Object bean) {
if (bean == null) {
return Maps.newHashMapWithExpectedSize(0);
}
return BeanMap.create(bean);
}
/**
* To string map map
*
* @param bean bean
* @return the map
* @since 1.0.0
*/
@Contract("null -> !null")
public static Map<String, String> toStringMap(Object bean) {
Map<String, Object> map = toMap(bean);
Map<String, String> stringMap = Maps.newHashMapWithExpectedSize(map.size());
map.forEach((k, v) -> {
if (ObjectUtils.isNotNull(v)) {
stringMap.put(k, String.valueOf(v));
}
});
return stringMap;
}
/**
* 将map 转为 bean
*
* @param <T> 泛型标记
* @param beanMap map
* @param valueType 对象类型
* @return {T}
* @since 1.0.0
*/
public static <T> T toBean(Map<String, Object> beanMap, Class<T> valueType) {
Objects.requireNonNull(beanMap, "beanMap Could not null");
T bean = BeanUtils.newInstance(valueType);
if (beanMap.isEmpty()) {
return bean;
}
BeanMap.create(bean).putAll(beanMap);
return bean;
}
/**
* 给一个Bean添加字段
*
* @param superBean 父级Bean
* @param props 新增属性
* @return {Object}
* @since 1.0.0
*/
public static Object generator(@NotNull Object superBean, BeanProperty... props) {
Class<?> superclass = superBean.getClass();
Object genBean = generator(superclass, props);
BeanUtils.copy(superBean, genBean);
return genBean;
}
/**
* 给一个class添加字段
*
* @param superclass 父级
* @param props 新增属性
* @return {Object}
* @since 1.0.0
*/
public static Object generator(Class<?> superclass, @NotNull BeanProperty... props) {
BeanGenerator generator = new BeanGenerator();
generator.setSuperclass(superclass);
generator.setUseCache(true);
for (BeanProperty prop : props) {
generator.addProperty(prop.getName(), prop.getType());
}
return generator.create();
}
/**
* 拷贝对象
* 注意: 不支持链式Bean,链式用 copyProperties
*
* @param source 源对象
* @param targetBean 需要赋值的对象
* @since 1.0.0
*/
public static void copy(@NotNull Object source, @NotNull Object targetBean) {
BaseBeanCopier copier = BaseBeanCopier
.create(source.getClass(), targetBean.getClass(), false);
copier.copy(source, targetBean, null);
}
/**
* 获取 Bean 的所有 get方法
*
* @param type 类
* @return PropertyDescriptor数组 property descriptor [ ]
* @since 1.0.0
*/
public static PropertyDescriptor[] getBeanGetters(Class<?> type) {
return getPropertiesHelper(type, true, false);
}
/**
* Get properties helper property descriptor [ ]
*
* @param type type
* @param read read
* @param write write
* @return the property descriptor [ ]
* @since 1.0.0
*/
private static PropertyDescriptor[] getPropertiesHelper(Class<?> type, boolean read, boolean write) {
try {
PropertyDescriptor[] all = BeanUtils.getPropertyDescriptors(type);
if (read && write) {
return all;
} else {
List<PropertyDescriptor> properties = new ArrayList<>(all.length);
for (PropertyDescriptor pd : all) {
if (read && pd.getReadMethod() != null) {
properties.add(pd);
} else if (write && pd.getWriteMethod() != null) {
properties.add(pd);
}
}
return properties.toArray(new PropertyDescriptor[0]);
}
} catch (BeansException ex) {
throw new CodeGenerationException(ex);
}
}
/**
* 获取 Bean 的所有 set方法
*
* @param type 类
* @return PropertyDescriptor数组 property descriptor [ ]
* @since 1.0.0
*/
public static PropertyDescriptor[] getBeanSetters(Class<?> type) {
return getPropertiesHelper(type, false, true);
}
}
@@ -0,0 +1,21 @@
package com.aos.starter.core.util;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 类工具类 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.12.30 22:37
* @since 1.0.0
*/
@Slf4j
@UtilityClass
@SuppressWarnings("java:S2176")
public class ClassUtils extends com.aos.element.basic.basic.util.ClassUtils {
}
@@ -0,0 +1,316 @@
package com.aos.starter.core.util;
import com.google.common.collect.Maps;
import com.aos.element.basic.core.util.DataTypeUtils;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.experimental.UtilityClass;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 集合工具类 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.12.24 15:24
* @since 1.0.0
*/
@UtilityClass
@SuppressWarnings("java:S2176")
public class CollectionUtils extends org.springframework.util.CollectionUtils {
/** THREAD_LOCAL_RANDOM */
public static final ThreadLocalRandom THREAD_LOCAL_RANDOM = ThreadLocalRandom.current();
/**
* Return {@code true} if the supplied Collection is not {@code null} or empty.
* Otherwise, return {@code false}.
*
* @param collection the Collection to check
* @return whether the given Collection is not empty
* @since 1.0.0
*/
@Contract("null -> false")
public static boolean isNotEmpty(@Nullable Collection<?> collection) {
return !isEmpty(collection);
}
/**
* Return {@code true} if the supplied Map is not {@code null} or empty.
* Otherwise, return {@code false}.
*
* @param map the Map to check
* @return whether the given Map is not empty
* @since 1.0.0
*/
@Contract("null -> false")
public static boolean isNotEmpty(@Nullable Map<?, ?> map) {
return !isEmpty(map);
}
/**
* Check whether the given Array contains the given element.
*
* @param <T> The generic tag
* @param array the Array to check
* @param element the element to look for
* @return {@code true} if found, {@code false} else
* @since 1.0.0
*/
@Contract("null, _ -> false")
public static <T> boolean contains(@Nullable T[] array, T element) {
if (array == null) {
return false;
}
return Arrays.stream(array).anyMatch(x -> ObjectUtils.nullSafeEquals(x, element));
}
/**
* Concatenates 2 arrays
*
* @param one 数组1
* @param other 数组2
* @return 新数组 string [ ]
* @since 1.0.0
*/
public static String[] concat(String[] one, String[] other) {
return concat(one, other, String.class);
}
/**
* Concatenates 2 arrays
*
* @param <T> the type parameter
* @param one 数组1
* @param other 数组2
* @param clazz 数组类
* @return 新数组 t [ ]
* @since 1.0.0
*/
@SuppressWarnings("unchecked")
public static <T> T[] concat(@NotNull T[] one, @NotNull T[] other, Class<T> clazz) {
T[] target = (T[]) Array.newInstance(clazz, one.length + other.length);
System.arraycopy(one, 0, target, 0, one.length);
System.arraycopy(other, 0, target, one.length, other.length);
return target;
}
/**
* 不可变 Set
*
* @param <E> 泛型
* @param es 对象
* @return 集合 set
* @since 1.0.0
*/
public static <E> Set<E> ofImmutableSet(E[] es) {
Objects.requireNonNull(es, "args es is null.");
return Arrays.stream(es).collect(Collectors.toSet());
}
/**
* 不可变 List
*
* @param <E> 泛型
* @param es 对象
* @return 集合 list
* @since 1.0.0
*/
public static <E> List<E> ofImmutableList(E[] es) {
Objects.requireNonNull(es, "args es is null.");
return Arrays.stream(es).collect(Collectors.toList());
}
/**
* Iterable 转换为List集合
*
* @param <E> 泛型
* @param elements Iterable
* @return 集合 list
* @since 1.0.0
*/
public static <E> List<E> toList(Iterable<E> elements) {
Objects.requireNonNull(elements, "elements es is null.");
if (elements instanceof Collection) {
return new ArrayList<>((Collection<E>) elements);
}
Iterator<E> iterator = elements.iterator();
List<E> list = new ArrayList<>();
while (iterator.hasNext()) {
list.add(iterator.next());
}
return list;
}
/**
* 将key value 数组转为 map
*
* @param <K> key
* @param <V> value
* @param keysValues key value 数组
* @return map 集合
* @since 1.0.0
*/
@SuppressWarnings("unchecked")
public static <K, V> Map<K, V> toMap(@NotNull Object... keysValues) {
int separate = 2;
if (keysValues.length % separate != 0) {
throw new IllegalArgumentException("wrong number of arguments for met, keysValues length can not be odd");
}
Map<K, V> keyValueMap = Maps.newHashMapWithExpectedSize(keysValues.length / 2);
for (int i = keysValues.length - separate; i >= 0; i -= separate) {
keyValueMap.put((K) keysValues[i], (V) keysValues[i + 1]);
}
return keyValueMap;
}
/**
* 对象是否为数组对象
*
* @param obj 对象
* @return 是否为数组对象 ,如果为{@code null} 返回false
* @since 1.0.0
*/
@Contract("null -> false")
public static boolean isArray(Object obj) {
if (null == obj) {
return false;
}
return obj.getClass().isArray();
}
/**
* Find value of type t
*
* @param <T> parameter
* @param map map
* @param key key
* @param type type
* @return the t
* @since 1.0.0
*/
@Contract("null, _, _ -> null")
@Nullable
public static <T> T findValueOfType(Map<String, Object> map, String key, @Nullable Class<T> type) {
if (map == null || !map.containsKey(key) || StringUtils.isBlank(String.valueOf(map.get(key)))) {
return null;
}
return DataTypeUtils.convert(type, map.get(key));
}
/**
* 通过 map 的 value 排序
*
* @param <K> parameter
* @param <V> parameter
* @param map map
* @param asc asc
* @return the map
* @version jdk1.8
* @since 1.0.0
*/
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(@NotNull Map<K, V> map, boolean asc) {
Map<K, V> result = new LinkedHashMap<>();
Stream<Map.Entry<K, V>> stream = map.entrySet().stream();
// 升序
if (asc) {
stream.sorted(Map.Entry.comparingByValue())
.forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
} else {
// 降序
stream.sorted(Map.Entry.<K, V>comparingByValue().reversed())
.forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
}
return result;
}
/**
* 通过 map 的 key 排序
*
* @param <K> parameter
* @param <V> parameter
* @param map map
* @param asc asc
* @return the map
* @version jdk1.8
* @since 1.0.0
*/
public static <K extends Comparable<? super K>, V> Map<K, V> sortByKey(@NotNull Map<K, V> map, boolean asc) {
Map<K, V> result = new LinkedHashMap<>();
Stream<Map.Entry<K, V>> stream = map.entrySet().stream();
if (asc) {
stream.sorted(Map.Entry.comparingByKey())
.forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
} else {
stream.sorted(Map.Entry.<K, V>comparingByKey().reversed())
.forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
}
return result;
}
/**
* 获取多条集合中随机值
*
* @param <T> parameter
* @param list list
* @param num num
* @return the random list
* @Description list 随机取数据
* @params list list集合 num 随机取多少条
* @since 2.0.0
*/
public static <T> List<T> getRandomList(@NotNull List<T> list, int num) {
List<T> randomList = new ArrayList<>();
if (list.size() <= num) {
return list;
} else {
for (int i = 0; i < num; i++) {
int intRandom = THREAD_LOCAL_RANDOM.nextInt(list.size() - 1);
randomList.add(list.get(intRandom));
list.remove(list.get(intRandom));
}
return randomList;
}
}
/**
* 获取集合中随机值
*
* @param <T> parameter
* @param list list
* @return the random list
* @Description list 随机取数据
* @params list list集合 num 随机取多少条
* @since 2.0.0
*/
public static <T> T getRandom(@NotNull List<T> list) {
if (isEmpty(list)) {
return null;
}
int size = list.size();
if (size == 1) {
return list.get(0);
}
return list.get(THREAD_LOCAL_RANDOM.nextInt(size - 1));
}
}
@@ -0,0 +1,720 @@
package com.aos.starter.devtools;
import com.google.common.collect.Maps;
import com.aos.element.basic.basic.asserts.Assertions;
import com.aos.element.basic.common.util.GsonUtils;
import com.aos.element.common.constant.App;
import com.aos.element.common.exception.PropertiesException;
import com.aos.starter.core.util.DateUtils;
import com.aos.starter.core.util.StringUtils;
import com.aos.starter.core.util.Tools;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.FileOutConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.ITypeConvert;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.converts.OracleTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.12.26 21:45
* @since 1.0.0
*/
@Data
@Slf4j
@Accessors(chain = true)
@SuppressWarnings("all")
public class AutoGeneratorCode {
/** ROOT_PACKAGE */
public static final String ROOT_PACKAGE = App.BASE_PACKAGES + StringPool.DOT;
/** 自定义生成文件时需要指定文件后缀 */
public static final String VM_SUFFIX = ".vm";
/** TEMPLATE_CONTROLLER */
public static final String TEMPLATE_CONTROLLER = "/templates/controller.java";
/** TEMPLATE_CONTROLLER_EX */
public static final String TEMPLATE_CONTROLLER_EX = "/templates/controller-ext.java";
/** TEMPLATE_ENTITY_JAVA */
public static final String TEMPLATE_ENTITY_JAVA = "/templates/entity.java" + VM_SUFFIX;
/** TEMPLATE_VO_JAVA */
public static final String TEMPLATE_VO_JAVA = "/templates/vo.java" + VM_SUFFIX;
/** TEMPLATE_PAGE_JAVA */
public static final String TEMPLATE_PAGE_JAVA = "/templates/page.java" + VM_SUFFIX;
/** TEMPLATE_DTO_JAVA */
public static final String TEMPLATE_DTO_JAVA = "/templates/dto.java" + VM_SUFFIX;
/** TEMPLATE_FORM_JAVA */
public static final String TEMPLATE_FORM_JAVA = "/templates/form.java" + VM_SUFFIX;
/** TEMPLATE_QUERY_JAVA */
public static final String TEMPLATE_QUERY_JAVA = "/templates/query.java" + VM_SUFFIX;
/** TEMPLATE_WRAPPER_JAVA */
public static final String TEMPLATE_WRAPPER_JAVA = "/templates/wrapper.java" + VM_SUFFIX;
/** TEMPLATE_SINGLE_WRAPPER_JAVA */
public static final String TEMPLATE_SINGLE_WRAPPER_JAVA = "/templates/single-wrapper.java" + VM_SUFFIX;
/** TEMPLATE_OUTER_WRAPPER_JAVA */
public static final String TEMPLATE_OUTER_WRAPPER_JAVA = "/templates/outer-wrapper.java" + VM_SUFFIX;
/** TEMPLATE_INNER_WRAPPER_JAVA */
public static final String TEMPLATE_INNER_WRAPPER_JAVA = "/templates/inner-wrapper.java" + VM_SUFFIX;
/** TEMPLATE_MAPPER */
public static final String TEMPLATE_MAPPER = "/templates/mapper.java";
/** TEMPLATE_XML */
public static final String TEMPLATE_XML = "/templates/mapper.xml" + VM_SUFFIX;
/** TEMPLATE_SERVICE */
public static final String TEMPLATE_SERVICE = "/templates/service.java";
/** TEMPLATE_SERVICEIMPL */
public static final String TEMPLATE_SERVICEIMPL = "/templates/serviceImpl.java";
/** TEMPLATE_GLOBAL_PROPERTIES */
public static final String TEMPLATE_GLOBAL_PROPERTIES = "/templates/application.properties" + VM_SUFFIX;
/** TEMPLATE_APPLICATION */
public static final String TEMPLATE_APPLICATION = "/templates/Application.java" + VM_SUFFIX;
/** TEMPLATE_APPLICATION_TEST */
public static final String TEMPLATE_APPLICATION_TEST = "/templates/ApplicationTest.java" + VM_SUFFIX;
/** TEMPLATE_CLOUD_YML */
public static final String TEMPLATE_CLOUD_YML = "/templates/bootstrap.yml" + VM_SUFFIX;
/** TEMPLATE_BOOT_YML */
public static final String TEMPLATE_BOOT_YML = "/templates/application.yml" + VM_SUFFIX;
/** RESOURCE_ROOT_PATH */
public static final String RESOURCE_ROOT_PATH = "/src/main/resources/";
/** ASSEMBLY_PATH */
public static final String ASSEMBLY_PATH = "/src/main/assembly/";
/** BIN_PATH */
public static final String BIN_PATH = "/src/main/bin/";
/** RESOURCE_TEST_PATH */
public static final String RESOURCE_TEST_PATH = "/src/test/resources/";
/** JAVA_ROOT_PATH */
public static final String JAVA_ROOT_PATH = "/src/main/java/";
/** JAVA_TEST_PATH */
public static final String JAVA_TEST_PATH = "/src/test/java/";
/** 设置 model 路径, 最后一级为 src 上一级 */
private String modelPath;
/** Author */
private String author;
/** Version */
private String version;
/** Model name */
private String modelName;
/** Driver name */
private String driverName;
/** User name */
private String userName;
/** Pass word */
private String passWord;
/** Url */
private String url;
/** Tables */
private String[] tables;
/** Prefix */
private String[] prefix;
/** 自定义实体父类 */
private String superEntityClass;
/** 自定义 dao 父类 */
private String superMapperClass;
/** 自定义 service 基类 */
private String superServiceClass;
/** 自定义 serviceImpl 基类 */
private String superServiceImplClass;
/** 自定义 controller 父类 */
private String superControllerClass;
/** 需要生成的 package */
private String packageName;
/** 需要生成的组件的配置 */
private String[] componets;
/** Templates */
private String[] templates;
/** 是否为 web 应用 */
private boolean webapp;
/** Package config */
private PackageConfig packageConfig;
/** Templates config */
private TemplatesConfig templatesConfig;
/** Properties config */
private PropertiesConfig propertiesConfig;
/** Module type */
private ModuleConfig.ModuleType moduleType;
/**
* 生成全局变量
*
* @return the global config
* @since 1.0.0
*/
GlobalConfig buildGlobalConfig() {
// 输出路径
GlobalConfig globalConfig = new GlobalConfig()
.setDateType(DateType.ONLY_DATE)
.setOutputDir(this.modelPath + "/src/main/java")
// 开启 ActiveRecord 支持
.setActiveRecord(true)
// 设置 author
.setAuthor(this.author)
// 是否覆盖文件
.setFileOverride(false)
// 是否开始二级缓存
.setEnableCache(false)
// 是否设置 sql 的 columnlist
.setBaseColumnList(true)
// 是否设置 resultmap
.setBaseResultMap(true)
// 设置 controller 名称 (%s 会自动填充表实体属性)
.setControllerName("%sController")
// 设置 service 名称
.setServiceName("%sRepositoryService")
// 设置 serviceImpl 名称
.setServiceImplName("%sRepositoryServiceImpl")
// 设置 mapper 名称
.setMapperName("%sDao")
// 设置 xml 名称
.setXmlName("%sMapper")
// 生成后是否打开目录
.setOpen(false);
log.info("GlobalConfig = {}", GsonUtils.toJson(globalConfig, true));
return globalConfig;
}
/**
* Build data source config data source config.
* 生成 数据源
*
* @return the data source config
* @since 1.0.0
*/
@SuppressWarnings("PMD.UndefineMagicConstantRule")
DataSourceConfig buildDataSourceConfig() {
ITypeConvert convert;
DbType dbType = JdbcUtils.getDbType(this.url);
switch (dbType) {
case ORACLE:
convert = new OracleTypeConvert() {
// 自定义数据库表字段类型转换【可选】
@Override
public IColumnType processTypeConvert(GlobalConfig globalConfig, String fieldType) {
log.info("转换类型: {}", fieldType);
// 注意!!processTypeConvert 存在默认类型转换,如果不是你要的效果请自定义返回、非如下直接返回.
return super.processTypeConvert(globalConfig, fieldType);
}
};
break;
case MYSQL:
convert = new MySqlTypeConvert() {
@Override
public IColumnType processTypeConvert(GlobalConfig globalConfig, String fieldType) {
log.info("转换类型: {}", fieldType);
String t = fieldType.toLowerCase();
// tinyint 转换为 Integer 类型
if (t.contains("tinyint")) {
log.info("转换类型: {} -> Integer", fieldType);
return DbColumnType.INTEGER;
}
// 注意!!processTypeConvert 存在默认类型转换,如果不是你要的效果请自定义返回、非如下直接返回.
return super.processTypeConvert(globalConfig, fieldType);
}
};
break;
default:
throw new UnsupportedOperationException("暂时不支持其他数据库类型转换");
}
DataSourceConfig dataSourceConfig = new DataSourceConfig().setDriverName(this.driverName)
.setUsername(this.userName)
.setPassword(this.passWord)
.setUrl(this.url)
.setTypeConvert(convert);
log.info("dataSourceConfig = {}", GsonUtils.toJson(dataSourceConfig, true));
return dataSourceConfig;
}
/**
* 生成 策略配置
*
* @return the strategy config
* @since 1.0.0
*/
StrategyConfig buildStrategyConfig() {
StrategyConfig strategyConfig = new StrategyConfig()
// 全局大写命名 ORACLE 注意
.setCapitalMode(true)
// 是否开启 lombok 支持
.setEntityLombokModel(true)
// 是否开启 @RestContriller 风格
.setRestControllerStyle(true)
// 此处可以修改为您的表前缀
.setTablePrefix(this.prefix)
// 表名生成策略 (下划线转驼峰)
.setNaming(NamingStrategy.underline_to_camel)
// 需要生成的表
.setInclude(this.tables)
// 自定义实体父类
.setSuperEntityClass(this.superEntityClass)
// 自定义实体,公共字段
.setSuperEntityColumns("id", "deleted", "update_time", "create_time")
// 自定义 dao 父类
.setSuperMapperClass(this.superMapperClass)
// 自定义 service 父类
.setSuperServiceClass(this.superServiceClass)
// 自定义 service 实现类父类
.setSuperServiceImplClass(this.superServiceImplClass)
// 自定义 controller 父类
.setSuperControllerClass(this.superControllerClass)
// 实体是否生成字段常量 (默认 false)
.setEntityColumnConstant(true)
// 实体是否为构建者模型 (默认 false)
.setEntityBuilderModel(false);
log.info("strategyConfig = {}", GsonUtils.toJson(strategyConfig, true));
return strategyConfig;
}
/**
* 生成 包配置
*
* @return the package config
* @since 1.0.0
*/
PackageConfig buildPackageConfig() {
Assertions.notBlank(this.packageName, "未配置项目 package");
String[] names = this.packageName.split("\\.");
if (names.length < 1) {
throw new PropertiesException("配置错误, 至少配置一个模块名吧!");
}
this.modelName = names[names.length - 1];
this.modelName = Tools.isBlank(this.modelName) ? "auto" : this.modelName;
// 首字母大写
this.modelName = StringUtils.firstCharToUpper(this.modelName);
this.packageConfig = new PackageConfig()
.setParent(ROOT_PACKAGE + this.packageName)
.setMapper("dao");
log.info("packageConfig = {}", GsonUtils.toJson(this.packageConfig, true));
return this.packageConfig;
}
/**
* 自定义模板配置,可以 copy 源码 mybatis-plus/src/main/resources/template 下面内容修改,
* 放置自己项目的 src/main/resources/template 目录下, 默认名称一下可以不配置,也可以自定义模板名称
*
* @return the template config
* @since 1.0.0
*/
TemplateConfig buildTemplateConfig() {
this.templatesConfig = new TemplatesConfig();
if (this.templates == null || this.templates.length == 0) {
this.templatesConfig.setController(true)
.setDao(true)
.setEntity(true)
.setImpl(true)
.setService(true)
.setImpl(true)
.setStart(true);
} else {
// 是否生成其他全局配置
for (String template : this.templates) {
switch (template) {
case TemplatesConfig.CONTROLLER:
this.templatesConfig.setController(true);
log.info("生成 controller 文件");
break;
case TemplatesConfig.SERVICE:
this.templatesConfig.setService(true);
log.info("生成 service 文件");
break;
case TemplatesConfig.IMPL:
this.templatesConfig.setImpl(true);
log.info("生成 service impl 文件");
break;
case TemplatesConfig.DAO:
this.templatesConfig.setDao(true);
log.info("生成 dao 文件");
break;
case TemplatesConfig.XML:
this.templatesConfig.setXml(true);
log.info("生成 mapper.xml 文件");
break;
case TemplatesConfig.ENTITY:
this.templatesConfig.setEntity(true);
log.info("生成 entity 文件");
break;
case TemplatesConfig.VO:
this.templatesConfig.setVo(true);
log.info("生成 vo 文件");
break;
case TemplatesConfig.DTO:
this.templatesConfig.setDto(true);
log.info("生成 dto 文件");
break;
//noinspection deprecation
case TemplatesConfig.WRAPPER:
log.error("请使用 TemplatesConfig.CONVERTER 代替");
case TemplatesConfig.CONVERTER:
this.templatesConfig.setConverter(true);
log.info("生成 converter 文件");
break;
case TemplatesConfig.START:
// 生成
this.templatesConfig.setStart(true);
log.info("生成启动类");
break;
default:
break;
}
}
}
return this.buildTemplate();
}
/**
* Build template template config
*
* @return the template config
* @since 1.0.0
*/
private TemplateConfig buildTemplate() {
TemplateConfig templateConfig = new TemplateConfig()
.setController(null)
.setService(null)
.setEntity(null)
.setMapper(null)
.setServiceImpl(null)
.setXml(null);
if (this.templatesConfig.isController()) {
templateConfig.setController(TEMPLATE_CONTROLLER_EX);
}
if (this.templatesConfig.isService()) {
templateConfig.setService(TEMPLATE_SERVICE);
}
if (this.templatesConfig.isImpl()) {
templateConfig.setServiceImpl(TEMPLATE_SERVICEIMPL);
}
if (this.templatesConfig.isDao()) {
templateConfig.setMapper(TEMPLATE_MAPPER);
}
if (this.templatesConfig.isEntity()) {
log.info("开启自定义 entity 生成");
}
if (this.templatesConfig.isDto()) {
log.info("开启自定义 dto 生成");
}
if (this.templatesConfig.isVo()) {
log.info("开启自定义 vo 生成");
}
if (this.templatesConfig.isConverter()) {
log.info("开启自定义 converter 生成");
}
if (this.templatesConfig.isXml()) {
log.info("开启自定义 xml 生成");
}
log.info("templateConfig = {}", GsonUtils.toJson(templateConfig, true));
return templateConfig;
}
/**
* 自定义配置
*
* @return the injection config
* @since 1.0.0
*/
InjectionConfig buildInjectionConfig() {
log.info("开始处理自定义配置");
// 注入自定义配置,可以在 VM 中使用 cfg.abc 【可无】
InjectionConfig injectionConfig = new InjectionConfig() {
@Override
public void initMap() {
Map<String, Object> map = Maps.newHashMapWithExpectedSize(3);
map.put("app_name", "${project.artifactId}");
map.put("app_version", "${project.version}");
// 替换包变量名, 避免被替换
map.put("profile_active", "${profile.active}");
map.put("package_dto",
AutoGeneratorCode.this.packageConfig.getParent()
+ StringPool.DOT
+ AutoGeneratorCode.this.packageConfig.getEntity()
+ StringPool.DOT + "dto");
map.put("package_vo",
AutoGeneratorCode.this.packageConfig.getParent()
+ StringPool.DOT
+ AutoGeneratorCode.this.packageConfig.getEntity()
+ StringPool.DOT + "vo");
map.put("package_form",
AutoGeneratorCode.this.packageConfig.getParent()
+ StringPool.DOT
+ AutoGeneratorCode.this.packageConfig.getEntity()
+ StringPool.DOT + "form");
map.put("package_po",
AutoGeneratorCode.this.packageConfig.getParent()
+ StringPool.DOT
+ AutoGeneratorCode.this.packageConfig.getEntity()
+ StringPool.DOT
+ "po");
map.put("package_converter", AutoGeneratorCode.this.packageConfig.getParent() + StringPool.DOT + "converter");
map.put("version", AutoGeneratorCode.this.getVersion());
map.put("date", DateUtils.format(new Date(), "yyyy.MM.dd HH:mm"));
map.put("model_name", AutoGeneratorCode.this.modelName);
map.put("package_name", AutoGeneratorCode.this.packageConfig.getParent());
// 生成 application.properties
map.put("gloabl", true);
map.put("webapp", AutoGeneratorCode.this.webapp);
map.put("pc", AutoGeneratorCode.this.propertiesConfig);
this.setMap(map);
}
};
// 调用 initMap(), 将 map 注入到 InjectionConfig
injectionConfig.initMap();
List<FileOutConfig> focList = new ArrayList<>();
String parentPath = this.packageConfig.getParent().replace(StringPool.DOT, File.separator);
this.buildCommonTemplate(focList, parentPath);
this.buildExpandTemplate(focList, parentPath);
injectionConfig.setFileOutConfigList(focList);
return injectionConfig;
}
/**
* 生成常用的模板
*
* @param focList foc list
* @param parentPath parent path
* @since 1.0.0
*/
private void buildCommonTemplate(List<FileOutConfig> focList, String parentPath) {
// 调整 xml 生成目录
if (this.templatesConfig.isXml()) {
focList.add(buildFileOutConfig(TEMPLATE_XML,
this.modelPath + RESOURCE_ROOT_PATH + "mapper",
"Mapper.xml",
true));
}
// 调整 entity 的生成目录
if (this.templatesConfig.isEntity()) {
focList.add(buildFileOutConfig(TEMPLATE_ENTITY_JAVA,
this.modelPath + JAVA_ROOT_PATH + parentPath + File.separator + "entity/po",
".java",
true));
// 生成一个 enums 目录
File dir = new File(this.modelPath + JAVA_ROOT_PATH + parentPath + File.separator + "enums");
if (!dir.mkdirs()) {
log.error("[{}] 创建失败", dir);
}
}
// 生成 vo, form, query, page
if (this.templatesConfig.isVo()) {
focList.add(buildFileOutConfig(TEMPLATE_VO_JAVA,
this.modelPath + JAVA_ROOT_PATH + parentPath + File.separator + "entity/vo",
"VO.java",
true));
focList.add(buildFileOutConfig(TEMPLATE_PAGE_JAVA,
this.modelPath + JAVA_ROOT_PATH + parentPath + File.separator + "entity/vo",
"Page.java",
true));
focList.add(buildFileOutConfig(TEMPLATE_FORM_JAVA,
this.modelPath + JAVA_ROOT_PATH + parentPath + File.separator + "entity/form",
"Form.java",
true));
focList.add(buildFileOutConfig(TEMPLATE_QUERY_JAVA,
this.modelPath + JAVA_ROOT_PATH + parentPath + File.separator + "entity/form",
"Query.java",
true));
}
// 生成 dto
if (this.templatesConfig.isDto()) {
focList.add(buildFileOutConfig(TEMPLATE_DTO_JAVA,
this.modelPath + JAVA_ROOT_PATH + parentPath + File.separator + "entity/dto",
"DTO.java",
true));
}
// 生成 converter
if (this.templatesConfig.isConverter()) {
if (ModuleConfig.ModuleType.SINGLE_MODULE.equals(this.moduleType)) {
focList.add(buildFileOutConfig(TEMPLATE_SINGLE_WRAPPER_JAVA,
this.modelPath + JAVA_ROOT_PATH + parentPath + File.separator + "converter",
"Converter.java",
true));
} else {
focList.add(buildFileOutConfig(TEMPLATE_OUTER_WRAPPER_JAVA,
this.modelPath + JAVA_ROOT_PATH + parentPath + File.separator + "converter",
"ViewConverter.java",
true));
focList.add(buildFileOutConfig(TEMPLATE_INNER_WRAPPER_JAVA,
this.modelPath + JAVA_ROOT_PATH + parentPath + File.separator + "converter",
"ServiceConverter.java",
true));
}
}
}
/**
* 生成扩展模板
*
* @param focList foc list
* @param parentPath parent path
* @since 1.0.0
*/
private void buildExpandTemplate(List<FileOutConfig> focList, String parentPath) {
this.buildPropertiesTemplate();
if (this.templatesConfig.isStart()) {
log.info("生成启动类");
focList.add(buildFileOutConfig(TEMPLATE_APPLICATION,
this.modelPath + JAVA_ROOT_PATH + parentPath,
this.modelName + "Application.java",
false));
log.info("生成单元测试主类");
focList.add(buildFileOutConfig(TEMPLATE_APPLICATION_TEST,
this.modelPath + JAVA_TEST_PATH + parentPath,
this.modelName + "ApplicationTest.java",
false));
if (this.propertiesConfig.isCloudConfig()) {
log.info("生成 spring cloud 配置文件");
focList.add(buildFileOutConfig(TEMPLATE_CLOUD_YML,
this.modelPath + RESOURCE_ROOT_PATH,
"bootstrap.yml",
false));
}
if (this.propertiesConfig.isBootConfig()) {
log.info("生成 spring boot 配置文件");
focList.add(buildFileOutConfig(TEMPLATE_BOOT_YML,
this.modelPath + RESOURCE_ROOT_PATH,
"application.yml",
false));
}
}
}
/**
* 初始化配置模板
*
* @since 1.0.0
*/
private void buildPropertiesTemplate() {
this.propertiesConfig = new PropertiesConfig();
if (CollectionUtils.isNotEmpty(Collections.singleton(this.componets))) {
Arrays.stream(this.componets).forEach(c -> {
switch (c) {
case PropertiesConfig.ACTIVEMQ:
this.propertiesConfig.setActivemq(true);
log.info("生成 activemq 相关配置, 需要 fkh-element-activemq 依赖");
break;
case PropertiesConfig.EMAIL:
this.propertiesConfig.setEmail(true);
log.info("生成 email 相关配置, 需要 fkh-element-email 依赖");
break;
case PropertiesConfig.REDIS:
this.propertiesConfig.setRedis(true);
log.info("生成 redis 相关配置, 需要 fkh-element-redis 依赖, "
+ "默认为 standalone 模式, 其他模式配置参照 fkh-element-redis/src/test/resource 配置");
break;
case PropertiesConfig.ROCKTEMQ:
this.propertiesConfig.setRocktemq(true);
log.info("生成 rocketmq 相关配置, 需要 fkh-element-rocketmq 依赖");
break;
case PropertiesConfig.WEBSERVICE:
this.propertiesConfig.setWebservice(true);
log.info("生成 webservice 相关配置, 需要 fkh-element-webservice 依赖");
break;
case PropertiesConfig.WEBSOCKET:
this.propertiesConfig.setWebsocket(true);
log.info("生成 websocklet 相关配置, 需要 fkh-element-websocket 依赖");
break;
case PropertiesConfig.MYBATIS:
this.propertiesConfig.setMybatis(true);
log.info("生成 mybatis + jdbc + druid 相关配置, 需要 fkh-element-mybatis 依赖");
log.info("如果是多数据源, 需要 ms-mybatis-multi 依赖, 如果不能满足需求, 可以参照 fkh-element-mybatis-multi");
break;
case PropertiesConfig.DUBBO:
this.propertiesConfig.setDubbo(true);
log.info("生成 dubbo 相关配置, 需要 ms-dubbo 依赖");
break;
case PropertiesConfig.ADMIN:
this.propertiesConfig.setAdmin(true);
log.warn("需要 spring-boot-starter-web, spring-boot-starter-actuator, "
+ "spring-boot-admin-starter-client, spring-boot-starter-security 依赖");
break;
case PropertiesConfig.BOOT_CONFIG:
this.propertiesConfig.setBootConfig(true);
break;
case PropertiesConfig.CLOUD_CONFIG:
this.propertiesConfig.setCloudConfig(true);
break;
default:
break;
}
});
}
}
/**
* Build file out config file out config.
*
* @param template the template
* @param finalPath the final path
* @param suffix the suffix
* @param isSuffix is suffix
* @return the file out config
* @since 1.0.0
*/
@Contract(value = "_, _, _, _ -> new", pure = true)
@NotNull
private static FileOutConfig buildFileOutConfig(String template, String finalPath, String suffix, boolean isSuffix) {
return new FileOutConfig(template) {
@Override
public String outputFile(TableInfo tableInfo) {
File dir = new File(finalPath);
if (!dir.exists()) {
boolean result = dir.mkdirs();
if (result) {
log.info("创建目录: [{}]", dir);
}
}
if (isSuffix) {
return dir + File.separator + tableInfo.getEntityName() + suffix;
}
return dir + File.separator + suffix;
}
};
}
}
@@ -0,0 +1,361 @@
package com.aos.starter.devtools;
import com.aos.element.common.constant.App;
import com.aos.starter.core.util.Tools;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import org.apache.commons.lang3.SystemUtils;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Properties;
import lombok.extern.slf4j.Slf4j;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.12.26 21:45
* @since 1.0.0
*/
@Slf4j
@SuppressWarnings("all")
public final class AutoGeneratorCodeBuilder {
/** Model path */
private String modelPath;
/** Author */
private String author = App.FKH_NAME_SPACE;
/** Version */
private String version = "1.0.0";
/** Tables */
private String[] tables;
/** 数据表前缀 */
private String[] prefix;
/** 自定义实体基类 */
private String superEntityClass = App.BASE_PACKAGES + ".starter.common.base.BasePO";
/** 自定义 dao 基类 */
private String superMapperClass = App.BASE_PACKAGES + ".starter.common.base.BaseDao";
/** 自定义 service 基类 */
private String superServiceClass = App.BASE_PACKAGES + ".starter.mybatis.service.BaseService";
/** 自定义 serviceImpl 基类 */
private String superServiceImplClass = App.BASE_PACKAGES + ".starter.mybatis.service.impl.BaseServiceImpl";
/** 自动以 controller 父类 */
private String superControllerClass = App.BASE_PACKAGES + ".starter.rest.ServletController";
/** 需要生成的 package */
private String packageName;
/** Componets */
private String[] componets;
/** Template */
private String[] template;
/** Module type */
private ModuleConfig.ModuleType moduleType;
/** Webapp */
private boolean webapp = false;
/**
* Auto generator code builder
*
* @since 1.0.0
*/
@Contract(pure = true)
private AutoGeneratorCodeBuilder() {
}
/**
* An auto generator code auto generator code builder.
*
* @return the auto generator code builder
* @since 1.0.0
*/
@NotNull
@Contract(value = " -> new", pure = true)
public static AutoGeneratorCodeBuilder onAutoGeneratorCode() {
return new AutoGeneratorCodeBuilder();
}
/**
* With model path auto generator code builder.
*
* @param modelPath the model path
* @return the auto generator code builder
* @since 1.0.0
*/
@Contract("_ -> this")
public AutoGeneratorCodeBuilder withModelPath(String modelPath) {
this.modelPath = modelPath;
return this;
}
/**
* With author auto generator code builder
*
* @param author author
* @return the auto generator code builder
* @since 1.0.0
*/
@Contract("_ -> this")
public AutoGeneratorCodeBuilder withAuthor(String author) {
this.author = author;
return this;
}
/**
* With version auto generator code builder
*
* @param version version
* @return the auto generator code builder
* @since 1.0.0
*/
@Contract("_ -> this")
public AutoGeneratorCodeBuilder withVersion(String version) {
this.version = version;
return this;
}
/**
* With tables auto generator code builder.
*
* @param tables the tables'
* @return the auto generator code builder
* @since 1.0.0
*/
@Contract("_ -> this")
public AutoGeneratorCodeBuilder withTables(String[] tables) {
this.tables = tables;
return this;
}
/**
* With prefix auto generator code builder
*
* @param prefix prefix
* @return the auto generator code builder
* @since 1.0.0
*/
@Contract("_ -> this")
public AutoGeneratorCodeBuilder withPrefix(String[] prefix) {
this.prefix = prefix;
return this;
}
/**
* With super entity class auto generator code builder.
*
* @param superEntityClass the super entity class
* @return the auto generator code builder
* @since 1.0.0
*/
@Contract("_ -> this")
public AutoGeneratorCodeBuilder withSuperEntityClass(String superEntityClass) {
this.superEntityClass = superEntityClass;
return this;
}
/**
* With super mapper class auto generator code builder.
*
* @param superMapperClass the super mapper class
* @return the auto generator code builder
* @since 1.0.0
*/
@Contract("_ -> this")
public AutoGeneratorCodeBuilder withSuperMapperClass(String superMapperClass) {
this.superMapperClass = superMapperClass;
return this;
}
/**
* With super service class auto generator code builder
*
* @param superServiceClass super service class
* @return the auto generator code builder
* @since 1.0.0
*/
@Contract("_ -> this")
public AutoGeneratorCodeBuilder withSuperServiceClass(String superServiceClass) {
this.superServiceClass = superServiceClass;
return this;
}
/**
* With super service impl class auto generator code builder
*
* @param superServiceImplClass super service impl class
* @return the auto generator code builder
* @since 1.0.0
*/
@Contract("_ -> this")
public AutoGeneratorCodeBuilder withSuperServiceImplClass(String superServiceImplClass) {
this.superServiceImplClass = superServiceImplClass;
return this;
}
/**
* With super controller class auto generator code builder.
*
* @param superControllerClass the super controller class
* @return the auto generator code builder
* @since 1.0.0
*/
@Contract("_ -> this")
public AutoGeneratorCodeBuilder withSuperControllerClass(String superControllerClass) {
this.superControllerClass = superControllerClass;
return this;
}
/**
* With package name auto generator code builder.
*
* @param packageName the package name
* @return the auto generator code builder
* @since 1.0.0
*/
@Contract("_ -> this")
public AutoGeneratorCodeBuilder withPackageName(String packageName) {
this.packageName = packageName;
return this;
}
/**
* With componets auto generator code builder.
*
* @param componets the componets
* @return the auto generator code builder
* @since 1.0.0
*/
@Contract("_ -> this")
public AutoGeneratorCodeBuilder withComponets(String... componets) {
this.componets = componets;
return this;
}
/**
* With module type auto generator code builder
*
* @param moduleType module type
* @return the auto generator code builder
* @since 1.0.0
*/
@Contract("_ -> this")
public AutoGeneratorCodeBuilder withModuleType(ModuleConfig.ModuleType moduleType) {
this.moduleType = moduleType;
return this;
}
/**
* With webapp auto generator code builder.
*
* @param webapp the webapp
* @return the auto generator code builder
* @since 1.0.0
*/
@Contract("_ -> this")
public AutoGeneratorCodeBuilder withWebapp(boolean webapp) {
this.webapp = webapp;
return this;
}
/**
* With template auto generator code builder
*
* @param template template
* @return the auto generator code builder
* @since 1.0.0
*/
@Contract("_ -> this")
public AutoGeneratorCodeBuilder withTemplate(String... template) {
this.template = template;
return this;
}
/**
* Build.
*
* @since 1.0.0
*/
public void build() {
AutoGeneratorCode autoGeneratorCode = new AutoGeneratorCode();
String path = new File(this.modelPath).getAbsolutePath();
autoGeneratorCode.setModelPath(path);
Properties properties = this.getProperties();
autoGeneratorCode.setDriverName(properties.getProperty("spring.datasource.driver-class-name"));
autoGeneratorCode.setUserName(properties.getProperty("spring.datasource.username"));
autoGeneratorCode.setPassWord(properties.getProperty("spring.datasource.password"));
autoGeneratorCode.setUrl(properties.getProperty("spring.datasource.url"));
autoGeneratorCode.setAuthor(Tools.isBlank(this.author) ? SystemUtils.USER_NAME : this.author);
autoGeneratorCode.setVersion(this.version);
autoGeneratorCode.setTables(this.tables);
autoGeneratorCode.setPrefix(this.prefix);
autoGeneratorCode.setSuperEntityClass(this.superEntityClass);
autoGeneratorCode.setSuperMapperClass(this.superMapperClass);
autoGeneratorCode.setSuperServiceClass(this.superServiceClass);
autoGeneratorCode.setSuperServiceImplClass(this.superServiceImplClass);
autoGeneratorCode.setSuperControllerClass(this.superControllerClass);
autoGeneratorCode.setPackageName(this.packageName);
autoGeneratorCode.setComponets(this.componets);
autoGeneratorCode.setWebapp(this.webapp);
autoGeneratorCode.setTemplates(this.template);
autoGeneratorCode.setModuleType(this.moduleType);
AutoGenerator autoGenerator = new AutoGenerator();
autoGenerator.setGlobalConfig(autoGeneratorCode.buildGlobalConfig())
.setDataSource(autoGeneratorCode.buildDataSourceConfig())
.setStrategy(autoGeneratorCode.buildStrategyConfig())
.setPackageInfo(autoGeneratorCode.buildPackageConfig())
.setTemplate(autoGeneratorCode.buildTemplateConfig())
.setCfg(autoGeneratorCode.buildInjectionConfig())
.setTemplateEngine(new VelocityTemplateEngine())
.execute();
log.debug("{}", autoGenerator.getCfg().getMap().get("app_name"));
}
/**
* 获取配置文件
*
* @return 配置Props properties
* @since 1.0.0
*/
@NotNull
private Properties getProperties() {
InputStream inputStream;
inputStream = this.getClass().getClassLoader().getResourceAsStream("jdbc.properties");
if (inputStream == null) {
URL url = this.getClass().getClassLoader().getResource("jdbc-default.properties");
if (url != null) {
try {
inputStream = url.openStream();
} catch (IOException ignored) {
// nothing to do
}
}
}
// 读取配置文件
Properties props = new Properties();
try {
props.load(inputStream);
} catch (IOException e) {
log.error(e.getMessage(), e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
return props;
}
}
@@ -0,0 +1,58 @@
package ${cfg.package_name};
import com.fkhwl.starter.launcher.FkhStarter;
import org.jetbrains.annotations.NotNull;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import lombok.extern.slf4j.Slf4j;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 模板启动类 (Auto))</p>
*
* @author ${author}
* @version ${cfg.version}
* @email "mailto:${author}@fkhwl.com"
* @date ${cfg.date}
* @since ${cfg.version}
*/
@Slf4j
@SpringBootApplication
public class ${cfg.model_name}Application extends FkhStarter {
//region todo-${author} : (${cfg.date}) [根据需求实现以下扩展, 可全部删除]
/**
* 启动前处理逻辑
*
* @since ${cfg.version}
*/
@Override
public void before(){
log.info("before");
}
/**
* 启动完成后处理逻辑
*
* @since ${cfg.version}
*/
@Override
public void after(){
log.info("after");
}
/**
* 启动完成后发送自定义事件
*
* @param context the context
* @since ${cfg.version}
*/
@Override
public void publishEvent(@NotNull ConfigurableApplicationContext context) {
// Object 替换为自定义事件实体, 需要继承 BaseEvent
context.publishEvent(new Object());
}
//endregion
}
@@ -0,0 +1,55 @@
package ${cfg.package_name};
import com.fkhwl.starter.basic.constant.ConfigKey;
import com.fkhwl.starter.common.context.SpringContext;
import com.fkhwl.starter.test.FkhTest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import lombok.extern.slf4j.Slf4j;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 单元测试主类 </p>
*
* @author ${author}
* @version ${cfg.version}
* @email "mailto:${author}@fkhwl.com"
* @date ${cfg.date}
* @since ${cfg.version}
*/
@Slf4j
@FkhTest
public class ${cfg.model_name}ApplicationTest {
/**
* Set up
*
* @since ${cfg.version}
*/
@BeforeEach
void setUp(){
log.info("start ${cfg.model_name}Application test");
}
/**
* Tear down
*
* @since ${cfg.version}
*/
@AfterEach
void tearDown(){
log.info("end ${cfg.model_name}Application test");
}
/**
* Test
*
* @since ${cfg.version}
*/
@Test
void test() {
log.info("{}", SpringContext.getApplicationContext().getEnvironment().getProperty(ConfigKey.SpringConfigKey.APPLICATION_NAME));
}
}
@@ -0,0 +1,6 @@
server:
port: 0
spring:
profiles:
active: $!{profile_active}
@@ -0,0 +1,6 @@
server:
port: 0
spring:
profiles:
active: ${profile_active}
@@ -0,0 +1,96 @@
package $!{package.Controller};
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fkhwl.starter.basic.Result;
import com.fkhwl.starter.rest.ServletController;
import com.fkhwl.starter.rest.annotation.RestControllerWrapper;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import $!{package.Entity}.dto.$!{entity}DTO;
import $!{package.Entity}.form.$!{entity}Query;
import $!{package.Entity}.vo.$!{entity}VO;
import $!{package.Service}.$!{table.serviceName};
#set($wrapperPackage=$package.Entity.replace("entity","converter"))
import $!{wrapperPackage}.$!{entity}ViewConverter;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: $!{table.comment} 控制器 </p>
*
* @author ${author}
* @version ${cfg.version}
* @email "mailto:${author}@fkhwl.com"
* @date ${cfg.date}
* @since ${cfg.version}
*/
@AllArgsConstructor
@RestControllerWrapper
@Api(value = "$!{table.comment}", tags = "$!{table.comment}接口")
public class $!{table.controllerName} extends $!{superControllerClass} {
/** $!{entity} service */
private final $!{table.serviceName} $!{table.entityPath}Service;
/**
* 分页查询方式 1
*
* @param query the query
* @return the result
* @since ${cfg.version}
*/
@GetMapping("/$!{table.entityPath}s/page_1")
@ApiOperation(value = "分页查询实现方式 1", notes = " $!{table.entityPath} 查询条件")
public IPage<$!{entity}VO> pages1($!{entity}Query query) {
IPage<$!{entity}DTO> page = this.$!{table.entityPath}Service.page(query);
return page.convert($!{entity}ViewConverter.INSTANCE::vo);
}
/**
* 分页查询方式 2
*
* @param query query
* @return the result
* @since ${cfg.version}
*/
@GetMapping("/$!{table.entityPath}s/page_2")
@ApiOperation(value = "分页查询实现方式 2", notes = " $!{table.entityPath} 查询条件")
public IPage<$!{entity}VO> pages2($!{entity}Query query) {
IPage<$!{entity}DTO> page = this.$!{table.entityPath}Service.page(query);
return $!{entity}ViewConverter.INSTANCE.vo(page);
}
/**
* 根据条件查询全部数据
*
* @return the result
* @since ${cfg.version}
*/
@GetMapping("/$!{table.entityPath}s/list")
@ApiOperation(value = "获取所有 $!{table.entityPath} 集合")
public List<$!{entity}VO> list($!{entity}Query query) {
List<$!{entity}DTO> list = this.$!{table.entityPath}Service.list(query);
return $!{entity}ViewConverter.INSTANCE.vo(list);
}
/**
* 批量删除
*
* @param user 参数
* @return the result
* @since ${cfg.version}
*/
@DeleteMapping
@ApiOperation(value = "删除", notes = "传入 ids")
public Result<Void> remove(@ApiParam(value = "主键集合", required = true) @RequestBody List<Long> ids) {
return this.$!{table.entityPath}Service.removeByIds(ids) ? this.ok() : this.fail("批量删除失败");
}
}