TA的每日心情 | 衰 2021-2-2 11:21 |
---|
签到天数: 36 天 [LV.5]常住居民I
|
忙里偷闲最近在看关于springAop的一些功能、顺便完善一下项目。
6 F, O6 E8 d, b$ ~4 @9 d0 r" K' u4 A 一般我们的异常都会抛出到控制层,如果使用struts2也就是action。然后try{//正确代码实现}catch{//在里面记录错误日志},这样咋一看是不错,代码很完美。但是如果项目中有成千上万个项目怎么办?难道在每个action的catch里面都要加入异常记录代码?很显然工作量是很大的。" A( @3 M8 K! }' a7 k1 J
S6 a4 ?0 d+ Z1 L/ I" h( ^1 X' T
鉴于项目中配置了数据库事务,其实也是使用了AOP 详见applicationContext-service.xml配置文件。由于配置文件的局限性这里采用注释的方式实现。之所有使用注释是可以自定义参数并实现日志的详细记录。既然使用注释,现成的没有,只有自己定义来实现需求。其实spring 注释实现的注入、hibernate的model类注释实现与数据库关联以及我们最常见Override。
0 K- I2 b1 l6 v4 V, ]# |" U- ~5 J 资料:java如何实现自定义注释http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html
# m6 ? R' |4 D: @( r S6 K0 f3 Y6 g# y- _/ n
一、 记录日志并发送邮件通知+ K# d. s5 x+ A6 Z; v. Y4 b
(1)、定义注解:% |+ }! S. n! a6 T
1.ServiceLog.java(各种参数类型详见上面的资料)1 X; _( H& ]9 o8 N
- import java.lang.annotation.*; + a8 P+ s' B/ J) k- h
- /**
* i# y$ h. t/ O' e/ c0 H+ I - * 自定义注解 拦截service ; {7 e+ ?. \5 X) \% a0 o
- * 创建者 张志朋$ p+ Q8 J# |) |
- * 创建时间 2015年6月3日
) t" H8 F1 y, C: f5 B+ }! r - *
3 {$ M/ }8 S/ p, k6 O6 Z" [- L' \ - */- k0 l3 O& s% v v+ u
- @Target({ElementType.PARAMETER, ElementType.METHOD}) $ J1 S# S1 r: Q: `: l
- @Retention(RetentionPolicy.RUNTIME) 2 a" h! v s* }! p
- @Documented % s4 T6 e8 J; {) O9 R' G3 a" e
- public @interface ServiceLog { # [# e3 b! i, F# F5 Z. |
- String description() default "";/ ^' S6 e. a) d. l, T
- }
复制代码 2.ControllerLog.java
& `4 t+ j; d$ e, O% P- import java.lang.annotation.*;
1 L4 D3 Q- Q4 j4 k$ U, u4 f - /**7 b1 m5 n; }' e0 D0 ^, r( W. L
- * 自定义注解 拦截Controller
4 K/ L! n0 ^6 U: n - * 创建者 张志朋0 N: q3 z. `2 T" T( k8 e' f9 q
- * 创建时间 2015年6月3日
+ Q- M& ?* a3 W$ g/ Z y - *, Y* @$ P1 D4 X! i
- */6 m7 u6 p: z$ d: l1 K" c
- @Target({ElementType.PARAMETER, ElementType.METHOD}) ( f2 ?. z9 X: C/ ~; Q7 Y
- @Retention(RetentionPolicy.RUNTIME) ( f8 O2 f7 ]* R- m- x6 g5 ~* Z
- @Documented' g$ E+ A$ l: i9 M1 ~3 m' B
- public @interface ControllerLog {
3 s# V3 p7 i5 U& g - String description() default ""; 5 ]5 @; C5 M8 v
- }
复制代码 (2)、定义切面以及切入点6 x" m! o5 ~: F( w3 L
1.LogAspect.java
: K* U: D) T" w- /**- J' y6 k% |: i% t7 L, f4 J
- * 日志记录AOP
% }) S% R8 o, t - * 创建者 张志朋
7 P! p2 N# b2 e8 e - * 创建时间 2015年6月3日& J& n; w8 }& x
- *% }0 n( s, l% _; t5 V' T" l# \( [
- */$ z( X9 L# E. S" z
- @Component
% B+ L( q8 c7 r0 N& P, L4 S - @Scope7 I; X3 w$ a( y$ v
- @Aspect
. V# c, [; ~- o& p - public class LogAspect {
Y4 I0 ?1 a% `+ }: f7 F2 S - //Service层切点 用于记录错误日志5 Y! H. B: [- |, W! d# l
- @Pointcut("@annotation(com.web.aop.ServiceLog)")
: U* `0 b) V0 S* r - public void serviceAspect() {
3 j! V1 e: P: t7 g - ; _: S, Y: \# h7 J) I2 E# ~
- }
# B+ u4 K/ `8 \ - /**
* h# ]' N8 V! Y- p7 _1 r - * 异常通知 用于拦截service层记录异常日志 " C& `' Q. M% o" r5 S
- * @Author 张志朋& y) m0 ^2 s) g$ Z3 G, \3 y+ ^
- * @param joinPoint4 x. J( f+ Z- O" f p% y( A
- * @param e void
/ q2 R( g( L6 _- m/ p0 a - * @Date 2015年6月3日
3 F: F$ s4 X& c - * 更新日志
: D' d6 d- q1 w; L1 U! a7 X - * 2015年6月3日 张志朋 首次创建
3 K9 t! j9 B- i+ y& x - *
" `0 B. o( O4 |; p D0 x8 K - */' r2 k: }; E( j* r( k) W9 |) y
- @AfterThrowing(pointcut = "serviceAspect()", throwing = "e")
6 i4 P. o) x6 W' a9 I3 }4 | Q$ [ - public void doAfterThrowing(JoinPoint joinPoint, Throwable e) { $ r+ s1 d3 U# u! a3 A/ \
- HttpServletRequest request = ServletActionContext.getRequest();( u6 L* X/ M, W4 q( r9 g
- TeacherEntity user = CommonUtil.getUser();
& g+ }( Q+ M, j+ V2 W - String ip = AddressUtils.getIpAddr(request);, r. h* |0 B7 s2 w7 v4 r
- try {
. a3 w* Q7 K) n2 R1 G* L - String params = "";7 q+ h8 D! b( { S" u# u
- if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
1 Y0 n* t8 v1 M6 ~8 v0 z5 r - for (int i = 0; i < joinPoint.getArgs().length; i++) { G" z, l3 i# v8 J. S5 {9 G* K: v
- params += JSONUtil.toJSONstring(joinPoint.getArgs()[i]) + ";";$ Q. F; A2 {4 `& C, h
- }
* a' J% \& T* t0 k - }
" a+ }( C5 i. m+ _$ V' H; V - String description = getServiceMthodDescription(joinPoint);//用户操作
* U: ]: y7 H5 Z7 W - String exceptionCode =e.getClass().getName();//异常类型代码
, }. F8 J M0 ` - String exceptionDetail = e.getMessage();//异常详细信息
# ^3 v: D1 R' c) |1 z - String method = joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()";//异常方法) [8 Q6 i- ]* D% p9 o8 K' [
- /*==========记录数据库异常日志==========*/ 7 I$ T3 q* ?2 j4 s( W
- Log log = new Log();
* F7 G+ N( B* Y8 K, J) D) f - log.setDescription(description);; | o- Q, U. Y' d# j! G
- log.setExceptionCode(exceptionCode);
, B, T" S* |( r - log.setExceptionDetail(exceptionDetail);, L! T: ~ ~2 K# D6 }& D/ r
- log.setMethod(method);8 Z- d+ `& I @* Z; T7 {* l
- log.setType(Constants.LOG_ERROE);// 日志类型6 W; }( P8 g9 f- J2 |: }( |
- log.setRequestIp(ip);// 请求IP) p( ]1 m" z- y! `# R% G2 d
- log.setParams(params);//请求参数
0 H# }% n9 m( e6 l( g2 Z% d; e - if(null!=user){% X6 I$ M2 _, G
- log.setCreateUid(user.getUid());//用户ID
' i! O( P0 e0 z1 B- K - log.setCreateName(user.getNickname());//用户昵称9 I/ R' ]5 l F: l$ S6 t3 Q
- }
: j) G2 I5 R' u. r - log.setPlatFrom(Constants.SUBJECT_CODE);
! B: [9 n# P7 z# G, J4 F9 `0 Z) H - /*==========记录数本地异常日志==========*/
3 I9 o0 j6 q9 |$ {$ H - //LogUtil.error(description, e);
9 q- D! t& k1 U( T* [! l% ` - /*==========发送异常日志到邮箱==========*/
! P: @' J. e9 Y9 L2 w - StringBuffer errorMsg = new StringBuffer();
3 z, ?( `- i. {. C) a% ?0 q5 `7 S - errorMsg.append("异常方法:");$ a. r! H; K1 j% W {; _
- errorMsg.append(method);9 k% z' C5 W8 b
- errorMsg.append("</br>");
3 n0 ~4 M7 X" t! z8 \, w/ _ - errorMsg.append("异常类型代码:");
. }* [" b B1 p6 j8 g+ H - errorMsg.append(exceptionCode);
5 m& a$ F# [, h5 I$ \/ W: D( [8 \$ Y3 l - errorMsg.append("</br>");
, R A2 ?. Y2 t6 `$ k - errorMsg.append("异常详细信息:");# x/ T% d1 ] Q+ L: M" Q. C+ U+ Q) H
- errorMsg.append(exceptionDetail);
8 E3 H& V7 y' s& G9 e - errorMsg.append("</br>");* a# }: Y4 P2 O# `7 }% b
- log.setErrorMsg(errorMsg.toString());
! U, {7 @9 u! y& H' X. k& K - WebServiceMathClient Client = new WebServiceMathClient();
/ l8 G# s' L% I) G - Client.sendError(log);; }6 f5 N. P1 L$ P" M
- } catch (Exception ex) {
; y/ Q Y& r! r* T9 r7 E - e.printStackTrace();
' g& E9 Q/ v$ ]) O9 i4 g3 G; B - }) r: l+ @* V' v0 ?. M) m( C8 j) h
- } 3 [: g! F$ G3 o3 s. E
- /**2 A) h( `6 X2 e& Q k5 ?7 o! V
- * 获取注解中对方法的描述信息 用于service层注解 (基于反射)
% p) q8 ^ C& V- o" R& [ - * @Author 张志朋1 E5 B7 E- P/ p; r2 m
- * @param joinPoint
' Z: B1 h* _2 M+ L4 Y - * @return
' u5 E9 a# S" F2 z6 n - * @throws Exception String1 o# ]4 D& u; a& t7 E1 }# C5 r
- * @Date 2015年6月3日4 k* |7 L) Q9 R4 H- O( [
- * 更新日志
1 W7 k; x& J/ c# Q - * 2015年6月3日 张志朋 首次创建
5 R) ?& Z, u* E! S - *
. c/ G, Z ]& P9 h U( `6 p9 [ - */6 u- q' k; T' W( l6 q% x
- @SuppressWarnings("rawtypes")
+ P. g0 }! S" y* A" {8 J - public static String getServiceMthodDescription(JoinPoint joinPoint) m" G% ~" M; S5 Q
- throws Exception { ' e1 c! v- g5 C# R* l' y. a3 A
- String targetName = joinPoint.getTarget().getClass().getName();
' L- L/ E/ x7 z" M1 r - String methodName = joinPoint.getSignature().getName(); ; X! B( u5 T/ ]9 [
- Object[] arguments = joinPoint.getArgs();
8 ^6 m4 P Y. p5 J0 { - Class targetClass = Class.forName(targetName);
0 ^ K% Y* z0 `5 s4 V - Method[] methods = targetClass.getMethods(); 4 X& |' }3 O( a& T2 U5 \
- String description = ""; 9 ^+ e" z; M p) S
- for (Method method : methods) {
! u' u: i5 D7 |; }( o" n - if (method.getName().equals(methodName)) {
: s8 B+ _- ? N/ x0 M0 A! F - Class[] clazzs = method.getParameterTypes();
- _7 `8 e2 `( ~4 J) b - if (clazzs.length == arguments.length) { - J& Y1 p4 W3 a2 X; i5 L( @% B' a
- description = method.getAnnotation(ServiceLog. class).description(); # ^& e+ w9 z( y( O3 X) K
- break;
: e" _- N/ O# u: P) D0 c - }
3 O# ?, O8 Q& I, n9 V+ l - }
1 G( y+ l$ [8 Y" d8 ` - } 9 @ A4 \8 A3 V5 k" R
- return description; ( K5 [% I' j9 `
- }
6 N) D4 z& k% f5 A - }
复制代码
7 V* w9 D" a, c这里说明一下 serviceAspect()方法 上面注释了 @Pointcut("@annotation(com.acts.web.aop.ServiceLog)") 、也就说明这是一个切入点,springAOP对其进行了封装。
/ W9 }, ?0 N# i. g9 [doAfterThrowing()方法上面加入了@AfterThrowing(pointcut = "serviceAspect()", throwing = "e") 对切入点的所有异常信息进行处理(记录日志到数据库或者发送错误信息到指定邮箱等等等,可以做任何你想做的事情)。: F( B2 o" `4 ]' s( m# j% S S
) J: | F# D5 L. C
2.QuesPerServiceImpl.java(注意此类必须实现接口 默认JDK的动态代理实现是基于接口实现的 否则会报错)
% N/ N& k/ d5 T; a5 p' U! m/ Y- @ServiceLog(description="获取待审试题数量")
# J$ s; q% C2 H3 @2 ] - public long getAuditQuesNum(TeacherEntity currentUser) throws Exception { w. J0 ]3 l7 k2 R6 v0 K
- return quesPerDao.getAuditQuesNum(currentUser);; H- _/ Y: v9 F" v! F$ g/ M; j% q8 r
- }
复制代码
* w, }' d) n% T* @之所以定义description 描述 是为了更好的记录错误日志 文字总是比方法名 更容易识别。/ W7 K+ K6 @. G# p |
二、AOP实现权限控制1 G$ r$ N0 P5 ?: ?, D1 C9 ]" P; n
上面说过使用动态代理的类 必须实现接口但是我们的action并没有实现接口。 JDK 的动态代理只能对实现了接口的目标类进行代理,而不实现接口的类就不能使用 JDK 的动态代理。! r0 I6 [" x# T f7 M
还好有第三方的包为我们解决了问题。项目中引入cglib.jar,CGLIB 是针对类来实现代理,当没有实现接口的类需要代理时就需要通过 CGLIB 来实现代理了,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但是因为采用的是继承,所以不能对 finall 类进行继承。
; L5 T8 R0 {" p- [! u7 r首先配置文件要引入这样一段配置(看注释说明):
' o" A+ N' @) p3 X' _1 U- <!--通知spring使用cglib而不是jdk的来生成代理方法 AOP可以拦截到Controller(Action)-->
& X- C$ O& U: i% d5 ^ - <aop:aspectj-autoproxy proxy-target-class="true"/>
复制代码
7 w+ \# J! I" @9 a) ?; o& X(1)、定义注释:$ f* @) j- w2 L) U0 v
1.Permission.java
! f+ C6 [/ U% O! o0 G. B% v- /**# A: O6 X6 `7 t( _
- * 自定义权限管理
) S7 l( M' \0 Y: v; g - * 创建者 张志朋
# R! t7 B8 k0 Y% @/ k0 L+ r - * 创建时间 2015年6月30日
6 @% x4 O5 B* a2 U4 B - *- p l8 j5 r! G5 S6 Q9 V% \/ b
- */! G ?6 ?1 z6 y; e, F! T
- @Target({ElementType.PARAMETER, ElementType.METHOD})
, u% e5 R; U2 W2 y0 v1 g( G# U" W - @Retention(RetentionPolicy.RUNTIME)
9 w6 Q, ` e5 g/ z3 k6 H* e - @Documented0 x" e; E% U) _3 S% `% Q
- public @interface Permission {
4 ~/ }0 K* F6 B/ }# A$ U - String name() default ""; //操作行为
# H7 ^+ g- o+ c4 b# R - int id() default -1;//权限值
S, H. [3 ~, I% c+ g - }
复制代码 (2)、定义切面以及切入点/ i3 U+ V. V0 i6 a; Y' N9 [
1.PsemissionAspect.java
9 u( F8 |! \8 P5 O- /**7 q) [0 @0 @, J
- * 权限管理
% ~5 o- x1 f! ^9 n - * 创建者 张志朋7 h" T5 e# U6 g R1 y" w
- * 创建时间 2015年7月3日
6 u1 X7 p1 L s4 S! J" Y - *# G' w+ t( Y. k3 O) }( d6 q; O. r
- */
+ g. L. D& i+ t: I) \, P - @Component# j1 j5 t) P' u* Z4 Q
- @Scope
5 a1 ]9 g; z0 W/ E& V - @Aspect
( X7 ^& y+ T1 g, | - public class PsemissionAspect {
) f- X! X* a2 b6 |2 H7 C, a0 y9 { -
6 E3 F; W2 [0 R2 P2 ] - //Controller层切点 用于权限控制
2 g& D( B/ o, ~( m5 d, W - @Pointcut("@annotation(com.acts.web.aop.Permission)") $ Q+ j7 t! W+ n9 x, Y, a% N8 v) p( g
- public void permissionAspect() {5 e/ [' E4 o/ I1 k- `4 n
- * a7 \" j, h+ d6 {/ p4 N9 m
- }
$ Z1 F( }" T! v7 l/ R: N: P% i, n - /**, f, g5 X3 }! e! U
- * 用于拦截Controller层用户操作权限(环绕通知)4 G6 C+ x* A& g, z5 G. t
- * @Author 张志朋
0 D+ M/ @/ c- C0 S5 I - * @param joinPoint void) f" n4 \# I' G% Z/ ?5 v. F4 b
- * @Date 2015年6月3日
: b) Z1 m9 z1 o2 ~9 j# \' z) B - * 更新日志
4 s8 y8 Q; x% n' {) [8 \ - * 2015年6月3日 张志朋 首次创建
* _3 j9 v! k$ i7 k - *7 |" w N! C5 \: V" y0 I
- */
- y5 Z+ w0 R% K( F. ~: j6 G - @Around("permissionAspect()")
& _# N) n/ R4 u; L- ]! ^5 t }7 x% a - public Object permission(ProceedingJoinPoint joinPoint)throws Throwable { 5 e: @5 ]3 R6 b2 ~! L
- Object retVal = null;
4 v: b: \5 x$ W; E4 q - int role = getControllerMethodRole(joinPoint);6 M9 Q; i a/ }; I; i' W
- TeacherEntity user = CommonUtil.getUser();
% m4 _) ]4 m! f9 x& q% w2 A - if((user.getSpecRole()&role)==role){//没有权限
! C/ N/ j' a8 w% V4 C3 | - retVal = joinPoint.proceed();% G6 t. [+ C- c- `! q# U- n
- }else{
6 y- o5 D5 l- j5 B" j, m7 U - noAuthorization();$ ~) O9 [" A% z% A# m3 |
- }
3 R0 D1 q' W, R - return retVal;
! f5 R+ x! x& A - }
+ \8 S M1 U& U: W" ] g( ^7 t: R. B8 l - /**
) ]4 Y# Q/ R& q% P6 o - * 没有权限 实现跳转& i \5 r. b n$ N7 ^" t1 f
- * @Author 张志朋
1 a: s+ p6 V: D; e2 ~- x5 z0 n - * @throws IOException void
. o( w! b7 |) c2 b% W* c# u: F( I - * @Date 2015年7月3日
( z& C( [0 l% F J9 g - * 更新日志
4 X V7 Z/ |/ r% x: F - * 2015年7月3日 张志朋 首次创建3 o2 W K! A/ e W; D# `
- *, {( ~& G9 w% d( }( a+ H e' g. y
- */
5 [% w7 G1 D' y - public void noAuthorization() throws IOException{/ J0 s' f- P* J. `+ V, C
- HttpServletRequest request = ServletActionContext.getRequest();5 t. i* g: F. r9 X5 n# M$ G
- String path = request.getContextPath();
5 m. p4 y6 q8 t - HttpServletResponse response = ServletActionContext.getResponse();
) P [ D) a( `& E - response.sendRedirect(path+"/pages/noAuthorization.jsp");1 v4 N. j D6 U4 n4 G$ g
- }5 D) h4 T9 V( `/ [ r
- /**
4 s) b+ ^* O8 u' F& G6 F - * 获取注解中对方法的权限值 用于Controller层注解 . e3 R) r" W5 \" ], k f3 w* g
- * @Author 张志朋( {( N9 h5 N8 v' |2 _6 T$ n6 x: b" G
- * @param joinPoint
% Z F9 I* v, Y3 l# @2 c - * @return
- l+ r6 P4 O$ G6 @; t4 Z: _ - * @throws Exception int, }" L9 e$ h* o( B5 K c
- * @Date 2015年7月3日2 S( E9 k v$ b4 R
- * 更新日志. y( g0 a* e1 x2 P8 V2 U
- * 2015年7月3日 张志朋 首次创建
8 C2 u3 A9 R# _3 v6 k - *' O# a. o% U. @2 F
- */) R) p" r0 z0 m$ b6 y5 K# n1 w
- @SuppressWarnings("rawtypes")
0 l3 c; C6 {: f6 ?+ i; k - public static int getControllerMethodRole(JoinPoint joinPoint) throws Exception {8 ~- D0 ?) ]' y W- c) h
- String targetName = joinPoint.getTarget().getClass().getName();
, n6 F) `8 c2 O g- I - String methodName = joinPoint.getSignature().getName(); , v0 D3 G9 n: P! X. ?' d
- Object[] arguments = joinPoint.getArgs();
6 y1 `" h$ q) u) h% l1 F% Q - Class targetClass = Class.forName(targetName); 4 V% @: N- Y+ ]/ a
- Method[] methods = targetClass.getMethods();
7 Z/ |1 d. O S% s5 H - int role = -1; : h6 `+ W3 x; Q4 T# F" V# B
- for (Method method : methods) { " k) h) M4 i" B% W( U" Y/ A( o/ T
- if (method.getName().equals(methodName)) { 7 E- u4 w* P9 @& ?7 J3 s7 h! K( x; M; V
- Class[] clazzs = method.getParameterTypes(); \7 e# g" c* l( R& q
- if (clazzs.length == arguments.length) { ! R1 ]3 p& D" }- {
- role = method.getAnnotation(Permission. class).id();
$ F( E) ]" b! o# X6 v+ G - break;
+ E) X! _: a( Y - }
' ]# ]* |$ b1 }$ m6 u - } 9 i" \) N, s8 J9 Y
- } % R; H/ A% O/ Q( P
- return role;
$ f( h' f6 y1 }* V U - }
复制代码
5 G5 h2 x5 A4 P0 I! @2.action层代码实现:# D0 W; k8 l9 \# r
- /**
/ I! p8 p( M J) w6 R - * 试题审核不通过5 R& L) V1 x5 G. ]2 F4 Q
- * @Author 张志朋 void4 ]" k$ V- U7 Y! s' {
- * @Date 2015年5月4日 ~6 @8 u1 |5 w6 G) C% n
- * 更新日志$ a6 }8 ^% g! ]" R
- * 2015年5月4日 张志朋 首次创建4 c+ K. b% u7 V$ O. w- J
- *, R- z3 d. i* H" t
- */
5 L& L/ O( L" ~# F( x' w - @Permission(name="审核试题权限(审核不通过)",id=Constants.ROLE_QUES_AUDIT)
( Z3 b) j' U' J - public void auditQuestions(){, o$ m7 F% C% _$ n( W
- try {
# N8 y/ f$ ~, \% ?+ C! m/ v: L - //代码实现
3 c+ K4 i$ i9 X- W( \4 E! e - } catch (Exception e) {+ n1 B- T$ ]% g4 L$ ]
- e.printStackTrace();
) [( `6 B0 d) u1 f4 R3 F5 m - }1 f' Q8 w# ^0 U; |9 R3 f
- 0 G4 q- I" }' M$ o
- }
复制代码 ) `9 \$ \) V; P% W" `1 M1 a4 A
* ?6 s9 i+ x" b9 r9 L( Q5 Z4 L4 ` |
|