springAOP实现的异常日志记录+异常邮件发送+权限控制
2016-03-08 17:10
597 查看
一般我们的异常都会抛出到控制层,如果使用struts2也就是action。然后try{//正确代码实现}catch{//在里面记录错误日志},这样咋一看是不错,代码很完美。但是如果项目中有成千上万个项目怎么办?难道在每个action的catch里面都要加入异常记录代码?很显然工作量是很大的。
鉴于项目中配置了数据库事务,其实也是使用了AOP 详见applicationContext-service.xml配置文件。由于配置文件的局限性这里采用注释的方式实现。之所有使用注释是可以自定义参数并实现日志的详细记录。既然使用注释,现成的没有,只有自己定义来实现需求。其实spring
注释实现的注入、hibernate的model类注释实现与数据库关联以及我们最常见Override。
资料:java如何实现自定义注释/article/4739577.html+
l# q+ o8 e' ]2 x% ]# F
% t! x- o! A7 m& `8 q" p2 o
一、 记录日志并发送邮件通知4 y! ~7 [/ L! ?4 ]4 s; M
(1)、定义注解:
1.ServiceLog.java(各种参数类型详见上面的资料)
import java.lang.annotation.*;
/**
* 自定义注解 拦截service : ~. L- V8 v( t$ \9 ^6 V% g
* 创建者 张志朋+ x7 c Z# W; b# T- G& W( o: t
* 创建时间 2015年6月3日9 d; P1 X) r6 {6 q# u% h& p6 k6 H
*
*/1 j! l9 _+ e/ z' S
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME) 1 M; d7 P x$ ^8 x( v( E
@Documented
public @interface ServiceLog { 6 D4 w3 z2 y! A1 h
String description() default "";
}
复制代码
2.ControllerLog.java)
v7 n! A. q. a
import java.lang.annotation.*;
- y6 V9 ~& T" u6 }6 t" D' e% \2 E
/**
* 自定义注解 拦截Controller
* 创建者 张志朋 S; q: G8 h) Y' T
* 创建时间 2015年6月3日0 n- V: l' t( h2 C, Y9 i" [
*
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
% R, ]9 ?( S2 b
@Retention(RetentionPolicy.RUNTIME)
@Documented+ v% F( p2 \* s( ` _7 c
public @interface ControllerLog {( x2 \5 o$ y/ Y; G0 {, d
String description() default ""; 7 k- m. x% \7 n) O
}
复制代码
(2)、定义切面以及切入点1 M1 m4 u! b7 l
1.LogAspect.java6 w: S& Y. ^6 J
/**
* 日志记录AOP
* 创建者 张志朋
* 创建时间 2015年6月3日! {) e5 l- m* i; O: l# ]
*/ g, h) `& i* q- x+ A! o( C* R
*/
@Component
@Scope8 j0 @$ R: l% p5 I# a: u$ w4 |
@Aspect
public class LogAspect {/ P. [% F( v% ?- I2 [$ R
//Service层切点 用于记录错误日志
@Pointcut("@annotation(com.web.aop.ServiceLog)")
public void serviceAspect() {
Z' e- i4 d! C; R: v
}4 {* e) K' j! k2 c
/**( G8 V$ a D5 X1 m4 h
* 异常通知 用于拦截service层记录异常日志 3 C4 I" p- e) X* O$ F, j
* @Author 张志朋0 u% _ _, P( H) e6 {4 O
* @param joinPoint
* @param e void ~6 [" q- B, K* C& u$ H: ?( z8 i
* @Date 2015年6月3日
* 更新日志
* 2015年6月3日 张志朋 首次创建 ^9 X/ Z8 g; n6 c/ a! r; H5 J
*- X# i8 H: u) A0 `3 ]: _3 z
*/
@AfterThrowing(pointcut = "serviceAspect()", throwing = "e")
# F& ^/ ^& e1 Y. g$ f: E
public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
! n$ ~9 v0 t+ R" Z: c/ C) [
HttpServletRequest request = ServletActionContext.getRequest();# [9 ^. \( u% Z/ r1 b
TeacherEntity user = CommonUtil.getUser();
String ip = AddressUtils.getIpAddr(request);, P5 }1 B0 X. }1 D
try {
String params = "";' Z+ y6 N) J& ]: A
if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
for (int i = 0; i < joinPoint.getArgs().length; i++) {
params += JSONUtil.toJSONstring(joinPoint.getArgs()[i]) + ";";# n& ~! N. H3 [: S" M
}6 h! K6 z F$ ?0 H' I2 c) n
}
String description = getServiceMthodDescription(joinPoint);//用户操作8 d7 r0 {! G4 S; P/ ]! C2 L* m
String exceptionCode =e.getClass().getName();//异常类型代码3 }: p" W3 I1 J
String exceptionDetail = e.getMessage();//异常详细信息; l3 u3 R& D" l
String method = joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()";//异常方法
/*==========记录数据库异常日志==========*/ &
^1 }% o# t4 S5 R' `/ \( H8 y& U# R% o
Log log =
new
Log();
log.setDescription(description);
log.setExceptionCode(exceptionCode);8 S! X8 j! C1 h& y2 s& z
log.setExceptionDetail(exceptionDetail);
log.setMethod(method);( f) g) b7 ~: {/ j
log.setType(Constants.LOG_ERROE);// 日志类型, B0 J' P# p6 T* K/ p. m
log.setRequestIp(ip);// 请求IP& o* ?4 e- L, b& A; |6 M
log.setParams(params);//请求参数0 h2 D7 s* s0 @7 K9 ?. t
if(null!=user){, O/ l6 M7 x$ S6 K# |5 r& s! K7 q
log.setCreateUid(user.getUid());//用户ID( z0 L( j$ ~: J" K' J% v
log.setCreateName(user.getNickname());//用户昵称
}" s9 ~: U6 y- G- M' Q' }
log.setPlatFrom(Constants.SUBJECT_CODE);
/*==========记录数本地异常日志==========*/
//LogUtil.error(description, e);; T8 N! s/ l* Q
/*==========发送异常日志到邮箱==========*/
StringBuffer errorMsg =
new
StringBuffer();5 |' L( e# ~+ R% Q' r$ g( U* g
errorMsg.append("异常方法:");
errorMsg.append(method);
errorMsg.append("</br>");& E- N- u; w1 E) M+ Y6 I( L$ [
errorMsg.append("异常类型代码:");0 ^$ R5 I/ R8 {
errorMsg.append(exceptionCode);7 z. ~; m. H) c; C( I
errorMsg.append("</br>");
errorMsg.append("异常详细信息:");
errorMsg.append(exceptionDetail);- X' n: G0 Z" s" Z( o# v) r$ U7 k
errorMsg.append("</br>");
log.setErrorMsg(errorMsg.toString());3 |, C- c5 N3 s, ?/ i& m
WebServiceMathClient Client =
new
WebServiceMathClient();$ u% a& x/ n* s
Client.sendError(log);
} catch (Exception ex) {* d6 U3 M% Z7 n. W0 S
e.printStackTrace();
}* c$ B6 q6 \. N: Z3 w5 y
} 5 \( I% M- y& t) r
/**
* 获取注解中对方法的描述信息 用于service层注解 (基于反射)4 |; L( M9 d" `8 _. m! n& X5 ]
* @Author 张志朋
* @param joinPoint
* @return
* @throws Exception String
* @Date 2015年6月3日
* 更新日志
* 2015年6月3日 张志朋 首次创建
*
*/
@SuppressWarnings("rawtypes")
public static String getServiceMthodDescription(JoinPoint joinPoint)
throws Exception { 0 W* G s D7 D2 b; w. H
String targetName = joinPoint.getTarget().getClass().getName();
% F8 s+ \: Z3 ?7 \$ ]
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
6 v$ V7 n5 K& {) O8 x
Class targetClass = Class.forName(targetName);
% _: @/ t$ y* q$ N& j
Method[] methods =
targetClass.getMethods();
String description = "";
for (Method method : methods) { , k R# C- s7 v$ L
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
2 R# E# k2 G7 I4 c$ X) Y
description = method.getAnnotation(ServiceLog. class).description();
break;
}
} - v8 ~( _: X( Z
}
return description;
} # I/ ?! V; V' q5 o0 z
}
复制代码
这里说明一下 serviceAspect()方法 上面注释了 @Pointcut("@annotation(com.acts.web.aop.ServiceLog)") 、也就说明这是一个切入点,springAOP对其进行了封装。
doAfterThrowing()方法上面加入了@AfterThrowing(pointcut = "serviceAspect()", throwing = "e") 对切入点的所有异常信息进行处理(记录日志到数据库或者发送错误信息到指定邮箱等等等,可以做任何你想做的事情)。
* U: G8 b. E7 a
2.QuesPerServiceImpl.java(注意此类必须实现接口
默认JDK的动态代理实现是基于接口实现的 否则会报错)3 v5 C( c! m% H+ J0 w; `) g/ M" i
@ServiceLog(description="获取待审试题数量")/ \( }1 m3 c8 a
public long
getAuditQuesNum(TeacherEntity currentUser) throws Exception {7 {( q8 U+ l2 ]2 M5 i/ h1 y
return quesPerDao.getAuditQuesNum(currentUser);
}
复制代码
之所以定义description 描述 是为了更好的记录错误日志 文字总是比方法名 更容易识别。! q9 r% w- _% |0 H n3 Z! `
二、AOP实现权限控制
上面说过使用动态代理的类 必须实现接口但是我们的action并没有实现接口。 JDK 的动态代理只能对实现了接口的目标类进行代理,而不实现接口的类就不能使用 JDK 的动态代理。/ B4 `/ O. K$ L; u* ~
还好有第三方的包为我们解决了问题。项目中引入cglib.jar,CGLIB 是针对类来实现代理,当没有实现接口的类需要代理时就需要通过
CGLIB 来实现代理了,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但是因为采用的是继承,所以不能对
finall 类进行继承。
首先配置文件要引入这样一段配置(看注释说明):: j# ] _7 X: o/ \5 [* ~% A D$ }% k
<!--通知spring使用cglib而不是jdk的来生成代理方法
AOP可以拦截到Controller(Action)-->! V+ A3 o+ F/ c- n5 b0 U
<aop:aspectj-autoproxy proxy-target-class="true"/>
复制代码
I1 G0 ]! Z& O1 z
(1)、定义注释:
1.Permission.java
/**/ I) L0 }6 W3 p* q! W/ ?( a8 i
* 自定义权限管理
* 创建者 张志朋
* 创建时间 2015年6月30日( n: [8 B& z- F: D4 K* O' ~
*, {9 `4 ~* P- h) P& Z$ i e" J# G
*/7 M' ]! E4 r7 N* N$ z
@Target({ElementType.PARAMETER, ElementType.METHOD})
) y8 _ M9 T. X9 Y- J- R
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Permission {
String name() default ""; //操作行为
int id() default -1;//权限值
}
复制代码
(2)、定义切面以及切入点
1.PsemissionAspect.java,
X0 h4 T, c% R# u* u6 E& r" a
/**
* 权限管理
* 创建者 张志朋
* 创建时间 2015年7月3日+ w; @. ]$ l/ _) X/ f
*4 e( B" q' } B1 C* }( _; y
*/! V; M; x: ]9 X# J; V1 N& c" A2 Q
@Component* s" l. ?' U( r( n# x
@Scope% U( P, l! q+ [1 f
@Aspect, q* ~8 `$ G+ `/ N7 M& w
public class PsemissionAspect {
" E& c, n; x G
//Controller层切点 用于权限控制. G$ L# x% l- a9 ^) o5 ^
@Pointcut("@annotation(com.acts.web.aop.Permission)")
public void permissionAspect() {
}! k G' ?, J4 J5 k
/**
* 用于拦截Controller层用户操作权限(环绕通知)
* @Author 张志朋
* @param joinPoint void3 r# p: b" b$ n3 Z, U
* @Date 2015年6月3日/ b/ C* y+ ^6 \. z' \
* 更新日志
* 2015年6月3日 张志朋 首次创建! o6 d- C3 V: k/ J6 H, ~
** j! O( p+ a6 e& ?
*/, K! V. a, w( D/ G
@Around("permissionAspect()")
public Object permission(ProceedingJoinPoint joinPoint)throws Throwable {
Object retVal = null;+ Z" m9 g" Z# ~3 K' I/ p( |. j
int role = getControllerMethodRole(joinPoint);8 d% J# e o9 s% m2 K" C) X7 E }5 o7 N
TeacherEntity user = CommonUtil.getUser();
if((user.getSpecRole()&role)==role){//没有权限8 K! v4 t$ u1 n9 q, n3 D
retVal = joinPoint.proceed();# \+ Z {' Z/ H/ x8 A8 |4 r( q
}else{
noAuthorization();1 g4 F7 d& _: r
}
return retVal;3 a+ q7 g- Z0 r, S& z& C- X
}: ?$ _1 T2 Q. V& u7 p# R/ ~2 j
/**
* 没有权限 实现跳转4 d7 n' q. c* h5 i0 H& Z3 j& {. m
* @Author 张志朋
* @throws IOException void
* @Date 2015年7月3日
* 更新日志% p2 f, w# [) S, J6 F/ {
* 2015年7月3日 张志朋 首次创建$ v3 H) E- V4 {; S! H9 Q9 `
*, R* K; p) X4 K& ^, ^
*/) ~% Q- M- Y* J$ H: x$ v
public void noAuthorization() throws IOException{
HttpServletRequest request = ServletActionContext.getRequest();
String path = request.getContextPath();
HttpServletResponse response = ServletActionContext.getResponse();0 h- n9 \4 P- n% G8 _7 ~
response.sendRedirect(path+"/pages/noAuthorization.jsp");# v7 O# |# p; a9 B
}+ e: h' w9 b9 r: G
/**- D" C9 P; ~$ x$ k1 y ^
* 获取注解中对方法的权限值 用于Controller层注解 & B" T K! |' @, b; f$ ]
* @Author 张志朋' C3 ^) ?" r. {/ T
* @param joinPoint- G1 M4 T0 O2 h, }2 k; S! ]7 N
* @return2 T; ?7 t. Z; f) T7 g B) G
* @throws Exception int
* @Date 2015年7月3日# d3 v. j9 |6 h# Y- f
* 更新日志) x; M. l9 z( s* I Z; V3 w( b; h
* 2015年7月3日 张志朋 首次创建6 C1 J8 ~7 `; I
*
*/ g* c8 _5 h' f
@SuppressWarnings("rawtypes")
public static int getControllerMethodRole(JoinPoint joinPoint) throws Exception {/ Z5 }$ A' O4 a! c# l
String targetName = joinPoint.getTarget().getClass().getName();
: r. D2 X) ~" t7 j: i% L
String methodName = joinPoint.getSignature().getName();
( ]1 ?! v4 ?% b. s/ W/ o! P
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
9 _- m; s* s6 {9 r+ R O2 [8 Y
Method[] methods =
targetClass.getMethods();
6 w0 q$ D% A4 U+ l
int role = -1;
for (Method method : methods) { " B+ C7 I. \2 m5 i) w R
if (method.getName().equals(methodName)) {
& N) M. w }4 u: j* p v
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
role = method.getAnnotation(Permission. class).id();
break;
}
}
} 7 _* H- x2 b1 H
return role;
}
复制代码
0 D, F; Y& O% c/ v) p
2.action层代码实现:
/**
* 试题审核不通过
* @Author 张志朋 void* u/ t3 p Y/ N8 r7 z: e) P
* @Date 2015年5月4日1 H9 N! ^2 T( ^
* 更新日志
* 2015年5月4日 张志朋 首次创建
*
*// C: H: Y, x( b' J
@Permission(name="审核试题权限(审核不通过)",id=Constants.ROLE_QUES_AUDIT)$ C- I" p0 R) S, I! ]
public void auditQuestions(){. o; ?# b6 Y# E% o; z4 r! x! u
try {
//代码实现3 ^9 a2 U3 R' b
} catch (Exception e) {8 q7 {2 Z! Z/ K# R
e.printStackTrace();
}
}
复制代码
鉴于项目中配置了数据库事务,其实也是使用了AOP 详见applicationContext-service.xml配置文件。由于配置文件的局限性这里采用注释的方式实现。之所有使用注释是可以自定义参数并实现日志的详细记录。既然使用注释,现成的没有,只有自己定义来实现需求。其实spring
注释实现的注入、hibernate的model类注释实现与数据库关联以及我们最常见Override。
资料:java如何实现自定义注释/article/4739577.html+
l# q+ o8 e' ]2 x% ]# F
% t! x- o! A7 m& `8 q" p2 o
一、 记录日志并发送邮件通知4 y! ~7 [/ L! ?4 ]4 s; M
(1)、定义注解:
1.ServiceLog.java(各种参数类型详见上面的资料)
import java.lang.annotation.*;
/**
* 自定义注解 拦截service : ~. L- V8 v( t$ \9 ^6 V% g
* 创建者 张志朋+ x7 c Z# W; b# T- G& W( o: t
* 创建时间 2015年6月3日9 d; P1 X) r6 {6 q# u% h& p6 k6 H
*
*/1 j! l9 _+ e/ z' S
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME) 1 M; d7 P x$ ^8 x( v( E
@Documented
public @interface ServiceLog { 6 D4 w3 z2 y! A1 h
String description() default "";
}
复制代码
2.ControllerLog.java)
v7 n! A. q. a
import java.lang.annotation.*;
- y6 V9 ~& T" u6 }6 t" D' e% \2 E
/**
* 自定义注解 拦截Controller
* 创建者 张志朋 S; q: G8 h) Y' T
* 创建时间 2015年6月3日0 n- V: l' t( h2 C, Y9 i" [
*
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
% R, ]9 ?( S2 b
@Retention(RetentionPolicy.RUNTIME)
@Documented+ v% F( p2 \* s( ` _7 c
public @interface ControllerLog {( x2 \5 o$ y/ Y; G0 {, d
String description() default ""; 7 k- m. x% \7 n) O
}
复制代码
(2)、定义切面以及切入点1 M1 m4 u! b7 l
1.LogAspect.java6 w: S& Y. ^6 J
/**
* 日志记录AOP
* 创建者 张志朋
* 创建时间 2015年6月3日! {) e5 l- m* i; O: l# ]
*/ g, h) `& i* q- x+ A! o( C* R
*/
@Component
@Scope8 j0 @$ R: l% p5 I# a: u$ w4 |
@Aspect
public class LogAspect {/ P. [% F( v% ?- I2 [$ R
//Service层切点 用于记录错误日志
@Pointcut("@annotation(com.web.aop.ServiceLog)")
public void serviceAspect() {
Z' e- i4 d! C; R: v
}4 {* e) K' j! k2 c
/**( G8 V$ a D5 X1 m4 h
* 异常通知 用于拦截service层记录异常日志 3 C4 I" p- e) X* O$ F, j
* @Author 张志朋0 u% _ _, P( H) e6 {4 O
* @param joinPoint
* @param e void ~6 [" q- B, K* C& u$ H: ?( z8 i
* @Date 2015年6月3日
* 更新日志
* 2015年6月3日 张志朋 首次创建 ^9 X/ Z8 g; n6 c/ a! r; H5 J
*- X# i8 H: u) A0 `3 ]: _3 z
*/
@AfterThrowing(pointcut = "serviceAspect()", throwing = "e")
# F& ^/ ^& e1 Y. g$ f: E
public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
! n$ ~9 v0 t+ R" Z: c/ C) [
HttpServletRequest request = ServletActionContext.getRequest();# [9 ^. \( u% Z/ r1 b
TeacherEntity user = CommonUtil.getUser();
String ip = AddressUtils.getIpAddr(request);, P5 }1 B0 X. }1 D
try {
String params = "";' Z+ y6 N) J& ]: A
if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
for (int i = 0; i < joinPoint.getArgs().length; i++) {
params += JSONUtil.toJSONstring(joinPoint.getArgs()[i]) + ";";# n& ~! N. H3 [: S" M
}6 h! K6 z F$ ?0 H' I2 c) n
}
String description = getServiceMthodDescription(joinPoint);//用户操作8 d7 r0 {! G4 S; P/ ]! C2 L* m
String exceptionCode =e.getClass().getName();//异常类型代码3 }: p" W3 I1 J
String exceptionDetail = e.getMessage();//异常详细信息; l3 u3 R& D" l
String method = joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()";//异常方法
/*==========记录数据库异常日志==========*/ &
^1 }% o# t4 S5 R' `/ \( H8 y& U# R% o
Log log =
new
Log();
log.setDescription(description);
log.setExceptionCode(exceptionCode);8 S! X8 j! C1 h& y2 s& z
log.setExceptionDetail(exceptionDetail);
log.setMethod(method);( f) g) b7 ~: {/ j
log.setType(Constants.LOG_ERROE);// 日志类型, B0 J' P# p6 T* K/ p. m
log.setRequestIp(ip);// 请求IP& o* ?4 e- L, b& A; |6 M
log.setParams(params);//请求参数0 h2 D7 s* s0 @7 K9 ?. t
if(null!=user){, O/ l6 M7 x$ S6 K# |5 r& s! K7 q
log.setCreateUid(user.getUid());//用户ID( z0 L( j$ ~: J" K' J% v
log.setCreateName(user.getNickname());//用户昵称
}" s9 ~: U6 y- G- M' Q' }
log.setPlatFrom(Constants.SUBJECT_CODE);
/*==========记录数本地异常日志==========*/
//LogUtil.error(description, e);; T8 N! s/ l* Q
/*==========发送异常日志到邮箱==========*/
StringBuffer errorMsg =
new
StringBuffer();5 |' L( e# ~+ R% Q' r$ g( U* g
errorMsg.append("异常方法:");
errorMsg.append(method);
errorMsg.append("</br>");& E- N- u; w1 E) M+ Y6 I( L$ [
errorMsg.append("异常类型代码:");0 ^$ R5 I/ R8 {
errorMsg.append(exceptionCode);7 z. ~; m. H) c; C( I
errorMsg.append("</br>");
errorMsg.append("异常详细信息:");
errorMsg.append(exceptionDetail);- X' n: G0 Z" s" Z( o# v) r$ U7 k
errorMsg.append("</br>");
log.setErrorMsg(errorMsg.toString());3 |, C- c5 N3 s, ?/ i& m
WebServiceMathClient Client =
new
WebServiceMathClient();$ u% a& x/ n* s
Client.sendError(log);
} catch (Exception ex) {* d6 U3 M% Z7 n. W0 S
e.printStackTrace();
}* c$ B6 q6 \. N: Z3 w5 y
} 5 \( I% M- y& t) r
/**
* 获取注解中对方法的描述信息 用于service层注解 (基于反射)4 |; L( M9 d" `8 _. m! n& X5 ]
* @Author 张志朋
* @param joinPoint
* @return
* @throws Exception String
* @Date 2015年6月3日
* 更新日志
* 2015年6月3日 张志朋 首次创建
*
*/
@SuppressWarnings("rawtypes")
public static String getServiceMthodDescription(JoinPoint joinPoint)
throws Exception { 0 W* G s D7 D2 b; w. H
String targetName = joinPoint.getTarget().getClass().getName();
% F8 s+ \: Z3 ?7 \$ ]
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
6 v$ V7 n5 K& {) O8 x
Class targetClass = Class.forName(targetName);
% _: @/ t$ y* q$ N& j
Method[] methods =
targetClass.getMethods();
String description = "";
for (Method method : methods) { , k R# C- s7 v$ L
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
2 R# E# k2 G7 I4 c$ X) Y
description = method.getAnnotation(ServiceLog. class).description();
break;
}
} - v8 ~( _: X( Z
}
return description;
} # I/ ?! V; V' q5 o0 z
}
复制代码
这里说明一下 serviceAspect()方法 上面注释了 @Pointcut("@annotation(com.acts.web.aop.ServiceLog)") 、也就说明这是一个切入点,springAOP对其进行了封装。
doAfterThrowing()方法上面加入了@AfterThrowing(pointcut = "serviceAspect()", throwing = "e") 对切入点的所有异常信息进行处理(记录日志到数据库或者发送错误信息到指定邮箱等等等,可以做任何你想做的事情)。
* U: G8 b. E7 a
2.QuesPerServiceImpl.java(注意此类必须实现接口
默认JDK的动态代理实现是基于接口实现的 否则会报错)3 v5 C( c! m% H+ J0 w; `) g/ M" i
@ServiceLog(description="获取待审试题数量")/ \( }1 m3 c8 a
public long
getAuditQuesNum(TeacherEntity currentUser) throws Exception {7 {( q8 U+ l2 ]2 M5 i/ h1 y
return quesPerDao.getAuditQuesNum(currentUser);
}
复制代码
之所以定义description 描述 是为了更好的记录错误日志 文字总是比方法名 更容易识别。! q9 r% w- _% |0 H n3 Z! `
二、AOP实现权限控制
上面说过使用动态代理的类 必须实现接口但是我们的action并没有实现接口。 JDK 的动态代理只能对实现了接口的目标类进行代理,而不实现接口的类就不能使用 JDK 的动态代理。/ B4 `/ O. K$ L; u* ~
还好有第三方的包为我们解决了问题。项目中引入cglib.jar,CGLIB 是针对类来实现代理,当没有实现接口的类需要代理时就需要通过
CGLIB 来实现代理了,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但是因为采用的是继承,所以不能对
finall 类进行继承。
首先配置文件要引入这样一段配置(看注释说明):: j# ] _7 X: o/ \5 [* ~% A D$ }% k
<!--通知spring使用cglib而不是jdk的来生成代理方法
AOP可以拦截到Controller(Action)-->! V+ A3 o+ F/ c- n5 b0 U
<aop:aspectj-autoproxy proxy-target-class="true"/>
复制代码
I1 G0 ]! Z& O1 z
(1)、定义注释:
1.Permission.java
/**/ I) L0 }6 W3 p* q! W/ ?( a8 i
* 自定义权限管理
* 创建者 张志朋
* 创建时间 2015年6月30日( n: [8 B& z- F: D4 K* O' ~
*, {9 `4 ~* P- h) P& Z$ i e" J# G
*/7 M' ]! E4 r7 N* N$ z
@Target({ElementType.PARAMETER, ElementType.METHOD})
) y8 _ M9 T. X9 Y- J- R
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Permission {
String name() default ""; //操作行为
int id() default -1;//权限值
}
复制代码
(2)、定义切面以及切入点
1.PsemissionAspect.java,
X0 h4 T, c% R# u* u6 E& r" a
/**
* 权限管理
* 创建者 张志朋
* 创建时间 2015年7月3日+ w; @. ]$ l/ _) X/ f
*4 e( B" q' } B1 C* }( _; y
*/! V; M; x: ]9 X# J; V1 N& c" A2 Q
@Component* s" l. ?' U( r( n# x
@Scope% U( P, l! q+ [1 f
@Aspect, q* ~8 `$ G+ `/ N7 M& w
public class PsemissionAspect {
" E& c, n; x G
//Controller层切点 用于权限控制. G$ L# x% l- a9 ^) o5 ^
@Pointcut("@annotation(com.acts.web.aop.Permission)")
public void permissionAspect() {
}! k G' ?, J4 J5 k
/**
* 用于拦截Controller层用户操作权限(环绕通知)
* @Author 张志朋
* @param joinPoint void3 r# p: b" b$ n3 Z, U
* @Date 2015年6月3日/ b/ C* y+ ^6 \. z' \
* 更新日志
* 2015年6月3日 张志朋 首次创建! o6 d- C3 V: k/ J6 H, ~
** j! O( p+ a6 e& ?
*/, K! V. a, w( D/ G
@Around("permissionAspect()")
public Object permission(ProceedingJoinPoint joinPoint)throws Throwable {
Object retVal = null;+ Z" m9 g" Z# ~3 K' I/ p( |. j
int role = getControllerMethodRole(joinPoint);8 d% J# e o9 s% m2 K" C) X7 E }5 o7 N
TeacherEntity user = CommonUtil.getUser();
if((user.getSpecRole()&role)==role){//没有权限8 K! v4 t$ u1 n9 q, n3 D
retVal = joinPoint.proceed();# \+ Z {' Z/ H/ x8 A8 |4 r( q
}else{
noAuthorization();1 g4 F7 d& _: r
}
return retVal;3 a+ q7 g- Z0 r, S& z& C- X
}: ?$ _1 T2 Q. V& u7 p# R/ ~2 j
/**
* 没有权限 实现跳转4 d7 n' q. c* h5 i0 H& Z3 j& {. m
* @Author 张志朋
* @throws IOException void
* @Date 2015年7月3日
* 更新日志% p2 f, w# [) S, J6 F/ {
* 2015年7月3日 张志朋 首次创建$ v3 H) E- V4 {; S! H9 Q9 `
*, R* K; p) X4 K& ^, ^
*/) ~% Q- M- Y* J$ H: x$ v
public void noAuthorization() throws IOException{
HttpServletRequest request = ServletActionContext.getRequest();
String path = request.getContextPath();
HttpServletResponse response = ServletActionContext.getResponse();0 h- n9 \4 P- n% G8 _7 ~
response.sendRedirect(path+"/pages/noAuthorization.jsp");# v7 O# |# p; a9 B
}+ e: h' w9 b9 r: G
/**- D" C9 P; ~$ x$ k1 y ^
* 获取注解中对方法的权限值 用于Controller层注解 & B" T K! |' @, b; f$ ]
* @Author 张志朋' C3 ^) ?" r. {/ T
* @param joinPoint- G1 M4 T0 O2 h, }2 k; S! ]7 N
* @return2 T; ?7 t. Z; f) T7 g B) G
* @throws Exception int
* @Date 2015年7月3日# d3 v. j9 |6 h# Y- f
* 更新日志) x; M. l9 z( s* I Z; V3 w( b; h
* 2015年7月3日 张志朋 首次创建6 C1 J8 ~7 `; I
*
*/ g* c8 _5 h' f
@SuppressWarnings("rawtypes")
public static int getControllerMethodRole(JoinPoint joinPoint) throws Exception {/ Z5 }$ A' O4 a! c# l
String targetName = joinPoint.getTarget().getClass().getName();
: r. D2 X) ~" t7 j: i% L
String methodName = joinPoint.getSignature().getName();
( ]1 ?! v4 ?% b. s/ W/ o! P
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
9 _- m; s* s6 {9 r+ R O2 [8 Y
Method[] methods =
targetClass.getMethods();
6 w0 q$ D% A4 U+ l
int role = -1;
for (Method method : methods) { " B+ C7 I. \2 m5 i) w R
if (method.getName().equals(methodName)) {
& N) M. w }4 u: j* p v
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
role = method.getAnnotation(Permission. class).id();
break;
}
}
} 7 _* H- x2 b1 H
return role;
}
复制代码
0 D, F; Y& O% c/ v) p
2.action层代码实现:
/**
* 试题审核不通过
* @Author 张志朋 void* u/ t3 p Y/ N8 r7 z: e) P
* @Date 2015年5月4日1 H9 N! ^2 T( ^
* 更新日志
* 2015年5月4日 张志朋 首次创建
*
*// C: H: Y, x( b' J
@Permission(name="审核试题权限(审核不通过)",id=Constants.ROLE_QUES_AUDIT)$ C- I" p0 R) S, I! ]
public void auditQuestions(){. o; ?# b6 Y# E% o; z4 r! x! u
try {
//代码实现3 ^9 a2 U3 R' b
} catch (Exception e) {8 q7 {2 Z! Z/ K# R
e.printStackTrace();
}
}
复制代码
相关文章推荐
- jdkd环境变量
- jdk配置环境变量
- jdk
- java :按钮触发定时器
- java读取文本,插到mysql表中,出现问题。内存溢出。
- springmvc配置相关
- IT十八掌作业_java基础第八天_多线程
- Java垃圾回收机制原理及算法
- 00001笔试题(JAVA)
- FreeMarker与Spring MVC的结合应用
- java并发编程:线程安全管理类--原子操作类--AtomicLongFieldUpdater<T>
- 抛出自定义异常,spring AOP事务不回滚的解决方案
- java并发编程:线程安全管理类--原子操作类--AtomicLongArray
- 如何在spring中读取properties配置文件里面的信息
- Java源码阅读之HashMap
- 第一周JAVA学习笔记(一)
- myeclipse操作相关
- java中的Comparator和Comparable的区别
- JDK的环境变量设置
- java并发编程:线程安全管理类--原子操作类--AtomicIntegerFieldUpdater<T>