TA的每日心情 | 衰 2021-2-2 11:21 |
---|
签到天数: 36 天 [LV.5]常住居民I
|
忙里偷闲最近在看关于springAop的一些功能、顺便完善一下项目。 " O+ t; B: u" X2 B; H5 A
一般我们的异常都会抛出到控制层,如果使用struts2也就是action。然后try{//正确代码实现}catch{//在里面记录错误日志},这样咋一看是不错,代码很完美。但是如果项目中有成千上万个项目怎么办?难道在每个action的catch里面都要加入异常记录代码?很显然工作量是很大的。
3 D. y" t# {5 @' L# U& r8 J& a: Y; ^. G4 M0 Q3 p
7 U8 w: Y5 C3 r9 i) F# W6 ]* I 鉴于项目中配置了数据库事务,其实也是使用了AOP 详见applicationContext-service.xml配置文件。由于配置文件的局限性这里采用注释的方式实现。之所有使用注释是可以自定义参数并实现日志的详细记录。既然使用注释,现成的没有,只有自己定义来实现需求。其实spring 注释实现的注入、hibernate的model类注释实现与数据库关联以及我们最常见Override。. s3 f& d8 T0 f" z
资料:java如何实现自定义注释http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html
/ R* n9 k/ m6 Q6 h% {
! e+ P4 f+ J% ]% l7 X+ M一、 记录日志并发送邮件通知
" |: g) b5 |' X( o( Q+ Z) C/ K(1)、定义注解:
, X' Y8 F6 Z8 I/ |) S! C0 _1.ServiceLog.java(各种参数类型详见上面的资料) B6 w# ^/ E, V
- import java.lang.annotation.*;
5 m' s# m% w, a5 T& E& } - /**
9 t( B' H/ O% D - * 自定义注解 拦截service
# h+ O* B# s7 @+ m) ]& n6 b, @ - * 创建者 张志朋
8 @. n, ~ K3 I @ - * 创建时间 2015年6月3日2 g" _6 W# x' S% M
- *: [# M [9 B2 d: v9 L g* K }/ Z% F
- */2 u, f4 l* p/ l8 j
- @Target({ElementType.PARAMETER, ElementType.METHOD}) " {& U7 e% v" z0 ^2 y
- @Retention(RetentionPolicy.RUNTIME) 7 }9 W% o9 d$ Q7 |. E ^2 f* W
- @Documented , J) D) ]' {) Q: U
- public @interface ServiceLog {
5 o6 @ F0 g4 O2 c - String description() default "";
; i7 w& @( A1 I! V N - }
复制代码 2.ControllerLog.java
8 z- {/ I0 R! k4 b2 p& T2 J- import java.lang.annotation.*; " }3 b2 z. m' O0 E9 R" ^
- /**, G+ W0 d4 `6 c
- * 自定义注解 拦截Controller' m! l8 s: O+ o/ |! I; _
- * 创建者 张志朋# ^% R; v+ y2 x: z' ]! Z) |% K
- * 创建时间 2015年6月3日# `3 T! ~+ W4 B1 G
- *
! k* K; s% p8 z$ s5 o - */
* j- A" V: g+ }4 U- d2 ] - @Target({ElementType.PARAMETER, ElementType.METHOD})
8 E5 ^( Q7 @! C1 f' G" L$ ? - @Retention(RetentionPolicy.RUNTIME)
3 a( K; M+ H% Z7 H% ?! N( v - @Documented2 c, Z5 w: {& c9 e
- public @interface ControllerLog {9 M) d1 X/ Y( i+ n+ Z; o
- String description() default ""; 3 k* W! N; P/ Z$ G }- b) Q/ y& g
- }
复制代码 (2)、定义切面以及切入点
+ S3 R& \9 {6 g! p) P2 q1.LogAspect.java
7 S8 X Q4 |' i8 N: o- /**
8 G% Y u+ k+ }. I - * 日志记录AOP
4 {! {1 A! o- R2 R( B - * 创建者 张志朋
4 v5 A/ A! S. d$ Y, e4 i - * 创建时间 2015年6月3日
; I6 Q8 F3 q6 R - *$ f. P8 E; H" t5 }4 ^
- */
1 E/ V% k( b& _+ p3 k' ?* H - @Component9 M1 _$ ?3 b, u) f8 T
- @Scope
) {( o) F4 I$ a9 k. V' R! J, i - @Aspect! T5 z0 T: p. K6 k* i
- public class LogAspect {; b+ W8 j# y7 [5 s5 A
- //Service层切点 用于记录错误日志. X& _9 g' z. {* i: M `& ]
- @Pointcut("@annotation(com.web.aop.ServiceLog)")
( \# p7 V2 Q( g" y- `& H/ l; D - public void serviceAspect() {
( O7 \; M' i5 R+ N f2 |3 g -
0 H- S8 y: b* P* d - }/ g# r# u( h( \0 t: W) r# m
- /**
. {0 T1 W4 [' u; ] - * 异常通知 用于拦截service层记录异常日志 * s, V+ m; s4 L* e1 K) J, |$ W0 g
- * @Author 张志朋
( I c9 N1 G) Z! z - * @param joinPoint
% {# k0 z" B+ m; p# X - * @param e void4 S) P! ]/ U4 K' d1 k% k
- * @Date 2015年6月3日* I3 E* h6 G2 m9 N5 L: Q; E- ?
- * 更新日志
# o/ F+ G9 f: F' Z$ ] - * 2015年6月3日 张志朋 首次创建
) i/ z' N/ r3 b3 w" M - *1 {* @; ]" u# k5 Y1 M
- */
0 ^5 E: x: N3 D! ^6 S; t# y) k - @AfterThrowing(pointcut = "serviceAspect()", throwing = "e")
% u# {8 W; `" F9 B0 |, N; T5 ? - public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
5 X; ^% z9 M0 X" a# S - HttpServletRequest request = ServletActionContext.getRequest();
: I5 J) G. T" _0 t! m - TeacherEntity user = CommonUtil.getUser();
- A% A- T1 f$ j4 e: } - String ip = AddressUtils.getIpAddr(request);4 Y' a! ^% q) r$ K5 H& C
- try {
5 j% [2 ^0 b5 T2 d$ t( x - String params = "";- v4 _4 R2 r* S% z. o: Z" |5 C7 ^
- if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
! X4 q+ J+ z0 b. m7 k2 } - for (int i = 0; i < joinPoint.getArgs().length; i++) { k% \" R+ D! ~3 d1 Q
- params += JSONUtil.toJSONstring(joinPoint.getArgs()[i]) + ";";
/ V6 S- D' N2 {# t" z - }
7 X9 ^: K. X; q - }
' T* `2 \/ k+ z- D% R - String description = getServiceMthodDescription(joinPoint);//用户操作
f8 L0 \! u I. L! Q5 x. K - String exceptionCode =e.getClass().getName();//异常类型代码
& [# |- H* a6 r* Q - String exceptionDetail = e.getMessage();//异常详细信息
7 T1 C* M: n9 }" ?3 b; Q6 G* ^ - String method = joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()";//异常方法
* s& P7 g' d1 R - /*==========记录数据库异常日志==========*/
! }# B4 |$ ^; D: p; J - Log log = new Log();
3 A7 M7 e" ~6 j" {: d" l - log.setDescription(description);' c! K( p1 E: j/ U# T: c
- log.setExceptionCode(exceptionCode);# ?& @- \6 W6 G& T. s4 S
- log.setExceptionDetail(exceptionDetail);0 Z5 _! { C+ \* U7 M, J( e' c
- log.setMethod(method);2 o$ U/ e6 [2 ]
- log.setType(Constants.LOG_ERROE);// 日志类型' U9 {# O, N6 J* L1 X) K
- log.setRequestIp(ip);// 请求IP- [8 `) a6 q3 r! Z- f4 M
- log.setParams(params);//请求参数% n+ S% ?# V% i- N/ C
- if(null!=user){' I5 u. O K4 ^9 t% i
- log.setCreateUid(user.getUid());//用户ID. f) j/ }. R$ ]- S
- log.setCreateName(user.getNickname());//用户昵称
4 f6 J/ M, b7 G0 R' k6 n$ x - }! A& k- ~- y# ?* E( l% M5 |5 q
- log.setPlatFrom(Constants.SUBJECT_CODE);: v: A2 O, p( T
- /*==========记录数本地异常日志==========*/
' R& v/ O& W$ s' A! H2 U - //LogUtil.error(description, e);
* C4 r, E- S- w& D - /*==========发送异常日志到邮箱==========*/
- f% x N2 C, e6 l! \+ d - StringBuffer errorMsg = new StringBuffer();4 M" V& L0 T0 t& E
- errorMsg.append("异常方法:");
) N* K/ L; C* ^ - errorMsg.append(method);
, _( [' M$ y% H+ L u- m# ~ - errorMsg.append("</br>");4 o7 v. w# }7 m/ s9 n9 w. T4 `" v
- errorMsg.append("异常类型代码:");
8 U; r0 C% ^% g. y( e0 }' ?, f! { - errorMsg.append(exceptionCode);
, `+ w8 n/ Q( g" C - errorMsg.append("</br>");: k) ? A9 u3 I5 P. ?. Y1 g' @
- errorMsg.append("异常详细信息:");# ]( c9 G( }4 E# J( I
- errorMsg.append(exceptionDetail);# c4 d" @- N& k4 E: E
- errorMsg.append("</br>");
9 f1 [: ^( f1 H - log.setErrorMsg(errorMsg.toString());
+ M |9 @ ]3 r6 U - WebServiceMathClient Client = new WebServiceMathClient();
3 ?, l0 y6 L/ {( N/ v - Client.sendError(log);# Y9 E; d. H5 T+ U7 Q8 y
- } catch (Exception ex) {
+ u) g4 `; h) R7 e2 F# b - e.printStackTrace();
( L( c( b. h4 q8 M - }
' ]% Y0 y0 x. _) I - } 3 x# U+ z/ U% ?: m; E+ e
- /**
* Z1 [) H0 g7 D( J) ]8 Q7 | - * 获取注解中对方法的描述信息 用于service层注解 (基于反射)" p8 \7 P8 L; y4 s, V3 r O& E! w4 D
- * @Author 张志朋
0 Y, E; e, I+ L% A2 k+ @' y" V) N - * @param joinPoint
) \$ B2 W3 _! D - * @return
$ A' V9 ` Y; q; G, U, H/ D$ Q& Q - * @throws Exception String
6 X! N# x% \2 `9 U2 P - * @Date 2015年6月3日5 f; X" P- @! \3 W, X
- * 更新日志
" W& W2 @/ z! | R f - * 2015年6月3日 张志朋 首次创建3 v1 m* Q( e+ m
- *& L. K/ _# c* ~0 T; B/ w+ l9 V) f
- */
b& K7 {* y6 ]2 D* X7 x+ w - @SuppressWarnings("rawtypes")
: ]& J' s8 q9 d+ w, m - public static String getServiceMthodDescription(JoinPoint joinPoint)
- h+ [4 v: [( p/ `' s. [5 p6 V - throws Exception { ( M. f7 d6 n0 E' e0 _$ M4 h/ H7 U
- String targetName = joinPoint.getTarget().getClass().getName(); 4 S. w, O; r7 q7 q4 J
- String methodName = joinPoint.getSignature().getName();
! A8 A; a! Z% f5 Z# b e - Object[] arguments = joinPoint.getArgs(); 3 _; k2 e0 T3 n7 w4 t6 y% ~
- Class targetClass = Class.forName(targetName);
% r. u! T% t- P$ ]. [ - Method[] methods = targetClass.getMethods(); 7 t3 _; r7 z' C5 g
- String description = ""; # |, y) {" f* |( b, ~9 U9 z
- for (Method method : methods) {
7 X# i* b* C: |% z* ] - if (method.getName().equals(methodName)) {
# J( b* ?3 x' w8 f9 f0 m6 X - Class[] clazzs = method.getParameterTypes();
6 e2 f0 R7 U& T e* m& o6 A - if (clazzs.length == arguments.length) {
: v# g: W$ n( l: c - description = method.getAnnotation(ServiceLog. class).description(); * ^, q/ K2 m2 |6 e& v
- break;
; y( Y7 \" a3 W& Y: s8 G - }
8 {0 t3 P% j1 x9 B" w6 g! L - } 6 c) }& U/ y9 w: k
- } 2 A7 t$ s4 K( A9 s- `" J
- return description; ) v4 b! p1 b5 ?% ?4 X6 s
- }
/ k) N5 Y+ S" p2 T - }
复制代码 4 S" m/ l. a t( E# T/ I
这里说明一下 serviceAspect()方法 上面注释了 @Pointcut("@annotation(com.acts.web.aop.ServiceLog)") 、也就说明这是一个切入点,springAOP对其进行了封装。
9 o# z# @# E: h. q+ g2 odoAfterThrowing()方法上面加入了@AfterThrowing(pointcut = "serviceAspect()", throwing = "e") 对切入点的所有异常信息进行处理(记录日志到数据库或者发送错误信息到指定邮箱等等等,可以做任何你想做的事情)。 z% x9 {+ d. @- _
0 C: L" z l! S2 z' s
2.QuesPerServiceImpl.java(注意此类必须实现接口 默认JDK的动态代理实现是基于接口实现的 否则会报错)
( m. L: h, W0 `. H& C0 n- @ServiceLog(description="获取待审试题数量")
: @$ P8 y' O& _" N - public long getAuditQuesNum(TeacherEntity currentUser) throws Exception {! N" q3 m4 a5 N
- return quesPerDao.getAuditQuesNum(currentUser);
8 R2 o* D$ ^$ ]6 p5 N5 Q - }
复制代码
0 {! x8 m4 G" L% z" ?之所以定义description 描述 是为了更好的记录错误日志 文字总是比方法名 更容易识别。. V" s1 f: j P& k
二、AOP实现权限控制2 P, g: }7 P: P, K
上面说过使用动态代理的类 必须实现接口但是我们的action并没有实现接口。 JDK 的动态代理只能对实现了接口的目标类进行代理,而不实现接口的类就不能使用 JDK 的动态代理。
2 C- q# U: z# [4 Q/ A: y. \ 还好有第三方的包为我们解决了问题。项目中引入cglib.jar,CGLIB 是针对类来实现代理,当没有实现接口的类需要代理时就需要通过 CGLIB 来实现代理了,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但是因为采用的是继承,所以不能对 finall 类进行继承。
3 d5 Z0 _ u4 \1 @' o首先配置文件要引入这样一段配置(看注释说明):
& X" d9 X' z* j/ g4 ~. b- <!--通知spring使用cglib而不是jdk的来生成代理方法 AOP可以拦截到Controller(Action)-->
" ~( G# l7 }1 T9 _! k7 j - <aop:aspectj-autoproxy proxy-target-class="true"/>
复制代码
# `9 S$ z6 w0 _4 ]6 r8 i(1)、定义注释:
, f7 m7 T8 F" Y8 l/ V6 w1.Permission.java
4 J) }( A. T0 K4 C' k$ C5 }0 W, {- /**
( w8 J& m) j( H& v7 P6 ^ - * 自定义权限管理, I; b5 x( r& ?. d$ K, a
- * 创建者 张志朋
: ~& O2 v+ P5 H, t - * 创建时间 2015年6月30日
! Q. N, T. b& ]3 R5 W: x - *3 c2 W' }" @# d/ e' P
- */
* K/ x' ?6 S" k2 H% ?: @ - @Target({ElementType.PARAMETER, ElementType.METHOD})
) J" n+ b" \. v+ i7 k$ V0 N* Q; ^ - @Retention(RetentionPolicy.RUNTIME) " _1 ]! j8 n" P! ~" |
- @Documented
6 r% y: r4 R+ h2 M2 P' `3 [$ s - public @interface Permission { h$ v$ R/ w4 D( @# N5 i! ?" X$ s
- String name() default ""; //操作行为
& g0 @( n2 l3 z3 N/ R' E# _, }0 r0 f - int id() default -1;//权限值
& T% ]4 A3 E3 a- Z! o( U8 i - }
复制代码 (2)、定义切面以及切入点
# \* x; b+ K) X# ^3 T, B1.PsemissionAspect.java6 C v% Z: \: g8 n. K+ F& x
- /**7 _2 x) }7 G8 ~9 V: j% N
- * 权限管理
" H. C* k7 [3 s% J9 e9 o0 K - * 创建者 张志朋
% Q0 A& |0 O, g$ a) ^ - * 创建时间 2015年7月3日
& Y* I& s( a p" E% D - *! N/ M3 K! N1 {5 d6 _0 z! }
- */
+ x$ l$ q2 n% g: F - @Component
1 ^8 _/ x _* O# C/ e4 F - @Scope- I% c$ r, K8 E7 S1 u' Q$ J( Y
- @Aspect; b& @+ P v: [7 P' ?/ o \4 x' V4 F8 g
- public class PsemissionAspect {" L5 ~( |8 [0 r' ]+ j
- - ]+ o) s1 @8 c9 S5 n3 u! Y2 c6 j2 f
- //Controller层切点 用于权限控制
6 G& Q8 Y2 q/ Q' x - @Pointcut("@annotation(com.acts.web.aop.Permission)") / N0 x$ C! a+ j3 I: ^+ \0 t
- public void permissionAspect() {) r6 F5 g# v( h0 R9 ]! _4 Q
-
+ \2 u2 ?: Y: l3 x% D, B - }
4 n$ Y9 `& J/ `+ ]" L - /**/ S/ U6 g" Q; Q# z
- * 用于拦截Controller层用户操作权限(环绕通知)9 ?% ~! L. W/ ~. w" h: }
- * @Author 张志朋, B! H) g( D ^# |" F4 p
- * @param joinPoint void
9 N& b4 z) V/ [9 U' O - * @Date 2015年6月3日
) n& G$ O* Q# s4 X - * 更新日志
* [4 R( M8 U4 p* W- u& o: ` - * 2015年6月3日 张志朋 首次创建" C& z9 ], u* f; c
- *9 `# u+ ]$ K$ G6 ~; `5 ^7 \" e
- */
9 [) m; j$ b5 Q* ~" z9 g - @Around("permissionAspect()") 8 {. K8 T6 _( r
- public Object permission(ProceedingJoinPoint joinPoint)throws Throwable {
0 v! w9 Y1 h D0 K. y1 @( d! a2 ^ - Object retVal = null;: C4 n9 s7 }7 v' ]9 Z# L9 e
- int role = getControllerMethodRole(joinPoint);" h: s' ?# K5 L4 R
- TeacherEntity user = CommonUtil.getUser();
! P* i! ?4 t+ N - if((user.getSpecRole()&role)==role){//没有权限
! e5 w, ]; X0 O - retVal = joinPoint.proceed();
! q4 d% Z" X: P) u - }else{
3 W. g. w, A5 X" w% O - noAuthorization();/ {/ G, D _; f) e3 {
- }! i2 k8 z$ k8 b1 R+ I7 R
- return retVal;
: v- e! h# Q* o" t - }
7 r8 N6 `* e; v9 ~ - /**
& A9 }, Q4 U8 M9 {7 K6 ?; n - * 没有权限 实现跳转; a3 h' u& \( [ L7 B! I
- * @Author 张志朋$ c, @, C; w6 }8 U; ~: [* @. \8 A
- * @throws IOException void) Q d/ M8 z% j% d! \& \
- * @Date 2015年7月3日
& d! y( M/ y5 n$ ^ - * 更新日志
' R$ d8 ]0 W/ s7 F/ J - * 2015年7月3日 张志朋 首次创建
0 l/ C% l$ p. ~ - *7 ~; j9 c( L1 @$ U: D- G7 r
- */! ^5 }& G* o* Z$ ^; q
- public void noAuthorization() throws IOException{
8 a8 Y% [" r0 `+ B& e* v - HttpServletRequest request = ServletActionContext.getRequest(); T. i; ]! t1 y+ i% W
- String path = request.getContextPath();. C- \8 ~) x1 j0 e- \
- HttpServletResponse response = ServletActionContext.getResponse();
% F% v& o! g: @4 f5 ] - response.sendRedirect(path+"/pages/noAuthorization.jsp");
3 p- ~4 A& h' s; c1 f3 d8 C - }* a% ]' [3 w2 e
- /**" e3 n) d. a# c5 f, c3 q& I1 Y
- * 获取注解中对方法的权限值 用于Controller层注解
& z* G; z) e6 {$ |' i# M7 B. f' R - * @Author 张志朋( P r4 Z5 \6 {# T
- * @param joinPoint
' ~( C' ]8 @+ h. h+ ^4 a- G - * @return' |$ E% x& [" `) ] }+ B% Q i# B: ~% C
- * @throws Exception int" Z! v/ ~( _) x
- * @Date 2015年7月3日
0 n& C3 M9 f9 n/ x! q# g - * 更新日志8 C8 p* j6 S! |
- * 2015年7月3日 张志朋 首次创建" h2 A5 L8 ~; O$ J4 X& |. B
- *' S- x4 z! m" [
- */
4 j4 c) W3 H$ \3 s, F - @SuppressWarnings("rawtypes"). i* m8 f. M. a
- public static int getControllerMethodRole(JoinPoint joinPoint) throws Exception {
# Z& A& r% s0 G# d - String targetName = joinPoint.getTarget().getClass().getName(); 3 W% N) ?5 V3 v2 ?( j1 U0 }
- String methodName = joinPoint.getSignature().getName(); 6 o9 n4 y+ ~; S- A: c
- Object[] arguments = joinPoint.getArgs();
e" J' N+ n/ V' `2 a) n - Class targetClass = Class.forName(targetName);
/ t5 {- h5 M+ \: } - Method[] methods = targetClass.getMethods(); 2 i! _# d& v7 o P& B0 l
- int role = -1;
# c9 }5 f$ ]# ?+ B } - for (Method method : methods) { 2 q4 X }! m" i
- if (method.getName().equals(methodName)) {
' J! R9 h ~) t6 Z0 b6 r2 v$ t: s+ W - Class[] clazzs = method.getParameterTypes(); ' l! g: m9 D. a: Y# m; |
- if (clazzs.length == arguments.length) {
2 q3 U; m' j+ L3 M1 j1 v( R- K - role = method.getAnnotation(Permission. class).id();
* N/ k; G) P: c% h3 ? - break;
) { E/ R+ O* h - }
+ d. ]& I2 a2 i2 ~9 h) z' C( ~ - }
6 [7 b+ V1 \: E* I - } 9 c) ~9 b: X- x5 i, g) ^
- return role;
/ m" v6 o3 Q/ ^' N - }
复制代码
! N9 n' a/ Y7 d% ~- F2.action层代码实现:: C6 D* y5 D( t8 B5 ^+ P: ]* v, z
- /**$ r/ Q+ v6 C) \! J! p! D( x( y
- * 试题审核不通过: v8 |0 W& j2 d
- * @Author 张志朋 void
G& M6 b/ E* s2 d - * @Date 2015年5月4日
$ a1 V: f3 e2 k; d, {( [8 I - * 更新日志
7 k$ a% W3 s( A7 p$ T1 D - * 2015年5月4日 张志朋 首次创建
7 A; l0 P, A1 B - *$ g# T) p9 O# v& }: ^% T; f A
- */
$ z- d8 b% I4 O. Y - @Permission(name="审核试题权限(审核不通过)",id=Constants.ROLE_QUES_AUDIT)
0 B$ q. R$ V3 J0 ^5 G - public void auditQuestions(){ p& C8 B3 f" U8 @7 B
- try {
* v8 D; j- ~8 Q - //代码实现- J2 N+ u8 `3 J" t8 g/ U
- } catch (Exception e) {
. i" N. T5 ]1 `0 C - e.printStackTrace();) m u+ x. T i& W5 n* Z' b
- }# F0 W, N9 ?- I; R0 q, j% Q$ h4 l
- F% ^" {* n9 j o+ u- }
复制代码
& Q0 a) C9 a4 X: |9 e+ X9 Z+ g- B- ]4 y9 _
|
|