admin
2021-09-24 881f273bca0f94345efb2c0cac52279af4a7f4e4
后台管理自动化代码生成
3 文件已重命名
6个文件已修改
3 文件已复制
30个文件已添加
1511 ■■■■■ 已修改文件
src/main/java/org/yeshi/utils/FreemarkerUtils.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/SpringComponentGenerater.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/annotation/admin/AdminController.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/annotation/admin/DaoQueryCondition.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/annotation/admin/Show.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/annotation/admin/form/CheckBox.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/annotation/admin/form/Img.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/annotation/admin/form/Password.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/annotation/admin/form/RadioGroup.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/annotation/admin/form/Select.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/annotation/admin/form/Switch.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/annotation/admin/form/Text.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/annotation/admin/form/TextArea.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/entity/CommonSearchForm.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/entity/DaoQueryColumnData.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/entity/KeyValue.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/entity/MongoDBDaoData.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/entity/admin/AdminGeneraterInfo.java 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/entity/admin/FormRowData.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/entity/admin/FormVerifyType.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/exception/AnotationException.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/util/AnotationUtil.java 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/util/FormAnotationValidUtil.java 127 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/ios/pay/IOSPayVerifyUtil.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/ios/pay/vo/IOSAPPBuyVerifyResult.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/admin/add.ftl 181 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/admin/adminController.template 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/admin/form/checkBox.ftl 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/admin/form/img.ftl 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/admin/form/password.ftl 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/admin/form/radioGroup.ftl 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/admin/form/select.ftl 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/admin/form/switch.ftl 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/admin/form/text.ftl 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/admin/form/textArea.ftl 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/admin/list.flt 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/admin/update.ftl 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/mongoDBDao.template 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/service.template 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/serviceImpl.template 补丁 | 查看 | 原始文档 | blame | 历史
src/test/java/com/generater/GeneratorTest.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/java/com/generater/TestEntity.java 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/FreemarkerUtils.java
@@ -6,6 +6,8 @@
import org.apache.commons.io.IOUtils;
import java.io.*;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class FreemarkerUtils {
@@ -54,6 +56,29 @@
        return generateString(data, str);
    }
    public static String generateInputStream(Object data, String name, Map<String, InputStream> templateStreams) throws IOException {
        String result = null;
        try {
            StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
            for (Iterator<String> its = templateStreams.keySet().iterator(); its.hasNext(); ) {
                String key = its.next();
                stringTemplateLoader.putTemplate(key, IOUtils.toString(templateStreams.get(key), "UTF-8"));
            }
            cfg.setTemplateLoader(stringTemplateLoader);
            Template template = cfg.getTemplate(name, defaultCharacter);
            StringWriter out = new StringWriter();
            template.process(data, out);
            out.flush();
            result = out.toString();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 将模板渲染以后保存到文件
     *
src/main/java/org/yeshi/utils/generater/SpringComponentGenerater.java
@@ -17,7 +17,7 @@
     * @throws Exception
     */
    public static void createMongoDao(MongoDBDaoData data, String targetDir) throws Exception {
        FreemarkerUtils.renderingTemplateAndGenerateFile(SpringComponentGenerater.class.getClassLoader().getResourceAsStream("mongoDBDao.template"), new File(targetDir, data.getDaoName() + ".java").getAbsolutePath(), data);
        FreemarkerUtils.renderingTemplateAndGenerateFile(SpringComponentGenerater.class.getClassLoader().getResourceAsStream("generater/mongoDBDao.template"), new File(targetDir, data.getDaoName() + ".java").getAbsolutePath(), data);
    }
    /**
@@ -29,7 +29,7 @@
     */
    public static void createService(ServiceData data, String targetDir) throws Exception {
        FreemarkerUtils.renderingTemplateAndGenerateFile(SpringComponentGenerater.class.getClassLoader().getResourceAsStream("service.template"), new File(targetDir, data.getServiceClassName() + ".java").getAbsolutePath(), data);
        FreemarkerUtils.renderingTemplateAndGenerateFile(SpringComponentGenerater.class.getClassLoader().getResourceAsStream("generater/service.template"), new File(targetDir, data.getServiceClassName() + ".java").getAbsolutePath(), data);
    }
    /**
@@ -41,7 +41,7 @@
     */
    public static void createServiceImpl(ServiceData data, String targetDir) throws Exception {
        FreemarkerUtils.renderingTemplateAndGenerateFile(SpringComponentGenerater.class.getClassLoader().getResourceAsStream("serviceImpl.template"), new File(targetDir, data.getServiceClassName() + "Impl.java").getAbsolutePath(), data);
        FreemarkerUtils.renderingTemplateAndGenerateFile(SpringComponentGenerater.class.getClassLoader().getResourceAsStream("generater/serviceImpl.template"), new File(targetDir, data.getServiceClassName() + "Impl.java").getAbsolutePath(), data);
    }
src/main/java/org/yeshi/utils/generater/annotation/admin/AdminController.java
New file
@@ -0,0 +1,40 @@
package org.yeshi.utils.generater.annotation.admin;
import java.lang.annotation.*;
/**
 * @author Administrator
 * @title: AdminController
 * @projectName utils
 * @description: 后台接口controller
 * @date 2021/9/2315:10
 */
@Documented
@Target(ElementType.TYPE)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface AdminController {
    //接口
    String mapping();
    String title();
    //是否开启工具栏
    boolean toolbar() default true;
    //是否开启操作栏
    boolean operate() default true;
    //默认开启删除
    boolean delete() default true;
    //默认开启编辑
    boolean edit() default true;
    //默认开启分页
    boolean page() default true;
    Class searchForm() default Void.class;
}
src/main/java/org/yeshi/utils/generater/annotation/admin/DaoQueryCondition.java
New file
@@ -0,0 +1,27 @@
package org.yeshi.utils.generater.annotation.admin;
import java.lang.annotation.*;
/**
 * @author Administrator
 * @title: DaoQueryCondition
 * @projectName utils
 * @description:
 * @date 2021/9/23 13:42
 */
@Documented
@Target(ElementType.FIELD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface DaoQueryCondition {
    //查询类型
    QueryType queryType() default QueryType.equal;
    //显示类型
    enum QueryType {
        start, end, contains, equal
    }
}
src/main/java/org/yeshi/utils/generater/annotation/admin/Show.java
New file
@@ -0,0 +1,44 @@
package org.yeshi.utils.generater.annotation.admin;
import java.lang.annotation.*;
/**
 * @author Administrator
 * @title: Show
 * @projectName utils
 * @description: 是否在列表中显示
 * @date 2021/9/2313:42
 */
@Documented
@Target(ElementType.FIELD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface Show {
    //显示的顺序
    int order() default 0;
    //标题
    String title();
    //显示类型
    ShowType showType() default ShowType.TEXT;
    //显示类型为IMG时生效
    int imgWidth() default -1;
    int imgHeight() default -1;
    //当格式为日期格式时选填此项
    String dateFormate() default "yyyy.MM.dd";
    //显示类型
    enum ShowType {
        TEXT, IMG;
    }
}
src/main/java/org/yeshi/utils/generater/annotation/admin/form/CheckBox.java
New file
@@ -0,0 +1,37 @@
package org.yeshi.utils.generater.annotation.admin.form;
import java.lang.annotation.*;
/**
 * @author Administrator
 * @title: CheckBox
 * @projectName utils
 * @description: 复选框
 * @date 2021/9/2313:42
 */
@Documented
@Target(ElementType.FIELD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckBox {
    //标题
    String title();
    //是否可更新
    boolean update() default true;
    //简介
    String desc() default "";
    //是否禁止编辑
    boolean disable() default false;
    //值,键值采用逗号分隔
    String[] values();
}
src/main/java/org/yeshi/utils/generater/annotation/admin/form/Img.java
New file
@@ -0,0 +1,34 @@
package org.yeshi.utils.generater.annotation.admin.form;
import java.lang.annotation.*;
/**
 * @author Administrator
 * @title: Img
 * @projectName utils
 * @description: 图片控件
 * @date 2021/9/2312:06
 */
@Documented
@Target(ElementType.FIELD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface Img {
    //标题
    String title();
    //是否可更新
    boolean update() default true;
    //简介
    String desc() default "";
    //是否禁止编辑
    boolean disable() default false;
    //图片宽度px,默认不设置
    int width() default -1;
    //图片高度px,默认不设置
    int height() default -1;
}
src/main/java/org/yeshi/utils/generater/annotation/admin/form/Password.java
New file
@@ -0,0 +1,37 @@
package org.yeshi.utils.generater.annotation.admin.form;
import java.lang.annotation.*;
/**
 * @author Administrator
 * @title: Password
 * @projectName utils
 * @description: 密码
 * @date 2021/9/2313:43
 */
@Documented
@Target(ElementType.FIELD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface Password {
    //标题
    String title();
    //是否可更新
    boolean update() default true;
    //简介
    String desc() default "";
    //是否禁止编辑
    boolean disable() default false;
    //是否必须
    boolean require() default false;
    //最小长度
    int minLength() default -1;
    //最长长度
    int maxLength() default -1;
}
src/main/java/org/yeshi/utils/generater/annotation/admin/form/RadioGroup.java
New file
@@ -0,0 +1,31 @@
package org.yeshi.utils.generater.annotation.admin.form;
import java.lang.annotation.*;
/**
 * @author Administrator
 * @title: RadioGroup
 * @projectName utils
 * @description: 单选框
 * @date 2021/9/2313:41
 */
@Documented
@Target(ElementType.FIELD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface RadioGroup {
    //标题
    String title();
    //是否可更新
    boolean update() default true;
    //简介
    String desc() default "";
    //是否禁止编辑
    boolean disable() default false;
    //值,键值采用逗号分隔
    String[] values();
}
src/main/java/org/yeshi/utils/generater/annotation/admin/form/Select.java
New file
@@ -0,0 +1,39 @@
package org.yeshi.utils.generater.annotation.admin.form;
import java.lang.annotation.*;
/**
 * @author Administrator
 * @title: Select
 * @projectName utils
 * @description: 下拉列表
 * @date 2021/9/2312:07
 */
@Documented
@Target(ElementType.FIELD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface Select {
    //标题
    String title();
    //是否可更新
    boolean update() default true;
    //简介
    String desc() default "";
    //是否禁止编辑
    boolean disable() default false;
    //是否必须
    boolean require() default false;
    //值,键值采用逗号分隔
    String[] values() default "";
    //链接请求的路径
    String apiPath() default "";
}
src/main/java/org/yeshi/utils/generater/annotation/admin/form/Switch.java
New file
@@ -0,0 +1,28 @@
package org.yeshi.utils.generater.annotation.admin.form;
import java.lang.annotation.*;
/**
 * @author Administrator
 * @title: Switch
 * @projectName utils
 * @description: 开关
 * @date 2021/9/2313:42
 */
@Documented
@Target(ElementType.FIELD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface Switch {
    //标题
    String title();
    //是否可更新
    boolean update() default true;
    //简介
    String desc() default "";
    //是否禁止编辑
    boolean disable() default false;
}
src/main/java/org/yeshi/utils/generater/annotation/admin/form/Text.java
New file
@@ -0,0 +1,62 @@
package org.yeshi.utils.generater.annotation.admin.form;
import org.yeshi.utils.generater.entity.admin.FormVerifyType;
import java.lang.annotation.*;
/**
 * @author Administrator
 * @title: Text
 * @projectName utils
 * @description: 文本
 * @date 2021/9/2312:07
 */
@Documented
@Target(ElementType.FIELD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface Text {
    //标题
    String title();
    //是否可更新
    boolean update() default true;
    //简介
    String desc() default "";
    //是否禁止编辑
    boolean disable() default false;
    //是否必须
    boolean require() default false;
    //最小长度
    int minLength() default -1;
    //最长长度
    int maxLength() default -1;
    //验证类型
    FormVerifyType verifyType() default FormVerifyType.none;
    //如果验证类型为正则需要此项
    String verifyValue() default "";
    //如果验证类型为正则需要此项
    String verifyNotifyMsg() default "";
    String placeHolder() default "";
    Type inputType() default Type.TEXT;
    //当inputType为DATE或者DATETIME时有效
    String dateFormat() default "yyyy.MM.dd";
    enum Type {
        TEXT, DATE, DATETIME;
    }
}
src/main/java/org/yeshi/utils/generater/annotation/admin/form/TextArea.java
New file
@@ -0,0 +1,52 @@
package org.yeshi.utils.generater.annotation.admin.form;
import org.yeshi.utils.generater.entity.admin.FormVerifyType;
import java.lang.annotation.*;
/**
 * @author Administrator
 * @title: TextArea
 * @projectName utils
 * @description: 文本域
 * @date 2021/9/2312:07
 */
@Documented
@Target(ElementType.FIELD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface TextArea {
    //标题
    String title();
    //是否可更新
    boolean update() default true;
    //简介
    String desc() default "";
    //是否禁止编辑
    boolean disable() default false;
    //是否必须
    boolean require() default false;
    //最小长度
    int minLength() default -1;
    //最长长度
    int maxLength() default -1;
    //验证类型
    FormVerifyType verifyType();
    //如果验证类型为正则需要此项
    String verifyValue() default "";
    //如果验证类型为正则需要此项
    String verifyNotifyMsg() default "";
    String placeHolder() default "";
}
src/main/java/org/yeshi/utils/generater/entity/CommonSearchForm.java
New file
@@ -0,0 +1,44 @@
package org.yeshi.utils.generater.entity;
import org.yeshi.utils.generater.annotation.admin.form.Text;
/**
 * @author Administrator
 * @title: CommonSearchForm
 * @description: 搜索表单
 * @date 2021/9/23 16:12
 */
public class CommonSearchForm {
    @Text(title = "开始日期", inputType = Text.Type.DATE)
    private String startDate;
    @Text(title = "结束日期", inputType = Text.Type.DATE)
    private String endDate;
    @Text(title = "请输入关键词", inputType = Text.Type.TEXT)
    private String key;
    public String getStartDate() {
        return startDate;
    }
    public void setStartDate(String startDate) {
        this.startDate = startDate;
    }
    public String getEndDate() {
        return endDate;
    }
    public void setEndDate(String endDate) {
        this.endDate = endDate;
    }
    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }
}
src/main/java/org/yeshi/utils/generater/entity/DaoQueryColumnData.java
New file
@@ -0,0 +1,23 @@
package org.yeshi.utils.generater.entity;
import org.yeshi.utils.generater.annotation.admin.DaoQueryCondition;
public class DaoQueryColumnData extends ColumnData {
    //查询方式
    private DaoQueryCondition.QueryType queryType;
    public DaoQueryColumnData(String columnName, String type, DaoQueryCondition.QueryType queryType) {
        super(columnName, type);
        this.queryType = queryType;
    }
    public DaoQueryCondition.QueryType getQueryType() {
        return queryType;
    }
    public void setQueryType(DaoQueryCondition.QueryType queryType) {
        this.queryType = queryType;
    }
}
src/main/java/org/yeshi/utils/generater/entity/KeyValue.java
New file
@@ -0,0 +1,33 @@
package org.yeshi.utils.generater.entity;
/**
 * @author Administrator
 * @title: KeyValue
 * @description: 键值对
 * @date 2021/9/23 17:42
 */
public class KeyValue {
    private String key;
    private String value;
    public KeyValue(String key, String value) {
        this.key = key;
        this.value = value;
    }
    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
}
src/main/java/org/yeshi/utils/generater/entity/MongoDBDaoData.java
@@ -2,6 +2,7 @@
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.yeshi.utils.generater.annotation.admin.DaoQueryCondition;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
@@ -19,6 +20,8 @@
    private ColumnData identityColumn;
    private List<ColumnData> columnDataList;
    private List<DaoQueryColumnData> daoQueryColumnDataList;
    public static class Builder {
@@ -62,6 +65,7 @@
            String identityColumnName = null;
            String identityColumnType = null;
            List<ColumnData> columlist = new ArrayList<>();
            List<DaoQueryColumnData> daoQueryColumnList = new ArrayList<>();
            for (Field fd : fields) {
                //private/public 非final,static属性才会参与解析
                if (fd.getModifiers() != 1 && fd.getModifiers() != 2) {
@@ -89,6 +93,14 @@
                    //不参与解析
                    if (a instanceof Transient || a instanceof java.beans.Transient) {
                        columName = null;
                        break;
                    }
                }
                //获取查询条件
                for (Annotation a : as) {
                    if (a instanceof DaoQueryCondition) {
                        daoQueryColumnList.add(new DaoQueryColumnData(columName, columnDataType, ((DaoQueryCondition) a).queryType()));
                        break;
                    }
                }
@@ -121,6 +133,7 @@
            MongoDBDaoData data = new MongoDBDaoData();
            data.setBaseDaoClassName(baseDaoClass.getSimpleName());
            data.setColumnDataList(columnDataList);
            data.setDaoQueryColumnDataList(daoQueryColumnList);
            data.setDaoName(daoName);
            data.setEntityClass(entityClass.getName());
            data.setEntityClassName(entityClass.getSimpleName());
@@ -185,4 +198,13 @@
    public void setImportClasses(Set<String> importClasses) {
        this.importClasses = importClasses;
    }
    public List<DaoQueryColumnData> getDaoQueryColumnDataList() {
        return daoQueryColumnDataList;
    }
    public void setDaoQueryColumnDataList(List<DaoQueryColumnData> daoQueryColumnDataList) {
        this.daoQueryColumnDataList = daoQueryColumnDataList;
    }
}
src/main/java/org/yeshi/utils/generater/entity/admin/AdminGeneraterInfo.java
New file
@@ -0,0 +1,115 @@
package org.yeshi.utils.generater.entity.admin;
import org.yeshi.utils.generater.annotation.admin.AdminController;
import org.yeshi.utils.generater.util.AnotationUtil;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Map;
/**
 * @author Administrator
 * @title: AdminGeneraterInfo
 * @description: TODO
 * @date 2021/9/24 11:03
 */
public class AdminGeneraterInfo {
    //entity类
    private Class entity;
    //controller注解对象
    private Map<String, Object> controllerData;
    //修改的表单行数据
    private List<FormRowData> updateFormRows;
    //添加的表单行数据
    private List<FormRowData> addFormRows;
    //搜索的表单行数据
    private List<FormRowData> searchFormRows;
    private List<Map<String, Object>> showDataList;
    public Class getEntity() {
        return entity;
    }
    public void setEntity(Class entity) {
        this.entity = entity;
    }
    public Map<String, Object> getControllerData() {
        return controllerData;
    }
    public void setControllerData(Map<String, Object> controllerData) {
        this.controllerData = controllerData;
    }
    public List<FormRowData> getUpdateFormRows() {
        return updateFormRows;
    }
    public void setUpdateFormRows(List<FormRowData> updateFormRows) {
        this.updateFormRows = updateFormRows;
    }
    public List<FormRowData> getAddFormRows() {
        return addFormRows;
    }
    public void setAddFormRows(List<FormRowData> addFormRows) {
        this.addFormRows = addFormRows;
    }
    public List<FormRowData> getSearchFormRows() {
        return searchFormRows;
    }
    public void setSearchFormRows(List<FormRowData> searchFormRows) {
        this.searchFormRows = searchFormRows;
    }
    public List<Map<String, Object>> getShowDataList() {
        return showDataList;
    }
    public void setShowDataList(List<Map<String, Object>> showDataList) {
        this.showDataList = showDataList;
    }
    public static class Builder {
        private Class entity;
        public Builder setEntityClass(Class clazz) {
            this.entity = clazz;
            return this;
        }
        public AdminGeneraterInfo build() throws Exception {
            if (entity == null) {
                throw new Exception("尚未设置entity");
            }
            //查询是否需要生成管理界面与controller
            Annotation[] ans = entity.getAnnotations();
            for (Annotation an : ans) {
                if (an instanceof AdminController) {
                    Class searchFormClass = ((AdminController) an).searchForm();
                    AdminGeneraterInfo info = new AdminGeneraterInfo();
                    info.setControllerData(AnotationUtil.getParamsMap(an));
                    info.setSearchFormRows(AnotationUtil.getFormRowData(searchFormClass));
                    info.setAddFormRows(AnotationUtil.getFormRowData(entity));
                    info.setUpdateFormRows(AnotationUtil.getUpdateFormRowData(entity));
                    info.setShowDataList(AnotationUtil.getShowDataList(entity));
                    return info;
                }
            }
            return null;
        }
    }
}
src/main/java/org/yeshi/utils/generater/entity/admin/FormRowData.java
New file
@@ -0,0 +1,43 @@
package org.yeshi.utils.generater.entity.admin;
import java.util.Map;
/**
 * @author Administrator
 * @title: FormRowData
 * @description: 后台编辑表单每一行的信息
 * @date 2021/9/24 10:39
 */
public class FormRowData {
    //键值
    private String key;
    //行类型
    private String type;
    //参数
    private Map<String, Object> params;
    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public Map<String, Object> getParams() {
        return params;
    }
    public void setParams(Map<String, Object> params) {
        this.params = params;
    }
}
src/main/java/org/yeshi/utils/generater/entity/admin/FormVerifyType.java
New file
@@ -0,0 +1,17 @@
package org.yeshi.utils.generater.entity.admin;
/**
 * @author Administrator
 * @title: FormVerifyType
 * @description: 表单验证类型
 * @date 2021/9/23 14:00
 */
public enum FormVerifyType {
    number("数字"), phone("电话号码"), email("邮箱"), date("日期"), url("链接"), identity("身份证"), regex("正则"),none("无验证规则");
    private FormVerifyType(String desc) {
    }
}
src/main/java/org/yeshi/utils/generater/exception/AnotationException.java
New file
@@ -0,0 +1,9 @@
package org.yeshi.utils.generater.exception;
public class AnotationException extends Exception {
    public AnotationException(String msg) {
        super(msg);
    }
}
src/main/java/org/yeshi/utils/generater/util/AnotationUtil.java
New file
@@ -0,0 +1,132 @@
package org.yeshi.utils.generater.util;
import org.yeshi.utils.StringUtil;
import org.yeshi.utils.generater.annotation.admin.Show;
import org.yeshi.utils.generater.annotation.admin.form.*;
import org.yeshi.utils.generater.entity.KeyValue;
import org.yeshi.utils.generater.entity.admin.FormRowData;
import org.yeshi.utils.generater.exception.AnotationException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.*;
/**
 * @author Administrator
 * @title: FormAnotationUtil
 * @description: 注解帮助类
 * @date 2021/9/24 10:31
 */
public class AnotationUtil {
    public static Map<String, Object> getParamsMap(Annotation a) throws InvocationTargetException, IllegalAccessException {
        Map<String, Object> params = new HashMap<>();
        Method[] fs = a.getClass().getDeclaredMethods();
        for (Method md : fs) {
            if (md.getGenericParameterTypes().length > 0)
                continue;
            if (md.getName().equals("toString") || md.getName().equals("hashCode") || md.getName().equalsIgnoreCase("annotationType"))
                continue;
            Object value = md.invoke(a);
            if (value instanceof String[]) {
                params.put(md.getName(), value);
                List<KeyValue> values = new ArrayList<>();
                String[] arrays = (String[]) value;
                if (arrays.length == 1 && StringUtil.isNullOrEmpty(arrays[0])) {
                } else {
                    for (String st : (String[]) value) {
                        values.add(new KeyValue(st.substring(0, st.indexOf(",")), st.substring(st.indexOf(",") + 1)));
                    }
                }
                params.put(md.getName(), values);
            } else {
                params.put(md.getName(), value);
            }
        }
        return params;
    }
    //获取表单的行数据
    public static List<FormRowData> getFormRowData(Class entity) throws AnotationException, Exception {
        List<FormRowData> list = new ArrayList<>();
        Field[] fields = entity.getDeclaredFields();
        for (Field fd : fields) {
            Annotation[] as = fd.getAnnotations();
            FormRowData formRowData = null;
            for (Annotation an : as) {
                formRowData = new FormRowData();
                if (an instanceof CheckBox) {
                    FormAnotationValidUtil.valid((CheckBox) an);
                } else if (an instanceof Img) {
                    FormAnotationValidUtil.valid((Img) an);
                } else if (an instanceof Password) {
                    FormAnotationValidUtil.valid((Password) an);
                } else if (an instanceof RadioGroup) {
                    FormAnotationValidUtil.valid((RadioGroup) an);
                } else if (an instanceof Select) {
                    FormAnotationValidUtil.valid((Select) an);
                } else if (an instanceof Switch) {
                    FormAnotationValidUtil.valid((Switch) an);
                } else if (an instanceof Text) {
                    FormAnotationValidUtil.valid((Text) an);
                } else if (an instanceof TextArea) {
                    FormAnotationValidUtil.valid((TextArea) an);
                } else {
                    formRowData = null;
                }
                if (formRowData != null) {
                    formRowData.setKey(fd.getName());
                    formRowData.setType(an.annotationType().getSimpleName());
                    formRowData.setParams(getParamsMap(an));
                    list.add(formRowData);
                    break;
                }
            }
        }
        return list;
    }
    //获取可以更新的字段
    public static List<FormRowData> getUpdateFormRowData(Class entity) throws AnotationException, Exception {
        List<FormRowData> list = getFormRowData(entity);
        if (list != null) {
            for (int i = 0; i < list.size(); i++) {
                if (list.get(i) == null || list.get(i).getParams() == null || !((Boolean) list.get(i).getParams().get("update"))) {
                    //没有配置更新项目
                    list.remove(i--);
                }
            }
        }
        return list;
    }
    //获取显示的字段数据
    public static List<Map<String, Object>> getShowDataList(Class entity) throws InvocationTargetException, IllegalAccessException {
        List<Map<String, Object>> list = new ArrayList<>();
        Field[] fields = entity.getDeclaredFields();
        for (Field fd : fields) {
            Annotation[] as = fd.getAnnotations();
            FormRowData formRowData = null;
            for (Annotation an : as) {
                if (an instanceof Show) {
                    list.add(getParamsMap(an));
                }
            }
        }
        if (list != null && list.size() > 0) {
            Comparator<Map<String, Object>> cm = (Map<String, Object> o1, Map<String, Object> o2) -> {
                return (int) (o1.get("order")) - (int) (o2.get("order"));
            };
            Collections.sort(list, cm);
        }
        return list;
    }
}
src/main/java/org/yeshi/utils/generater/util/FormAnotationValidUtil.java
New file
@@ -0,0 +1,127 @@
package org.yeshi.utils.generater.util;
import org.yeshi.utils.StringUtil;
import org.yeshi.utils.generater.annotation.admin.form.*;
import org.yeshi.utils.generater.entity.admin.FormVerifyType;
import org.yeshi.utils.generater.exception.AnotationException;
/**
 * @author Administrator
 * @title: FormEditValidUtil
 * @description: 验证表单的注解是否正确
 * @date 2021/9/23 15:30
 */
public class FormAnotationValidUtil {
    private static void validTitle(String title) throws AnotationException {
        if (StringUtil.isNullOrEmpty(title)) {
            throw new AnotationException("title不能为空");
        }
    }
    public static void valid(Text text) throws AnotationException {
        validTitle(text.title());
        //验证长度
        if (text.minLength() > text.maxLength()) {
            throw new AnotationException("最大长度不能小于最小长度");
        }
        if (text.verifyType() == FormVerifyType.regex && StringUtil.isNullOrEmpty(text.verifyValue())) {
            throw new AnotationException("验证的输入的正则表达式不能为空");
        }
        if (text.verifyType() == FormVerifyType.regex && StringUtil.isNullOrEmpty(text.verifyNotifyMsg())) {
            throw new AnotationException("不满足正则表达式的提示语不能为空");
        }
        if (text.inputType() == Text.Type.DATE || text.inputType() == Text.Type.DATETIME) {
            if (StringUtil.isNullOrEmpty(text.dateFormat())) {
                throw new AnotationException("日志格式化表达式不能为空");
            }
        }
    }
    public static void valid(TextArea text) throws AnotationException {
        validTitle(text.title());
        //验证长度
        if (text.minLength() > text.maxLength()) {
            throw new AnotationException("最大长度不能小于最小长度");
        }
        if (text.verifyType() == FormVerifyType.regex && StringUtil.isNullOrEmpty(text.verifyValue())) {
            throw new AnotationException("验证的输入的正则表达式不能为空");
        }
        if (text.verifyType() == FormVerifyType.regex && StringUtil.isNullOrEmpty(text.verifyNotifyMsg())) {
            throw new AnotationException("不满足正则表达式的提示语不能为空");
        }
    }
    public static void valid(CheckBox checkBox) throws AnotationException {
        validTitle(checkBox.title());
        //验证长度
        if (checkBox.values() == null || checkBox.values().length < 1) {
            throw new AnotationException("复选框的内容不能为空");
        }
        for (String st : checkBox.values()) {
            if (!st.contains(",")) {
                throw new AnotationException("复选框的内容格式错误,键值对要用逗号分隔");
            }
        }
    }
    public static void valid(Img img) throws AnotationException {
        validTitle(img.title());
    }
    public static void valid(Password password) throws AnotationException {
        validTitle(password.title());
        //验证长度
        if (password.minLength() > password.maxLength()) {
            throw new AnotationException("最大长度不能小于最小长度");
        }
    }
    public static void valid(RadioGroup radioGroup) throws AnotationException {
        validTitle(radioGroup.title());
        if (radioGroup.values() == null || radioGroup.values().length < 1) {
            throw new AnotationException("单选框的内容不能为空");
        }
        for (String st : radioGroup.values()) {
            if (!st.contains(",")) {
                throw new AnotationException("单选框的内容格式错误,键值对要用逗号分隔");
            }
        }
    }
    public static void valid(Select select) throws AnotationException {
        validTitle(select.title());
        if ((select.values() == null || select.values().length < 1 || (select.values().length == 1 && StringUtil.isNullOrEmpty(select.values()[0])))) {
            if (StringUtil.isNullOrEmpty(select.apiPath())) {
                throw new AnotationException("下拉框的内容不能为空");
            }
        } else {
            for (String st : select.values()) {
                if (!st.contains(",")) {
                    throw new AnotationException("下拉框的内容格式错误,键值对要用逗号分隔");
                }
            }
        }
    }
    public static void valid(Switch st) throws AnotationException {
        validTitle(st.title());
    }
}
src/main/java/org/yeshi/utils/ios/pay/IOSPayVerifyUtil.java
@@ -1,8 +1,9 @@
package org.yeshi.utils.ios.pay;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.yeshi.utils.HttpUtil;
import org.yeshi.utils.ios.pay.vo.IOSAPPBuyVerifyResult;
import javax.net.ssl.*;
@@ -10,9 +11,11 @@
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Locale;
public class IOSPayVerifyUtil {
@@ -91,6 +94,15 @@
            JSONObject receiptNew = root.optJSONObject("receipt");
            Gson gson = new Gson();
            IOSAPPBuyVerifyResult verifyResult = gson.fromJson(receiptNew.toString(), IOSAPPBuyVerifyResult.class);
            JSONArray latestReceiptInfo = root.optJSONArray("latest_receipt_info");
            if (latestReceiptInfo != null) {
                Type type = new TypeToken<List<IOSAPPBuyVerifyResult.OrderInfo>>() {
                }.getType();
                List<IOSAPPBuyVerifyResult.OrderInfo> orderInfoList = gson.fromJson(latestReceiptInfo.toString(), type);
                verifyResult.setLatestReceiptInfo(orderInfoList);
            }
            return verifyResult;
        } catch (Exception ex) {
            ex.printStackTrace();
@@ -99,7 +111,7 @@
    }
    public static void main(String[] args) {
        String receiptData = "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";
        String receiptData = "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";
        try {
            IOSAPPBuyVerifyResult result=    buyAppVerify(receiptData, "28ca52e358b94c4eba3de41dfa7dd023", true);
            System.out.println(result);
src/main/java/org/yeshi/utils/ios/pay/vo/IOSAPPBuyVerifyResult.java
@@ -21,6 +21,17 @@
    private Long requestDateMs;
    @SerializedName("in_app")
    private List<OrderInfo> inApps;
    @SerializedName("latest_receipt_info")
    private  List<OrderInfo> latestReceiptInfo;
    public List<OrderInfo> getLatestReceiptInfo() {
        return latestReceiptInfo;
    }
    public void setLatestReceiptInfo(List<OrderInfo> latestReceiptInfo) {
        this.latestReceiptInfo = latestReceiptInfo;
    }
    public String getBundleId() {
        return bundleId;
src/main/resources/generater/admin/add.ftl
New file
@@ -0,0 +1,181 @@
<!DOCTYPE html>
<html class="x-admin-sm">
<head>
    <meta charset="UTF-8">
    <title>新增${controllerData.title}</title>
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport"
          content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8,target-densitydpi=low-dpi"/>
    <link rel="stylesheet" href="./css/font.css">
    <link rel="stylesheet" href="./css/xadmin.css">
    <script type="text/javascript" src="./lib/layui/layui.js" charset="utf-8"></script>
    <script type="text/javascript" src="./js/xadmin.js"></script>
    <script src="js/vue.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="js/http.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
    <!-- 让IE8/9支持媒体查询,从而兼容栅格 -->
    <!--[if lt IE 9]>
    <script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
    <script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->
</head>
<body>
<div class="layui-fluid">
    <div class="layui-row">
        <form class="layui-form" lay-filter="add">
            <#list addFormRows as value>
                <div class="layui-form-item">
                    <label for="L_appCode" class="layui-form-label">
                        <#if value.params.require??&&value.params.require>
                           <span class="x-red">*</span>
                        </#if>
                        ${value.params.title}</label>
                    <#switch value.type>
                        <#case "CheckBox"><#include "/admin/form/checkBox.ftl" ><#break>
                        <#case "Img">  <#include "/admin/form/img.ftl"><#break>
                        <#case "Password">  <#include "/admin/form/password.ftl"><#break>
                        <#case "RadioGroup">  <#include "/admin/form/radioGroup.ftl"><#break>
                        <#case "Select">  <#include "/admin/form/select.ftl"><#break>
                        <#case "Switch">  <#include "/admin/form/switch.ftl"><#break>
                        <#case "Text">  <#include "/admin/form/text.ftl"><#break>
                        <#case "TextArea">  <#include "/admin/form/textArea.ftl"><#break>
                        <#default>
                    </#switch>
                <#if (value.desc!"") != "">
                    <div class="layui-form-mid layui-word-aux">${value.desc}</div>
                </#if>
                </div>
            </#list>
            <div class="layui-form-item">
                <label for="L_remarks" class="layui-form-label"></label>
                <button class="layui-btn" lay-filter="add" lay-submit="">确定</button>
            </div>
        </form>
    </div>
</div>
<script>
    layui.use(['form', 'layer', 'jquery'], function () {
        $ = layui.jquery;
        var form = layui.form,
                layer = layui.layer;
        //自定义验证规则
        form.verify({
            username: function (value) {
                if (value.length < 3) {
                    return '名称至少得3个字符';
                }
            },
            code: function (value) {
                if (value) {
                    if (!(/^([A-Za-z0-9]|\-|_)+$/).test(value)) {
                        return '标识只能包含 数字、英文字符、_ 、-';
                    }
                }
            },
            packageName: [/^([A-Za-z0-9]|\-|_|\.)+$/, '包名只能包含 数字、英文字符、_ 、-、.'],
            desc: function (value) {
                if (value != null && value.length > 128) {
                    return '简介最大为128个字符';
                }
            },
            remarks: function (value) {
                if (value != null && value.length > 128) {
                    return '备注最大为128个字符';
                }
            },
        });
        //监听提交
        form.on('submit(add)',
                function (data) {
                    console.log(data.field);
                    //转换json对象
                    for (key in data.field) {
                        if (key.indexOf(".") > -1) {
                            var value = data.field[key];
                            delete data.field[key];
                            var onkeys = key.split(".");
                            //创建对象
                            if (data.field[onkeys[0]] == undefined) {
                                data.field[onkeys[0]] = {};
                            }
                            data.field[onkeys[0]][onkeys[1]] = value;
                        }
                    }
                    //发异步,把数据提交给php
                    ksapp.postJSON('/admin/api/pushplatform-app/add', data.field, function (res) {
                        if (res.code == 0) {
                            layer.alert("增加成功", {
                                        icon: 6
                                    },
                                    function () {
                                        //关闭当前frame
                                        xadmin.close();
                                        // 可以对父窗口进行刷新
                                        // xadmin.father_reload();
                                    });
                        } else {
                            layer.msg(res.msg);
                        }
                    }, function (res) {
                    });
                    return false;
                });
    });
    var app = new Vue({
        el: '.layui-form',
        data: {
            appList: [],
            platformList: [
                {name: "小米", platform: "xm"},
                {name: "华为", platform: "hw"},
                {name: "OPPO", platform: "oppo"},
                {name: "VIVO", platform: "vivo"},
                {name: "魅族", platform: "mz"}
            ]
        },
        created: function () {
            this.getAppList();
        },
        watch: {
            appList: function () {
                app.render();
            }
        },
        methods: {
            getAppList: function () {
                ksapp.post("/admin/api/app/list", {page: 1, limit: 100}, function (e) {
                    if (e.code == 0) {
                        app.appList = e.data.list;
                    } else
                        layer.msg(e.msg);
                }, function (e) {
                });
            },
            render: function () {
                console.log("render")
            }
        }
    });
</script>
</body>
</html>
src/main/resources/generater/admin/adminController.template
copy from src/main/resources/mongoDBDao.template copy to src/main/resources/generater/admin/adminController.template
File was copied from src/main/resources/mongoDBDao.template
@@ -47,7 +47,7 @@
    private Query getQuery(DaoQuery daoQuery){
          List<Criteria> andList=new ArrayList<>();
           <#list columnDataList as value>
           <#list daoQueryColumnDataList as value>
               <#if (value.type!"") == "Date">
               if(daoQuery.min${value.columnName?cap_first}!=null){
                    andList.add(Criteria.where("${value.columnName}").gte(daoQuery.min${value.columnName?cap_first}));
@@ -57,7 +57,11 @@
               }
               <#else>
               if(daoQuery.${value.columnName}!=null){
                 <#if (value.queryType!"") == "equal">
                    andList.add(Criteria.where("${value.columnName}").is(daoQuery.${value.columnName}));
                 <#else>
                      andList.add(Criteria.where("${value.columnName}").regex(daoQuery.${value.columnName}));
                 </#if>
               }
               </#if>
          </#list>
@@ -71,8 +75,8 @@
    }
  public static class DaoQuery{
     <#if columnDataList??>
       <#list columnDataList as value>
     <#if daoQueryColumnDataList??>
       <#list daoQueryColumnDataList as value>
        <#if (value.type!"") == "Date">
        public ${value.type} min${value.columnName?cap_first};
        public ${value.type} max${value.columnName?cap_first};
src/main/resources/generater/admin/form/checkBox.ftl
New file
@@ -0,0 +1,3 @@
                       <div class="layui-input-block">
                            <input type="checkbox" name="${value.key}" title="写作">
                        </div>
src/main/resources/generater/admin/form/img.ftl
New file
@@ -0,0 +1,6 @@
                    <div class="layui-input-inline">
                        <select id="L_appCode" name="appCode" lay-verify="required" lay-search="">
                            <option value="">直接选择或搜索应用</option>
                            <option v-for="item in appList" :value="item.appCode">{{item.name}}</option>
                        </select>
                    </div>
src/main/resources/generater/admin/form/password.ftl
New file
@@ -0,0 +1,4 @@
                    <div class="layui-input-inline">
                        <input type="password" name="${value.key}" required lay-verify="required" placeholder="请输入密码" autocomplete="off"
                               class="layui-input">
                    </div>
src/main/resources/generater/admin/form/radioGroup.ftl
New file
@@ -0,0 +1,5 @@
                    <div class="layui-input-block">
                            <#list value.params.values as item >
                                <input type="radio" name="${value.key}" value="${item.key}" title="${item.value}">
                            </#list>
                    </div>
src/main/resources/generater/admin/form/select.ftl
New file
@@ -0,0 +1,9 @@
                    <div class="layui-input-block">
                        <select name="${value.key}" lay-verify="required">
                                <#if value.params.values??&&(value.params.values?size>0)>
                                    <#list value.params.values as item>
                                      <option value="${item.key}">${item.value}</option>
                                    </#list>
                                </#if>
                        </select>
                    </div>
src/main/resources/generater/admin/form/switch.ftl
New file
@@ -0,0 +1,3 @@
                    <div class="layui-input-block">
                        <input type="checkbox" name="${value.key}" lay-skin="switch">
                    </div>
src/main/resources/generater/admin/form/text.ftl
New file
@@ -0,0 +1,4 @@
                    <div class="layui-input-block">
                        <input type="text" name="${value.key}" required lay-verify="required" placeholder="${value.params.placeHolder}" autocomplete="off"
                               class="layui-input">
                    </div>
src/main/resources/generater/admin/form/textArea.ftl
New file
@@ -0,0 +1,3 @@
                    <div class="layui-input-block">
                        <textarea name="${value.key}" placeholder="${value.params.placeHolder}" class="layui-textarea"></textarea>
                    </div>
src/main/resources/generater/admin/list.flt
copy from src/main/resources/mongoDBDao.template copy to src/main/resources/generater/admin/list.flt
File was copied from src/main/resources/mongoDBDao.template
@@ -47,7 +47,7 @@
    private Query getQuery(DaoQuery daoQuery){
          List<Criteria> andList=new ArrayList<>();
           <#list columnDataList as value>
           <#list daoQueryColumnDataList as value>
               <#if (value.type!"") == "Date">
               if(daoQuery.min${value.columnName?cap_first}!=null){
                    andList.add(Criteria.where("${value.columnName}").gte(daoQuery.min${value.columnName?cap_first}));
@@ -57,7 +57,11 @@
               }
               <#else>
               if(daoQuery.${value.columnName}!=null){
                 <#if (value.queryType!"") == "equal">
                    andList.add(Criteria.where("${value.columnName}").is(daoQuery.${value.columnName}));
                 <#else>
                      andList.add(Criteria.where("${value.columnName}").regex(daoQuery.${value.columnName}));
                 </#if>
               }
               </#if>
          </#list>
@@ -71,8 +75,8 @@
    }
  public static class DaoQuery{
     <#if columnDataList??>
       <#list columnDataList as value>
     <#if daoQueryColumnDataList??>
       <#list daoQueryColumnDataList as value>
        <#if (value.type!"") == "Date">
        public ${value.type} min${value.columnName?cap_first};
        public ${value.type} max${value.columnName?cap_first};
src/main/resources/generater/admin/update.ftl
copy from src/main/resources/mongoDBDao.template copy to src/main/resources/generater/admin/update.ftl
File was copied from src/main/resources/mongoDBDao.template
@@ -47,7 +47,7 @@
    private Query getQuery(DaoQuery daoQuery){
          List<Criteria> andList=new ArrayList<>();
           <#list columnDataList as value>
           <#list daoQueryColumnDataList as value>
               <#if (value.type!"") == "Date">
               if(daoQuery.min${value.columnName?cap_first}!=null){
                    andList.add(Criteria.where("${value.columnName}").gte(daoQuery.min${value.columnName?cap_first}));
@@ -57,7 +57,11 @@
               }
               <#else>
               if(daoQuery.${value.columnName}!=null){
                 <#if (value.queryType!"") == "equal">
                    andList.add(Criteria.where("${value.columnName}").is(daoQuery.${value.columnName}));
                 <#else>
                      andList.add(Criteria.where("${value.columnName}").regex(daoQuery.${value.columnName}));
                 </#if>
               }
               </#if>
          </#list>
@@ -71,8 +75,8 @@
    }
  public static class DaoQuery{
     <#if columnDataList??>
       <#list columnDataList as value>
     <#if daoQueryColumnDataList??>
       <#list daoQueryColumnDataList as value>
        <#if (value.type!"") == "Date">
        public ${value.type} min${value.columnName?cap_first};
        public ${value.type} max${value.columnName?cap_first};
src/main/resources/generater/mongoDBDao.template
File was renamed from src/main/resources/mongoDBDao.template
@@ -47,7 +47,7 @@
    private Query getQuery(DaoQuery daoQuery){
          List<Criteria> andList=new ArrayList<>();
           <#list columnDataList as value>
           <#list daoQueryColumnDataList as value>
               <#if (value.type!"") == "Date">
               if(daoQuery.min${value.columnName?cap_first}!=null){
                    andList.add(Criteria.where("${value.columnName}").gte(daoQuery.min${value.columnName?cap_first}));
@@ -57,7 +57,11 @@
               }
               <#else>
               if(daoQuery.${value.columnName}!=null){
                 <#if (value.queryType!"") == "equal">
                    andList.add(Criteria.where("${value.columnName}").is(daoQuery.${value.columnName}));
                 <#else>
                      andList.add(Criteria.where("${value.columnName}").regex(daoQuery.${value.columnName}));
                 </#if>
               }
               </#if>
          </#list>
@@ -71,8 +75,8 @@
    }
  public static class DaoQuery{
     <#if columnDataList??>
       <#list columnDataList as value>
     <#if daoQueryColumnDataList??>
       <#list daoQueryColumnDataList as value>
        <#if (value.type!"") == "Date">
        public ${value.type} min${value.columnName?cap_first};
        public ${value.type} max${value.columnName?cap_first};
src/main/resources/generater/service.template
src/main/resources/generater/serviceImpl.template
src/test/java/com/generater/GeneratorTest.java
@@ -1,19 +1,82 @@
package com.generater;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Template;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.yeshi.utils.FreemarkerUtils;
import org.yeshi.utils.generater.SpringComponentGenerater;
import org.yeshi.utils.generater.annotation.admin.form.CheckBox;
import org.yeshi.utils.generater.annotation.admin.form.Select;
import org.yeshi.utils.generater.annotation.admin.form.Text;
import org.yeshi.utils.generater.entity.KeyValue;
import org.yeshi.utils.generater.entity.MongoDBDaoData;
import org.yeshi.utils.generater.entity.admin.AdminGeneraterInfo;
import org.yeshi.utils.generater.mybatis.Column;
import org.yeshi.utils.generater.mybatis.MyBatisMapperUtil;
import org.yeshi.utils.generater.mybatis.Table;
import java.util.Date;
import java.io.File;
import java.io.InputStream;
import java.io.StringWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.regex.Pattern;
public class GeneratorTest {
        public static void main(String[] args) throws Exception {
        //SpringComponentGenerater.createMongoDao(new MongoDBDaoData.Builder().setBaseDaoClass(BaseDao.class).setDaoPackageName("com.generator.result").setEntityClass(Entity.class).create(), "D:\\workspace\\server\\utils\\src\\test\\java\\com\\generater\\result");
        MyBatisMapperUtil.createMapper(Entity.class);
//        MyBatisMapperUtil.createMapper(Entity.class);
//打乱xml中的数据
//        Scanner scanner = new Scanner(new File("D:\\workspace\\Android\\buwan\\HanJuPlayer\\app\\res\\values\\strings.xml"));
//        List<String> lines = new ArrayList<>();
//        while (scanner.hasNextLine()) {
//            String line = scanner.nextLine().trim();
//            if (line == null || (line.startsWith("<?xml") || line.contains("<resources>") || line.contains("</resources>")))
//                continue;
//            lines.add(line);
//        }
//        scanner.close();
//        Collections.shuffle(lines);
//        for (String line : lines) {
//            System.out.println(line);
//        }
        AdminGeneraterInfo info = new AdminGeneraterInfo.Builder().setEntityClass(TestEntity.class).build();
        //将所有的控件模板加载进去
        String[] template = new String[]{
                "admin/form/checkBox.ftl",
                "admin/form/img.ftl",
                "admin/form/password.ftl",
                "admin/form/radioGroup.ftl",
                "admin/form/select.ftl",
                "admin/form/switch.ftl",
                "admin/form/text.ftl",
                "admin/form/textArea.ftl",
                "admin/add.ftl"
        };
        Map<String, InputStream> map = new HashMap<>();
        for (String st : template) {
            map.put(st, SpringComponentGenerater.class.getClassLoader().getResourceAsStream("generater/" + st));
        }
        String result = FreemarkerUtils.generateInputStream(info, "admin/add.ftl", map);
        System.out.println(result);
        //
//        boolean match = Pattern.matches("^(https://){1}.*(\\.m3u8)$", "https://n1.szjal.cn/20210805/qnDXhXBa/index.m3u8123");
//        System.out.println(match);
    }
src/test/java/com/generater/TestEntity.java
New file
@@ -0,0 +1,132 @@
package com.generater;
import org.springframework.data.annotation.Id;
import org.yeshi.utils.generater.annotation.admin.AdminController;
import org.yeshi.utils.generater.annotation.admin.DaoQueryCondition;
import org.yeshi.utils.generater.annotation.admin.Show;
import org.yeshi.utils.generater.annotation.admin.form.Img;
import org.yeshi.utils.generater.annotation.admin.form.RadioGroup;
import org.yeshi.utils.generater.annotation.admin.form.Select;
import org.yeshi.utils.generater.annotation.admin.form.Text;
import org.yeshi.utils.generater.entity.admin.FormVerifyType;
/**
 * @author Administrator
 * @title: TestEntity
 * @description: 测试entity
 * @date 2021/9/23 14:22
 */
@AdminController(mapping = "admin/api/test", title = "测试", searchForm = TestEntity.SearchForm.class)
public class TestEntity {
    @Id
    private String id;
    @DaoQueryCondition(queryType = DaoQueryCondition.QueryType.contains)
    @Show(order = 0, title = "昵称")
    @Text(title = "昵称", maxLength = 50, require = true, placeHolder = "请输入昵称", desc = "昵称不能包含特殊字符", verifyType = FormVerifyType.regex, verifyValue = "^.{0-100}$", verifyNotifyMsg = "请输入正确的昵称")
    private String nickName;
    @DaoQueryCondition
    @Show(order = 1, title = "类型")
    @Select(values = {"1,男", "2,女"}, title = "类型")
    private int type;
    @DaoQueryCondition
    @Show(order = 2, title = "性别")
    @RadioGroup(values = {"1,男", "2,女"}, title = "性别")
    private int sex;
    @Show(order = 3, title = "头像", showType = Show.ShowType.IMG, imgWidth = 50, imgHeight = 50)
    @Img(width = 50, height = 50, title = "头像")
    private String portrait;
    @DaoQueryCondition
    @Show(order = 4, title = "省")
    @Select(apiPath = "/admin/api/getProvince", title = "省")
    private String province;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getNickName() {
        return nickName;
    }
    public void setNickName(String nickName) {
        this.nickName = nickName;
    }
    public int getType() {
        return type;
    }
    public void setType(int type) {
        this.type = type;
    }
    public int getSex() {
        return sex;
    }
    public void setSex(int sex) {
        this.sex = sex;
    }
    public String getPortrait() {
        return portrait;
    }
    public void setPortrait(String portrait) {
        this.portrait = portrait;
    }
    public String getProvince() {
        return province;
    }
    public void setProvince(String province) {
        this.province = province;
    }
    public class SearchForm {
        @Text(title = "开始日期", inputType = Text.Type.DATE)
        private String startDate;
        @Text(title = "结束日期", inputType = Text.Type.DATE)
        private String endDate;
        @Text(title = "请输入关键词", inputType = Text.Type.TEXT)
        private String key;
        public String getStartDate() {
            return startDate;
        }
        public void setStartDate(String startDate) {
            this.startDate = startDate;
        }
        public String getEndDate() {
            return endDate;
        }
        public void setEndDate(String endDate) {
            this.endDate = endDate;
        }
        public String getKey() {
            return key;
        }
        public void setKey(String key) {
            this.key = key;
        }
    }
}