Java Aop 环绕通知 监控 controller 层

我们项目中一般需要去监控 controller 层, 校验参数、加密、日志打印等等。

一、首先是写个切面,定位所有controller 层的方法

@Aspect
@Component
@Slf4j
public class MutmsAspect {

	@Value("${spring.application.name}")
	private String  appName;

    @Autowired
    private ExeService exeService;

	@Around("execution(public * com.ceair.mutms..controller.*.*(..))")
	public Object exeMethod(ProceedingJoinPoint joinPoint)throws Throwable{

二、校验参数

// 版本验证,低版本报错
MutmsVersion.update(methodName,req);
// token 验证
MutmsToken.verify(appName, permittedServer, joinPoint,req);
// session校验
MutmsSession.verify(appName,permittedServer, joinPoint);

三、打印入参,执行方法,拿到反参

// 因为阿里云日志只支持xxxx* 这种方式模糊查找不支持*xxxx这种方式所以给关键日志加一个前缀
log.info("{}{}方法:{},入参: {}", AliyunLogConsts.MUTMS_REQ_PREFIX, methodName, joinPoint.getSignature().getName(), JsonUtil.toString(req,""));
res=joinPoint.proceed(joinPoint.getArgs());

四、打印反参,方法执行时间,保存访问记录等

// 因为阿里云日志只支持xxxx* 这种方式模糊查找不支持*xxxx这种方式所以给关键日志加一个前缀
log.info("{}{}返回: {}", AliyunLogConsts.MUTMS_RES_PREFIX, methodName, JsonUtil.toString(res,""));
log.info("方法: {}, 接口耗时:{}毫秒", methodName, (System.currentTimeMillis()-starttime));
// 异步保存接口访问记录
MUTMSAccessLogQueueHelper.execute(() -> {
MUTMSAccessLog accessLog = new MUTMSAccessLog();
accessLog.setPassportId(passportId);
accessLog.setTransactionId(transactionId);  // 明文transactionId
accessLog.setSessionId(sessionId);
accessLog.setOs(req.getOs());
accessLog.setLocalIp(IpHelper.getLocalIp());
accessLog.setClientRealIp(clentRealIp);
accessLog.setLanguage(req.getLanguage());
accessLog.setRegion(req.getRegion());
accessLog.setAppVersion(req.getAppVersion());
accessLog.setChannelNo(req.getChannelNo());
accessLog.setSecondChannelNo(req.getSecondChannelNo());
accessLog.setThirdChannelNo(req.getThirdChannelNo());
accessLog.setSalesChannel(salesChannel);

 完整代码

package com.ceair.mutms.common.aop;

import com.ceair.mutms.common.aliyunlog.AliyunLogConsts;
import com.ceair.mutms.common.aliyunlog.MUTMSAccessLogItemKeyConsts;
import com.ceair.mutms.common.base.BaseReq;
import com.ceair.mutms.common.base.CommonRes;
import com.ceair.mutms.common.entity.MUTMSAccessLog;
import com.ceair.mutms.common.exception.*;
import com.ceair.mutms.common.filter.ContextUtil;
import com.ceair.mutms.common.aliyunlog.AliyunLogHelper;
import com.ceair.mutms.common.aliyunlog.AliyunLogItemKeyConsts;
import com.ceair.mutms.common.log.MDCBean;
import com.ceair.mutms.common.log.MDCHelper;
import com.ceair.mutms.common.sec.aes.BangBang;
import com.ceair.mutms.common.service.ExeService;
import com.ceair.mutms.common.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;

import java.util.Map;
/**
 * 接口控制
 * @author DELL
 *
 */
@Order(-1)
@Aspect
@Component
@Slf4j
public class MutmsAspect {
	@Value("${spring.application.name}")
	private String  appName;

    @Autowired
    private ExeService exeService;


	@Around("execution(public * com.ceair.mutms..controller.*.*(..))")
	public Object exeMethod(ProceedingJoinPoint joinPoint)throws Throwable{
		long starttime = System.currentTimeMillis();

		String permittedServer=CacheUtil.getOtherCode(CacheKey.PERMITTED_SERVER);
		BaseReq req=getParam(joinPoint.getArgs());

		// 加密 token
		String tokenRsa = req.getCeairToken();
		Long passportId = req.getPassportId();
		String clentRealIp = ContextUtil.getContext().getString(CacheKey.CLIENT_REAL_IP_KEY);
		String sessionId = ContextUtil.getContext().getString(CacheKey.SESSION_ID_KEY);
		String salesChannel = SalesChannelHelper.salesChannel(req.getLanguage(), req.getRegion());
		//当前请求所执行的controller类的方法
		final String methodName=joinPoint.getSignature().getName();
		String className = joinPoint.getSignature().getDeclaringTypeName();
		final String interfaceKey = className + "." + methodName;

        Object res=null;

        final String transactionId = Assert.isNotEmpty(req.getTransactionId()) ? req.getTransactionId() : BaseReq.generateTransactionId(passportId);

        MDCBean bean = new MDCBean();

        bean.setTransactionId(transactionId);
        bean.setPassportId(Assert.nullToEmpty(passportId));
        bean.setSessionId(sessionId);

        AliyunLogHelper.addItemIfAbsent(req.getAliyunLogItems(), AliyunLogItemKeyConsts.TRANSACTION_ID, transactionId);
        AliyunLogHelper.addItemIfAbsent(req.getAliyunLogItems(), AliyunLogItemKeyConsts.SESSION_ID, sessionId);
        AliyunLogHelper.addItemIfAbsent(req.getAliyunLogItems(), AliyunLogItemKeyConsts.PASSPORT_ID, passportId);
        AliyunLogHelper.addItemIfAbsent(req.getAliyunLogItems(), AliyunLogItemKeyConsts.INTERFACE_NAME, interfaceKey);
        AliyunLogHelper.addLogTime(req.getAliyunLogItems());

		try {
            MDCHelper.insertIntoMDC(bean);

			// 当前请求所使用的语言类型
			ContextUtil.getContext().put(CacheKey.LANGUAGE_CACHE_KEY, Assert.isEmpty(req.getLanguage())?"zh":req.getLanguage());
			// 版本验证,低版本报错
			MutmsVersion.update(methodName,req);
			// token 验证
			MutmsToken.verify(appName, permittedServer, joinPoint,req);

			req.setSalesChannel(salesChannel);
			// 当前线程执行子任务的唯一标识
//			ContextUtil.getContext().put("logbean.uuid", UUID.randomUUID().toString());
			// 地区
			ContextUtil.getContext().put(CacheKey.REGION_CACHE_KEY, Assert.isEmpty(req.getRegion())?"CN":req.getRegion());
			// 渠道
			ContextUtil.getContext().put(CacheKey.SALES_CHANNEL_CACHE_KEY, salesChannel);
			//系统支持的支付方式
			if(req.getSupportPay()!=null && req.getSupportPay()) {
				ContextUtil.getContext().put(CacheKey.OS_PAY_METHOD_CACHE_KEY, req.getOsPayMethod());
			}
			// 每次请求唯一ID,明文tansactionId
			ContextUtil.getContext().put(CacheKey.TRANSACTION_ID_CACHE_KEY, transactionId);
			// 当前请求的用户ID
			ContextUtil.getContext().put(CacheKey.PASSPORTID_CACHE_KEY, passportId);
			// 当前请求的客户端平台系统:AD|iOS
			ContextUtil.getContext().put(CacheKey.APP_OS_CACHE_KEY, req.getOs());
			// 当前请求的客户端版本号
			ContextUtil.getContext().put(CacheKey.APP_VERSION_CACHE_KEY, req.getAppVersion());
			// 当前请求的设备ID
			ContextUtil.getContext().put(CacheKey.IEMI_CACHE_KEY,req.getImei());
			//阿里token
			ContextUtil.getContext().put(CacheKey.APDIDTOKEN_CACHE_KEY,req.getApdidToken());

			// session校验
			MutmsSession.verify(appName,permittedServer, joinPoint);

			String codeEnity=null;

			if(permittedServer==null||!permittedServer.contains(appName)) {
				//接口调用开关
				codeEnity=CacheUtil.getMethod(methodName);
			}
			//*表示关闭当前所有接口
			if(codeEnity !=null || (codeEnity=CacheUtil.getMethod("*"))!=null) {
				log.info("方法:{},被禁用:{}", joinPoint.getSignature().getName(), codeEnity);
				res = new CommonRes<Object>(CommonRes.FAIL,CacheUtil.getI18nVal(codeEnity, codeEnity));
			}else {
			    // 因为阿里云日志只支持xxxx* 这种方式模糊查找不支持*xxxx这种方式所以给关键日志加一个前缀
				log.info("{}{}方法:{},入参: {}", AliyunLogConsts.MUTMS_REQ_PREFIX, methodName, joinPoint.getSignature().getName(), JsonUtil.toString(req,""));
				res=joinPoint.proceed(joinPoint.getArgs());

			}

		}catch (MUTMSFirstExceptionWithData tx){
            res= ExceptionHandler.doException(tx);
        }catch (MUTMSFirstException tx){
			res= ExceptionHandler.doException(tx);
		}catch (MUTMSRuntimeException tx){
			res= ExceptionHandler.doException(tx);
		}catch(MUTMSSecondExceptionWithData e){
            res= ExceptionHandler.doException(e);
        }catch(MUTMSSecondException e){
			res= ExceptionHandler.doException(e);
		}catch(MUTMSThirdException e){
			res= ExceptionHandler.doException(e);
		}catch(MUTMSFourthException e){
            res= ExceptionHandler.doException(e);
        }catch(Exception e) {
		    if(e instanceof NullPointerException)
            {
                log.info("接口调用出现异常, ex: {}:", Assert.callStackOneLine(e));
            }

			res= ExceptionHandler.doException(e);
			log.error("接口调用出现异常:", e);
		}finally {
			// 把请求参数存入redis缓存
			exeService.exec(()-> {
				try {
					MutmsToken.setToken(tokenRsa,req);
				} catch (Exception e) {
					log.error("异步记录ceair token 出现异常:", e);
				}
			});

			final String resultCode;
			final String resultMsg;
			if(res instanceof CommonRes){
				((CommonRes<?>) res).setTransactionId(transactionId);
				resultCode = ((CommonRes<?>) res).getResultCode();
				resultMsg = ((CommonRes<?>) res).getResultMsg();
				// 构建统一弹框
                DialogHelper.buildDialog((CommonRes<?>)res, interfaceKey, req.getDialogParams());

			}else {
				resultCode = "";
				resultMsg = "";
			}

//			log.info("isNeedToAliyunLog: {}, interfaceKey: {}", AliyunLogHelper.isNeedToAliyunLog(interfaceKey), interfaceKey);
			if(AliyunLogHelper.isNeedToAliyunLog(interfaceKey))
            {
                AliyunLogHelper.addTopic(req.getAliyunLogItems(), interfaceKey);

                AliyunLogHelper.execute(() -> {
                    AliyunLogHelper.putLogs(req.getAliyunLogItems());
                });
            }

            Long costTimeMillisecond = System.currentTimeMillis() - starttime;
			// 异步保存接口访问记录
			MUTMSAccessLogQueueHelper.execute(() -> {
				MUTMSAccessLog accessLog = new MUTMSAccessLog();
				accessLog.setPassportId(passportId);
				accessLog.setTransactionId(transactionId);  // 明文transactionId
				accessLog.setSessionId(sessionId);
				accessLog.setOs(req.getOs());
				accessLog.setLocalIp(IpHelper.getLocalIp());
				accessLog.setClientRealIp(clentRealIp);
				accessLog.setLanguage(req.getLanguage());
				accessLog.setRegion(req.getRegion());
				accessLog.setAppVersion(req.getAppVersion());
				accessLog.setChannelNo(req.getChannelNo());
				accessLog.setSecondChannelNo(req.getSecondChannelNo());
				accessLog.setThirdChannelNo(req.getThirdChannelNo());
				accessLog.setSalesChannel(salesChannel);
				accessLog.setCrtDt(TimeUtils.nowLong());
				accessLog.setClassName(className);
				accessLog.setMethodName(methodName);
				accessLog.setImei(req.getImei());
				accessLog.setResultCode(resultCode);
				accessLog.setResultMsg(resultMsg);
                accessLog.setRegistrationID(req.getRegistrationID());
				accessLog.setCostTimeMillisecond(costTimeMillisecond);

                Map<String, String> accessLogItemsMap =  MUTMSAccessLogItemKeyConsts.buildAliyunLogItems(accessLog, req.getAliyunLogItems(), req.getAliyunLogItemsExt());

                AliyunLogHelper.putAccessLogs(accessLogItemsMap);

//                MongoTemplate mongoTemplate = AppContext.getBean(MongoTemplate.class);
//				mongoTemplate.insert(accessLog);
			});

			//非生产环境打印接口返回值
			if(CacheUtil.PRINT_RES) {
			    // 因为阿里云日志只支持xxxx* 这种方式模糊查找不支持*xxxx这种方式所以给关键日志加一个前缀
				log.info("{}{}返回: {}", AliyunLogConsts.MUTMS_RES_PREFIX, methodName, JsonUtil.toString(res,""));
			}
 
            log.info("方法: {}, 接口耗时:{}毫秒", methodName, (System.currentTimeMillis()-starttime));
		}
		return res;
	}


	private BaseReq getParam(Object args[]) {

	    String appVersion = null;
	    Long passportId = null;
		// 转BaseReq 对象并返回
	    if(args !=null) {
			for (Object object : args) {
				if(object instanceof BaseReq) {
					return (BaseReq)object;
				// 参数写在 form-data中处理
				}else if(object instanceof StandardMultipartHttpServletRequest){
                    try {
                        String pid = ((StandardMultipartHttpServletRequest) object).getParameter("passportId");
                        passportId = Assert.isEmpty(pid)?null:Long.valueOf(pid);
                        appVersion = ((StandardMultipartHttpServletRequest) object).getParameter("appVersion");
                    }catch (Exception e){
                        Assert.callStack(e);
                    }
                }
			}
		}


		BaseReq req =new BaseReq();
		req.setLanguage("zh");
		req.setRegion("CN");
        req.setAppVersion(appVersion);
        req.setPassportId(passportId);
		return req;
	}

}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值