JDK1.5中引入注解,spring框架把java注解發揚光大
一 創建自定義注解
import java.lang.annotation.Retention; import java.lang.annotation.ElementType; import java.lang.annotation.Target; import java.lang.annotation.RetentionPolicy; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Log { String value() default ""; }
二 解析注解
使用@Aspect注解使得該類成為切面類
import java.lang.reflect.Method; import java.util.Date; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import javax.servlet.http.HttpServletRequest; import com.prostate.common.service.LogService; import com.prostate.system.domain.UserToken; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; 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.scheduling.annotation.Async; import org.springframework.stereotype.Component; import com.prostate.common.annotation.Log; import com.prostate.common.dao.LogDao; import com.prostate.common.domain.LogDO; import com.prostate.common.utils.HttpContextUtils; import com.prostate.common.utils.IPUtils; import com.prostate.common.utils.JSONUtils; import com.prostate.common.utils.ShiroUtils; import com.prostate.system.domain.UserDO; @Aspect @Component public class LogAspect { private static final Logger logger = LoggerFactory.getLogger(LogAspect.class); @Autowired LogService logService; @Pointcut("@annotation(com.common.annotation.Log)") public void logPointCut() { } @Around("logPointCut()") public Object around(ProceedingJoinPoint point) throws Throwable { long beginTime = System.currentTimeMillis(); // 執行方法 Object result = point.proceed(); // 執行時長(毫秒) long time = System.currentTimeMillis() - beginTime; //異步保存日志 saveLog(point, time); return result; } void saveLog(ProceedingJoinPoint joinPoint, long time) throws InterruptedException { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); LogDO sysLog = new LogDO(); Log syslog = method.getAnnotation(Log.class); if (syslog != null) { // 注解上的描述 sysLog.setOperation(syslog.value()); } // 請求的方法名 String className = joinPoint.getTarget().getClass().getName(); String methodName = signature.getName(); sysLog.setMethod(className + "." + methodName + "()"); // 請求的參數 Object[] args = joinPoint.getArgs(); try { String params = JSONUtils.beanToJson(args[0]).substring(0, 4999); sysLog.setParams(params); } catch (Exception e) { } // 獲取request HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); // 設置IP地址 sysLog.setIp(IPUtils.getIpAddr(request)); // 用戶名 UserDO currUser = ShiroUtils.getUser(); if (null == currUser) { if (null != sysLog.getParams()) { sysLog.setUserId(-1L); sysLog.setUsername(sysLog.getParams()); } else { sysLog.setUserId(-1L); sysLog.setUsername("獲取用戶信息為空"); } } else { sysLog.setUserId(ShiroUtils.getUserId()); sysLog.setUsername(ShiroUtils.getUser().getUsername()); } sysLog.setTime((int) time); // 系統當前時間 Date date = new Date(); sysLog.setGmtCreate(date); // 保存系統日志 logService.save(sysLog); } }
通過@Pointcut指定切入點,這里指定Log注解,也就是被@Log修飾的方法,進入該切入點
① @Before 前置通知 在某連接點之前執行的通知
② @Around 環繞通知 在實現方法的前后執行的通知
③ @AfterReturning 后置通知 在某連接點正常完成執行的通知
④ @AfterThrowing 異常通知 在方法拋出異常退出執行的通知
⑤ @After 后置通知
@RequiresPermissions("base:scaleManager:edit") @Log("編輯題目或選項") @GetMapping("/edit/{id}") String edit(Model model, @PathVariable("id") String id) { ScaleDO scaleDO = scaleManagerService.get(id); model.addAttribute("scaleDO", scaleDO); ScaleDO scale = scaleManagerService.get(scaleDO.getParentId()); model.addAttribute("scale",scale); return prefix+"/edit"; }
隨便弄一個測試類就可測試了