package com.ph.sp.integration.advice;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
/**
feign接口mock
*/
@Component
@Aspect
@Order(-1)
@Slf4j
public class FeignMockAspect {@Pointcut("@within(org.springframework.cloud.openfeign.FeignClient)")
public void typeCut() {
}@Around("typeCut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {if (isPrd) { return pjp.proceed(); } Pair<Boolean, String> mockConfig = getMockConfig(pjp); Boolean haveConfig = mockConfig.getKey(); String mockResp = mockConfig.getValue(); if (!haveConfig || mockResp == null) { return pjp.proceed(); } return transMockResp2Obj(pjp, mockResp);
}
private Object transMockResp2Obj(ProceedingJoinPoint pjp, String mockResp) {
Method method = ((MethodSignature) pjp.getSignature()).getMethod(); try { Type returnType = method.getGenericReturnType(); return JsonUtil.json2obj(mockResp, returnType); } catch (Exception e) { log.warn("trans GenericReturnType error~", e); Type returnType = method.getReturnType(); return JsonUtil.json2obj(mockResp, returnType); }
}
private Pair getMockConfig(ProceedingJoinPoint pjp) {
String body = JsonUtil.writeValueToString(pjp.getArgs()); String uri = getUri(pjp); HashOperations<String, String, String> operation = hashTemplate.opsForHash(); Map<String, String> mockConfig = operation.entries("A_MOCK_" + uri); if (CollUtil.isEmpty(mockConfig)) { return new Pair<>(false, null); } return new Pair<>(true, getMockResp(body, mockConfig));
}
private String getMockResp(String body, Map mockConfig) {
Set<Map.Entry<String, String>> entries = mockConfig.entrySet(); for (Map.Entry<String, String> entry : entries) { if (StrUtil.contains(body, entry.getKey())) { log.info("命中入参,返回mock数据 reqPattern:{}", entry.getKey()); return Base64Utils.decode(entry.getValue()); } } log.info("未命中入参,请求真实数据"); return null;
}
private static String getUri(ProceedingJoinPoint pjp) {
Method method = ((MethodSignature) pjp.getSignature()).getMethod(); return Optional.ofNullable(method.getAnnotation(PostMapping.class)).map(PostMapping::value).map(e -> e[0]) .orElseGet(() -> Optional.ofNullable(method.getAnnotation(GetMapping.class)) .map(GetMapping::value).map(e -> e[0]).orElse(""));
}
@Resource
private RedisTemplate> hashTemplate;
}