From 392b1ebc09e7a5fcbb485746af084a63528e5e61 Mon Sep 17 00:00:00 2001
From: wangyu <727842003@qq.com>
Date: Mon, 4 Jan 2021 14:44:03 +0800
Subject: [PATCH] =?UTF-8?q?Feat=EF=BC=9A=E5=A2=9E=E5=8A=A0=E5=8A=A8?=
=?UTF-8?q?=E6=80=81=E4=BB=A3=E7=A0=81=E7=BC=96=E8=AF=91=E5=BC=95=E6=93=8E?=
=?UTF-8?q?=E7=9B=B8=E5=85=B3=E9=80=BB=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
flyfish-common/pom.xml | 8 +
.../com/flyfish/framework/bean/EnumValue.java | 19 ++
.../compiler/DynamicJavaCompiler.java | 41 ++++
.../support/DelegateJavaCompiler.java | 65 ++++++
.../compiler/support/JavaSource.java | 50 ++++
.../compiler/support/SimpleJavaCompiler.java | 71 ++++++
.../compiler/support/StringJavaObject.java | 35 +++
.../compiler/template/TemplateCompiler.java | 88 +++++++
.../flyfish/framework/utils/MapBuilder.java | 47 ++++
.../framework/utils/StringFormats.java | 37 +++
.../annotations/EnableEnumEndpoint.java | 25 ++
.../flyfish/framework/config/EnumConfig.java | 45 ++++
.../annotations/EnableRestBeanDetect.java | 23 ++
.../framework/beans/annotations/RestBean.java | 36 ++-
.../repository/CustomRepositoryBuilder.java | 220 ++++++++++++++++++
.../repository/CustomRepositoryRegistrar.java | 63 +++++
.../resolver/DynamicRestBeanResolver.java | 4 -
.../config/RestBeanAutoConfigure.java | 181 ++++++++++++++
.../framework/controller/EnumController.java | 70 ++++++
.../framework/controller/SafeController.java | 4 +
.../main/resources/templates/Controller.tpl | 13 ++
.../main/resources/templates/Repository.tpl | 7 +
.../src/main/resources/templates/Service.tpl | 9 +
pom.xml | 15 ++
24 files changed, 1171 insertions(+), 5 deletions(-)
create mode 100644 flyfish-common/src/main/java/com/flyfish/framework/bean/EnumValue.java
create mode 100644 flyfish-common/src/main/java/com/flyfish/framework/compiler/DynamicJavaCompiler.java
create mode 100644 flyfish-common/src/main/java/com/flyfish/framework/compiler/support/DelegateJavaCompiler.java
create mode 100644 flyfish-common/src/main/java/com/flyfish/framework/compiler/support/JavaSource.java
create mode 100644 flyfish-common/src/main/java/com/flyfish/framework/compiler/support/SimpleJavaCompiler.java
create mode 100644 flyfish-common/src/main/java/com/flyfish/framework/compiler/support/StringJavaObject.java
create mode 100644 flyfish-common/src/main/java/com/flyfish/framework/compiler/template/TemplateCompiler.java
create mode 100644 flyfish-common/src/main/java/com/flyfish/framework/utils/MapBuilder.java
create mode 100644 flyfish-common/src/main/java/com/flyfish/framework/utils/StringFormats.java
create mode 100644 flyfish-data/src/main/java/com/flyfish/framework/annotations/EnableEnumEndpoint.java
create mode 100644 flyfish-data/src/main/java/com/flyfish/framework/config/EnumConfig.java
create mode 100644 flyfish-web/src/main/java/com/flyfish/framework/beans/annotations/EnableRestBeanDetect.java
create mode 100644 flyfish-web/src/main/java/com/flyfish/framework/beans/repository/CustomRepositoryBuilder.java
create mode 100644 flyfish-web/src/main/java/com/flyfish/framework/beans/repository/CustomRepositoryRegistrar.java
create mode 100644 flyfish-web/src/main/java/com/flyfish/framework/config/RestBeanAutoConfigure.java
create mode 100644 flyfish-web/src/main/java/com/flyfish/framework/controller/EnumController.java
create mode 100644 flyfish-web/src/main/resources/templates/Controller.tpl
create mode 100644 flyfish-web/src/main/resources/templates/Repository.tpl
create mode 100644 flyfish-web/src/main/resources/templates/Service.tpl
diff --git a/flyfish-common/pom.xml b/flyfish-common/pom.xml
index ae28dd3..ecb9225 100644
--- a/flyfish-common/pom.xml
+++ b/flyfish-common/pom.xml
@@ -59,6 +59,14 @@
org.slf4j
slf4j-api
+
+ com.itranswarp
+ compiler
+
+
+ org.reflections
+ reflections
+
\ No newline at end of file
diff --git a/flyfish-common/src/main/java/com/flyfish/framework/bean/EnumValue.java b/flyfish-common/src/main/java/com/flyfish/framework/bean/EnumValue.java
new file mode 100644
index 0000000..d60fdea
--- /dev/null
+++ b/flyfish-common/src/main/java/com/flyfish/framework/bean/EnumValue.java
@@ -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;
+}
diff --git a/flyfish-common/src/main/java/com/flyfish/framework/compiler/DynamicJavaCompiler.java b/flyfish-common/src/main/java/com/flyfish/framework/compiler/DynamicJavaCompiler.java
new file mode 100644
index 0000000..0f8ffb1
--- /dev/null
+++ b/flyfish-common/src/main/java/com/flyfish/framework/compiler/DynamicJavaCompiler.java
@@ -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;
+}
diff --git a/flyfish-common/src/main/java/com/flyfish/framework/compiler/support/DelegateJavaCompiler.java b/flyfish-common/src/main/java/com/flyfish/framework/compiler/support/DelegateJavaCompiler.java
new file mode 100644
index 0000000..d363feb
--- /dev/null
+++ b/flyfish-common/src/main/java/com/flyfish/framework/compiler/support/DelegateJavaCompiler.java
@@ -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 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 + "秒");
+ }
+}
diff --git a/flyfish-common/src/main/java/com/flyfish/framework/compiler/support/JavaSource.java b/flyfish-common/src/main/java/com/flyfish/framework/compiler/support/JavaSource.java
new file mode 100644
index 0000000..ed9fbe4
--- /dev/null
+++ b/flyfish-common/src/main/java/com/flyfish/framework/compiler/support/JavaSource.java
@@ -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, ".");
+ }
+}
diff --git a/flyfish-common/src/main/java/com/flyfish/framework/compiler/support/SimpleJavaCompiler.java b/flyfish-common/src/main/java/com/flyfish/framework/compiler/support/SimpleJavaCompiler.java
new file mode 100644
index 0000000..832b498
--- /dev/null
+++ b/flyfish-common/src/main/java/com/flyfish/framework/compiler/support/SimpleJavaCompiler.java
@@ -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 options = Arrays.asList("-d", "./bin");
+ // 编译池
+ private final Map> 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();
+
+ }
+}
diff --git a/flyfish-common/src/main/java/com/flyfish/framework/compiler/support/StringJavaObject.java b/flyfish-common/src/main/java/com/flyfish/framework/compiler/support/StringJavaObject.java
new file mode 100644
index 0000000..5465ad8
--- /dev/null
+++ b/flyfish-common/src/main/java/com/flyfish/framework/compiler/support/StringJavaObject.java
@@ -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;
+ }
+}
diff --git a/flyfish-common/src/main/java/com/flyfish/framework/compiler/template/TemplateCompiler.java b/flyfish-common/src/main/java/com/flyfish/framework/compiler/template/TemplateCompiler.java
new file mode 100644
index 0000000..0642e3a
--- /dev/null
+++ b/flyfish-common/src/main/java/com/flyfish/framework/compiler/template/TemplateCompiler.java
@@ -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 compile(Class> dataClass, String filename) {
+ // 获取文件内容
+ InputStream fis = TemplateCompiler.class.getResourceAsStream(filename);
+ try {
+ // 获取模板内容
+ String template = StreamUtils.copyToString(fis, StandardCharsets.UTF_8);
+ // 准备变量池
+ Map 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 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 compile(String filename) {
+ return compile(JavaSource.class, filename);
+ }
+}
diff --git a/flyfish-common/src/main/java/com/flyfish/framework/utils/MapBuilder.java b/flyfish-common/src/main/java/com/flyfish/framework/utils/MapBuilder.java
new file mode 100644
index 0000000..2cc4b8e
--- /dev/null
+++ b/flyfish-common/src/main/java/com/flyfish/framework/utils/MapBuilder.java
@@ -0,0 +1,47 @@
+package com.flyfish.framework.utils;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * map构造器
+ *
+ * @author wangyu
+ */
+public class MapBuilder {
+
+ // 内部的map
+ private final Map map = new LinkedHashMap<>();
+
+ /**
+ * 构造器
+ *
+ * @param 键
+ * @param 值
+ * @return 结果
+ */
+ public static MapBuilder builder() {
+ return new MapBuilder<>();
+ }
+
+ /**
+ * 放置参数
+ *
+ * @param k 键
+ * @param v 值
+ * @return 结果
+ */
+ public MapBuilder put(K k, V v) {
+ this.map.put(k, v);
+ return this;
+ }
+
+ /**
+ * 构建
+ *
+ * @return 结果
+ */
+ public Map build() {
+ return map;
+ }
+}
diff --git a/flyfish-common/src/main/java/com/flyfish/framework/utils/StringFormats.java b/flyfish-common/src/main/java/com/flyfish/framework/utils/StringFormats.java
new file mode 100644
index 0000000..7ce4ba7
--- /dev/null
+++ b/flyfish-common/src/main/java/com/flyfish/framework/utils/StringFormats.java
@@ -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();
+ }
+}
diff --git a/flyfish-data/src/main/java/com/flyfish/framework/annotations/EnableEnumEndpoint.java b/flyfish-data/src/main/java/com/flyfish/framework/annotations/EnableEnumEndpoint.java
new file mode 100644
index 0000000..aa028a6
--- /dev/null
+++ b/flyfish-data/src/main/java/com/flyfish/framework/annotations/EnableEnumEndpoint.java
@@ -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";
+}
diff --git a/flyfish-data/src/main/java/com/flyfish/framework/config/EnumConfig.java b/flyfish-data/src/main/java/com/flyfish/framework/config/EnumConfig.java
new file mode 100644
index 0000000..2a4cb2b
--- /dev/null
+++ b/flyfish-data/src/main/java/com/flyfish/framework/config/EnumConfig.java
@@ -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> mapper = new HashMap<>();
+
+ private final Map> values = new HashMap<>();
+
+ public EnumConfig() {
+ Reflections reflections = new Reflections("com.flyfish.project");
+ // 得到Resource注解的类
+ Set> classSet = reflections.getSubTypesOf(NamedEnum.class);
+ // 注入
+ classSet.stream().filter(clazz -> ClassUtils.isAssignable(clazz, Enum.class)).forEach(clazz -> {
+ String name = StringFormats.camel2Line(clazz.getSimpleName());
+ List 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 {
+
+ }
+}
diff --git a/flyfish-web/src/main/java/com/flyfish/framework/beans/annotations/EnableRestBeanDetect.java b/flyfish-web/src/main/java/com/flyfish/framework/beans/annotations/EnableRestBeanDetect.java
new file mode 100644
index 0000000..9e56d1a
--- /dev/null
+++ b/flyfish-web/src/main/java/com/flyfish/framework/beans/annotations/EnableRestBeanDetect.java
@@ -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";
+}
diff --git a/flyfish-web/src/main/java/com/flyfish/framework/beans/annotations/RestBean.java b/flyfish-web/src/main/java/com/flyfish/framework/beans/annotations/RestBean.java
index 8f7cbff..3395b3f 100644
--- a/flyfish-web/src/main/java/com/flyfish/framework/beans/annotations/RestBean.java
+++ b/flyfish-web/src/main/java/com/flyfish/framework/beans/annotations/RestBean.java
@@ -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;
}
diff --git a/flyfish-web/src/main/java/com/flyfish/framework/beans/repository/CustomRepositoryBuilder.java b/flyfish-web/src/main/java/com/flyfish/framework/beans/repository/CustomRepositoryBuilder.java
new file mode 100644
index 0000000..915c24d
--- /dev/null
+++ b/flyfish-web/src/main/java/com/flyfish/framework/beans/repository/CustomRepositoryBuilder.java
@@ -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 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 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 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 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 detectRepositoryFragmentConfiguration(String fragmentInterface,
+ ImplementationDetectionConfiguration config) {
+
+ ImplementationLookupConfiguration lookup = config.forFragment(fragmentInterface);
+ Optional 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;
+ }
+}
diff --git a/flyfish-web/src/main/java/com/flyfish/framework/beans/repository/CustomRepositoryRegistrar.java b/flyfish-web/src/main/java/com/flyfish/framework/beans/repository/CustomRepositoryRegistrar.java
new file mode 100644
index 0000000..b532e6f
--- /dev/null
+++ b/flyfish-web/src/main/java/com/flyfish/framework/beans/repository/CustomRepositoryRegistrar.java
@@ -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;
+ }
+}
diff --git a/flyfish-web/src/main/java/com/flyfish/framework/beans/resolver/DynamicRestBeanResolver.java b/flyfish-web/src/main/java/com/flyfish/framework/beans/resolver/DynamicRestBeanResolver.java
index be397aa..54bfcd5 100644
--- a/flyfish-web/src/main/java/com/flyfish/framework/beans/resolver/DynamicRestBeanResolver.java
+++ b/flyfish-web/src/main/java/com/flyfish/framework/beans/resolver/DynamicRestBeanResolver.java
@@ -1,14 +1,10 @@
package com.flyfish.framework.beans.resolver;
-import org.springframework.stereotype.Component;
-
/**
* 动态Bean生成解析器
*
* @author wangyu
*/
-@Component
public class DynamicRestBeanResolver {
-
}
diff --git a/flyfish-web/src/main/java/com/flyfish/framework/config/RestBeanAutoConfigure.java b/flyfish-web/src/main/java/com/flyfish/framework/config/RestBeanAutoConfigure.java
new file mode 100644
index 0000000..853a124
--- /dev/null
+++ b/flyfish-web/src/main/java/com/flyfish/framework/config/RestBeanAutoConfigure.java
@@ -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> templates = Stream.of("Repository", "Service", "Controller")
+ .collect(Collectors.toMap(key -> key, filename -> TemplateCompiler.compile("/templates/" + filename + ".tpl")));
+ private final Map>> superClasses;
+ private final Method handlerRegister;
+ private final List 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 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>> 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 getBasePackages(AnnotationMetadata metadata) {
+ // 获取启动类的注解配置
+ Map 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;
+ }
+}
diff --git a/flyfish-web/src/main/java/com/flyfish/framework/controller/EnumController.java b/flyfish-web/src/main/java/com/flyfish/framework/controller/EnumController.java
new file mode 100644
index 0000000..dd913b1
--- /dev/null
+++ b/flyfish-web/src/main/java/com/flyfish/framework/controller/EnumController.java
@@ -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> mapper = new HashMap<>();
+
+ private final Map> values = new HashMap<>();
+
+ public EnumController() {
+ Reflections reflections = new Reflections("com.flyfish.project");
+ // 得到Resource注解的类
+ Set> classSet = reflections.getSubTypesOf(NamedEnum.class);
+ // 注入
+ classSet.stream().filter(clazz -> ClassUtils.isAssignable(clazz, Enum.class)).forEach(clazz -> {
+ String name = StringFormats.camel2Line(clazz.getSimpleName());
+ List 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 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> values(@PathVariable("code") String code) {
+ return Result.ok(values.getOrDefault(code, Collections.emptyList()));
+ }
+}
\ No newline at end of file
diff --git a/flyfish-web/src/main/java/com/flyfish/framework/controller/SafeController.java b/flyfish-web/src/main/java/com/flyfish/framework/controller/SafeController.java
index ecd0f1d..255f5a8 100644
--- a/flyfish-web/src/main/java/com/flyfish/framework/controller/SafeController.java
+++ b/flyfish-web/src/main/java/com/flyfish/framework/controller/SafeController.java
@@ -1,4 +1,8 @@
package com.flyfish.framework.controller;
+/**
+ * 安全的controller
+ * @author wangyu 标记代码归属
+ */
public interface SafeController {
}
diff --git a/flyfish-web/src/main/resources/templates/Controller.tpl b/flyfish-web/src/main/resources/templates/Controller.tpl
new file mode 100644
index 0000000..ac0dd65
--- /dev/null
+++ b/flyfish-web/src/main/resources/templates/Controller.tpl
@@ -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}> {
+
+}
\ No newline at end of file
diff --git a/flyfish-web/src/main/resources/templates/Repository.tpl b/flyfish-web/src/main/resources/templates/Repository.tpl
new file mode 100644
index 0000000..7b18dd2
--- /dev/null
+++ b/flyfish-web/src/main/resources/templates/Repository.tpl
@@ -0,0 +1,7 @@
+package #{packageName};
+
+import #{superClass};
+import #{beanClass};
+
+public interface #{className} extends #{superClassName}<#{beanClassName}> {
+}
diff --git a/flyfish-web/src/main/resources/templates/Service.tpl b/flyfish-web/src/main/resources/templates/Service.tpl
new file mode 100644
index 0000000..fad4d3c
--- /dev/null
+++ b/flyfish-web/src/main/resources/templates/Service.tpl
@@ -0,0 +1,9 @@
+package #{packageName};
+
+import #{superClass};
+import #{beanClass};
+import org.springframework.stereotype.Service;
+
+@Service
+public class #{className} extends #{superClassName}<#{beanClassName}> {
+}
diff --git a/pom.xml b/pom.xml
index 77bf7c9..040d867 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,6 +24,7 @@
1.8
Finchley.SR1
0.11.0
+ 0.9.12
@@ -83,6 +84,16 @@
commons-io
2.6
+
+ com.itranswarp
+ compiler
+ 1.0
+
+
+ org.reflections
+ reflections
+ ${reflection.version}
+
@@ -98,6 +109,10 @@
${project.build.sourceEncoding}
+
+ org.apache.maven.plugins
+ maven-source-plugin
+