springboot2单服务框架

一. 环境配置

jdk8+,开发软件idea,关系型数据库mysql(持久型),非关系型数据库redis(缓存)

二. 创建maven项目

file -> new -> Project 选择Maven看到如下界面:
在这里插入图片描述
点击next, 出现:
在这里插入图片描述
填写GroupId 和 ArtifactId,然后点击next, 然后点finish

三. 项目结构

项目最终结构

四. 引入依赖及配置

1. 引入父依赖

	<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
    </parent>

2. 引入依赖

		<!-- web 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- aop 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- redis依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- 如果使用redis连接池(无论lettuce还是jedis客户端,都需要),需要导入如下依赖 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.6.0</version>
        </dependency>
        <!-- mysql依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.35</version>
            <scope>runtime</scope>
        </dependency>

        <!-- 连接池 阿里巴巴数据源 -->
        <!--<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>-->

        <!-- Hikaricp数据库连接池 -->
        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
        </dependency>
        <!-- 使用Hikaricp数据库连接池所需的jdbc包 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <!-- 提供了大量mybatis操作的方法 -->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>
        <!-- mybatis分页插件PageHelper -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.5</version>
        </dependency>

        <!-- swagger依赖开始 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
            <version>1.5.21</version>
        </dependency>
        <!-- swagger依赖结束 -->

        <!-- Lombok插件使用依赖 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.0</version>
            <scope>provided</scope>
        </dependency>

3. 打包配置(包括mybatis自动生成代码插件)

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <!--mybatis自动生成代码插件-->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.5</version>
                <configuration>
                    <!-- 是否覆盖 -->
                    <overwrite>true</overwrite>
                    <!--允许移动生成的文件 -->
                    <verbose>true</verbose>
                    <!-- 自动生成的配置,${basedir}表示项目根目录 ,configurationFile默认在resource目录下-->
                    <configurationFile>${basedir}/src/main/resources/mybatis/generator/mybatis-generator.xml</configurationFile>
                </configuration>
                <dependencies>
                    <!--mysql驱动包-->
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>5.1.35</version>
                        <scope>runtime</scope>
                    </dependency>
                    <dependency>
                        <groupId>tk.mybatis</groupId>
                        <artifactId>mapper</artifactId>
                        <version>3.5.3</version>
                    </dependency>
                    <dependency>
                        <groupId>org.mybatis.generator</groupId>
                        <artifactId>mybatis-generator-core</artifactId>
                        <version>1.3.5</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

4. application.properties配置

##连接mysql关系数据库配置
#spring.datasource.druid.url=jdbc:mysql://localhost:3306/cloudrises?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
#spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
#spring.datasource.druid.username=root
#spring.datasource.druid.password=root
#####com.alibaba.druid.pool.DruidDataSource 连接池 阿里巴巴数据源
#spring.datasource.druid.db-type=mysql
#spring.datasource.druid.max-active=10
#spring.datasource.druid.min-idle=1
#spring.datasource.druid.max-wait=30000
#spring.datasource.druid.use-unfair-lock=true
#spring.datasource.druid.pool-prepared-statements=false

#### Hikaricp数据库连接池  对于web项目,要配置:destroy-method="shutdown"
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.url=jdbc:mysql://localhost:3306/cloudrises?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=root
## 驱动
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
## 数据源只读配置(默认false)
spring.datasource.hikari.read-only=false
## 连接超时时间(默认30秒)
spring.datasource.hikari.connection-timeout=30000
## 空闲超时时间,只有在minimumIdle<maximumPoolSize时生效,超时的连接可能被回收,数值 0 表示空闲连接永不从池中删除
spring.datasource.hikari.idle-timeout=600000
## 连接池中的连接的最长生命周期,数值 0 表示不限制(默认30分钟)
spring.datasource.hikari.max-lifetime=300000
## 连接池中可同时连接的最大连接数(默认10)
spring.datasource.hikari.maximum-pool-size=10
## 最小空闲连接数(默认与maximumPoolSize数值相同)
spring.datasource.hikari.minimum-idle=10

#### 连接redis非关系型数据库配置
## ip
spring.redis.host=127.0.0.1
spring.redis.password=123456789
## 端口
spring.redis.port=6379
## 获取数据超时时间
spring.redis.timeout=20000
## 数据位置(默认是0)
spring.redis.database=6
## 保持连接的最小值
spring.redis.lettuce.pool.min-idle=0
## 保持连接的最大值
spring.redis.lettuce.pool.max-idle=3000
## 最大建立连接等待时间(10秒)
spring.redis.lettuce.pool.max-wait=10000
## 连接池的最大连接数(设为0表示无限制)
spring.redis.lettuce.pool.max-active=3000

#### mybatis配置
## mapper映射文件位置
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
## 包下文件别名装配
mybatis.type-aliases-package=com.study.model
## 开启驼峰转换
mybatis.configuration.map-underscore-to-camel-case=true
## 配置(查询语句中某些字段值是null)即使值为空也返回
mybatis.configuration.call-setters-on-nulls=true

#### mvc全局配置
## 端口号(默认8080)
server.port=8890
## 上下文路径(项目路径),是构成url地址的一部分
server.servlet.context-path=/projectframework

#### 配置默认(JsonFormat)时间格式转换
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT-8

#### 文件设置 最大文件10M,最大请求数据100M,文件大于该阀值则写入磁盘,否则写入内存,默认0
## 文件最大传输大小
spring.servlet.multipart.max-file-size=10MB
## 最大请求大小(包括文件+填写数据)
spring.servlet.multipart.max-request-size=100MB
## 文件大于该阀值则写入磁盘,否则写入内存(缓存)
spring.servlet.multipart.file-size-threshold=0

## 是否开启swagger2
swagger2.enable=true

#### 日志配置文件
logging.config=classpath:logback.xml

#### tomcat优化配置
## 编码
server.tomcat.uri-encoding=UTF-8
## 最大连接数
server.tomcat.max-connections=3000
## 最大post请求数据
server.tomcat.max-http-post-size=2MB
## 最大线程数
server.tomcat.max-threads=200
## 最小空闲线程数
server.tomcat.min-spare-threads=10
## 可同时接受数量
server.tomcat.accept-count=100

#### springboot默认配置的线程池是ThreadPoolTaskExecutor(已经写了JAVA类配置(AsyncConfig.class),取消默认配置)
#spring.task.scheduling.thread-name-prefix=cloudrises-schedule-
#spring.task.execution.pool.core-size=10
#spring.task.execution.pool.max-threads=100
#spring.task.execution.pool.queue-capacity=100
#spring.task.execution.pool.keep-alive=10s

#### 定时器线程 配置
## 线程池大小
spring.task.scheduling.pool.size=5
## 线程池名称
spring.task.scheduling.thread-name-prefix=singleframework_timer_schedule-

5. logback.xml日志文件

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <contextName>logback</contextName>
    <property name="log.path" value="logs/logback/" />
    <property name="log.file" value="logs/logback.log" />
    <!--输出到控制台 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!--输出到文件 -->
    <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.file}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}%d{yyyy-MM-dd_HH}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
            <!-- 指定日志文件的上限大小,例如设置为1GB的话,那么到了这个值,就会删除旧的日志 -->
            <totalSizeCap>1GB</totalSizeCap>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="info">
        <appender-ref ref="console" />
        <appender-ref ref="file" />
    </root>

    <!-- 打印执行的sql name指定mapper所在的包,additivity设定为true时,父级也会打印相应的信息,相当于打印多次 -->
    <logger name="com.study.dao" level="DEBUG" additivity="false">
        <appender-ref ref="console" />
        <appender-ref ref="file" />
    </logger>

</configuration>

6. mybatis-generator.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>

    <!-- 可以用于加载配置项或者配置文件,在整个配置文件中就可以使用${propertyKey}的方式来引用配置项
    resource:配置资源加载地址,使用resource,MBG从classpath开始找,比如com/myproject/generatorConfig.properties
    url:配置资源加载地质,使用URL的方式,比如file:///C:/myfolder/generatorConfig.properties.
    注意,两个属性只能选址一个;

    另外,如果使用了mybatis-generator-maven-plugin,那么在pom.xml中定义的properties都可以直接在generatorConfig.xml中使用
    <properties resource="" url="" />
   -->

    <!-- 在MBG工作的时候,需要额外加载的依赖包, location属性指明加载jar/zip包的全路径
   <classPathEntry location="/Program Files/IBM/SQLLIB/java/db2java.zip" />
     -->
    <!--如:数据库驱动包路径 -->
    <!--<classPathEntry location="C:\Users\Administrator\Downloads\mysql-connector-java-5.1.40.jar"/>-->

    <!--
        context:生成一组对象的环境
        id:必选,上下文id,用于在生成错误时提示
        defaultModelType:指定生成对象的样式
            1,conditional:类似hierarchical;
            2,flat:所有内容(主键,blob)等全部生成在一个对象中;
            3,hierarchical:主键生成一个XXKey对象(key class),Blob等单独生成一个对象,其他简单属性在一个对象中(record class)
        targetRuntime:
            1,MyBatis3:默认的值,生成基于MyBatis3.x以上版本的内容,包括XXXBySample;
            2,MyBatis3Simple:类似MyBatis3,只是不生成XXXBySample;
        introspectedColumnImpl:类全限定名,用于扩展MBG
    -->
    <context id="mybatis_generator" targetRuntime="MyBatis3" defaultModelType="flat">

        <!-- 自动识别数据库关键字,默认false,如果设置为true,根据SqlReservedWords中定义的关键字列表;
        一般保留默认值,遇到数据库关键字(Java关键字),使用columnOverride覆盖
        -->
        <property name="autoDelimitKeywords" value="false"/>

        <!-- 生成的Java文件的编码 -->
        <property name="javaFileEncoding" value="UTF-8"/>

        <!--beginningDelimiter和endingDelimiter:指明数据库的用于标记数据库对象名的符号,比如ORACLE就是双引号,MYSQL默认是`反引号;-->
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>

        <!--继承、注解-->
        <!--<plugin type="org.mybatis.generator.extension.LombokPlugin"/>-->
        <plugin type="tk.mybatis.mapper.generator.MapperPlugin">
            <property name="mappers" value="com.cloudrises.projectframework.common.BaseMapper"/>
        </plugin>
        <!--<plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>-->
        <plugin type="org.mybatis.generator.plugins.SerializablePlugin"/>
        <!--<plugin type="org.mybatis.generator.plugins.EqualsHashCodePlugin"/>-->
        <!--<commentGenerator type="org.mybatis.generator.extension.RemarksCommentGenerator">-->

        <commentGenerator>
            <!-- 格式化java代码 -->
            <property name="javaFormatter" value="org.mybatis.generator.api.dom.DefaultJavaFormatter"/>
            <!-- 格式化XML代码 -->
            <property name="xmlFormatter" value="org.mybatis.generator.api.dom.DefaultXmlFormatter"/>
            <!-- 是否禁止显示日期 true:是 : false:否 -->
            <property name="suppressDate" value="false"/>
            <!-- 是否去除自动生成的所有注释 true:是 : false:否 -->
            <property name="suppressAllComments" value="true"/>
            <!-- 是否添加字段注释 true:是 false:否 -->
            <property name="addRemarkComments" value="false"/>
        </commentGenerator>

        <!--MySql数据库连接的信息:驱动类、连接地址、用户名、密码 -->
        <!--<jdbcConnection driverClass="com.mysql.jdbc.Driver"-->
        <!--connectionURL="jdbc:mysql://47.104.16.79:3306/al74_connection"-->
        <!--userId="root" password="root">-->
        <!--<property name="useInformationSchema" value="true"/>-->
        <!--</jdbcConnection>-->

        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/cloudrises?tinyInt1isBit=false&amp;characterEncoding=utf-8"
                        userId="root" password="root">
            <property name="useInformationSchema" value="true"/>
        </jdbcConnection>

        <!-- java类型处理器
        用于处理DB中的类型到Java中的类型,默认使用JavaTypeResolverDefaultImpl;
        注意一点,默认会先尝试使用Integer,Long,Short等来对应DECIMAL和 NUMERIC数据类型;
        -->
        <!-- 默认false,把jdbc decimal 和 numeric 类型解析为 Integer,为 true时把jdbc decimal 和 numeric 类型解析为java.math.BigDecimal -->
        <javaTypeResolver>
            <!--
            true:使用BigDecimal对应DECIMAL和 NUMERIC数据类型
            false:默认,
                scale>0;length>18:使用BigDecimal;
                scale=0;length[10,18]:使用Long;
                scale=0;length[5,9]:使用Integer;
                scale=0;length<5:使用Short;
            -->
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>

        <!-- targetProject:生成PO实体类的位置 -->
        <javaModelGenerator targetPackage="com.study.model" targetProject="src/main/java">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="true"/>
            <!-- 从数据库返回的值被清理前后的空格 -->
            <property name="trimStrings" value="true"/>
            <!--<property name="rootClass" value="com.cqfae.pmo.hrm.app.dao.model.AbBaseDO"/>-->
        </javaModelGenerator>
        <!-- targetProject:mapper.xml映射文件生成的位置 -->
        <sqlMapGenerator targetPackage="/mybatis/mapper" targetProject="src/main/resources">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>

        <!--&lt;!&ndash; targetPackage:mapper接口生成的位置 &ndash;&gt;-->
        <javaClientGenerator targetPackage="com.study.dao" targetProject="src/main/java"
                             type="XMLMAPPER">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>

        <!-- 指定数据库表 -->
        <table tableName="sys_user" enableCountByExample="false"
               enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
        </table>

    </context>
</generatorConfiguration>

五. 代码层配置

1. 全局异常监控(处理异常发生后的数据返回)

package com.study.advice;

import com.study.enums.ResponseResultEnums;
import com.study.exceptions.CustomizeException;
import com.study.response.HttpResponse;
import org.apache.ibatis.session.SqlSessionException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;
import java.util.Calendar;

/**
 * 全局异常判断
 */
@ControllerAdvice
public class GolbalException {

    @ResponseBody
    @ExceptionHandler(Exception.class)
    public HttpResponse handleExceptions(HttpServletRequest request, HttpServletResponse response, Exception e){
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset = utf-8");
        Calendar calendar=Calendar.getInstance();
        String message = "";
        String code = ResponseResultEnums.ERROR.getCode();
        if (e instanceof NullPointerException){// 空指针异常
            message = "空指针异常";
        }else if(e instanceof HttpMediaTypeNotSupportedException){// 请求类型出错
            message = "不支持的内容格式出错";
        }else if (e instanceof MethodArgumentNotValidException){//swagger2注解判断抛出的异常
            MethodArgumentNotValidException me = (MethodArgumentNotValidException)e;
            message=me.getBindingResult().getAllErrors().get(0).getDefaultMessage();
        }else if (e instanceof IllegalArgumentException){
            IllegalArgumentException ie = (IllegalArgumentException) e;
            message = ie.getMessage();
        }else if (e instanceof SqlSessionException){// 数据库操作出错
            SqlSessionException se = (SqlSessionException)e;
            message = se.getMessage();
        }else if (e instanceof HttpRequestMethodNotSupportedException){
            HttpRequestMethodNotSupportedException he = (HttpRequestMethodNotSupportedException)e;
            message = he.getMessage();
        } else if (e instanceof ConstraintViolationException){// notnull等注解会出现的异常
            ConstraintViolationException me = (ConstraintViolationException)e;
            message=me.getMessage();
        }else if (e instanceof CustomizeException){
            CustomizeException ce = (CustomizeException)e;
            code = ce.getCode();
            message = ce.getMessage();
        }else {
            message = "发生全局异常";
        }
        System.out.println(calendar.getTime()+" : "+this.getClass().getName()+" : "+message);
        e.printStackTrace();
        return HttpResponse.success(code,message);
    }

}

2. 请求处理方法(前)监控(打印方法的参数名和参数值)

package com.study.advice;

import lombok.extern.log4j.Log4j2;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

@Aspect
@Component
@Log4j2
public class MvcMethodLogAdvice {

    @Resource
    private HttpServletRequest request;

    @Before("@annotation(org.springframework.web.bind.annotation.PostMapping)" +
            "||@annotation(org.springframework.web.bind.annotation.RequestMapping)" +
            "||@annotation(org.springframework.web.bind.annotation.GetMapping)")
    public void beforeAdvice(JoinPoint joinPoint) {
        printMethodParams(joinPoint);
    }

    /**
     * @param point
     * @description 打印方法的参数名和参数值
     */
    public void printMethodParams(JoinPoint point) {
        if (point == null) {
            return;
        }
        // Signature 包含了方法名、申明类型以及地址等信息
        // String className = point.getTarget().getClass().getName();
        // String methodName = point.getSignature().getName();
        // 获取方法的参数值数组。
        Object[] method_args = point.getArgs();
        // 获取方法参数名称
        String[] paramNames = ((MethodSignature) point.getSignature()).getParameterNames();
        logParam(paramNames, method_args);
    }

    /**
     * @param paramsArgsName  方法参数名数组
     * @param paramsArgsValue 方法参数值数组
     * @description 打印方法的参数名和参数值, 基本类型直接打印, 非基本类型需要重写toString方法
     */
    private void logParam(String[] paramsArgsName, Object[] paramsArgsValue) {
        if ((paramsArgsName == null || paramsArgsName.length <= 0) ||
                (paramsArgsValue == null || paramsArgsValue.length <= 0)) {
            log.info("url=[" + request.getRequestURL() + "]无请求参数");
            return;
        }
        StringBuffer buffer = new StringBuffer();
        buffer.append("{ ");
        for (int i = 0; i < paramsArgsName.length; i++) {
            String name = paramsArgsName[i];
            if (name.equals("session")) {
                continue;
            }
            Object value = paramsArgsValue[i];
            buffer.append(name + " : ");
            if (null == value) {
                buffer.append(null + " ,");
            } else if (isPrimite(value.getClass())) {
                buffer.append(value + " ,");
            } else {
                buffer.append(value.toString() + " ,");
            }
        }
        String logString = buffer.toString();
        if (logString.contains(",")) {
            logString = logString.substring(0, logString.lastIndexOf(","));
        }
        // buffer.deleteCharAt(buffer.lastIndexOf(","));
        // buffer.append("}");
        logString += "}";
        log.info("url=[" + request.getRequestURL() + "]请求参数为: \033[35;0m" + logString + "\033[0m");
    }

    /**
     * @param clazz
     * @return
     * @description 判断是否为基本类型:包括String
     */
    private boolean isPrimite(Class<?> clazz) {
        if (clazz.isPrimitive() || clazz == String.class) {
            return true;
        } else {
            return false;
        }
    }
}

3. 请求处理方法(后)监控(打印返回结果)

package com.study.advice;

import com.study.utils.JsonUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.log4j.Log4j2;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

@Log4j2
@ControllerAdvice(basePackages = "com.study")
public class LogResponseAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
                                  ServerHttpResponse response) {
        try {
            log.info("url=[" + request.getURI() + "]请求返回的结果为:" + JsonUtils.Object2json(body));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return body;
    }
}

4. BaseMapper用于mybatis逆向工程生成的xml文件继承

package com.study.common;

import tk.mybatis.mapper.annotation.RegisterMapper;
import tk.mybatis.mapper.common.ExampleMapper;
import tk.mybatis.mapper.common.IdsMapper;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;

/**
 * @author lzr
 * @date 2019/3/26 0026 09:38
 */
@RegisterMapper
public interface BaseMapper<T> extends Mapper<T>, MySqlMapper<T>, IdsMapper<T>, ExampleMapper<T> {
}

5. BasePage通用分页参数类

package com.study.common;

import lombok.Data;
import lombok.ToString;

import java.io.Serializable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Data
@ToString
public class BasePage implements Serializable {
    
    /**
     * 每页条数
     */
    private Integer pageSize = 10;
    /**
     * 当前页数
     */
    private Integer pageNum = 1;
    /**
     * 排序字段
     */
    private String orderField;
    /**
     * 正序还是倒序
     */
    private String order;

    public String createOrderSql() {
        if (this.orderField != null) {
            return camelToUnderline(new StringBuffer(this.orderField)).append(" " + order).toString();
        }
        return "";
    }

    /**
     * 下划线转驼峰
     *
     * @param str
     * @return
     */
    public static StringBuffer underlineToCamel(StringBuffer str) {
        //利用正则删除下划线,把下划线后一位改成大写
        Pattern pattern = Pattern.compile("_(\\w)");
        Matcher matcher = pattern.matcher(str);
        StringBuffer sb = new StringBuffer(str);
        if (matcher.find()) {
            sb = new StringBuffer();
            //将当前匹配子串替换为指定字符串,并且将替换后的子串以及其之前到上次匹配子串之后的字符串段添加到一个StringBuffer对象里。
            //正则之前的字符和被替换的字符
            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
            //把之后的也添加到StringBuffer对象里
            matcher.appendTail(sb);
        } else {
            return sb;
        }
        return underlineToCamel(sb);
    }


    /**
     * 驼峰转下划线
     *
     * @param str
     * @return
     */
    private static StringBuffer camelToUnderline(StringBuffer str) {
        Pattern pattern = Pattern.compile("[A-Z]");
        Matcher matcher = pattern.matcher(str);
        StringBuffer sb = new StringBuffer(str);
        if (matcher.find()) {
            sb = new StringBuffer();
            //将当前匹配子串替换为指定字符串,并且将替换后的子串以及其之前到上次匹配子串之后的字符串段添加到一个StringBuffer对象里。
            //正则之前的字符和被替换的字符
            matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
            //把之后的也添加到StringBuffer对象里
            matcher.appendTail(sb);
        } else {
            return sb;
        }
        return camelToUnderline(sb);
    }
}

6. PageResult通用分页查询结果包装类

package com.study.common;


import com.github.pagehelper.Page;
import lombok.Data;
import lombok.ToString;

import java.util.List;

@Data
@ToString
public class PageResult<T> {

    public PageResult(Page<T> page) {
        this.pageNum = page.getPageNum();
        this.pageSize = page.getPageSize();
        this.total = page.getTotal();
        this.pages = page.getPages();
        this.result = page.getResult();
    }

    /**
     * 当前页数
     */
    private Integer pageNum;
    /**
     * 每页条数
     */
    private Integer pageSize;
    /**
     * 总条数
     */
    private long total;
    /**
     * 总页数
     */
    private Integer pages;
    /**
     * 数据
     */
    private List<T> result;

}

7. 异步线程池配置类

package com.study.config;

import com.study.exceptions.MyAsyncUncaughtExceptionHandler;
import lombok.extern.log4j.Log4j2;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 自定义线程池 (java的异步,常用于<strong>多线程开发</strong>)
 * 异步线程池配置
 * @Async注解无效的可能点:
 * 1、异步方法使用static修饰
 * 2、异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类
 * 3、测试异步方法不能与异步方法在同一个类中
 * 4、测试类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
 * 5、如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解
 */
@Configuration
@Log4j2
public class AsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);// 最小线程数为10(核心线程池大小)
        executor.setMaxPoolSize(100);// 最大线程数为100
        executor.setQueueCapacity(100);// 队列最大数量为100
        executor.setKeepAliveSeconds(20);// 当线程空闲20秒(活跃时间,默认情况下是60秒)时回收线程时
        executor.setThreadNamePrefix("cloudrises-async-schedule-");// 线程的前置名称
        // setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务
        // CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //如果不初始化,导致找到不到执行器
        executor.initialize();
        return executor;
    }

    /**
     * 异步任务中处理异常
     */
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new MyAsyncUncaughtExceptionHandler();
    }

}

8. redis配置类

package com.study.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
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;

@Configuration
public class RedisConfiguration {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 使用Jackson2JsonRedisSerialize 替换默认序列化
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        // 设置value的序列化规则和 key的序列化规则
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setKeySerializer(new StringRedisSerializer());// 定义key序列化
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

9. swagger2配置类

package com.study.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
//@ConditionalOnProperty(prefix = "swagger2",value = {"enable"},havingValue = "true")
public class Swagger2 {

    // swagger2.enable是application中的配置(自己添加"swagger2.enable=true")
    @Value("${swagger2.enable}")
    private boolean externallyConfiguredFlag;

    //swagger2的配置文件,这里可以配置swagger2的一些基本的内容,比如扫描的包等等
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(externallyConfiguredFlag)
                .apiInfo(apiInfo())
                .select()
                //为当前包路径
                .apis(RequestHandlerSelectors.basePackage("com.cloudrises.projectframework.logic.controller"))
                .paths(PathSelectors.any())
                .build();
    }
    //构建 api文档的详细信息函数,注意这里的注解引用的是哪个
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                //页面标题
                .title("工程项目请求路径")
                //创建人
                .contact(new Contact("柳正润", "http://www.baidu.com", "1640071746@qq.com"))
                //版本号
                .version("1.0")
                //描述
                .description("项目框架")
                .build();
    }
 
 
}

10. 信息枚举类

package com.study.enums;

/**
 * @author lzr
 * @date 2019/3/27 0027 14:48
 */
public enum ResponseResultEnums {

    SUCCESS("1","请求成功"),
    FAIL("-1","请求失败"),
    ERROR("-9","系统错误");

    private String code;// code码
    private String msg;// 消息

    ResponseResultEnums(String code, String msg){this.code=code;this.msg=msg;}

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

11. 自定义全局异常类

package com.study.exceptions;

import com.study.enums.ResponseResultEnums;
import lombok.Data;

/**
 * @author lzr
 * @date 2019/5/13 0013 17:01
 */
@Data
public class CustomizeException extends RuntimeException{

    private String code;

    public CustomizeException(String message) {
        super(message);
    }

    public CustomizeException(String code, String message) {
        super(message);
        this.code = code;
    }

    public CustomizeException(ResponseResultEnums responseResultEnums){
        super(responseResultEnums.getMsg());
        this.code = responseResultEnums.getCode();
    }

}

12. 自定义异步操作异常类

package com.study.exceptions;

import lombok.extern.log4j.Log4j2;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;

import java.lang.reflect.Method;

/**
 * 异步操作,异常处理
 * lzr
 * MyAsyncUncaughtExceptionHandler
 */
@Log4j2
public class MyAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {

    @Override
    public void handleUncaughtException(Throwable ex, Method method, Object... params) {
        log.error("ex=",ex,",方法名称",method.getName(),",参数",params.toString());
    }
}

13. 消息返回包装类

package com.study.response;

import com.study.exceptions.CustomizeException;
import com.study.enums.ResponseResultEnums;
import lombok.AllArgsConstructor;
import lombok.Data;

import java.io.Serializable;

/**
 * @author lzr
 * @date 2019/11/11 0027 14:28
 */
@Data
@AllArgsConstructor
public class HttpResponse implements Serializable {

    private String code;

    private String msg;

    private Object data;

    public static HttpResponse success() {
        return success(null);
    }

    public static HttpResponse success(Object data) {
        return success(ResponseResultEnums.SUCCESS.getCode(), ResponseResultEnums.SUCCESS.getMsg(), data);
    }

    public static HttpResponse success(String code, String msg) {
        return success(code, msg, null);
    }

    public static HttpResponse success(String msg, Object data) {
        return success(ResponseResultEnums.SUCCESS.getCode(), msg, data);
    }

    private static HttpResponse success(String code, String msg, Object data) {
        return new HttpResponse(code, msg, data);
    }

    public static HttpResponse fail(String code, String msg) {
        throw new CustomizeException(code,msg);
    }

    public static HttpResponse fail(String msg){
        throw new CustomizeException(ResponseResultEnums.FAIL.getCode(), msg);
    }

    public static HttpResponse fail(ResponseResultEnums responseResultEnums){
        throw new CustomizeException(responseResultEnums.getCode(),responseResultEnums.getMsg());
    }

    public static HttpResponse fail(){
        throw new CustomizeException(ResponseResultEnums.FAIL);
    }

    /**
     * 只用于过滤器 返回数据
     */
    public static HttpResponse filterData(ResponseResultEnums responseResultEnums){
        return HttpResponse.success(responseResultEnums.getCode(),responseResultEnums.getMsg());
    }

}

14. Json转化类

package com.study.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.log4j.Log4j2;

import javax.servlet.ServletRequest;
import java.io.BufferedReader;
import java.io.IOException;


@Log4j2
public class JsonUtils {

    public static ObjectMapper objectMapper = new ObjectMapper();

    public static String Object2json(Object object) throws JsonProcessingException {
        return objectMapper.writeValueAsString(object);
    }

    public static <T> T json2Object(String json, Class<T> valueType) throws IOException {
        return objectMapper.readValue(json, valueType);
    }

}

14. 启动类

package com.study;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author lzr
 * @date 2019/11/11 0011 17:18
 */
 @MapperScan("com.study.dao")// 扫描mapper接口文件,注意引入的包是:“tk.mybatis.spring.annotation.MapperScan”
@EnableScheduling// 开启定时器线程
@EnableAsync// 开启异步操作
@SpringBootApplication
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class,args);
    }

}

六. 易忽略点

  1. 调用异步方法的时候,不能在同一类文件内
  2. @MapperScan(“com.study.dao”)// 扫描mapper接口文件,注意引入的包是:“tk.mybatis.spring.annotation.MapperScan”,(使用分页)

七. 项目地址

git@github.com:liuzhengrun/study_singleframework.git

若有疑问,请在评论区留言,谢谢

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值