From d0de0bf06f69c8584330e857ec1ecce34b244c9f Mon Sep 17 00:00:00 2001
From: Helius <wangdoubleone@gmail.com>
Date: Wed, 13 May 2020 16:11:46 +0800
Subject: [PATCH] init framework
---
src/main/java/com/xcong/excoin/common/system/dto/LoginDto.java | 21
src/main/java/com/xcong/excoin/configurations/security/TokenFilter.java | 97 ++
src/main/java/com/xcong/excoin/common/response/Result.java | 62 +
src/test/java/com/xcong/excoin/mapper/CarMapper.java | 46 +
src/main/java/com/xcong/excoin/common/annotations/UserAuth.java | 14
src/main/java/com/xcong/excoin/modules/member/entity/MemberEntity.java | 23
src/main/java/com/xcong/excoin/configurations/security/CustomAuthenticationEntryPoint.java | 26
src/main/java/com/xcong/excoin/common/contants/AppContants.java | 24
src/main/java/com/xcong/excoin/common/system/base/IBaseService.java | 10
src/main/java/com/xcong/excoin/modules/test/dao/TestUserDao.java | 18
src/test/java/com/xcong/excoin/mapper/MapStructMapper.java | 89 +
src/main/java/com/xcong/excoin/configurations/properties/ApplicationProperties.java | 18
src/main/java/com/xcong/excoin/configurations/MybatisPlusConfig.java | 23
src/main/java/com/xcong/excoin/utils/SpringContextHolder.java | 64 +
src/main/resources/i18n/messages.properties | 0
src/main/java/com/xcong/excoin/modules/test/dto/TestUserDto.java | 34
src/main/resources/logback-spring.xml | 147 +++
src/main/java/com/xcong/excoin/configurations/i18n/CustomLocaleResolver.java | 33
src/main/java/com/xcong/excoin/common/system/base/BaseEntity.java | 28
src/test/java/com/xcong/excoin/KssframeworkApplicationTests.java | 33
src/main/java/com/xcong/excoin/configurations/GlobalExceptionHandler.java | 70 +
src/main/java/com/xcong/excoin/configurations/properties/SecurityProperties.java | 17
README.md | 72
src/main/java/com/xcong/excoin/configurations/security/WebSecurityConfig.java | 72 +
src/main/java/com/xcong/excoin/common/response/ResultCode.java | 34
src/main/java/com/xcong/excoin/modules/test/vo/TestUserVo.java | 29
src/main/java/com/xcong/excoin/configurations/interceptor/MybatisInterceptor.java | 10
.gitignore | 36
src/main/java/com/xcong/excoin/configurations/WebMvcConfig.java | 40
src/main/java/com/xcong/excoin/configurations/security/TokenConfigurer.java | 21
src/main/java/com/xcong/excoin/common/system/bean/LoginUserBean.java | 61 +
src/main/resources/i18n/messages_en_US.properties | 2
pom.xml | 201 ++++
src/main/java/com/xcong/excoin/configurations/SwaggerConfig.java | 48 +
src/main/java/com/xcong/excoin/ExcoinApplication.java | 20
src/main/java/com/xcong/excoin/configurations/RedisConfig.java | 47 +
src/main/java/com/xcong/excoin/modules/test/service/TestUserService.java | 14
src/test/java/com/xcong/excoin/RSATest.java | 97 ++
src/main/java/com/xcong/excoin/utils/RedisUtils.java | 554 ++++++++++++
src/main/java/com/xcong/excoin/configurations/security/CustomAccessDeniedHandler.java | 25
src/main/java/com/xcong/excoin/modules/test/controller/TestUserController.java | 78 +
src/main/java/com/xcong/excoin/modules/test/mapper/TestUserEntityMapper.java | 20
src/test/java/com/xcong/excoin/mapper/Car.java | 18
src/main/java/com/xcong/excoin/configurations/i18n/LocaleResolverConfig.java | 19
src/main/java/com/xcong/excoin/modules/test/service/impl/TestUserServiceImpl.java | 28
src/test/java/com/xcong/excoin/mapper/CarDto.java | 16
src/main/java/com/xcong/excoin/common/system/service/UserDetailsServiceImpl.java | 38
src/main/java/com/xcong/excoin/modules/test/vo/TestVo.java | 20
src/main/resources/i18n/messages_zh_CN.properties | 2
src/test/java/com/xcong/excoin/mapper/CarEntity.java | 16
src/main/java/com/xcong/excoin/utils/MessageSourceUtils.java | 31
src/main/resources/mapper/TestUserDao.xml | 12
src/main/java/com/xcong/excoin/modules/test/entity/TestUserEntity.java | 22
src/main/java/com/xcong/excoin/common/system/controller/LoginController.java | 57 +
src/main/resources/application.yml | 80 +
55 files changed, 2,700 insertions(+), 37 deletions(-)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d472d37
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,36 @@
+HELP.md
+target/
+logs/
+!.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
+
+.mvn
+mvnw
+mvnw.cmd
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+
+### VS Code ###
+.vscode/
diff --git a/README.md b/README.md
index 98e24bf..48846f1 100644
--- a/README.md
+++ b/README.md
@@ -1,37 +1,35 @@
-# new_excoin
-
-#### 介绍
-excoin改版
-
-#### 软件架构
-软件架构说明
-
-
-#### 安装教程
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### 使用说明
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### 参与贡献
-
-1. Fork 本仓库
-2. 新建 Feat_xxx 分支
-3. 提交代码
-4. 新建 Pull Request
-
-
-#### 码云特技
-
-1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
-2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com)
-3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目
-4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目
-5. 码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
-6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
+# kss-framework
+
+#### 介绍
+{**以下是码云平台说明,您可以替换此简介**
+码云是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台
+无论是个人、团队、或是企业,都能够用码云实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
+
+#### 软件架构
+软件架构说明
+
+
+#### 安装教程
+
+1. xxxx
+2. xxxx
+3. xxxx
+
+#### 使用说明
+
+1. mapstruct
+https://mapstruct.org/documentation/stable/reference/html/
+
+2. mybatis-plus
+https://mybatis.plus/guide/#%E7%89%B9%E6%80%A7
+3. 参数校验
+https://mp.weixin.qq.com/s/yRuLmtUkARG3OziHB9dJPw
+
+#### 参与贡献
+
+1. Fork 本仓库
+2. 新建 Feat_xxx 分支
+3. 提交代码
+4. 新建 Pull Request
+
+
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..4431a55
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-parent</artifactId>
+ <version>2.2.6.RELEASE</version>
+ <relativePath/> <!-- lookup parent from repository -->
+ </parent>
+ <groupId>com.xcong</groupId>
+ <artifactId>excoin</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <name>excoin</name>
+ <description>Demo project for Spring Boot</description>
+
+ <properties>
+ <java.version>1.8</java.version>
+ <mysql-driver.version>8.0.17</mysql-driver.version>
+ <alibaba-druid.version>1.1.18</alibaba-druid.version>
+ <mybatis.version>2.0.1</mybatis.version>
+ <mybatis-plus.version>3.3.1.tmp</mybatis-plus.version>
+ <validation-api.version>2.0.1.Final</validation-api.version>
+ <hibernate-validator.version>6.1.0.Final</hibernate-validator.version>
+ <swagger.version>2.9.2</swagger.version>
+ <io-swagger.version>1.5.23</io-swagger.version>
+ <mapstruct.version>1.3.1.Final</mapstruct.version>
+ <hutool.version>5.3.1</hutool.version>
+ <fastjson.version>1.2.61</fastjson.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-actuator</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-security</artifactId>
+ </dependency>
+
+<!-- <dependency>-->
+<!-- <groupId>org.springframework.security</groupId>-->
+<!-- <artifactId>spring-security-test</artifactId>-->
+<!-- <scope>test</scope>-->
+<!-- </dependency>-->
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-data-redis</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-devtools</artifactId>
+ <scope>runtime</scope>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.junit.vintage</groupId>
+ <artifactId>junit-vintage-engine</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.mybatis.spring.boot</groupId>
+ <artifactId>mybatis-spring-boot-starter</artifactId>
+ <version>${mybatis.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.baomidou</groupId>
+ <artifactId>mybatis-plus-boot-starter</artifactId>
+ <version>${mybatis-plus.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>druid-spring-boot-starter</artifactId>
+ <version>${alibaba-druid.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>mysql</groupId>
+ <artifactId>mysql-connector-java</artifactId>
+ <version>${mysql-driver.version}</version>
+ </dependency>
+
+ <!-- 参数校验 start -->
+ <dependency>
+ <groupId>javax.validation</groupId>
+ <artifactId>validation-api</artifactId>
+ <version>${validation-api.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-validator</artifactId>
+ <version>${hibernate-validator.version}</version>
+ </dependency>
+ <!-- 参数校验 end -->
+
+ <!-- swagger2 start -->
+ <dependency>
+ <groupId>io.springfox</groupId>
+ <artifactId>springfox-swagger2</artifactId>
+ <version>${swagger.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.swagger</groupId>
+ <artifactId>swagger-annotations</artifactId>
+ <version>${io-swagger.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.swagger</groupId>
+ <artifactId>swagger-models</artifactId>
+ <version>${io-swagger.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.springfox</groupId>
+ <artifactId>springfox-swagger-ui</artifactId>
+ <version>${swagger.version}</version>
+ </dependency>
+ <!-- swagger2 end -->
+
+ <!-- bean映射转化 -->
+ <dependency>
+ <groupId>org.mapstruct</groupId>
+ <artifactId>mapstruct</artifactId>
+ <version>${mapstruct.version}</version>
+ </dependency>
+
+<!-- <dependency>-->
+<!-- <groupId>org.mapstruct</groupId>-->
+<!-- <artifactId>mapstruct-processor</artifactId>-->
+<!-- <version>${mapstruct.version}</version>-->
+<!-- </dependency>-->
+
+ <dependency>
+ <groupId>cn.hutool</groupId>
+ <artifactId>hutool-all</artifactId>
+ <version>${hutool.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>fastjson</artifactId>
+ <version>${fastjson.version}</version>
+ </dependency>
+
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.5.1</version>
+ <configuration>
+ <source>${java.version}</source>
+ <target>${java.version}</target>
+ <annotationProcessorPaths>
+ <path>
+ <groupId>org.mapstruct</groupId>
+ <artifactId>mapstruct-processor</artifactId>
+ <version>${mapstruct.version}</version>
+ </path>
+ <path>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ <version>${lombok.version}</version>
+ </path>
+ </annotationProcessorPaths>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/src/main/java/com/xcong/excoin/ExcoinApplication.java b/src/main/java/com/xcong/excoin/ExcoinApplication.java
new file mode 100644
index 0000000..0c94c3f
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/ExcoinApplication.java
@@ -0,0 +1,20 @@
+package com.xcong.excoin;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+/**
+ * @author helius
+ */
+@EnableSwagger2
+@SpringBootApplication
+@MapperScan("com.xcong.excoin.modules.*.dao")
+public class ExcoinApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ExcoinApplication.class, args);
+ }
+
+}
diff --git a/src/main/java/com/xcong/excoin/common/annotations/UserAuth.java b/src/main/java/com/xcong/excoin/common/annotations/UserAuth.java
new file mode 100644
index 0000000..cf1f12a
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/common/annotations/UserAuth.java
@@ -0,0 +1,14 @@
+package com.xcong.excoin.common.annotations;
+
+import java.lang.annotation.*;
+
+
+/**
+ * 自动注入当前登录用户
+ *
+ */
+@Target({ ElementType.PARAMETER, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface UserAuth {
+}
diff --git a/src/main/java/com/xcong/excoin/common/contants/AppContants.java b/src/main/java/com/xcong/excoin/common/contants/AppContants.java
new file mode 100644
index 0000000..4513ee1
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/common/contants/AppContants.java
@@ -0,0 +1,24 @@
+package com.xcong.excoin.common.contants;
+
+/**
+ * @author wzy
+ * @date 2020-05-12
+ **/
+public class AppContants {
+
+ /**
+ * app用户登陆redis前缀
+ */
+ public static final String APP_LOGIN_PREFIX = "app_";
+
+ /**
+ * token头部
+ */
+ public static final String TOKEN_HEADER = "Authorization";
+
+ /**
+ * token start with
+ */
+ public static final String TOKEN_START_WITH = "Bearer ";
+
+}
diff --git a/src/main/java/com/xcong/excoin/common/response/Result.java b/src/main/java/com/xcong/excoin/common/response/Result.java
new file mode 100644
index 0000000..d75ad2b
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/common/response/Result.java
@@ -0,0 +1,62 @@
+package com.xcong.excoin.common.response;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author wzy
+ * @date 2020-04-29 11:27
+ **/
+@Data
+@ApiModel(value = "返回基类", description = "基础返回类")
+public class Result implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final int SUCCESS = 0;
+
+ private static final int FAIL = -1;
+
+ private static final int LOGIN_FAIL = -2;
+
+ @ApiModelProperty(value = "状态码", example = "0")
+ private int code;
+
+ @ApiModelProperty(value = "提示消息")
+ private String msg;
+
+ @ApiModelProperty(value = "数据对象")
+ private Object data;
+
+ public static Result ok(String msg) {
+ Result result = new Result();
+ result.code = SUCCESS;
+ result.msg = msg;
+ return result;
+ }
+
+ public static Result ok(String msg, Object data) {
+ Result result = new Result();
+ result.code = SUCCESS;
+ result.msg = msg;
+ result.data = data;
+ return result;
+ }
+
+ public static Result fail(String msg) {
+ Result result = new Result();
+ result.code = FAIL;
+ result.msg = msg;
+ return result;
+ }
+
+ public static Result loginFail(String msg) {
+ Result result = new Result();
+ result.code = LOGIN_FAIL;
+ result.msg = msg;
+ return result;
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/common/response/ResultCode.java b/src/main/java/com/xcong/excoin/common/response/ResultCode.java
new file mode 100644
index 0000000..9a93765
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/common/response/ResultCode.java
@@ -0,0 +1,34 @@
+package com.xcong.excoin.common.response;
+
+/**
+ * 状态码
+ * @author wzy
+ */
+public enum ResultCode {
+ /**
+ * 成功
+ */
+ SUCCESS("1", "成功"),
+
+ /**
+ * 失败
+ */
+ FAIL("0", "失败");
+
+
+ private String code;
+ private String message;
+
+ ResultCode(String code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ public String code() {
+ return this.code;
+ }
+
+ public String message() {
+ return this.message;
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/common/system/base/BaseEntity.java b/src/main/java/com/xcong/excoin/common/system/base/BaseEntity.java
new file mode 100644
index 0000000..aa75f57
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/common/system/base/BaseEntity.java
@@ -0,0 +1,28 @@
+package com.xcong.excoin.common.system.base;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @author wzy
+ * @date 2020-04-24 14:58
+ **/
+@Data
+public class BaseEntity implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private Long id;
+
+ private String createBy;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Date createTime;
+
+ private String updateBy;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Date updateTime;
+}
diff --git a/src/main/java/com/xcong/excoin/common/system/base/IBaseService.java b/src/main/java/com/xcong/excoin/common/system/base/IBaseService.java
new file mode 100644
index 0000000..f11cae2
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/common/system/base/IBaseService.java
@@ -0,0 +1,10 @@
+package com.xcong.excoin.common.system.base;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * @author wzy
+ */
+public interface IBaseService<T> extends IService<T> {
+ T findById(Object id);
+}
diff --git a/src/main/java/com/xcong/excoin/common/system/bean/LoginUserBean.java b/src/main/java/com/xcong/excoin/common/system/bean/LoginUserBean.java
new file mode 100644
index 0000000..a2e10cf
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/common/system/bean/LoginUserBean.java
@@ -0,0 +1,61 @@
+package com.xcong.excoin.common.system.bean;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.xcong.excoin.modules.member.entity.MemberEntity;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.List;
+
+/**
+ * @author wzy
+ * @date 2020-05-12
+ **/
+@Getter
+@AllArgsConstructor
+public class LoginUserBean implements UserDetails {
+
+ private final MemberEntity memberEntity;
+
+ private final List<Long> roles;
+
+ private final List<GrantedAuthority> authorities;
+
+ @JsonIgnore
+ @Override
+ public String getPassword() {
+ return memberEntity.getPassword();
+ }
+
+ @JsonIgnore
+ @Override
+ public String getUsername() {
+ return memberEntity.getUsername();
+ }
+
+ @JsonIgnore
+ @Override
+ public boolean isAccountNonExpired() {
+ return true;
+ }
+
+ @JsonIgnore
+ @Override
+ public boolean isAccountNonLocked() {
+ return true;
+ }
+
+ @JsonIgnore
+ @Override
+ public boolean isCredentialsNonExpired() {
+ return true;
+ }
+
+ @JsonIgnore
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/common/system/controller/LoginController.java b/src/main/java/com/xcong/excoin/common/system/controller/LoginController.java
new file mode 100644
index 0000000..28feccb
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/common/system/controller/LoginController.java
@@ -0,0 +1,57 @@
+package com.xcong.excoin.common.system.controller;
+
+import cn.hutool.core.util.IdUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.xcong.excoin.common.contants.AppContants;
+import com.xcong.excoin.common.response.Result;
+import com.xcong.excoin.common.system.bean.LoginUserBean;
+import com.xcong.excoin.common.system.dto.LoginDto;
+import com.xcong.excoin.utils.RedisUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.core.Authentication;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @Author wzy
+ * @Date 2020/5/11
+ * @email wangdoubleone@gmail.com
+ * @Version V1.0
+ **/
+@Slf4j
+@RestController
+@RequestMapping(value = "/")
+public class LoginController {
+
+ @Value("${rsa.private_key}")
+ private String privateKey;
+
+ @Resource
+ private AuthenticationManagerBuilder authenticationManagerBuilder;
+
+ @Resource
+ private RedisUtils redisUtils;
+
+ @PostMapping("/login")
+ public Result login(@RequestBody @Validated LoginDto loginDto) {
+ UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword());
+ Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authToken);
+ String token = IdUtil.simpleUUID();
+ LoginUserBean loginUserBean = (LoginUserBean) authentication.getPrincipal();
+ redisUtils.set(AppContants.APP_LOGIN_PREFIX + token, JSONObject.toJSONString(loginUserBean), 300000);
+ Map<String, Object> authInfo = new HashMap<String, Object>(2){
+ {
+ put("token", token);
+ put("user", loginUserBean);
+ }
+ };
+ return Result.ok("success", authInfo);
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/common/system/dto/LoginDto.java b/src/main/java/com/xcong/excoin/common/system/dto/LoginDto.java
new file mode 100644
index 0000000..bc7ec00
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/common/system/dto/LoginDto.java
@@ -0,0 +1,21 @@
+package com.xcong.excoin.common.system.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author wzy
+ * @date 2020-05-12
+ **/
+@Data
+public class LoginDto {
+
+ @NotBlank(message = "用户名或密码错误")
+ private String username;
+
+ @NotBlank(message = "用户名或密码错误")
+ private String password;
+
+ private String code;
+}
diff --git a/src/main/java/com/xcong/excoin/common/system/service/UserDetailsServiceImpl.java b/src/main/java/com/xcong/excoin/common/system/service/UserDetailsServiceImpl.java
new file mode 100644
index 0000000..c33fc4b
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/common/system/service/UserDetailsServiceImpl.java
@@ -0,0 +1,38 @@
+package com.xcong.excoin.common.system.service;
+
+import com.xcong.excoin.common.system.bean.LoginUserBean;
+import com.xcong.excoin.modules.member.entity.MemberEntity;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @Author wzy
+ * @Date 2020/5/11
+ * @email wangdoubleone@gmail.com
+ * @Version V1.0
+ **/
+@Slf4j
+@Service("userDetailsService")
+public class UserDetailsServiceImpl implements UserDetailsService {
+
+ @Override
+ public LoginUserBean loadUserByUsername(String username) throws UsernameNotFoundException {
+ List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
+// GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_ADMIN");
+// grantedAuthorities.add(grantedAuthority);
+
+ MemberEntity memberEntity = new MemberEntity();
+ memberEntity.setId(1L);
+ memberEntity.setUsername("11111");
+ memberEntity.setPassword(new BCryptPasswordEncoder().encode("123456"));
+
+ return new LoginUserBean(memberEntity, null, null);
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/configurations/GlobalExceptionHandler.java b/src/main/java/com/xcong/excoin/configurations/GlobalExceptionHandler.java
new file mode 100644
index 0000000..97ed2d9
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/configurations/GlobalExceptionHandler.java
@@ -0,0 +1,70 @@
+package com.xcong.excoin.configurations;
+
+import com.xcong.excoin.common.response.Result;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.validation.FieldError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import javax.validation.ValidationException;
+
+/**
+ * @author wzy
+ * @date 2020-05-08 15:40
+ **/
+@RestControllerAdvice
+@Slf4j
+public class GlobalExceptionHandler {
+
+ /**
+ * 方法参数校验
+ *
+ * @param e
+ * @return
+ */
+ @ExceptionHandler(value = {MethodArgumentNotValidException.class})
+ public Result handleException(MethodArgumentNotValidException e) {
+ log.error(e.getMessage());
+ FieldError fieldError = e.getBindingResult().getFieldError();
+ if (fieldError != null) {
+ return Result.fail(fieldError.getDefaultMessage());
+ } else {
+ return Result.fail("参数校验失败");
+ }
+ }
+
+
+ @ExceptionHandler(value = {ValidationException.class})
+ public Result handleException(ValidationException e) {
+ log.error(e.getMessage(), e);
+ return null;
+ }
+
+ @ExceptionHandler(value = {DuplicateKeyException.class})
+ public Result handleException(DuplicateKeyException e) {
+ log.error(e.getMessage(), e);
+ return null;
+ }
+
+ @ExceptionHandler(value = {Exception.class})
+ public Result handleException(Exception e) {
+ log.error(e.getMessage(), e);
+ return Result.fail("系统异常");
+ }
+
+ /**
+ * spring security 账户密码验证异常
+ *
+ * @param e
+ * @return
+ */
+ @ExceptionHandler(value = { BadCredentialsException.class })
+ public Result handleException(BadCredentialsException e) {
+ log.error(e.getMessage(), e);
+ return Result.fail("用户名或密码错误");
+ }
+
+}
diff --git a/src/main/java/com/xcong/excoin/configurations/MybatisPlusConfig.java b/src/main/java/com/xcong/excoin/configurations/MybatisPlusConfig.java
new file mode 100644
index 0000000..6f48e95
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/configurations/MybatisPlusConfig.java
@@ -0,0 +1,23 @@
+package com.xcong.excoin.configurations;
+
+import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author wzy
+ * @date 2020-04-29 11:17
+ **/
+@Configuration
+public class MybatisPlusConfig {
+
+ /**
+ * 分页插件
+ *
+ * @return
+ */
+ @Bean
+ public PaginationInterceptor paginationInterceptor(){
+ return new PaginationInterceptor();
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/configurations/RedisConfig.java b/src/main/java/com/xcong/excoin/configurations/RedisConfig.java
new file mode 100644
index 0000000..a9a61fa
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/configurations/RedisConfig.java
@@ -0,0 +1,47 @@
+package com.xcong.excoin.configurations;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+/**
+ * @Author wzy
+ * @Date 2020/5/10
+ * @email wangdoubleone@gmail.com
+ * @Version V1.0
+ **/
+@EnableCaching
+@Configuration
+public class RedisConfig {
+
+ @Bean
+ @SuppressWarnings("all")
+ public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
+ RedisTemplate<String, Object> template = new RedisTemplate<>();
+ template.setConnectionFactory(factory);
+ Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
+ ObjectMapper om = new ObjectMapper();
+ om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+ om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+ jackson2JsonRedisSerializer.setObjectMapper(om);
+ StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
+ // key采用String的序列化方式
+ template.setKeySerializer(stringRedisSerializer);
+ // hash的key也采用String的序列化方式
+ template.setHashKeySerializer(stringRedisSerializer);
+ // value序列化方式采用jackson
+ template.setValueSerializer(jackson2JsonRedisSerializer);
+ // hash的value序列化方式采用jackson
+ template.setHashValueSerializer(jackson2JsonRedisSerializer);
+ template.afterPropertiesSet();
+ return template;
+ }
+
+}
diff --git a/src/main/java/com/xcong/excoin/configurations/SwaggerConfig.java b/src/main/java/com/xcong/excoin/configurations/SwaggerConfig.java
new file mode 100644
index 0000000..1d1c0aa
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/configurations/SwaggerConfig.java
@@ -0,0 +1,48 @@
+package com.xcong.excoin.configurations;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.ParameterBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.schema.ModelRef;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Parameter;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @Author wzy
+ * @Date 2020/5/11
+ * @email wangdoubleone@gmail.com
+ * @Version V1.0
+ **/
+@Configuration
+@EnableSwagger2
+public class SwaggerConfig {
+
+ @Bean
+ public Docket createRestApi(){
+ // 添加请求参数,我们这里把token作为请求头部参数传入后端
+ ParameterBuilder parameterBuilder = new ParameterBuilder();
+ List<Parameter> parameters = new ArrayList<Parameter>();
+ parameterBuilder.name("Authorization").description("令牌").modelRef(new ModelRef("string")).parameterType("header")
+ .required(false).build();
+ parameters.add(parameterBuilder.build());
+ return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.any())
+ .paths(PathSelectors.any()).build().globalOperationParameters(parameters);
+ }
+
+ private ApiInfo apiInfo(){
+ return new ApiInfoBuilder()
+ .title("ExCoin")
+ .description("This is a restful api document of ExCoin.")
+ .version("1.0")
+ .build();
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/configurations/WebMvcConfig.java b/src/main/java/com/xcong/excoin/configurations/WebMvcConfig.java
new file mode 100644
index 0000000..c31c084
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/configurations/WebMvcConfig.java
@@ -0,0 +1,40 @@
+package com.xcong.excoin.configurations;
+
+import com.xcong.excoin.utils.SpringContextHolder;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.SpringBootConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * @author wzy
+ * @date 2020-04-27 11:54
+ **/
+@SpringBootConfiguration
+@Slf4j
+public class WebMvcConfig implements WebMvcConfigurer {
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ }
+
+ /**
+ * 设置cors跨域支持
+ *
+ * @param registry
+ */
+ @Override
+ public void addCorsMappings(CorsRegistry registry) {
+ registry.addMapping("/**")
+ .allowedOrigins("*")
+ .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
+ .allowCredentials(true).maxAge(3600);
+ }
+
+ @Bean
+ public SpringContextHolder springContextHolder() {
+ return new SpringContextHolder();
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/configurations/i18n/CustomLocaleResolver.java b/src/main/java/com/xcong/excoin/configurations/i18n/CustomLocaleResolver.java
new file mode 100644
index 0000000..30324c9
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/configurations/i18n/CustomLocaleResolver.java
@@ -0,0 +1,33 @@
+package com.xcong.excoin.configurations.i18n;
+
+import cn.hutool.core.util.StrUtil;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.LocaleResolver;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Locale;
+
+/**
+ * @author wzy
+ * @date 2020-04-30 14:56
+ **/
+@Configuration
+public class CustomLocaleResolver implements LocaleResolver {
+
+ @Override
+ public Locale resolveLocale(HttpServletRequest httpServletRequest) {
+ String lang = httpServletRequest.getHeader("lang");
+ if(StrUtil.isBlank(lang)) {
+ return new Locale("zh", "CN");
+ } else {
+ String[] splite = lang.split("_");
+ return new Locale(splite[0], splite[1]);
+ }
+ }
+
+ @Override
+ public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
+
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/configurations/i18n/LocaleResolverConfig.java b/src/main/java/com/xcong/excoin/configurations/i18n/LocaleResolverConfig.java
new file mode 100644
index 0000000..df80884
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/configurations/i18n/LocaleResolverConfig.java
@@ -0,0 +1,19 @@
+package com.xcong.excoin.configurations.i18n;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.LocaleResolver;
+
+
+/**
+ * @author wzy
+ * @date 2020-04-27 11:55
+ **/
+@Configuration
+public class LocaleResolverConfig {
+
+ @Bean
+ public LocaleResolver localeResolver() {
+ return new CustomLocaleResolver();
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/configurations/interceptor/MybatisInterceptor.java b/src/main/java/com/xcong/excoin/configurations/interceptor/MybatisInterceptor.java
new file mode 100644
index 0000000..08aa177
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/configurations/interceptor/MybatisInterceptor.java
@@ -0,0 +1,10 @@
+package com.xcong.excoin.configurations.interceptor;
+
+/**
+ * mybatis拦截器,自动注入创建人、创建时间、修改人、修改时间
+ *
+ * @author wzy
+ * @date 2020-05-13
+ **/
+public class MybatisInterceptor {
+}
diff --git a/src/main/java/com/xcong/excoin/configurations/properties/ApplicationProperties.java b/src/main/java/com/xcong/excoin/configurations/properties/ApplicationProperties.java
new file mode 100644
index 0000000..cdacf9b
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/configurations/properties/ApplicationProperties.java
@@ -0,0 +1,18 @@
+package com.xcong.excoin.configurations.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 应用配置
+ *
+ * @author wzy
+ * @date 2020-05-12
+ **/
+@Data
+@Configuration
+@ConfigurationProperties(prefix = "app")
+public class ApplicationProperties {
+ private boolean debug;
+}
diff --git a/src/main/java/com/xcong/excoin/configurations/properties/SecurityProperties.java b/src/main/java/com/xcong/excoin/configurations/properties/SecurityProperties.java
new file mode 100644
index 0000000..0227458
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/configurations/properties/SecurityProperties.java
@@ -0,0 +1,17 @@
+package com.xcong.excoin.configurations.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author wzy
+ * @date 2020-05-13
+ **/
+@Data
+@Configuration
+@ConfigurationProperties(prefix = "rsa")
+public class SecurityProperties {
+
+ private String privateKey;
+}
diff --git a/src/main/java/com/xcong/excoin/configurations/security/CustomAccessDeniedHandler.java b/src/main/java/com/xcong/excoin/configurations/security/CustomAccessDeniedHandler.java
new file mode 100644
index 0000000..e59b286
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/configurations/security/CustomAccessDeniedHandler.java
@@ -0,0 +1,25 @@
+package com.xcong.excoin.configurations.security;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.xcong.excoin.common.response.Result;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.web.access.AccessDeniedHandler;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * @author wzy
+ * @date 2020-05-12
+ **/
+@Slf4j
+public class CustomAccessDeniedHandler implements AccessDeniedHandler {
+ @Override
+ public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
+ Result result = Result.loginFail("fail");
+ httpServletResponse.getWriter().write(new ObjectMapper().writeValueAsString(result));
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/configurations/security/CustomAuthenticationEntryPoint.java b/src/main/java/com/xcong/excoin/configurations/security/CustomAuthenticationEntryPoint.java
new file mode 100644
index 0000000..a28ffb8
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/configurations/security/CustomAuthenticationEntryPoint.java
@@ -0,0 +1,26 @@
+package com.xcong.excoin.configurations.security;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.xcong.excoin.common.response.Result;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * @author wzy
+ * @date 2020-05-12
+ **/
+public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
+
+ @Override
+ public void commence(HttpServletRequest httpServletRequest, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
+ Result result = Result.loginFail("fail");
+ response.setCharacterEncoding("UTF-8");
+ response.setContentType("application/json; charset=utf-8");
+ response.getWriter().write(new ObjectMapper().writeValueAsString(result));
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/configurations/security/TokenConfigurer.java b/src/main/java/com/xcong/excoin/configurations/security/TokenConfigurer.java
new file mode 100644
index 0000000..a998762
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/configurations/security/TokenConfigurer.java
@@ -0,0 +1,21 @@
+package com.xcong.excoin.configurations.security;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.web.DefaultSecurityFilterChain;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+
+/**
+ * @author wzy
+ * @date 2020-05-12
+ **/
+@RequiredArgsConstructor
+public class TokenConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
+
+ @Override
+ public void configure(HttpSecurity http) {
+ TokenFilter customFilter = new TokenFilter();
+ http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/configurations/security/TokenFilter.java b/src/main/java/com/xcong/excoin/configurations/security/TokenFilter.java
new file mode 100644
index 0000000..6ebf4d8
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/configurations/security/TokenFilter.java
@@ -0,0 +1,97 @@
+package com.xcong.excoin.configurations.security;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.asymmetric.KeyType;
+import cn.hutool.crypto.asymmetric.RSA;
+import com.alibaba.fastjson.JSONObject;
+import com.xcong.excoin.common.contants.AppContants;
+import com.xcong.excoin.common.system.bean.LoginUserBean;
+import com.xcong.excoin.configurations.properties.ApplicationProperties;
+import com.xcong.excoin.configurations.properties.SecurityProperties;
+import com.xcong.excoin.utils.RedisUtils;
+import com.xcong.excoin.utils.SpringContextHolder;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.util.StringUtils;
+import org.springframework.web.filter.GenericFilterBean;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * @author wzy
+ * @date 2020-05-12
+ **/
+@Slf4j
+public class TokenFilter extends GenericFilterBean {
+
+ private final ApplicationProperties applicationProperties = SpringContextHolder.getBean(ApplicationProperties.class);
+
+ private final SecurityProperties securityProperties = SpringContextHolder.getBean(SecurityProperties.class);
+
+ private final RedisUtils redisUtils = SpringContextHolder.getBean(RedisUtils.class);
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+ HttpServletRequest request = (HttpServletRequest) servletRequest;
+ String token = resolveToken(request);
+ if (StrUtil.isNotBlank(token)) {
+ String loginStr = (String) redisUtils.get(AppContants.APP_LOGIN_PREFIX + token);
+ if (StrUtil.isNotBlank(loginStr)) {
+ LoginUserBean loginUser = JSONObject.parseObject(loginStr, LoginUserBean.class);
+ Authentication authentication = new UsernamePasswordAuthenticationToken(loginUser.getMemberEntity(), token, new ArrayList<>());
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ redisUtils.expire(AppContants.APP_LOGIN_PREFIX + token, 300000);
+ } else {
+ SecurityContextHolder.clearContext();
+ }
+ } else {
+ SecurityContextHolder.clearContext();
+ }
+
+ filterChain.doFilter(servletRequest, servletResponse);
+ }
+
+ /**
+ * 解析前端传来的token,先去掉Bearer,在rsa解密得到token_time,返回token,并判断time与当前是否在5s内
+ *
+ * @param request
+ * @return
+ */
+ private String resolveToken(HttpServletRequest request) {
+ try {
+ String bearerToken = request.getHeader(AppContants.TOKEN_HEADER);
+ if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(AppContants.TOKEN_START_WITH)) {
+ // 去掉令牌前缀
+ String rsaToken = bearerToken.replace(AppContants.TOKEN_START_WITH, "");
+ RSA rsa = new RSA(securityProperties.getPrivateKey(), null);
+ String[] tokens = StrUtil.split(rsa.decryptStr(rsaToken, KeyType.PrivateKey), "_");
+
+ if (verifyTokenExpired(Long.parseLong(tokens[1]))) {
+ return tokens[0];
+ }
+ return null;
+ }
+ } catch (Exception e) {
+ log.error("#解析token异常#", e);
+ return null;
+ }
+ return null;
+ }
+
+ private Boolean verifyTokenExpired(Long time) {
+ boolean isDebug = applicationProperties.isDebug();
+ if (!isDebug) {
+ long currentTime = System.currentTimeMillis();
+ return currentTime - time <= 5000;
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/configurations/security/WebSecurityConfig.java b/src/main/java/com/xcong/excoin/configurations/security/WebSecurityConfig.java
new file mode 100644
index 0000000..868cb65
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/configurations/security/WebSecurityConfig.java
@@ -0,0 +1,72 @@
+package com.xcong.excoin.configurations.security;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.security.web.access.AccessDeniedHandler;
+
+import javax.annotation.Resource;
+
+/**
+ * @author wzy
+ * @date 2020-05-11
+ **/
+@Slf4j
+@Configuration
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(prePostEnabled = true)
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Resource
+ private UserDetailsService userDetailsService;
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.httpBasic().and().
+ cors().and().csrf().disable()
+ .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())
+ .and()
+ .authorizeRequests()
+ .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
+ .antMatchers("/login").permitAll()
+ .antMatchers("/swagger**/**").permitAll()
+ .antMatchers("/webjars/**").permitAll()
+ .antMatchers("/v2/**").permitAll()
+ .anyRequest().authenticated()
+ .and().apply(securityConfiguereAdapter());
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
+ }
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+
+ @Bean
+ public AccessDeniedHandler accessDeniedHandler() {
+ return new CustomAccessDeniedHandler();
+ }
+
+ @Bean
+ public AuthenticationEntryPoint authenticationEntryPoint() {
+ return new CustomAuthenticationEntryPoint();
+ }
+
+ public TokenConfigurer securityConfiguereAdapter() {
+ return new TokenConfigurer();
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/modules/member/entity/MemberEntity.java b/src/main/java/com/xcong/excoin/modules/member/entity/MemberEntity.java
new file mode 100644
index 0000000..11eff4b
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/member/entity/MemberEntity.java
@@ -0,0 +1,23 @@
+package com.xcong.excoin.modules.member.entity;
+
+import com.xcong.excoin.common.system.base.BaseEntity;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 会员信息实体
+ *
+ * @author wzy
+ * @date 2020-05-12
+ **/
+@Data
+public class MemberEntity extends BaseEntity implements Serializable {
+ private static final long serialVersionUID = -1L;
+
+ private Long id;
+
+ private String username;
+
+ private String password;
+}
diff --git a/src/main/java/com/xcong/excoin/modules/test/controller/TestUserController.java b/src/main/java/com/xcong/excoin/modules/test/controller/TestUserController.java
new file mode 100644
index 0000000..430f8e6
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/test/controller/TestUserController.java
@@ -0,0 +1,78 @@
+package com.xcong.excoin.modules.test.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.xcong.excoin.common.response.Result;
+import com.xcong.excoin.modules.test.dto.TestUserDto;
+import com.xcong.excoin.modules.test.entity.TestUserEntity;
+import com.xcong.excoin.modules.test.mapper.TestUserEntityMapper;
+import com.xcong.excoin.modules.test.service.TestUserService;
+import com.xcong.excoin.modules.test.vo.TestUserVo;
+import com.xcong.excoin.utils.MessageSourceUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+
+/**
+ * @author wzy
+ * @date 2020-04-24 15:25
+ **/
+@RestController
+@RequestMapping(value = "/test")
+@Slf4j
+@Api(value = "这是测试用类", tags = "这是测试用类")
+public class TestUserController {
+
+ @Resource
+ private TestUserService testUserService;
+
+ @ApiOperation(value = "测试用户分页请求", notes = "说明")
+ @ApiResponses({@ApiResponse(code = 0, message = "ok", response = TestUserVo.class)})
+ @PostMapping(value = "/findUserInPage")
+ public Result findUserInPage(@RequestParam(value = "pageSize", defaultValue = "10") int pageSize,
+ @RequestParam(value = "pageNum", defaultValue = "1") int pageNum,
+ @RequestBody @Valid TestUserDto testUserDto) {
+ log.info("--->{}",SecurityContextHolder.getContext().getAuthentication());
+ Page<TestUserEntity> page = new Page<>(pageNum, pageSize);
+ log.info(testUserDto.getName());
+ IPage<TestUserEntity> list = testUserService.page(page);
+ return Result.ok(MessageSourceUtils.getString("111"), list);
+ }
+
+
+ @ApiOperation(value = "添加测试用户", notes = "该接口用于添加测试用户")
+ @PostMapping(value = "/add")
+ public Result add(@RequestBody @Valid TestUserDto testUserDto) {
+ TestUserEntity testUserEntity = TestUserEntityMapper.INSTANCE.dtoToEntity(testUserDto);
+ boolean flag = testUserService.save(testUserEntity);
+ if (flag) {
+ return Result.ok("success");
+ }
+ return Result.fail("fail");
+ }
+
+ @ApiOperation(value = "根据ID删除用户", notes = "根据ID删除用户")
+ @GetMapping(value = "/del/{id}")
+ public Result del(@PathVariable(value = "id") Long id) {
+ boolean flag = testUserService.removeById(id);
+ if (flag) {
+ return Result.ok("success");
+ }
+ return Result.fail("fail");
+ }
+
+ @ApiOperation(value = "根据Id查询用户信息", notes = "根据Id查询用户信息")
+ @GetMapping(value = "/findById/{id}")
+ public Result findById(@PathVariable(value = "id") Long id) {
+ TestUserEntity testUserEntity = testUserService.getById(id);
+ TestUserVo testUserVo = TestUserEntityMapper.INSTANCE.entityToVo(testUserEntity);
+ return Result.ok("success", testUserVo);
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/modules/test/dao/TestUserDao.java b/src/main/java/com/xcong/excoin/modules/test/dao/TestUserDao.java
new file mode 100644
index 0000000..eba5557
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/test/dao/TestUserDao.java
@@ -0,0 +1,18 @@
+package com.xcong.excoin.modules.test.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.xcong.excoin.modules.test.entity.TestUserEntity;
+
+import java.util.List;
+
+/**
+ * @author helius
+ */
+public interface TestUserDao extends BaseMapper<TestUserEntity> {
+
+ public List<TestUserEntity> selectAll();
+
+ IPage<TestUserEntity> selectInPage(Page<TestUserEntity> page);
+}
diff --git a/src/main/java/com/xcong/excoin/modules/test/dto/TestUserDto.java b/src/main/java/com/xcong/excoin/modules/test/dto/TestUserDto.java
new file mode 100644
index 0000000..c4879a7
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/test/dto/TestUserDto.java
@@ -0,0 +1,34 @@
+package com.xcong.excoin.modules.test.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+
+/**
+ * @author wzy
+ * @date 2020-05-08 10:17
+ **/
+@Data
+@ApiModel(value = "testUser参数接收类", description = "findUserInPage 参数接收类")
+public class TestUserDto {
+
+// @NotNull(message = "id不能为空")
+ @ApiModelProperty(value = "这是名字啊", example = "张三")
+ private String name;
+
+// @Length(min = 6, max = 16, message = "账号长度需为6-16位")
+ @ApiModelProperty(value = "账号", example = "admin")
+ private String account;
+
+// @NotBlank(message = "密码不能为空")
+ @ApiModelProperty(value = "这是密码字段啊", example = "123456")
+ private String password;
+
+ @ApiModelProperty(value = "这是地址ID", example = "123")
+ private Long addressId;
+}
diff --git a/src/main/java/com/xcong/excoin/modules/test/entity/TestUserEntity.java b/src/main/java/com/xcong/excoin/modules/test/entity/TestUserEntity.java
new file mode 100644
index 0000000..d4373d5
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/test/entity/TestUserEntity.java
@@ -0,0 +1,22 @@
+package com.xcong.excoin.modules.test.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.xcong.excoin.common.system.base.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * @author wzy
+ * @date 2020-04-24 15:00
+ **/
+@EqualsAndHashCode(callSuper = true)
+@Data
+@TableName("test_user")
+public class TestUserEntity extends BaseEntity {
+
+ private String name;
+
+ private String account;
+
+ private String password;
+}
diff --git a/src/main/java/com/xcong/excoin/modules/test/mapper/TestUserEntityMapper.java b/src/main/java/com/xcong/excoin/modules/test/mapper/TestUserEntityMapper.java
new file mode 100644
index 0000000..d451e00
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/test/mapper/TestUserEntityMapper.java
@@ -0,0 +1,20 @@
+package com.xcong.excoin.modules.test.mapper;
+
+import com.xcong.excoin.modules.test.dto.TestUserDto;
+import com.xcong.excoin.modules.test.entity.TestUserEntity;
+import com.xcong.excoin.modules.test.vo.TestUserVo;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+/**
+ * @author wzy
+ * @date 2020-05-09 15:26
+ **/
+@Mapper
+public abstract class TestUserEntityMapper {
+ public static final TestUserEntityMapper INSTANCE = Mappers.getMapper(TestUserEntityMapper.class);
+
+ public abstract TestUserEntity dtoToEntity(TestUserDto testUserDto);
+
+ public abstract TestUserVo entityToVo(TestUserEntity testUserEntity);
+}
diff --git a/src/main/java/com/xcong/excoin/modules/test/service/TestUserService.java b/src/main/java/com/xcong/excoin/modules/test/service/TestUserService.java
new file mode 100644
index 0000000..448ffb3
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/test/service/TestUserService.java
@@ -0,0 +1,14 @@
+package com.xcong.excoin.modules.test.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.xcong.excoin.modules.test.entity.TestUserEntity;
+
+import java.util.List;
+
+/**
+ * @author helius
+ */
+public interface TestUserService extends IService<TestUserEntity> {
+
+ public List<TestUserEntity> findAll();
+}
diff --git a/src/main/java/com/xcong/excoin/modules/test/service/impl/TestUserServiceImpl.java b/src/main/java/com/xcong/excoin/modules/test/service/impl/TestUserServiceImpl.java
new file mode 100644
index 0000000..ab2b9f2
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/test/service/impl/TestUserServiceImpl.java
@@ -0,0 +1,28 @@
+package com.xcong.excoin.modules.test.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.xcong.excoin.modules.test.dao.TestUserDao;
+import com.xcong.excoin.modules.test.entity.TestUserEntity;
+import com.xcong.excoin.modules.test.service.TestUserService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * @author wzy
+ * @date 2020-04-24 15:23
+ **/
+@Service
+@Slf4j
+public class TestUserServiceImpl extends ServiceImpl<TestUserDao, TestUserEntity> implements TestUserService {
+
+ @Resource
+ private TestUserDao testUserDao;
+
+ @Override
+ public List<TestUserEntity> findAll() {
+ return testUserDao.selectAll();
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/modules/test/vo/TestUserVo.java b/src/main/java/com/xcong/excoin/modules/test/vo/TestUserVo.java
new file mode 100644
index 0000000..efd4073
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/test/vo/TestUserVo.java
@@ -0,0 +1,29 @@
+package com.xcong.excoin.modules.test.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author wzy
+ * @date 2020-05-07 17:24
+ **/
+@Data
+@ApiModel(value = "测试", description = "测试用户类")
+public class TestUserVo {
+
+ @ApiModelProperty(value = "主键ID")
+ private Long id;
+
+ @ApiModelProperty(value = "用户姓名")
+ private String userName;
+
+ @ApiModelProperty(value = "密码")
+ private String password;
+
+ @ApiModelProperty(value = "12345")
+ private List<TestVo> testVo;
+
+}
diff --git a/src/main/java/com/xcong/excoin/modules/test/vo/TestVo.java b/src/main/java/com/xcong/excoin/modules/test/vo/TestVo.java
new file mode 100644
index 0000000..ba344b3
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/test/vo/TestVo.java
@@ -0,0 +1,20 @@
+package com.xcong.excoin.modules.test.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author wzy
+ * @date 2020-05-08 10:09
+ **/
+@Data
+@ApiModel(value = "12345", description = "2222222")
+public class TestVo {
+
+ @ApiModelProperty(value = "名字")
+ private String name;
+
+ @ApiModelProperty(value = "密码")
+ private String pwd;
+}
diff --git a/src/main/java/com/xcong/excoin/utils/MessageSourceUtils.java b/src/main/java/com/xcong/excoin/utils/MessageSourceUtils.java
new file mode 100644
index 0000000..4663dd4
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/utils/MessageSourceUtils.java
@@ -0,0 +1,31 @@
+package com.xcong.excoin.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.MessageSource;
+import org.springframework.context.NoSuchMessageException;
+import org.springframework.context.i18n.LocaleContextHolder;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author wzy
+ * @date 2020-05-05 16:57
+ **/
+@Component
+@Slf4j
+public class MessageSourceUtils {
+
+ private static MessageSource messageSource;
+
+ public MessageSourceUtils(MessageSource messageSource) {
+ MessageSourceUtils.messageSource = messageSource;
+ }
+
+ public static String getString(String key) {
+ try {
+ return messageSource.getMessage(key, null, LocaleContextHolder.getLocale());
+ } catch (NoSuchMessageException e) {
+ log.error("#获取国际化异常#", e);
+ return key;
+ }
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/utils/RedisUtils.java b/src/main/java/com/xcong/excoin/utils/RedisUtils.java
new file mode 100644
index 0000000..936fab4
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/utils/RedisUtils.java
@@ -0,0 +1,554 @@
+package com.xcong.excoin.utils;
+
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @Author wzy
+ * @Date 2020/5/10
+ * @email wangdoubleone@gmail.com
+ * @Version V1.0
+ **/
+@Component
+public class RedisUtils {
+
+
+ @Resource
+ private RedisTemplate<String, Object> redisTemplate;
+
+
+ // =============================common============================
+ /**
+ * 指定缓存失效时间
+ * @param key 键
+ * @param time 时间(秒)
+ * @return
+ */
+ public boolean expire(String key, long time) {
+ try {
+ if (time > 0) {
+ redisTemplate.expire(key, time, TimeUnit.SECONDS);
+ }
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * 根据key 获取过期时间
+ * @param key 键 不能为null
+ * @return 时间(秒) 返回0代表为永久有效
+ */
+ public long getExpire(String key) {
+ return redisTemplate.getExpire(key, TimeUnit.SECONDS);
+ }
+
+ /**
+ * 判断key是否存在
+ * @param key 键
+ * @return true 存在 false不存在
+ */
+ public boolean hasKey(String key) {
+ try {
+ return redisTemplate.hasKey(key);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * 删除缓存
+ * @param key 可以传一个值 或多个
+ */
+ @SuppressWarnings("unchecked")
+ public void del(String... key) {
+ if (key != null && key.length > 0) {
+ if (key.length == 1) {
+ redisTemplate.delete(key[0]);
+ } else {
+ redisTemplate.delete(CollectionUtils.arrayToList(key));
+ }
+ }
+ }
+
+ // ============================String=============================
+ /**
+ * 普通缓存获取
+ * @param key 键
+ * @return 值
+ */
+ public Object get(String key) {
+ return key == null ? null : redisTemplate.opsForValue().get(key);
+ }
+
+
+ /**
+ * 普通缓存获取
+ * @param key 键
+ * @return 值
+ */
+ public String getString(String key) {
+ Object obj = key == null ? null : redisTemplate.opsForValue().get(key);
+ if(obj!=null){
+ return obj.toString();
+ }
+ return null;
+ }
+
+ /**
+ * 普通缓存放入
+ * @param key 键
+ * @param value 值
+ * @return true成功 false失败
+ */
+ public boolean set(String key, Object value) {
+ try {
+ redisTemplate.opsForValue().set(key, value);
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * 普通缓存放入并设置时间
+ * @param key 键
+ * @param value 值
+ * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
+ * @return true成功 false 失败
+ */
+ public boolean set(String key, Object value, long time) {
+ try {
+ if (time > 0) {
+ redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
+ } else {
+ set(key, value);
+ }
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ public boolean setNotExist(String key, Object value, long time) {
+ return redisTemplate.opsForValue().setIfAbsent(key, value, time, TimeUnit.SECONDS);
+ }
+
+ /**
+ * 递增
+ * @param key 键
+ * @param delta 要增加几(大于0)
+ * @return
+ */
+ public long incr(String key, long delta) {
+ if (delta < 0) {
+ throw new RuntimeException("递增因子必须大于0");
+ }
+ return redisTemplate.opsForValue().increment(key, delta);
+ }
+
+ /**
+ * 递减
+ * @param key 键
+ * @param delta 要减少几(小于0)
+ * @return
+ */
+ public long decr(String key, long delta) {
+ if (delta < 0) {
+ throw new RuntimeException("递减因子必须大于0");
+ }
+ return redisTemplate.opsForValue().increment(key, -delta);
+ }
+
+
+ // ================================Map=================================
+
+ /**
+ * HashGet
+ * @param key 键 不能为null
+ * @param item 项 不能为null
+ * @return 值
+ */
+ public Object hget(String key, String item) {
+ return redisTemplate.opsForHash().get(key, item);
+ }
+
+ /**
+ * 获取hashKey对应的所有键值
+ * @param key 键
+ * @return 对应的多个键值
+ */
+ public Map<Object, Object> hmget(String key) {
+ return redisTemplate.opsForHash().entries(key);
+ }
+ /**
+ * HashSet
+
+ * @param key 键
+ * @param map 对应多个键值
+ * @return true 成功 false 失败
+ */
+ public boolean hmset(String key, Map<String, Object> map) {
+ try {
+ redisTemplate.opsForHash().putAll(key, map);
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+ /**
+ * HashSet 并设置时间
+ * @param key 键
+ * @param map 应多个键值
+ * @param time 时间(秒)
+ * @return true成功 false失败
+ */
+ public boolean hmset(String key, Map<String, Object> map, long time) {
+ try {
+ redisTemplate.opsForHash().putAll(key, map);
+ if (time > 0) {
+ expire(key, time);
+ }
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+
+ /**
+ * 向一张hash表中放入数据,如果不存在将创建
+ * @param key 键
+ * @param item 项
+ * @param value 值
+ * @return true 成功 false失败
+ */
+ public boolean hset(String key, String item, Object value) {
+ try {
+ redisTemplate.opsForHash().put(key, item, value);
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+ /**
+ * 向一张hash表中放入数据,如果不存在将创建
+ * @param key 键
+ * @param item 项
+ * @param value 值
+ * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
+ * @return true 成功 false失败
+ */
+ public boolean hset(String key, String item, Object value, long time) {
+ try {
+ redisTemplate.opsForHash().put(key, item, value);
+ if (time > 0) {
+ expire(key, time);
+ }
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+ /**
+ * 删除hash表中的值
+ * @param key 键 不能为null
+ * @param item 项 可以使多个 不能为null
+ */
+ public void hdel(String key, Object... item) {
+ redisTemplate.opsForHash().delete(key, item);
+ }
+ /**
+ * 判断hash表中是否有该项的值
+ * @param key 键 不能为null
+ * @param item 项 不能为null
+ * @return true 存在 false不存在
+ */
+ public boolean hHasKey(String key, String item) {
+ return redisTemplate.opsForHash().hasKey(key, item);
+ }
+
+ /**
+ * hash递增 如果不存在,就会创建一个 并把新增后的值返回
+ * @param key 键
+ * @param item 项
+ * @param by 要增加几(大于0)
+ * @return
+ */
+ public double hincr(String key, String item, double by) {
+ return redisTemplate.opsForHash().increment(key, item, by);
+ }
+
+ /**
+ * hash递减
+ * @param key 键
+ * @param item 项
+ * @param by 要减少记(小于0)
+ * @return
+ */
+ public double hdecr(String key, String item, double by) {
+ return redisTemplate.opsForHash().increment(key, item, -by);
+ }
+ // ============================set=============================
+ /**
+ * 根据key获取Set中的所有值
+ * @param key 键
+ * @return
+ */
+ public Set<Object> sGet(String key) {
+ try {
+ return redisTemplate.opsForSet().members(key);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+ /**
+ * 根据value从一个set中查询,是否存在
+ * @param key 键
+ * @param value 值
+ * @return true 存在 false不存在
+ */
+ public boolean sHasKey(String key, Object value) {
+ try {
+ return redisTemplate.opsForSet().isMember(key, value);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+ /**
+ * 将数据放入set缓存
+ * @param key 键
+ * @param values 值 可以是多个
+ * @return 成功个数
+ */
+ public long sSet(String key, Object... values) {
+ try {
+ return redisTemplate.opsForSet().add(key, values);
+ } catch (Exception e) {
+ e.printStackTrace();
+
+ return 0;
+ }
+ }
+ /**
+ 336
+ * 将set数据放入缓存
+ 337
+ * @param key 键
+ * @param time 时间(秒)
+ * @param values 值 可以是多个
+ * @return 成功个数
+ */
+ public long sSetAndTime(String key, long time, Object... values) {
+ try {
+ Long count = redisTemplate.opsForSet().add(key, values);
+ if (time > 0)
+ expire(key, time);
+ return count;
+
+ }catch(Exception e) {
+ e.printStackTrace();
+ return 0;
+ }
+ }
+ /**
+ * 获取set缓存的长度
+ * @param key 键
+ * @return
+ */
+
+ public long sGetSetSize(String key) {
+ try {
+ return redisTemplate.opsForSet().size(key);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ return 0;
+ }
+
+ }
+
+ /**
+ * 移除值为value的
+ * @param key 键
+ * @param values 值 可以是多个
+ * @return 移除的个数
+
+ */
+ public long setRemove(String key, Object... values) {
+ try {
+ Long count = redisTemplate.opsForSet().remove(key, values);
+ return count;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ return 0;
+ }
+ }
+ // ===============================list=================================
+ /**
+ * 获取list缓存的内容 * @param key 键
+ * @param start 开始
+ * @param end 结束 0 到 -1代表所有值
+ * @return
+ */
+ public List<Object> lGet(String key, long start, long end) {
+ try {
+ return redisTemplate.opsForList().range(key, start, end);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+
+ }
+
+ /**
+ * 获取list缓存的长度
+ * @param key 键
+
+ * @return
+ */
+ public long lGetListSize(String key) { try {
+ return redisTemplate.opsForList().size(key);
+ } catch (Exception e) {
+
+ e.printStackTrace();
+ return 0;
+ }
+ } /**
+ * 通过索引 获取list中的值
+ * @param key 键
+ * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
+ * @return
+ */
+ public Object lGetIndex(String key, long index) {
+
+ try {
+ return redisTemplate.opsForList().index(key, index);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * 将list放入缓存
+ * @param key 键
+ * @param value 值
+ * @return
+ */
+ public boolean lSet(String key, Object value) {
+ try {
+ redisTemplate.opsForList().rightPush(key, value);
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * 将list放入缓存
+ * @param key 键
+ * @param value 值
+ * @param time 时间(秒)
+ * @return
+ */
+ public boolean lSet(String key, Object value, long time) {
+ try {
+ redisTemplate.opsForList().rightPush(key, value);
+ if (time > 0)
+ expire(key, time);
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+ /**
+ * 将list放入缓存
+ * @param key 键
+ * @param value 值
+ * @return
+ */
+ public boolean lSet(String key, List<Object> value) {
+ try {
+ redisTemplate.opsForList().rightPushAll(key, value);
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+ /**
+ * 将list放入缓存
+ *
+ * @param key 键
+ * @param value 值
+ * @param time 时间(秒)
+ * @return
+ */
+ public boolean lSet(String key, List<Object> value, long time) {
+ try {
+ redisTemplate.opsForList().rightPushAll(key, value);
+ if (time > 0)
+ expire(key, time);
+ return true;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+ /**
+ * 根据索引修改list中的某条数据
+ * @param key 键
+ * @param index 索引
+ * @param value 值
+ * @return
+ */
+ public boolean lUpdateIndex(String key, long index, Object value) {
+ try {
+ redisTemplate.opsForList().set(key, index, value);
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+
+ /**
+ * 移除N个值为value
+ * @param key 键
+ * @param count 移除多少个
+ * @param value 值
+ * @return 移除的个数
+ */
+ public long lRemove(String key, long count, Object value) {
+ try {
+ return redisTemplate.opsForList().remove(key, count, value);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return 0;
+ }
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/utils/SpringContextHolder.java b/src/main/java/com/xcong/excoin/utils/SpringContextHolder.java
new file mode 100644
index 0000000..7dbf951
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/utils/SpringContextHolder.java
@@ -0,0 +1,64 @@
+package com.xcong.excoin.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+/**
+ * @Author wzy
+ * @Date 2020/5/11
+ * @email wangdoubleone@gmail.com
+ * @Version V1.0
+ **/
+@Slf4j
+public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
+
+ private static ApplicationContext applicationContext = null;
+
+ /**
+ * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T getBean(String name) {
+ assertContextInjected();
+ return (T) applicationContext.getBean(name);
+ }
+
+ /**
+ * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
+ */
+ public static <T> T getBean(Class<T> requiredType) {
+ assertContextInjected();
+ return applicationContext.getBean(requiredType);
+ }
+
+ private static void assertContextInjected() {
+ if (applicationContext == null) {
+ throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" +
+ ".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder.");
+ }
+ }
+
+ /**
+ * 检查ApplicationContext不为空.
+ */
+ private static void clearHolder() {
+ log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
+ applicationContext = null;
+ }
+
+ @Override
+ public void destroy() throws Exception {
+ SpringContextHolder.clearHolder();
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ if (SpringContextHolder.applicationContext != null) {
+ log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);
+ }
+ SpringContextHolder.applicationContext = applicationContext;
+ }
+}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
new file mode 100644
index 0000000..c6e5be1
--- /dev/null
+++ b/src/main/resources/application.yml
@@ -0,0 +1,80 @@
+server:
+ port: 8888
+ servlet:
+ context-path: /
+
+spring:
+ datasource:
+ url: jdbc:mysql://120.27.238.55:3306/kss_framework?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2b8
+ username: ct_test
+ password: 123456
+ driver-class-name: com.mysql.jdbc.Driver
+ type: com.alibaba.druid.pool.DruidDataSource
+ druid:
+ initial-size: ${spring_datasource_druid_initial_size:10}
+ max-active: ${spring_datasource_druid_max_active:20}
+ min-idle: ${spring_datasource_druid_min_idle:3}
+ #配置获取连接等待超时的时间
+ max-wait: 60000
+ pool-prepared-statements: true
+ max-pool-prepared-statement-per-connection-size: 20
+ validation-query: SELECT 'x'
+ test-on-borrow: true
+ test-on-return: true
+ test-while-idle: true
+ #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+ time-between-eviction-runs-millis: 60000
+ #配置一个连接在池中最小生存的时间,单位是毫秒
+ min-evictable-idle-time-millis: 300000
+ #spring.datasource.druid.max-evguide.ftlictable-idle-time-millis=
+ filters: stat,wall
+ stat-view-servlet:
+ # 默认true 内置监控页面首页/druid/index.html
+ enabled: true
+ url-pattern: /druid/*
+ # 允许清空统计数据
+ reset-enable: true
+ login-username: root
+ login-password: 123456
+ # IP白名单 多个逗号分隔
+ allow: ${spring_datasource_stat_view_servlet_allow:}
+ # IP黑名单
+ deny: ${spring_datasource_stat_view_servlet_deny:}
+ ## 国际化配置
+ messages:
+ basename: i18n/messages
+ ## redis配置
+ redis:
+ ## Redis数据库索引(默认为0)
+ database: 1
+ ## Redis服务器地址
+ host: 121.40.158.8
+ ## Redis服务器连接端口
+ port: 6379
+ ## Redis服务器连接密码(默认为空)
+ password: biyi123
+ jedis:
+ pool:
+ ## 连接池最大连接数(使用负值表示没有限制)
+ #spring.redis.pool.max-active=8
+ max-active: 300
+ ## 连接池最大阻塞等待时间(使用负值表示没有限制)
+ #spring.redis.pool.max-wait=-1
+ max-wait: -1
+ ## 连接池中的最大空闲连接
+ #spring.redis.pool.max-idle=8
+ max-idle: 100
+ ## 连接池中的最小空闲连接
+ #spring.redis.pool.min-idle=0
+ min-idle: 8
+ ## 连接超时时间(毫秒)
+ timeout: 30000
+mybatis-plus:
+ mapper-locations: classpath:mapper/*.xml
+
+
+app:
+ debug: true
+
+rsa:
+ private_key: MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIJ/xQVkrngCIrg9G7u0135nypnvuj9BcKeTbkNGbKBWk4S7mYY1IC9+daYqnakRXZGWN5erdGJ3/4tCSidp5swl5cpIXTLEv9WDJ5PwlpDmA1s6t192Vz6YWRcnLPIm3xiS8CkR09E1JTYQ0GfuaBF8PQFg8zi9nr+u/517fwUnAgMBAAECgYBhPt9NvpI4wbanvnndLczr2GJkxfzvSE+vwLCJF4C5FusFHVsxZINggQcg1V75bwRgCiXRMyYefreCSdrCditS43PzTOmE4RRrpxLlm8oubJc0C98LQ2qlN9AsUqL5IHpVGgbHDyWAwjc1GBID6nwXKpxq1/VodFqhahG9D5EZsQJBALnkb+5VTxQbiyQI4Uc9NIvAyVcNY1OisbvY6tvNgdBbJkADgAb78M1HWxxYjUqsvzggNHc7cWqWBHMgpnJaqm8CQQCztze4D7uAk7OC9MJHY5eE980J8Kk+GEZKxz4LahzU6V6dcb9GFac3wEtgilj/tOAn9y0/Q8sm9vvCIbMDzgzJAkEAqRYcqhF26LdVDOX25DHMBgLKISDQZFbsjA13M4/usHL4i+mjHrc0BcUOHu59NpuDI65HitzLAUSLr5zXSdUmiQJAW77wOg4GCejdXsB3IhzMsHwU97sdm26nC+vVV9xvJZ6Rx8zW+f9543NOx9U5BCmhuaVtOvvwDU9PTVcI3atmSQJAXAIJ5gGdtXx0DXiX4VvzNFHqgaqHMGvXyjNVkU2FYQbSAd2A6app4uRO+BkZu9dSjh14m+oXMnV2HzAN2rRnjA==
diff --git a/src/main/resources/i18n/messages.properties b/src/main/resources/i18n/messages.properties
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/main/resources/i18n/messages.properties
diff --git a/src/main/resources/i18n/messages_en_US.properties b/src/main/resources/i18n/messages_en_US.properties
new file mode 100644
index 0000000..cb5b84d
--- /dev/null
+++ b/src/main/resources/i18n/messages_en_US.properties
@@ -0,0 +1,2 @@
+test=test
+111=this is test msg
\ No newline at end of file
diff --git a/src/main/resources/i18n/messages_zh_CN.properties b/src/main/resources/i18n/messages_zh_CN.properties
new file mode 100644
index 0000000..81795a5
--- /dev/null
+++ b/src/main/resources/i18n/messages_zh_CN.properties
@@ -0,0 +1,2 @@
+test=测试
+111=这是测试消息
\ No newline at end of file
diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml
new file mode 100644
index 0000000..efc56f9
--- /dev/null
+++ b/src/main/resources/logback-spring.xml
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+ <contextName>logback</contextName>
+ <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
+ <property name="log.path" value="logs" />
+
+ <!-- 彩色日志 -->
+ <!-- 彩色日志依赖的渲染类 -->
+ <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
+ <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
+ <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
+ <!-- 彩色日志格式 -->
+ <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
+
+ <!--输出到控制台-->
+ <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+ <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
+ <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+ <level>info</level>
+ </filter>
+ <encoder>
+ <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
+ <!-- 设置字符集 -->
+ <charset>UTF-8</charset>
+ </encoder>
+ </appender>
+
+ <!-- 时间滚动输出 level为 DEBUG 日志 -->
+ <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <!-- 正在记录的日志文件的路径及文件名 -->
+ <file>${log.path}/log_debug.log</file>
+ <!--日志文件输出格式-->
+ <encoder>
+ <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] %logger{50} - %msg%n</pattern>
+ <charset>UTF-8</charset> <!-- 设置字符集 -->
+ </encoder>
+ <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <!-- 日志归档 -->
+ <fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+ <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+ <maxFileSize>100MB</maxFileSize>
+ </timeBasedFileNamingAndTriggeringPolicy>
+ <!--日志文件保留天数-->
+ <maxHistory>15</maxHistory>
+ </rollingPolicy>
+ <!-- 此日志文件只记录debug级别的 -->
+ <filter class="ch.qos.logback.classic.filter.LevelFilter">
+ <level>debug</level>
+ <onMatch>ACCEPT</onMatch>
+ <onMismatch>DENY</onMismatch>
+ </filter>
+ </appender>
+
+ <!-- 时间滚动输出 level为 INFO 日志 -->
+ <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <!-- 正在记录的日志文件的路径及文件名 -->
+ <file>${log.path}/log_info.log</file>
+ <!--日志文件输出格式-->
+ <encoder>
+ <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] %logger{50} - %msg%n</pattern>
+ <charset>UTF-8</charset>
+ </encoder>
+ <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <!-- 每天日志归档路径以及格式 -->
+ <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+ <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+ <maxFileSize>100MB</maxFileSize>
+ </timeBasedFileNamingAndTriggeringPolicy>
+ <!--日志文件保留天数-->
+ <maxHistory>15</maxHistory>
+ </rollingPolicy>
+ <!-- 此日志文件只记录info级别的 -->
+ <filter class="ch.qos.logback.classic.filter.LevelFilter">
+ <level>info</level>
+ <onMatch>ACCEPT</onMatch>
+ <onMismatch>DENY</onMismatch>
+ </filter>
+ </appender>
+
+ <!-- 时间滚动输出 level为 WARN 日志 -->
+ <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <!-- 正在记录的日志文件的路径及文件名 -->
+ <file>${log.path}/log_warn.log</file>
+ <!--日志文件输出格式-->
+ <encoder>
+ <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] %logger{50} - %msg%n</pattern>
+ <charset>UTF-8</charset> <!-- 此处设置字符集 -->
+ </encoder>
+ <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+ <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+ <maxFileSize>100MB</maxFileSize>
+ </timeBasedFileNamingAndTriggeringPolicy>
+ <!--日志文件保留天数-->
+ <maxHistory>15</maxHistory>
+ </rollingPolicy>
+ <!-- 此日志文件只记录warn级别的 -->
+ <filter class="ch.qos.logback.classic.filter.LevelFilter">
+ <level>warn</level>
+ <onMatch>ACCEPT</onMatch>
+ <onMismatch>DENY</onMismatch>
+ </filter>
+ </appender>
+
+
+ <!-- 时间滚动输出 level为 ERROR 日志 -->
+ <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <!-- 正在记录的日志文件的路径及文件名 -->
+ <file>${log.path}/log_error.log</file>
+ <!--日志文件输出格式-->
+ <encoder>
+ <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] %logger{50} - %msg%n</pattern>
+ <charset>UTF-8</charset> <!-- 此处设置字符集 -->
+ </encoder>
+ <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+ <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+ <maxFileSize>100MB</maxFileSize>
+ </timeBasedFileNamingAndTriggeringPolicy>
+ <!--日志文件保留天数-->
+ <maxHistory>15</maxHistory>
+ </rollingPolicy>
+ <!-- 此日志文件只记录ERROR级别的 -->
+ <filter class="ch.qos.logback.classic.filter.LevelFilter">
+ <level>ERROR</level>
+ <onMatch>ACCEPT</onMatch>
+ <onMismatch>DENY</onMismatch>
+ </filter>
+ </appender>
+
+ <!--开发环境:打印控制台-->
+ <springProfile name="dev">
+ <logger name="com.xcong.excoin" level="debug"/>
+ </springProfile>
+
+ <root level="info">
+ <appender-ref ref="CONSOLE" />
+ <appender-ref ref="DEBUG_FILE" />
+ <appender-ref ref="INFO_FILE" />
+ <appender-ref ref="WARN_FILE" />
+ <appender-ref ref="ERROR_FILE" />
+ </root>
+</configuration>
\ No newline at end of file
diff --git a/src/main/resources/mapper/TestUserDao.xml b/src/main/resources/mapper/TestUserDao.xml
new file mode 100644
index 0000000..a52f9b5
--- /dev/null
+++ b/src/main/resources/mapper/TestUserDao.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.xcong.excoin.modules.test.dao.TestUserDao">
+
+ <select id="selectAll" resultType="com.xcong.excoin.modules.test.entity.TestUserEntity">
+ select * from test_user
+ </select>
+
+ <select id="selectInPage" resultType="com.xcong.excoin.modules.test.entity.TestUserEntity">
+ select * from test_user
+ </select>
+</mapper>
\ No newline at end of file
diff --git a/src/test/java/com/xcong/excoin/KssframeworkApplicationTests.java b/src/test/java/com/xcong/excoin/KssframeworkApplicationTests.java
new file mode 100644
index 0000000..1ce2e4d
--- /dev/null
+++ b/src/test/java/com/xcong/excoin/KssframeworkApplicationTests.java
@@ -0,0 +1,33 @@
+package com.xcong.excoin;
+
+import com.xcong.excoin.modules.test.dao.TestUserDao;
+import com.xcong.excoin.modules.test.entity.TestUserEntity;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import javax.annotation.Resource;
+import java.util.Date;
+
+@SpringBootTest
+class KssframeworkApplicationTests {
+
+ @Resource
+ private TestUserDao testUserDao;
+
+ @Test
+ public void testUserInsert() {
+ for(int i = 0; i < 20; i++) {
+ TestUserEntity testUser = new TestUserEntity();
+ testUser.setCreateBy("123");
+ testUser.setCreateTime(new Date());
+ testUser.setUpdateBy("123");
+ testUser.setUpdateTime(new Date());
+ testUser.setAccount("12345" + i);
+ testUser.setName("hehe" + i);
+ testUser.setPassword("33333");
+ testUserDao.insert(testUser);
+ }
+
+ }
+
+}
diff --git a/src/test/java/com/xcong/excoin/RSATest.java b/src/test/java/com/xcong/excoin/RSATest.java
new file mode 100644
index 0000000..02dd114
--- /dev/null
+++ b/src/test/java/com/xcong/excoin/RSATest.java
@@ -0,0 +1,97 @@
+package com.xcong.excoin;
+
+import cn.hutool.core.codec.Base64;
+import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.core.util.HexUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.SecureUtil;
+import cn.hutool.crypto.asymmetric.KeyType;
+import cn.hutool.crypto.asymmetric.RSA;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.security.KeyPair;
+
+/**
+ * @author wzy
+ * @date 2020-05-12
+ **/
+@Slf4j
+@SpringBootTest
+public class RSATest {
+
+ private String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCFU26floADA4PSEmE99u1YD30P3LAP6c7XYRASejCte+uOUfveSGHip2cgwpElu4y/r8PKAbclvs8j3y0g4MhjQbRjsiK8O2PKPaTWW+bHWPapPAhTuRHDMVFV6sajZ4dcg7mZ9+zPqG2RkvXi993v7kcTYq8hpE20/+Do7gwFowIDAQAB";
+
+ private String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIVTbp+WgAMDg9ISYT327VgPfQ/csA/pztdhEBJ6MK17645R+95IYeKnZyDCkSW7jL+vw8oBtyW+zyPfLSDgyGNBtGOyIrw7Y8o9pNZb5sdY9qk8CFO5EcMxUVXqxqNnh1yDuZn37M+obZGS9eL33e/uRxNiryGkTbT/4OjuDAWjAgMBAAECgYAUw8TD6C2xyndaXXB1tSKMB4WD1ew53kFPvBdDuXIhYt5yAQTIPt+37DicmpD+nnIyXI6SxKegolIilRyzNS8gQqXyqnj+UrIX8hJp0bxwEx2epcKAcwn84XFEXFGMFe2POUpFgNkxbKcWH9UNAALsO20ipP3UB6dj832HjGSagQJBAPKeVrXTnEf0Ien2A4jXAX4WZp0x7pg9ccGRo8RKFUrY0xVGstKEpCTTdDZ596/L8EN83dP2reHl2sCJpzC5NsECQQCMre6tadDg/cZE7SbxGhxlIRM1SyqGnxk+owiQbiYKLlhNR5GEZUdh+xubjtWPWhmXiy3nmFki9NESIhWf0xljAkAD/LAmGs0lrZBlHOLf+9CNdubGzIxEOjZFXRRY5HLHIRsO7XOA3CcqZ8MwJf75B5vyL/ohQpuG69UVdu2lclXBAkBq0/4Gc+9pm2y/lLNYrXJYnWg/tSfC+Pgrp5RuUSbT3mOxs6JePqaZUh2h4DJuXIZInSkr0HYH5I8LTRTMvHpvAkEAl81YqDl/deSXAq4Xy38/UrMTSEwGmHtVTxlwJ9Of+iX+pSDu/TIi3ZJtjxL+P1IcJD5r89SgJnl6secBz9rPBQ==";
+
+
+ @Test
+ public void rsaTest() {
+ KeyPair keyPair = SecureUtil.generateKeyPair("RSA");
+ log.info("{}", Base64.encode(keyPair.getPublic().getEncoded()));
+ log.info("{}", Base64.encode(keyPair.getPrivate().getEncoded()));
+ }
+
+
+ @Test
+ public void aaTest() {
+ RSA rsa = new RSA();
+ String encrypt = new String(rsa.encrypt(StrUtil.bytes("1234567", CharsetUtil.CHARSET_UTF_8), KeyType.PublicKey));
+ log.info("#---->{}#", encrypt);
+
+ String decrypt = new String(rsa.decrypt(encrypt, KeyType.PrivateKey));
+ log.info("#------>{}#", decrypt);
+ }
+
+ @Test
+ public void enAndDenTest() {
+ RSA rsa = new RSA();
+
+ rsa.getPrivateKey();
+ log.info(rsa.getPrivateKeyBase64());
+ rsa.getPublicKey();
+ log.info(rsa.getPublicKeyBase64());
+
+ byte[] encrypt = rsa.encrypt(StrUtil.bytes("我是一段测试aaaa", CharsetUtil.CHARSET_UTF_8), KeyType.PublicKey);
+ byte[] decrypt = rsa.decrypt(encrypt, KeyType.PrivateKey);
+
+ log.info("---->{}", new String(encrypt));
+ log.info("------>{}", new String(decrypt));
+ }
+
+ @Test
+ public void decTest() {
+ String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCCf8UFZK54AiK4PRu7tNd+Z8qZ77o/QXCnk25DRmygVpOEu5mGNSAvfnWmKp2pEV2RljeXq3Rid/+LQkonaebMJeXKSF0yxL/VgyeT8JaQ5gNbOrdfdlc+mFkXJyzyJt8YkvApEdPRNSU2ENBn7mgRfD0BYPM4vZ6/rv+de38FJwIDAQAB";
+ String str = "OsaRaZOuBYGiI1j62SQvJOj4CieiAFIdWRTQln2ZSAx1KHBhyCpJuLjb84ZuwsPd98crQOlE4VhgoQB/9SD5b1ATRGmpr6FR5FqXl76JDOirdYvrplJw3hO0cZM3ADL2TQTbtGanUskOWYPG+GXRdqV21und3aZXh+itTWcSFYw=";
+ String privateKeys = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIJ/xQVkrngCIrg9G7u0135nypnvuj9BcKeTbkNGbKBWk4S7mYY1IC9+daYqnakRXZGWN5erdGJ3/4tCSidp5swl5cpIXTLEv9WDJ5PwlpDmA1s6t192Vz6YWRcnLPIm3xiS8CkR09E1JTYQ0GfuaBF8PQFg8zi9nr+u/517fwUnAgMBAAECgYBhPt9NvpI4wbanvnndLczr2GJkxfzvSE+vwLCJF4C5FusFHVsxZINggQcg1V75bwRgCiXRMyYefreCSdrCditS43PzTOmE4RRrpxLlm8oubJc0C98LQ2qlN9AsUqL5IHpVGgbHDyWAwjc1GBID6nwXKpxq1/VodFqhahG9D5EZsQJBALnkb+5VTxQbiyQI4Uc9NIvAyVcNY1OisbvY6tvNgdBbJkADgAb78M1HWxxYjUqsvzggNHc7cWqWBHMgpnJaqm8CQQCztze4D7uAk7OC9MJHY5eE980J8Kk+GEZKxz4LahzU6V6dcb9GFac3wEtgilj/tOAn9y0/Q8sm9vvCIbMDzgzJAkEAqRYcqhF26LdVDOX25DHMBgLKISDQZFbsjA13M4/usHL4i+mjHrc0BcUOHu59NpuDI65HitzLAUSLr5zXSdUmiQJAW77wOg4GCejdXsB3IhzMsHwU97sdm26nC+vVV9xvJZ6Rx8zW+f9543NOx9U5BCmhuaVtOvvwDU9PTVcI3atmSQJAXAIJ5gGdtXx0DXiX4VvzNFHqgaqHMGvXyjNVkU2FYQbSAd2A6app4uRO+BkZu9dSjh14m+oXMnV2HzAN2rRnjA==";
+
+ RSA rsa = new RSA(privateKeys, null);
+ String aaa = new String(rsa.decrypt(str, KeyType.PrivateKey));
+ log.info("---->{}", aaa);
+ }
+
+ @Test
+ public void demoTest() {
+ String PRIVATE_KEY = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAIL7pbQ+5KKGYRhw7jE31hmA"
+ + "f8Q60ybd+xZuRmuO5kOFBRqXGxKTQ9TfQI+aMW+0lw/kibKzaD/EKV91107xE384qOy6IcuBfaR5lv39OcoqNZ"
+ + "5l+Dah5ABGnVkBP9fKOFhPgghBknTRo0/rZFGI6Q1UHXb+4atP++LNFlDymJcPAgMBAAECgYBammGb1alndta"
+ + "xBmTtLLdveoBmp14p04D8mhkiC33iFKBcLUvvxGg2Vpuc+cbagyu/NZG+R/WDrlgEDUp6861M5BeFN0L9O4hz"
+ + "GAEn8xyTE96f8sh4VlRmBOvVdwZqRO+ilkOM96+KL88A9RKdp8V2tna7TM6oI3LHDyf/JBoXaQJBAMcVN7fKlYP"
+ + "Skzfh/yZzW2fmC0ZNg/qaW8Oa/wfDxlWjgnS0p/EKWZ8BxjR/d199L3i/KMaGdfpaWbYZLvYENqUCQQCobjsuCW"
+ + "nlZhcWajjzpsSuy8/bICVEpUax1fUZ58Mq69CQXfaZemD9Ar4omzuEAAs2/uee3kt3AvCBaeq05NyjAkBme8SwB0iK"
+ + "kLcaeGuJlq7CQIkjSrobIqUEf+CzVZPe+AorG+isS+Cw2w/2bHu+G0p5xSYvdH59P0+ZT0N+f9LFAkA6v3Ae56OrI"
+ + "wfMhrJksfeKbIaMjNLS9b8JynIaXg9iCiyOHmgkMl5gAbPoH/ULXqSKwzBw5mJ2GW1gBlyaSfV3AkA/RJC+adIjsRGg"
+ + "JOkiRjSmPpGv3FOhl9fsBPjupZBEIuoMWOC8GXK/73DHxwmfNmN7C9+sIi4RBcjEeQ5F5FHZ";
+
+ RSA rsa = new RSA(PRIVATE_KEY, null);
+
+ String a = "2707F9FD4288CEF302C972058712F24A5F3EC62C5A14AD2FC59DAB93503AA0FA17113A020EE4EA35EB53F"
+ + "75F36564BA1DABAA20F3B90FD39315C30E68FE8A1803B36C29029B23EB612C06ACF3A34BE815074F5EB5AA3A"
+ + "C0C8832EC42DA725B4E1C38EF4EA1B85904F8B10B2D62EA782B813229F9090E6F7394E42E6F44494BB8";
+
+ byte[] aByte = HexUtil.decodeHex(a);
+ byte[] decrypt = rsa.decrypt(aByte, KeyType.PrivateKey);
+ }
+
+}
diff --git a/src/test/java/com/xcong/excoin/mapper/Car.java b/src/test/java/com/xcong/excoin/mapper/Car.java
new file mode 100644
index 0000000..b432912
--- /dev/null
+++ b/src/test/java/com/xcong/excoin/mapper/Car.java
@@ -0,0 +1,18 @@
+package com.xcong.excoin.mapper;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @author wzy
+ * @date 2020-05-05 11:00
+ **/
+@Data
+public class Car {
+ private String name;
+
+ private String color;
+
+ private Date createTime;
+}
diff --git a/src/test/java/com/xcong/excoin/mapper/CarDto.java b/src/test/java/com/xcong/excoin/mapper/CarDto.java
new file mode 100644
index 0000000..3d19f26
--- /dev/null
+++ b/src/test/java/com/xcong/excoin/mapper/CarDto.java
@@ -0,0 +1,16 @@
+package com.xcong.excoin.mapper;
+
+import lombok.Data;
+
+/**
+ * @author wzy
+ * @date 2020-05-05 11:00
+ **/
+@Data
+public class CarDto {
+ private String name;
+
+ private String color;
+
+ private String createTime;
+}
diff --git a/src/test/java/com/xcong/excoin/mapper/CarEntity.java b/src/test/java/com/xcong/excoin/mapper/CarEntity.java
new file mode 100644
index 0000000..f92675c
--- /dev/null
+++ b/src/test/java/com/xcong/excoin/mapper/CarEntity.java
@@ -0,0 +1,16 @@
+package com.xcong.excoin.mapper;
+
+import lombok.Data;
+
+/**
+ * @author wzy
+ * @date 2020-05-05 15:04
+ **/
+@Data
+public class CarEntity {
+ private String userName;
+
+ private String userColor;
+
+ private String time;
+}
diff --git a/src/test/java/com/xcong/excoin/mapper/CarMapper.java b/src/test/java/com/xcong/excoin/mapper/CarMapper.java
new file mode 100644
index 0000000..3d27cc1
--- /dev/null
+++ b/src/test/java/com/xcong/excoin/mapper/CarMapper.java
@@ -0,0 +1,46 @@
+package com.xcong.excoin.mapper;
+
+import org.mapstruct.*;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+/**
+ * @author wzy
+ * @date 2020-05-05 11:00
+ **/
+@Mapper
+public abstract class CarMapper {
+ public static final CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);
+
+ @Mapping(source = "createTime", target = "createTime", dateFormat = "yyyy-MM-dd HH:mm:ss")
+ public abstract CarDto carToCarDto(Car car);
+
+ @InheritInverseConfiguration
+ @Mapping(target = "name", ignore = true)
+ public abstract Car carDtoToCar(CarDto carDto);
+
+ @Named("useMe1")
+ @Mapping(source = "name", target = "userName")
+ @Mapping(source = "color", target = "userColor")
+ @Mapping(source = "createTime", target = "time", dateFormat = "yyyy-MM-dd HH:mm:ss")
+ public abstract CarEntity carToCarEntity(Car car);
+
+ @Mapping(source = "name", target = "userName")
+ @Mapping(source = "color", target = "userColor")
+ public abstract CarEntity carToCarEntityList(Car car);
+
+ @InheritInverseConfiguration(name = "carToCarEntity")
+ public abstract Car carEntityToCar(CarEntity carEntity);
+
+
+ @Named("useMe")
+ @InheritInverseConfiguration(name = "carToCarEntityList")
+ public abstract Car carEntityToCar1(CarEntity carEntity);
+
+ @IterableMapping(qualifiedByName = "useMe1")
+ public abstract List<CarEntity> carEntitiesToCarList(List<Car> list);
+
+ @IterableMapping(qualifiedByName = "useMe")
+ public abstract List<Car> carsToCarEntities(List<CarEntity> list);
+}
diff --git a/src/test/java/com/xcong/excoin/mapper/MapStructMapper.java b/src/test/java/com/xcong/excoin/mapper/MapStructMapper.java
new file mode 100644
index 0000000..97436ae
--- /dev/null
+++ b/src/test/java/com/xcong/excoin/mapper/MapStructMapper.java
@@ -0,0 +1,89 @@
+package com.xcong.excoin.mapper;
+
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author wzy
+ * @date 2020-05-05 10:59
+ **/
+@Slf4j
+@SpringBootTest
+public class MapStructMapper {
+
+
+ @Test
+ public void mapperConvert() {
+ Car car = new Car();
+ car.setColor("123");
+ car.setName("321");
+ car.setCreateTime(new Date());
+ CarDto carDto = CarMapper.INSTANCE.carToCarDto(car);
+ log.info(carDto.toString());
+ }
+
+ @Test
+ public void carDtoToCarConvert() {
+ CarDto carDto = new CarDto();
+ carDto.setName("dddd");
+ carDto.setColor("aaaa");
+ carDto.setCreateTime("2020-12-12 12:22:22");
+ Car car = CarMapper.INSTANCE.carDtoToCar(carDto);
+ log.info(car.toString());
+ }
+
+ @Test
+ public void carToCarEntity() {
+ Car car = new Car();
+ car.setName("123");
+ car.setColor("33333");
+ car.setCreateTime(new Date());
+ CarEntity carEntity = CarMapper.INSTANCE.carToCarEntity(car);
+ log.info(carEntity.toString());
+ }
+
+ @Test
+ public void carEntityToCar() {
+ CarEntity carEntity = new CarEntity();
+ carEntity.setUserName("11111");
+ carEntity.setUserColor("33333");
+ carEntity.setTime("2020-12-12 12:22:22");
+ Car car = CarMapper.INSTANCE.carEntityToCar(carEntity);
+ log.info(car.toString());
+ }
+
+ @Test
+ public void carEntityListToCarList() {
+ List<CarEntity> list = new ArrayList<>();
+ for (int i = 0; i < 4; i++) {
+ CarEntity carEntity = new CarEntity();
+ carEntity.setTime("2020-12-12 12:22:33");
+ carEntity.setUserName("zs" + i);
+ carEntity.setUserColor("red" + i);
+ list.add(carEntity);
+ }
+ List<Car> cars = CarMapper.INSTANCE.carsToCarEntities(list);
+ log.info(cars.toString());
+ }
+
+ @Test
+ public void carToCarEntityList() {
+ List<Car> list = new ArrayList<>();
+ for (int i = 0; i < 4; i++) {
+ Car car = new Car();
+ car.setName("zs"+i);
+ car.setColor("black" + i);
+ car.setCreateTime(new Date());
+ list.add(car);
+ }
+
+ List<CarEntity> entities = CarMapper.INSTANCE.carEntitiesToCarList(list);
+ log.info(entities.toString());
+ }
+
+}
--
Gitblit v1.9.1