聚合支付:使用唯一序列号监控http相关请求:用户使用微信APP扫码以及微信回调相关事件跟踪

聚合支付中,当用户使用微信APP扫码时(码为聚合系统生成的聚合码,非微信原生码,最终支付需要使用微信JSAPI支付方式),需要进行重定向到微信侧获取用户支付code,然后通过微信后台http接口使用code换取openId,然后进行支付.由于根据业务需求,需要进行两次重定向(第一次使用支付时使用的支付APPID,第二次使用大的公众号进行重定向),由于担心两次重定向相关流程处理时间较长,所以需要通过唯一请求流水号进行相关请求跟踪:业务具体流程为:

由于需要监控除http请求入口以及出口相关执行时间还需要监控某个service相关方法的执行时间,所以需要使用Spring Web MVC的处理器拦截器,以及aspect AOP切面编程具体了解,请详阅

理器拦截器详解——跟着开涛学SpringMVC

相关url:https://jinnianshilongnian.iteye.com/blog/1670856 

具体代码

public class TimeRecordWebInterceptor extends HandlerInterceptorAdapter {
    private static final Logger logger = LoggerFactory.getLogger(TimeRecordWebInterceptor.class);

    @Resource(name = "sequenceGenerator")
    private SequenceGenerator sequenceGenerator;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        try {
            String sequenceId = StringUtils.isNotBlank(request.getParameter(Constants.SEQUENCEID_KEY)) ? request.getParameter(Constants.SEQUENCEID_KEY) : "seq" + sequenceGenerator.createSequenceForPOS();
            ThreadLocalTimeRecord.setSequenceId(sequenceId);
        } catch (Exception e) {
            logger.error("在controller请求preHandle生成sequenceId时,发生异常,异常信息:", e);
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //防止内存溢出
        ThreadLocalTimeRecord.removeSequenceId();
    }
}

spring-mvc.xml文件中拦截器配置:

<mvc:interceptors>
    <!--扫码支付以及微信等回调生成唯一请求sequenceId,跟踪请求使用-->
    <mvc:interceptor>
        <mvc:mapping path="/s"/>
        <mvc:mapping path="/p"/>
        <mvc:mapping path="/t"/>
        <mvc:mapping path="/*CallBack"/>
        <bean class="com.jd.jr.aggre.front.web.interceptor.TimeRecordWebInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>
/**
 * 〈一句话功能简述〉<br>
 * 〈方法执行时间流水号存储计时器〉
 *
 * @author guojunliang
 * @create 2019/3/25
 * @since 1.0.0
 */
public class ThreadLocalTimeRecord {

    private static final ThreadLocal<String> sequenceIdLocal = new ThreadLocal<String>();

    public static String getSequenceId() {
        return sequenceIdLocal.get();
    }

    public static void setSequenceId(String sequenceId) {
        sequenceIdLocal.set(sequenceId);
    }

    public static void removeSequenceId() {
        sequenceIdLocal.remove();
    }
}

aspectJ相关AOP切面定义:

@Aspect
@Component
public class TimeRecordInterceptor {
    private static final Logger logger = LoggerFactory.getLogger(TimeRecordInterceptor.class);

    @Pointcut("@annotation(com.jd.jr.aggre.front.common.interceptor.TimeRecord)")
    public void aopPoint() {
    }

    @Around("aopPoint()")
    public Object timeAround(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = "";
        long startTime = System.currentTimeMillis();
        try {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            methodName = signature.getDeclaringTypeName() + "." + signature.getName();
            logger.info("##执行{}方法开始,请求标识sequenceId={},执行时间{}", methodName, ThreadLocalTimeRecord.getSequenceId(), DateUtil.date2String(new Date(), DateUtil.PATTERN_STANDARD23W));
        } catch (Exception e) {
            logger.error("统计某方法执行耗时环绕通知方法执行前出错", e);
        }
        try {
            return joinPoint.proceed(joinPoint.getArgs());
        } finally {
            logger.info("##执行{}方法结束,请求标识sequenceId={},执行时间={},耗时{}ms", methodName, ThreadLocalTimeRecord.getSequenceId(), DateUtil.date2String(new Date(), DateUtil.PATTERN_STANDARD23W), System.currentTimeMillis() - startTime);
        }
    }
}
/**
 * 方法执行时长注解定义
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TimeRecord {

}

由于重定向到微信或者支付宝或者京东支付时,拼接回调url编码方式不同,所以不能在springMVC中postHandle中进行modelAndView重定向页面进行拼接参数,需要在service中组装回调url时,进行请求号拼接:

/**
 * 重新拼接回调url,增加请求sequenceId,为记录时长使用
 *
 * @param callBackUrl
 * @return
 */
String addSequenceIdForCallBackUrl(String callBackUrl) {
    if (StringUtils.isNotBlank(callBackUrl) && StringUtils.isNotBlank(ThreadLocalTimeRecord.getSequenceId())) {
        StringBuilder stringBuilder = new StringBuilder(callBackUrl);
        stringBuilder.append("&")
                .append(Constants.SEQUENCEID_KEY)
                .append("=")
                .append(ThreadLocalTimeRecord.getSequenceId());
        return stringBuilder.toString();
    } else {
        return callBackUrl;
    }
}

执行结果:

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值