妙用自定義注解,一行代碼搞定大功能(文末贈書)
以下內(nèi)容來自公眾號逆鋒起筆,關(guān)注每日干貨及時送達
1.簡介
2.Spring AOP
2.1.關(guān)于Spring AOP的一些術(shù)語
切面(Aspect):在Spring AOP中,切面可以使用通用類或者在普通類中以@Aspect 注解(@AspectJ風格)來實現(xiàn) 連接點(Joinpoint):在Spring AOP中一個連接點代表一個方法的執(zhí)行 通知(Advice):在切面的某個特定的連接點(Joinpoint)上執(zhí)行的動作。通知有各種類型,其中包括"around"、"before”和"after"等通知。許多AOP框架,包括Spring,都是以攔截器做通知模型, 并維護一個以連接點為中心的攔截器鏈 切入點(Pointcut):定義出一個或一組方法,當執(zhí)行這些方法時可產(chǎn)生通知,Spring缺省使用AspectJ切入點語法。
通知類型
前置通知(@Before):在某連接點(join point)之前執(zhí)行的通知,但這個通知不能阻止連接點前的執(zhí)行(除非它拋出一個異常) 返回后通知(@AfterReturning):在某連接點(join point)正常完成后執(zhí)行的通知:例如,一個方法沒有拋出任何異常,正常返回 拋出異常后通知(@AfterThrowing):方法拋出異常退出時執(zhí)行的通知 后通知(@After):當某連接點退出的時候執(zhí)行的通知(不論是正常返回還是異常退出) 環(huán)繞通知(@Around):包圍一個連接點(join point)的通知,如方法調(diào)用。這是最強大的一種通知類型,環(huán)繞通知可以在方法調(diào)用前后完成自定義的行為,它也會選擇是否繼續(xù)執(zhí)行連接點或直接返回它們自己的返回值或拋出異常來結(jié)束執(zhí)行。
2.2.Spring AOP配置有兩種風格:
XML風格 = 采用聲明形式實現(xiàn)Spring AOP AspectJ風格 = 采用注解形式實現(xiàn)Spring AOP
3.首先自定義注解
package com.ywj.log;
import java.lang.annotation.*;
/**
* ClassName Crmlog
* AOP日志記錄 自定義注解類
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemCrmlog {
/**
* 日志描述
* 對于什么表格進行了什么操作
*/
String description() default "";
/**
* 操作了的表名
* @return
*/
String tableName() default "";
}
3.1.定義切面類,從切入點獲取注解信息保存到數(shù)據(jù)庫
org.aspectj.lang.JoinPoint接口表示目標類連接點對象,如果是環(huán)繞增強時,使用org.aspectj.lang.ProceedingJoinPoint表示連接點對象,該類是JoinPoint的子接口。任何一個增強方法都可以通過將第一個入?yún)⒙暶鳛镴oinPoint訪問到連接點上下文的信息。我們先來了解一下這兩個接口的主要方法:1)JoinPoint
java.lang.Object[] getArgs():獲取連接點方法運行時的入?yún)⒘斜恚?/span>Signature getSignature():獲取連接點的方法簽名對象;java.lang.Object getTarget():獲取連接點所在的目標對象;java.lang.Object getThis():獲取代理對象本身;
2)ProceedingJoinPoint
java.lang.Object proceed() throws java.lang.Throwable:通過反射執(zhí)行目標對象的連接點處的方法;java.lang.Object proceed(java.lang.Object[] args) throws java.lang.Throwable:通過反射執(zhí)行目標對象連接點處的方法,不過使用新的入?yún)⑻鎿Q原來的入?yún)ⅰ?a target="_blank" textvalue="因為看了這些資料,我就成了別人眼中的大佬!" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" data-linktype="2">因為看了這些資料,我就成了別人眼中的大佬!
package com.ywj.log;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ywj.log.biz.Sys_logBiz;
import com.ywj.log.dao.Sys_logDao;
import com.ywj.login.biz.Sys_UserBiz;
import com.ywj.login.dao.Sys_UserDao;
import com.ywj.login.dao.Sys_righDao;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
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.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* @ClassName SystemLogAspect
* @Author Administrator
* @Describe 定義切入面類
*/
@Aspect
@Component
public class SystemLogAspect {
/**
* 注解Pointcut切入點
* 定義出一個或一組方法,當執(zhí)行這些方法時可產(chǎn)生通知
* 指向你的切面類方法
* 由于這里使用了自定義注解所以指向你的自定義注解
*/
@Pointcut("@annotation(com.ywj.log.SystemCrmlog)")
public void crmAspect() {
}
/**
*拋出異常后通知(@AfterThrowing):方法拋出異常退出時執(zhí)行的通知
* 注意在這里不能使用ProceedingJoinPoint
* 不然會報錯ProceedingJoinPoint is only supported for around advice
* throwing注解為錯誤信息
* @param joinPoint
* @param ex
*/
@AfterThrowing(value="crmAspect()", throwing="ex")
public void afterThrowingMethod(JoinPoint joinPoint, Exception ex) throws Exception {
HttpServletRequest httpServletRequest = getHttpServletRequest();
//獲取管理員用戶信息\
WebUtil webUtil = new WebUtil();
Map<String, Object> user = webUtil.getUser(httpServletRequest);
CrmLogMessage log=new CrmLogMessage();
//獲取需要的信息
String context=getServiceMthodDescription(joinPoint);
String usr_name="";
String rolename="";
if(user!=null){
usr_name = user.get("usr_name").toString();
rolename=user.get("rolename").toString();
}
//管理員姓名
log.setUserName(usr_name);
//角色名
log.setUserRole(rolename);
//日志信息
log.setContent(usr_name+context);
//設(shè)置參數(shù)集合
log.setRemarks(getServiceMthodParams(joinPoint));
//設(shè)置表名
log.setTableName(getServiceMthodTableName(joinPoint));
//操作時間
SimpleDateFormat sif=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
log.setDateTime(sif.format(new Date()));
//設(shè)置ip地址
log.setIp(httpServletRequest.getRemoteAddr());
//設(shè)置請求地址
log.setRequestUrl(httpServletRequest.getRequestURI());
//執(zhí)行結(jié)果
log.setResult("執(zhí)行失敗");
//錯誤信息
log.setExString(ex.getMessage());
//將數(shù)據(jù)保存到數(shù)據(jù)庫
Sys_logDao sysLogDao=new Sys_logDao();
sysLogDao.addSys_log(log);
}
/**
* 返回后通知(@AfterReturning):在某連接點(joinpoint)
* 正常完成后執(zhí)行的通知:例如,一個方法沒有拋出任何異常,正常返回
* 方法執(zhí)行完畢之后
* 注意在這里不能使用ProceedingJoinPoint
* 不然會報錯ProceedingJoinPoint is only supported for around advice
* crmAspect()指向需要控制的方法
* returning 注解返回值
* @param joinPoint
* @param returnValue 返回值
* @throws Exception
*/
@AfterReturning(value = "crmAspect()",returning = "returnValue")
public void doCrmLog(JoinPoint joinPoint,Object returnValue) throws Exception {
HttpServletRequest httpServletRequest = getHttpServletRequest();
//獲取管理員用戶信息
WebUtil webUtil = new WebUtil();
Map<String, Object> user = webUtil.getUser(httpServletRequest);
CrmLogMessage log=new CrmLogMessage();
String context=getServiceMthodDescription(joinPoint);
String usr_name="";
String rolename="";
if(user!=null){
usr_name = user.get("usr_name").toString();
rolename=user.get("rolename").toString();
}
//管理員姓名
log.setUserName(usr_name);
//角色名
log.setUserRole(rolename);
//日志信息
log.setContent(usr_name+context);
//設(shè)置參數(shù)集合
log.setRemarks(getServiceMthodParams(joinPoint));
//設(shè)置表名
log.setTableName(getServiceMthodTableName(joinPoint));
//操作時間
SimpleDateFormat sif=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
log.setDateTime(sif.format(new Date()));
//設(shè)置ip地址
log.setIp(httpServletRequest.getRemoteAddr());
//設(shè)置請求地址
log.setRequestUrl(httpServletRequest.getRequestURI());
if(returnValue!=null){
if(returnValue instanceof List){
List ls= (List) returnValue;
if(ls.size()>0){
log.setResult("執(zhí)行成功");
}else{
log.setResult("執(zhí)行成功");
}
}else if(returnValue instanceof Boolean){
Boolean falg= (Boolean) returnValue;
if(falg){
log.setResult("執(zhí)行成功");
}else{
log.setResult("執(zhí)行失敗");
}
}else if(returnValue instanceof Integer){
Integer i= (Integer) returnValue;
if(i>0){
log.setResult("執(zhí)行成功");
}else{
log.setResult("執(zhí)行失敗");
}
}else{
log.setResult("執(zhí)行成功");
}
}
//將數(shù)據(jù)保存到數(shù)據(jù)庫
Sys_logDao sysLogDao=new Sys_logDao();
sysLogDao.addSys_log(log);
}
/**
*獲取自定義注解里的日志描述
* @param joinPoint
* @return 返回注解里面的日志描述
* @throws Exception
*/
private String getServiceMthodDescription(JoinPoint joinPoint)
throws Exception {
//類名
String targetName = joinPoint.getTarget().getClass().getName();
//方法名
String methodName = joinPoint.getSignature().getName();
//參數(shù)
Object[] arguments = joinPoint.getArgs();
//通過反射獲取示例對象
Class targetClass = Class.forName(targetName);
//通過實例對象方法數(shù)組
Method[] methods = targetClass.getMethods();
String description = "";
for(Method method : methods) {
//判斷方法名是不是一樣
if(method.getName().equals(methodName)) {
//對比參數(shù)數(shù)組的長度
Class[] clazzs = method.getParameterTypes();
if(clazzs.length == arguments.length) {
//獲取注解里的日志信息
description = method.getAnnotation(SystemCrmlog.class).description();
break;
}
}
}
return description;
}
/**
*獲取自定義注解里的表名
* @param joinPoint
* @return 返回注解里的表名字
* @throws Exception
*/
private String getServiceMthodTableName(JoinPoint joinPoint)
throws Exception {
//類名
String targetName = joinPoint.getTarget().getClass().getName();
//方法名
String methodName = joinPoint.getSignature().getName();
//參數(shù)
Object[] arguments = joinPoint.getArgs();
//通過反射獲取示例對象
Class targetClass = Class.forName(targetName);
//通過實例對象方法數(shù)組
Method[] methods = targetClass.getMethods();
//表名
String tableName = "";
for (Method method : methods) {
//判斷方法名是不是一樣
if (method.getName().equals(methodName)) {
//對比參數(shù)數(shù)組的長度
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
//獲取注解里的表名
tableName = method.getAnnotation(SystemCrmlog.class).tableName();
break;
}
}
}
return tableName;
}
/**
* 獲取json格式的參數(shù)用于存儲到數(shù)據(jù)庫中
* @param joinPoint
* @return
* @throws Exception
*/
private String getServiceMthodParams(JoinPoint joinPoint)
throws Exception {
Object[] arguments = joinPoint.getArgs();
ObjectMapper om=new ObjectMapper();
return om.writeValueAsString(arguments);
}
/**
* 獲取當前的request
* 這里如果報空指針異常是因為單獨使用spring獲取request
* 需要在配置文件里添加監(jiān)聽
* <listener>
* <listener-class>
* org.springframework.web.context.request.RequestContextListener
* </listener-class>
* </listener>
* @return
*/
public HttpServletRequest getHttpServletRequest(){
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes)ra;
HttpServletRequest request = sra.getRequest();
return request;
}
}
相關(guān)類:
package com.ywj.log;
/**
* @ClassName CrmLogMessage
* @Author Administrator
* @Describe 數(shù)據(jù)庫日志類
*/
public class CrmLogMessage {
private Integer logid;//日志id
private String UserName;//管理員姓名
private String UserRole;//管理員角色
private String Content;//日志描述
private String Remarks;//參數(shù)集合
private String TableName;//表格名稱
private String DateTime;//操作時間
private String resultValue;//返回值
private String ip;//ip地址
private String requestUrl;//請求地址
private String result;//操作結(jié)果
private String ExString;//錯誤信息
public CrmLogMessage() {
}
@Override
public String toString() {
return "CrmLogMessage{" +
"logid=" + logid +
", UserName='" + UserName + '\'' +
", UserRole='" + UserRole + '\'' +
", Content='" + Content + '\'' +
", Remarks='" + Remarks + '\'' +
", TableName='" + TableName + '\'' +
", DateTime='" + DateTime + '\'' +
", resultValue='" + resultValue + '\'' +
", ip='" + ip + '\'' +
", requestUrl='" + requestUrl + '\'' +
", result='" + result + '\'' +
", ExString='" + ExString + '\'' +
'}';
}
public CrmLogMessage(Integer logid, String userName, String userRole, String content, String remarks, String tableName, String dateTime, String resultValue, String ip, String requestUrl, String result, String exString) {
this.logid = logid;
UserName = userName;
UserRole = userRole;
Content = content;
Remarks = remarks;
TableName = tableName;
DateTime = dateTime;
this.resultValue = resultValue;
this.ip = ip;
this.requestUrl = requestUrl;
this.result = result;
ExString = exString;
}
public String getExString() {
return ExString;
}
public void setExString(String exString) {
ExString = exString;
}
public Integer getLogid() {
return logid;
}
public void setLogid(Integer logid) {
this.logid = logid;
}
public String getUserName() {
return UserName;
}
public void setUserName(String userName) {
UserName = userName;
}
public String getUserRole() {
return UserRole;
}
public void setUserRole(String userRole) {
UserRole = userRole;
}
public String getContent() {
return Content;
}
public void setContent(String content) {
Content = content;
}
public String getRemarks() {
return Remarks;
}
public void setRemarks(String remarks) {
Remarks = remarks;
}
public String getTableName() {
return TableName;
}
public void setTableName(String tableName) {
TableName = tableName;
}
public String getDateTime() {
return DateTime;
}
public void setDateTime(String dateTime) {
DateTime = dateTime;
}
public String getResultValue() {
return resultValue;
}
public void setResultValue(String resultValue) {
this.resultValue = resultValue;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getRequestUrl() {
return requestUrl;
}
public void setRequestUrl(String requestUrl) {
this.requestUrl = requestUrl;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
}
package com.ywj.log;
import com.base.web.BaseAction;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* @ClassName WebUtil
* @Author Administrator
* @Describe 日志幫助類 用來獲取session中的用戶信息來存入數(shù)據(jù)庫
*/
public class WebUtil {
/**
* 從session中獲取到用戶對象
* @return
*/
public Map<String, Object> getUser(HttpServletRequest request){
Map<String, Object> attribute=null;
if(request!=null){
Object user = request.getSession().getAttribute(Constans.USER_KEY);
attribute = (Map<String, Object>) user;}
return attribute;
}
}
<!-- 啟動對@AspectJ注解的支持 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
<!-- 自動掃描包路徑 -->
<!--你需要剛才的切面類的包路徑-->
<context:component-scan base-package="com.ywj.log" />
<!--你需要注解方法的包路徑-->
<context:component-scan base-package="com.*.*.biz.impl" />
@SystemCrmlog(description = "進行了登錄操作",tableName =Constans.USER_TABLENAME)



來源:blog.csdn.net/yjt520557/article/details/85099115

今日福利
贈送如下圖書籍:

贈送規(guī)則:
1、給本文點贊、在看
2、給本文留言(留言內(nèi)容與本書有關(guān))
3、中獎后我會回復(fù)你的留言,請注意公眾號消息。
上次中獎?wù)撸?/span>

評論
圖片
表情
