Helius
2020-05-13 d0de0bf06f69c8584330e857ec1ecce34b244c9f
init framework
1 files modified
54 files added
2737 ■■■■■ changed files
.gitignore 36 ●●●●● patch | view | raw | blame | history
README.md 72 ●●●● patch | view | raw | blame | history
pom.xml 201 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/ExcoinApplication.java 20 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/common/annotations/UserAuth.java 14 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/common/contants/AppContants.java 24 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/common/response/Result.java 62 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/common/response/ResultCode.java 34 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/common/system/base/BaseEntity.java 28 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/common/system/base/IBaseService.java 10 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/common/system/bean/LoginUserBean.java 61 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/common/system/controller/LoginController.java 57 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/common/system/dto/LoginDto.java 21 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/common/system/service/UserDetailsServiceImpl.java 38 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/configurations/GlobalExceptionHandler.java 70 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/configurations/MybatisPlusConfig.java 23 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/configurations/RedisConfig.java 47 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/configurations/SwaggerConfig.java 48 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/configurations/WebMvcConfig.java 40 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/configurations/i18n/CustomLocaleResolver.java 33 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/configurations/i18n/LocaleResolverConfig.java 19 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/configurations/interceptor/MybatisInterceptor.java 10 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/configurations/properties/ApplicationProperties.java 18 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/configurations/properties/SecurityProperties.java 17 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/configurations/security/CustomAccessDeniedHandler.java 25 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/configurations/security/CustomAuthenticationEntryPoint.java 26 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/configurations/security/TokenConfigurer.java 21 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/configurations/security/TokenFilter.java 97 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/configurations/security/WebSecurityConfig.java 72 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/member/entity/MemberEntity.java 23 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/test/controller/TestUserController.java 78 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/test/dao/TestUserDao.java 18 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/test/dto/TestUserDto.java 34 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/test/entity/TestUserEntity.java 22 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/test/mapper/TestUserEntityMapper.java 20 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/test/service/TestUserService.java 14 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/test/service/impl/TestUserServiceImpl.java 28 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/test/vo/TestUserVo.java 29 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/test/vo/TestVo.java 20 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/utils/MessageSourceUtils.java 31 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/utils/RedisUtils.java 554 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/utils/SpringContextHolder.java 64 ●●●●● patch | view | raw | blame | history
src/main/resources/application.yml 80 ●●●●● patch | view | raw | blame | history
src/main/resources/i18n/messages.properties patch | view | raw | blame | history
src/main/resources/i18n/messages_en_US.properties 2 ●●●●● patch | view | raw | blame | history
src/main/resources/i18n/messages_zh_CN.properties 2 ●●●●● patch | view | raw | blame | history
src/main/resources/logback-spring.xml 147 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/TestUserDao.xml 12 ●●●●● patch | view | raw | blame | history
src/test/java/com/xcong/excoin/KssframeworkApplicationTests.java 33 ●●●●● patch | view | raw | blame | history
src/test/java/com/xcong/excoin/RSATest.java 97 ●●●●● patch | view | raw | blame | history
src/test/java/com/xcong/excoin/mapper/Car.java 18 ●●●●● patch | view | raw | blame | history
src/test/java/com/xcong/excoin/mapper/CarDto.java 16 ●●●●● patch | view | raw | blame | history
src/test/java/com/xcong/excoin/mapper/CarEntity.java 16 ●●●●● patch | view | raw | blame | history
src/test/java/com/xcong/excoin/mapper/CarMapper.java 46 ●●●●● patch | view | raw | blame | history
src/test/java/com/xcong/excoin/mapper/MapStructMapper.java 89 ●●●●● patch | view | raw | blame | history
.gitignore
New file
@@ -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/
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
pom.xml
New file
@@ -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>
src/main/java/com/xcong/excoin/ExcoinApplication.java
New file
@@ -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);
    }
}
src/main/java/com/xcong/excoin/common/annotations/UserAuth.java
New file
@@ -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 {
}
src/main/java/com/xcong/excoin/common/contants/AppContants.java
New file
@@ -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 ";
}
src/main/java/com/xcong/excoin/common/response/Result.java
New file
@@ -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;
    }
}
src/main/java/com/xcong/excoin/common/response/ResultCode.java
New file
@@ -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;
    }
}
src/main/java/com/xcong/excoin/common/system/base/BaseEntity.java
New file
@@ -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;
}
src/main/java/com/xcong/excoin/common/system/base/IBaseService.java
New file
@@ -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);
}
src/main/java/com/xcong/excoin/common/system/bean/LoginUserBean.java
New file
@@ -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;
    }
}
src/main/java/com/xcong/excoin/common/system/controller/LoginController.java
New file
@@ -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);
    }
}
src/main/java/com/xcong/excoin/common/system/dto/LoginDto.java
New file
@@ -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;
}
src/main/java/com/xcong/excoin/common/system/service/UserDetailsServiceImpl.java
New file
@@ -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);
    }
}
src/main/java/com/xcong/excoin/configurations/GlobalExceptionHandler.java
New file
@@ -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("用户名或密码错误");
    }
}
src/main/java/com/xcong/excoin/configurations/MybatisPlusConfig.java
New file
@@ -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();
    }
}
src/main/java/com/xcong/excoin/configurations/RedisConfig.java
New file
@@ -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;
    }
}
src/main/java/com/xcong/excoin/configurations/SwaggerConfig.java
New file
@@ -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();
    }
}
src/main/java/com/xcong/excoin/configurations/WebMvcConfig.java
New file
@@ -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();
    }
}
src/main/java/com/xcong/excoin/configurations/i18n/CustomLocaleResolver.java
New file
@@ -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) {
    }
}
src/main/java/com/xcong/excoin/configurations/i18n/LocaleResolverConfig.java
New file
@@ -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();
    }
}
src/main/java/com/xcong/excoin/configurations/interceptor/MybatisInterceptor.java
New file
@@ -0,0 +1,10 @@
package com.xcong.excoin.configurations.interceptor;
/**
 * mybatis拦截器,自动注入创建人、创建时间、修改人、修改时间
 *
 * @author wzy
 * @date 2020-05-13
 **/
public class MybatisInterceptor {
}
src/main/java/com/xcong/excoin/configurations/properties/ApplicationProperties.java
New file
@@ -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;
}
src/main/java/com/xcong/excoin/configurations/properties/SecurityProperties.java
New file
@@ -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;
}
src/main/java/com/xcong/excoin/configurations/security/CustomAccessDeniedHandler.java
New file
@@ -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));
    }
}
src/main/java/com/xcong/excoin/configurations/security/CustomAuthenticationEntryPoint.java
New file
@@ -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));
    }
}
src/main/java/com/xcong/excoin/configurations/security/TokenConfigurer.java
New file
@@ -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);
    }
}
src/main/java/com/xcong/excoin/configurations/security/TokenFilter.java
New file
@@ -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;
    }
}
src/main/java/com/xcong/excoin/configurations/security/WebSecurityConfig.java
New file
@@ -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();
    }
}
src/main/java/com/xcong/excoin/modules/member/entity/MemberEntity.java
New file
@@ -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;
}
src/main/java/com/xcong/excoin/modules/test/controller/TestUserController.java
New file
@@ -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);
    }
}
src/main/java/com/xcong/excoin/modules/test/dao/TestUserDao.java
New file
@@ -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);
}
src/main/java/com/xcong/excoin/modules/test/dto/TestUserDto.java
New file
@@ -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;
}
src/main/java/com/xcong/excoin/modules/test/entity/TestUserEntity.java
New file
@@ -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;
}
src/main/java/com/xcong/excoin/modules/test/mapper/TestUserEntityMapper.java
New file
@@ -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);
}
src/main/java/com/xcong/excoin/modules/test/service/TestUserService.java
New file
@@ -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();
}
src/main/java/com/xcong/excoin/modules/test/service/impl/TestUserServiceImpl.java
New file
@@ -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();
    }
}
src/main/java/com/xcong/excoin/modules/test/vo/TestUserVo.java
New file
@@ -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;
}
src/main/java/com/xcong/excoin/modules/test/vo/TestVo.java
New file
@@ -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;
}
src/main/java/com/xcong/excoin/utils/MessageSourceUtils.java
New file
@@ -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;
        }
    }
}
src/main/java/com/xcong/excoin/utils/RedisUtils.java
New file
@@ -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;
        }
    }
}
src/main/java/com/xcong/excoin/utils/SpringContextHolder.java
New file
@@ -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;
    }
}
src/main/resources/application.yml
New file
@@ -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==
src/main/resources/i18n/messages.properties
src/main/resources/i18n/messages_en_US.properties
New file
@@ -0,0 +1,2 @@
test=test
111=this is test msg
src/main/resources/i18n/messages_zh_CN.properties
New file
@@ -0,0 +1,2 @@
test=测试
111=这是测试消息
src/main/resources/logback-spring.xml
New file
@@ -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>
src/main/resources/mapper/TestUserDao.xml
New file
@@ -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>
src/test/java/com/xcong/excoin/KssframeworkApplicationTests.java
New file
@@ -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);
        }
    }
}
src/test/java/com/xcong/excoin/RSATest.java
New file
@@ -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);
    }
}
src/test/java/com/xcong/excoin/mapper/Car.java
New file
@@ -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;
}
src/test/java/com/xcong/excoin/mapper/CarDto.java
New file
@@ -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;
}
src/test/java/com/xcong/excoin/mapper/CarEntity.java
New file
@@ -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;
}
src/test/java/com/xcong/excoin/mapper/CarMapper.java
New file
@@ -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);
}
src/test/java/com/xcong/excoin/mapper/MapStructMapper.java
New file
@@ -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());
    }
}