网站Logo 派大星的石头屋

LswlApi封装restTemplate注解

patrickstar
7
2025-07-09

LswlApi.java

package com.uustop.framework.aspectj.lang.annotation;

import org.springframework.http.HttpMethod;

import java.lang.annotation.*;

/**
 * 自定义出入参记录注解
 *
 * @author uustop
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LswlApi {
    /**
     * 描述信息
     */
    public String description() default "";

    /**
     * 自定义请求路径(覆盖默认方法名路径)
     */
    String customPath() default "";

    /**
     * HTTP请求方法(默认为POST)
     */
    HttpMethod method() default HttpMethod.POST;
}

LswlApiInvokerAspect.java

package com.uustop.framework.aspectj;

import cn.hutool.core.lang.TypeReference;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.uustop.framework.aspectj.lang.annotation.ApiClass;
import com.uustop.framework.aspectj.lang.annotation.LswlApi;
import com.uustop.framework.web.domain.RespEntity;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;

@Aspect
@Component
public class LswlApiInvokerAspect {

    // 使用注入的RestTemplate(确保在配置中配置)
    private final RestTemplate restTemplate;

    private static final ObjectMapper mapper = new ObjectMapper();

    // 基础URL从配置读取(示例值)
    private final String baseUrl;

    public LswlApiInvokerAspect(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
        this.baseUrl = "http://127.0.0.1:6087/business/api"; // 实际应从@Value注入
    }

    /**
     * 核心拦截逻辑
     */
    @Around("@annotation(com.uustop.framework.aspectj.lang.annotation.LswlApi)")
    public Object remoteMethodInvocation(ProceedingJoinPoint pjp) {
        // 1. 获取方法元数据
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        LswlApi apiAnnotation = method.getAnnotation(LswlApi.class);

        // 2. 获取目标类信息(关键修改点)
        Class<?> targetClass = getTargetClass(pjp);

        // 3. 获取类上的注解
        ApiClass apiClassAnnotation = targetClass.getAnnotation(ApiClass.class);

        // 2. 构建目标URL
        String url = buildTargetUrl(method.getName(), apiAnnotation.customPath(), apiClassAnnotation);

        // 3. 准备请求实体
        HttpEntity<Object> requestEntity = prepareRequestEntity(pjp.getArgs());

        // 4. 获取返回类型信息
//        Class<?> returnType = signature.getReturnType();
        Type genericReturnType = method.getGenericReturnType();

        // 5. 执行远程调用并转换类型
        return executeRemoteCall(url, apiAnnotation.method(), requestEntity, genericReturnType);
    }

    /**
     * 获取目标类(处理代理类情况)
     */
    private Class<?> getTargetClass(ProceedingJoinPoint pjp) {
        Object target = pjp.getTarget();

        // 处理Spring代理类(CGLIB)
        if (target.getClass().getName().contains("$$")) {
            return target.getClass().getSuperclass();
        }

        // 处理JDK动态代理
        if (Proxy.isProxyClass(target.getClass())) {
            // 获取代理实现的接口
            Class<?>[] interfaces = target.getClass().getInterfaces();
            if (interfaces.length > 0) {
                return interfaces[0]; // 返回第一个接口
            }
        }

        // 普通类
        return target.getClass();
    }


    /**
     * 构建目标URL
     */
    private String buildTargetUrl(String methodName, String customPath, ApiClass apiClassAnnotation) {
        StringBuilder urlBuilder = new StringBuilder(baseUrl);
        // 添加类注解路径(如果存在)
        if (apiClassAnnotation != null && !apiClassAnnotation.path().isEmpty()) {
            String classPath = apiClassAnnotation.path();
            if (!classPath.startsWith("/")) {
                urlBuilder.append('/');
            }
            urlBuilder.append(classPath);
        }
        if (!customPath.isEmpty()) {
            urlBuilder.append(customPath.startsWith("/") ? customPath : "/" + customPath);
        } else {
            urlBuilder.append("/").append(methodName);
        }
        return urlBuilder.toString();
    }

    /**
     * 准备请求实体
     */
    private HttpEntity<Object> prepareRequestEntity(Object[] args) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        // 智能选择请求体:
        // - 无参数: null
        // - 单参数: 直接作为body
        // - 多参数: 封装为数组
        Object requestBody = null;
        if (args.length == 1) {
            requestBody = args[0];
        } else if (args.length > 1) {
            requestBody = args;
        }

        return new HttpEntity<>(requestBody, headers);
    }
    /**
     * 准备请求实体
     */
//    private HttpEntity<Object> prepareRequestEntity(Method method, Object[] args) {
//        HttpHeaders headers = new HttpHeaders();
//        headers.setContentType(MediaType.APPLICATION_JSON);
//
//        // 获取方法的参数名
//        java.lang.reflect.Parameter[] parameters = method.getParameters();
//
//        // 创建一个Map来存储参数名和值
//        Map<String, Object> requestBodyMap = new HashMap<>();
//        for (int i = 0; i < parameters.length; i++) {
//            requestBodyMap.put(parameters[i].getName(), args[i]);
//        }
//
//        // 智能选择请求体:
//        // - 无参数: null
//        // - 单参数: 直接作为body
//        // - 多参数: 封装为数组
//        Object requestBody = null;
//        try {
//            // 使用ObjectMapper将Map转换为JSON字符串
//            ObjectMapper objectMapper = new ObjectMapper();
//            requestBody = objectMapper.writeValueAsString(requestBodyMap);
//        } catch (Exception e) {
//            // 处理JSON转换异常
//            throw new RuntimeException("Failed to convert request body to JSON", e);
//        }
//
//        return new HttpEntity<>(requestBody, headers);
//    }


    /**
     * 执行远程调用并处理响应
     */
    private <T> T executeRemoteCall(String url, HttpMethod httpMethod,
                                    HttpEntity<?> requestEntity,
                                    Type genericType) {

        // 处理泛型类型(如List<User>)
        ResponseEntity<String> response = restTemplate.exchange(url, httpMethod, requestEntity, String.class);
        try {
            return handleResponse(response, genericType);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 将JSON字符串转换为RespEntity<T>类型,支持嵌套泛型
     */
    public static <T> Object convertJsonToRespEntity(String json, Type genericReturnType) throws Exception {

        // 构建包含完整泛型信息的JavaType
        JavaType javaType = buildRespEntityType(genericReturnType);

        // 执行转换
        return mapper.readValue(json, javaType);
    }

    public static Object deserializeFromType(String jsonString, Type genericReturnType) throws IOException {
        // 1. 创建 ObjectMapper 实例
        ObjectMapper objectMapper = new ObjectMapper();

        // 2. 将 Type 转换为 JavaType
        JavaType javaType = objectMapper.getTypeFactory().constructType(genericReturnType);

        // 3. 反序列化 JSON 字符串
        return objectMapper.readValue(jsonString, javaType);
    }


    public static Object parseJsonToType(String jsonString, Type targetType) {
        // 1. 创建自定义JSON配置(解决日期格式问题)
        JSONConfig config = JSONConfig.create()
                // 设置日期格式为 "yyyy-MM-dd HH:mm:ss"
                .setDateFormat("yyyy-MM-dd HH:mm:ss")
                // 自动忽略不存在的字段
                .setIgnoreCase(true);

        // 2. 使用 Hutool 的强大解析能力
        JSON json = JSONUtil.parse(jsonString, config); // 关键:直接解析为通用JSON类型

        // 3. 转换为目标类型(通过动态TypeReference)
        return json.toBean(new TypeReference<Object>() {
            @Override
            public Type getType() {
                return targetType; // 使用反射获取的泛型类型
            }
        });
    }

    /**
     * 处理HTTP响应
     */
    private <T> T handleResponse(ResponseEntity<String> response, Type genericType) throws Exception {
        if (response.getStatusCode().is2xxSuccessful()) {
            return (T) parseJsonToType(response.getBody(), genericType);
        }

        // 自定义异常处理(根据实际需求扩展)
        throw new RemoteApiException(
                "Remote API call failed: " + response.getStatusCode() +
                        " - " + response.getBody()
        );
    }

    /**
     * 构建RespEntity<T>的JavaType,处理嵌套泛型
     */
    private static JavaType buildRespEntityType(Type genericType) {
        if (!(genericType instanceof ParameterizedType)) {
            // 非泛型类型,使用原始类型
            return mapper.getTypeFactory().constructType(RespEntity.class);
        }

        ParameterizedType paramType = (ParameterizedType) genericType;
        Type[] typeArgs = paramType.getActualTypeArguments();

        if (typeArgs.length == 0) {
            // 无泛型参数,使用原始类型
            return mapper.getTypeFactory().constructType(RespEntity.class);
        }

        // 处理泛型参数(例如List<Project>)
        JavaType genericTypeArg = mapper.getTypeFactory().constructType(typeArgs[0]);

        // 构建RespEntity<T>类型
        return mapper.getTypeFactory().constructParametricType(
                RespEntity.class,
                genericTypeArg
        );
    }

    /**
     * 自定义异常类
     */
    public static class RemoteApiException extends RuntimeException {
        public RemoteApiException(String message) {
            super(message);
        }
    }
}