Kotlin服务端Spring Boot系列干货教程2 - 框架整合

框架整合,整合MyBatis/MyBatis-Plus、Log4j2、Generator代码生成、Druid连接池、Freemarker等

ChMkJlnJ4TOIAyeVAJqtjV-XTiAAAgzDAE7v40Amq2l708.jpg

1. pom.xml中引入相关jar包

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>me.forxx.springboot4kt</groupId>
	<artifactId>springboot4kt</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<name>springboot4kt</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.9.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<kotlin.version>1.1.61</kotlin.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.jetbrains.kotlin</groupId>
			<artifactId>kotlin-stdlib-jre8</artifactId>
			<version>${kotlin.version}</version>
		</dependency>
		<dependency>
			<groupId>org.jetbrains.kotlin</groupId>
			<artifactId>kotlin-reflect</artifactId>
			<version>${kotlin.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>

		<!--mysql-->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<!--json-->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.41</version>
		</dependency>
		<!--druid连接池-->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid-spring-boot-starter</artifactId>
			<version>1.1.6</version>
		</dependency>
		<!--log4j2-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-log4j2</artifactId>
		</dependency>
		<!--用于log4j2日志的异步存储-->
		<dependency>
			<groupId>com.lmax</groupId>
			<artifactId>disruptor</artifactId>
			<version>3.3.7</version>
		</dependency>
		<!--mybatis-->
		<!--<dependency>-->
			<!--<groupId>org.mybatis.spring.boot</groupId>-->
			<!--<artifactId>mybatis-spring-boot-starter</artifactId>-->
			<!--<version>1.3.0</version>-->
		<!--</dependency>-->
		<!--mybatis-plus-->
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatisplus-spring-boot-starter</artifactId>
			<version>1.0.5</version>
		</dependency>
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus</artifactId>
			<version>2.1.7</version>
		</dependency>
		<!--分页插件-->
		<dependency>
			<groupId>com.github.pagehelper</groupId>
			<artifactId>pagehelper-spring-boot-starter</artifactId>
			<version>1.2.3</version>
		</dependency>
		<!--开启 cache 缓存-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-cache</artifactId>
		</dependency>
		<!-- ehcache 缓存 -->
		<dependency>
			<groupId>net.sf.ehcache</groupId>
			<artifactId>ehcache</artifactId>
		</dependency>
		<!--freemarker模板-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-freemarker</artifactId>
		</dependency>

	</dependencies>

	<build>
		<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
		<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
			<plugin>
				<artifactId>kotlin-maven-plugin</artifactId>
				<groupId>org.jetbrains.kotlin</groupId>
				<version>${kotlin.version}</version>
				<configuration>
					<compilerPlugins>
						<plugin>spring</plugin>
					</compilerPlugins>
					<jvmTarget>1.8</jvmTarget>
				</configuration>
				<executions>
					<execution>
						<id>compile</id>
						<phase>compile</phase>
						<goals>
							<goal>compile</goal>
						</goals>
					</execution>
					<execution>
						<id>test-compile</id>
						<phase>test-compile</phase>
						<goals>
							<goal>test-compile</goal>
						</goals>
					</execution>
				</executions>
				<dependencies>
					<dependency>
						<groupId>org.jetbrains.kotlin</groupId>
						<artifactId>kotlin-maven-allopen</artifactId>
						<version>${kotlin.version}</version>
					</dependency>
				</dependencies>
			</plugin>
			<plugin>
				<groupId>org.mybatis.generator</groupId>
				<artifactId>mybatis-generator-maven-plugin</artifactId>
				<version>1.3.5</version>
				<dependencies>
					<dependency>
						<groupId>com.kecikeci</groupId>
						<artifactId>mybatis-generator-kecikeci</artifactId>
						<version>1.0</version>
						<scope>system</scope>
						<systemPath>${project.basedir}/src/main/resources/mybatis-generator-kecikeci.jar</systemPath>
					</dependency>
				</dependencies>
			</plugin>
		</plugins>
	</build>


</project>

2. application.properties配置

## druid基础配置
spring.datasource.druid.url=jdbc:mysql://127.0.0.1:3306/springboot4kt?useUnicode=true&characterEncoding=utf-8
spring.datasource.druid.username=root
spring.datasource.druid.password=root
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
## 连接池配置
spring.datasource.druid.initial-size=5
spring.datasource.druid.max-active=30
spring.datasource.druid.min-idle=5
spring.datasource.druid.max-wait=60000
spring.datasource.druid.pool-prepared-statements=true
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
spring.datasource.druid.max-open-prepared-statements=20
spring.datasource.druid.validation-query=SELECT 1
spring.datasource.druid.validation-query-timeout=30000
spring.datasource.druid.test-on-borrow=true
spring.datasource.druid.test-on-return=false
spring.datasource.druid.test-while-idle=false
## 监控配置
spring.datasource.druid.filters=stat,wall,log4j2
spring.datasource.druid.web-stat-filter.enabled=true 
spring.datasource.druid.web-stat-filter.url-pattern=/druid/*
spring.datasource.druid.web-stat-filter.profile-enable=true
spring.datasource.druid.web-stat-filter.exclusions=*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*
## StatViewServlet配置
spring.datasource.druid.stat-view-servlet.enabled=true
spring.datasource.druid.stat-view-servlet.url-pattern=/druid/*
spring.datasource.druid.stat-view-servlet.reset-enable=true
spring.datasource.druid.stat-view-servlet.login-username=admin
spring.datasource.druid.stat-view-servlet.login-password=forxx
## Spring监控配置
spring.datasource.druid.aop-patterns=me.forxx.springboot4kt.service..*(..),me.forxx.springboot4kt.web..*(..)
spring.aop.proxy-target-class=true

#log4j2
logging.config=classpath:log4j2.xml

#mybatis
#mybatis.type-aliases-package=me.forxx.springboot4kt.dao
#mybatis.mapperLocations=classpath:/mapper/*.xml
#mybatis和mybatis-plus 2选1
#mybatis-plus
mybatis-plus.mapper-locations=classpath:/mapper/*.xml
mybatis-plus.type-aliases-package=me.forxx.springboot4kt.dao
#刷新mapper 调试神器
mybatis-plus.global-config.refresh-mapper=true

3. log4j2.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF" debug="off" monitorInterval="1800">
    <Properties>
        <property name="LOG_HOME_ERROR">/data/logs/</property>
        <property name="FILE_NAME_ERROR">springboot4kt_logs_error</property>
        <property name="LOG_HOME_INFO">/data/logs/</property>
        <property name="FILE_NAME_INFO">springboot4kt_logs</property>
    </Properties>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>
            <!-- 输出日志的格式 -->
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>

        <RollingFile name="app_info" fileName="${LOG_HOME_INFO}/${FILE_NAME_INFO}.log" immediateFlush="false" filePattern="${LOG_HOME_INFO}/$${date:yyyy-MM}/${FILE_NAME_INFO}-%d{yyyy-MM-dd}-%i.log.gz">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} %L %M - %msg%xEx%n" />
            <Policies>
                <TimeBasedTriggeringPolicy interval="6" modulate="true" />
                <SizeBasedTriggeringPolicy size="50 MB"/>
            </Policies>
            <Filters>
                <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />
            </Filters>
            <DefaultRolloverStrategy max="50"/>
        </RollingFile>

        <RollingFile name="app_error" fileName="${LOG_HOME_ERROR}/${FILE_NAME_ERROR}.log" immediateFlush="false" filePattern="${LOG_HOME_ERROR}/$${date:yyyy-MM}/${FILE_NAME_ERROR}-%d{yyyy-MM-dd}-%i.log.gz">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} %L %M - %msg%xEx%n" />
            <Policies>
                <TimeBasedTriggeringPolicy interval="6" modulate="true" />
                <SizeBasedTriggeringPolicy size="50 MB"/>
            </Policies>
            <Filters>
                <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY" />
            </Filters>
            <DefaultRolloverStrategy max="50"/>
        </RollingFile>

    </Appenders>
    <Loggers>
        <Logger name="org.springframework" level="error" additivity="false">
            <appender-ref ref="Console"/>
            <appender-ref ref="app_error"/>
        </Logger>
        <Logger name="org.apache.ibatis" level="error" additivity="false">
            <appender-ref ref="Console"/>
            <appender-ref ref="app_error"/>
        </Logger>
        <Logger name="org.mybatis" level="error" additivity="false">
            <appender-ref ref="Console"/>
            <appender-ref ref="app_error"/>
        </Logger>
        <Logger name="me.forxx.springboot4kt" level="debug" additivity="false">
            <appender-ref ref="Console"/>
            <appender-ref ref="app_info"/>
        </Logger>
        <!-- AsyncRoot - 异步记录日志 - 需要LMAX Disruptor的支持 -->
        <AsyncRoot level="info" additivity="false">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="app_info"/>
            <AppenderRef ref="app_error"/>
        </AsyncRoot>

    </Loggers>
</configuration>

4. Springboot4ktApplication中开启自动配置注解

@SpringBootApplication
@EnableCaching
@MapperScan("me.forxx.springboot4kt.dao")
@EnableScheduling
class Springboot4ktApplication

fun main(args: Array<String>) {
    SpringApplication.run(Springboot4ktApplication::class.java, *args)
}

5. Aop日志记录类构建

package me.forxx.springboot4kt.aop;


import com.alibaba.fastjson.JSON;
import me.forxx.springboot4kt.util.Util;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

/**
 * Created by GaoMingQiang on 2017/12/12 0019 11:19.
 */
@Component
@Aspect
public class Logs {

    private Logger log = LogManager.getLogger();
    @Autowired
    private HttpServletRequest res;

    @Before("execution(* me.forxx.springboot4kt.service..*(..)) || execution(* me.forxx.springboot4kt.web..*(..))")
    public void before(JoinPoint join){
        StringBuffer userName = new StringBuffer("游客");
        String ip = Util.getIp(res);
        String className = join.getTarget().getClass().getName();
        String function = join.getSignature().getName();
        String args = Arrays.asList(join.getArgs()).toString();
        StringBuffer msg = new StringBuffer();
        msg.append("当前用户 【");
        msg.append(userName);
        msg.append("】 IP 【");
        msg.append(ip);
        msg.append("】 正在访问 【类:<");
        msg.append(className);
        msg.append(">,方法:<");
        msg.append(function);
        msg.append(">,参数:<");
        msg.append(args);
        msg.append(">】");
        log.info(msg);
    }

    @AfterThrowing(pointcut="execution(* me.forxx.springboot4kt.service..*(..)) || execution(* me.forxx.springboot4kt.web..*(..))",throwing="e")
    public void exception(JoinPoint join, Exception e) {
        StringBuffer userName = new StringBuffer("游客");
        String ip = Util.getIp(res);
        String className = join.getTarget().getClass().getName();
        String function = join.getSignature().getName();
        String args = Arrays.asList(join.getArgs()).toString();
        StringBuffer msg = new StringBuffer();
        //记录报错内容
        StackTraceElement[] elems = e.getStackTrace();
        String text = "\n";
        for(StackTraceElement elem : elems) {
            text +=  "\t"+elem.toString()+"\n";
        }
        msg.append("当前用户 【");
        msg.append(userName);
        msg.append("】 IP 【");
        msg.append(ip);
        msg.append("】 正在访问 【类:<");
        msg.append(className);
        msg.append(">,方法:<");
        msg.append(function);
        msg.append(">,参数:<");
        msg.append(args);
        msg.append(">】 出现异常:【");
        msg.append(e.toString());
        msg.append("】 \n\t >> ------------------ 异常详情 -----------------<< \n");
        msg.append(text);
        log.error(msg);

        StringBuffer msgs = new StringBuffer();
        msgs.append("当前用户 【");
        msgs.append(userName);
        msgs.append("】 IP 【");
        msgs.append(ip);
        msgs.append("】 正在访问 【类:<");
        msgs.append(className);
        msgs.append(">,方法:<");
        msgs.append(function);
        msgs.append(">,参数:<");
        msgs.append(args);
        msgs.append(">】 出现异常:【");
        msgs.append(e.toString());
        msgs.append("】");
        log.info(msgs);
    }

    @AfterReturning(returning = "result",pointcut = "execution(* me.forxx.springboot4kt.service..*(..)) || execution(* me.forxx.springboot4kt.web..*(..))")
    public void After(JoinPoint join, Object result){
        StringBuffer userName = new StringBuffer("游客");
        String ip = Util.getIp(res);
        String className = join.getTarget().getClass().getName();
        String function = join.getSignature().getName();
        String args = JSON.toJSONString(result);
        StringBuffer msg = new StringBuffer();
        msg.append("当前用户 【");
        msg.append(userName);
        msg.append("】 IP 【");
        msg.append(ip);
        msg.append("】 返回结果 【类:<");
        msg.append(className);
        msg.append(">,方法:<");
        msg.append(function);
        msg.append(">,结果:<");
        msg.append(args);
        msg.append(">】");
        log.info(msg);
    }

}

QQ截图20171214150703.png


GitHub源码地址:https://github.com/kecikeci/springboot4kt

Gitee码云地址:https://gitee.com/kecikeci/springboot4kt