• MCN参考文档



    一、前言

    MCN是一个基于SpringBoot和SpringCloud的一个快速构建JavaWeb系统的工具。MCN在SpringBoot的基础上提供更多的默认配置以及更多的自动配置,如多数据源配置、跨域、编码、数据完整性校验等等,同时支持Servlet和Reactive以及非Web开发模式。

    SSS

    二、使用教程

    示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

    快速开始

    新建Maven项目

    1. 引入父模块
    <parent>
        <artifactId>mcn-boot-starter-parentartifactId>
        <groupId>cn.hiboot.mcngroupId>
        <version>${最新稳定版}version>
    parent>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 添加依赖
    <dependencies>
    
        <dependency>
            <groupId>cn.hiboot.mcngroupId>
            <artifactId>mcn-spring-boot-starterartifactId>
        dependency>
    
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
    
        <dependency>
            <groupId>cn.hiboot.mcngroupId>
            <artifactId>mvc-swagger2artifactId>
        dependency>
    
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <scope>providedscope>
        dependency>
    
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    1. 添加maven插件
    <build>
        <finalName>${project.artifactId}finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-surefire-pluginartifactId>
                <configuration>
                    <skipTests>trueskipTests>
                configuration>
            plugin>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-jar-pluginartifactId>
                <configuration>
                    <archive>
                        <manifestEntries>
                            
                            <Build-Timestamp>${timestamp}Build-Timestamp>
                            <Implementation-Version>${project.version}Implementation-Version>
                        manifestEntries>
                    archive>
                configuration>
            plugin>
            <plugin>
                <groupId>org.codehaus.mojogroupId>
                <artifactId>buildnumber-maven-pluginartifactId>
                <configuration>
                    <timestampFormat>yyyy-MM-dd HH:mm:sstimestampFormat>
                configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>create-timestampgoal>
                        goals>
                    execution>
                executions>
            plugin>
        plugins>
    build>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    组织包结构

    1. 创建base package,如cn.hiboot.demo,并创建一个SpringBoot应用启动类,如:DemoApplication
    package cn.hiboot.demo;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    /**
     * 应用启动类
     *
     * @author DingHao
     * @since 2020/5/27 10:19
     */
    @SpringBootApplication
    public class DemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    1. 创建rest包,如cn.hiboot.demo.rest,并创建DemoRestApi,内容如下
    package cn.hiboot.demo.rest;
    
    import cn.hiboot.demo.bean.DemoBean;
    import cn.hiboot.mcn.core.model.result.RestResp;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.*;
    
    /**
     * rest接口
     *
     * @author DingHao
     * @since 2020/5/27 10:20
     */
    @RequestMapping("demo")
    @RestController
    @Validated
    @Api(tags = "demo接口")
    public class DemoRestApi {
    
        @GetMapping("list")
        @ApiOperation("列表")
        public RestResp<String> list(String query) {
            return new RestResp(query);
        }
    
        @PostMapping("json")
        @ApiOperation("post json")
        public RestResp<DemoBean> postJson(@Validated @RequestBody DemoBean userBean) {
            return new RestResp(userBean);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    1. 在src/java/resources下新建config文件夹,再在里面新建一个application.properties并写入以下内容
    #一般与项目模块对应
    spring.application.name=demo
    #开启swagger
    swagger.enable=true
    
    • 1
    • 2
    • 3
    • 4

    运行&访问

    1. 运行DemoApplication
    2. 访问SwaggerUI

    依赖管理

    下表提供了可用于覆盖 MCN 管理的版本的所有属性。应用可自定义这些版本。

    版本属性当前版本
    bcprov-jdk15onbcprov-jdk15on.version1.70
    bcpkix-jdk18onbcprov-jdk18on.version1.71
    spring-boot-admin-starter-clientboot-admin.version2.7.7
    spring-boot-admin-starter-serverboot-admin.version2.7.7
    commons-iocommons-io.version2.11.0
    fastjsonfastjson.version1.2.83
    fastjson2fastjson2.version2.0.14
    guavaguava.version31.1-jre
    hutool-corehutool.version5.8.9
    jsoupjsoup.version1.15.3
    knife4j-spring-uiknife4j.version3.0.3
    mapstructmapstruct.version1.5.2.Final
    mybatis-spring-boot-startermybatis-spring-boot.version2.2.2
    miniominio.version8.4.3
    snakeyamlsnakeyaml.version1.32
    spring-boot-dependenciesspring-boot.version2.7.4
    spring-cloud-dependenciesspring-cloud.version2021.0.4
    spring-cloud-alibaba-dependenciesspring-cloud-alibaba.version2021.1
    springfox-swagger2springfox-swagger.version3.0.0
    springfox-swagger-uispringfox-swagger.version3.0.0
    swagger-modelsswagger.version1.6.4
    swagger-bootstrap-uiswagger-bootstrap-ui.version1.9.6
    xxl-job-corexxl-job.version2.3.1

    三、功能说明

    通用模块

    统一数据结构

    package cn.hiboot.mcn.core.model.result;
    
    import com.fasterxml.jackson.annotation.JsonIgnore;
    import com.fasterxml.jackson.annotation.JsonInclude;
    import com.fasterxml.jackson.annotation.JsonProperty;
    
    @JsonInclude(JsonInclude.Include.NON_NULL)//Null字段不返回
    public class RestResp<T> {
    
        public enum ActionStatusMethod {
            OK,
            FAIL
        }
    
        @JsonProperty("ActionStatus")//返回字段名大写,默认OK表示正常结果返回
    	private ActionStatusMethod ActionStatus = ActionStatusMethod.OK;
    
        @JsonProperty("ErrorCode")//返回字段名大写,默认0表示无错误
    	private Integer ErrorCode = 0;
    
        @JsonProperty("ErrorInfo")//返回字段名大写,错误具体信息(当异常返回时)
    	private String ErrorInfo = "";
    
    	@JsonProperty("Duration")//接口执行时间需结合注解@Timing使用
    	private Long duration;
    
    	private T data;//接口返回的数据
    
    	private Long count;//数据返回的count数,分页时使用
    
        //省略set/get
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    常用工具

    1. JacksonUtils(可在非spring环境中使用)-基于jackson的一个序列化和反序列化工具

    ::: warning 注意

    当在SpringBoot项目里使用时,IOC容器中存在ObjectMapper则优先使用外部的

    :::

    1. SpringBeanUtils-一个方便在静态方法中从IOC容器获取bean的工具

    ::: warning 注意

    当存在多个上下文时且当前上下文是子上下文时会更新applicationContext

    :::

    扩展模块

    系统内置三种属性源名称分别是:mcn-global-unique、mcn-map、mcn-default

    mcn-global-unique

    1. 只要EnvironmentPostProcessor触发就自动加载classpath:config/mcn.properties文件。无论当前是否是引导上下文。

    ::: tip 提示

    当启用了spring.profiles.active配置同时会加载文件mcn-{profile}.properties,当激活多个profile时且存在相同属性配置时后面的优先级比前面的高

    :::

    mcn-map

    该属性源里只包含五个配置(内部使用):

    1. app.base-package:项目启动的根路径即Application所在package
    2. logging.level.{app.base-package}.dao:设置dao包下的日志级别为info
    3. project.version:项目版本号读取manifest文件(如果存在)
    4. mcn.log.file.name:日志输出的文件名默认为error(注意:不包含扩展名)
    5. mcn.version:mcn版本号读取manifest文件

    mcn-default

    该属性源里包含很多配置如:

    #内嵌tomcat根路径
    server.tomcat.basedir=/tmp/tomcat/
    #启用tomcat数据压缩
    server.compression.enabled=true
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    全部配置

    ::: warning 注意

    除了mcn-global-unique之外其它属性源默认不会加引导上下文中加载

    1. 当配置mcn.bootstrap.eagerLoad.enable=true可启用其它三个属性源也在引导上下文中加载

    2. 当环境中存在mcn-default属性源,则mcn-default、mcn-map属性源都不会加载

    3. 日志文件按天压缩,自动删除30天前日志

    :::

    属性源打印

    调试时使用,生产应关闭!!!

    当环境中配置mcn.print-env.enable=true时,项目在启动时会自动打印所有可枚举的属性源。

    自动配置

    统一异常处理

    1. [推荐]直接使用异常ServiceException
    public class UserService{
        
        private UserMapper userMapper;
        
        public UserService(UserMapper userMapper){
            this.userMapper = userMapper;
        }
        
        public void login(String username,String password){
            if(userMapper.find(username) == null){
                throw ServiceException.newInstance("用户不存在");
            }
        }
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    1. 直接自定义异常继承BaseException
    public class CustomException extends BaseException{
        public CustomException(Throwable cause) {
            super(cause);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 直接自定义异常继承RuntimeException
    public class CustomException extends RuntimeException{
        
    }
    
    • 1
    • 2
    • 3

    ::: warning 注意

    1. 如果抛出的BaseException子类异常无错误码则使用默认错误码999999
    2. 如果抛出非BaseException子类异常则使用默认错误码999998
    3. 如果抛出异常信息的同时指定了错误码则不使用默认的错误码
    4. 如果只抛出错误码则从classpath:error-msg.properties中获取,获取不到则使用默认的内部服务器错误信息
      :::

    自定义异常解析器

    自定义一个处理HttpMessageNotReadableException的异常处理器。

    @Configuration
    public class CustomExceptionResolver {
        @Bean
        public ExceptionResolver specialSymbolExceptionResolver() {
            return new ExceptionResolver() {
    
                @Override
                public boolean support(HttpServletRequest request, Throwable t) {
                    return t instanceof HttpMessageNotReadableException;
                }
    
                @Override
                public RestResp<Object> resolveException(HttpServletRequest request, Throwable t) {
                    ServiceException serviceException = ServiceException.find(t);
                    if (serviceException == null || serviceException.getCode() != ExceptionKeys.SPECIAL_SYMBOL_ERROR) {
                        return null;
                    }
                    return RestResp.error(serviceException.getCode(), serviceException.getMessage());
                }
    
            };
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    Swagger配置

    1. 默认swagger自动配置关闭,可通过swagger.enable=true开启
    2. 默认将带有注解RestController的接口生成文档忽略带有注解@IgnoreApi和@ApiIgnore的接口

    跨域配置

    1. 默认跨域不启动,可通过filter.cross=true启用跨域,方便开发调试
    2. 参数说明
    #配置允许的请求方式
    mcn.cors.allowed-method=GET,POST
    #配置允许的请求来源
    mcn.cors.allowed-origin=https://www.xxx.com/
    #配置允许的请求头
    mcn.cors.allowed-header=TSM
    #配置拦截的路径模式,默认/**即拦截所有
    mcn.cors.pattern=/**
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    ::: tip 提示
    生产环境一定要关闭跨域设置
    :::

    XSS配置

    1. 默认跨域不启用,可通过mcn.xss.enable=true启用
    2. 如果使用security,默认顺序在安全过滤器链后执行,可通过mcn.xss.order=-101调整到其之前执行
    3. 参数说明
    #是否启用参数处理
    mcn.xss.enable=true
    #指定哪些接口需要处理(ant匹配模式)
    mcn.xss.exclude-urls=
    #指定哪些字段不做处理(全局生效),如mcn.xss.exclude-fields=name,则所有接口中name字段不处理
    mcn.xss.exclude-fields=
    #指定哪些接口需要处理(ant匹配模式),默认/**
    mcn.xss.include-urls=/**
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    ::: tip 提示
    生产环境建议开启XSS设置
    :::

    WebSecurity配置

    1. 当使用了SpringSecurity时mcn自动忽略以下路径
    web.security.default-exclude-urls=/v2/api-docs,/swagger-resources/**,/doc.html,/webjars/**,/error,/favicon.ico,/_imagePreview,/*.png,/_groovyDebug_
    
    • 1
    1. 配置说明
    #配置不拦截的路径
    web.security.exclude-urls==/user/**,/news/add
    
    • 1
    • 2

    ::: tip 提示
    可通过web.security.enable-default-ignore=false关闭默认忽略的路径
    :::

    Validator配置

    1. 配置了hibernate.validator.fail_fast=true,当第一个参数校验失败后续不校验
    2. 扩展了分组校验区分校验时是否需要校验默认分组
    3. 提供注解@Phone校验手机号

    ::: tip 提示

    @Phone 仅简单校验了11位数字手机号

    :::

    多数据源配置

    通过前缀multiple.datasource配置数据源即代表使用的是多数据源配置。

    1. 配置多个数据源
    multiple.datasource.hello.url=jdbc:mysql://127.0.0.1:3306/test?createDatabaseIfNotExist=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false&useSSL=false&serverTimezone=Asia/Shanghai
    multiple.datasource.hello.username=root
    multiple.datasource.hello.password=123456
    
    multiple.datasource.world.url=jdbc:mysql://127.0.0.1:3306/web_template?createDatabaseIfNotExist=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false&useSSL=false&serverTimezone=Asia/Shanghai
    multiple.datasource.world.username=root
    multiple.datasource.world.password=123456
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. 启用动态数据源支持
    dynamic.datasource.enable=true
    
    • 1

    在MyBatis和Jpa使用动态数据源

    1. 在Mybatis中使用
    <dependency>
        <groupId>org.mybatis.spring.bootgroupId>
        <artifactId>mybatis-spring-boot-starterartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    1. 在Jpa中使用
     <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-data-jpaartifactId>
    dependency>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 使用注解SwitchSource切换数据源(数据源名称就是multiple.datasource后的第一个字符串即hello和world
    @RequestMapping("test")
    @RestController
    @SwitchSource("hello")
    public class TestRestApi {
    
        private UserDao userDao;
        
    	public TestRestApi(UserDao userDao) {
            this.userDao = userDao;
        }
    
        @GetMapping("list")
        public RestResp<List<User>> list() {
            return new RestResp<>(userDao.findAll());
        }
    
        @GetMapping("list2")
        @SwitchSource("world")
        public RestResp<List<User>> list2() {
            return new RestResp<>(userDao.findAll());
        }
    }    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    ::: tip 提示
    SwitchSource注解既可以用在类上也可以用在方法上,方法上的优先级高
    :::

    MyBatis和Jpa使用多数据源

    1. 使用多数据源
    #同时只能启动一个
    #mybatis.multiple.datasource.enable=true
    jpa.multiple.datasource.enable=true
    
    • 1
    • 2
    • 3
    1. 数据访问层位置

    dao层必须在启动类所在包的子包dao下且用数据源的名称当子包名称,如下图所示
    数据访问层位置

    1. 使用
    @RequestMapping("test")
    @RestController
    public class TestRestApi {
        private UserDao userDao;
        private UserDao2 userDao2;
    
        public TestRestApi(UserDao userDao, UserDao2 userDao2) {
            this.userDao = userDao;
            this.userDao2 = userDao2;
        }
    
        @GetMapping("list3")
        public RestResp<List<User>> list3() {
            List<User> all = userDao2.findAll();
            all.addAll(userDao.findAll());
            return new RestResp<>(all);
        }
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    ::: warning 注意

    1. 动态数据源开关和jpa多数据源开关以及mybatis多数据源开关三者同时只能开启一个
    2. 当三个开关都没开启时,默认会使用动态数据源模式
    3. jpa和mybatis的多数据源配置基本一样,引入不同的依赖就行了
      :::

    传输加解密

    使用SM2加密配置

    使用方式

    1. 引入依赖并配置密钥对
    <dependencies>
        <dependency>
            <groupId>org.bouncycastlegroupId>
            <artifactId>bcprov-jdk18onartifactId>
        dependency>
    
        <dependency>
            <groupId>cn.hutoolgroupId>
            <artifactId>hutool-cryptoartifactId>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    encryptor.sm2.private-key=308193020100301306072a8648ce3d020106082a811ccf5501822d04793077020101042044880abf2572c0946e4d7a18a812fe554f20db40bc852a3b78b7e057af72344ca00a06082a811ccf5501822da14403420004258785f13a181c19fe366f13e1e4d93834944fb6b2d05b0ef58963e3cbdc3d680b228bdeab895a1f113dd6690279cd932ab85ecf694ebf34d6201b9d76055094
    encryptor.sm2.public-key=3059301306072a8648ce3d020106082a811ccf5501822d03420004258785f13a181c19fe366f13e1e4d93834944fb6b2d05b0ef58963e3cbdc3d680b228bdeab895a1f113dd6690279cd932ab85ecf694ebf34d6201b9d76055094
    
    • 1
    • 2
    1. 接口中使用
    
    @RequestMapping("test")
    @RestController
    public class TestRestApi {
    
        private final TextEncryptor textEncryptor;
    
        public TestRestApi(TextEncryptor textEncryptor) {
            this.textEncryptor = textEncryptor;
        }
    
        @GetMapping("encrypt")
        public RestResp<String> encrypt(String text) {
            return new RestResp<>(textEncryptor.encrypt(text));
        }
    
        @GetMapping("decrypt")
        public RestResp<String> decrypt(String text) {
            return new RestResp<>(textEncryptor.decrypt(text));
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    1. 数据模型中使用

    只需要在需要解密的参数上添加注解@Decrypt即可

    @RequestMapping("test")
    @RestController
    public class TestRestApi {
    
        @GetMapping("list")
        public RestResp<String> list(@Decrypt String query) {
            return new RestResp<>(query);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    1. json反序列化中使用

    只需要在需要解密的字段上添加注解@Decrypt即可

    @RequestMapping("test")
    @RestController
    public class TestRestApi {
    
        @PostMapping("add")
        public RestResp<User> add( @RequestBody User userBean) {
            return new RestResp<>(userBean);
        }
    
    }
    
    @Setter
    @Getter
    public class User{
    
        private Integer id;
    
        @Decrypt
        private String name;
    
        private Integer age;
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    完整性校验

    使用SM3计算摘要

    使用方式

    1. 引入依赖
    <dependencies>
        <dependency>
            <groupId>org.bouncycastlegroupId>
            <artifactId>bcprov-jdk18onartifactId>
        dependency>
    
        <dependency>
            <groupId>cn.hutoolgroupId>
            <artifactId>hutool-cryptoartifactId>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    1. 配置说明
    #开启完整性校验
    data.integrity.enable=true
    #指定哪些接口不需要校验(ant匹配模式)
    data.integrity.exclude-patterns=
    #指定哪些接口需要校验(ant匹配模式),默认/**
    data.integrity.include-patterns=/**
    #指定是否在feign调用中也校验,默认false不校验
    #data.integrity.interceptor.enable=false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1. 接口中使用

    在header里出入以下三个参数timestamp(时间戳)、nonceStr(随机字符串)、signature(签名)

    @RequestMapping("test")
    @RestController
    public class TestRestApi {
    
        @GetMapping("list")
        public RestResp<String> list(String query) {
            return new RestResp<>(query);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    ::: tip 提示
    如果不在header里传入相关参数或者校验失败会提示

    {
        "ActionStatus": "FAIL",
        "ErrorCode": 999999,
        "ErrorInfo": "验证失败,数据被篡改"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    :::

    配置加解密

    使用SM4加密配置

    使用方式

    1. 引入依赖
    <dependencies>
        <dependency>
            <groupId>org.bouncycastlegroupId>
            <artifactId>bcprov-jdk18onartifactId>
        dependency>
    
        <dependency>
            <groupId>cn.hutoolgroupId>
            <artifactId>hutool-cryptoartifactId>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    1. 配置加密key

    以下配置必须放在classpath:config/mcn.properties文件中

    #加密key,必须128位即16字节
    encryptor.sm4.key=abcdefghijklmnop
    
    • 1
    • 2
    1. 配置中使用

    如在application.properties中存在加密项spring.datasource.username,而真正使用的是解密后的值root

    spring.datasource.username={cipher}7eda434344898ba11617084e0f117103
    
    • 1
    1. 接口中使用
    @RequestMapping("test")
    @RestController
    public class TestRestApi {
        
        private UserDao userDao;
        private TextEncryptor textEncryptor;
    
        public TestRestApi(UserDao userDao, TextEncryptor textEncryptor) {
            this.userDao = userDao;
            this.textEncryptor = textEncryptor;
        }
    
        @PostMapping("add")
        public RestResp<User> add( @RequestBody User userBean) {
            //入库手机号加密
            userBean.setMobile(textEncryptor.encrypt(userBean.getMobile()));
            userDao.save(userBean);
            return new RestResp<>(userBean);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    ::: warning 注意

    1. sm4是对称加密一般用于后端配置项及入库数据加密
    2. 密钥key必须放在classpath:config/mcn.properties文件中
      :::

    参数预处理

    对输入的参数的统一处理,支持kv编码和json编码参数

    1. 参数说明
    #是否启用参数处理
    param.processor.enable=true
    #指定哪些接口需要校验(ant匹配模式)
    param.processor.exclude-urls=
    #指定哪些字段不做处理(全局生效),如param.processor.exclude-fields=name,则所有接口中name字段不处理
    param.processor.exclude-fields=
    #指定哪些接口需要校验(ant匹配模式),默认/**
    param.processor.include-urls=/**
    #全局校验规则(正则表达式),默认的参数处理器ParamProcessor是基于正则的
    global.rule.pattern=.*
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    1. 自定义参数处理器
    @Component
    public class CustomRule{
    
        @Bean
        public ParamProcessor myParamProcessor() {
            return (rule, name, value) -> {
                //这里可以编写校验逻辑
                //rule:当前规则
                //name:当前字段名
                //value:当前字段值
                Pattern pattern = Pattern.compile(rule);
                if(pattern.matcher(value).matches()){
                    throw ServiceException.newInstance(ExceptionKeys.SPECIAL_SYMBOL_ERROR);
                }
                return value;
            };
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    1. 各字段自定义规则(一般用不到)

    通过在参数上指定注解@CheckParam来定义各字段不同的校验规则

    
    @Setter
    @Getter
    @CheckParam("[a-z0-9]+")
    public class User{
    
    	private Integer id;
        @CheckParam("[a-z]+")
    	private String name;
    
    	private Integer age;
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    分布式锁

    默认获取锁及锁持有的时间都是5秒。

    1. 方式一:使用注解@DistributedLock
      示例:
    
    @RequestMapping("test")
    @RestController
    public class TestRestApi {
    
        @GetMapping("list")
        @DistributedLock("list_lock")
        public RestResp<String> list(String query) {
            return new RestResp<>(query);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    1. 方式二:直接使用DistributedLocker接口
      示例:
    
    @RequestMapping("test")
    @RestController
    public class TestRestApi {
    
        private static final String LIST_LOCK_NAME = "list_lock";
        private final DistributedLocker distributedLocker;
    
        public TestRestApi(DistributedLocker distributedLocker) {
            this.distributedLocker = distributedLocker;
        }
    
        @GetMapping("list")
        @DistributedLock("list_lock")
        public RestResp<String> list(String query) {
            if(distributedLocker.tryLock(LIST_LOCK_NAME,10,10)){//获取锁等待超时10秒持有超时时间10秒
                //do something
                distributedLocker.unlock(LIST_LOCK_NAME);
            }
            return new RestResp<>(query);
        }
    
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    War包模式

    1. 在classpath的config目录下创建mcn.properties文件
    2. 添加main.class=应用启动类(即main方法所在类)

    数据库初始化

    扩展原有的数据库初始化即默认情况处理classpath*下的db文件夹下的脚本,另额外添加文件名为other的sql文件解析并可指定一个分隔符。

    示例:自动初始化一张表并须支持不同环境,如MySQL和kingbase的初始化脚本。

    1. pom.xml添加驱动
    <dependencies>
    
         <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
        dependency>
        
        <dependency>
            <groupId>com.kingbase8groupId>
            <artifactId>kingbase8artifactId>
            <version>8.6.0version>
        dependency>
        
    dependencies>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    1. 在application配置文件添加以下配置
    spring.datasource.url=jdbc:${spring.sql.init.platform}://127.0.0.1:3306/test?createDatabaseIfNotExist=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false&useSSL=false&serverTimezone=Asia/Shanghai
    spring.datasource.username=root
    spring.datasource.password=111111
    
    spring.sql.init.mode=always
    #指定当前应用运行环境使用的是mysql
    spring.sql.init.platform=mysql
    spring.sql.init.continue-on-error=true
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 在classpath:db/下分别创建schema-mysql.sql、schema-kingbase8.sql、other-kingbase8.sql文件

    schema-mysql.sql内容如下:

    CREATE TABLE t_user (
      id int(11) NOT NULL AUTO_INCREMENT,
      name varchar(64) NOT NULL,
      age int(11) DEFAULT NULL,
      create_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
      update_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      PRIMARY KEY (id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    schema-kingbase8.sql内容如下:

    CREATE TABLE t_user (
      id INT NOT NULL AUTO_INCREMENT,
      name VARCHAR(64) NOT NULL,
      age INT DEFAULT NULL,
      create_at timestamp DEFAULT sysdate NOT NULL,
      update_at timestamp DEFAULT sysdate NOT NULL,
      PRIMARY KEY ("id")
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    other-kingbase8.sql内容如下:

    create or replace trigger t_user_trigger
    before
    update on t_user
        for each row
    begin
    select sysdate into :NEW.update_at from dual;
    end;
    //
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ::: tip 提示

    1. 由于kingbase不支持createDatabaseIfNotExist参数,所以kingbase需要手动先建数据库或者指定一个已存在的库来自动建库
    #系统会与该init_db建立连接再创建test库
    spring.sql.init.additional.init-db-name=init_db
    
    • 1
    • 2
    1. 由于kingbase不支持ON UPDATE CURRENT_TIMESTAMP,所以需要使用触发器实现
    2. 由于触发器脚本不能以;分隔,所以需要指定一个其它的分隔符,默认//

    :::

    1. 切换使用kingbase数据库
    • 修改配置项spring.sql.init.platform=kingbase8
    • [推荐]在系统属性或环境变量中指定spring.sql.init.platform=kingbase8
    • [推荐]若使用配置中心(如:nacos)则直接在配置中心指定spring.sql.init.platform=kingbase8
  • 相关阅读:
    一文搞懂泛型——泛型简介/优点/上界/通配符
    HRNet-Facial-Landmark-Detection 训练自己数据集
    我的创作纪念日
    微信小程序开发之投票管理及小程序UI的使用
    Ansible的debug模块和魔法变量介绍,fact变量采集和缓存相关操作演示
    爱婴室主要股东再现减持:莫锐伟、王云亦是如此,业绩表现不理想
    【学习笔记03】node.js搭建一个简易的服务器
    Lua专栏目录
    EdgeSAM: Prompt-In-the-Loop Distillation for On-Device Deployment of SAM
    手把手教你解决ClassCastException类型转换异常
  • 原文地址:https://blog.csdn.net/dh798417147/article/details/126446423