From d98ac7a5d4732613e173350a1ef0876bd55b893b Mon Sep 17 00:00:00 2001 From: AllenDu <15162678717@163.com> Date: Tue, 2 Jun 2020 11:24:46 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E6=90=AD=E5=BB=BA?= =?UTF-8?q?=E5=90=8E=E5=8F=B0=E6=9E=B6=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/cheri/keller/KellerApplication.java | 30 ++ .../com/cheri/keller/common/KellerRunner.java | 33 ++ .../keller/common/config/CommonConfig.java | 23 + .../keller/common/config/PublicConstant.java | 108 +++++ .../keller/common/config/RequestConfig.java | 22 + .../keller/common/mybatis/BaseEntity.java | 86 ++++ .../keller/common/mybatis/BaseException.java | 14 + .../keller/common/mybatis/BaseMapper.java | 161 +++++++ .../keller/common/mybatis/SqlFieldReader.java | 401 ++++++++++++++++++ .../keller/common/mybatis/TypeCaster.java | 113 +++++ .../mybatis/annotation/FieldAttribute.java | 51 +++ .../mybatis/annotation/IndexAttribute.java | 22 + .../mybatis/annotation/KeyAttribute.java | 26 ++ .../mybatis/annotation/SortAttribute.java | 40 ++ .../mybatis/annotation/TableAttribute.java | 33 ++ .../mybatis/provider/BaseCreateProvider.java | 25 ++ .../mybatis/provider/BaseDeleteProvider.java | 73 ++++ .../mybatis/provider/BaseInsertProvider.java | 104 +++++ .../mybatis/provider/BaseSelectProvider.java | 170 ++++++++ .../mybatis/provider/BaseUpdateProvider.java | 70 +++ .../keller/common/proxy/ApiController.java | 111 +++++ .../keller/common/proxy/FormController.java | 120 ++++++ .../keller/common/response/Response.java | 80 ++++ .../keller/common/response/ResultData.java | 89 ++++ .../com/cheri/keller/common/util/Console.java | 57 +++ .../cheri/keller/common/util/RequestUtil.java | 142 +++++++ .../keller/common/util/ResponseUtils.java | 52 +++ .../keller/common/util/SendEmailUtils.java | 144 +++++++ .../cheri/keller/common/util/StringUtils.java | 177 ++++++++ .../keller/controller/BaseController.java | 62 +++ .../keller/controller/JsonResourceUtils.java | 36 ++ .../com/cheri/keller/controller/PageUtil.java | 50 +++ .../controller/TestTableController.java | 32 ++ .../keller/controller/UserController.java | 39 ++ .../com/cheri/keller/entity/EmailLog.java | 194 +++++++++ .../com/cheri/keller/entity/TestTable.java | 56 +++ .../com/cheri/keller/entity/UserInfo.java | 145 +++++++ .../com/cheri/keller/mapper/EmailMapper.java | 14 + .../cheri/keller/mapper/TestTableMapper.java | 21 + .../com/cheri/keller/mapper/UserMapper.java | 36 ++ .../cheri/keller/service/EmailService.java | 57 +++ .../com/cheri/keller/service/UserService.java | 131 ++++++ 42 files changed, 3450 insertions(+) create mode 100644 src/main/java/com/cheri/keller/KellerApplication.java create mode 100644 src/main/java/com/cheri/keller/common/KellerRunner.java create mode 100644 src/main/java/com/cheri/keller/common/config/CommonConfig.java create mode 100644 src/main/java/com/cheri/keller/common/config/PublicConstant.java create mode 100644 src/main/java/com/cheri/keller/common/config/RequestConfig.java create mode 100644 src/main/java/com/cheri/keller/common/mybatis/BaseEntity.java create mode 100644 src/main/java/com/cheri/keller/common/mybatis/BaseException.java create mode 100644 src/main/java/com/cheri/keller/common/mybatis/BaseMapper.java create mode 100644 src/main/java/com/cheri/keller/common/mybatis/SqlFieldReader.java create mode 100644 src/main/java/com/cheri/keller/common/mybatis/TypeCaster.java create mode 100644 src/main/java/com/cheri/keller/common/mybatis/annotation/FieldAttribute.java create mode 100644 src/main/java/com/cheri/keller/common/mybatis/annotation/IndexAttribute.java create mode 100644 src/main/java/com/cheri/keller/common/mybatis/annotation/KeyAttribute.java create mode 100644 src/main/java/com/cheri/keller/common/mybatis/annotation/SortAttribute.java create mode 100644 src/main/java/com/cheri/keller/common/mybatis/annotation/TableAttribute.java create mode 100644 src/main/java/com/cheri/keller/common/mybatis/provider/BaseCreateProvider.java create mode 100644 src/main/java/com/cheri/keller/common/mybatis/provider/BaseDeleteProvider.java create mode 100644 src/main/java/com/cheri/keller/common/mybatis/provider/BaseInsertProvider.java create mode 100644 src/main/java/com/cheri/keller/common/mybatis/provider/BaseSelectProvider.java create mode 100644 src/main/java/com/cheri/keller/common/mybatis/provider/BaseUpdateProvider.java create mode 100644 src/main/java/com/cheri/keller/common/proxy/ApiController.java create mode 100644 src/main/java/com/cheri/keller/common/proxy/FormController.java create mode 100644 src/main/java/com/cheri/keller/common/response/Response.java create mode 100644 src/main/java/com/cheri/keller/common/response/ResultData.java create mode 100644 src/main/java/com/cheri/keller/common/util/Console.java create mode 100644 src/main/java/com/cheri/keller/common/util/RequestUtil.java create mode 100644 src/main/java/com/cheri/keller/common/util/ResponseUtils.java create mode 100644 src/main/java/com/cheri/keller/common/util/SendEmailUtils.java create mode 100644 src/main/java/com/cheri/keller/common/util/StringUtils.java create mode 100644 src/main/java/com/cheri/keller/controller/BaseController.java create mode 100644 src/main/java/com/cheri/keller/controller/JsonResourceUtils.java create mode 100644 src/main/java/com/cheri/keller/controller/PageUtil.java create mode 100644 src/main/java/com/cheri/keller/controller/TestTableController.java create mode 100644 src/main/java/com/cheri/keller/controller/UserController.java create mode 100644 src/main/java/com/cheri/keller/entity/EmailLog.java create mode 100644 src/main/java/com/cheri/keller/entity/TestTable.java create mode 100644 src/main/java/com/cheri/keller/entity/UserInfo.java create mode 100644 src/main/java/com/cheri/keller/mapper/EmailMapper.java create mode 100644 src/main/java/com/cheri/keller/mapper/TestTableMapper.java create mode 100644 src/main/java/com/cheri/keller/mapper/UserMapper.java create mode 100644 src/main/java/com/cheri/keller/service/EmailService.java create mode 100644 src/main/java/com/cheri/keller/service/UserService.java diff --git a/src/main/java/com/cheri/keller/KellerApplication.java b/src/main/java/com/cheri/keller/KellerApplication.java new file mode 100644 index 0000000..12ca523 --- /dev/null +++ b/src/main/java/com/cheri/keller/KellerApplication.java @@ -0,0 +1,30 @@ +package com.cheri.keller; + +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +@MapperScan("com.cheri.keller.mapper") +@SpringBootApplication +public class KellerApplication { + + @Bean + /** + * 引入RestTemplate Bean + * 用来进行服务间的Http通信 + * 同时重新定义其解析时用到的字符集,防止中文乱码 + */ + RestTemplate restTemplate(){ + RestTemplate restTemplate = new RestTemplate(); + restTemplate.getMessageConverters().clear(); + restTemplate.getMessageConverters().add(new FastJsonHttpMessageConverter()); + return restTemplate; + } + public static void main(String[] args) { + SpringApplication.run(KellerApplication.class, args); + } + +} diff --git a/src/main/java/com/cheri/keller/common/KellerRunner.java b/src/main/java/com/cheri/keller/common/KellerRunner.java new file mode 100644 index 0000000..361f2cd --- /dev/null +++ b/src/main/java/com/cheri/keller/common/KellerRunner.java @@ -0,0 +1,33 @@ +package com.cheri.keller.common; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 12:35 + **/ + +import com.cheri.keller.common.config.CommonConfig; +import com.cheri.keller.common.util.RequestUtil; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 继承Application接口后项目启动时会按照执行顺序执行run方法 + * 通过设置Order的value来指定执行的顺序 + */ +@Component +@Order(value = 1) +public class KellerRunner implements ApplicationRunner { + @Resource + private CommonConfig config; + + @Override + public void run(ApplicationArguments args) throws Exception { + RequestUtil.port = config.port; + RequestUtil.address = config.address; + } +} diff --git a/src/main/java/com/cheri/keller/common/config/CommonConfig.java b/src/main/java/com/cheri/keller/common/config/CommonConfig.java new file mode 100644 index 0000000..ec322c7 --- /dev/null +++ b/src/main/java/com/cheri/keller/common/config/CommonConfig.java @@ -0,0 +1,23 @@ +package com.cheri.keller.common.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +/** + * 项目配置文件,从application.properties中加载 + * + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 11:08 + **/ +@Configuration +@PropertySource("classpath:application.properties") +public class CommonConfig { + @Value("${server.port:8080}") + public String port; + + @Value("${server.address:http://127.0.0.1}") + public String address; + +} diff --git a/src/main/java/com/cheri/keller/common/config/PublicConstant.java b/src/main/java/com/cheri/keller/common/config/PublicConstant.java new file mode 100644 index 0000000..a9075ba --- /dev/null +++ b/src/main/java/com/cheri/keller/common/config/PublicConstant.java @@ -0,0 +1,108 @@ +package com.cheri.keller.common.config; + +/** + * 公用常量,项目中要到的一些常量 + * + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 22:05 + **/ +public class PublicConstant { + + public static final int DEFAULT_USER_TYPE = 0; + + /** + * 业务成功标示 + */ + public static final int SUCCESS = 0; + /** + * 业务失败标示 + */ + public static final int FAILED = 1; + + /** + * 注册类型 + */ + public static final int REGISTER_TYPE = 0; + + /** + * 登录类型 + */ + public static final int LOGIN_TYPE = 1; + + /** + * 重置密码类型 + */ + public static final int RESET_PASSWORD_TYPE = 2; + + /** + * 邮件验证码有效期 + */ + public static final int EMAIL_CODE_TIME = 5; + + /** + * 邮件验证码长度 + */ + public static final int EMAIL_CODE_LENGTH = 6; + + + /** + * 应用启动的端口号 + */ + public static String port ; + + /** + * 应用运行的 IP 地址 + */ + public static String address ; + + + /** + * 应用名 + */ + public static String appName = "Keller笔记"; + + /** + * 服务器访问地址 + */ + public static String serviceUrl = "http://" + address + ":" + port; + + /** + * 邮件服务器地址 + */ + public static String mailServerHost; + + + /** + * 邮件服务器登录用户名 + */ + public static String mailServerUser = "1227826445@qq.com"; + + + /** + * 邮件服务器登录密码 + */ + public static String mailServerPassword = "iwrwaaoythiuieei"; + + /** + * 通用,不做访问权限设置 + */ + public static final int AUTHORITY_COMMON = 1 << 0; + + /** + * 用户登录后可以访问 + */ + public static final int AUTHORITY_LOGON = 1 << 1; + + /** + * 管理员可以访问 + */ + public static final int AUTHORITY_ADMIN = 1 << 2; + + /** + * 超级管理员可以访问 + */ + public static final int AUTHORITY_SUPPER_ADMIN = 1 << 3; + + +} diff --git a/src/main/java/com/cheri/keller/common/config/RequestConfig.java b/src/main/java/com/cheri/keller/common/config/RequestConfig.java new file mode 100644 index 0000000..75b659f --- /dev/null +++ b/src/main/java/com/cheri/keller/common/config/RequestConfig.java @@ -0,0 +1,22 @@ +package com.cheri.keller.common.config; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 11:09 + **/ +public class RequestConfig { + public static final String URL = "URL"; + public static final String URI = "URI"; + public static final String REMOTE_ADDR = "REMOTE_ADDR"; + public static final String REMOTE_HOST = "REMOTE_HOST"; + public static final String REMOTE_PORT = "REMOTE_PORT"; + public static final String REMOTE_USER = "REMOTE_USER"; + + public static final String REQUEST_METHOD = "REQUEST_METHOD"; + + public static final String METHOD = "method"; + public static final String TOKEN = "token"; + + +} diff --git a/src/main/java/com/cheri/keller/common/mybatis/BaseEntity.java b/src/main/java/com/cheri/keller/common/mybatis/BaseEntity.java new file mode 100644 index 0000000..cfb4a3a --- /dev/null +++ b/src/main/java/com/cheri/keller/common/mybatis/BaseEntity.java @@ -0,0 +1,86 @@ +package com.cheri.keller.common.mybatis; + +/** + * * BaseEntity,使用复杂查询(带条件的增删改查和分页查询)时需要继承的父类 + * * 该类提供了可供选择的多条件查询方式、排序方式、分页查询相关参数等 + * * 数据实体类继承该类即可使用 + * + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 11:15 + **/ +public class BaseEntity { + /** + * 是否查询明细字段 + */ + private boolean baseKyleDetailed = true; + /** + * 多个查询条件是否用And连接 + */ + private Boolean baseKyleUseAnd = true; + /** + * 是否按排序关键字升序排列 + */ + private Boolean baseKyleUseASC = true; + /** + * 页面大小 + */ + private int baseKylePageSize = 10; + /** + * 要查询的页码 + */ + private int baseKyleCurrentPage = 1; + /** + * 根据页面大小和要查询的页码计算出的起始行号 + */ + private int baseKyleStartRows ; + public Boolean getBaseKyleUseAnd() { + return baseKyleUseAnd; + } + + public void setBaseKyleUseAnd(Boolean baseKyleUseAnd) { + this.baseKyleUseAnd = baseKyleUseAnd; + } + + public Boolean getBaseKyleUseASC() { + return baseKyleUseASC; + } + + public void setBaseKyleUseASC(Boolean baseKyleUseASC) { + this.baseKyleUseASC = baseKyleUseASC; + } + + public void setBaseKylePageSize(int baseKylePageSize) { + this.baseKylePageSize = baseKylePageSize; + this.baseKyleStartRows = this.baseKylePageSize * (this.baseKyleCurrentPage - 1); + } + + public int getBaseKylePageSize() { + return baseKylePageSize; + } + + public int getBaseKyleStartRows() { + return baseKyleStartRows; + } + + public void setBaseKyleStartRows(int baseKyleStartRows) { + this.baseKyleStartRows = baseKyleStartRows; + } + + public int getBaseKyleCurrentPage() { + return baseKyleCurrentPage; + } + + public void setBaseKyleCurrentPage(int baseKyleCurrentPage) { + this.baseKyleStartRows = this.baseKylePageSize * (this.baseKyleCurrentPage - 1); + this.baseKyleCurrentPage = baseKyleCurrentPage; + } + + public boolean isBaseKyleDetailed() { + return baseKyleDetailed; + } + + public void setBaseKyleDetailed(boolean baseKyleDetailed) { + this.baseKyleDetailed = baseKyleDetailed; + } +} \ No newline at end of file diff --git a/src/main/java/com/cheri/keller/common/mybatis/BaseException.java b/src/main/java/com/cheri/keller/common/mybatis/BaseException.java new file mode 100644 index 0000000..9e9c822 --- /dev/null +++ b/src/main/java/com/cheri/keller/common/mybatis/BaseException.java @@ -0,0 +1,14 @@ +package com.cheri.keller.common.mybatis; + +/** + * 自定义异常,用来处理BaseMapper使用过程中抛出的异常 + * + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 11:16 + **/ +public class BaseException extends RuntimeException{ + public BaseException(String message){ + super(message); + } +} diff --git a/src/main/java/com/cheri/keller/common/mybatis/BaseMapper.java b/src/main/java/com/cheri/keller/common/mybatis/BaseMapper.java new file mode 100644 index 0000000..4f81706 --- /dev/null +++ b/src/main/java/com/cheri/keller/common/mybatis/BaseMapper.java @@ -0,0 +1,161 @@ +package com.cheri.keller.common.mybatis; + +import com.cheri.keller.common.mybatis.provider.*; +import org.apache.ibatis.annotations.*; +import org.springframework.dao.DuplicateKeyException; + +import java.util.List; + +/** + * * BaseMapper提供了通用的Mapper + * * 实现了insert、insertAndReturnKey、deleteById、SelectById、updateById等基本的增删改查方法 + * * 数据实体的Mapper继承该接口即可 + * * + * * BaseMapper还提供了带条件的删除和查询操作,以及带条件的分页查询,需要实体类继承BaseEntity方可使用 + * + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 11:17 + **/ +public interface BaseMapper { + /** + * 创建表 + * @param entity + */ + @UpdateProvider(type = BaseCreateProvider.class , method = "create") + void baseCreate(T entity); + + /** + * 插入操作 + * 将实体类的所有字段和字段的值分别列出来,适用于主键不是自增的表 + * @param entity + * @return INSERT INTO tableName (id,name...) VALUES (#{id},#{name}...) + * @throws DuplicateKeyException 当唯一字段重复插入时,会抛该异常 + */ + @InsertProvider(type = BaseInsertProvider.class,method = "insert") + Integer baseInsert(T entity) throws DuplicateKeyException; + + /** + * 插入数据并返回自增的主键(建议使用id) + * 将实体类中除主键以外的字段和值分别列出来,适用于主键是自增的表 + * @param entity + * @return INSERT INTO tableName (name...) VALUES(#{name}...) + * @throws DuplicateKeyException 当唯一字段重复插入时,会抛该异常 + */ + @InsertProvider(type = BaseInsertProvider.class,method = "insertAndReturnKey") + @Options(useGeneratedKeys=true,keyProperty = "id", keyColumn = "id") + Integer baseInsertAndReturnKey(T entity) throws DuplicateKeyException; + + + /** + * 根据Id删除数据,要求必须有id字段 + * @param entity + * @return + */ + @DeleteProvider(type = BaseDeleteProvider.class,method = "deleteById") + Integer baseDeleteById(T entity); + + /** + * 根据条件删除 + * 传入的对象中带@IndexAttribute注解的字段有值的都作为查询条件 + * 多个查询条件用And连接 + * @param entity 实体对象 + * @return DELETE FROM router WHERE name = #{name} AND serviceName = #{serviceName} + */ + @SelectProvider(type= BaseDeleteProvider.class,method = "deleteByCondition") + Integer baseDeleteByCondition(T entity); + + /** + * 根据id 更新数据,空值不更新 ,要求必须有id字段 + * @param entity + * @return + */ + @UpdateProvider(type = BaseUpdateProvider.class,method = "updateById") + Integer baseUpdateById(T entity); + + /** + * 根据主键更新数据,空值不更新,要求数据至少有一个主键,且主键有值 + * @param entity + * @return + */ + @UpdateProvider(type = BaseUpdateProvider.class,method = "updateByKey") + Integer baseUpdateByKey(T entity); + + /** + * 根据Id 查找数据,要求必须有id 字段 + * @param entity + * @return + */ + @SelectProvider(type= BaseSelectProvider.class,method = "selectById") + T baseSelectById(T entity); + + /** + * 根据主键查询数据,要求至少有一个主键,且主键必须有值 + * @param entity + * @return + */ + @SelectProvider(type= BaseSelectProvider.class,method = "selectByKey") + T baseSelectByKey(T entity); + + + + /** + * 查询全部数据 + * @param entity + * @return + */ + @SelectProvider(type= BaseSelectProvider.class,method = "selectAll") + List baseSelectAll(T entity); + + /** + * 带条件的查询,该查询为动态查询,不可缓存 + * 传入的对象中带@IndexAttribute注解的字段有值的都作为查询条件 + * 传入对象中带@SortAttribute注解的字段作为排序字段 + * @param entity 实体对象 + * param and 多个查询条件组合方式 true:AND false:OR + * param asc 排序方式 null:不指定排序方式 true:按指定排序字段升序 false:按指定排序字段降序 + * @return SELECT id,name... FROM router WHERE name = #{name} AND serviceName = #{serviceName} ORDER BY createTime ASC + */ + @SelectProvider(type= BaseSelectProvider.class,method = "selectByCondition") + List baseSelectByCondition(T entity); + + + /** + * 查询记录总数 + * 返回的是 "SELECT COUNT(1) FROM 表名" 的结果 + * 不带查询条件 + * @param entity + * @return + */ + @SelectProvider(type = BaseSelectProvider.class,method = "selectCount") + Integer baseSelectCount(T entity); + + /** + * 根据条件查询记录总数 + * 传入的对象中带@IndexAttribute注解的字段有值的都作为查询条件 + * @param entity + * @return SELECT COUNT(1) FROM router WHERE name = #{name} AND serviceName = #{serviceName} + */ + @SelectProvider(type = BaseSelectProvider.class,method = "selectCountByCondition") + Integer baseSelectCountByCondition(T entity); + + + /** + * 分页查询 + * 返回 “SELECT 所有字段 FROM 表名 LIMIT startRows,pageSize” 的结果 + * 不带查询条件 + * @param entity + * @return + */ + @SelectProvider(type = BaseSelectProvider.class,method = "selectPageList") + List baseSelectPageList(T entity); + + /** + * 加条件的分页查询 + * 传入的对象中带@IndexAttribute注解的字段有值的都作为查询条件 + * @return SELECT id,name... FROM router WHERE name = #{name} AND serviceName = #{serviceName} ORDER BY createTime ASC LIMIT #{startRows},#{pageSize} + */ + @SelectProvider(type = BaseSelectProvider.class,method = "selectPageListByCondition") + List baseSelectPageListByCondition(T entity); + +} diff --git a/src/main/java/com/cheri/keller/common/mybatis/SqlFieldReader.java b/src/main/java/com/cheri/keller/common/mybatis/SqlFieldReader.java new file mode 100644 index 0000000..bd5e2bf --- /dev/null +++ b/src/main/java/com/cheri/keller/common/mybatis/SqlFieldReader.java @@ -0,0 +1,401 @@ +package com.cheri.keller.common.mybatis; + +import com.cheri.keller.common.mybatis.annotation.*; +import com.cheri.keller.common.util.Console; +import com.cheri.keller.common.util.StringUtils; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +/** + * * Provider工具类 + * * 提供获取读取表名、字段名等公用方法 + * + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 11:17 + **/ +public class SqlFieldReader { + + public static ConcurrentHashMap tableNameMap = new ConcurrentHashMap<>(16); + + /** + * 读取表名,要求类上有@TableAttribute注解 + * @param entity 实体对象 + * @return tableName + */ + public static String getTableName(T entity) { + Class cls = entity.getClass(); + String tableName = tableNameMap.get(cls.getName()); + if(StringUtils.isNotEmpty(tableName)){ + return tableName; + } + TableAttribute table = entity.getClass().getAnnotation(TableAttribute.class); + if(table == null){ + throw new BaseException("需要解析表名,但未找到@TableAttribute注解"); + } + tableNameMap.put(cls.getName(),table.name()); + return table.name(); + } + + /** + * 将所有字段名以逗号拼接起来返回 + * 从属性前的@FieldAttribute注解解析要查询的字段名 + * 当所有属性都没有@FieldAttribute注解时,解析所有属性名作为字段名 + * @param entity 实体对象 + * @return id,name + */ + public static String getFieldStr(T entity){ + Class cls = entity.getClass(); + Field[] fields = cls.getDeclaredFields(); + //带@FieldAttribute注解的属性名 + StringBuilder builder = new StringBuilder(); + //所有属性名 + StringBuilder allFields = new StringBuilder(); + for(Field field:fields){ + allFields.append(field.getName()).append(","); + if(field.getAnnotation(FieldAttribute.class) != null){ + FieldAttribute fieldAttribute = field.getAnnotation(FieldAttribute.class); + //如果查询明细字段,返回明细字段 + if(entity.isBaseKyleDetailed()){ + builder.append(field.getName()).append(","); + //如果不查询明细字段,不返回明细字段 + }else { + if(!fieldAttribute.detailed()){ + builder.append(field.getName()).append(","); + } + } + + } + } + if(builder.length() > 0){ + return builder.substring(0,builder.length() - 1); + }else if(allFields.length() > 0){ + return allFields.substring(0,allFields.length() - 1); + }else { + return null; + } + } + + /** + * 根据索引字段生成查询条件 + * 传入的对象中带@IndexAttribute注解的字段有值的都作为查询条件 + * @param entity 实体对象 + * @param 实体类型 + * @return WHERE name = #{name} OR controllerName = #{controllerName} + */ + public static String getConditionSuffix(T entity){ + String condition; + if(entity.getBaseKyleUseAnd() == null){ + return ""; + } + if(entity.getBaseKyleUseAnd()){ + condition = "AND"; + }else { + condition = "OR"; + } + Class cls = entity.getClass(); + Field[] fields = cls.getDeclaredFields(); + StringBuilder builder = new StringBuilder(); + builder.append(" WHERE "); + try { + for(Field field:fields){ + if(field.getAnnotation(IndexAttribute.class) != null){ + if(SqlFieldReader.hasValue(entity,field.getName())){ + builder.append(field.getName()) + .append(" = #{").append(field.getName()).append("} ") + .append(condition).append(" "); + } + + } + } + int index = builder.lastIndexOf(condition); + if(index < 0){ + return ""; + } + return builder.substring(0,index); + + }catch (Exception e){ + e.printStackTrace(); + } + //注意,不要return null + return ""; + } + + /** + * 获取主键的查询条件 + * 传入的对象必须满足以下条件: + * 1. 必须有且只有一个带有@keyAttribute注解的字段,如果有多个,只取第一个 + * 2. 带有@KeyAttribute注解的字段必须有值 + * 这是为了避免产生因为没有设置@KeyAttribute注解而造成全部数据修改或删除的问题 + * @param entity + * @param + * @return WHERE userId = #{userId} + */ + public static String getConditionByKeySuffix(T entity) throws BaseException { + Class cls = entity.getClass(); + Field[] fields = cls.getDeclaredFields(); + StringBuilder builder = new StringBuilder(); + builder.append(" WHERE "); + try { + for(Field field:fields){ + if(field.getAnnotation(KeyAttribute.class) != null){ + if(hasValue(entity,field.getName())){ + builder.append(field.getName()) + .append(" = #{").append(field.getName()).append("} "); + }else { + throw new BaseException("@KeyAttribute修饰的字段不能为空"); + } + break; + } + } + int index = builder.lastIndexOf("="); + if(index < 0){ + throw new BaseException("没有找到@KeyAttribute修饰的字段"); + } + return builder.toString(); + }catch (Exception e){ + e.printStackTrace(); + throw new BaseException(e.getMessage()); + } + } + + /** + * + * @param entity + * @param + * @return + */ + public static String getSortSuffix(T entity){ + String condition; + if(entity.getBaseKyleUseASC() == null){ + return ""; + } + if(entity.getBaseKyleUseASC()){ + condition = "ASC"; + }else { + condition = "DESC"; + } + Class cls = entity.getClass(); + Field[] fields = cls.getDeclaredFields(); + StringBuilder builder = new StringBuilder(); + builder.append(" ORDER BY "); + try { + for(Field field:fields){ + if(field.getAnnotation(SortAttribute.class) != null){ + builder.append(field.getName()).append(" ") + .append(condition).append(","); + + } + } + int index = builder.lastIndexOf(","); + if(index < 0){ + return ""; + } + return builder.substring(0,index); + + }catch (Exception e){ + e.printStackTrace(); + } + return ""; + } + + /** + * 获取所有字段列表 + * 读取类中带@FieldAttribute注解的字段,如果都没有带该注解,则返回类中所有字段 + * @return {id,name} + */ + public static List getFields(T entity){ + Field[] fields = entity.getClass().getDeclaredFields(); + List fieldList = new ArrayList<>(); + List allList = new ArrayList<>(); + //带@FieldAttribute注解的属性名 + for(Field field:fields){ + allList.add(field.getName()); + if(field.getAnnotation(FieldAttribute.class) != null){ + fieldList.add(field.getName()); + } + } + if(fieldList.size() == 0){ + return allList; + } + return fieldList; + } + + /** + * 读取@TableAttribute注解,解析表名和描述 + * 读取@FieldAttribute注解,解析字段名和描述 + * 读取@KeyAttribute注解,解析主键 + * 读取@IndexAttribute注解,解析索引 + * + * 创建的数据表,含表名、数据表描述、字段名、字段描述、主键、自增主键、索引 + * @param entity + * @return + */ + public static String getCreateTableSql(T entity){ + TableAttribute table = entity.getClass().getAnnotation(TableAttribute.class); + if(table == null){ + throw new BaseException("要解析表名,未发现@TableAttribute注解"); + } + String tableName = table.name(); + String tableComment = table.comment(); + + StringBuilder builder = new StringBuilder(); + + /* + * 拼写基础建表语句 + */ + builder.append("create table ") + .append(tableName) + .append("( \n"); + + + // 添加字段 + builder.append(getAddFieldSql(entity)); + builder.append(") "); + + // 如果有表说明,添加表说明 + if(StringUtils.isNotEmpty(tableComment)){ + builder.append("comment '") + .append(tableComment) + .append("'; \n"); + }else { + builder.append("; \n"); + } + + //添加主键 + builder.append(getCreateKeySql(entity)); + + //添加索引 + builder.append(getCreateIndexSql(entity)); + + Console.print("",builder.toString()); + return builder.toString(); + } + + + public static String getAddFieldSql(T entity){ + Field[] fields = entity.getClass().getDeclaredFields(); + StringBuilder builder = new StringBuilder(); + + /* + 解析字段描述:是否唯一、是否必填、是否设置了最大长度等 + */ + for(Field field:fields){ + FieldAttribute fieldAttribute = field.getAnnotation(FieldAttribute.class); + if(fieldAttribute != null){ + + builder.append(field.getName()) + .append(" ") + .append(TypeCaster.getType(field.getType().getSimpleName(),fieldAttribute.length())); + if(fieldAttribute.notNull()){ + builder.append(" not null "); + } + + if(fieldAttribute.unique()){ + builder.append(" unique "); + } + + //如果有字段说明,添加字段说明 + if(StringUtils.isNotEmpty(fieldAttribute.value())) { + builder.append(" comment '") + .append(fieldAttribute.value()) + .append("'"); + } + builder.append(", \n"); + } + } + builder.deleteCharAt(builder.lastIndexOf(",")); + return builder.toString(); + } + + private static String getCreateKeySql(T entity){ + Field[] fields = entity.getClass().getDeclaredFields(); + StringBuilder builder = new StringBuilder(); + for(Field field:fields){ + KeyAttribute keyAttribute = field.getAnnotation(KeyAttribute.class); + if(keyAttribute != null){ + FieldAttribute fieldAttribute = field.getAnnotation(FieldAttribute.class); + if(fieldAttribute == null){ + return ""; + } + builder .append("alter table ") + .append(getTableName(entity)) + .append(" change ") + .append(field.getName()) + .append(" ") + .append(field.getName()) + .append(" ") + .append(TypeCaster.getType(field.getType().getSimpleName(),fieldAttribute.length())); + if(keyAttribute.autoIncr()){ + builder.append(" auto_increment "); + } + builder.append(" primary key comment '") + .append(fieldAttribute.value()) + .append("'; \n"); + + break; + } + } + return builder.toString(); + } + + + /** + * 获取索引字段列表 + * @return + */ + public static String getCreateIndexSql(T entity){ + + String tableName = getTableName(entity); + StringBuilder builder = new StringBuilder(); + + Field[] fields = entity.getClass().getDeclaredFields(); + for(Field field:fields){ + if(field.getAnnotation(IndexAttribute.class) != null){ + + builder.append("alter table ") + .append(tableName) + .append(" add index ") + .append(tableName) + .append("_index_") + .append(field.getName()) + .append(" (") + .append(field.getName()) + .append("); \n"); + } + } + return builder.toString(); + } + + + /** + * 判断一个对象的指定字段有没有值 + * @param entity 实体对象 + * @param fieldName 对象的字段名 + * @param 实体类型 + * @return 值存在且不为null:返回true; 否则:返回false + */ + public static boolean hasValue(T entity, String fieldName){ + try { + Class cls = entity.getClass(); + Method method = cls.getMethod("get" + StringUtils.captureName(fieldName)); + if(method.invoke(entity) == null){ + return false; + }else { + return true; + } + }catch (IllegalAccessException e){ + e.printStackTrace(); + }catch (NoSuchMethodException e){ + e.printStackTrace(); + }catch (InvocationTargetException e){ + e.printStackTrace(); + } + return false; + } +} diff --git a/src/main/java/com/cheri/keller/common/mybatis/TypeCaster.java b/src/main/java/com/cheri/keller/common/mybatis/TypeCaster.java new file mode 100644 index 0000000..c78657f --- /dev/null +++ b/src/main/java/com/cheri/keller/common/mybatis/TypeCaster.java @@ -0,0 +1,113 @@ +package com.cheri.keller.common.mybatis; + +import com.cheri.keller.common.util.Console; +import org.springframework.util.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * Java类型和mysql类型间的转换,仅创建数据表时使用 + * + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 11:17 + **/ +public class TypeCaster { + /** + * varchar/varbinary类型,允许最大长度为65535,在这里限制:如果超过3000,转换为text/blob + */ + private static final int MAX = 3000; + + /** + * TINYTEXT 256 bytes + * TEXT 65,535 bytes ~64kb + * MEDIUMTEXT 16,777,215 bytes ~16Mb + * LONGTEXT 4,294,967,295 bytes ~4Gb + */ + private static final int TEXT_MAX = 65535; + + /** + * decimal类型的最大长度为65,根据平时使用的需要,设置为20,足够大多数场景使用了 + */ + private static final int DECIMAL_MAX = 20; + private static Map map = new HashMap<>(16); + + private static final String STRING = "string"; + private static final String INT = "int"; + private static final String INTEGER = "integer"; + private static final String LONG = "long"; + private static final String DATE = "date"; + private static final String BYTE_ARRAY = "byte[]"; + private static final String FLOAT = "float"; + private static final String DOUBLE = "double"; + static { + map.put(STRING,"varchar(50)"); + map.put(INT,"int"); + map.put(INTEGER,"int"); + map.put(LONG,"bigint"); + map.put(DATE,"datetime"); + map.put(BYTE_ARRAY,"varbinary(50)"); + map.put(FLOAT,"decimal(10,2)"); + map.put(DOUBLE,"decimal(10,2)"); + } + /** + * 根据Java数据类型和设置的长度,转换为MySQL的数据类型 + * @param key + * @param length + * @return + */ + public static String getType(String key,int length){ + if(StringUtils.isEmpty(key)){ + return null; + } + + if(length <= 0){ + return map.get(key.toLowerCase()); + } + + /* + float/Float/double/Double类型判断设置的长度是否符合规则,如果超长,将长度设置为允许的最大长度 + */ + if(FLOAT.equalsIgnoreCase(key) + || DOUBLE.equalsIgnoreCase(key)){ + length = length > DECIMAL_MAX ? DECIMAL_MAX:length; + return "decimal(" + length + ",2)"; + } + + //String 根据长度,转换为 varchar 或 text + if(STRING.equalsIgnoreCase(key)){ + if(length < MAX){ + return "varchar(" + length + ")"; + } + if(length < TEXT_MAX){ + return "text"; + } + + return "mediumtext"; + + + } + + //byte[] 根据长度,转换为 varbinary 或 blob + if(BYTE_ARRAY.equalsIgnoreCase(key)){ + if(length < MAX){ + return "varbinary(" + length + ")"; + } + return "blob"; + } + + return map.get(key.toLowerCase()); + } + + public static void main(String[] args){ + Console.println("String",getType("String",10000)); + Console.println("Integer",getType("Integer",100)); + Console.println("float",getType("float",100)); + Console.println("Float",getType("Float",10)); + Console.println("long",getType("long",10)); + Console.println("Long",getType("Long",10)); + Console.println("Date",getType("Date",10)); + Console.println("double",getType("double",10)); + } +} diff --git a/src/main/java/com/cheri/keller/common/mybatis/annotation/FieldAttribute.java b/src/main/java/com/cheri/keller/common/mybatis/annotation/FieldAttribute.java new file mode 100644 index 0000000..46b514a --- /dev/null +++ b/src/main/java/com/cheri/keller/common/mybatis/annotation/FieldAttribute.java @@ -0,0 +1,51 @@ +package com.cheri.keller.common.mybatis.annotation; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 11:34 + **/ + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 字段名注解,用于要查询的字段名之前 + * 在select * from tableName时,代替*的位置 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface FieldAttribute { + /** + * 字段说明 + * @return + */ + String value() default ""; + + /** + * 是否必填字段,默认不是必填 + * @return + */ + boolean notNull() default false; + + /** + * 字段长度 ,仅可变长类型设置 + * String 、byte[] 类型分别对应 mysql 中 varchar、varbinary类型,需要设置长度,默认50 + * @return + */ + int length() default 0; + + /** + * 是否唯一,默认不唯一 + * @return + */ + boolean unique() default false; + + /** + * 是否是明细字段,如果是明细字段,在查询列表时不显示该字段 + * @return + */ + boolean detailed() default false; +} diff --git a/src/main/java/com/cheri/keller/common/mybatis/annotation/IndexAttribute.java b/src/main/java/com/cheri/keller/common/mybatis/annotation/IndexAttribute.java new file mode 100644 index 0000000..3c92be3 --- /dev/null +++ b/src/main/java/com/cheri/keller/common/mybatis/annotation/IndexAttribute.java @@ -0,0 +1,22 @@ +package com.cheri.keller.common.mybatis.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * * 索引字段注解,可以根据索引字段进行查找、删除操作 + * * 注意:索引字段尽量使用包装类,如:Integer,避免使用 int long等基本类型 + * * 因为条件查询会将有值的索引字段作为查询条件, + * * 此时,如果字段类型为int,初始值为0,0 将作为查询条件。 + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 11:42 + **/ + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface IndexAttribute { + +} diff --git a/src/main/java/com/cheri/keller/common/mybatis/annotation/KeyAttribute.java b/src/main/java/com/cheri/keller/common/mybatis/annotation/KeyAttribute.java new file mode 100644 index 0000000..5ac3800 --- /dev/null +++ b/src/main/java/com/cheri/keller/common/mybatis/annotation/KeyAttribute.java @@ -0,0 +1,26 @@ +package com.cheri.keller.common.mybatis.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * * 数据库主键的注解 + * * 1. 仅支持单字段作为主键使用,将该字段上添加该注解即可 + * * 2. 当使用id字段作为主键时,不需要添加该注解 + * * 3. BaseMapper里后缀为ById的方法均是依照id字段作为主键设计的 + * + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 11:47 + **/ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface KeyAttribute { + /** + * 是否是自增主键 + * @return + */ + boolean autoIncr() default false; +} \ No newline at end of file diff --git a/src/main/java/com/cheri/keller/common/mybatis/annotation/SortAttribute.java b/src/main/java/com/cheri/keller/common/mybatis/annotation/SortAttribute.java new file mode 100644 index 0000000..386f648 --- /dev/null +++ b/src/main/java/com/cheri/keller/common/mybatis/annotation/SortAttribute.java @@ -0,0 +1,40 @@ +package com.cheri.keller.common.mybatis.annotation; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 11:48 + **/ + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 排序字段的注解 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface SortAttribute { + /** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 21:05 + **/ + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.RUNTIME) + @interface TableAttribute { + /** + * 表名 + * @return + */ + String name() ; + + /** + * 描述 + * @return + */ + String comment() default ""; + } +} diff --git a/src/main/java/com/cheri/keller/common/mybatis/annotation/TableAttribute.java b/src/main/java/com/cheri/keller/common/mybatis/annotation/TableAttribute.java new file mode 100644 index 0000000..1cbde65 --- /dev/null +++ b/src/main/java/com/cheri/keller/common/mybatis/annotation/TableAttribute.java @@ -0,0 +1,33 @@ +package com.cheri.keller.common.mybatis.annotation; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 11:54 + **/ + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 表注解,用在entity的类声明之前 + * value赋值为表名 + * @author Cheri + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface TableAttribute { + /** + * 表名 + * @return + */ + String name() ; + + /** + * 描述 + * @return + */ + String comment() default ""; +} \ No newline at end of file diff --git a/src/main/java/com/cheri/keller/common/mybatis/provider/BaseCreateProvider.java b/src/main/java/com/cheri/keller/common/mybatis/provider/BaseCreateProvider.java new file mode 100644 index 0000000..469c7e3 --- /dev/null +++ b/src/main/java/com/cheri/keller/common/mybatis/provider/BaseCreateProvider.java @@ -0,0 +1,25 @@ +package com.cheri.keller.common.mybatis.provider; + +import com.cheri.keller.common.mybatis.BaseEntity; +import com.cheri.keller.common.mybatis.SqlFieldReader; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 11:56 + **/ +public class BaseCreateProvider { + + /** + * + * 创建表的同时要创建索引,会执行多条语句,在application.properties中要设置 allowMultiQueries=true + * spring.datasource.url = jdbc:mysql://localhost:3306/my_core + * ?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true + * @param entity + * @param + * @return + */ + public static String create(T entity){ + return SqlFieldReader.getCreateTableSql(entity); + } +} \ No newline at end of file diff --git a/src/main/java/com/cheri/keller/common/mybatis/provider/BaseDeleteProvider.java b/src/main/java/com/cheri/keller/common/mybatis/provider/BaseDeleteProvider.java new file mode 100644 index 0000000..81d9d50 --- /dev/null +++ b/src/main/java/com/cheri/keller/common/mybatis/provider/BaseDeleteProvider.java @@ -0,0 +1,73 @@ +package com.cheri.keller.common.mybatis.provider; + +import com.cheri.keller.common.mybatis.BaseEntity; +import com.cheri.keller.common.mybatis.SqlFieldReader; +import com.cheri.keller.common.util.Console; +import org.springframework.util.StringUtils; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 11:56 + **/ +public class BaseDeleteProvider { + + public static Map deleteByIdMap = new ConcurrentHashMap<>(16); + + /** + * 根据Id 删除数据,要求必须有id字段 + * + * @param entity + * @param + * @return DELETE FROM router WHERE id = #{id} + */ + public static String deleteById(T entity) { + Class cls = entity.getClass(); + String className = cls.getName(); + String sql = deleteByIdMap.get(className); + if (StringUtils.isEmpty(sql)) { + sql = getDeletePrefix(entity) + " WHERE id = #{id} "; + deleteByIdMap.put(className, sql); + } + Console.info("deleteById", sql, entity); + return sql; + } + + public static String deleteByKey(T entity) { + try { + String sql = getDeletePrefix(entity) + SqlFieldReader.getConditionByKeySuffix(entity); + Console.info("deleteByKey", sql, entity); + return sql; + } catch (Exception e) { + return null; + } + } + + /** + * 根据条件删除,该查询为动态查询,不可缓存 + * 传入的对象中带@IndexAttribute注解的字段有值的都作为查询条件 + * 多个查询条件用And连接 + * + * @param entity 实体对象 + * param and 多个查询条件组合方式 null:不指定查询条件 true:多个查询条件用AND连接 false:多个查询条件用OR连接 + * @param 对象类型 + * @return DELETE FROM router WHERE name = #{name} AND serviceName = #{serviceName} + */ + public static String deleteByCondition(T entity) { + String sql = getDeletePrefix(entity) + SqlFieldReader.getConditionSuffix(entity); + Console.info("deleteByCondition", sql, entity); + return sql; + } + + private static String getDeletePrefix(T entity) { + return "DELETE FROM " + SqlFieldReader.getTableName(entity) + " "; + } + + public static void main(String[] args) { + + } + +} diff --git a/src/main/java/com/cheri/keller/common/mybatis/provider/BaseInsertProvider.java b/src/main/java/com/cheri/keller/common/mybatis/provider/BaseInsertProvider.java new file mode 100644 index 0000000..a2771ce --- /dev/null +++ b/src/main/java/com/cheri/keller/common/mybatis/provider/BaseInsertProvider.java @@ -0,0 +1,104 @@ +package com.cheri.keller.common.mybatis.provider; + +import com.cheri.keller.common.mybatis.BaseEntity; +import com.cheri.keller.common.mybatis.SqlFieldReader; +import com.cheri.keller.common.util.Console; +import org.springframework.util.StringUtils; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 11:57 + **/ +public class BaseInsertProvider { + /** + * 缓存insert语句 + */ + public static Map insertMap = new ConcurrentHashMap<>(16); + + public static Map insertAndReturnKeyMap = new ConcurrentHashMap<>(16); + + /** + * 基础的添加语句 + * 读取对象的所有字段属性,生成insert语句 + * + * @param entity + * @param + * @return + */ + public static String insert(T entity) { + Class cls = entity.getClass(); + String className = cls.getName(); + String sql = insertMap.get(className); + if (StringUtils.isEmpty(sql)) { + String fieldStr = SqlFieldReader.getFieldStr(entity); + + StringBuilder builder = new StringBuilder(); + builder.append("INSERT INTO ") + .append(SqlFieldReader.getTableName(entity)).append(" ") + .append("(").append(fieldStr).append(") ") + .append("VALUES("); + + StringBuilder valuesStr = new StringBuilder(); + String[] arrays = fieldStr.split(","); + for (String str : arrays) { + valuesStr.append("#{").append(str).append("}").append(","); + } + builder.append(valuesStr.substring(0, valuesStr.length() - 1)) + .append(") "); + sql = builder.toString(); + insertMap.put(className, sql); + } + Console.info("insert", sql, entity); + return sql; + } + + public static String insertAndReturnKey(T entity) { + Class cls = entity.getClass(); + String className = cls.getName(); + String sql = insertAndReturnKeyMap.get(className); + if (StringUtils.isEmpty(sql)) { + String fieldStr = SqlFieldReader.getFieldStr(entity); + String[] arrays = fieldStr.split(","); + + StringBuilder builder = new StringBuilder(); + + StringBuilder valuesStr = new StringBuilder(); + + builder.append("INSERT INTO ") + .append(SqlFieldReader.getTableName(entity)).append(" ") + .append("("); + for (String str : arrays) { + if ("id".equals(str)) { + continue; + } + valuesStr.append(str).append(","); + } + builder.append(valuesStr.substring(0, valuesStr.length() - 1)); + + builder.append(") ").append("VALUES("); + + valuesStr = new StringBuilder(); + for (String str : arrays) { + if ("id".equals(str)) { + continue; + } + valuesStr.append("#{").append(str).append("}").append(","); + } + builder.append(valuesStr.substring(0, valuesStr.length() - 1)) + .append(") "); + sql = builder.toString(); + insertAndReturnKeyMap.put(className, sql); + } + Console.info("insertAndReturnKey", sql, entity); + return sql; + } + + + public static void main(String[] args) { + + } +} \ No newline at end of file diff --git a/src/main/java/com/cheri/keller/common/mybatis/provider/BaseSelectProvider.java b/src/main/java/com/cheri/keller/common/mybatis/provider/BaseSelectProvider.java new file mode 100644 index 0000000..8aa6014 --- /dev/null +++ b/src/main/java/com/cheri/keller/common/mybatis/provider/BaseSelectProvider.java @@ -0,0 +1,170 @@ +package com.cheri.keller.common.mybatis.provider; + +import com.cheri.keller.common.mybatis.BaseEntity; +import com.cheri.keller.common.mybatis.SqlFieldReader; +import com.cheri.keller.common.util.Console; +import org.springframework.util.StringUtils; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 11:57 + **/ +public class BaseSelectProvider { + + public static Map selectPrefixWithDetailedMap = new ConcurrentHashMap<>(16); + public static Map selectPrefixMap = new ConcurrentHashMap<>(16); + + + /** + * 根据ID 查询数据 + * + * @param entity 实体对象 + * @param 实体类型 + * @return SELECT id,name... FROM route WHERE id = #{id} + */ + public static String selectById(T entity) { + String sql = getSelectPrefix(entity) + " WHERE id = #{id}"; + Console.info("selectById", sql, entity); + return sql; + } + + /** + * 根据主键查询数据,要求至少有一个主键,且主键必须有值 + * + * @param entity + * @param + * @return + */ + public static String selectByKey(T entity) { + try { + String sql = getSelectPrefix(entity) + SqlFieldReader.getConditionByKeySuffix(entity); + Console.info("selectByKey", sql, entity); + return sql; + } catch (Exception e) { + return null; + } + } + + + /** + * 查询所有数据,不带条件 + * + * @param entity 实体对象 + * @param 实体类型 + * @return SELECT id,name... FROM router + */ + public static String selectAll(T entity) { + String sql = getSelectPrefix(entity); + Console.info("selectAll", sql, entity); + return sql; + } + + + /** + * 带条件的查询,该查询为动态查询,不可缓存 + * 传入的对象中带@IndexAttribute注解的字段有值的都作为查询条件 + * 传入对象中带@SortAttribute注解的字段作为排序字段 + * + * @param entity 实体对象 + * param and 多个查询条件组合方式 null:不指定查询条件 true:多个查询条件用AND连接 false:多个查询条件用OR连接 + * param asc 排序方式 null:不指定排序方式 true:按指定排序字段升序 false:按指定排序字段降序 + * @param 实体类型 + * @return SELECT id,name... FROM router WHERE name = #{name} AND serviceName = #{serviceName} ORDER BY createTime ASC + */ + public static String selectByCondition(T entity) { + String sql = getSelectPrefix(entity) + + SqlFieldReader.getConditionSuffix(entity) + + SqlFieldReader.getSortSuffix(entity); + Console.info("selectByCondition", sql, entity); + return sql; + } + + /** + * 查询记录总数 + * + * @param entity + * @param + * @return SELECT COUNT(1) FROM router + */ + public static String selectCount(T entity) { + String sql = "SELECT COUNT(1) FROM " + SqlFieldReader.getTableName(entity); + Console.info("selectCount", sql, entity); + return sql; + } + + /** + * 根据条件查询记录总数 + * 传入的对象中带@IndexAttribute注解的字段有值的都作为查询条件 + * + * @param entity param and 多个查询条件组合方式 null:不指定查询条件 true:多个查询条件用AND连接 false:多个查询条件用OR连接 + * @param + * @return SELECT COUNT(1) FROM router WHERE name = #{name} AND serviceName = #{serviceName} + */ + public static String selectCountByCondition(T entity) { + String sql = selectCount(entity) + SqlFieldReader.getConditionSuffix(entity); + Console.info("selectCountByCondition", sql, entity); + return sql; + } + + /** + * 不加条件的分页查询 + * + * @param entity 实体对象 + * param startRows 起始行 + * param pageSize 查询页大小 + * @param 实体类型 + * @return SELECT id,name... FROM router LIMIT #{startRows},#{pageSize} + */ + public static String selectPageList(T entity) { + String sql = selectAll(entity) + " LIMIT #{baseKyleStartRows},#{baseKylePageSize}"; + Console.info("selectPageList", sql, entity); + return sql; + } + + /** + * 加条件的分页查询 + * 传入的对象中带@IndexAttribute注解的字段有值的都作为查询条件 + * + * @param entity param and 多个查询条件组合方式 null:不指定查询条件 true:多个查询条件用AND连接 false:多个查询条件用OR连接 + * param asc 排序方式 null:不指定排序方式 true:按指定排序字段升序 false:按指定排序字段降序 + * param startRows 起始行数 + * param pageSize 查询条数 + * @param + * @return SELECT id,name... FROM router WHERE name = #{name} AND serviceName = #{serviceName} ORDER BY createTime ASC LIMIT #{startRows},#{pageSize} + */ + public static String selectPageListByCondition(T entity) { + String sql = selectByCondition(entity) + " LIMIT #{baseKyleStartRows},#{baseKylePageSize}"; + Console.info("selectPageListByCondition", sql, entity); + return sql; + } + + /** + * 获取通用查询前缀 + * + * @param entity 实体类类型 + * @return SELECT 所有字段 FROM 表名 + */ + private static String getSelectPrefix(T entity) { + String className = entity.getClass().getName(); + String sql; + if (entity.isBaseKyleDetailed()) { + sql = selectPrefixWithDetailedMap.get(className); + } else { + sql = selectPrefixMap.get(className); + } + if (StringUtils.isEmpty(sql)) { + sql = "SELECT " + SqlFieldReader.getFieldStr(entity) + " FROM " + SqlFieldReader.getTableName(entity) + " "; + if (entity.isBaseKyleDetailed()) { + selectPrefixWithDetailedMap.put(className, sql); + } else { + selectPrefixMap.put(className, sql); + } + } + return sql; + + } +} diff --git a/src/main/java/com/cheri/keller/common/mybatis/provider/BaseUpdateProvider.java b/src/main/java/com/cheri/keller/common/mybatis/provider/BaseUpdateProvider.java new file mode 100644 index 0000000..c1f998d --- /dev/null +++ b/src/main/java/com/cheri/keller/common/mybatis/provider/BaseUpdateProvider.java @@ -0,0 +1,70 @@ +package com.cheri.keller.common.mybatis.provider; + +import com.cheri.keller.common.mybatis.BaseEntity; +import com.cheri.keller.common.mybatis.SqlFieldReader; +import com.cheri.keller.common.util.Console; + +import java.util.List; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 11:57 + **/ +public class BaseUpdateProvider { + + /** + * 根据id 更新数据,空值不更新 ,要求数据有id字段 + * + * @param entity + * @param + * @return UPDATE router SET methodName = #{methodName} ,createTime = #{createTime} WHERE id = #{id} + */ + public static String updateById(T entity) { + String sql = getUpdatePrefix(entity) + " WHERE id = #{id}"; + Console.info("updateById", sql, entity); + return sql; + } + + /** + * 根据主键更新数据,空值不更新,要求数据至少有一个主键,且主键有值 + * + * @param entity + * @param + * @return + */ + public static String updateByKey(T entity) { + try { + String sql = getUpdatePrefix(entity) + SqlFieldReader.getConditionByKeySuffix(entity); + Console.info("updateByKey", sql, entity); + return sql; + } catch (Exception e) { + return null; + } + } + + /** + * 获取更新操作的前缀部分 + * + * @param entity + * @return UPDATE 表名 SET + */ + private static String getUpdatePrefix(T entity) { + Class cls = entity.getClass(); + StringBuilder builder = new StringBuilder(); + builder.append("UPDATE ").append(SqlFieldReader.getTableName(entity)).append(" SET "); + List fields = SqlFieldReader.getFields(entity); + try { + for (String field : fields) { + if (SqlFieldReader.hasValue(entity, field)) { + builder.append(field).append(" = #{") + .append(field).append("} ").append(","); + } + } + return builder.substring(0, builder.lastIndexOf(",")); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/src/main/java/com/cheri/keller/common/proxy/ApiController.java b/src/main/java/com/cheri/keller/common/proxy/ApiController.java new file mode 100644 index 0000000..c0cb366 --- /dev/null +++ b/src/main/java/com/cheri/keller/common/proxy/ApiController.java @@ -0,0 +1,111 @@ +package com.cheri.keller.common.proxy; + +import com.cheri.keller.common.response.Response; +import com.cheri.keller.common.util.RequestUtil; +import com.cheri.keller.common.util.ResponseUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 12:27 + **/ +@RestController +@RequestMapping("/api") +@CrossOrigin(origins = "*", allowedHeaders = "*", maxAge = 3600) +public class ApiController { + + @Resource + HttpServletRequest request; + + @Autowired + RestTemplate restTemplate; + + // TODO 转发前校验JWT和用户权限 + + /** + * json 格式的GET请求 + * + * @param params + * @return + */ + @GetMapping + public ResponseEntity get(@RequestBody Map params) { + + ResponseEntity responseEntity; + try { + responseEntity = restTemplate.getForEntity(RequestUtil.getUrl(params, request), String.class, params); + RequestUtil.successLog(request, params, responseEntity); + } catch (Exception e) { + responseEntity = ResponseUtils.getResponseFromException(e); + RequestUtil.errorLog(request, params, responseEntity); + } + return responseEntity; + } + + + /** + * JSON 形式的 POST 请求 + * + * @param params + * @return + */ + @PostMapping + public ResponseEntity post(@RequestBody Map params) { + ResponseEntity responseEntity; + try { + responseEntity = restTemplate.postForEntity(RequestUtil.getUrl(params, request), null, String.class, params); + RequestUtil.successLog(request, params, responseEntity); + } catch (Exception e) { + responseEntity = ResponseUtils.getResponseFromException(e); + RequestUtil.errorLog(request, params, responseEntity); + } + return responseEntity; + } + + /** + * JSON 格式的 PUT 请求 + * + * @param params + * @return + */ + @PutMapping + public ResponseEntity put(@RequestBody Map params) { + ResponseEntity responseEntity = Response.ok(); + try { + restTemplate.put(RequestUtil.getUrl(params, request), null, params); + RequestUtil.successLog(request, params, responseEntity); + } catch (Exception e) { + responseEntity = ResponseUtils.getResponseFromException(e); + RequestUtil.errorLog(request, params, responseEntity); + } + return responseEntity; + } + + /** + * JSON 形式的 DELETE 请求 + * + * @param params + * @return + */ + @DeleteMapping + public ResponseEntity delete(@RequestBody Map params) { + ResponseEntity responseEntity = Response.ok(); + try { + restTemplate.delete(RequestUtil.getUrl(params, request), params); + RequestUtil.successLog(request, params, responseEntity); + } catch (Exception e) { + responseEntity = ResponseUtils.getResponseFromException(e); + RequestUtil.errorLog(request, params, responseEntity); + } + return responseEntity; + } +} + diff --git a/src/main/java/com/cheri/keller/common/proxy/FormController.java b/src/main/java/com/cheri/keller/common/proxy/FormController.java new file mode 100644 index 0000000..96e6875 --- /dev/null +++ b/src/main/java/com/cheri/keller/common/proxy/FormController.java @@ -0,0 +1,120 @@ +package com.cheri.keller.common.proxy; + +import com.cheri.keller.common.response.Response; +import com.cheri.keller.common.util.RequestUtil; +import com.cheri.keller.common.util.ResponseUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * 接口转发 + * + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 12:28 + **/ +@RestController +@RequestMapping("/form") +@CrossOrigin(origins = "*", allowedHeaders = "*", maxAge = 3600) +public class FormController { + + @Resource + HttpServletRequest request; + + @Autowired + RestTemplate restTemplate; + + // TODO 转发前校验JWT和用户权限 + + /** + * 表单形式的GET请求 + * + * @return + */ + @GetMapping + public ResponseEntity get() { + Map map = RequestUtil.getParam(request); + ResponseEntity responseEntity; + try { + String url = RequestUtil.getUrl(map, request); + if (map == null) { + responseEntity = restTemplate.getForEntity(url, String.class); + } else { + responseEntity = restTemplate.getForEntity(url, String.class, map); + } + RequestUtil.successLog(request, responseEntity); + } catch (Exception e) { + responseEntity = ResponseUtils.getResponseFromException(e); + RequestUtil.errorLog(request, responseEntity); + } + return responseEntity; + } + + + /** + * 表单形式的 POST 请求 + * + * @return + */ + @PostMapping + public ResponseEntity post() { + Map map = RequestUtil.getParam(request); + ResponseEntity responseEntity; + try { + responseEntity = restTemplate.postForEntity(RequestUtil.getUrl(map, request), null, String.class, map); + RequestUtil.successLog(request, responseEntity); + } catch (Exception e) { + responseEntity = ResponseUtils.getResponseFromException(e); + RequestUtil.errorLog(request, responseEntity); + } + return responseEntity; + } + + + /** + * 表单形式的 PUT 请求 + * + * @return + */ + @PutMapping + public ResponseEntity put() { + Map map = RequestUtil.getParam(request); + ResponseEntity responseEntity = Response.ok(); + try { + restTemplate.put(RequestUtil.getUrl(map, request), null, map); + RequestUtil.successLog(request, responseEntity); + } catch (Exception e) { + responseEntity = ResponseUtils.getResponseFromException(e); + RequestUtil.errorLog(request, responseEntity); + } + return responseEntity; + } + + /** + * 表单形式的 DELETE 请求 + * restTemplate.delete()方法没有返回值,因此在delete操作时无法知道执行状态 + * + * @return + */ + @DeleteMapping + public ResponseEntity delete() { + Map map = RequestUtil.getParam(request); + ResponseEntity responseEntity = Response.ok(); + try { + restTemplate.delete(RequestUtil.getUrl(map, request), map); + RequestUtil.successLog(request, responseEntity); + } catch (Exception e) { + responseEntity = ResponseUtils.getResponseFromException(e); + RequestUtil.errorLog(request, responseEntity); + } + return responseEntity; + + } + +} diff --git a/src/main/java/com/cheri/keller/common/response/Response.java b/src/main/java/com/cheri/keller/common/response/Response.java new file mode 100644 index 0000000..4e6a014 --- /dev/null +++ b/src/main/java/com/cheri/keller/common/response/Response.java @@ -0,0 +1,80 @@ +package com.cheri.keller.common.response; + +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; + +/** + * 规定Controller统一的消息返回格式 + * + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 12:18 + **/ +public class Response { + /** + * 返回OK + * + * @param object + * @return + */ + public static ResponseEntity ok(ResultData object) { + return ResponseEntity.ok() + .contentType(MediaType.APPLICATION_JSON).body(object); + } + + /** + * 返回OK + * + * @return + */ + public static ResponseEntity ok() { + ResultData response = ResultData.success(); + return ResponseEntity.ok() + .contentType(MediaType.APPLICATION_JSON).body(response); + } + + /** + * 异常请求 + * + * @return + */ + public static ResponseEntity badRequest() { + ResultData response = ResultData.error("请求参数异常"); + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .contentType(MediaType.APPLICATION_JSON).body(response); + } + + /** + * 没有登录 + * + * @return + */ + public static ResponseEntity unauthorized() { + ResultData response = ResultData.error("用户未登录"); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .contentType(MediaType.APPLICATION_JSON).body(response); + } + + /** + * 没有访问权限 + * + * @return + */ + public static ResponseEntity forbidden() { + ResultData response = ResultData.error("没有权限"); + return ResponseEntity.status(HttpStatus.FORBIDDEN) + .contentType(MediaType.APPLICATION_JSON).body(response); + } + + /** + * 系统内部错误 + * + * @return + */ + public static ResponseEntity error() { + ResultData response = ResultData.error("系统错误"); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .contentType(MediaType.APPLICATION_JSON).body(response); + } +} diff --git a/src/main/java/com/cheri/keller/common/response/ResultData.java b/src/main/java/com/cheri/keller/common/response/ResultData.java new file mode 100644 index 0000000..311487f --- /dev/null +++ b/src/main/java/com/cheri/keller/common/response/ResultData.java @@ -0,0 +1,89 @@ +package com.cheri.keller.common.response; + +/** + * * 规定Service统一的消息返回格式 + * * 在Controller中统一返回ResponseEntity格式的数据,在ResponseEntity的body里,必须使用MyResponseObject格式的数据 + * + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 12:19 + **/ +public class ResultData { + + /** + * 业务状态 0:成功 1:失败 + */ + private int success; + /** + * 返回数据 + */ + private Object data; + /** + * 文字描述,一般放业务处理失败时返回的错误信息 + */ + private String message; + + public final static int SUCCESS_CODE_SUCCESS = 0; + public final static int SUCCESS_CODE_FAILED = 1; + + public ResultData() { + } + + public static ResultData success() { + ResultData resultData = new ResultData(); + resultData.setSuccess(SUCCESS_CODE_SUCCESS); + return resultData; + } + + public static ResultData success(Object data) { + ResultData resultData = new ResultData(); + resultData.setSuccess(SUCCESS_CODE_SUCCESS); + resultData.setData(data); + return resultData; + } + + public static ResultData error(String message) { + ResultData resultData = new ResultData(); + resultData.setSuccess(SUCCESS_CODE_FAILED); + resultData.setMessage(message); + return resultData; + } + + public boolean isSuccess() { + return success == SUCCESS_CODE_SUCCESS; + } + + + public int getSuccess() { + return success; + } + + public void setSuccess(int success) { + this.success = success; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + @Override + public String toString() { + return "ResultData{" + + "success=" + success + + ", data=" + data + + ", message='" + message + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/src/main/java/com/cheri/keller/common/util/Console.java b/src/main/java/com/cheri/keller/common/util/Console.java new file mode 100644 index 0000000..772caf4 --- /dev/null +++ b/src/main/java/com/cheri/keller/common/util/Console.java @@ -0,0 +1,57 @@ +package com.cheri.keller.common.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 控制台日志输出工具类 + * + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 12:11 + **/ +public class Console { + + private static Logger logger = LoggerFactory.getLogger(Console.class); + + public static void print(String title,Object ... objects){ + System.out.println("=======" + title + "========"); + for(Object object : objects){ + System.out.print(object + "\t"); + } + System.out.println(); + } + + public static void println(String title,Object ... objects){ + System.out.println("=======" + title + "========"); + for(Object object : objects){ + System.out.println(object); + } + System.out.println(); + } + + public static void info(String title,Object ... objects){ + if(logger.isInfoEnabled()){ + StringBuilder builder = new StringBuilder(); + builder.append("======").append(title).append("======"); + for (Object object:objects){ + builder.append("\n").append(object); + } + builder.append("\n"); + logger.info(builder.toString()); + } + } + + public static void error(String title,Object ... objects){ + if(logger.isErrorEnabled()){ + StringBuilder builder = new StringBuilder(); + builder.append("======").append(title).append("======"); + for (Object object:objects){ + builder.append("\n").append(object); + } + builder.append("\n"); + logger.error(builder.toString()); + } + } + +} diff --git a/src/main/java/com/cheri/keller/common/util/RequestUtil.java b/src/main/java/com/cheri/keller/common/util/RequestUtil.java new file mode 100644 index 0000000..79c23ac --- /dev/null +++ b/src/main/java/com/cheri/keller/common/util/RequestUtil.java @@ -0,0 +1,142 @@ +package com.cheri.keller.common.util; + +import com.cheri.keller.common.config.RequestConfig; +import org.springframework.http.ResponseEntity; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * 请求参数验证工具类 + * + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 12:12 + **/ +public class RequestUtil { + + public static String port; + public static String address; + + /** + * 记录请求成功的日志(使用json提交参数的请求) + * @param request 请求 + * @param params 请求参数 + * @param response 应答 + */ + public static void successLog(HttpServletRequest request, Map params, ResponseEntity response){ + String requestId = StringUtils.getUUID(); + Console.info("api header",requestId,getHeader(request)); + Console.info("param",requestId,params); + Console.info("response success",requestId,response.getBody()); + } + + /** + * 记录请求成功的日志(使用form提交参数的请求,请求在Request中) + * @param request 请求 + * @param response 应答 + */ + public static void successLog(HttpServletRequest request, ResponseEntity response){ + String requestId = StringUtils.getUUID(); + Console.info("form header",requestId,getHeader(request)); + Console.info("param",requestId,getParam(request)); + Console.info("response success",requestId,response.getBody()); + } + + /** + * 记录请求失败的日志(使用json提交参数的请求) + * @param request 请求 + * @param params 参数 + * @param response 应答 + */ + public static void errorLog(HttpServletRequest request, Map params, ResponseEntity response){ + String requestId = StringUtils.getUUID(); + Console.error("api header",requestId,getHeader(request)); + Console.error("param",requestId,params); + Console.error("response error",requestId,response.getBody()); + } + + /** + * 记录请求失败的日志(使用form提交参数的请求,请求在Request中) + * @param request 请求 + * @param response 应答 + */ + public static void errorLog(HttpServletRequest request, ResponseEntity response){ + String requestId = StringUtils.getUUID(); + Console.error("form header",requestId,getHeader(request)); + Console.error("param",requestId,getParam(request)); + Console.error("response error",requestId,response.getBody()); + } + + public static HashMap getHeader(HttpServletRequest request){ + HashMap headerMap = new HashMap<>(16); + //请求的URL地址 + headerMap.put(RequestConfig.URL,request.getRequestURL().toString()); + //请求的资源 + headerMap.put(RequestConfig.URI,request.getRequestURI()); + //请求方式 GET/POST + headerMap.put(RequestConfig.REQUEST_METHOD,request.getMethod()); + + //来访者的IP地址 + headerMap.put(RequestConfig.REMOTE_ADDR,request.getRemoteAddr()); + //来访者的HOST + headerMap.put(RequestConfig.REMOTE_HOST,request.getRemoteHost()); + //来访者的端口 + headerMap.put(RequestConfig.REMOTE_PORT,request.getRemotePort() + ""); + //来访者的用户名 + headerMap.put(RequestConfig.REMOTE_USER,request.getRemoteUser()); + + + //自定义的Header (接口名) + headerMap.put(RequestConfig.METHOD,request.getHeader(RequestConfig.METHOD)); + //自定义的Header (TOKEN) + headerMap.put(RequestConfig.TOKEN,request.getHeader(RequestConfig.TOKEN)); + return headerMap; + } + + public static Map getParam(HttpServletRequest request){ + Map paramMap = new HashMap<>(16); + //request对象封装的参数是以Map的形式存储的 + Map map = request.getParameterMap(); + for(Map.Entry entry :map.entrySet()){ + String paramName = entry.getKey(); + String paramValue = ""; + String[] paramValueArr = entry.getValue(); + for (int i = 0; paramValueArr!=null && i < paramValueArr.length; i++) { + if (i == paramValueArr.length-1) { + paramValue += paramValueArr[i]; + }else { + paramValue += paramValueArr[i]+","; + } + } + paramMap.put(paramName,paramValue); + } + if(paramMap.size() == 0){ + return null; + } + return paramMap; + } + public static String getUrl(Map params, HttpServletRequest request){ + HashMap headers = getHeader(request); + StringBuilder builder = new StringBuilder(); + + builder + .append(address).append(":") + .append(port).append("/") + .append(headers.get(RequestConfig.METHOD)); + if(params == null){ + return builder.toString(); + } + builder.append("?"); + for(String key :params.keySet()){ + builder.append(key) + .append("={") + .append(key) + .append("}&"); + } + Console.info(builder.toString()); + return builder.toString(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/cheri/keller/common/util/ResponseUtils.java b/src/main/java/com/cheri/keller/common/util/ResponseUtils.java new file mode 100644 index 0000000..5402300 --- /dev/null +++ b/src/main/java/com/cheri/keller/common/util/ResponseUtils.java @@ -0,0 +1,52 @@ +package com.cheri.keller.common.util; + +import com.cheri.keller.common.response.Response; +import com.cheri.keller.common.response.ResultData; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.HttpClientErrorException; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 12:12 + **/ +public class ResponseUtils { + /** + * 根据组件返回的错误码重组应答报文 + * + * @param exception + * @return + */ + public static ResponseEntity getResponseFromException(Exception exception) { + ResponseEntity response; + if (exception instanceof HttpClientErrorException) { + HttpClientErrorException errorException = (HttpClientErrorException) exception; + switch (errorException.getStatusCode()) { + case FORBIDDEN: + response = Response.forbidden(); + break; + case BAD_REQUEST: + response = Response.badRequest(); + break; + case UNAUTHORIZED: + response = Response.unauthorized(); + break; + case INTERNAL_SERVER_ERROR: + response = Response.error(); + break; + default: { + ResultData resultData = ResultData.error("ERROR"); + response = ResponseEntity.status(errorException.getStatusCode()).contentType(MediaType.APPLICATION_JSON).body(resultData); + } + } + } else { + response = Response.badRequest(); + } + return response; + } + + public static ResultData getResultDataFromException(HttpClientErrorException exception) { + return (ResultData) getResponseFromException(exception).getBody(); + } +} \ No newline at end of file diff --git a/src/main/java/com/cheri/keller/common/util/SendEmailUtils.java b/src/main/java/com/cheri/keller/common/util/SendEmailUtils.java new file mode 100644 index 0000000..e765436 --- /dev/null +++ b/src/main/java/com/cheri/keller/common/util/SendEmailUtils.java @@ -0,0 +1,144 @@ +package com.cheri.keller.common.util; + +import com.cheri.keller.common.config.PublicConstant; +import com.cheri.keller.entity.EmailLog; + +import javax.mail.Message; +import javax.mail.Session; +import javax.mail.Transport; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; +import java.util.Properties; + +/** + * * SendEmailUtils.getSender( + * * myConfig.mailServerHost, + * * myConfig.mailServerUser, + * * myConfig.mailServerPassword) + * * .sendSimpleMail("atomiclong@aliyun.com", + * * "你好", + * * "邮件内容"); + * + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 21:30 + **/ +public class SendEmailUtils { + /** + * 邮件验证码标题 + */ + public static final String TITLE ="【From】" + PublicConstant.appName; + + /** + * 邮件验证码正文内容 + */ + public static final String RegisterBody = + "验证码:%1$s,用于账号: %2$s 注册,泄露有风险。" + + PublicConstant.EMAIL_CODE_TIME + "分钟内使用有效。"; + + public static final String LoginBody = + "验证码:%1$s,用于账号: %2$s 登录,泄露有风险。" + + PublicConstant.EMAIL_CODE_TIME + "分钟内使用有效。"; + + public static final String ResetPasswordBody = + "验证码:%1$s,用于账号: %2$s 找回密码,泄露有风险。" + + PublicConstant.EMAIL_CODE_TIME + "分钟内使用有效。"; + + + public static Session session= null; + + /** + * 初始化Session + * @return + */ + private static Session initSession(){ + if(session == null) { + try { + Properties prop = new Properties(); + //邮件服务器地址 + prop.setProperty("mail.host", "smtp.qq.com"); + //邮件发送协议 + prop.setProperty("mail.transport.protocol", "smtp"); + //是否需要身份验证 + prop.setProperty("mail.smtp.auth", "true"); + //创建session + session = Session.getInstance(prop); + //开启Session的debug模式,这样就可以查看到程序发送Email的运行状态 + session.setDebug(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + return session; + } + + /** + * 发送简单邮件 + * @param toEmailAddress 收件人地址 + * @param title 邮件标题 + * @param content 邮件内容 + * @throws Exception + */ + private static void sendSimpleMail(String toEmailAddress,String title,String content) + throws Exception { + Session session = initSession(); + //创建邮件对象 + MimeMessage message = new MimeMessage(session); + //指明邮件的发件人 + message.setFrom(new InternetAddress(PublicConstant.mailServerUser)); + //指明邮件的收件人 + message.setRecipient(Message.RecipientType.TO, new InternetAddress(toEmailAddress)); + //邮件的标题 + message.setSubject(title); + //邮件的文本内容 + message.setContent(content, "text/html;charset=UTF-8"); + //返回创建好的邮件对象 + Transport transport = session.getTransport(); + //使用邮箱的用户名和密码连上邮件服务器,发送邮件时,发件人需要提交邮箱的用户名和密码给smtp服务器,用户名和密码都通过验证之后才能够正常发送邮件给收件人 + transport.connect(PublicConstant.mailServerHost,PublicConstant.mailServerUser,PublicConstant.mailServerPassword); + transport.sendMessage(message, message.getAllRecipients()); + transport.close(); + } + + /** + * 发送邮件验证码 + * 1.随机生成指定位数的验证码 + * 2.创建邮件实体类,设置收件人地址、邮件标题、邮件内容、验证码 + * 3.发送邮件并记录发送结果 + * 4.返回包含发送结果的邮件实体类 + * @param email 收件人邮箱 + * @return 邮件实体类EmailEntity + */ + public static EmailLog sendVCode(int type, String email){ + String code = StringUtils.getAllCharString(PublicConstant.EMAIL_CODE_LENGTH); + EmailLog entity = new EmailLog(); + entity.setEmail(email); + entity.setType(type); + entity.setTitle(TITLE); + String body; + switch (type){ + case PublicConstant.REGISTER_TYPE : + body = String.format(RegisterBody,code,email); + break; + case PublicConstant.LOGIN_TYPE : + body = String.format(LoginBody,code,email); + break; + case PublicConstant.RESET_PASSWORD_TYPE : + body = String.format(ResetPasswordBody,code,email); + break; + default:return null; + } + entity.setContent(body); + entity.setCode(code); + try { + sendSimpleMail(entity.getEmail(),entity.getTitle(),entity.getContent()); + }catch (Exception e){ + Console.error("send sendVerificationCode error :",e.getMessage()); + entity.setResult(e.getMessage()); + entity.setStatusCode(PublicConstant.FAILED); + } + return entity; + } + + +} diff --git a/src/main/java/com/cheri/keller/common/util/StringUtils.java b/src/main/java/com/cheri/keller/common/util/StringUtils.java new file mode 100644 index 0000000..d60aabd --- /dev/null +++ b/src/main/java/com/cheri/keller/common/util/StringUtils.java @@ -0,0 +1,177 @@ +package com.cheri.keller.common.util; + +import java.util.Random; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 12:14 + **/ +public class StringUtils { + + /** + * 纯数字集合 + */ + private static final String numbersChar = "0123456789"; + + /** + * 大小写字母、数字集合 + */ + private static final String allChar = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + + /** + * 手机号校验规则:1开头的11位数字 + */ + private static final String PHONE_NUMBER_PATTERN = "^1+\\d{10}$"; + + /** + * 用户名校验规则:允许字母、数字、下划线 + */ + private static final String USER_NAME_PATTERN = "^[a-zA-Z0-9_]+$"; + + /** + * 邮箱校验规则:**@**.** + */ + private static final String EMAIL_ADDRESS_PATTERN = "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|" + + "(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$"; + + /** + * 校验是否是用户名 + * + * @param string + * @return + */ + public static boolean isUserName(String string) { + if (isEmpty(string)) { + return false; + } + Pattern pattern = Pattern.compile(USER_NAME_PATTERN); + Matcher matcher = pattern.matcher(string); + return matcher.matches(); + } + + /** + * 校验是否是手机号 + * + * @param string + * @return + */ + public static boolean isPhoneNo(String string) { + if (isEmpty(string)) { + return false; + } + Pattern pattern = Pattern.compile(PHONE_NUMBER_PATTERN); + Matcher matcher = pattern.matcher(string); + return matcher.matches(); + + } + + + public static boolean notPhoneOrEmail(String string) { + return !isEmail(string) && !isPhoneNo(string); + } + + public static boolean isPhoneOrEmail(String string) { + return isEmail(string) || isPhoneNo(string); + } + + /** + * 校验是否是邮箱 + * + * @param string + * @return + */ + public static boolean isEmail(String string) { + if (isEmpty(string)) { + return false; + } + Pattern pattern = Pattern.compile(EMAIL_ADDRESS_PATTERN); + Matcher matcher = pattern.matcher(string); + return matcher.matches(); + } + + public static boolean notEmail(String string) { + return !isEmail(string); + } + + + /** + * 判断一系列字符串中是否有空的(包含:空字符串、null、纯空格字符) + * + * @param parameters 需要判断的字符串,可以是多个 + * @return + */ + public static boolean isEmpty(String... parameters) { + for (String str : parameters) { + if (str == null || str.isEmpty() || str.trim().isEmpty()) { + return true; + } + } + return false; + } + + public static boolean isNotEmpty(String... parameters) { + return !isEmpty(parameters); + } + + /** + * 将字符串的首字母转大写 + * + * @param str 需要转换的字符串 + * @return + */ + public static String captureName(String str) { + // 进行字母的ascii编码前移,效率要高于截取字符串进行转换的操作 + char[] cs = str.toCharArray(); + cs[0] -= 32; + return String.valueOf(cs); + } + + /** + * 生成指定长度的数字字符串 + * + * @param length 字符串长度 + * @return + */ + public static String getNumberString(int length) { + StringBuffer sb = new StringBuffer(); + Random random = new Random(); + for (int i = 0; i < length; i++) { + sb.append(numbersChar.charAt(random.nextInt(numbersChar.length()))); + } + return sb.toString(); + } + + /** + * 生成指定长度的字符串(含大小写字母及数字) + * + * @param length + * @return + */ + public static String getAllCharString(int length) { + StringBuffer sb = new StringBuffer(); + Random random = new Random(); + for (int i = 0; i < length; i++) { + sb.append(allChar.charAt(random.nextInt(allChar.length()))); + } + return sb.toString(); + } + + /** + * 获取UUID(32位的字母数字的集合) + * + * @return + */ + public static String getUUID() { + return UUID.randomUUID().toString().replace("-", "").toUpperCase(); + } + + public static void main(String[] args) { + Console.print("", isEmail("guyexing@cc.com")); + Console.print("UUID", getUUID()); + } + +} \ No newline at end of file diff --git a/src/main/java/com/cheri/keller/controller/BaseController.java b/src/main/java/com/cheri/keller/controller/BaseController.java new file mode 100644 index 0000000..edd351d --- /dev/null +++ b/src/main/java/com/cheri/keller/controller/BaseController.java @@ -0,0 +1,62 @@ +package com.cheri.keller.controller; + +import com.cheri.keller.common.config.PublicConstant; +import com.cheri.keller.common.response.Response; +import com.cheri.keller.common.util.Console; +import com.cheri.keller.common.util.StringUtils; +import com.cheri.keller.entity.UserInfo; +import com.cheri.keller.service.UserService; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.Map; + +/** + * 不需要登录就能调用的接口 + * + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 22:21 + **/ +@RestController +@RequestMapping("/base") +@CrossOrigin(origins = "*",allowedHeaders="*", maxAge = 3600) +public class BaseController { + @Resource + private UserService userService; + + /** + * 注册功能 + */ + @PostMapping("/register") + public ResponseEntity register(@RequestBody Map params){ + Console.info("register",params); + String email = params.get("email"); + String password = params.get("password"); + String code = params.get("code"); + if(StringUtils.isEmpty(password,code) || StringUtils.notEmail(email)){ + return Response.badRequest(); + } + UserInfo userInfo = new UserInfo(); + userInfo.setEmail(email); + userInfo.setPassword(password); + userInfo.setType(PublicConstant.DEFAULT_USER_TYPE); + + return Response.ok(userService.register(userInfo,code)); + } + + /** + * 获取验证码 + * @param email + * @return + */ + @GetMapping("/getCodeForRegister") + public ResponseEntity getCode(String email){ + Console.info("getCodeForRegister",email); + if(StringUtils.notEmail(email)){ + return Response.badRequest(); + } + return Response.ok(userService.sendRegisterCode(PublicConstant.DEFAULT_USER_TYPE,email)); + } +} diff --git a/src/main/java/com/cheri/keller/controller/JsonResourceUtils.java b/src/main/java/com/cheri/keller/controller/JsonResourceUtils.java new file mode 100644 index 0000000..216f851 --- /dev/null +++ b/src/main/java/com/cheri/keller/controller/JsonResourceUtils.java @@ -0,0 +1,36 @@ +package com.cheri.keller.controller; + +import java.io.*; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/23 20:35 + **/ +public class JsonResourceUtils { + public static String readJsonFile(String fileName) { + String jsonStr = ""; + try { + File jsonFile = new File(fileName); + FileReader fileReader = new FileReader(jsonFile); + + Reader reader = new InputStreamReader(new FileInputStream(jsonFile),"utf-8"); + int ch = 0; + StringBuffer sb = new StringBuffer(); + while ((ch = reader.read()) != -1) { + sb.append((char) ch); + } + fileReader.close(); + reader.close(); + jsonStr = sb.toString(); + return jsonStr; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + public static void main(String[] args) throws Exception{ + + } +} diff --git a/src/main/java/com/cheri/keller/controller/PageUtil.java b/src/main/java/com/cheri/keller/controller/PageUtil.java new file mode 100644 index 0000000..68c9591 --- /dev/null +++ b/src/main/java/com/cheri/keller/controller/PageUtil.java @@ -0,0 +1,50 @@ +package com.cheri.keller.controller; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/23 19:51 + **/ +public class PageUtil { + + private int code=0; + private String msg; + private Long count; //总条数 + private List data = new ArrayList(); //装前台当前页的数据 + //getter/setter方法... + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public Long getCount() { + return count; + } + + public void setCount(Long count) { + this.count = count; + } + + public List getData() { + return data; + } + + public void setData(List data) { + this.data = data; + } +} \ No newline at end of file diff --git a/src/main/java/com/cheri/keller/controller/TestTableController.java b/src/main/java/com/cheri/keller/controller/TestTableController.java new file mode 100644 index 0000000..1fca557 --- /dev/null +++ b/src/main/java/com/cheri/keller/controller/TestTableController.java @@ -0,0 +1,32 @@ +package com.cheri.keller.controller; + +import com.cheri.keller.common.response.Response; +import com.cheri.keller.common.response.ResultData; +import com.cheri.keller.mapper.TestTableMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.List; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/23 19:30 + **/ +@CrossOrigin(origins = "*",allowedHeaders="*", maxAge = 3600) +@RestController +@RequestMapping("/testTable") +public class TestTableController { + @Autowired + TestTableMapper mapper; + @RequestMapping("/all") + @PostMapping + public String getAll(@RequestParam("taskIds") Long taskIds) { + List longs = Arrays.asList(taskIds); + int resultData = mapper.batchUpdate("1",longs,"0"); + return JsonResourceUtils.readJsonFile("H:\\SoftwareDev\\LearningSpace\\keller\\src\\main\\resources\\config\\json.json"); + + } +} diff --git a/src/main/java/com/cheri/keller/controller/UserController.java b/src/main/java/com/cheri/keller/controller/UserController.java new file mode 100644 index 0000000..e70ebe4 --- /dev/null +++ b/src/main/java/com/cheri/keller/controller/UserController.java @@ -0,0 +1,39 @@ +package com.cheri.keller.controller; + +import com.cheri.keller.common.response.Response; +import com.cheri.keller.common.response.ResultData; +import com.cheri.keller.common.util.StringUtils; +import com.cheri.keller.service.UserService; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 12:45 + **/ +@RestController +@RequestMapping("/user") +public class UserController { + @Resource + private UserService userService; + + @GetMapping + public ResponseEntity getAll() { + ResultData resultData = userService.getAll(); + return Response.ok(resultData); + } + + @GetMapping("/getByEmail") + public ResponseEntity getByEmail(String email) { + if (StringUtils.isEmpty(email)) { + return Response.badRequest(); + } + ResultData resultData = userService.getByEmail(email); + return Response.ok(resultData); + } +} \ No newline at end of file diff --git a/src/main/java/com/cheri/keller/entity/EmailLog.java b/src/main/java/com/cheri/keller/entity/EmailLog.java new file mode 100644 index 0000000..fdd57d3 --- /dev/null +++ b/src/main/java/com/cheri/keller/entity/EmailLog.java @@ -0,0 +1,194 @@ +package com.cheri.keller.entity; + +import com.cheri.keller.common.mybatis.BaseEntity; +import com.cheri.keller.common.mybatis.annotation.*; + +import java.util.Date; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 21:04 + **/ +@TableAttribute(name = "email_log") +public class EmailLog extends BaseEntity { + @FieldAttribute + @KeyAttribute(autoIncr = true) + private int id; + /** + * 邮件发送类型 + */ + @FieldAttribute(value = "邮件发送类型,不能为空", notNull = true) + @IndexAttribute + private Integer type; + /** + * 收件人 + */ + @FieldAttribute(value = "收件人,不能为空", notNull = true) + @IndexAttribute + private String email; + /** + * 标题 + */ + @FieldAttribute(value = "邮件标题,不能为空", notNull = true, length = 200) + private String title; + /** + * 内容 + */ + @FieldAttribute(value = "邮件内容,不能为空", notNull = true, length = 500) + private String content; + /** + * 验证码 + * 包含验证码的邮件,需要将验证码单独填写,方便查询 + */ + @FieldAttribute("验证码") + private String code; + + @FieldAttribute(value = "发送结果描述,如:发送失败的原因等", length = 500) + private String result; + /** + * 状态码 + * 0 成功 + * 1 失败 + */ + @FieldAttribute(value = "发送状态", notNull = true) + private int statusCode; + + /** + * 发送时间,验证码邮件的有效时间为5分钟 + */ + @FieldAttribute(value = "发送时间", notNull = true) + @SortAttribute + private Date createTime = new Date(); + + /** + * 验证码是否已使用 0:未使用 1:已使用 + */ + @FieldAttribute("验证码是否已使用") + private int isUsed = 0; + + public EmailLog() { + super(); + } + + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + 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 getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getResult() { + return result; + } + + public void setResult(String result) { + this.result = result; + } + + public int getStatusCode() { + return statusCode; + } + + public void setStatusCode(int statusCode) { + this.statusCode = statusCode; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public int getIsUsed() { + return isUsed; + } + + public void setIsUsed(int isUsed) { + this.isUsed = isUsed; + } + + @Override + public String toString() { + return "Email{" + + "id=" + id + + ", type=" + type + + ", email='" + email + '\'' + + ", title='" + title + '\'' + + ", content='" + content + '\'' + + ", code='" + code + '\'' + + ", result='" + result + '\'' + + ", statusCode=" + statusCode + + ", createTime=" + createTime + + ", isUsed=" + isUsed + + '}'; + } + + + public boolean equalsCode(EmailLog emailLog) { + if (emailLog.getType().equals(type) + && emailLog.getEmail().equals(email) + && emailLog.getCode().equals(code)) { + return true; + } + + return false; + } + + /** + * 是否是有效的验证码 + * 要求成功发送,发送时间在5分钟内,且未使用过 + * + * @return + */ + public boolean isEfficientVerificationCode() { + return (System.currentTimeMillis() - createTime.getTime() < 5 * 60 * 1000 + && isUsed == 0 + && statusCode == 0 + ); + } +} \ No newline at end of file diff --git a/src/main/java/com/cheri/keller/entity/TestTable.java b/src/main/java/com/cheri/keller/entity/TestTable.java new file mode 100644 index 0000000..f2a618c --- /dev/null +++ b/src/main/java/com/cheri/keller/entity/TestTable.java @@ -0,0 +1,56 @@ +package com.cheri.keller.entity; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/23 17:42 + **/ +public class TestTable { + private Integer id; + private String name; + private String state; + private Integer age; + + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + @Override + public String toString() { + return "TestTable{" + + "id=" + id + + ", name='" + name + '\'' + + ", state='" + state + '\'' + + ", age=" + age + + '}'; + } +} diff --git a/src/main/java/com/cheri/keller/entity/UserInfo.java b/src/main/java/com/cheri/keller/entity/UserInfo.java new file mode 100644 index 0000000..d0b3f49 --- /dev/null +++ b/src/main/java/com/cheri/keller/entity/UserInfo.java @@ -0,0 +1,145 @@ +package com.cheri.keller.entity; + +import com.cheri.keller.common.mybatis.BaseEntity; +import com.cheri.keller.common.mybatis.annotation.FieldAttribute; +import com.cheri.keller.common.mybatis.annotation.IndexAttribute; +import com.cheri.keller.common.mybatis.annotation.KeyAttribute; +import com.cheri.keller.common.mybatis.annotation.TableAttribute; + +import java.util.Date; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 11:02 + **/ +@TableAttribute(name = "user_info", comment = "用户信息表") +public class UserInfo extends BaseEntity { + @KeyAttribute(autoIncr = true) + @FieldAttribute + private int id; + + @FieldAttribute(value = "用户类型", notNull = true) + @IndexAttribute + private Integer type; + + + @FieldAttribute(value = "密码", length = 200) + private String password; + + @FieldAttribute(value = "邮箱", notNull = true, length = 200) + @IndexAttribute + private String email; + + @FieldAttribute + private Date createTime = new Date(); + + @FieldAttribute("用户账号状态") + @IndexAttribute + private Integer status; + + @FieldAttribute("是否删除,1 表示删除") + @IndexAttribute + private Integer isDelete; + + @FieldAttribute("最后一次修改时间") + private Date updateTime = new Date(); + + @FieldAttribute("修改人") + private Integer updateUserId; + + public UserInfo() { + } + + public UserInfo(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getIsDelete() { + return isDelete; + } + + public void setIsDelete(Integer isDelete) { + this.isDelete = isDelete; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + public Integer getUpdateUserId() { + return updateUserId; + } + + public void setUpdateUserId(Integer updateUserId) { + this.updateUserId = updateUserId; + } + + @Override + public String toString() { + return "UserInfo{" + + "id=" + id + + ", type=" + type + + ", password='" + password + '\'' + + ", email='" + email + '\'' + + ", createTime=" + createTime + + ", status=" + status + + ", isDelete=" + isDelete + + ", updateTime=" + updateTime + + ", updateUserId=" + updateUserId + + '}'; + } +} diff --git a/src/main/java/com/cheri/keller/mapper/EmailMapper.java b/src/main/java/com/cheri/keller/mapper/EmailMapper.java new file mode 100644 index 0000000..15f79e8 --- /dev/null +++ b/src/main/java/com/cheri/keller/mapper/EmailMapper.java @@ -0,0 +1,14 @@ +package com.cheri.keller.mapper; + +import com.cheri.keller.common.mybatis.BaseMapper; +import com.cheri.keller.entity.EmailLog; +import org.apache.ibatis.annotations.Mapper; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 21:28 + **/ +@Mapper +public interface EmailMapper extends BaseMapper { +} \ No newline at end of file diff --git a/src/main/java/com/cheri/keller/mapper/TestTableMapper.java b/src/main/java/com/cheri/keller/mapper/TestTableMapper.java new file mode 100644 index 0000000..a3e83ce --- /dev/null +++ b/src/main/java/com/cheri/keller/mapper/TestTableMapper.java @@ -0,0 +1,21 @@ +package com.cheri.keller.mapper; + +import com.cheri.keller.entity.TestTable; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/23 17:31 + **/ +public interface TestTableMapper { + + List bacthSelect(@Param("ids")List ids); + + int batchUpdate(@Param("state")String state, @Param("ids") List ids, + @Param("newState") String newState); + + int batchDelete(@Param("ids")List ids); +} diff --git a/src/main/java/com/cheri/keller/mapper/UserMapper.java b/src/main/java/com/cheri/keller/mapper/UserMapper.java new file mode 100644 index 0000000..cf9c178 --- /dev/null +++ b/src/main/java/com/cheri/keller/mapper/UserMapper.java @@ -0,0 +1,36 @@ +package com.cheri.keller.mapper; + +import com.cheri.keller.common.mybatis.BaseMapper; +import com.cheri.keller.entity.UserInfo; +import org.apache.ibatis.annotations.Insert; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Options; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 12:42 + **/ +@Mapper +public interface UserMapper extends BaseMapper { + @Select("select id, type, email, password, createTime, status, isDelete, updateTime, updateUserId " + + "from user_info") + List selectAll(); + + @Select("select id, type, email, password, createTime, status, isDelete, updateTime, updateUserId " + + "from user_info where id = #{id}") + UserInfo selectById(int id); + + @Select("Select id, type, email, password, createTime, status, isDelete, updateTime, updateUserId " + + "from user_info where email = #{email} ") + UserInfo selectByEmail(String email); + + @Insert("Insert into user_info (id, type, email, password, createTime, status, isDelete) " + + "values(#{id}, #{type}, #{email}, #{password}, #{createTime}, #{status}, #{isDelete})") + @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id") + Integer insertAndReturnKey(UserInfo userInfo); + +} diff --git a/src/main/java/com/cheri/keller/service/EmailService.java b/src/main/java/com/cheri/keller/service/EmailService.java new file mode 100644 index 0000000..8bef978 --- /dev/null +++ b/src/main/java/com/cheri/keller/service/EmailService.java @@ -0,0 +1,57 @@ +package com.cheri.keller.service; + +import com.cheri.keller.common.response.ResultData; +import com.cheri.keller.common.util.SendEmailUtils; +import com.cheri.keller.entity.EmailLog; +import com.cheri.keller.mapper.EmailMapper; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 21:29 + **/ +@Service +public class EmailService { + @Resource + private EmailMapper mapper; + + /** + * 发送邮件验证码 + * @param type + * @param email + * @return + */ + public ResultData sendCode(int type, String email){ + EmailLog emailLog = SendEmailUtils.sendVCode(type,email); + if(emailLog == null){ + return ResultData.error("邮件发送失败"); + } + mapper.baseInsertAndReturnKey(emailLog); + return ResultData.success(); + } + + public boolean checkCode(EmailLog emailLog){ + emailLog.setEmail(emailLog.getEmail()); + emailLog.setBaseKyleUseASC(false); + List list = mapper.baseSelectByCondition(emailLog); + if(list == null || list.size() <= 0){ + return false; + } + EmailLog result = list.get(0); + if(result.isEfficientVerificationCode() && + result.equalsCode(emailLog)){ + setCodeUsed(result); + return true; + } + return false; + } + + private void setCodeUsed(EmailLog emailLog){ + emailLog.setIsUsed(1); + mapper.baseUpdateById(emailLog); + } +} diff --git a/src/main/java/com/cheri/keller/service/UserService.java b/src/main/java/com/cheri/keller/service/UserService.java new file mode 100644 index 0000000..a0265e7 --- /dev/null +++ b/src/main/java/com/cheri/keller/service/UserService.java @@ -0,0 +1,131 @@ +package com.cheri.keller.service; + +import com.cheri.keller.common.config.PublicConstant; +import com.cheri.keller.common.response.ResultData; +import com.cheri.keller.entity.EmailLog; +import com.cheri.keller.entity.UserInfo; +import com.cheri.keller.mapper.UserMapper; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 12:43 + **/ +@Service +public class UserService { + + @Resource + private UserMapper userMapper; + + @Resource + private EmailService emailService; + + /** + * 发送注册验证码 + * 根据用户类型和邮箱判断用户是否已经注册,如果已注册,返回:该邮箱已注册 + * 否则,发送邮件验证码 + * @param type 用户类型 + * @param email 邮箱 + * @return + */ + public ResultData sendRegisterCode(int type,String email){ + + UserInfo userInfo = getByEmailAndType(type,email); + System.out.println("======================>>>检查" + userInfo ); + if(userInfo != null){ + return ResultData.error("该邮箱已被注册"); + } + return emailService.sendCode(PublicConstant.REGISTER_TYPE,email); + } + + + public ResultData register(UserInfo userInfo,String code){ + + EmailLog emailLog = new EmailLog(); + emailLog.setEmail(userInfo.getEmail()); + emailLog.setType(PublicConstant.REGISTER_TYPE); + emailLog.setCode(code); + if(emailService.checkCode(emailLog)){ + userInfo = insert(userInfo); + if(userInfo == null){ + return ResultData.error("注册失败"); + } + return ResultData.success(userInfo.getId()); + } + return ResultData.error("验证码错误或已过期,请重新获取"); + } + + + public ResultData getAll(){ + UserInfo userInfo = new UserInfo(); + List list = userMapper.baseSelectAll(userInfo); + if(list == null || list.size() < 1){ + return ResultData.error("没有数据"); + } + return ResultData.success(list); + } + + public ResultData getByEmail(String email){ + UserInfo userInfo = new UserInfo(); + userInfo.setEmail(email); + List list = userMapper.baseSelectByCondition(userInfo); + if(list != null && list.size() > 0){ + return ResultData.success(list.get(0)); + } + return ResultData.error("该邮箱未注册"); + } + /** + * 根据类型和邮箱查询用户 + * @param type + * @param email + * @return + */ +// private UserInfo getByEmailAndType(int type,String email){ +// UserInfo userInfo = new UserInfo(); +// userInfo.setEmail(email); +// userInfo.setType(type); +// userInfo.setBaseKyleUseAnd(true); +// List list = userMapper.baseSelectByCondition(userInfo); +// if(list != null && list.size() > 0){ +// return list.get(0); +// } +// return null; +// } + + + private UserInfo insert(UserInfo userInfo){ + UserInfo user = getByEmailAndType(userInfo.getType(),userInfo.getEmail()); + if(user != null){ + return null; + } + userMapper.baseInsertAndReturnKey(userInfo); + return userInfo; + } + + /** + * 根据类型和邮箱查询用户 + * @param type + * @param email + * @return + */ + public UserInfo getByEmailAndType(int type,String email){ + UserInfo userInfo = new UserInfo(); + //指定邮箱地址为第一个查询条件 + userInfo.setEmail(email); + //指定用户类型为第二个查询条件 + userInfo.setType(type); + //指定多条件间使用 AND 连接 + userInfo.setBaseKyleUseAnd(true); + //使用通用 Mapper 实现条件查询 + List list = userMapper.baseSelectByCondition(userInfo); + System.out.println(list); + if(list != null && list.size() > 0){ + return list.get(0); + } + return null; + } +} \ No newline at end of file -- Gitee From 1aaf736993bbfad763f239804b6238e514e7fdd2 Mon Sep 17 00:00:00 2001 From: AllenDu <15162678717@163.com> Date: Tue, 2 Jun 2020 11:25:04 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E6=90=AD=E5=BB=BA?= =?UTF-8?q?=E5=90=8E=E5=8F=B0=E6=9E=B6=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.properties | 24 ++++ src/main/resources/config/json.json | 129 ++++++++++++++++++ src/main/resources/dbinfo/user_info.sql | 31 +++++ .../resources/mappers/TestTableMapper.xml | 44 ++++++ .../cheri/keller/KellerApplicationTests.java | 13 ++ .../keller/mapper/TestTableMapperTest.java | 40 ++++++ .../cheri/keller/mapper/UserMapperTest.java | 55 ++++++++ 7 files changed, 336 insertions(+) create mode 100644 src/main/resources/application.properties create mode 100644 src/main/resources/config/json.json create mode 100644 src/main/resources/dbinfo/user_info.sql create mode 100644 src/main/resources/mappers/TestTableMapper.xml create mode 100644 src/test/java/com/cheri/keller/KellerApplicationTests.java create mode 100644 src/test/java/com/cheri/keller/mapper/TestTableMapperTest.java create mode 100644 src/test/java/com/cheri/keller/mapper/UserMapperTest.java diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..b51b943 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,24 @@ +## \u7AEF\u53E3 +server.port=8089 +## \u5E94\u7528\u540D +spring.application.name=KellerNotes + +#mysql\u9A71\u52A8\u7C7B +spring.datasource.driverClassName = com.mysql.cj.jdbc.Driver +#mysql\u8FDE\u63A5\u5730\u5740 +spring.datasource.url = jdbc:mysql://localhost:3307/kyle_notes?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT +#mysql\u7528\u6237\u540D +spring.datasource.username = root +#mysql\u5BC6\u7801 +spring.datasource.password = root + +mybatis.mapper-locations=classpath:mappers/*.xml +logging.level.com.cheri.keller.mapper=debug + +##=====\u4EE5\u4E0B\u4E3A\u81EA\u5B9A\u4E49\u914D\u7F6E======== +#\u90AE\u4EF6\u53D1\u9001\u670D\u52A1\u5668\u5730\u5740 +mail.server.host = smtp.qq.com +#\u7528\u6237\u540D +mail.server.user = +#\u5BC6\u7801 +mail.server.password = \ No newline at end of file diff --git a/src/main/resources/config/json.json b/src/main/resources/config/json.json new file mode 100644 index 0000000..7d2c474 --- /dev/null +++ b/src/main/resources/config/json.json @@ -0,0 +1,129 @@ + + +{ + "code":0, + "msg":"", + "count":1000, + "data":[ + { + "id":1, + "username":"user-0", + "sex":"女", + "city":"城市-0", + "sign":"签名-0", + "experience":255, + "logins":24, + "wealth":82830700, + "classify":"作家", + "score":57 + }, + { + "id":2, + "username":"user-0", + "sex":"女", + "city":"城市-0", + "sign":"签名-0", + "experience":255, + "logins":24, + "wealth":82830700, + "classify":"作家", + "score":57 + }, + { + "id":1, + "username":"user-0", + "sex":"女", + "city":"城市-0", + "sign":"签名-0", + "experience":255, + "logins":24, + "wealth":82830700, + "classify":"作家", + "score":57 + }, + { + "id":1, + "username":"user-0", + "sex":"女", + "city":"城市-0", + "sign":"签名-0", + "experience":255, + "logins":24, + "wealth":82830700, + "classify":"作家", + "score":57 + }, + { + "id":1, + "username":"user-0", + "sex":"女", + "city":"城市-0", + "sign":"签名-0", + "experience":255, + "logins":24, + "wealth":82830700, + "classify":"作家", + "score":57 + }, + { + "id":1, + "username":"user-0", + "sex":"女", + "city":"城市-0", + "sign":"签名-0", + "experience":255, + "logins":24, + "wealth":82830700, + "classify":"作家", + "score":57 + }, + { + "id":1, + "username":"user-0", + "sex":"女", + "city":"城市-0", + "sign":"签名-0", + "experience":255, + "logins":24, + "wealth":82830700, + "classify":"作家", + "score":57 + }, + { + "id":1, + "username":"user-0", + "sex":"女", + "city":"城市-0", + "sign":"签名-0", + "experience":255, + "logins":24, + "wealth":82830700, + "classify":"作家", + "score":57 + }, + { + "id":1, + "username":"user-0", + "sex":"女", + "city":"城市-0", + "sign":"签名-0", + "experience":255, + "logins":24, + "wealth":82830700, + "classify":"作家", + "score":57 + }, + { + "id":1, + "username":"user-0", + "sex":"女", + "city":"城市-0", + "sign":"签名-0", + "experience":255, + "logins":24, + "wealth":82830700, + "classify":"作家", + "score":57 + } + ] +} \ No newline at end of file diff --git a/src/main/resources/dbinfo/user_info.sql b/src/main/resources/dbinfo/user_info.sql new file mode 100644 index 0000000..9fa4100 --- /dev/null +++ b/src/main/resources/dbinfo/user_info.sql @@ -0,0 +1,31 @@ +create table user_info +( + id int auto_increment + primary key, + type int not null comment '用户类型', + email varchar(200) not null comment '邮箱', + password varchar(200) null comment '密码', + createTime datetime null, + status int null comment '用户账号状态', + isDelete int null, + updateTime datetime null, + updateUserId int null +) +comment '用户信息表' +; + +create index user_info_index_email + on user_info (email) +; + +create index user_info_index_status + on user_info (status) +; + +create index user_info_index_type + on user_info (type) +; + + +INSERT INTO kyle_notes.user_info (id, type, email, password, createTime, status, isDelete, updateTime, updateUserId) +VALUES (1, 0, 'guyexing@foxmail.com', '123456', '2019-11-25 19:34:25', null, null, null, null); \ No newline at end of file diff --git a/src/main/resources/mappers/TestTableMapper.xml b/src/main/resources/mappers/TestTableMapper.xml new file mode 100644 index 0000000..aded79a --- /dev/null +++ b/src/main/resources/mappers/TestTableMapper.xml @@ -0,0 +1,44 @@ + + + + + id, + name, + age, + state + + + + update test_table t + + + + when id= #{id} then #{newState} + + + + where t.state = #{state} + and t.id in + + #{id} + + + + delete from test_table t + where + t.id in + + #{id} + + + + diff --git a/src/test/java/com/cheri/keller/KellerApplicationTests.java b/src/test/java/com/cheri/keller/KellerApplicationTests.java new file mode 100644 index 0000000..bd9d65a --- /dev/null +++ b/src/test/java/com/cheri/keller/KellerApplicationTests.java @@ -0,0 +1,13 @@ +package com.cheri.keller; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class KellerApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/src/test/java/com/cheri/keller/mapper/TestTableMapperTest.java b/src/test/java/com/cheri/keller/mapper/TestTableMapperTest.java new file mode 100644 index 0000000..1567100 --- /dev/null +++ b/src/test/java/com/cheri/keller/mapper/TestTableMapperTest.java @@ -0,0 +1,40 @@ +package com.cheri.keller.mapper; + +import com.cheri.keller.entity.TestTable; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/23 17:46 + **/ +@SpringBootTest +class TestTableMapperTest { + + @Autowired + TestTableMapper mapper; + + @Test + void bacthSelect() { + List testTables = mapper.bacthSelect(Arrays.asList(1L,2L,3L,4L,4L,5L,6L)); + System.out.println(testTables); + } + + @Test + void batchUpdate() { + + mapper.batchUpdate("1",Arrays.asList(1L,2L,3L,4L,4L,5L,6L),"9"); + } + + public static void main(String[] args) { + String s = "1,2,3,3,5,"; + String[] S1 = s.split(","); + System.out.println(S1.length); + } +} \ No newline at end of file diff --git a/src/test/java/com/cheri/keller/mapper/UserMapperTest.java b/src/test/java/com/cheri/keller/mapper/UserMapperTest.java new file mode 100644 index 0000000..7a3cf25 --- /dev/null +++ b/src/test/java/com/cheri/keller/mapper/UserMapperTest.java @@ -0,0 +1,55 @@ +package com.cheri.keller.mapper; + +import com.cheri.keller.common.util.Console; +import com.cheri.keller.common.util.StringUtils; +import com.cheri.keller.entity.EmailLog; +import com.cheri.keller.entity.UserInfo; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import javax.annotation.Resource; +import java.util.List; + +/** + * @author Aaron Du + * @version V1.0 + * @date 2020/5/5 13:11 + **/ +@SpringBootTest +class UserMapperTest { + + @Resource + private UserMapper userMapper; + @Resource + private EmailMapper emailMapper; + + @Test + void contextLoads() { + } + + + @Test + public void initTestData() { + for (int i = 0; i < 10; i++) { + UserInfo userInfo = new UserInfo(); + userInfo.setType(1); + userInfo.setEmail(StringUtils.getAllCharString(10)); + userInfo.setPassword("123456"); + userMapper.baseInsertAndReturnKey(userInfo); + Console.println(userInfo.getId() + "", userInfo); + } + } + + @Test + public void getAll() { + List list = userMapper.baseSelectAll(new UserInfo()); + for (UserInfo userInfo : list) { + Console.println(userInfo.getId() + "", userInfo); + } + } + + @Test + public void createUserInfoTable() { + emailMapper.baseCreate(new EmailLog()); + } +} -- Gitee From 51501f0bb8f0384c8f14c1ba6306b77918087bd6 Mon Sep 17 00:00:00 2001 From: AllenDu <15162678717@163.com> Date: Tue, 2 Jun 2020 11:27:40 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E6=90=AD=E5=BB=BA?= =?UTF-8?q?=E5=90=8E=E5=8F=B0=E6=9E=B6=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 31 ++++++ mvnw | 310 +++++++++++++++++++++++++++++++++++++++++++++++++++++ mvnw.cmd | 182 +++++++++++++++++++++++++++++++ pom.xml | 73 +++++++++++++ 4 files changed, 596 insertions(+) create mode 100644 .gitignore create mode 100644 mvnw create mode 100644 mvnw.cmd create mode 100644 pom.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a2a3040 --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/** +!**/src/test/** + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ diff --git a/mvnw b/mvnw new file mode 100644 index 0000000..a16b543 --- /dev/null +++ b/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..c8d4337 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..bab71a6 --- /dev/null +++ b/pom.xml @@ -0,0 +1,73 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + + com.cheri + keller + 0.0.1-SNAPSHOT + keller + Demo project for Spring Boot + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.1.1 + + + + mysql + mysql-connector-java + runtime + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + javax.mail + mail + 1.4.7 + + + com.alibaba + fastjson + 1.2.51 + + + org.xmlunit + xmlunit-core + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + -- Gitee From d3a1b7ecc0ca8fcad6ab1914390af52671284ad9 Mon Sep 17 00:00:00 2001 From: AllenDu <15162678717@163.com> Date: Tue, 2 Jun 2020 11:34:35 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BD=A0=E8=87=AA?= =?UTF-8?q?=E5=B7=B1=E7=9A=84=E9=85=8D=E7=BD=AE=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/cheri/keller/common/config/PublicConstant.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/cheri/keller/common/config/PublicConstant.java b/src/main/java/com/cheri/keller/common/config/PublicConstant.java index a9075ba..23056e8 100644 --- a/src/main/java/com/cheri/keller/common/config/PublicConstant.java +++ b/src/main/java/com/cheri/keller/common/config/PublicConstant.java @@ -82,7 +82,7 @@ public class PublicConstant { /** * 邮件服务器登录密码 */ - public static String mailServerPassword = "iwrwaaoythiuieei"; + public static String mailServerPassword = ""; /** * 通用,不做访问权限设置 -- Gitee