AOP記錄異常郵件傳送記錄
一般我們的異常都會丟擲到控制層,如果使用struts2也就是action。然後try{//正確程式碼實現}catch{//在裡面記錄錯誤日誌},這樣咋一看是不錯,程式碼很完美。但是如果專案中有成千上萬個專案怎麼辦?難道在每個action的catch裡面都要加入異常記錄程式碼?很顯然工作量是很大的。7 `, X, R" [ \1 [2 D
鑑於專案中配置了資料庫事務,其實也是使用了AOP 詳見applicationContext-service.xml配置檔案。由於配置檔案的侷限性這裡採用註釋的方式實現。之所有使用註釋是可以自定義引數並實現日誌的詳細記錄。既然使用註釋,現成的沒有,只有自己定義來實現需求。其實spring 註釋實現的注入、hibernate的model類註釋實現與資料庫關聯以及我們最常見Override。
資料:java如何實現自定義註釋http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html
一、 記錄日誌併傳送郵件通知
(1)、定義註解:
1.ServiceLog.java(各種引數型別詳見上面的資料)
-
import java.lang.annotation.*;
-
/**
-
* 自定義註解 攔截service
-
* 建立者 張志朋
-
* 建立時間 2015年6月3日
-
*/
-
@Target({ElementType.PARAMETER, ElementType.METHOD})
-
@Retention(RetentionPolicy.RUNTIME)
-
@Documented
-
public @interface ServiceLog {
-
String description() default "";
- }
-
import java.lang.annotation.*; 1 O6 b$ f+ A5 N G5 R
-
/**
-
* 自定義註解 攔截Controller: g' a) s9 S- b- [% Z+ v" s
-
* 建立者 張志朋
-
* 建立時間 2015年6月3日
-
*
-
*/
-
@Target({ElementType.PARAMETER, ElementType.METHOD})
-
@Retention(RetentionPolicy.RUNTIME) * D. u, W' W3 d. P9 J! h
-
@Documented
-
public @interface ControllerLog {
-
String description() default "";
- }
1.LogAspect.java
-
/**
-
* 日誌記錄AOP+ ~# G$ `. M' W+ b
-
* 建立者 張志朋* U3 Q. a' V* d' c+ {1 |' Q i/ H" A
-
* 建立時間 2015年6月3日
-
*
-
*/* a& I5 G, i9 [
-
@Component
-
@Scope$ w& p0 A1 g7 h5 |: V# p! ?2 T7 P
-
@Aspect
-
public class LogAspect {. n [5 j- F( q( ^8 Q& i3 X7 [
-
//Service層切點 用於記錄錯誤日誌
-
@Pointcut("@annotation(com.web.aop.ServiceLog)")
-
public void serviceAspect() {$ g: a. u5 m. Y" w
-
6 C9 [5 x" }3 m2 z
-
}; ]7 {, \" L1 }) [ l1 t' i
-
/**
-
* 異常通知 用於攔截service層記錄異常日誌 ! J( E: g* X' T ~ c5 Y
-
* @Author 張志朋
-
* @param joinPoint- L3 l7 g* T1 F$ H z- m
-
* @param e void B- K3 D" I. H3 D) `
-
* @Date 2015年6月3日
-
* 更新日誌9 N- S: z6 {2 B* q5 K: C! ^, H$ w
-
* 2015年6月3日 張志朋 首次建立/ f( k# a5 t/ X7 p( r, f
-
*
-
*/! ^' U; k, B- G2 u" y; U4 v- R) x
-
@AfterThrowing(pointcut = "serviceAspect()", throwing = "e") * X0 K5 m! P' l( }# \- w
-
public void doAfterThrowing(JoinPoint joinPoint, Throwable e) { 2 X; e8 [$ n8 `; l
-
HttpServletRequest request = ServletActionContext.getRequest();1 w4 k0 ?4 h( O6 ~1 h8 p) w7 D/ n
-
TeacherEntity user = CommonUtil.getUser();
-
String ip = AddressUtils.getIpAddr(request);
-
try {( L* R+ }4 E: g- p2 |5 p1 I
-
String params = "";4 F2 u- c b7 v5 x: q) w
-
if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
-
for (int i = 0; i < joinPoint.getArgs().length; i++) {
-
params += JSONUtil.toJSONstring(joinPoint.getArgs()[i]) + ";";- m4 ^8 \* @9 c% `8 a
-
}
-
}; {7 t9 m$ K$ T! R1 P0 h2 C
-
String description = getServiceMthodDescription(joinPoint);//使用者操作
-
String exceptionCode =e.getClass().getName();//異常型別程式碼* D" q% b# H1 P1 N
-
String exceptionDetail = e.getMessage();//異常詳細資訊
-
String method = joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()";//異常方法
-
/*==========記錄資料庫異常日誌==========*/ 4 P* G$ z, O& F
-
Log log = new Log();
-
log.setDescription(description);
-
log.setExceptionCode(exceptionCode);
-
log.setExceptionDetail(exceptionDetail);
-
log.setMethod(method);2 ~/ g: N' F4 j# ?
-
log.setType(Constants.LOG_ERROE);// 日誌型別
-
log.setRequestIp(ip);// 請求IP2 E4 ~- N, E. s2 Z
-
log.setParams(params);//請求引數
-
if(null!=user){' N# l6 h/ r3 I2 D/ }' q) ~
-
log.setCreateUid(user.getUid());//使用者ID
-
log.setCreateName(user.getNickname());//使用者暱稱
-
}# C& ? ?7 f2 {) I
-
log.setPlatFrom(Constants.SUBJECT_CODE);. ]8 `3 x3 F& k' L, ]: o: }7 Z) w
-
/*==========記錄數本地異常日誌==========*/ , O' ~) z+ t- z4 ~* b
-
//LogUtil.error(description, e);
-
/*==========傳送異常日誌到郵箱==========*/
-
StringBuffer errorMsg = new StringBuffer();8 i! O' d, {. F) C0 d$ w
-
errorMsg.append("異常方法:");* F; l& W8 J- V
-
errorMsg.append(method);
-
errorMsg.append("</br>");8 {7 i1 F$ b3 c, V. o
-
errorMsg.append("異常型別程式碼:");
-
errorMsg.append(exceptionCode);% [# B0 Y/ S- P& i) d; m6 V3 B
-
errorMsg.append("</br>");
-
errorMsg.append("異常詳細資訊:");. p; r6 _5 q7 D* |8 T% q
-
errorMsg.append(exceptionDetail);
-
errorMsg.append("</br>");4 x" A' q3 l9 _0 I/ x8 n
-
log.setErrorMsg(errorMsg.toString());; h& Y* b% O9 W0 W$ c
-
WebServiceMathClient Client = new WebServiceMathClient();; x7 h7 J2 c& F9 w2 t
-
Client.sendError(log);. l+ b+ S5 J# J0 e% l+ ^, r
-
} catch (Exception ex) {3 q% B/ R0 Z0 H0 S1 l8 U
-
e.printStackTrace();; k' e3 l( |+ ~0 |3 c7 |+ ]* e
-
}) J# A4 j# B4 x; q8 b4 N& v D
-
}
-
/**$ C$ j2 z7 z @% g7 [, ^
-
* 獲取註解中對方法的描述資訊 用於service層註解 (基於反射)& \ r6 Y' c1 ~
-
* @Author 張志朋+ c% C7 k7 D4 x
-
* @param joinPoint5 }" U0 W, g' f$ S8 q
-
* @return/ y7 K5 y* w" m
-
* @throws Exception String6 D1 `5 p" J }+ B/ G
-
* @Date 2015年6月3日# h1 g7 Y; v! d
-
* 更新日誌
-
* 2015年6月3日 張志朋 首次建立
-
*1 ]" @9 k' t% s, \
-
*/1 B! U- |) f( \
-
@SuppressWarnings("rawtypes")
-
public static String getServiceMthodDescription(JoinPoint joinPoint) ' g0 G6 P2 Q+ G5 ^+ S
-
throws Exception { ( m* w& @% A0 k, v' ?, U
-
String targetName = joinPoint.getTarget().getClass().getName(); I: V# i5 i; j( l3 u
-
String methodName = joinPoint.getSignature().getName(); $ a9 t; `2 q( g3 K5 N
-
Object[] arguments = joinPoint.getArgs();
-
Class targetClass = Class.forName(targetName); , I* G; G0 ?0 o
-
Method[] methods = targetClass.getMethods(); 2 x1 P8 ~9 ^7 ~( r2 j. z8 f
-
String description = "";
-
for (Method method : methods) { 6 q0 X) I, F# P$ v
-
if (method.getName().equals(methodName)) { ' d" n& `1 ]; U0 z, N
-
Class[] clazzs = method.getParameterTypes(); 8 z4 D* r+ T. n( e
-
if (clazzs.length == arguments.length) {
-
description = method.getAnnotation(ServiceLog. class).description();
-
break;
-
}
-
}
-
} 3 e& ~% G' z- I/ ]
-
return description; , ~ v4 J7 A4 T: }2 S4 F8 p. Q
-
}
- }
這裡說明一下 serviceAspect()方法 上面註釋了 @Pointcut("@annotation(com.acts.web.aop.ServiceLog)") 、也就說明這是一個切入點,springAOP對其進行了封裝。# u$ g! \5 u3 w' }7 W0 H4 t& j( _7 y0 f
doAfterThrowing()方法上面加入了@AfterThrowing(pointcut = "serviceAspect()", throwing = "e") 對切入點的所有異常資訊進行處理(記錄日誌到資料庫或者傳送錯誤資訊到指定郵箱等等等,可以做任何你想做的事情)。, Z7 h; x$ U* D. U, E
2.QuesPerServiceImpl.java(注意此類必須實現介面 預設JDK的動態代理實現是基於介面實現的 否則會報錯)
-
@ServiceLog(description="獲取待審試題數量")
-
public long getAuditQuesNum(TeacherEntity currentUser) throws Exception {5 \9 a& ~6 {4 `- |9 ?' E& L& c
-
return quesPerDao.getAuditQuesNum(currentUser);
- }
之所以定義description 描述 是為了更好的記錄錯誤日誌 文字總是比方法名 更容易識別。1 C0 Z3 n7 v+ X# ^
二、AOP實現許可權控制
上面說過使用動態代理的類 必須實現介面但是我們的action並沒有實現介面。 JDK 的動態代理只能對實現了介面的目標類進行代理,而不實現介面的類就不能使用 JDK 的動態代理。$ F% v5 V( H" s. a' `0 }
還好有第三方的包為我們解決了問題。專案中引入cglib.jar,CGLIB 是針對類來實現代理,當沒有實現介面的類需要代理時就需要通過 CGLIB 來實現代理了,他的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現增強,但是因為採用的是繼承,所以不能對 finall 類進行繼承。( {, s ]2 z E! N7 U! ]) l* B
首先配置檔案要引入這樣一段配置(看註釋說明):& `2 m6 Q- q. p3 [7 e* ] s
-
<!--通知spring使用cglib而不是jdk的來生成代理方法 AOP可以攔截到Controller(Action)-->
- <aop:aspectj-autoproxy proxy-target-class="true"/>
(1)、定義註釋:
1.Permission.java
-
/**/ N4 f: v' A" C1 X8 g6 d3 r( G& J
-
* 自定義許可權管理
-
* 建立者 張志朋
-
* 建立時間 2015年6月30日6 h! R: f* O* W8 R) f* X8 V+ _
-
*1 N* y; g7 u- ~5 J% m- R
-
*/$ t$ a- X- e( T) _
-
@Target({ElementType.PARAMETER, ElementType.METHOD})
-
@Retention(RetentionPolicy.RUNTIME)
-
@Documented
-
public @interface Permission {
-
String name() default ""; //操作行為
-
int id() default -1;//許可權值
- }
1.PsemissionAspect.java0 U+ g8 C+ _7 g6 K( T: V% }+ A
-
/**% V/ {# B- w7 j8 z
-
* 許可權管理% f! C% F7 {; w) B( c
-
* 建立者 張志朋
-
* 建立時間 2015年7月3日
-
*% l2 Y! |8 y8 c/ Y. R. O
-
*/, h; k+ k7 X- I- A5 P z i
-
@Component
-
@Scope7 J/ [* j# j/ I" ]1 T% x6 N0 Q6 ^
-
@Aspect" p X9 T- |+ ?+ t- C2 b6 M
-
public class PsemissionAspect {
-
-
//Controller層切點 用於許可權控制
-
@Pointcut("@annotation(com.acts.web.aop.Permission)") ( l* c8 d* V4 E8 P
-
public void permissionAspect() {
-
-
}
-
/**
-
* 用於攔截Controller層使用者操作許可權(環繞通知)$ [% e5 v$ N. m* `) Y
-
* @Author 張志朋' f+ |; s' \1 m x, o
-
* @param joinPoint void
-
* @Date 2015年6月3日
-
* 更新日誌5 Q% }* O/ A- f
-
* 2015年6月3日 張志朋 首次建立/ u; i# F0 C5 g# S% [, b- q9 X
-
*' N/ T8 _: u( p) {" o, y0 X: A
-
*/
-
@Around("permissionAspect()") ) x( w# {1 ?. w' l
-
public Object permission(ProceedingJoinPoint joinPoint)throws Throwable { 8 o) |) B0 V+ Z3 t
-
Object retVal = null;) ^8 U# G% D+ z7 s
-
int role = getControllerMethodRole(joinPoint);! K1 [# g6 T5 W# F
-
TeacherEntity user = CommonUtil.getUser();! f, y0 S+ q0 l/ W. m! f* S9 J
-
if((user.getSpecRole()&role)==role){//沒有許可權6 T$ c1 \0 E( \+ J$ L h
-
retVal = joinPoint.proceed();) z. _3 ?( l5 g% P+ B" q
-
}else{/ O* W# X( ?: }" j4 |) ?
-
noAuthorization();
-
}8 K+ T" f$ Y9 ~+ w$ s
-
return retVal;
-
}& h2 k' S. q/ T! @
-
/**
-
* 沒有許可權 實現跳轉/ o3 g, c6 N: _- B
-
* @Author 張志朋
-
* @throws IOException void
-
* @Date 2015年7月3日
-
* 更新日誌
-
* 2015年7月3日 張志朋 首次建立
-
*
-
*/# M! f l3 `* e6 `
-
public void noAuthorization() throws IOException{& h) n% K0 r4 {$ F/ B( F
-
HttpServletRequest request = ServletActionContext.getRequest();/ | k8 X0 [# M4 S4 p( y/ I
-
String path = request.getContextPath();+ r7 x" D4 v- p- R% E9 r" T
-
HttpServletResponse response = ServletActionContext.getResponse();
-
response.sendRedirect(path+"/pages/noAuthorization.jsp");
-
}/ V+ k% Q) m9 b+ W) f! |- p
-
/**4 o5 M E. ?7 F( Q! a7 @" |
-
* 獲取註解中對方法的許可權值 用於Controller層註解
-
* @Author 張志朋
-
* @param joinPoint
-
* @return
-
* @throws Exception int' r8 C3 [& v, z7 X, i
-
* @Date 2015年7月3日
-
* 更新日誌
-
* 2015年7月3日 張志朋 首次建立7 U, T9 U( y2 Y! z
-
*2 Z4 ?2 c: Y8 o, T
-
*/
-
@SuppressWarnings("rawtypes")
-
public static int getControllerMethodRole(JoinPoint joinPoint) throws Exception {
-
String targetName = joinPoint.getTarget().getClass().getName(); ! `' K; B2 l5 w
-
String methodName = joinPoint.getSignature().getName(); ( D* y9 w, o" V' E; W
-
Object[] arguments = joinPoint.getArgs(); , F* I# _8 K& H3 ^( ^; s
-
Class targetClass = Class.forName(targetName); , r# D, w9 N, R8 S2 @2 A0 c
-
Method[] methods = targetClass.getMethods();
-
int role = -1; * }' t8 i( O# ?% W# w
-
for (Method method : methods) { + a# n, }0 f1 X5 E# t4 M( P, C
-
if (method.getName().equals(methodName)) { * S9 C8 v/ G8 W5 @3 s8 G y
-
Class[] clazzs = method.getParameterTypes();
-
if (clazzs.length == arguments.length) { - i* n; p5 M9 }: u) @
-
role = method.getAnnotation(Permission. class).id(); 5 u( i9 ~1 B2 ~
-
break;
-
}
-
} ( g* S9 u, x' O. v( D& B1 J& V4 I
-
}
-
return role;
- }
2.action層程式碼實現:3 j. @6 G! b. H* z
-
/**
-
* 試題稽核不通過
-
* @Author 張志朋 void
-
* @Date 2015年5月4日
-
* 更新日誌. R5 [/ y4 i1 E) L/ P
-
* 2015年5月4日 張志朋 首次建立9 q' `2 s) k! k# r1 v! M$ R( O
-
*: }. L" Z! S Q
-
*/
-
@Permission(name="稽核試題許可權(稽核不通過)",id=Constants.ROLE_QUES_AUDIT)2 U, ]( e; H$ z
-
public void auditQuestions(){
-
try {
-
//程式碼實現
-
} catch (Exception e) {' b4 H' W+ @! i0 M
-
e.printStackTrace();
-
}- G& Y$ {* t" ~
-
# {8 s$ ~+ |2 ~7 c; U2 l
- }
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/750077/viewspace-2119041/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- SSIS遍歷記錄傳送郵件
- C#原生郵件傳送+傳送日誌記錄C#
- 利用SPF記錄缺失傳送偽造郵件
- 新增了SPF記錄後仍然能夠冒名傳送郵件
- Jenkins實現自動化郵件傳送踩坑記錄Jenkins
- JSP筆記-傳送郵件JS筆記
- 使用Zabbix服務端本地郵箱賬號傳送報警郵件及指定報警郵件操作記錄服務端
- CoreDNS解析異常記錄DNS
- 記錄 Laravel5.6 中使用 Notification 傳送郵件的一次錯誤Laravel
- 記錄使用 guzzlehttp 異常捕獲踩坑記錄HTTP
- Django筆記三十八之傳送郵件Django筆記
- 記錄Javascript 異常捕獲JavaScript
- 郵件傳送
- 傳送郵件
- 記錄Laravel異常處理類Laravel
- gitlab配置郵件通知功能操作記錄Gitlab
- JavaMail傳送郵件時常見錯誤JavaAI
- SpringBoot整合Mail傳送郵件&傳送模板郵件Spring BootAI
- Laravel 傳送郵件Laravel
- PHP傳送郵件PHP
- Django——郵件傳送Django
- java郵件傳送Java
- Laravel傳送郵件Laravel
- gmail傳送郵件AI
- Oracle郵件傳送Oracle
- java傳送郵件Java
- Powershell郵件傳送
- thinkphp 郵件傳送PHP
- centos 傳送郵件CentOS
- phpcms傳送郵件PHP
- 郵件的傳送
- 異常處理 - Go 學習記錄Go
- TCP連線狀態異常記錄TCP
- Java Mail 郵件傳送(二):簡單封裝的郵件傳送JavaAI封裝
- golang傳送郵件(qq郵箱)Golang
- 郵件傳送API整理API
- php windows 傳送郵件PHPWindows
- 定時傳送郵件