用自定义注解和aop实现操作日志

昨天和同事一起看怎么用自定义注解和aop实现操作日志,现在来记录一下。

大致的思路是在修改删除新增的方法前面加上自定义注解,然后定义一个切面,在切面的环绕通知中处理注解和请求带过来的参数。PS:JSONObject真好用,因为现在的查询后的数据都是用JSONObject来接收的,所以对比修改前后的变化连反射都不用。

首先是自定义注解:

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)   //表示注解用在方法上

public @interface OperateLogAnnotation {

String page() default "";

String opration_table() default "";

String key() default "";  //id名称

}

使用自定义注解:

注意:因为实现了接口,所以使用的是jdk动态代理,代理那些接口中有的方法,@自定义注解只能加在接口对应的方法上


@OperateLogAnnotation(page="系统管理——数据字典",opration_table="patee_dictionary",key="id_patee_dictionary")

public BaseResult editDict(JSONObject req) {

// TODO Auto-generated method stub

log.info("editDict in, req:{}", JSONObject.toJSON(req));

String uuid = req.getString("uuid");

String oper = req.getString("oper");

BaseResult result = null;

if ("edit".equals(oper)) {

result = updateDictById(req);

log.info("updateDictById out result:{}", result);

return result;

} else if ("del".equals(oper)) {

result = deleteDictById(req);

log.info("deleteDictById out result:{}", result);

return result;

} else if ("add".equals(oper)) {

result = addDict(req);

log.info("addDict out result:{}", result);

return result;

}

return BaseResult.returnSuccessMessage("所传编辑类型有误!", uuid);


}

PS:之前一致纠结的问题是怎么让注解知道是修改删除还是新增,即使这个注解是用在方法上的,但当真的用在updateDictById/addDict/deleteDictById上时,aop并不会进去,自定义注解也不支持占位符(mark一下占位符的使用:MessageFormat.format(),莫大神推荐的),还好req里面有oper(edit/add/del),可以在切面里面拿到req的具体值。

看到莫大神写的一段代码,注解里面是可以有占位符的,但是这里好像也不太适用

@RequestMapping(value = "dataGridEdit/{service}/{method}", method = RequestMethod.POST)

@ResponseBody

public BaseResult dataGridEdit(@PathVariable("service") String service,@PathVariable("method") String method,HttpServletRequest request){

UUID uuid = UUID.randomUUID();

JSONObject req = getParameterJson(request);

req.put("uuid", uuid.toString());

log.info("dataGridEdit in req : {},url is {}", req,request.getRequestURI());

return callService(req, "app/public/"+service+"/"+method);


}

定义切面:


@Aspect

@Component

public class OperateLogAspect {



private static final Logger logger = LoggerFactory.getLogger(OperateLogAspect.class);

@Autowired

TableChangeRecoderDao tableChangeRecoderDAO;



/**

* Controller层切点 注解拦截

*/

@Pointcut("@annotation(com.paic.patee.core.app.aop.OperateLogAnnotation)")

public void controllerAspect() {

}



// 配置controller环绕通知,使用在方法aspect()上注册的切入点

@Around(value = "controllerAspect()&&@annotation(operate)")

public Object around(ProceedingJoinPoint pjp, OperateLogAnnotation operate) throws Throwable {

logger.info("OperateLogAspect around in");

JSONObject req = null;

Object[] args = pjp.getArgs();

if (args.length > 0 && args[0] instanceof JSONObject) {

req = (JSONObject) args[0];

}

JSONObject oldObject = new JSONObject();

if (null == req || req.isEmpty()) {

return pjp.proceed();

}

String oper = req.getString("oper");

if("edit".equals(oper)||"del".equals(oper)) {

oldObject = searchOldObject(operate.opration_table(),operate.key(),req.get(operate.key()));

}

BaseResult result = (BaseResult) pjp.proceed();

String errorCode = result.getErrorCode();

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())

.getRequest();

String userName=request.getHeader("userName");

if ("0".equals(errorCode)) {

JSONObject json = new JSONObject();

json.put("um_id", userName);

String page = operate.page();

json.put("page", page);

if("edit".equals(oper)) {

String opration_description = compareTwoObject(req,oldObject);

json.put("opration_description", "修改了id为:"+req.get(operate.key())+opration_description);

}else if("del".equals(oper)) {

json.put("opration_description", "删除!删除掉的数据为:"+oldObject);

}else if("add".equals(oper)) {

json.put("opration_description", "新增!新增的数据为:"+req);

}

json.put("opration_table", operate.opration_table());

json.put("change_id", UUID.randomUUID().toString());

json.put("operation_time",new Date());

tableChangeRecoderDAO.insertOneRecord(json);

}

return result;

}

public JSONObject searchOldObject(String tableName,String key,Object id){

JSONObject req = new JSONObject();

req.put("table_name", tableName);

req.put("key", key);

req.put("id", "'"+id+"'");

return tableChangeRecoderDAO.queryObj(req);

}



public static String compareTwoObject(JSONObject req, JSONObject oldObject) {

StringBuffer sb  = new StringBuffer();

sb.append("修改的数据为:{");

JSONObject newObject = req;



for(String str:newObject.keySet()){

for(String str1:oldObject.keySet()){

if((!"update_time".equals(str))&&str.equals(str1)&&(!newObject.get(str).equals(oldObject.get(str1)))) {

sb.append(str1).append(":").append(oldObject.get(str1));

sb.append(" 改为 ").append(newObject.get(str)).append(";");

}

}

}

sb.deleteCharAt(sb.length()-1);

sb.append("}");



return sb.toString();

}

}

AOP的基本概念:

Aspect(切面):通常是一个类,里面可以定义切入点和通知;

JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用。被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器;

Advice(通知):AOP在特定的切入点上执行的增强处理,有before(前置),after(后置),afterReturning(最终),afterThrowing(异常),around(环绕);

Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容