AOP (Aspect Oriented Programming) 面向切面編程。
業務有核心業務和邊緣業務。
比如用戶管理,菜單管理,權限管理,這些都屬於核心業務。
比如日志管理,操作記錄管理,這些都是邊緣業務,可以統一的提出來。
嘗試使用SpringBoot +AOP 提出操作記錄業務。
github aop_demo
package com.lick.aspect.lang.annotation;
import com.lick.aspect.lang.enums.BusinessType;
import java.lang.annotation.*;
/**
* 自定義操作記錄注解
*/
@Target({ElementType.PARAMETER,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
/**
* 模塊
*/
public String title() default "";
/**
* 功能
*/
public BusinessType businessType() default BusinessType.OTHER;
}
package com.lick.aspect.lang.enums;
/**
* 操作狀態
*
*/
public enum BusinessStatus {
/**
* 成功
*/
SUCCESS,
/**
* 失敗
*/
FAIL,
}
package com.lick.aspect.lang.enums;
/**
* 業務操作類型
*/
public enum BusinessType {
/**
* 其它
*/
OTHER,
/**
* 新增
*/
INSERT,
/**
* 修改
*/
UPDATE,
/**
* 刪除
*/
DELETE,
/**
* 查詢列表
*/
LIST,
/**
* 登錄
*/
LOGIN,
/**
* 登出
*/
LOGOUT,
}
package com.lick.aspect.lang;
import com.lick.aspect.lang.annotation.Log;
import com.lick.aspect.lang.enums.BusinessStatus;
import com.lick.domain.OperateLog;
import com.lick.domain.User;
import com.lick.service.OperateLogService;
import com.lick.utils.IpUtils;
import com.lick.utils.ServletUtils;
import com.lick.utils.StringUtils;
import eu.bitwalker.useragentutils.UserAgent;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.Date;
/**
* 操作記錄處理
*/
@Aspect
@Component
public class LogAspect {
@Autowired
private OperateLogService operateLogService;
private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
//配置織入點
@Pointcut("@annotation(com.lick.aspect.lang.annotation.Log)")
public void logPointCut() {
}
/**
* 處理玩請求后執行
* @param joinPoint 切點
*/
@AfterReturning(pointcut = "logPointCut()")
public void doAfterReturning(JoinPoint joinPoint){
handleLog(joinPoint,null);
}
/**
* 攔截異常操作
* @param joinPoint 切點
* @param e 異常
*/
@AfterThrowing(value = "logPointCut()",throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint,Exception e){
handleLog(joinPoint,e);
}
protected void handleLog(final JoinPoint joinPoint,final Exception e) {
try{
//獲得注解
Log controllerLog = getAnnotation(joinPoint);
if(controllerLog == null) {
return;
}
UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
String hostIp = IpUtils.getHostIp();
String os = userAgent.getOperatingSystem().getName();
String browser = userAgent.getBrowser().getName();
OperateLog operateLog = new OperateLog();
//主機地址
operateLog.setOperIP(hostIp);
//事務狀態
operateLog.setStatus(BusinessStatus.SUCCESS.name());
//瀏覽器類型
operateLog.setBrowser(browser);
//操作系統類型
operateLog.setOs(os);
HttpServletRequest request = ServletUtils.getRequest();
//請求地址
operateLog.setOperURL(request.getRequestURI());
HttpSession session = ServletUtils.getSession();
try {
User currentUser = (User)session.getAttribute("currentUser");
//操作人
operateLog.setOperator(currentUser.getUsername());
}
catch(Exception exp) {
exp.printStackTrace();
}
if (e != null)
{ //事務狀態 錯誤的情況
operateLog.setStatus(BusinessStatus.FAIL.name());
//錯誤消息
operateLog.setErrorMSG(StringUtils.substring(e.getMessage(), 0, 2000));
}
//設置方法名稱
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
//操作的方法
operateLog.setMethod(className + "." + methodName + "()");
//處理設置注解上的參數
getControllerMethosDescription(controllerLog,operateLog);
operateLog.setOperTime(new Date());
//保存數據庫
operateLogService.insertOperateLog(operateLog);
}catch (Exception exp){
//記錄本地異常日志
log.error("==前置通知異常==");
log.error("異常消息{}",exp.getMessage());
exp.printStackTrace();
}
}
public void getControllerMethosDescription(Log log, OperateLog operateLog) throws Exception {
//設置action 動作
//業務類型
operateLog.setOperAction(log.businessType().name());
//設置標題
//模塊標題
operateLog.setTitle(log.title());
}
private Log getAnnotation(JoinPoint joinPoint) throws Exception {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if(method != null) {
return method.getAnnotation(Log.class);
}
return null;
}
}
package com.lick.config;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* 配置
*/
@Configuration
// 表示通過aop框架暴露該代理對象,AopContext能夠訪問
@EnableAspectJAutoProxy(exposeProxy = true)
// 指定要掃描的Mapper類的包的路徑
@MapperScan(basePackages = "com.lick.mapper")
public class ApplicationConfig {
}
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<contextName>Aop</contextName>
<!-- 日志存放路徑 -->
<property name="log.path" value="C:\\aop\\logs" />
<!--輸出到控制台-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%black(%contextName-) %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}) - %gray(%msg%n)</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!-- 系統模塊日志級別控制 -->
<logger name="com.lick" level="debug" />
<!-- Spring日志級別控制 -->
<logger name="org.springframework" level="warn" />
<!--普通日志輸出到控制台-->
<root level="info">
<appender-ref ref="console" />
</root>
</configuration>
package com.lick.controller;
import com.lick.aspect.lang.annotation.Log;
import com.lick.aspect.lang.enums.BusinessType;
import com.lick.domain.User;
import com.lick.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Date;
import java.util.List;
@Controller
@RequestMapping(value = "/user/")
public class UserController {
@Autowired
private UserService userService;
@GetMapping(value = "/add")
public String add() {
return "addUser";
}
@Log(title="添加用戶",businessType = BusinessType.INSERT)
@PostMapping(value = "/add")
public String add(User user) {
user.setCreatedTime(new Date());
user.setUpdatedTime(new Date());
userService.insertUser(user);
return "redirect:/user/list";
}
@Log(title="查詢用戶列表",businessType = BusinessType.LIST)
@GetMapping(value = "/list")
public String listUser(ModelMap map) {
List<User> allUser = userService.findAllUser();
map.put("userList",allUser);
return "userList";
}
}