springboot整合aop实现网站访问日志记录
目的:
统一日志输出格式,统计访问网站的ip.
思路:
1、针对不同的调用场景定义不同的注解,目前想的是接口层和服务层。
2、我设想的接口层和服务层的区别在于:
(1)接口层可以打印客户端IP,而服务层不需要
(2)接口层的异常需要统一处理并返回,而服务层的异常只需要向上抛出即可
3、就像Spring中的@Controller、@Service、@Repository注解那样,虽然作用是一样的,但是不同的注解用在不同的地方显得很清晰,层次感一下就出来了
4、AOP去拦截特定注解的方法调用
5、为了简化使用者的操作,采用Spring Boot自动配置
如果要直接用@Aspect注解的话,要在spring的配置文件中加入
<aop:aspectj-autoproxy />
那么我们这里要不要在程序的主类中增加@EnableAspectJAutoProxy来启用呢?实际并不需要
好的也就是说,只要引入SpringAOP相关的jar包依赖,我们就可以开始相关的Aspet的编程了。有时候拦截器也是可以实现的,但是如果我们采用的是post请求,如果使用拦截器就需要从报文中读取数据,
其实就是io流,只能获取一次,所以在controller中无法获取数据,所以拦截器的方法是不可行的.
首先需要引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
controller中:
package com.cxy.shibernate.controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; /***
* @ClassName: HelloController
* @Description:
* @Auther: cxy
* @Date: 2019/5/19:18:06
* @version : V1.0
*/
@Controller
public class HelloController {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
@ResponseBody
public String hello(@RequestParam String name) {
return "Hello " + name;
} }
工具类:
package com.cxy.shibernate.controller; /***
* @ClassName: HttpContextUtils
* @Description:
* @Auther: cxy
* @Date: 2019/5/19:18:17
* @version : V1.0
*/
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; public class HttpContextUtils { public static HttpServletRequest getHttpServletRequest() {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
return servletRequestAttributes.getRequest();
}
//获取ip
public static String getIpAddress() {
HttpServletRequest request = getHttpServletRequest();
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == || "unknown".equalsIgnoreCase(ip)) {
if (ip == null || ip.length() == || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
}else if (ip != null && ip.length() > ) {
String[] ips = ip.split(",");
for (int index = ; index < ips.length; index++) {
String strIp = (String) ips[index];
if (!("unknown".equalsIgnoreCase(strIp))) {
ip = strIp;
break;
}
}
}
return ip;
}
}
切面:
package com.cxy.shibernate.controller; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest;
import java.util.Arrays; /***
* @ClassName: WebLogAspect
* @Description:
* @Auther: cxy
* @Date: 2019/5/19:18:08
* @version : V1.0
*/
@Aspect
@Order()
@Component
public class WebLogAspect {
private final Logger logger = LoggerFactory.getLogger(WebLogAspect.class); ThreadLocal<Long> startTime = new ThreadLocal<>();
/**
第一个*表示返回任何类型,com.cxy.shibernate.controller下任何类,任何方法,任何参数
也可以加入参数限定例如com.cxy.shibernate.controller.*.*(..)&&args(name,..) 下面那中表示方法也是对的,表示com.cxy.shibernate.下面任何子包下任何方法,任何参数
**/
@Pointcut("execution(public * com.cxy.shibernate..*.*(..))")
public void webLog(){} @Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
startTime.set(System.currentTimeMillis()); // 接收到请求,记录请求内容 HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
String ipAddress = HttpContextUtils.getIpAddress(); // 记录下请求内容
logger.info("URL : " + request.getRequestURL().toString());
logger.info("HTTP_METHOD : " + request.getMethod());
logger.info("IP : " + request.getRemoteAddr());
logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
logger.info("ip:"+ipAddress); } @AfterReturning(returning = "ret", pointcut = "webLog()")
public void doAfterReturning(Object ret) throws Throwable {
// 处理完请求,返回内容
logger.info("RESPONSE : " + ret);
logger.info("SPEND TIME : " + (System.currentTimeMillis() - startTime.get()));
} }
启动类:
package com.cxy.shibernate; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication
public class ShibernateApplication { public static void main(String[] args) {
SpringApplication.run(ShibernateApplication.class, args);
} }
在application.yml不需要配置任何东西
启动项目:
当然可以配置文件输出的级别,制定输出的文件夹
springboot整合aop实现网站访问日志记录的更多相关文章
- 来一手 AOP 注解方式进行日志记录
系统日志对于定位/排查问题的重要性不言而喻,相信许多开发和运维都深有体会. 通过日志追踪代码运行状况,模拟系统执行情况,并迅速定位代码/部署环境问题. 系统日志同样也是数据统计/建模的重要依据,通过分 ...
- CentOS中设置Apache服务器网站访问日志[每天的日志]
在阿里云的linux 服务器下Apache的日志默认设置是七天更新一次, 并且所在的目录无法通过FTP浏览器查看, 这样让小白操作起来非常麻烦 可以使用rotatelogs来设置服务器的网站访问日志按 ...
- SpringBoot学习笔记(七):SpringBoot使用AOP统一处理请求日志、SpringBoot定时任务@Scheduled、SpringBoot异步调用Async、自定义参数
SpringBoot使用AOP统一处理请求日志 这里就提到了我们Spring当中的AOP,也就是面向切面编程,今天我们使用AOP去对我们的所有请求进行一个统一处理.首先在pom.xml中引入我们需要的 ...
- 【Spring Cloud & Alibaba全栈开源项目实战】:SpringBoot整合ELK实现分布式登录日志收集和统计
一. 前言 其实早前就想计划出这篇文章,但是最近主要精力在完善微服务.系统权限设计.微信小程序和管理前端的功能,不过好在有群里小伙伴的一起帮忙反馈问题,基础版的功能已经差不多,也在此谢过,希望今后大家 ...
- springboot 整合logback(有全套的日志配置文件)
logback介绍:基于Log4j基础上大量改良,不能单独使用,推荐配合日志框架SLF4J来使用,可以和springboot很好的整合,也是springboot默认推荐的. 1.在resources ...
- 利用AOP与ToStringBuilder简化日志记录
刚学spring的时候书上就强调spring的核心就是ioc和aop blablabla...... IOC到处都能看到...AOP么刚开始接触的时候使用在声明式事务上面..当时书上还提到一个用到ao ...
- Apache访问日志记录用户的每一个请求
我们使用的是/usr/local/apache2.4/conf/extra/httpd-vhosts.conf配置文件下的第二段配置,它的日志在/usr/local/apache2.4/logs/下面 ...
- springboot—spring aop 实现系统操作日志记录存储到数据库
原文:https://www.jianshu.com/p/d0bbdf1974bd 采用方案: 使用spring 的 aop 技术切到自定义注解上,针对不同注解标志进行参数解析,记录日志 缺点是要针对 ...
- SpringBoot:4.SpringBoot整合Mybatis实现数据库访问
在公司项目开发中,使用Mybatis居多.在 SpringBoot:3.SpringBoot使用Spring-data-jpa实现数据库访问 中,这种jpa风格的把sql语句和java代码放到一起,总 ...
随机推荐
- Xcode常见路径
模拟器安装的位置: /Library/Developer/CoreSimulator/Profiles/Runtimes 可以通过Xcode安装 模拟器程序的沙盒 Xcode编译生成的Product ...
- 随笔记录 MBR扇区故障系统备份与还原 2019.8.7
系统备份: [root@localhost ~]# mkdir /abc [root@localhost ~]# mount /dev/sdb1 /abc [root@localhost ~]# dd ...
- 新知道一个 端对端加密 Signal protocol
看 socketio Sponsors 列表中的小蓝鸟,发现网站中有使用 x-jquery-tmpl [翻译]WhatsApp 加密概述(技术白皮书) 知道一个叫 Signal 协议 的端对端加密 端 ...
- 从服务器上下载下来的代码,部署到本地时,Url自动带www前缀
fix步骤: 1.网站根目录下,找到.htacess文件,有记事本打开 2.定位到 RewriteCond %{HTTP_HOST} . RewriteCond %{HTTP_HOST} !^www\ ...
- 【JZOJ6277】矩阵游戏
description analysis 设所有操作之后,\(f[i]\)表示\(i\)行乘的数,\(g[j]\)表示\(j\)列乘的数,那么 \[Answer=\sum^{n}_{i=1}\sum^ ...
- 【转载】Abstract Factory Step by Step --- 抽象工厂
抽象工厂是创建型模式的代表,其他的还有单件(Singleton).生成器(Builder).工厂方法(Factory Method)以及原型(Prototype),模式本身没有好坏之分,只有适用不适用 ...
- thingkphp 路由实例
我们已经了解了如何定义路由规则,下面我们来举个例子加深印象. 假设我们定义了News控制器如下(代码实现仅供参考): namespace Home\Controller; use Think\Cont ...
- win10 mysql5.7指定某个配置文件启动
点击开始菜单,搜索cmd.exe,左击以管理员身份运行 C:\Users\Administrator>cd C:\Program Files\MySQL\MySQL Server 5.7\bin ...
- JDK语法糖之switch字串与枚举支持
在JDK1.7之前,switch只支持byte,short,char,int,注意1.5之后的自动拆箱,对应的这四种基础类型的封装类也同样支持Byte,Short,Character,Integer, ...
- 使用Maven命令行下载依赖库
这篇文章,不是教大家如何新建maven项目,不是与大家分享Eclipse与Maven整合. 注意:是在命令行下使用Maven下载依赖库. 废话不说,步骤如下: 1.保证电脑上已成功安装了JDK.运行j ...