admin
2022-03-25 17055fd8d36504b79a5def28f5d4b4740faf012d
TDMQ工具集成
23个文件已修改
13个文件已添加
1458 ■■■■■ 已修改文件
pom.xml 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/HttpUtil.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/ThreadUtil.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/annotation/RequestMonitor.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/exception/MailSendException.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/GeneraterManager.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/GeneraterUtil.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/annotation/admin/Show.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/entity/ClassInfo.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/params/AdminGeneraterParams.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/params/DaoGeneraterParams.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/params/ServiceGeneraterParams.java 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/util/AnotationUtil.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/vo/admin/controller/AdminControllerInfoVO.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/generater/vo/admin/page/ListInfoVO.java 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/mail/EmailApiUtil.java 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/mail/EmailInfo.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/mongo/MongodbBaseDao.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/mq/TDMQUtil.java 503 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/sms/VerifyCodeFactory.java 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/statistic/BaseStatisticMySQLTimeQuery.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/statistic/BaseStatisticTimeQuery.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/statistic/StatisticNumberResult.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/statistic/StatisticResulterFilterUtil.java 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/statistic/StatisticTimeSpan.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/yeshi/utils/statistic/StatisticValueResult.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/admin/add.ftl 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/admin/adminController.template 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/admin/form/text.ftl 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/admin/list.ftl 109 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/admin/update.ftl 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/dao/mongoDBDao.template 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/dao/mybatisDBXML.ftl 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/service/method/impl/mybatis/delete.ftl 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generater/service/serviceImpl.template 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/java/com/generater/GeneratorTest.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -11,9 +11,17 @@
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <org.springframework-version>4.3.0.RELEASE</org.springframework-version>
        <spring.mongodb.version>1.10.10.RELEASE</spring.mongodb.version>
        <spring.mongodb.version>3.0.5.RELEASE</spring.mongodb.version>
        <kafka.client.version>0.10.1.1</kafka.client.version>
    </properties>
    <repositories>
        <repository>
            <id>nexus</id>
            <name>nexus</name>
            <url>http://193.112.35.168:8889/nexus/content/groups/public/</url>
        </repository>
    </repositories>
    <dependencies>
        <dependency>
@@ -192,7 +200,7 @@
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-mongodb-cross-store</artifactId>
            <version>${spring.mongodb.version}</version>
            <version>2.1.21.RELEASE</version>
        </dependency>
        <dependency>
@@ -279,12 +287,16 @@
            <groupId>ok-http</groupId>
            <artifactId>okhttp</artifactId>
            <version>3.14.2</version>
            <scope>system</scope>
            <systemPath>${basedir}/libs/okhttp-3.14.2.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>okio</groupId>
            <artifactId>okio</artifactId>
            <version>1.17.2</version>
            <scope>system</scope>
            <systemPath>${basedir}/libs/okio-1.17.2.jar</systemPath>
        </dependency>
        <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-core -->
@@ -337,6 +349,14 @@
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.tencentcloudapi</groupId>
            <artifactId>tencentcloud-sdk-java</artifactId>
            <!-- go to https://search.maven.org/search?q=tencentcloud-sdk-java and get the latest version. -->
            <!-- 请到https://search.maven.org/search?q=tencentcloud-sdk-java查询所有版本,最新版本如下 -->
            <version>3.1.472</version>
        </dependency>
@@ -398,8 +418,6 @@
                    </execution>
                </executions>
            </plugin>
        </plugins>
        <resources>
            <resource>
src/main/java/org/yeshi/utils/HttpUtil.java
@@ -450,7 +450,7 @@
    public static String post(String url, Map<String, String> map, Map<String, String> headers) {
        HttpClient client = new HttpClient();
        // client.getHostConfiguration().setProxy("192.168.1.122", 8888);
//         client.getHostConfiguration().setProxy("192.168.3.122", 8888);
        PostMethod pm = new PostMethod(url);// 创建HttpPost对象
        NameValuePair[] ns = new NameValuePair[map.keySet().size()];
        Iterator<String> its = map.keySet().iterator();
src/main/java/org/yeshi/utils/ThreadUtil.java
New file
@@ -0,0 +1,27 @@
package org.yeshi.utils;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
 * @author hxh
 * @title: ThreadUtil
 * @description: TODO
 * @date 2021/12/2 17:50
 */
public class ThreadUtil {
    private static LinkedBlockingQueue<Runnable> queue=new LinkedBlockingQueue<Runnable>(100);
    private static ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(30, 3000, 20, TimeUnit.SECONDS, queue);
    static{
        threadPoolExecutor.allowCoreThreadTimeOut(true);
    }
    public static void run(Runnable runnable){
        threadPoolExecutor.execute(runnable);
    }
}
src/main/java/org/yeshi/utils/annotation/RequestMonitor.java
New file
@@ -0,0 +1,16 @@
package org.yeshi.utils.annotation;
/**
 * @author Administrator
 * @title: RequestMonitor
 * @projectName utils
 * @description: 请求监控
 * @date 2021/10/1418:45
 */
public @interface RequestMonitor {
    //redis的主键
    String key() default "";
    //最大间隔时间 单位为s
    int maxSpaceTime();
}
src/main/java/org/yeshi/utils/exception/MailSendException.java
New file
@@ -0,0 +1,32 @@
package org.yeshi.utils.exception;
public class MailSendException extends Exception {
    public final static int CODE_NETWORK_ERROR = 1;
    public final static int CODE_BUSINESS_ERROR = 2;
    private static final long serialVersionUID = 1L;
    private int code;
    private String msg;
    public int getCode() {
        return code;
    }
    public String getMsg() {
        return msg;
    }
    public MailSendException(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    public MailSendException() {
    }
    @Override
    public String getMessage() {
        return this.msg;
    }
}
src/main/java/org/yeshi/utils/generater/GeneraterManager.java
@@ -225,6 +225,9 @@
        saveFile(result, new File(path, controllerName + ".java").getAbsolutePath());
        if (!new File(htmlDir).exists()) {
            new File(htmlDir).mkdirs();
        }
        result = GeneraterUtil.createAdminPageForList(generaterInfo);
        saveFile(result, new File(htmlDir, htmlNamePrefix + "_list.html").getAbsolutePath());
src/main/java/org/yeshi/utils/generater/GeneraterUtil.java
@@ -21,52 +21,52 @@
public class GeneraterUtil {
    public static String createException(ExceptionVO vo) throws IOException {
        String result = FreemarkerUtils.generateInputStream(vo, GeneraterUtil.class.getClassLoader().getResourceAsStream("generater\\exception.template"));
        String result = FreemarkerUtils.generateInputStream(vo, GeneraterUtil.class.getClassLoader().getResourceAsStream("generater/exception.template"));
        System.out.println(result);
        return result;
    }
    public static String createMongoDBDao(MongoDBDaoVO vo) throws IOException {
        String result = FreemarkerUtils.generateInputStream(vo, GeneraterUtil.class.getClassLoader().getResourceAsStream("generater\\dao\\mongoDBDao.template"));
        String result = FreemarkerUtils.generateInputStream(vo, GeneraterUtil.class.getClassLoader().getResourceAsStream("generater/dao/mongoDBDao.template"));
        System.out.println(result);
        return result;
    }
    public static String createMybatisDBMapper(MyBatisDBDaoVO vo) throws IOException {
        String result = FreemarkerUtils.generateInputStream(vo, GeneraterUtil.class.getClassLoader().getResourceAsStream("generater\\dao\\mybatisDBDao.template"));
        String result = FreemarkerUtils.generateInputStream(vo, GeneraterUtil.class.getClassLoader().getResourceAsStream("generater/dao/mybatisDBDao.template"));
        System.out.println(result);
        return result;
    }
    public static String createMybatisDBMapperXML(MyBatisDBDaoVO vo) throws IOException {
        String result = FreemarkerUtils.generateInputStream(vo, GeneraterUtil.class.getClassLoader().getResourceAsStream("generater\\dao\\mybatisDBXML.ftl"));
        String result = FreemarkerUtils.generateInputStream(vo, GeneraterUtil.class.getClassLoader().getResourceAsStream("generater/dao/mybatisDBXML.ftl"));
        System.out.println(result);
        return result;
    }
    public static String createQuery(QueryVO vo) throws IOException {
        String result = FreemarkerUtils.generateInputStream(vo, GeneraterUtil.class.getClassLoader().getResourceAsStream("generater\\service\\queryVO.ftl"));
        String result = FreemarkerUtils.generateInputStream(vo, GeneraterUtil.class.getClassLoader().getResourceAsStream("generater/service/queryVO.ftl"));
        System.out.println(result);
        return result;
    }
    public static String createService(ServiceInfoVO vo) throws IOException {
        String result = FreemarkerUtils.generateInputStream(vo, GeneraterUtil.class.getClassLoader().getResourceAsStream("generater\\service\\service.template"));
        String result = FreemarkerUtils.generateInputStream(vo, GeneraterUtil.class.getClassLoader().getResourceAsStream("generater/service/service.template"));
        System.out.println(result);
        return result;
    }
    public static String createServiceImpl(ServiceImplInfoVO vo) throws IOException {
        String result = FreemarkerUtils.generateInputStream(vo, GeneraterUtil.class.getClassLoader().getResourceAsStream("generater\\service\\serviceImpl.template"));
        String result = FreemarkerUtils.generateInputStream(vo, GeneraterUtil.class.getClassLoader().getResourceAsStream("generater/service/serviceImpl.template"));
        System.out.println(result);
        return result;
    }
    public static String createAdminController(AdminControllerInfoVO vo) throws IOException {
        String result = FreemarkerUtils.generateInputStream(vo, GeneraterUtil.class.getClassLoader().getResourceAsStream("generater\\admin\\adminController.template"));
        String result = FreemarkerUtils.generateInputStream(vo, GeneraterUtil.class.getClassLoader().getResourceAsStream("generater/admin/adminController.template"));
        System.out.println(result);
        return result;
    }
@@ -115,5 +115,10 @@
        return result;
    }
    public static void main(String[] args) {
        InputStream input = GeneraterUtil.class.getClassLoader().getResourceAsStream("generater/dao/mybatisDBDao.template");
        System.out.println(input);
    }
}
src/main/java/org/yeshi/utils/generater/annotation/admin/Show.java
@@ -37,7 +37,7 @@
    //显示类型
    enum ShowType {
        TEXT, IMG;
        TEXT, IMG,SWITCH;
    }
src/main/java/org/yeshi/utils/generater/entity/ClassInfo.java
@@ -13,8 +13,9 @@
    public ClassInfo(String name, String clazz) {
        this.name = name;
        this.clazz = clazz.replace("$",".");
        this.clazz = clazz.replace("$", ".");
    }
    public String getName() {
        return name;
@@ -29,6 +30,10 @@
    }
    public void setClazz(String clazz) {
        this.clazz = clazz.replace("$",".");
        this.clazz = clazz.replace("$", ".");
    }
    public static ClassInfo create(Class clazz) {
        return new ClassInfo(clazz.getSimpleName(), clazz.getName());
    }
}
src/main/java/org/yeshi/utils/generater/params/AdminGeneraterParams.java
@@ -10,24 +10,23 @@
    private String controllerPackage;
    private String htmlDir;
    public AdminGeneraterParams(String controllerPackage, String htmlDir) {
        this.controllerPackage = controllerPackage;
        this.htmlDir = htmlDir;
    }
    public String getControllerPackage() {
        return controllerPackage;
    }
    public void setControllerPackage(String controllerPackage) {
    public AdminGeneraterParams setControllerPackage(String controllerPackage) {
        this.controllerPackage = controllerPackage;
        return this;
    }
    public String getHtmlDir() {
        return htmlDir;
    }
    public void setHtmlDir(String htmlDir) {
    public AdminGeneraterParams setHtmlDir(String htmlDir) {
        this.htmlDir = htmlDir;
        return this;
    }
}
src/main/java/org/yeshi/utils/generater/params/DaoGeneraterParams.java
@@ -10,24 +10,27 @@
    private String daoPackage;
    private String mapperXMLDir;
    public DaoGeneraterParams(String daoPackage, String mapperXMLDir) {
        this.daoPackage = daoPackage;
        this.mapperXMLDir = mapperXMLDir;
    }
    public String getDaoPackage() {
        return daoPackage;
    }
    public void setDaoPackage(String daoPackage) {
    public DaoGeneraterParams setDaoPackage(String daoPackage) {
        this.daoPackage = daoPackage;
        return this;
    }
    public String getMapperXMLDir() {
        return mapperXMLDir;
    }
    public void setMapperXMLDir(String mapperXMLDir) {
    public DaoGeneraterParams setMapperXMLDir(String mapperXMLDir) {
        this.mapperXMLDir = mapperXMLDir;
        return this;
    }
}
src/main/java/org/yeshi/utils/generater/params/ServiceGeneraterParams.java
@@ -12,33 +12,32 @@
    private String serviceInterPackage;
    private String serviceImplPackage;
    public ServiceGeneraterParams(String queryPackage, String serviceInterPackage, String serviceImplPackage) {
        this.queryPackage = queryPackage;
        this.serviceInterPackage = serviceInterPackage;
        this.serviceImplPackage = serviceImplPackage;
    }
    public String getQueryPackage() {
        return queryPackage;
    }
    public void setQueryPackage(String queryPackage) {
    public ServiceGeneraterParams setQueryPackage(String queryPackage) {
        this.queryPackage = queryPackage;
        return this;
    }
    public String getServiceInterPackage() {
        return serviceInterPackage;
    }
    public void setServiceInterPackage(String serviceInterPackage) {
    public ServiceGeneraterParams setServiceInterPackage(String serviceInterPackage) {
        this.serviceInterPackage = serviceInterPackage;
        return this;
    }
    public String getServiceImplPackage() {
        return serviceImplPackage;
    }
    public void setServiceImplPackage(String serviceImplPackage) {
    public ServiceGeneraterParams setServiceImplPackage(String serviceImplPackage) {
        this.serviceImplPackage = serviceImplPackage;
        return this;
    }
}
src/main/java/org/yeshi/utils/generater/util/AnotationUtil.java
@@ -113,10 +113,11 @@
        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));
                    Map<String, Object> map = getParamsMap(an);
                    map.put("identifier", fd.getName());
                    list.add(map);
                }
            }
        }
src/main/java/org/yeshi/utils/generater/vo/admin/controller/AdminControllerInfoVO.java
@@ -25,6 +25,10 @@
    //名称
    private String controllerName;
    private boolean add;
    private boolean update;
    private boolean delete;
    public static class Builder {
        private AdminGeneraterInfo generaterInfo;
@@ -77,8 +81,12 @@
            vo.setPackageName(packageName);
            vo.setQueryVO(query);
            vo.setService(service);
            vo.setAdd(generaterInfo.getAddFormRows() != null && generaterInfo.getAddFormRows().size() > 0);
            vo.setUpdate(generaterInfo.getUpdateFormRows() != null && generaterInfo.getUpdateFormRows().size() > 0 && generaterInfo.getControllerData().edit());
            vo.setDelete(generaterInfo.getControllerData().delete());
            vo.setIdentifyIdType(EntityUtil.getIdentifyId(generaterInfo.getEntity()).getType().getSimpleName());
            vo.setControllerName(vo.getEntity().getName()+"AdminController");
            vo.setControllerName(vo.getEntity().getName() + "AdminController");
            return vo;
        }
@@ -152,4 +160,28 @@
    public void setControllerName(String controllerName) {
        this.controllerName = controllerName;
    }
    public boolean isAdd() {
        return add;
    }
    public void setAdd(boolean add) {
        this.add = add;
    }
    public boolean isUpdate() {
        return update;
    }
    public void setUpdate(boolean update) {
        this.update = update;
    }
    public boolean isDelete() {
        return delete;
    }
    public void setDelete(boolean delete) {
        this.delete = delete;
    }
}
src/main/java/org/yeshi/utils/generater/vo/admin/page/ListInfoVO.java
@@ -30,6 +30,10 @@
    private List<FormInputRegexVerifyVO> regexVerifyList;
    //列表接口
    private String listApi;
    //删除接口
    private String deleteApi;
    //添加页路径
    private String addPagePath;
    //更新页路径
@@ -48,11 +52,21 @@
        public ListInfoVO build() {
            ListInfoVO vo = new ListInfoVO();
            vo.setListApi(generaterInfo.getControllerData().mapping() + "/list");
            vo.setAddPagePath("add.html");
            vo.setUpdatePagePath("update.html");
            if (generaterInfo.getAddFormRows() != null && generaterInfo.getAddFormRows().size() > 0) {
                vo.setAddPagePath(generaterInfo.getEntity().getSimpleName().toLowerCase() + "_add.html");
            }
            if (generaterInfo.getUpdateFormRows() != null && generaterInfo.getUpdateFormRows().size() > 0) {
                vo.setUpdatePagePath(generaterInfo.getEntity().getSimpleName().toLowerCase() + "_update.html");
            }
            vo.setSearchFormRows(generaterInfo.getSearchFormRows());
            vo.setShowFileds(generaterInfo.getShowDataList());
            vo.setTitle("修改" + generaterInfo.getControllerData().title());
            vo.setTitle(generaterInfo.getControllerData().title());
            if (generaterInfo.getControllerData().delete()) {
                vo.setDeleteApi(generaterInfo.getControllerData().mapping() + "/delete");
            }
            //遍历需要正则表达式的Text或者TextArea
            List<FormInputRegexVerifyVO> verifyVOList = new ArrayList<>();
            for (FormRowData row : vo.getSearchFormRows()) {
@@ -190,4 +204,12 @@
    public void setShowFileds(List<Map<String, Object>> showFileds) {
        this.showFileds = showFileds;
    }
    public String getDeleteApi() {
        return deleteApi;
    }
    public void setDeleteApi(String deleteApi) {
        this.deleteApi = deleteApi;
    }
}
src/main/java/org/yeshi/utils/mail/EmailApiUtil.java
New file
@@ -0,0 +1,104 @@
package org.yeshi.utils.mail;
import net.sf.json.JSONObject;
import org.yeshi.utils.HttpUtil;
import org.yeshi.utils.StringUtil;
import org.yeshi.utils.encrypt.AESUtil;
import org.yeshi.utils.exception.MailSendException;
import java.util.*;
/**
 * @author hxh
 * @title: EmailApiUtil
 * @description: 邮件帮助
 * @date 2022/3/15 17:04
 */
public class EmailApiUtil {
    final static String AESKEY = "123bN5%M7*~a8888";
    final static String SIGNKEY = "EmailYeshi@88889!~";
    final static String API_SEND = "http://api.mail.yeshitv.com:8081/email/send";
    /**
     * @return void
     * @author hxh
     * @description 邮件发送接口
     * @date 18:13 2022/3/15
     * @param: emailInfo
     **/
    public static void sendEmail(EmailInfo emailInfo) throws MailSendException {
        JSONObject accountJSON = new JSONObject();
        accountJSON.put("toEmail", emailInfo.getToEmail());
        accountJSON.put("fromEmail", emailInfo.getFromEmail());
        accountJSON.put("fromEmailPwd", emailInfo.getFormEmailPwd());
        Map<String, String> params = getBaseParams();
        params.put("title", emailInfo.getTitle());
        params.put("content", emailInfo.getContent());
        params.put("app", emailInfo.getApp());
        params.put("accountInfo", AESUtil.encrypt(accountJSON.toString(), AESKEY));
        params.put("sign", getSign(params));
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
        try {
            String result = HttpUtil.post(API_SEND, params, headers);
            if (StringUtil.isNullOrEmpty(result)) {
                throw new Exception("内容返回为空");
            }
            JSONObject resultJSON = JSONObject.fromObject(result);
            if (resultJSON.optInt("code") != 0) {
                throw new MailSendException(MailSendException.CODE_BUSINESS_ERROR, resultJSON.optString("msg"));
            }
        } catch (MailSendException e) {
            throw e;
        } catch (Exception e) {
            throw new MailSendException(MailSendException.CODE_NETWORK_ERROR, "接口网络出错");
        }
    }
    private static Map<String, String> getBaseParams() {
        Map<String, String> params = new HashMap<>();
        params.put("timestamp", System.currentTimeMillis() + "");
        return params;
    }
    private static String getSign(Map<String, String> params) {
        List<String> list = new ArrayList<>();
        for (Iterator<String> its = params.keySet().iterator(); its.hasNext(); ) {
            String key = its.next();
            if ("sign".equalsIgnoreCase(key))
                continue;
            list.add(key + "=" + params.get(key));
        }
        Collections.sort(list);
        String str = StringUtil.concat(list, "&");
        str += SIGNKEY;
        String sign = StringUtil.Md5(str);
        return sign;
    }
//    public static void main(String[] args) {
//
//        //"he15901227708@163.com", "hexiaohui1011", "hexiaohui@banliapp.com", "测试", "测试内容"
//        EmailInfo emailInfo = new EmailInfo();
//        emailInfo.setApp("test");
//        emailInfo.setContent("测试内容");
//        emailInfo.setFormEmailPwd("hexiaohui1011");
//        emailInfo.setFromEmail("he15901227708@163.com");
//        emailInfo.setTitle("测试");
//        emailInfo.setToEmail("hexiaohui@banliapp.com");
//
//        try {
//            EmailApiUtil.sendEmail(emailInfo);
//        } catch (MailSendException e) {
//            e.printStackTrace();
//        }
//
//    }
}
src/main/java/org/yeshi/utils/mail/EmailInfo.java
New file
@@ -0,0 +1,65 @@
package org.yeshi.utils.mail;
/**
 * @author hxh
 * @title: EmailInfo
 * @description: 邮件信息
 * @date 2022/3/15 18:11
 */
public class EmailInfo {
    private String fromEmail;
    private String formEmailPwd;
    private String toEmail;
    private String title;
    private String content;
    private String app;
    public String getFromEmail() {
        return fromEmail;
    }
    public void setFromEmail(String fromEmail) {
        this.fromEmail = fromEmail;
    }
    public String getFormEmailPwd() {
        return formEmailPwd;
    }
    public void setFormEmailPwd(String formEmailPwd) {
        this.formEmailPwd = formEmailPwd;
    }
    public String getToEmail() {
        return toEmail;
    }
    public void setToEmail(String toEmail) {
        this.toEmail = toEmail;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public String getApp() {
        return app;
    }
    public void setApp(String app) {
        this.app = app;
    }
}
src/main/java/org/yeshi/utils/mongo/MongodbBaseDao.java
@@ -1,6 +1,9 @@
package org.yeshi.utils.mongo;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
@@ -82,6 +85,19 @@
        return (T) mongoTemplate.findById(id, this.getEntityClass());
    }
    /**
     * 聚合查询
     *
     * @param opts
     * @param output
     * @return
     */
    public AggregationResults aggregate(List<? extends AggregationOperation> opts, Class output) {
        Aggregation aggregation = Aggregation.newAggregation(opts);
        return mongoTemplate.aggregate(aggregation, this.getEntityClass(), output);
    }
    /**
     * 通过主键删除
     *
src/main/java/org/yeshi/utils/mq/TDMQUtil.java
New file
@@ -0,0 +1,503 @@
package org.yeshi.utils.mq;
import com.qcloud.cmq.Account;
import com.qcloud.cmq.Message;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.tdmq.v20200217.TdmqClient;
import com.tencentcloudapi.tdmq.v20200217.models.*;
import java.util.Arrays;
import java.util.List;
//腾讯CMQ消息
public class TDMQUtil {
    private static TDMQUtil cmqUtil;
    public static TDMQUtil getInstance() {
        if (cmqUtil == null) {
            cmqUtil = new TDMQUtil();
        }
        return cmqUtil;
    }
    private String secretId = "";
    private String secretKey = "";
    private String region = "ap-guangzhou";
    // 内网 http://gz.mqadapter.cmq.tencentyun.com
    // 公网 https://cmq-gz.public.tencenttdmq.com
    private static String endpoint = "http://gz.mqadapter.cmq.tencentyun.com";
    // private static String endpoint =
    // "http://cmq-queue-gz.api.tencentyun.com";
    private Account account;
    /**
     * @return void
     * @author hxh
     * @description 初始化
     * @date 17:00 2022/3/21
     * @param: secretId
     * @param: secretKey
     * @param: region 区域,如: ap-guangzhou
     * @param: apiRegion 接口区域,如: gz
     * @param: isPub 是否为公网
     **/
    public void init(String secretId, String secretKey, String region, String apiRegion, boolean isPub) {
        this.secretId = secretId;
        this.secretKey = secretKey;
        this.region = region;
        String ep;
        if (isPub) {
            ep = String.format("https://cmq-%s.public.tencenttdmq.com", apiRegion);
        } else {
            ep = String.format("http://%s.mqadapter.cmq.tencentyun.com", apiRegion);
        }
        endpoint = ep;
        account = new Account(endpoint, this.secretId, this.secretKey);
    }
    public void init(String secretId, String secretKey, boolean isPub) {
        this.secretId = secretId;
        this.secretKey = secretKey;
        String ep;
        if (isPub) {
            ep = String.format("https://cmq-%s.public.tencenttdmq.com", "gz");
        } else {
            ep = String.format("http://%s.mqadapter.cmq.tencentyun.com", "gz");
        }
        endpoint = ep;
        account = new Account(endpoint, this.secretId, this.secretKey);
    }
    private TdmqClient getClient() {
        return getClient(this.region);
    }
    private TdmqClient getClient(String region) {
        Credential cred = new Credential(secretId, secretKey);
        // 实例化一个 http 选项,可选的,没有特殊需求可以跳过
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint("tdmq.tencentcloudapi.com");
        // 实例化一个client选项,可选的,没有特殊需求可以跳过
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);
        // 实例化要请求产品的 client 对象,clientProfile 是可选的
        TdmqClient client = new TdmqClient(cred, region, clientProfile);
        return client;
    }
    private TdmqClient getMsgClient() {
        return getClient(this.region);
    }
    public boolean existQueue(String queueName) {
        if (getQueue(queueName) != null) {
            return true;
        }
        return false;
    }
    // 创建队列
    public boolean createQueue(String queueName) {
        return this.createQueue(queueName, 10L, 5 * 60L, 65536L);
    }
    // 创建队列
    public boolean createQueue(String queueName, int maxMsgSize) {
        return this.createQueue(queueName, 10L, 5 * 60L, maxMsgSize);
    }
    /**
     * 指定参数创建队列
     *
     * @param queueName
     * @param pollingWaitSeconds -长轮训等待时间
     * @param visibilityTimeout  -消息消费后再次可见的时间
     * @return
     */
    public boolean createQueue(String queueName, long pollingWaitSeconds, long visibilityTimeout, long maxMsgSize) {
        if (existQueue(queueName)) {
            return true;
        }
        CreateCmqQueueRequest request = new CreateCmqQueueRequest();
        request.setQueueName(queueName);
        request.setPollingWaitSeconds(pollingWaitSeconds);
        request.setVisibilityTimeout(visibilityTimeout);
        request.setMaxMsgSize(maxMsgSize);
        request.setMsgRetentionSeconds(345600L);
        try {
            getClient().CreateCmqQueue(request);
            return true;
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return false;
    }
    // 删除队列
    public boolean deleteQueue(String queueName) {
        DeleteCmqQueueRequest request = new DeleteCmqQueueRequest();
        request.setQueueName(queueName);
        try {
            getClient().DeleteCmqQueue(request);
            return true;
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return false;
    }
    // 获取队列列表
    public List<CmqQueue> getQueueNameList(String key) {
        DescribeCmqQueuesRequest request = new DescribeCmqQueuesRequest();
        request.setOffset(0L);
        request.setLimit(1000L);
        try {
            DescribeCmqQueuesResponse response = getClient().DescribeCmqQueues(request);
            CmqQueue[] queues = response.getQueueList();
            return Arrays.asList(queues);
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return null;
    }
    // 获取队列
    public CmqQueue getQueue(String queueName) {
        DescribeCmqQueueDetailRequest req = new DescribeCmqQueueDetailRequest();
        req.setQueueName(queueName);
        // 返回的 resp 是一个 CreateCmqQueueResponse 的实例,与请求对象对应
        try {
            DescribeCmqQueueDetailResponse resp = getClient().DescribeCmqQueueDetail(req);
            return resp.getQueueDescribe();
        } catch (TencentCloudSDKException e) {
        }
        return null;
    }
    // 发送消息
    public String sendMsg(String queueName, String msg, long delaySeconds) {
        SendCmqMsgRequest request = new SendCmqMsgRequest();
        request.setQueueName(queueName);
        request.setMsgContent(msg);
        request.setDelaySeconds(delaySeconds);
        try {
            SendCmqMsgResponse response = getMsgClient().SendCmqMsg(request);
            return response.getMsgId();
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return null;
    }
    public String sendMsg(String queueName, String msg) {
        return this.sendMsg(queueName, msg, 0L);
    }
    // 消费消息
    public Message recieveMsg(String queueName) throws Exception {
        com.qcloud.cmq.Queue queue = account.getQueue(queueName);
        return queue.receiveMessage();
    }
    /**
     * 消费消息
     *
     * @param count     1-16
     * @param queueName 队列名字
     * @return
     */
    public List<Message> recieveMsg(int count, String queueName) {
        com.qcloud.cmq.Queue queue = account.getQueue(queueName);
        if (queue == null) {
            return null;
        }
        List<Message> msgList = null;
        try {
            msgList = queue.batchReceiveMessage(count);
            return msgList;
        } catch (Exception e) {
            if (e.getMessage() != null && !e.getMessage().contains("no message"))
                e.printStackTrace();
        }
        return null;
    }
    // 删除消息
    public boolean deleteMsg(String queueName, String receiptHandle) {
        try {
            com.qcloud.cmq.Queue queue = account.getQueue(queueName);
            queue.deleteMessage(receiptHandle);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
    /**
     * 订阅消息相关
     */
    /**
     * 主题名称是否已经存在
     *
     * @param topicName
     * @return
     */
    private boolean topicNameExist(String topicName) {
        DescribeCmqTopicDetailRequest req = new DescribeCmqTopicDetailRequest();
        req.setTopicName(topicName);
        try {
            getClient().DescribeCmqTopicDetail(req);
            return true;
        } catch (TencentCloudSDKException e) {
            return false;
        }
    }
    /**
     * 创建订阅主题
     *
     * @param topicName-主题名称
     * @param maxMsgSize-消息最大长度
     * @param filterType-过滤类型
     * @return
     */
    public boolean createTopic(String topicName, Long maxMsgSize, Long filterType) {
        if (topicNameExist(topicName)) {
            return true;
        }
        CreateCmqTopicRequest req = new CreateCmqTopicRequest();
        if (filterType != null) {
            req.setFilterType(filterType);
        }
        if (maxMsgSize != null) {
            req.setMaxMsgSize(maxMsgSize);
        }
        req.setTopicName(topicName);
        try {
            getClient().CreateCmqTopic(req);
            return true;
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return false;
    }
    //刪除主題
    public boolean deleteTopic(String topicName) {
        DeleteCmqTopicRequest req = new DeleteCmqTopicRequest();
        req.setTopicName(topicName);
        try {
            getClient().DeleteCmqTopic(req);
            return true;
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return false;
    }
    /**
     * 创建默认参数的主题
     *
     * @param topicName
     * @return
     */
    public boolean createTopic(String topicName) {
        return createTopic(topicName, null, null);
    }
    /**
     * 是否已经订阅
     *
     * @param topicName
     * @param subscriptionName
     * @return
     */
    private boolean isAlreadySubscribe(String topicName, String subscriptionName) {
        DescribeCmqSubscriptionDetailRequest req = new DescribeCmqSubscriptionDetailRequest();
        req.setSubscriptionName(subscriptionName);
        req.setTopicName(topicName);
        req.setLimit(1L);
        req.setOffset(0L);
        try {
            DescribeCmqSubscriptionDetailResponse response = getClient().DescribeCmqSubscriptionDetail(req);
            if (response.getTotalCount() > 0)
                return true;
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return false;
    }
    /**
     * 订阅主题
     *
     * @param topicName-主题名称
     * @param subscriptionName-订阅名称
     * @param queueName-接受消息的队列名称
     * @return
     */
    public boolean subscribeTopic(String topicName, String subscriptionName, String queueName) {
        return subscribeTopic(topicName, subscriptionName, queueName, null);
    }
    public boolean subscribeTopic(String topicName, String subscriptionName, String queueName, List<String> filterTags) {
        try {
            if (isAlreadySubscribe(topicName, subscriptionName)) {
                return true;
            }
        } catch (Exception e) {
        }
        CreateCmqSubscribeRequest req = new CreateCmqSubscribeRequest();
        req.setTopicName(topicName);
        req.setEndpoint(queueName);
        req.setSubscriptionName(subscriptionName);
        req.setProtocol("queue");
        req.setNotifyContentFormat("SIMPLIFIED");
        if (filterTags != null && filterTags.size() > 0) {
            String[] tags = new String[filterTags.size()];
            filterTags.toArray(tags);
            req.setFilterTag(tags);
        }
        try {
            getClient().CreateCmqSubscribe(req);
            return true;
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 删除订阅
     *
     * @param topicName
     * @param subscriptionName
     * @return
     */
    public boolean deleteSubscribeTopic(String topicName, String subscriptionName) {
        DeleteCmqSubscribeRequest req = new DeleteCmqSubscribeRequest();
        req.setSubscriptionName(subscriptionName);
        req.setTopicName(topicName);
        try {
            getClient().DeleteCmqSubscribe(req);
            return true;
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return false;
    }
    /**
     * 发布订阅消息
     *
     * @param topicName
     * @param message
     * @return
     */
    public String publishTopicMessage(String topicName, String message) {
        return publishTopicMessage(topicName, null, message);
    }
    /**
     * 发布订阅消息
     *
     * @param topicName
     * @param tagList   -标签
     * @param message
     * @return
     */
    public String publishTopicMessage(String topicName, List<String> tagList, String message) {
        PublishCmqMsgRequest req = new PublishCmqMsgRequest();
        req.setMsgContent(message);
        req.setTopicName(topicName);
        if (tagList != null && tagList.size() > 0) {
            String[] tags = new String[tagList.size()];
            tagList.toArray(tags);
            req.setMsgTag(tags);
        }
        try {
            PublishCmqMsgResponse response = getMsgClient().PublishCmqMsg(req);
            return response.getMsgId();
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static void main(String[] args) {
        TDMQUtil.getInstance().init("AKIDTlpgJhLjOozvd6QI2XnpfGbgV4NQJk25", "xhCSUHo55oHUQ6XicFcmfIgspX0EEzWo", true);
        String queueName = "test1";
        String topicName = "topic_test";
        //创建
        TDMQUtil.getInstance().createQueue(queueName);
        //发送消息
        TDMQUtil.getInstance().sendMsg(queueName, "测试消息");
        //创建主题
        TDMQUtil.getInstance().createTopic(topicName);
        //创建订阅
        TDMQUtil.getInstance().subscribeTopic(topicName, topicName + queueName, queueName);
        //发送订阅消息
        TDMQUtil.getInstance().publishTopicMessage(topicName, "主题消息");
        //消费消息
        try {
            Message message = TDMQUtil.getInstance().recieveMsg(queueName);
            System.out.println("接受到的消息:" + message.msgBody);
            TDMQUtil.getInstance().deleteMsg(queueName, message.receiptHandle);
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            List<Message> messages = TDMQUtil.getInstance().recieveMsg(10, queueName);
            for (Message message : messages) {
                System.out.println("批量接受到的消息:" + message.msgBody);
                TDMQUtil.getInstance().deleteMsg(queueName, message.receiptHandle);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //删除订阅
        TDMQUtil.getInstance().deleteSubscribeTopic(topicName, topicName + queueName);
        //删除主题
        TDMQUtil.getInstance().deleteTopic(topicName);
        //删除队列
        TDMQUtil.getInstance().deleteQueue(queueName);
    }
}
src/main/java/org/yeshi/utils/sms/VerifyCodeFactory.java
New file
@@ -0,0 +1,92 @@
package org.yeshi.utils.sms;
/**
 * @author hxh
 * @title: VerifyCodeFactory
 * @description: 验证码工厂
 * @date 2021/11/15 18:47
 */
public class VerifyCodeFactory {
    final static String NUMBERS = "0123456789";
    final static String NUMBERS_UPPER_CASE = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    final static String UPPER_CASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    final static String NUMBERS_LOWER_CASE = "0123456789abcdefghijklmnopqrstuvwxyz";
    final static String LOWER_CASE = "abcdefghijklmnopqrstuvwxyz";
    /**
     * @return java.lang.String
     * @author hxh
     * @description 纯数字验证码
     * @date 18:56 2021/11/15
     * @param: length
     **/
    public static String createNumber(int length) {
        return createCode(length, NUMBERS);
    }
    /**
     * @return java.lang.String
     * @author hxh
     * @description 数字大写字母混合验证码
     * @date 18:56 2021/11/15
     * @param: length
     **/
    public static String createNumberAndUpperCase(int length) {
        return createCode(length, NUMBERS_UPPER_CASE);
    }
    /**
     * @return java.lang.String
     * @author hxh
     * @description 数字小写字母混合验证码
     * @date 18:56 2021/11/15
     * @param: length
     **/
    public static String createNumberAndLowerCase(int length) {
        return createCode(length, NUMBERS_LOWER_CASE);
    }
    /**
     * @return java.lang.String
     * @author hxh
     * @description 纯大写字母混合验证码
     * @date 18:56 2021/11/15
     * @param: length
     **/
    public static String createUpperCase(int length) {
        return createCode(length, UPPER_CASE);
    }
    /**
     * @return java.lang.String
     * @author hxh
     * @description 纯小写字母混合验证码
     * @date 18:56 2021/11/15
     * @param: length
     **/
    public static String createLowerCase(int length) {
        return createCode(length, LOWER_CASE);
    }
    private static String createCode(int length, String source) {
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < length; i++) {
            buffer.append(source.charAt((int) (Math.random() * source.length())));
        }
        return buffer.toString();
    }
}
src/main/java/org/yeshi/utils/statistic/BaseStatisticMySQLTimeQuery.java
New file
@@ -0,0 +1,50 @@
package org.yeshi.utils.statistic;
import java.io.Serializable;
import java.util.Date;
/**
 * @author hxh
 * @title: BaseStatisticQuery
 * @description: 基础统计查询条件
 * @date 2021/11/18 18:24
 */
public class BaseStatisticMySQLTimeQuery implements Serializable {
    private Date startTime;
    private Date endTime;
    private String timeFormat;
    public Date getStartTime() {
        return startTime;
    }
    public void setStartTime(Date startTime) {
        this.startTime = startTime;
    }
    public Date getEndTime() {
        return endTime;
    }
    public void setEndTime(Date endTime) {
        this.endTime = endTime;
    }
    public String getTimeFormat() {
        return timeFormat;
    }
    public void setTimeFormat(String timeFormat) {
        this.timeFormat = timeFormat;
    }
    public static BaseStatisticMySQLTimeQuery create(BaseStatisticTimeQuery query) {
        BaseStatisticMySQLTimeQuery timeQuery = new BaseStatisticMySQLTimeQuery();
        timeQuery.setEndTime(query.getEndTime());
        timeQuery.setStartTime(query.getStartTime());
        timeQuery.setTimeFormat(query.getTimeSpan().getSqlTimeFormat());
        return timeQuery;
    }
}
src/main/java/org/yeshi/utils/statistic/BaseStatisticTimeQuery.java
New file
@@ -0,0 +1,41 @@
package org.yeshi.utils.statistic;
import java.io.Serializable;
import java.util.Date;
/**
 * @author hxh
 * @title: BaseStatisticQuery
 * @description: 基础统计查询条件
 * @date 2021/11/18 18:24
 */
public class BaseStatisticTimeQuery implements Serializable {
    private Date startTime;
    private Date endTime;
    private StatisticTimeSpan timeSpan;
    public Date getStartTime() {
        return startTime;
    }
    public void setStartTime(Date startTime) {
        this.startTime = startTime;
    }
    public Date getEndTime() {
        return endTime;
    }
    public void setEndTime(Date endTime) {
        this.endTime = endTime;
    }
    public StatisticTimeSpan getTimeSpan() {
        return timeSpan;
    }
    public void setTimeSpan(StatisticTimeSpan timeSpan) {
        this.timeSpan = timeSpan;
    }
}
src/main/java/org/yeshi/utils/statistic/StatisticNumberResult.java
New file
@@ -0,0 +1,28 @@
package org.yeshi.utils.statistic;
/**
 * @author hxh
 * @title: StatisticNumberResult
 * @description: 统计数量结果
 * @date 2021/11/18 18:53
 */
public class StatisticNumberResult {
    private String time;
    private long number;
    public String getTime() {
        return time;
    }
    public void setTime(String time) {
        this.time = time;
    }
    public long getNumber() {
        return number;
    }
    public void setNumber(long number) {
        this.number = number;
    }
}
src/main/java/org/yeshi/utils/statistic/StatisticResulterFilterUtil.java
New file
@@ -0,0 +1,104 @@
package org.yeshi.utils.statistic;
import org.yeshi.utils.TimeUtil;
import java.math.BigDecimal;
import java.util.*;
/**
 * @author hxh
 * @title: StatisticResulterFilterUtil
 * @description: 统计结果过滤
 * @date 2021/11/18 19:11
 */
public class StatisticResulterFilterUtil {
    public static List<StatisticNumberResult> filterNumberResult(List<StatisticNumberResult> list, BaseStatisticTimeQuery timeQuery) {
        List<StatisticNumberResult> resultList = new ArrayList<>();
        createEmptyList(timeQuery, new IAddEmptyData() {
            @Override
            public void onData(String time) {
                StatisticNumberResult result = new StatisticNumberResult();
                result.setNumber(0L);
                result.setTime(time);
                resultList.add(result);
            }
        });
        Map<String, StatisticNumberResult> map = new HashMap<>();
        for (StatisticNumberResult result : list) {
            map.put(result.getTime(), result);
        }
        for (StatisticNumberResult result : resultList) {
            if (map.get(result.getTime()) != null) {
                result.setNumber(map.get(result.getTime()).getNumber());
            }
        }
        return resultList;
    }
    public static List<StatisticValueResult> filterValueResult(List<StatisticValueResult> list, BaseStatisticTimeQuery timeQuery) {
        List<StatisticValueResult> resultList = new ArrayList<>();
        createEmptyList(timeQuery, new IAddEmptyData() {
            @Override
            public void onData(String time) {
                StatisticValueResult result = new StatisticValueResult();
                result.setValue(new BigDecimal(0));
                result.setTime(time);
                resultList.add(result);
            }
        });
        Map<String, StatisticValueResult> map = new HashMap<>();
        for (StatisticValueResult result : list) {
            map.put(result.getTime(), result);
        }
        for (StatisticValueResult result : resultList) {
            if (map.get(result.getTime()) != null) {
                result.setValue(map.get(result.getTime()).getValue());
            }
        }
        return resultList;
    }
    private static void createEmptyList(BaseStatisticTimeQuery timeQuery, IAddEmptyData addEmptyData) {
        //开始时间与结束时间整形
        Date startTime = new Date(timeQuery.getStartTime().getTime());
        Date endTime = new Date(timeQuery.getEndTime().getTime());
        startTime = new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(startTime.getTime(), timeQuery.getTimeSpan().getLocalTimeFormat()), timeQuery.getTimeSpan().getLocalTimeFormat()));
        endTime = new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(endTime.getTime(), timeQuery.getTimeSpan().getLocalTimeFormat()), timeQuery.getTimeSpan().getLocalTimeFormat()));
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(startTime.getTime());
        while (calendar.getTimeInMillis() <= endTime.getTime()) {
            addEmptyData.onData(TimeUtil.getGernalTime(calendar.getTimeInMillis(), timeQuery.getTimeSpan().getLocalTimeFormat()));
            //增加时间
            if (timeQuery.getTimeSpan() == StatisticTimeSpan.minute) {
                calendar.add(Calendar.SECOND, 60);
            } else if (timeQuery.getTimeSpan() == StatisticTimeSpan.hour) {
                calendar.add(Calendar.HOUR, 1);
            } else if (timeQuery.getTimeSpan() == StatisticTimeSpan.day) {
                calendar.add(Calendar.HOUR, 24);
            } else if (timeQuery.getTimeSpan() == StatisticTimeSpan.month) {
                calendar.add(Calendar.MONTH, 1);
            } else if (timeQuery.getTimeSpan() == StatisticTimeSpan.year) {
                calendar.add(Calendar.YEAR, 1);
            }
            //判断是否存在
        }
    }
    interface IAddEmptyData {
        public void onData(String time);
    }
}
src/main/java/org/yeshi/utils/statistic/StatisticTimeSpan.java
New file
@@ -0,0 +1,26 @@
package org.yeshi.utils.statistic;
/**
 * @author hxh
 * @title: StatisticSpan
 * @description: 统计的时间粒度
 * @date 2021/11/18 18:21
 */
public enum StatisticTimeSpan {
    minute("%Y-%m-%d %H %i", "yyyy-MM-dd HH mm"), hour("%Y-%m-%d %H", "yyyy-MM-dd HH"), day("%Y-%m-%d", "yyyy-MM-dd"), month("%Y-%m", "yyyy-MM"), year("%Y", "yyyy");
    private String sqlTimeFormat;
    private String localTimeFormat;
    private StatisticTimeSpan(String sqlTimeFormat, String localTimeFormat) {
        this.sqlTimeFormat = sqlTimeFormat;
        this.localTimeFormat = localTimeFormat;
    }
    public String getSqlTimeFormat() {
        return sqlTimeFormat;
    }
    public String getLocalTimeFormat() {
        return localTimeFormat;
    }
}
src/main/java/org/yeshi/utils/statistic/StatisticValueResult.java
New file
@@ -0,0 +1,30 @@
package org.yeshi.utils.statistic;
import java.math.BigDecimal;
/**
 * @author hxh
 * @title: StatisticNumberResult
 * @description: 统计数值结果
 * @date 2021/11/18 18:53
 */
public class StatisticValueResult {
    private String time;
    private BigDecimal value;
    public String getTime() {
        return time;
    }
    public void setTime(String time) {
        this.time = time;
    }
    public BigDecimal getValue() {
        return value;
    }
    public void setValue(BigDecimal value) {
        this.value = value;
    }
}
src/main/resources/generater/admin/add.ftl
@@ -177,7 +177,7 @@
                    }
                    uploadTool.upload(function(){
                        //发异步,把数据提交给php
                        ksapp.postJSON('${addApi}', data.field, function (res) {
                        ksapp.post('${addApi}', data.field, function (res) {
                            if (res.code == 0) {
                                layer.alert("增加成功", {
                                            icon: 6
src/main/resources/generater/admin/adminController.template
@@ -56,6 +56,7 @@
        return loadPrint(callback,JsonUtil.loadTrueResult(data));
    }
    <#if delete>
    @ResponseBody
    @RequestMapping("delete")
    public String delete(String ids, String callback) {
@@ -64,7 +65,9 @@
        ${serviceObjName}.delete(idList);
        return loadPrint(callback, JsonUtil.loadTrueResult(""));
    }
     </#if>
    <#if add>
    @ResponseBody
    @RequestMapping("add")
    public String add(${entity.name} bean, HttpSession session, String callback) {
@@ -75,6 +78,7 @@
            return loadPrint(callback, JsonUtil.loadFalseResult(e.getMessage()));
        }
    }
    </#if>
    @ResponseBody
    @RequestMapping("get")
@@ -88,6 +92,7 @@
    }
    <#if update>
    @ResponseBody
    @RequestMapping("update")
    public String update(${entity.name} bean, HttpSession session,String callback) {
@@ -101,6 +106,7 @@
        }
        return loadPrint(callback,JsonUtil.loadTrueResult(""));
    }
    </#if>
}
src/main/resources/generater/admin/form/text.ftl
@@ -1,2 +1,3 @@
                        <input type="text" name="${value.key}" <#if value.params.verifyValue??> lay-verify="${value.params.verifyValue}" </#if> placeholder="${value.params.placeHolder}" autocomplete="off"
                        <#assign inputType="${value.params.inputType?lower_case}" >
                        <input type="${inputType}" name="${value.key}" <#if value.params.verifyValue??> lay-verify="${value.params.verifyValue}" </#if> placeholder="${value.params.placeHolder}" autocomplete="off"
                               class="layui-input">
src/main/resources/generater/admin/list.ftl
@@ -12,9 +12,9 @@
    <link rel="stylesheet" href="./css/xadmin.css">
    <script src="./lib/layui/layui.js" charset="utf-8"></script>
    <link rel="stylesheet" href="./css/theme3049.min.css">
    <script src="js/vue.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="./js/vue.min.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript" src="./js/xadmin.js"></script>
    <script src="js/http.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>
    <!--[if lt IE 9]>
    <script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
@@ -57,7 +57,7 @@
                        </div>
                        </#list>
                        <div class="layui-inline layui-show-xs-block">
                            <button id="search" class="layui-btn" lay-submit="" lay-filter="sreach">
                            <button id="search" class="layui-btn" lay-submit="" lay-filter="search">
                                <i class="layui-icon">&#xe615;</i></button>
                        </div>
                    </form>
@@ -73,26 +73,32 @@
</body>
<script type="text/html" id="toolbar">
    <div class="layui-btn-container">
          <#if addPagePath??>
        <button class="layui-btn" onclick="xadmin.open('添加${title}','${addPagePath}',500,580)"><i
                class="layui-icon"></i>添加
        </button>
          </#if>
        <#if deleteApi??>
        <button class="layui-btn layui-btn-danger" lay-event="delete">
            <i class="layui-icon">&#xe640;</i>
            删除
        </button>
        </#if>
    </div>
</script>
<script type="text/html" id="deleteContainer">
<script type="text/html" id="optContainer">
    <div class="layui-btn-container">
        <!-- <a title='恢复' onclick='member_resume(this,{{d.LAY_INDEX }}, {{d.id}})' href='javascript:;'> -->
        <!--<i class="layui-icon">&#xe669;</i>-->
        <!--</a>-->
        <#if updatePagePath??>
        <a title="修改" onclick="xadmin.open('修改${title}','${updatePagePath}?id={{d.id}}',500,580)" href="javascript:;">
            <i class="layui-icon">&#xe642;</i>
        </a>
        </#if>
        <#if deleteApi??>
        <a title="删除" onclick="member_del(this,{{d.LAY_INDEX }},'{{d.id}}')" href="javascript:;">
            <i class="layui-icon">&#xe640;</i>
        </a>
        </#if>
    </div>
</script>
@@ -116,50 +122,30 @@
           10003 ? 'checked': ''}} >
</script>
<script type="text/html" id="imgshow">
    <!-- 这里的checked的状态只是演示 -->
    <img  src="{{d.}}"/>
    <input type="checkbox" name="sex" value="{{d.id}}" lay-skin="switch" lay-text="女|男" lay-filter="sexDemo" {{ d.id==
           10003 ? 'checked': ''}} >
</script>
<script>
     <#if deleteApi??>
    function member_del(obj, index, id) {
        layer.confirm('确认要删除吗?', function (index) {
            //发异步删除数据
            app.delete(obj, index, id);
        });
    }
    </#if>
</script>
<script>
    var tableIns = null;
    $(function () {
        //渲染表格
        function rederTable() {
            tableIns = table.render({
                elem: '#table_list',
                url: url,
                toolbar: "#toolbar",
                totalRow: true,
                cols: [{type: 'checkbox', title: "ID"},
                    {field: 'id', width: 120, sort: true, title: "ID"},
                    {fixed: 'right', width: 80, title: "操作", toolbar: '#deleteContainer'}],
                page: true,
                parseData:
                        function (res) { //res 即为原始返回的数据
                            if (res.code != 0)
                                return;
                            if (res.data.list == null)
                                return;
                            console.log(res.data.list)
                            return {
                                "code": res.code, //解析接口状态
                                "msg": res.msg, //解析提示文本
                                "count": res.data.count, //解析数据长度
                                "data": res.data.list //解析数据列表
                            };
                        }
            });
        }
        var app = new Vue({
            el: "#app",
@@ -196,12 +182,32 @@
                        tableIns = table.render({
                            elem: '#table_list',
                            url: ${listApi},
                            url: "${listApi}",
                            toolbar: "#toolbar",
                            totalRow: true,
                            cols: [{type: 'checkbox', title: "ID"},
                                {field: 'id', width: 120, sort: true, title: "ID"},
                                {fixed: 'right', width: 80, title: "操作", toolbar: '#deleteContainer'}],
                            cols: [[{type: 'checkbox', title: "ID"},
                                 <#list showFileds as field >
                                    <#if field.showType=='TEXT'>
                                    {field: '${field.identifier}', width: 120, sort: false, title: "${field.title}"},
                                    <#elseif field.showType=='SWITCH'>
                                    {field: '${field.identifier}', width: 120, sort: false, title: "${field.title}",templet:function(res){
                                         if(res.${field.identifier}){
                                             return " <input type=\"checkbox\" checked='true'  disabled  lay-skin=\"switch\"";
                                         }else{
                                             return " <input type=\"checkbox\"  disabled  lay-skin=\"switch\"";
                                         }
                                        }
                                    },
                                    <#elseif field.showType=='IMG'>
                                    {field: '${field.identifier}', width: 120, sort: false, title: "${field.title}",templet:function(res){
                                                return "<img src='"+res.${field.identifier}+"' style='height:50px;'>";
                                        }
                                    },
                                    <#else>
                                    {field: '${field.identifier}', template:"<img src='{{d.${field.identifier}}}'>", width: 120, sort: false, title: "${field.title}"},
                                    </#if>
                                </#list>
                                {fixed: 'right', width: 80, title: "操作", toolbar: '#optContainer'}]],
                            page: true,
                            parseData: function (res) { //res 即为原始返回的数据
                                if (res.code != 0)
@@ -215,12 +221,15 @@
                                    "count": res.data.count, //解析数据长度
                                    "data": res.data.list //解析数据列表
                                };
                            },
                            error: function (e, msg) {
                                ksapp.tableError(e)
                            }
                            //,…… //其他参数
                        });
                        //头工具栏事件
                        tableIns.on('toolbar(app)',
                        table.on('toolbar(app)',
                                function (obj) {
                                    var checkStatus = table.checkStatus(obj.config.id);
                                    switch (obj.event) {
@@ -242,8 +251,7 @@
                                            });
                                            break;
                                    }
                                    ;
                                    };
                                });
                        //请求搜索表单中需要的数据
                         <#if preRequestList??&&(preRequestList?size>0)>
@@ -317,12 +325,9 @@
                    });
                },
            }
        }
    })
    ;
    }
    )
    ;
    });
    app.init();
    });
</script>
src/main/resources/generater/admin/update.ftl
@@ -24,7 +24,7 @@
<body>
<div class="layui-fluid">
    <div class="layui-row">
        <form class="layui-form" lay-filter="add">
        <form class="layui-form" lay-filter="update">
            <#list rowsList as value>
                <div class="layui-form-item">
@@ -55,7 +55,7 @@
            <div class="layui-form-item">
                <label for="L_remarks" class="layui-form-label"></label>
                <button class="layui-btn" lay-filter="add" lay-submit="">确定修改</button>
                <button class="layui-btn" lay-filter="update" lay-submit="">确定修改</button>
            </div>
        </form>
    </div>
@@ -150,9 +150,9 @@
            return;
        }
        ksapp.postJSON('${detailApi}', {id: id}, function (res) {
        ksapp.post('${detailApi}', {id: id}, function (res) {
            if (res.code == 0) {
                form.data(res.data);
                form.val("update",res.data);
            } else {
                layer.msg(res.msg);
            }
@@ -185,7 +185,7 @@
        //监听提交
        form.on('submit(add)',
        form.on('submit(update)',
                function (data) {
                    console.log(data.field);
                    //转换json对象
@@ -206,9 +206,9 @@
                        var params = data.field;
                        params.id = ksapp.getQueryParam("id");
                        ksapp.postJSON('${updateApi}', data.field, function (res) {
                        ksapp.post('${updateApi}', data.field, function (res) {
                            if (res.code == 0) {
                                layer.alert("增加成功", {
                                layer.alert("修改成功", {
                                            icon: 6
                                        },
                                        function () {
@@ -237,7 +237,7 @@
             params["${key}"]=${request.params["${key}"]}
                 </#list>
         ksapp.postJSON('${request.url}', params, function (res) {
         ksapp.post('${request.url}', params, function (res) {
             if (res.code == 0) {
                 //填充数据
                 $("${request.fillTarget}").empty();
src/main/resources/generater/dao/mongoDBDao.template
@@ -33,7 +33,7 @@
  public List<${entity.name}> list(DaoQuery daoQuery){
        Query query = getQuery(daoQuery);
        if (daoQuery.sortList!=null && daoQuery.sortList.size()>0){
            query.with(new Sort(daoQuery.sortList));
            query.with(Sort.by(daoQuery.sortList));
        }
        query.skip(daoQuery.start);
        query.limit(daoQuery.count);
src/main/resources/generater/dao/mybatisDBXML.ftl
@@ -12,7 +12,7 @@
    <sql id="Base_Column_List">
        <trim suffixOverrides=",">
        <#list columnList as column>${column.column},</#list>
        ${identify.column},<#list columnList as column>${column.column},</#list>
        </trim>
    </sql>
src/main/resources/generater/service/method/impl/mybatis/delete.ftl
@@ -1,4 +1,4 @@
<#assign daoObjName="${dao.name?uncap_first}" >
     for (String id : idList){
     for (Long id : idList){
        ${daoObjName}.deleteByPrimaryKey(id);
     }
src/main/resources/generater/service/serviceImpl.template
@@ -14,6 +14,7 @@
  private ${dao.name} ${dao.name?uncap_first};
  <#list metodInfoList as method>
  @Override
  ${method.visiteAccess} ${method.returnType} ${method.name}(${method.params}) <#if method.exceptions??> throws ${method.exceptions}</#if> {
${method.content}
  }
src/test/java/com/generater/GeneratorTest.java
@@ -149,15 +149,15 @@
    }
    private static void generater() throws Exception {
        GeneraterManager.getInstance().init("D:\\workspace\\server\\utils\\src\\test\\java", TestEntity.class);
        AdminGeneraterParams adminGeneraterParams=new AdminGeneraterParams("com.generater.temp.controller","D:\\workspace\\server\\utils\\src\\test");
        GeneraterManager.getInstance().createWholeFunction(new DaoGeneraterParams("com.generater.temp.dao", "D:\\workspace\\server\\utils\\src\\test"), new ServiceGeneraterParams("com.generater.temp.query","com.generater.temp.service","com.generater.temp.service.impl"), adminGeneraterParams);
//        GeneraterManager.getInstance().init("D:\\workspace\\server\\utils\\src\\test\\java", TestEntity.class);
//        AdminGeneraterParams adminGeneraterParams=new AdminGeneraterParams("com.generater.temp.controller","D:\\workspace\\server\\utils\\src\\test");
//
//        GeneraterManager.getInstance().createWholeFunction(new DaoGeneraterParams("com.generater.temp.dao", "D:\\workspace\\server\\utils\\src\\test"), new ServiceGeneraterParams("com.generater.temp.query","com.generater.temp.service","com.generater.temp.service.impl"), adminGeneraterParams);
    }
    @Table("tb_test")
    public static class Entity {
     static class Entity {
        @Id
        @Column(name = "id")