记得以前看spring in action上面介绍AOP的那章,提到了可以用切面来记录系统的日志,实现日志和业务逻辑之间的解耦。
前些日子公司的系统也有了记录日志的需求,遂写了一个通过注解、AOP来实现记录系统日志的功能,以下是实现代码,分享出来大家一起学习,看看有无改进的地方
AOP配置
<span style="white-space:pre"> </span><bean id="logAspect" class="com.util.LogAspect"/> <aop:config> <aop:aspect ref="logAspect"> <aop:pointcut id="logPointCut" expression="execution(* com.service.*.add*(..))|| execution(* com.service.*.update*(..))"/> <aop:after pointcut-ref="logPointCut" method="doSystemLog"/> </aop:aspect> </aop:config>
日志处理类
/** * 通过Spring AOP来添加系统日志 */ public class LogAspect extends BaseAction{ private static final long serialVersionUID = -5063868902693772455L; private static String splitParaStr = ","; private static String splitNameValueStr = ":"; @Autowired LogServiceImpl logService; @SuppressWarnings( { "rawtypes", "unchecked" } ) public void doSystemLog(JoinPoint point) throws Throwable { Object[] param = point.getArgs(); Class[] parameterTypes = ((MethodSignature)point.getSignature()).getMethod().getParameterTypes(); Method method = null; String methodName = point.getSignature().getName(); if (!("set".startsWith(methodName)&&!"get".startsWith(methodName)&&!"query".startsWith(methodName)&&!"sel".startsWith(methodName))){ //不需要记录日志的方法名 Class targetClass = point.getTarget().getClass(); method = targetClass.getMethod(methodName,parameterTypes); if (method != null) { boolean hasAnnotation = method.isAnnotationPresent(com.util.Log.class); if (hasAnnotation) { //判断是否为log的注解 com.harmony.lottery.util.Log annotation = method.getAnnotation(com.harmony.lottery.util.Log.class); //验证是否登录 ActionContext actionContext = ActionContext.getContext(); if(actionContext == null){ return; } Map session = actionContext.getSession(); SysUser sysUser=(SysUser) session.get("user"); if (sysUser != null) { com.domain.Log logInfo = new com.domain.Log(); logInfo.setAddPerson(sysUser.getUserId()); logInfo.setAddTime(new Date()); logInfo.setRemark(sysUser.getUserId() + getParamsRemark(annotation,param));//获得注解参数值 logService.insert(logInfo); } } } } } /** * 通过java反射来从传入的参数object里取出我们需要记录的id,name等属性, * 此处我取出的是id */ private String getID(Object obj,String param){ if(obj instanceof String){ return obj.toString(); } PropertyDescriptor pd = null; Method method = null; String v = ""; try{ pd = new PropertyDescriptor(param, obj.getClass()); method = pd.getReadMethod(); v = String.valueOf(method.invoke(obj)); }catch (Exception e) { e.printStackTrace(); } return v; } private String getParamsRemark(com.harmony.lottery.util.Log annotation, Object[] param){ String propertys = annotation.propertys(); StringBuffer sb = new StringBuffer(); if(null != propertys&&!"".equals(propertys)){ String[] propertysRemark = annotation.propertys().split(splitParaStr); for (String property : propertysRemark) {//按参数对象属性,取参数值 String name = property.split(splitNameValueStr)[0]; String value = property.split(splitNameValueStr)[1]; sb.append(name + splitNameValueStr + getID(param[0],value) +splitParaStr); } return annotation.operation()+sb.toString().substring(0,sb.length()-1); }else{ String oper = annotation.operation(); List<String> list = PatternUtil.getList("\\{(\\d*)\\}",oper);//按参数位置取参数值 for (int i=0;i<list.size();i++) { String str = list.get(i); Object obj = param[Integer.parseInt(str)]; oper = PatternUtil.replease("\\{"+Integer.parseInt(str)+"\\}", oper, obj.toString()); } return oper; } } }
注解接口的定义
import java.lang.annotation.Documented; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.lang.annotation.*; /** * 类的方法描述注解 * @author LuoYu */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface Log { public String operation() default ""; public String propertys() default ""; }
具体实现类的配置,其中一个为对象属性的配置方式,一种为参数顺序的配置方式,格式可以根据自己的需要更改
@Log(operation="修改参数-->",propertys="参数名称:name,修改后的值为:value") public void update(SysParam record) { sysParamMapper.updateByPrimaryKeySelective(record); }
@Log(operation="为代销商{1}充值{2}元") <span style="white-space:pre"> </span>public void recharge(String userId,String agencyId,BigDecimal money,int type,Date date,String remark)