@@ -1,6 +1,6 @@ | |||
# Spring Boot Demo | |||
spring boot demo 是一个用来学习 spring boot 的项目,已经集成 actuator(监控)、logback(日志)、JPA(ORM 框架)、mybatis(ORM 框架)、redis-cache(缓存)、swagger(API 接口管理测试)、ureport2(中国式报表)模块,后续会集成activemq,email, freemarker,shiro,websocket,quartz,netty等模块。 | |||
spring boot demo 是一个用来学习 spring boot 的项目,已经集成 actuator(监控)、admin(可视化监控)、logback(日志)、aopLog(通过 AOP 记录 web 请求日志)、JPA(ORM 框架)、mybatis(ORM 框架)、redis-cache(缓存)、swagger(API 接口管理测试)、ureport2(中国式报表)模块,后续会集成activemq,email, freemarker,shiro,websocket,quartz,netty等模块。 | |||
依赖的 Spring Boot 版本: | |||
@@ -50,6 +50,7 @@ spring boot demo 是一个用来学习 spring boot 的项目,已经集成 actu | |||
<module>../spring-boot-demo-actuator</module> | |||
<module>../spring-boot-demo-admin</module> | |||
<module>../spring-boot-demo-logback</module> | |||
<module>../spring-boot-demo-aoplog</module> | |||
<module>../spring-boot-demo-orm-jpa</module> | |||
<module>../spring-boot-demo-orm-mybatis</module> | |||
<module>../spring-boot-demo-cache-redis</module> | |||
@@ -146,6 +147,7 @@ spring boot demo 是一个用来学习 spring boot 的项目,已经集成 actu | |||
| [spring-boot-demo-actuator](./spring-boot-demo-actuator) | spring-boot 集成 spring-boot-starter-actuator 用于监控 spring-boot 的启动和运行状态 | | |||
| [spring-boot-demo-admin](./spring-boot-demo-admin) | spring-boot 集成 spring-boot-admin 来可视化的监控 spring-boot 程序的运行状态,可以与 actuator 互相搭配使用 | | |||
| [spring-boot-demo-logback](./spring-boot-demo-logback) | spring-boot 集成 logback 日志 | | |||
| [spring-boot-demo-aoplog](./spring-boot-demo-aoplog) | spring-boot 使用 AOP 切面的方式记录 web 请求日志 | | |||
| [spring-boot-demo-orm-jpa](./spring-boot-demo-orm-jpa) | spring-boot 集成 spring-boot-starter-data-jpa 操作数据库 | | |||
| [spring-boot-demo-orm-mybatis](./spring-boot-demo-orm-mybatis) | spring-boot 集成 [mybatis-spring-boot-starter](https://github.com/mybatis/spring-boot-starter)、[mybatis-spring-boot-starter](https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter) | | |||
| [spring-boot-demo-cache-redis](./spring-boot-demo-cache-redis) | spring-boot 使用 Redis 做缓存 | | |||
@@ -7,7 +7,7 @@ | |||
- [x] ~~spring-boot-demo-actuator(对 Spring boot 的端点监控)~~ | |||
- [x] ~~spring-boot-demo-admin(对 Spring boot 可视化管控)~~ | |||
- [x] ~~spring-boot-demo-logback(集成 logback 日志)~~ | |||
- [ ] spring-boot-demo-aopLog(使用 AOP 拦截请求日志信息) | |||
- [ ] spring-boot-demo-aoplog(使用 AOP 拦截请求日志信息) | |||
- [ ] spring-boot-demo-exceptionHandler(统一异常处理) | |||
- [ ] spring-boot-demo-orm-jdbcTemplate(操作 SQL 关系型数据库 - JdbcTemplate) | |||
- [x] ~~spring-boot-demo-orm-jpa(操作 SQL 关系型数据库 - JPA)~~ | |||
@@ -0,0 +1,168 @@ | |||
# spring-boot-demo-aoplog | |||
依赖[spring-boot-demo-parent](../spring-boot-demo-parent)、`spring-boot-starter-aop` | |||
### pom.xml | |||
```xml | |||
<?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> | |||
<artifactId>spring-boot-demo-aoplog</artifactId> | |||
<version>0.0.1-SNAPSHOT</version> | |||
<packaging>jar</packaging> | |||
<name>spring-boot-demo-aoplog</name> | |||
<description>Demo project for Spring Boot</description> | |||
<parent> | |||
<groupId>com.xkcoding</groupId> | |||
<artifactId>spring-boot-demo-parent</artifactId> | |||
<version>0.0.1-SNAPSHOT</version> | |||
<relativePath>../spring-boot-demo-parent/pom.xml</relativePath> | |||
</parent> | |||
<properties> | |||
<useragent.version>1.20</useragent.version> | |||
</properties> | |||
<dependencies> | |||
<dependency> | |||
<groupId>org.springframework.boot</groupId> | |||
<artifactId>spring-boot-starter-aop</artifactId> | |||
</dependency> | |||
<!--UserAgent工具类--> | |||
<dependency> | |||
<groupId>eu.bitwalker</groupId> | |||
<artifactId>UserAgentUtils</artifactId> | |||
<version>${useragent.version}</version> | |||
</dependency> | |||
</dependencies> | |||
<build> | |||
<finalName>spring-boot-demo-aoplog</finalName> | |||
</build> | |||
</project> | |||
``` | |||
### AopLog.java | |||
```java | |||
/** | |||
* aop 切面记录请求日志 | |||
* | |||
* @package: com.xkcoding.springbootdemoaoplog.aspectj | |||
* @description:aop 切面记录请求日志 | |||
* @author: yangkai.shen | |||
* @date: Created in 2017/11/24 上午9:43 | |||
* @copyright: Copyright (c) 2017 | |||
* @version: 0.0.1 | |||
* @modified: yangkai.shen | |||
*/ | |||
@Aspect | |||
@Component | |||
@Slf4j | |||
public class AopLog { | |||
private static final String START_TIME = "start-request"; | |||
@Pointcut("execution(public * com.xkcoding.springbootdemoaoplog.controller.*Controller.*(..))") | |||
public void log() { | |||
} | |||
@Before("log()") | |||
public void beforeLog(JoinPoint joinPoint) { | |||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); | |||
HttpServletRequest request = attributes.getRequest(); | |||
log.info("【请求 URL】:{}", request.getRequestURL()); | |||
log.info("【请求 IP】:{}", request.getRemoteAddr()); | |||
log.info("【请求类名】:{},【请求方法名】:{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName()); | |||
Map parameterMap = request.getParameterMap(); | |||
log.info("【请求参数】:{},", JsonMapper.obj2Str(parameterMap)); | |||
Long start = System.currentTimeMillis(); | |||
request.setAttribute(START_TIME, start); | |||
} | |||
@Around("log()") | |||
public Object arroundLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { | |||
Object result = proceedingJoinPoint.proceed(); | |||
log.info("【返回值】:{}", JsonMapper.obj2Str(result)); | |||
return result; | |||
} | |||
@AfterReturning("log()") | |||
public void afterReturning(JoinPoint joinPoint) { | |||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); | |||
HttpServletRequest request = attributes.getRequest(); | |||
Long start = (Long) request.getAttribute(START_TIME); | |||
Long end = System.currentTimeMillis(); | |||
log.info("【请求耗时】:{}毫秒", end - start); | |||
String header = request.getHeader("User-Agent"); | |||
UserAgent userAgent = UserAgent.parseUserAgentString(header); | |||
log.info("【浏览器类型】:{},【操作系统】:{},【原始User-Agent】:{}", userAgent.getBrowser().toString(), userAgent.getOperatingSystem().toString(), header); | |||
} | |||
} | |||
``` | |||
### JsonMapper.java | |||
```java | |||
/** | |||
* Json 转化工具类 | |||
* | |||
* @package: com.xkcoding.springbootdemoaoplog.util | |||
* @description:Json 转化工具类 | |||
* @author: yangkai.shen | |||
* @date: Created in 2017/11/24 上午9:36 | |||
* @copyright: Copyright (c) 2017 | |||
* @version: 0.0.1 | |||
* @modified: yangkai.shen | |||
*/ | |||
@Slf4j | |||
public class JsonMapper { | |||
private static ObjectMapper objectMapper = new ObjectMapper(); | |||
/** | |||
* 对象转 json 字符串 | |||
* | |||
* @param src 元对象 | |||
* @param <T> 类型 | |||
* @return json 字符串 | |||
*/ | |||
public static <T> String obj2Str(T src) { | |||
if (src == null) { | |||
return null; | |||
} | |||
try { | |||
return src instanceof String ? (String) src : objectMapper.writeValueAsString(src); | |||
} catch (IOException e) { | |||
log.error("【JSON 转换:对象 --> 字符串】,异常堆栈:{}", e); | |||
return null; | |||
} | |||
} | |||
/** | |||
* json 字符串转化为对象 | |||
* | |||
* @param src 源 json 字符串 | |||
* @param typeReference 转化后的类型 | |||
* @param <T> 类型 | |||
* @return 返回转化后的对象 | |||
*/ | |||
public static <T> T str2Obj(String src, TypeReference<T> typeReference) { | |||
if (src == null || typeReference == null) { | |||
return null; | |||
} | |||
try { | |||
return (T) (typeReference.getType().equals(String.class) ? src : objectMapper.readValue(src, typeReference)); | |||
} catch (Exception e) { | |||
log.error("【JSON 转换:字符串 --> 对象】,异常堆栈:{}", e); | |||
return null; | |||
} | |||
} | |||
} | |||
``` | |||
@@ -0,0 +1,41 @@ | |||
<?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> | |||
<artifactId>spring-boot-demo-aoplog</artifactId> | |||
<version>0.0.1-SNAPSHOT</version> | |||
<packaging>jar</packaging> | |||
<name>spring-boot-demo-aoplog</name> | |||
<description>Demo project for Spring Boot</description> | |||
<parent> | |||
<groupId>com.xkcoding</groupId> | |||
<artifactId>spring-boot-demo-parent</artifactId> | |||
<version>0.0.1-SNAPSHOT</version> | |||
<relativePath>../spring-boot-demo-parent/pom.xml</relativePath> | |||
</parent> | |||
<properties> | |||
<useragent.version>1.20</useragent.version> | |||
</properties> | |||
<dependencies> | |||
<dependency> | |||
<groupId>org.springframework.boot</groupId> | |||
<artifactId>spring-boot-starter-aop</artifactId> | |||
</dependency> | |||
<!--UserAgent工具类--> | |||
<dependency> | |||
<groupId>eu.bitwalker</groupId> | |||
<artifactId>UserAgentUtils</artifactId> | |||
<version>${useragent.version}</version> | |||
</dependency> | |||
</dependencies> | |||
<build> | |||
<finalName>spring-boot-demo-aoplog</finalName> | |||
</build> | |||
</project> |
@@ -0,0 +1,12 @@ | |||
package com.xkcoding.springbootdemoaoplog; | |||
import org.springframework.boot.SpringApplication; | |||
import org.springframework.boot.autoconfigure.SpringBootApplication; | |||
@SpringBootApplication | |||
public class SpringBootDemoAoplogApplication { | |||
public static void main(String[] args) { | |||
SpringApplication.run(SpringBootDemoAoplogApplication.class, args); | |||
} | |||
} |
@@ -0,0 +1,69 @@ | |||
package com.xkcoding.springbootdemoaoplog.aspectj; | |||
import com.xkcoding.springbootdemoaoplog.util.JsonMapper; | |||
import eu.bitwalker.useragentutils.UserAgent; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.aspectj.lang.JoinPoint; | |||
import org.aspectj.lang.ProceedingJoinPoint; | |||
import org.aspectj.lang.annotation.*; | |||
import org.springframework.stereotype.Component; | |||
import org.springframework.web.context.request.RequestContextHolder; | |||
import org.springframework.web.context.request.ServletRequestAttributes; | |||
import javax.servlet.http.HttpServletRequest; | |||
import java.util.Map; | |||
/** | |||
* aop 切面记录请求日志 | |||
* | |||
* @package: com.xkcoding.springbootdemoaoplog.aspectj | |||
* @description:aop 切面记录请求日志 | |||
* @author: yangkai.shen | |||
* @date: Created in 2017/11/24 上午9:43 | |||
* @copyright: Copyright (c) 2017 | |||
* @version: 0.0.1 | |||
* @modified: yangkai.shen | |||
*/ | |||
@Aspect | |||
@Component | |||
@Slf4j | |||
public class AopLog { | |||
private static final String START_TIME = "start-request"; | |||
@Pointcut("execution(public * com.xkcoding.springbootdemoaoplog.controller.*Controller.*(..))") | |||
public void log() { | |||
} | |||
@Before("log()") | |||
public void beforeLog(JoinPoint joinPoint) { | |||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); | |||
HttpServletRequest request = attributes.getRequest(); | |||
log.info("【请求 URL】:{}", request.getRequestURL()); | |||
log.info("【请求 IP】:{}", request.getRemoteAddr()); | |||
log.info("【请求类名】:{},【请求方法名】:{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName()); | |||
Map parameterMap = request.getParameterMap(); | |||
log.info("【请求参数】:{},", JsonMapper.obj2Str(parameterMap)); | |||
Long start = System.currentTimeMillis(); | |||
request.setAttribute(START_TIME, start); | |||
} | |||
@Around("log()") | |||
public Object arroundLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { | |||
Object result = proceedingJoinPoint.proceed(); | |||
log.info("【返回值】:{}", JsonMapper.obj2Str(result)); | |||
return result; | |||
} | |||
@AfterReturning("log()") | |||
public void afterReturning(JoinPoint joinPoint) { | |||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); | |||
HttpServletRequest request = attributes.getRequest(); | |||
Long start = (Long) request.getAttribute(START_TIME); | |||
Long end = System.currentTimeMillis(); | |||
log.info("【请求耗时】:{}毫秒", end - start); | |||
String header = request.getHeader("User-Agent"); | |||
UserAgent userAgent = UserAgent.parseUserAgentString(header); | |||
log.info("【浏览器类型】:{},【操作系统】:{},【原始User-Agent】:{}", userAgent.getBrowser().toString(), userAgent.getOperatingSystem().toString(), header); | |||
} | |||
} |
@@ -0,0 +1,38 @@ | |||
package com.xkcoding.springbootdemoaoplog.controller; | |||
import com.google.common.collect.Maps; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.springframework.web.bind.annotation.GetMapping; | |||
import org.springframework.web.bind.annotation.RequestParam; | |||
import org.springframework.web.bind.annotation.RestController; | |||
import java.util.Map; | |||
import java.util.concurrent.ConcurrentMap; | |||
/** | |||
* IndexController | |||
* | |||
* @package: com.xkcoding.springbootdemoaoplog.controller | |||
* @description:IndexController | |||
* @author: yangkai.shen | |||
* @date: Created in 2017/11/24 上午9:36 | |||
* @copyright: Copyright (c) 2017 | |||
* @version: 0.0.1 | |||
* @modified: yangkai.shen | |||
*/ | |||
@Slf4j | |||
@RestController | |||
public class IndexController { | |||
@GetMapping({"", ""}) | |||
public String index() { | |||
return "index"; | |||
} | |||
@GetMapping({"/test"}) | |||
public Map test(@RequestParam String name) { | |||
ConcurrentMap<String, Object> ret = Maps.newConcurrentMap(); | |||
ret.put("name", name); | |||
return ret; | |||
} | |||
} |
@@ -0,0 +1,62 @@ | |||
package com.xkcoding.springbootdemoaoplog.util; | |||
import com.fasterxml.jackson.core.type.TypeReference; | |||
import com.fasterxml.jackson.databind.ObjectMapper; | |||
import lombok.extern.slf4j.Slf4j; | |||
import java.io.IOException; | |||
/** | |||
* Json 转化工具类 | |||
* | |||
* @package: com.xkcoding.springbootdemoaoplog.util | |||
* @description:Json 转化工具类 | |||
* @author: yangkai.shen | |||
* @date: Created in 2017/11/24 上午9:36 | |||
* @copyright: Copyright (c) 2017 | |||
* @version: 0.0.1 | |||
* @modified: yangkai.shen | |||
*/ | |||
@Slf4j | |||
public class JsonMapper { | |||
private static ObjectMapper objectMapper = new ObjectMapper(); | |||
/** | |||
* 对象转 json 字符串 | |||
* | |||
* @param src 元对象 | |||
* @param <T> 类型 | |||
* @return json 字符串 | |||
*/ | |||
public static <T> String obj2Str(T src) { | |||
if (src == null) { | |||
return null; | |||
} | |||
try { | |||
return src instanceof String ? (String) src : objectMapper.writeValueAsString(src); | |||
} catch (IOException e) { | |||
log.error("【JSON 转换:对象 --> 字符串】,异常堆栈:{}", e); | |||
return null; | |||
} | |||
} | |||
/** | |||
* json 字符串转化为对象 | |||
* | |||
* @param src 源 json 字符串 | |||
* @param typeReference 转化后的类型 | |||
* @param <T> 类型 | |||
* @return 返回转化后的对象 | |||
*/ | |||
public static <T> T str2Obj(String src, TypeReference<T> typeReference) { | |||
if (src == null || typeReference == null) { | |||
return null; | |||
} | |||
try { | |||
return (T) (typeReference.getType().equals(String.class) ? src : objectMapper.readValue(src, typeReference)); | |||
} catch (Exception e) { | |||
log.error("【JSON 转换:字符串 --> 对象】,异常堆栈:{}", e); | |||
return null; | |||
} | |||
} | |||
} |
@@ -0,0 +1,3 @@ | |||
server: | |||
port: 8080 | |||
context-path: /demo |
@@ -0,0 +1,16 @@ | |||
package com.xkcoding.springbootdemoaoplog; | |||
import org.junit.Test; | |||
import org.junit.runner.RunWith; | |||
import org.springframework.boot.test.context.SpringBootTest; | |||
import org.springframework.test.context.junit4.SpringRunner; | |||
@RunWith(SpringRunner.class) | |||
@SpringBootTest | |||
public class SpringBootDemoAoplogApplicationTests { | |||
@Test | |||
public void contextLoads() { | |||
} | |||
} |
@@ -17,6 +17,7 @@ | |||
<module>../spring-boot-demo-actuator</module> | |||
<module>../spring-boot-demo-admin</module> | |||
<module>../spring-boot-demo-logback</module> | |||
<module>../spring-boot-demo-aoplog</module> | |||
<module>../spring-boot-demo-orm-jpa</module> | |||
<module>../spring-boot-demo-orm-mybatis</module> | |||
<module>../spring-boot-demo-cache-redis</module> | |||