001package top.cenze.utils.aspect;
002
003import cn.hutool.core.collection.CollectionUtil;
004import cn.hutool.core.util.ArrayUtil;
005import cn.hutool.core.util.ObjectUtil;
006import cn.hutool.core.util.StrUtil;
007import com.alibaba.fastjson.JSON;
008import com.alibaba.fastjson.JSONObject;
009import lombok.SneakyThrows;
010import lombok.extern.slf4j.Slf4j;
011import org.aspectj.lang.JoinPoint;
012import org.aspectj.lang.reflect.CodeSignature;
013import org.aspectj.lang.reflect.MethodSignature;
014import org.omg.CORBA.UNKNOWN;
015import org.springframework.core.annotation.AnnotationFilter;
016
017import javax.servlet.http.HttpServletRequest;
018import javax.servlet.http.HttpServletResponse;
019import java.lang.reflect.Field;
020import java.lang.reflect.Method;
021import java.net.InetAddress;
022import java.net.UnknownHostException;
023import java.util.HashMap;
024import java.util.Map;
025
026/**
027 * AOP工具
028 */
029@Slf4j
030public class AspectUtil {
031    // 多次反向代理后会有多个ip值 的分割符
032    private final static String IP_UTILS_FLAG = ",";
033    // 未知IP
034    private final static String UNKNOWN = "unknown";
035    // 本地 IP
036    private final static String LOCALHOST_IP = "0:0:0:0:0:0:0:1";
037    private final static String LOCALHOST_IP1 = "127.0.0.1";
038
039
040    /**
041     * 获取所有请求参数
042     * 支持基础类型与对象及自定义对象混合情况,如果是对象或自定义对象,提取其成员变量
043     * @param point
044     * @return
045     */
046    public static Map<String, Object> getRequestAllParams(JoinPoint point) {
047        Map<String, Object> params = getRequestParams(point);
048        log.info("getRequestAllParams params: {}", JSON.toJSONString(params));
049
050        Map<String, Object> allParams = new HashMap<>();
051        if (CollectionUtil.isNotEmpty(allParams)) {
052            for (Map.Entry<String, Object> entry : allParams.entrySet()) {
053                String name = entry.getKey();
054                log.info("getRequestAllParams name: {}", name);
055                Object obj = entry.getValue();
056                log.info("getRequestAllParams obj: {}", JSON.toJSONString(obj));
057                // java基础类型
058                if (isJavaLang(obj)) {
059                    params.put(name, obj);
060                }
061                // 对象或自定义对象
062                else {
063                    Map<String, Object> paramsByObj = getParamsByObj(obj);
064                    log.info("getRequestAllParams paramsByObj: {}", JSON.toJSONString(paramsByObj));
065                    if (CollectionUtil.isNotEmpty(paramsByObj)) {
066                        allParams.putAll(paramsByObj);
067                    }
068                }
069            }
070        }
071
072        return allParams;
073    }
074
075    /**
076     * 获取所有请求参数
077     * 支持基础类型与对象及自定义对象混合情况,不提取对象或自定义对象内的成员变量
078     * @param point
079     * @return
080     */
081    public static Map<String, Object> getRequestParams(JoinPoint point) {
082        Map<String, Object> params = new HashMap<>();
083
084        MethodSignature signature = (MethodSignature) point.getSignature();
085        log.info("getRequestParams signature: {}", JSON.toJSONString(signature));
086//        Method method = signature.getMethod();
087
088        // 请求的方法所有参数值
089        Object[] args = point.getArgs();
090        log.info("getRequestParams args: {}", JSON.toJSONString(args));
091        // 请求的方法所有参数名称
092        String[] paramNames = ((CodeSignature)signature).getParameterNames();
093        // 请求的方法参数名称
094//        LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
095//        String[] paramNames = u.getParameterNames(method);
096        log.info("getRequestParams paramNames: {}", JSON.toJSONString(paramNames));
097
098        if (ObjectUtil.isNotEmpty(args) && ObjectUtil.isNotEmpty(paramNames)) {
099            for (int i = 0; i < args.length; i++) {
100                Object obj = args[i];
101                // 请求参数
102                if (obj instanceof HttpServletRequest) {
103                    String name = paramNames[i];
104                    params.put(name, obj);
105                }
106            }
107        }
108
109        return params;
110    }
111
112    public static Object getParamByName(JoinPoint point, String name) {
113        MethodSignature signature = (MethodSignature) point.getSignature();
114        log.info("getParamByName signature: {}", JSON.toJSONString(signature));
115
116        // 请求的方法所有参数值
117        Object[] args = point.getArgs();
118        log.info("getParamByName args: {}", JSON.toJSONString(args));
119        if (ObjectUtil.isNotEmpty(args)) {
120            for (Object obj : args) {
121                JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(obj));
122                log.info("getParamByName jsonObject: {}", JSON.toJSONString(jsonObject));
123                if (jsonObject.containsKey(name)) {
124                    return jsonObject.get(name);
125                }
126            }
127        }
128
129        return null;
130    }
131
132    /**
133     * 获取所有响应参数
134     * 支持基础类型与对象及自定义对象混合情况,如果是对象或自定义对象,提取其成员变量
135     * @param point
136     * @return
137     */
138    public static Map<String, Object> getResponseAllParams(JoinPoint point) {
139        Map<String, Object> params = getResponseParams(point);
140
141        Map<String, Object> allParams = new HashMap<>();
142        if (CollectionUtil.isNotEmpty(allParams)) {
143            for (Map.Entry<String, Object> entry : allParams.entrySet()) {
144                String name = entry.getKey();
145                Object obj = entry.getValue();
146                // java基础类型
147                if (isJavaLang(obj)) {
148                    params.put(name, obj);
149                }
150                // 对象或自定义对象
151                else {
152                    Map<String, Object> paramsByObj = getParamsByObj(obj);
153                    if (CollectionUtil.isNotEmpty(paramsByObj)) {
154                        allParams.putAll(paramsByObj);
155                    }
156                }
157            }
158        }
159
160        return allParams;
161    }
162
163    /**
164     * 获取所有响应参数
165     * 支持基础类型与对象及自定义对象混合情况,不提取对象或自定义对象内的成员变量
166     * @param point
167     * @return
168     */
169    public static Map<String, Object> getResponseParams(JoinPoint point) {
170        Map<String, Object> params = new HashMap<>();
171
172        MethodSignature signature = (MethodSignature) point.getSignature();
173
174        // 请求的方法所有参数值
175        Object[] args = point.getArgs();
176        // 请求的方法所有参数名称
177        String[] paramNames = ((CodeSignature)signature).getParameterNames();
178
179        if (ObjectUtil.isNotEmpty(args) && ObjectUtil.isNotEmpty(paramNames)) {
180            for (int i = 0; i < args.length; i++) {
181                Object obj = args[i];
182                // 请求参数
183                if (obj instanceof HttpServletResponse) {
184                    String name = paramNames[i];
185                    params.put(name, obj);
186                }
187            }
188        }
189
190        return params;
191    }
192
193    /**
194     * 获取对象内成员变量Map
195     * @param obj
196     * @return
197     */
198    public static Map<String, Object> getParamsByObj(Object obj) {
199        Map<String, Object> params = new HashMap<>();
200
201        Field[] fields = obj.getClass().getDeclaredFields();
202        if (ObjectUtil.isNotEmpty(fields)) {
203            for (Field field : fields) {
204                field.setAccessible(true);
205                String key = field.getName();
206                try {
207                    Object val = field.get(obj);
208
209                    if (ObjectUtil.isNotEmpty(val)) {
210                        params.put(key, val);
211                    }
212                } catch (IllegalAccessException e) {
213                    e.printStackTrace();
214                }
215            }
216        }
217
218        return params;
219    }
220
221    @SneakyThrows
222    public static void setParamByName(JoinPoint point, String name, Object val) {
223        MethodSignature methodSignature = (MethodSignature) point.getSignature();
224        final String[] names = methodSignature.getParameterNames(); // 获取参数的名字
225        log.info("setParamByName names: {}", JSON.toJSONString(names));
226        final Object[] args = point.getArgs(); // 获取参数的值
227        log.info("setParamByName args: {}", JSON.toJSONString(args));
228
229        if (ObjectUtil.isNull(names) || ObjectUtil.isNull(args) ||
230                0 == names.length || 0 == args.length) {
231            return;
232        }
233
234        // 直接查看参数名匹配(参数为基础类型,直接设置值)
235        int idx = ArrayUtil.indexOfIgnoreCase(names, name);
236        log.info("setParamByName idx: {}", idx);
237        if (idx >= 0) {
238            // 如果是基础类型,直接设置值
239            if (isJavaLang(args[idx])) {
240                args[idx] = val;
241            }
242        }
243        // 反射方式查找,并修改值
244        else {
245            for (Object obj : args) {
246                Method setPlatformIdMethod = obj.getClass().getMethod("setPlatformId", Long.class);
247                log.info("setParamByName args2: {}", JSON.toJSONString(args));
248                if (ObjectUtil.isNull(setPlatformIdMethod)) {
249                    continue;
250                }
251
252                setPlatformIdMethod.invoke(obj, val);
253                log.info("setParamByName args3: {}", JSON.toJSONString(args));
254            }
255        }
256    }
257
258    /**
259     * 获取request中的IP
260     *
261     * @param request
262     * @return
263     */
264    public static String getIpAddress(HttpServletRequest request) {
265        if (request == null) {
266            return "unknown";
267        }
268
269        String ip = null;
270        try {
271            // 以下两个获取在k8s中,将真实的客户端IP,放到了x-Original-Forwarded-For。而将WAF的回源地址放到了 x-Forwarded-For了。
272            ip = request.getHeader("X-Original-Forwarded-For");
273            if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
274                ip = request.getHeader("X-Forwarded-For");
275            }
276            // 获取nginx等代理的ip
277            if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
278                ip = request.getHeader("x-forwarded-for");
279            }
280            if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
281                ip = request.getHeader("Proxy-Client-IP");
282            }
283            if (StrUtil.isEmpty(ip) || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
284                ip = request.getHeader("WL-Proxy-Client-IP");
285            }
286            if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
287                ip = request.getHeader("HTTP_CLIENT_IP");
288            }
289            if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
290                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
291            }
292            if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
293                ip = request.getHeader("X-Real-IP");
294            }
295            // 兼容k8s集群获取ip
296            if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
297                ip = request.getRemoteAddr();
298                if (LOCALHOST_IP1.equalsIgnoreCase(ip) || LOCALHOST_IP.equalsIgnoreCase(ip)) {
299                    // 根据网卡取本机配置的IP
300                    InetAddress iNet = null;
301                    try {
302                        iNet = InetAddress.getLocalHost();
303                    } catch (UnknownHostException e) {
304                        log.error("getClientIp error: ", e);
305                    }
306                    ip = iNet.getHostAddress();
307                }
308            }
309        } catch (Exception e) {
310            log.error("IPUtils ERROR ", e);
311        }
312
313        // 使用代理,则获取第一个IP地址
314        if (StrUtil.isNotEmpty(ip) && ip.indexOf(IP_UTILS_FLAG) > 0) {
315            ip = ip.substring(0, ip.indexOf(IP_UTILS_FLAG));
316        }
317
318        return ip;
319    }
320
321    /**
322     * 判断是否为JAVA基础类型
323     * @param obj
324     * @return
325     */
326    public static boolean isJavaLang(Object obj) {
327        return AnnotationFilter.PLAIN.matches(obj.getClass());
328//        return obj.getClass().getName().startsWith("java.lang");
329    }
330}