Feat:增加动态代码编译引擎相关逻辑
This commit is contained in:
parent
66a1f23216
commit
392b1ebc09
@ -59,6 +59,14 @@
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.itranswarp</groupId>
|
||||
<artifactId>compiler</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.reflections</groupId>
|
||||
<artifactId>reflections</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,19 @@
|
||||
package com.flyfish.framework.bean;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 用来表示枚举
|
||||
* @author wangyu
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class EnumValue {
|
||||
|
||||
private String value;
|
||||
|
||||
private String text;
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.flyfish.framework.compiler;
|
||||
|
||||
import com.flyfish.framework.compiler.support.DelegateJavaCompiler;
|
||||
import com.flyfish.framework.compiler.support.SimpleJavaCompiler;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 动态的java编译器
|
||||
* 提供动态的java编译
|
||||
*
|
||||
* @author wangyu
|
||||
*/
|
||||
public interface DynamicJavaCompiler {
|
||||
|
||||
/**
|
||||
* 代理的java编译器,使用库文件
|
||||
* @return 结果
|
||||
*/
|
||||
static DynamicJavaCompiler delegate() {
|
||||
return DelegateJavaCompiler.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单的java编译器
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
static DynamicJavaCompiler simple() {
|
||||
return SimpleJavaCompiler.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 编译java源码,通过字符串
|
||||
*
|
||||
* @param name 文件名
|
||||
* @param source 源码
|
||||
* @return 结果
|
||||
*/
|
||||
Class<?> compile(String name, String source) throws ClassNotFoundException, IOException;
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package com.flyfish.framework.compiler.support;
|
||||
|
||||
import com.flyfish.framework.compiler.DynamicJavaCompiler;
|
||||
import com.itranswarp.compiler.JavaStringCompiler;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 使用第三方成熟框架
|
||||
*
|
||||
* @author wangyu
|
||||
*/
|
||||
public class DelegateJavaCompiler implements DynamicJavaCompiler {
|
||||
|
||||
// 第三方编译器
|
||||
private final JavaStringCompiler compiler = new JavaStringCompiler();
|
||||
|
||||
|
||||
private DelegateJavaCompiler() {
|
||||
}
|
||||
|
||||
public static DelegateJavaCompiler getInstance() {
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 编译java源码,通过字符串
|
||||
*
|
||||
* @param name 文件名
|
||||
* @param source 源码
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public Class<?> compile(String name, String source) throws IOException, ClassNotFoundException {
|
||||
Map<String, byte[]> byteMap = compiler.compile(name, source);
|
||||
String className = StringUtils.substringBeforeLast(name, ".");
|
||||
for (String key : byteMap.keySet()) {
|
||||
if (key.contains(className)) {
|
||||
return compiler.loadClass(key, byteMap);
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("【java编译器】源码中没有可以编译的类!");
|
||||
}
|
||||
|
||||
|
||||
private static class SingletonHolder {
|
||||
|
||||
private static final DelegateJavaCompiler INSTANCE = new DelegateJavaCompiler();
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) throws ClassNotFoundException, IOException {
|
||||
long time = System.currentTimeMillis();
|
||||
System.out.println(StreamUtils.copyToString(DelegateJavaCompiler.class.getResourceAsStream("./"), StandardCharsets.UTF_8));
|
||||
Class<?> clazz = getInstance().compile("Fuck.java", "package com.flyfish.project; public class Fuck {}");
|
||||
System.out.println(clazz + "耗时:" + (System.currentTimeMillis() - time) / 1000.0 + "秒");
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package com.flyfish.framework.compiler.support;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* java源代码对象,可以继承进行扩展
|
||||
* @author wangyu
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor(staticName = "create")
|
||||
@Accessors(chain = true)
|
||||
public class JavaSource {
|
||||
|
||||
// 类名
|
||||
private String className;
|
||||
|
||||
// 源码
|
||||
private String source;
|
||||
|
||||
// 包名
|
||||
private String packageName;
|
||||
|
||||
// 父类名
|
||||
private String superClass;
|
||||
|
||||
// bean的class
|
||||
private String beanClass;
|
||||
|
||||
// 查询实体class
|
||||
private String queryBeanClass;
|
||||
|
||||
// controller需要,提供请求地址
|
||||
private String uri;
|
||||
|
||||
public String getSuperClassName() {
|
||||
return StringUtils.substringAfterLast(superClass, ".");
|
||||
}
|
||||
|
||||
public String getBeanClassName() {
|
||||
return StringUtils.substringAfterLast(beanClass, ".");
|
||||
}
|
||||
|
||||
public String getQueryBeanClassName() {
|
||||
return StringUtils.substringAfterLast(queryBeanClass, ".");
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package com.flyfish.framework.compiler.support;
|
||||
|
||||
import com.flyfish.framework.compiler.DynamicJavaCompiler;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.JavaFileManager;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.ToolProvider;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 简单的java编译器,单文件,无缓存版
|
||||
* 只为了偷懒,快速撸代码
|
||||
*
|
||||
* @author wangyu
|
||||
*/
|
||||
public class SimpleJavaCompiler implements DynamicJavaCompiler {
|
||||
|
||||
// 当前的java编译器
|
||||
private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||
// java文件管理器
|
||||
private final JavaFileManager fileManager = compiler.getStandardFileManager(null, Locale.SIMPLIFIED_CHINESE, StandardCharsets.UTF_8);
|
||||
// 编译参数
|
||||
private final List<String> options = Arrays.asList("-d", "./bin");
|
||||
// 编译池
|
||||
private final Map<String, Class<?>> classMap = new ConcurrentHashMap<>();
|
||||
|
||||
private SimpleJavaCompiler() {
|
||||
}
|
||||
|
||||
public static SimpleJavaCompiler getInstance() {
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 编译java源码,通过字符串
|
||||
*
|
||||
* @param name 文件名R
|
||||
* @param source 源码
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public Class<?> compile(String name, String source) throws ClassNotFoundException {
|
||||
// 存在缓存,写入
|
||||
if (classMap.containsKey(name)) {
|
||||
return classMap.get(name);
|
||||
}
|
||||
// 构建java文件对象
|
||||
JavaFileObject fileObject = new StringJavaObject(name, source);
|
||||
// 设置编译环境
|
||||
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null,
|
||||
options, null, Collections.singletonList(fileObject));
|
||||
// 阻塞编译
|
||||
if (task.call()) {
|
||||
Class<?> clazz = Class.forName("com.flyfish.project." + name);
|
||||
classMap.put(name, clazz);
|
||||
return clazz;
|
||||
}
|
||||
throw new RuntimeException("【java编译器】尝试编译源代码出现异常!");
|
||||
}
|
||||
|
||||
private static class SingletonHolder {
|
||||
|
||||
private static final SimpleJavaCompiler INSTANCE = new SimpleJavaCompiler();
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.flyfish.framework.compiler.support;
|
||||
|
||||
import javax.tools.SimpleJavaFileObject;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
* 以文本存在的java对象
|
||||
*
|
||||
* @author wangyu
|
||||
*/
|
||||
public class StringJavaObject extends SimpleJavaFileObject {
|
||||
|
||||
private final String content;
|
||||
|
||||
public StringJavaObject(String filename, String content) {
|
||||
super(stringJavaObjectUri(filename), Kind.SOURCE);
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串java对象uri
|
||||
*
|
||||
* @param name 文件名
|
||||
* @return 结果
|
||||
*/
|
||||
private static URI stringJavaObjectUri(String name) {
|
||||
return URI.create("string:///" + name + Kind.SOURCE.extension);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
|
||||
return content;
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
package com.flyfish.framework.compiler.template;
|
||||
|
||||
import com.flyfish.framework.compiler.support.JavaSource;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.data.util.CastUtils;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 模板编译器
|
||||
*
|
||||
* @author wangyu
|
||||
*/
|
||||
public class TemplateCompiler {
|
||||
|
||||
/**
|
||||
* 编译模板文件和源码数据为源代码字符串
|
||||
*
|
||||
* @param dataClass 数据class
|
||||
* @param filename 文件名
|
||||
* @return 结果
|
||||
*/
|
||||
public static Function<JavaSource, String> compile(Class<?> dataClass, String filename) {
|
||||
// 获取文件内容
|
||||
InputStream fis = TemplateCompiler.class.getResourceAsStream(filename);
|
||||
try {
|
||||
// 获取模板内容
|
||||
String template = StreamUtils.copyToString(fis, StandardCharsets.UTF_8);
|
||||
// 准备变量池
|
||||
Map<String, PropertyDescriptor> pool = Arrays.stream(BeanUtils.getPropertyDescriptors(dataClass))
|
||||
.collect(Collectors.toMap(descriptor -> "#{" + descriptor.getName() + "}", a -> a));
|
||||
// 编译
|
||||
return cfg -> pool.keySet().stream().reduce(template, (result, key) -> {
|
||||
// 获取读取方法
|
||||
Method method = pool.get(key).getReadMethod();
|
||||
Object value = null;
|
||||
try {
|
||||
// 取得结果
|
||||
value = method.invoke(cfg);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
// 替换变量
|
||||
return result.replace(key, parseValue(value));
|
||||
}, (a, b) -> a);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("模板编译失败!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析单个值
|
||||
*
|
||||
* @param value 值
|
||||
* @return 结果
|
||||
*/
|
||||
private static String parseValue(Object value) {
|
||||
if (null == value) {
|
||||
return "";
|
||||
}
|
||||
if (value instanceof Map) {
|
||||
Map<String, String> map = CastUtils.cast(value);
|
||||
return map.entrySet().stream()
|
||||
.map(entry -> entry.getKey() + " " + entry.getValue())
|
||||
.collect(Collectors.joining(" "));
|
||||
}
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编译模板文件和源码数据为源代码字符串
|
||||
*
|
||||
* @param filename 文件名
|
||||
* @return 结果
|
||||
*/
|
||||
public static Function<JavaSource, String> compile(String filename) {
|
||||
return compile(JavaSource.class, filename);
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.flyfish.framework.utils;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* map构造器
|
||||
*
|
||||
* @author wangyu
|
||||
*/
|
||||
public class MapBuilder<K, V> {
|
||||
|
||||
// 内部的map
|
||||
private final Map<K, V> map = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* 构造器
|
||||
*
|
||||
* @param <K> 键
|
||||
* @param <V> 值
|
||||
* @return 结果
|
||||
*/
|
||||
public static <K, V> MapBuilder<K, V> builder() {
|
||||
return new MapBuilder<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 放置参数
|
||||
*
|
||||
* @param k 键
|
||||
* @param v 值
|
||||
* @return 结果
|
||||
*/
|
||||
public MapBuilder<K, V> put(K k, V v) {
|
||||
this.map.put(k, v);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
public Map<K, V> build() {
|
||||
return map;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.flyfish.framework.utils;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 字符串格式化工具类
|
||||
*
|
||||
* @author wangyu
|
||||
*/
|
||||
public abstract class StringFormats {
|
||||
|
||||
// 匹配表达式
|
||||
private static final Pattern pattern = Pattern.compile("[A-Z]([a-z\\d]+)?");
|
||||
|
||||
/**
|
||||
* 驼峰转连字符
|
||||
*
|
||||
* @param value 字符串
|
||||
* @return 结果
|
||||
*/
|
||||
public static String camel2Line(String value) {
|
||||
if (StringUtils.isBlank(value)) {
|
||||
return value;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Matcher matcher = pattern.matcher(value);
|
||||
while (matcher.find()) {
|
||||
String word = matcher.group();
|
||||
sb.append(word.toLowerCase());
|
||||
sb.append(matcher.end() == value.length() ? "" : "-");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.flyfish.framework.annotations;
|
||||
|
||||
import com.flyfish.framework.config.EnumConfig;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 启用枚举端点,处理枚举类型
|
||||
*
|
||||
* @author wangyu
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Import(EnumConfig.class)
|
||||
public @interface EnableEnumEndpoint {
|
||||
|
||||
/**
|
||||
* 默认扫描包
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
String[] scanPackages() default "com.flyfish.project";
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package com.flyfish.framework.config;
|
||||
|
||||
import com.flyfish.framework.bean.EnumValue;
|
||||
import com.flyfish.framework.enums.NamedEnum;
|
||||
import com.flyfish.framework.utils.StringFormats;
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
import org.reflections.Reflections;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 枚举相关,专门处理枚举
|
||||
* @author wangyu
|
||||
*/
|
||||
public class EnumConfig implements InitializingBean, ImportBeanDefinitionRegistrar {
|
||||
|
||||
// 映射管理,避免class.forName扫描包路径
|
||||
private final Map<String, Map<String, String>> mapper = new HashMap<>();
|
||||
|
||||
private final Map<String, List<EnumValue>> values = new HashMap<>();
|
||||
|
||||
public EnumConfig() {
|
||||
Reflections reflections = new Reflections("com.flyfish.project");
|
||||
// 得到Resource注解的类
|
||||
Set<Class<? extends NamedEnum>> classSet = reflections.getSubTypesOf(NamedEnum.class);
|
||||
// 注入
|
||||
classSet.stream().filter(clazz -> ClassUtils.isAssignable(clazz, Enum.class)).forEach(clazz -> {
|
||||
String name = StringFormats.camel2Line(clazz.getSimpleName());
|
||||
List<EnumValue> values = Arrays.stream(clazz.getEnumConstants()).reduce(new ArrayList<>(), (result, item) -> {
|
||||
result.add(new EnumValue(((Enum<?>) item).name(), item.getName()));
|
||||
return result;
|
||||
}, (a, b) -> a);
|
||||
this.mapper.put(name, values.stream().collect(Collectors.toMap(EnumValue::getValue, EnumValue::getText)));
|
||||
this.values.put(name, values);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.flyfish.framework.beans.annotations;
|
||||
|
||||
import com.flyfish.framework.config.RestBeanAutoConfigure;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 启动rest bean的扫描
|
||||
* @author wangyu
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Import(RestBeanAutoConfigure.class)
|
||||
public @interface EnableRestBeanDetect {
|
||||
|
||||
/**
|
||||
* 扫描的基本路径
|
||||
* @return 结果
|
||||
*/
|
||||
String[] basePackages() default "com.flyfish.project";
|
||||
}
|
@ -1,5 +1,12 @@
|
||||
package com.flyfish.framework.beans.annotations;
|
||||
|
||||
import com.flyfish.framework.controller.BaseController;
|
||||
import com.flyfish.framework.controller.SafeController;
|
||||
import com.flyfish.framework.domain.base.Qo;
|
||||
import com.flyfish.framework.repository.DefaultRepository;
|
||||
import com.flyfish.framework.service.BaseService;
|
||||
import com.flyfish.framework.service.impl.BaseServiceImpl;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
@ -15,7 +22,34 @@ public @interface RestBean {
|
||||
/**
|
||||
* 生成的REST资源名称
|
||||
*
|
||||
* @return
|
||||
* @return 资源名称
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
/**
|
||||
* 必须指定qo
|
||||
* @return 结果
|
||||
*/
|
||||
Class<? extends Qo<?>> queryClass();
|
||||
|
||||
/**
|
||||
* 仓库的超类,默认是default
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
Class<? extends DefaultRepository> repoClass() default DefaultRepository.class;
|
||||
|
||||
/**
|
||||
* 服务类,动态生成服务
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
Class<? extends BaseService> serviceClass() default BaseServiceImpl.class;
|
||||
|
||||
/**
|
||||
* controller的类,支持自定义
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
Class<? extends SafeController> controllerClass() default BaseController.class;
|
||||
}
|
||||
|
@ -0,0 +1,220 @@
|
||||
package com.flyfish.framework.beans.repository;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.data.config.ParsingUtils;
|
||||
import org.springframework.data.repository.config.*;
|
||||
import org.springframework.data.repository.core.support.RepositoryFragment;
|
||||
import org.springframework.data.repository.core.support.RepositoryFragmentsFactoryBean;
|
||||
import org.springframework.data.util.Optionals;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Builder to create {@link BeanDefinitionBuilder} instance to eventually create Spring Data repository instances.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Peter Rietzler
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class CustomRepositoryBuilder {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CustomRepositoryBuilder.class);
|
||||
|
||||
private final BeanDefinitionRegistry registry;
|
||||
private final RepositoryConfigurationExtension extension;
|
||||
private final ResourceLoader resourceLoader;
|
||||
|
||||
private final MetadataReaderFactory metadataReaderFactory;
|
||||
private final FragmentMetadata fragmentMetadata;
|
||||
private final CustomRepositoryImplementationDetector implementationDetector;
|
||||
|
||||
/**
|
||||
* Creates a new {@link CustomRepositoryBuilder} from the given {@link BeanDefinitionRegistry},
|
||||
* {@link RepositoryConfigurationExtension} and {@link ResourceLoader}.
|
||||
*
|
||||
* @param registry must not be {@literal null}.
|
||||
* @param extension must not be {@literal null}.
|
||||
* @param resourceLoader must not be {@literal null}.
|
||||
* @param environment must not be {@literal null}.
|
||||
*/
|
||||
public CustomRepositoryBuilder(BeanDefinitionRegistry registry, RepositoryConfigurationExtension extension,
|
||||
RepositoryConfigurationSource configurationSource, ResourceLoader resourceLoader, Environment environment) {
|
||||
|
||||
Assert.notNull(extension, "RepositoryConfigurationExtension must not be null!");
|
||||
Assert.notNull(resourceLoader, "ResourceLoader must not be null!");
|
||||
Assert.notNull(environment, "Environment must not be null!");
|
||||
|
||||
this.registry = registry;
|
||||
this.extension = extension;
|
||||
this.resourceLoader = resourceLoader;
|
||||
|
||||
this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
|
||||
|
||||
this.fragmentMetadata = new FragmentMetadata(metadataReaderFactory);
|
||||
this.implementationDetector = new CustomRepositoryImplementationDetector(environment, resourceLoader,
|
||||
configurationSource.toImplementationDetectionConfiguration(metadataReaderFactory));
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a new {@link BeanDefinitionBuilder} from the given {@link BeanDefinitionRegistry} and {@link ResourceLoader}
|
||||
* .
|
||||
*
|
||||
* @param configuration must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public BeanDefinitionBuilder build(RepositoryConfiguration<?> configuration) {
|
||||
|
||||
Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
|
||||
Assert.notNull(resourceLoader, "ResourceLoader must not be null!");
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(configuration.getRepositoryFactoryBeanClassName());
|
||||
|
||||
builder.getRawBeanDefinition().setSource(configuration.getSource());
|
||||
builder.addConstructorArgValue(configuration.getRepositoryInterface());
|
||||
builder.addPropertyValue("queryLookupStrategyKey", configuration.getQueryLookupStrategyKey());
|
||||
builder.addPropertyValue("lazyInit", configuration.isLazyInit());
|
||||
builder.setLazyInit(configuration.isLazyInit());
|
||||
|
||||
configuration.getRepositoryBaseClassName()//
|
||||
.ifPresent(it -> builder.addPropertyValue("repositoryBaseClass", it));
|
||||
|
||||
NamedQueriesBeanDefinitionBuilder definitionBuilder = new NamedQueriesBeanDefinitionBuilder(
|
||||
extension.getDefaultNamedQueryLocation());
|
||||
configuration.getNamedQueriesLocation().ifPresent(definitionBuilder::setLocations);
|
||||
|
||||
builder.addPropertyValue("namedQueries", definitionBuilder.build(configuration.getSource()));
|
||||
|
||||
registerCustomImplementation(configuration).ifPresent(it -> {
|
||||
builder.addPropertyReference("customImplementation", it);
|
||||
builder.addDependsOn(it);
|
||||
});
|
||||
|
||||
BeanDefinitionBuilder fragmentsBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(RepositoryFragmentsFactoryBean.class);
|
||||
//
|
||||
// List<String> fragmentBeanNames = registerRepositoryFragmentsImplementation(configuration) //
|
||||
// .map(RepositoryFragmentConfiguration::getFragmentBeanName) //
|
||||
// .collect(Collectors.toList());
|
||||
|
||||
fragmentsBuilder.addConstructorArgValue(Collections.emptyList());
|
||||
|
||||
builder.addPropertyValue("repositoryFragments",
|
||||
ParsingUtils.getSourceBeanDefinition(fragmentsBuilder, configuration.getSource()));
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private Optional<String> registerCustomImplementation(RepositoryConfiguration<?> configuration) {
|
||||
|
||||
ImplementationLookupConfiguration lookup = configuration.toLookupConfiguration(metadataReaderFactory);
|
||||
|
||||
String beanName = lookup.getImplementationBeanName();
|
||||
|
||||
// Already a bean configured?
|
||||
if (registry.containsBeanDefinition(beanName)) {
|
||||
return Optional.of(beanName);
|
||||
}
|
||||
|
||||
Optional<AbstractBeanDefinition> beanDefinition = implementationDetector.detectCustomImplementation(lookup);
|
||||
|
||||
return beanDefinition.map(it -> {
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Registering custom repository implementation: " + lookup.getImplementationBeanName() + " "
|
||||
+ it.getBeanClassName());
|
||||
}
|
||||
|
||||
it.setSource(configuration.getSource());
|
||||
registry.registerBeanDefinition(beanName, it);
|
||||
|
||||
return beanName;
|
||||
});
|
||||
}
|
||||
|
||||
private Stream<RepositoryFragmentConfiguration> registerRepositoryFragmentsImplementation(
|
||||
RepositoryConfiguration<?> configuration) {
|
||||
|
||||
ImplementationDetectionConfiguration config = configuration
|
||||
.toImplementationDetectionConfiguration(metadataReaderFactory);
|
||||
|
||||
return fragmentMetadata.getFragmentInterfaces(configuration.getRepositoryInterface()) //
|
||||
.map(it -> detectRepositoryFragmentConfiguration(it, config)) //
|
||||
.flatMap(Optionals::toStream) //
|
||||
.peek(it -> potentiallyRegisterFragmentImplementation(configuration, it)) //
|
||||
.peek(it -> potentiallyRegisterRepositoryFragment(configuration, it));
|
||||
}
|
||||
|
||||
private Optional<RepositoryFragmentConfiguration> detectRepositoryFragmentConfiguration(String fragmentInterface,
|
||||
ImplementationDetectionConfiguration config) {
|
||||
|
||||
ImplementationLookupConfiguration lookup = config.forFragment(fragmentInterface);
|
||||
Optional<AbstractBeanDefinition> beanDefinition = implementationDetector.detectCustomImplementation(lookup);
|
||||
|
||||
return beanDefinition.map(bd -> new RepositoryFragmentConfiguration(fragmentInterface, bd));
|
||||
}
|
||||
|
||||
private void potentiallyRegisterFragmentImplementation(RepositoryConfiguration<?> repositoryConfiguration,
|
||||
RepositoryFragmentConfiguration fragmentConfiguration) {
|
||||
|
||||
String beanName = fragmentConfiguration.getImplementationBeanName();
|
||||
|
||||
// Already a bean configured?
|
||||
if (registry.containsBeanDefinition(beanName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(String.format("Registering repository fragment implementation: %s %s", beanName,
|
||||
fragmentConfiguration.getClassName()));
|
||||
}
|
||||
|
||||
fragmentConfiguration.getBeanDefinition().ifPresent(bd -> {
|
||||
|
||||
bd.setSource(repositoryConfiguration.getSource());
|
||||
registry.registerBeanDefinition(beanName, bd);
|
||||
});
|
||||
}
|
||||
|
||||
private void potentiallyRegisterRepositoryFragment(RepositoryConfiguration<?> configuration,
|
||||
RepositoryFragmentConfiguration fragmentConfiguration) {
|
||||
|
||||
String beanName = fragmentConfiguration.getFragmentBeanName();
|
||||
|
||||
// Already a bean configured?
|
||||
if (registry.containsBeanDefinition(beanName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Registering repository fragment: " + beanName);
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder fragmentBuilder = BeanDefinitionBuilder.rootBeanDefinition(RepositoryFragment.class,
|
||||
"implemented");
|
||||
|
||||
fragmentBuilder.addConstructorArgValue(fragmentConfiguration.getInterfaceName());
|
||||
fragmentBuilder.addConstructorArgReference(fragmentConfiguration.getImplementationBeanName());
|
||||
|
||||
registry.registerBeanDefinition(beanName,
|
||||
ParsingUtils.getSourceBeanDefinition(fragmentBuilder, configuration.getSource()));
|
||||
}
|
||||
|
||||
public BeanDefinitionRegistry getRegistry() {
|
||||
return registry;
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package com.flyfish.framework.beans.repository;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
|
||||
import org.springframework.data.mongodb.repository.config.MongoRepositoryConfigurationExtension;
|
||||
import org.springframework.data.repository.config.*;
|
||||
|
||||
/**
|
||||
* 自定义的仓库注册器
|
||||
* @author wangyu
|
||||
*/
|
||||
public class CustomRepositoryRegistrar {
|
||||
|
||||
// repo生成的extension
|
||||
private final RepositoryConfigurationExtension extension = new MongoRepositoryConfigurationExtension();
|
||||
private final RepositoryConfigurationSource configurationSource;
|
||||
private final CustomRepositoryBuilder builder;
|
||||
|
||||
public CustomRepositoryRegistrar(AnnotationMetadata metadata, ResourceLoader resourceLoader, Environment environment,
|
||||
BeanDefinitionRegistry registry, BeanNameGenerator generator) {
|
||||
// repo生成的构建器
|
||||
this.configurationSource = new AnnotationRepositoryConfigurationSource(metadata,
|
||||
EnableMongoRepositories.class, resourceLoader, environment, registry, generator);
|
||||
// 构建器
|
||||
this.builder = new CustomRepositoryBuilder(registry, extension,
|
||||
configurationSource, resourceLoader, environment);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据class直接注册bean
|
||||
* @param clazz 编译后的class
|
||||
*/
|
||||
public void register(Class<?> clazz) {
|
||||
//生成BeanDefinition并注册到容器中
|
||||
BeanDefinition origin = BeanDefinitionBuilder.genericBeanDefinition(clazz).getRawBeanDefinition();
|
||||
//设置当前bean定义对象是单例的
|
||||
origin.setScope("singleton");
|
||||
// 构造配置
|
||||
RepositoryConfiguration<? extends RepositoryConfigurationSource> configuration =
|
||||
new DefaultRepositoryConfiguration<>(configurationSource, origin, extension);
|
||||
BeanDefinitionBuilder definitionBuilder = builder.build(configuration);
|
||||
extension.postProcess(definitionBuilder, configurationSource);
|
||||
extension.postProcess(definitionBuilder, (AnnotationRepositoryConfigurationSource) configurationSource);
|
||||
|
||||
AbstractBeanDefinition beanDefinition = definitionBuilder.getBeanDefinition();
|
||||
beanDefinition.setPrimary(configuration.isPrimary());
|
||||
String beanName = StringUtils.uncapitalize(clazz.getSimpleName());
|
||||
beanDefinition.setAttribute("factoryBeanObjectType", configuration.getRepositoryInterface());
|
||||
builder.getRegistry().registerBeanDefinition(beanName, beanDefinition);
|
||||
}
|
||||
|
||||
public RepositoryConfigurationExtension getExtension() {
|
||||
return extension;
|
||||
}
|
||||
}
|
@ -1,14 +1,10 @@
|
||||
package com.flyfish.framework.beans.resolver;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 动态Bean生成解析器
|
||||
*
|
||||
* @author wangyu
|
||||
*/
|
||||
@Component
|
||||
public class DynamicRestBeanResolver {
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,181 @@
|
||||
package com.flyfish.framework.config;
|
||||
|
||||
import com.flyfish.framework.beans.annotations.EnableRestBeanDetect;
|
||||
import com.flyfish.framework.beans.annotations.RestBean;
|
||||
import com.flyfish.framework.beans.repository.CustomRepositoryRegistrar;
|
||||
import com.flyfish.framework.compiler.DynamicJavaCompiler;
|
||||
import com.flyfish.framework.compiler.support.JavaSource;
|
||||
import com.flyfish.framework.compiler.template.TemplateCompiler;
|
||||
import com.flyfish.framework.utils.Assert;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.reflections.Reflections;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.web.reactive.result.method.AbstractHandlerMethodMapping;
|
||||
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* rest bean的自动配置
|
||||
*
|
||||
* @author wangyu
|
||||
*/
|
||||
@Slf4j
|
||||
public class RestBeanAutoConfigure implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware, InitializingBean {
|
||||
|
||||
// 预编译模板
|
||||
private final Map<String, Function<JavaSource, String>> templates = Stream.of("Repository", "Service", "Controller")
|
||||
.collect(Collectors.toMap(key -> key, filename -> TemplateCompiler.compile("/templates/" + filename + ".tpl")));
|
||||
private final Map<String, Function<RestBean, Class<?>>> superClasses;
|
||||
private final Method handlerRegister;
|
||||
private final List<String> controllers = new ArrayList<>();
|
||||
|
||||
@Resource
|
||||
private RequestMappingHandlerMapping requestMappingHandlerMapping;
|
||||
// 资源加载器
|
||||
private ResourceLoader resourceLoader;
|
||||
// 环境变量
|
||||
private Environment environment;
|
||||
|
||||
public RestBeanAutoConfigure() throws NoSuchMethodException {
|
||||
this.handlerRegister = AbstractHandlerMethodMapping.class.getDeclaredMethod("detectHandlerMethods", Object.class);
|
||||
superClasses = new HashMap<>();
|
||||
superClasses.put("Controller", RestBean::controllerClass);
|
||||
superClasses.put("Repository", RestBean::repoClass);
|
||||
superClasses.put("Service", RestBean::serviceClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册bean的支持,能够处理注解信息,注册bean等
|
||||
*
|
||||
* @param metadata 导入类的元数据
|
||||
* @param registry 注册器
|
||||
*/
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry, BeanNameGenerator beanNameGenerator) {
|
||||
log.info("开始注册rest bean...");
|
||||
// 获取元数据
|
||||
Set<String> basePackages = getBasePackages(metadata);
|
||||
// 扫描包路径,检测RestBean注解的bean
|
||||
Reflections reflections = new Reflections(basePackages);
|
||||
// 编译器
|
||||
DynamicJavaCompiler compiler = DynamicJavaCompiler.delegate();
|
||||
// repo注册器
|
||||
CustomRepositoryRegistrar repositoryRegistrar = new CustomRepositoryRegistrar(metadata, resourceLoader,
|
||||
environment, registry, beanNameGenerator);
|
||||
// 准备注册的repo
|
||||
Map<String, List<Class<?>>> loadedClasses = new ConcurrentHashMap<>();
|
||||
// 获取被注解的类,开始编译
|
||||
reflections.getTypesAnnotatedWith(RestBean.class).parallelStream().forEach(clazz -> {
|
||||
RestBean restBean = clazz.getDeclaredAnnotation(RestBean.class);
|
||||
if (null != restBean) {
|
||||
// 创建java source信息
|
||||
JavaSource source = JavaSource.create()
|
||||
.setBeanClass(clazz.getCanonicalName())
|
||||
.setQueryBeanClass(restBean.queryClass().getCanonicalName())
|
||||
.setPackageName(basePackages.stream().findFirst().orElse("com.flyfish.project"))
|
||||
.setUri(restBean.value());
|
||||
// 分别生成实现类,从repo到controller
|
||||
templates.forEach((key, template) -> {
|
||||
source.setSuperClass(superClasses.get(key).apply(restBean).getCanonicalName());
|
||||
source.setClassName(clazz.getSimpleName() + key);
|
||||
try {
|
||||
log.info("尝试注册{}", source.getClassName());
|
||||
Class<?> compiled = compiler.compile(source.getClassName() + ".java", template.apply(source));
|
||||
loadedClasses.computeIfAbsent(key, k -> new ArrayList<>()).add(compiled);
|
||||
// IllegalAccessException | InvocationTargetException
|
||||
} catch (ClassNotFoundException | IOException e) {
|
||||
log.error("注册{}时发生异常!", source.getClassName(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 从repo开始,注册bean
|
||||
loadedClasses.getOrDefault("Repository", Collections.emptyList())
|
||||
.forEach(repositoryRegistrar::register);
|
||||
loadedClasses.getOrDefault("Service", Collections.emptyList())
|
||||
.forEach(clazz -> registerBean(clazz, registry));
|
||||
loadedClasses.getOrDefault("Controller", Collections.emptyList())
|
||||
.forEach(clazz -> registerBean(clazz, registry));
|
||||
log.info("结束注册rest bean...");
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册bean,如果是controller,自动注册controller
|
||||
*
|
||||
* @param clazz class,要注册的class
|
||||
* @param registry 注册器,注册bean用
|
||||
*/
|
||||
private void registerBean(Class<?> clazz, BeanDefinitionRegistry registry) {
|
||||
//生成BeanDefinition并注册到容器中
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
|
||||
BeanDefinition beanDefinition = builder.getRawBeanDefinition();
|
||||
//设置当前bean定义对象是单利的
|
||||
beanDefinition.setScope("singleton");
|
||||
//将变量首字母置小写
|
||||
String beanName = StringUtils.uncapitalize(clazz.getSimpleName());
|
||||
log.info("注册bean:{}", beanName);
|
||||
registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
|
||||
// 如果是controller,注册
|
||||
if (clazz.getSimpleName().endsWith("Controller")) {
|
||||
controllers.add(beanName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取基本扫描包路径
|
||||
*
|
||||
* @param metadata 元数据
|
||||
* @return 结果
|
||||
*/
|
||||
private Set<String> getBasePackages(AnnotationMetadata metadata) {
|
||||
// 获取启动类的注解配置
|
||||
Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableRestBeanDetect.class.getCanonicalName(), true);
|
||||
Assert.isTrue(null != attrs && attrs.containsKey("basePackages"), "【rest配置】未指定包路径!");
|
||||
String[] packages = (String[]) attrs.get("basePackages");
|
||||
if (ArrayUtils.isEmpty(packages)) {
|
||||
return Stream.of(metadata.getClassName()).collect(Collectors.toSet());
|
||||
} else {
|
||||
return Arrays.stream(packages).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
for (String bean : controllers) {
|
||||
log.info("注册controller:{}", bean);
|
||||
handlerRegister.setAccessible(true);
|
||||
handlerRegister.invoke(requestMappingHandlerMapping, bean);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package com.flyfish.framework.controller;
|
||||
|
||||
import com.flyfish.framework.bean.EnumValue;
|
||||
import com.flyfish.framework.bean.Result;
|
||||
import com.flyfish.framework.enums.NamedEnum;
|
||||
import com.flyfish.framework.utils.StringFormats;
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
import org.reflections.Reflections;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 统一处理枚举
|
||||
* 将来会加入字典自动处理
|
||||
*
|
||||
* @author wangyu
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("enums/{code}")
|
||||
public class EnumController {
|
||||
|
||||
// 映射管理,避免class.forName扫描包路径
|
||||
private final Map<String, Map<String, String>> mapper = new HashMap<>();
|
||||
|
||||
private final Map<String, List<EnumValue>> values = new HashMap<>();
|
||||
|
||||
public EnumController() {
|
||||
Reflections reflections = new Reflections("com.flyfish.project");
|
||||
// 得到Resource注解的类
|
||||
Set<Class<? extends NamedEnum>> classSet = reflections.getSubTypesOf(NamedEnum.class);
|
||||
// 注入
|
||||
classSet.stream().filter(clazz -> ClassUtils.isAssignable(clazz, Enum.class)).forEach(clazz -> {
|
||||
String name = StringFormats.camel2Line(clazz.getSimpleName());
|
||||
List<EnumValue> values = Arrays.stream(clazz.getEnumConstants()).reduce(new ArrayList<>(), (result, item) -> {
|
||||
result.add(new EnumValue(((Enum<?>) item).name(), item.getName()));
|
||||
return result;
|
||||
}, (a, b) -> a);
|
||||
this.mapper.put(name, values.stream().collect(Collectors.toMap(EnumValue::getValue, EnumValue::getText)));
|
||||
this.values.put(name, values);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过code和key查找显示名称
|
||||
*
|
||||
* @param code 编码
|
||||
* @param key 键
|
||||
* @return 结果
|
||||
*/
|
||||
@GetMapping("{key}")
|
||||
public Result<String> getText(@PathVariable("code") String code, @PathVariable("key") String key) {
|
||||
return Result.ok(mapper.getOrDefault(code, Collections.emptyMap()).get(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* 值的集合
|
||||
*
|
||||
* @param code 编码
|
||||
* @return 结果
|
||||
*/
|
||||
@GetMapping
|
||||
public Result<List<EnumValue>> values(@PathVariable("code") String code) {
|
||||
return Result.ok(values.getOrDefault(code, Collections.emptyList()));
|
||||
}
|
||||
}
|
@ -1,4 +1,8 @@
|
||||
package com.flyfish.framework.controller;
|
||||
|
||||
/**
|
||||
* 安全的controller
|
||||
* @author wangyu 标记代码归属
|
||||
*/
|
||||
public interface SafeController {
|
||||
}
|
||||
|
13
flyfish-web/src/main/resources/templates/Controller.tpl
Normal file
13
flyfish-web/src/main/resources/templates/Controller.tpl
Normal file
@ -0,0 +1,13 @@
|
||||
package #{packageName};
|
||||
|
||||
import #{superClass};
|
||||
import #{beanClass};
|
||||
import #{queryBeanClass};
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("#{uri}")
|
||||
public class #{className} extends #{superClassName}<#{beanClassName}, #{queryBeanClassName}> {
|
||||
|
||||
}
|
7
flyfish-web/src/main/resources/templates/Repository.tpl
Normal file
7
flyfish-web/src/main/resources/templates/Repository.tpl
Normal file
@ -0,0 +1,7 @@
|
||||
package #{packageName};
|
||||
|
||||
import #{superClass};
|
||||
import #{beanClass};
|
||||
|
||||
public interface #{className} extends #{superClassName}<#{beanClassName}> {
|
||||
}
|
9
flyfish-web/src/main/resources/templates/Service.tpl
Normal file
9
flyfish-web/src/main/resources/templates/Service.tpl
Normal file
@ -0,0 +1,9 @@
|
||||
package #{packageName};
|
||||
|
||||
import #{superClass};
|
||||
import #{beanClass};
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class #{className} extends #{superClassName}<#{beanClassName}> {
|
||||
}
|
15
pom.xml
15
pom.xml
@ -24,6 +24,7 @@
|
||||
<java.version>1.8</java.version>
|
||||
<spring-cloud.version>Finchley.SR1</spring-cloud.version>
|
||||
<jjwt.version>0.11.0</jjwt.version>
|
||||
<reflection.version>0.9.12</reflection.version>
|
||||
</properties>
|
||||
|
||||
<developers>
|
||||
@ -83,6 +84,16 @@
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.itranswarp</groupId>
|
||||
<artifactId>compiler</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.reflections</groupId>
|
||||
<artifactId>reflections</artifactId>
|
||||
<version>${reflection.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
@ -98,6 +109,10 @@
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
Loading…
Reference in New Issue
Block a user