引入依賴
<!--spring切面aop依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
在application.properties添加配置
spring.aop.auto=true
1.創建自定義注解類
當然該注解類可以使用spring自帶注解類:@Before,@After,@AfterRuturning ,@AfterThrowing ,@Around 。
只是這5種方式的作用不同:
(1)Before ---在所攔截方法執行前執行;
(2)After ---在所攔截方法執行后執行;
(3)AfterRuturning ---在所攔截方法返回值后,執行;
(4)AfterThrowing ---當所攔截方法拋出異常時,執行;
(5)Around ---最為復雜的切入方式,剛方式可以包括上述4個方式。
import java.lang.annotation.*; /** * 自定義注解類 * @author MrRoot * @date 2019-01-16 */ @Target(ElementType.METHOD) //注解放置的目標位置,METHOD是可注解在方法級別上 @Retention(RetentionPolicy.RUNTIME) //注解在哪個階段執行 @Documented //生成文檔 public @interface MyLog { String value() default ""; }
2.生成日志實體類
博主使用的是mybatisplus根據表信息生成的實體類,當然也可以使用普通實體類。
import com.baomidou.mybatisplus.enums.IdType; import java.util.Date; import com.baomidou.mybatisplus.annotations.TableId; import com.baomidou.mybatisplus.annotations.TableField; import com.baomidou.mybatisplus.enums.FieldFill; import com.baomidou.mybatisplus.activerecord.Model; import com.baomidou.mybatisplus.annotations.TableName; import java.io.Serializable; /** * <p> * 日志表 * </p> * * @author MrRoot * @since 2019-01-16 */ @TableName("research_log") public class Log extends Model<Log> { private static final long serialVersionUID = 1L; /** * 主鍵 */ @TableId(value = "id", type = IdType.AUTO) private Long id; /** * 用戶id */ @TableField("user_id") private Long userId; /** * 操作時用戶的ip地址 */ private String ip; /** * 操作詳情 */ private String operation; /** * 創建時間 */ @TableField(value = "gmt_create", fill = FieldFill.INSERT) private Date gmtCreate; /** * 更新時間 */ @TableField(value = "gmt_modified", fill = FieldFill.INSERT_UPDATE) private Date gmtModified; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public Long getUserId() { return userId; } public void setUserId(Long userId) { this.userId = userId; } public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip; } public String getOperation() { return operation; } public void setOperation(String operation) { this.operation = operation; } public Date getGmtCreate() { return gmtCreate; } public void setGmtCreate(Date gmtCreate) { this.gmtCreate = gmtCreate; } public Date getGmtModified() { return gmtModified; } public void setGmtModified(Date gmtModified) { this.gmtModified = gmtModified; } @Override protected Serializable pkVal() { return this.id; } @Override public String toString() { return "Log{" + ", id=" + id + ", userId=" + userId + ", ip=" + ip + ", operation=" + operation + ", gmtCreate=" + gmtCreate + ", gmtModified=" + gmtModified + "}"; } }
3.系統日志:處理切面類
其中最后的insert方法為mybatisplus封裝好的插入方法,如果使用普通實體類則需要自己寫插入數據庫的方法。
IPUtils方法見附錄
import com.alibaba.fastjson.JSON; import com.panshi.cecdc.research.entity.Log; import com.panshi.cecdc.research.service.LogService; import com.panshi.cecdc.research.util.IPUtils; import org.apache.shiro.SecurityUtils; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; 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.lang.reflect.Method; import java.util.Date; /** * 系統日志:切面處理類 * @author MrRoot * @date 2019-01-16 */ @Aspect @Component public class SysLogAspect { @Autowired private LogService logService; /** * 定義切點 @Pointcut * 在注解的位置切入代碼 */ @Pointcut("@annotation(com.panshi.cecdc.research.common.MyLog)") public void logPointCut() { } /** * 切面 配置通知 * @param joinPoint */ @AfterReturning("logPointCut()")//這里可以選擇日志插入的方式 public void saveSysLog(JoinPoint joinPoint) { //保存日志 Log log = new Log(); //從切面織入點處通過反射機制獲取織入點處的方法 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); //獲取切入點所在的方法 Method method = signature.getMethod(); //獲取操作 MyLog myLog = method.getAnnotation(MyLog.class); if (myLog != null) { String value = myLog.value(); //保存獲取的操作 log.setOperation(value); } //獲取請求的類名 //String className = joinPoint.getTarget().getClass().getName(); //獲取請求的方法名 //String methodName = method.getName(); //sysLog.setMethod(className + "." + methodName); //請求的參數 //Object[] args = joinPoint.getArgs(); //將參數所在的數組轉換成json //String params = JSON.toJSONString(args); //log.setParams(params); log.setGmtCreate(new Date()); //獲取用戶名 log.setUserId((Long)SecurityUtils.getSubject().getSession().getAttribute("userId")); //獲取用戶ip地址 HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest(); log.setIp(IPUtils.getIp(request)); //調用service保存SysLog實體類到數據庫 logService.insert(log); } }
4.在需要監控的controller方法上加上注解
@MyLog(value = "用戶詳情")//操作類型 @GetMapping("/detail") public Result detail(@RequestParam("id") Long id){ return Result.createBySuccess(sysUserService.detail(id)); }
5.結果示例

附錄:
IPUtils:
import org.apache.commons.lang3.StringUtils; import javax.servlet.http.HttpServletRequest; /** * ip工具類 * @author MrRoot * @date 2019-01-16 */ public class IPUtils { private static final String UNKNOWN = "unKnown"; public static String getIp(HttpServletRequest request) { String ip = request.getHeader("X-Forwarded-For"); if(StringUtils.isNotEmpty(ip) && !UNKNOWN.equalsIgnoreCase(ip)){ //多次反向代理后會有多個ip值,第一個ip才是真實ip int index = ip.indexOf(","); if(index != -1){ return ip.substring(0,index); }else{ return ip; } } ip = request.getHeader("X-Real-IP"); if(StringUtils.isNotEmpty(ip) && !UNKNOWN.equalsIgnoreCase(ip)){ return ip; } return request.getRemoteAddr(); } }
