Browse Source

使用腾讯地图ip定位接口,优化异步任务异常判断

ZJY 6 months ago
parent
commit
c811dd03ea

+ 80 - 147
base-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ip/IpUtils.java

@@ -2,103 +2,103 @@ package com.ruoyi.common.core.utils.ip;
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.util.Objects;
 import javax.servlet.http.HttpServletRequest;
 import com.ruoyi.common.core.utils.StringUtils;
 
 /**
  * 获取IP方法
- * 
+ *
  * @author ruoyi
  */
-public class IpUtils
-{
-    /**
-     * 获取客户端IP
-     * 
-     * @param request 请求对象
-     * @return IP地址
-     */
-    public static String getIpAddr(HttpServletRequest request)
-    {
-        if (request == null)
-        {
+public final class IpUtils {
+
+    private IpUtils() {
+    }
+
+    public static String getIpAddr(HttpServletRequest request) {
+        if (request == null) {
             return "unknown";
         }
         String ip = request.getHeader("x-forwarded-for");
-        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
-        {
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
             ip = request.getHeader("Proxy-Client-IP");
         }
-        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
-        {
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
             ip = request.getHeader("X-Forwarded-For");
         }
-        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
-        {
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
             ip = request.getHeader("WL-Proxy-Client-IP");
         }
-        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
-        {
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
             ip = request.getHeader("X-Real-IP");
         }
-
-        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
-        {
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
             ip = request.getRemoteAddr();
         }
-
-        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip);
+        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getRemoteAddr();
+            if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
+                // 根据网卡取本机配置的IP
+                InetAddress inet = null;
+                try {
+                    inet = InetAddress.getLocalHost();
+                } catch (UnknownHostException e) {
+                    e.printStackTrace();
+                }
+                assert inet != null;
+                ip = inet.getHostAddress();
+            }
+        }
+        if ("0:0:0:0:0:0:0:1".equals(ip)) {
+            ip = "127.0.0.1";
+        } else {
+            String[] split = ip.split(",");
+            if (split.length > 1) {
+                for (String strIp : split) {
+                    if (!"127.0.0.1".equals(strIp)) {
+                        ip = strIp;
+                        break;
+                    }
+                }
+            }
+        }
+        return ip;
     }
 
-    /**
-     * 检查是否为内部IP地址
-     * 
-     * @param ip IP地址
-     * @return 结果
-     */
-    public static boolean internalIp(String ip)
-    {
+    public static boolean internalIp(String ip) {
         byte[] addr = textToNumericFormatV4(ip);
         return internalIp(addr) || "127.0.0.1".equals(ip);
     }
 
-    /**
-     * 检查是否为内部IP地址
-     * 
-     * @param addr byte地址
-     * @return 结果
-     */
-    private static boolean internalIp(byte[] addr)
-    {
-        if (StringUtils.isNull(addr) || addr.length < 2)
-        {
+    private static boolean internalIp(byte[] addr) {
+        if (Objects.isNull(addr) || addr.length < 2) {
             return true;
         }
         final byte b0 = addr[0];
         final byte b1 = addr[1];
         // 10.x.x.x/8
-        final byte SECTION_1 = 0x0A;
+        final byte section1 = 0x0A;
         // 172.16.x.x/12
-        final byte SECTION_2 = (byte) 0xAC;
-        final byte SECTION_3 = (byte) 0x10;
-        final byte SECTION_4 = (byte) 0x1F;
+        final byte section2 = (byte) 0xAC;
+        final byte section3 = (byte) 0x10;
+        final byte section4 = (byte) 0x1F;
         // 192.168.x.x/16
-        final byte SECTION_5 = (byte) 0xC0;
-        final byte SECTION_6 = (byte) 0xA8;
-        switch (b0)
-        {
-            case SECTION_1:
+        final byte section5 = (byte) 0xC0;
+        final byte section6 = (byte) 0xA8;
+        switch (b0) {
+            case section1:
                 return true;
-            case SECTION_2:
-                if (b1 >= SECTION_3 && b1 <= SECTION_4)
-                {
+            case section2:
+                if (b1 >= section3 && b1 <= section4) {
                     return true;
                 }
-            case SECTION_5:
-                switch (b1)
-                {
-                    case SECTION_6:
+            case section5:
+                switch (b1) {
+                    case section6:
                         return true;
+                    default:
+                        return false;
                 }
             default:
                 return false;
@@ -107,29 +107,24 @@ public class IpUtils
 
     /**
      * 将IPv4地址转换成字节
-     * 
+     *
      * @param text IPv4地址
      * @return byte 字节
      */
-    public static byte[] textToNumericFormatV4(String text)
-    {
-        if (text.length() == 0)
-        {
+    public static byte[] textToNumericFormatV4(String text) {
+        if (text.length() == 0) {
             return null;
         }
 
         byte[] bytes = new byte[4];
         String[] elements = text.split("\\.", -1);
-        try
-        {
+        try {
             long l;
             int i;
-            switch (elements.length)
-            {
+            switch (elements.length) {
                 case 1:
                     l = Long.parseLong(elements[0]);
-                    if ((l < 0L) || (l > 4294967295L))
-                    {
+                    if ((l < 0L) || (l > 4294967295L)) {
                         return null;
                     }
                     bytes[0] = (byte) (int) (l >> 24 & 0xFF);
@@ -139,14 +134,12 @@ public class IpUtils
                     break;
                 case 2:
                     l = Integer.parseInt(elements[0]);
-                    if ((l < 0L) || (l > 255L))
-                    {
+                    if ((l < 0L) || (l > 255L)) {
                         return null;
                     }
                     bytes[0] = (byte) (int) (l & 0xFF);
                     l = Integer.parseInt(elements[1]);
-                    if ((l < 0L) || (l > 16777215L))
-                    {
+                    if ((l < 0L) || (l > 16777215L)) {
                         return null;
                     }
                     bytes[1] = (byte) (int) (l >> 16 & 0xFF);
@@ -154,29 +147,24 @@ public class IpUtils
                     bytes[3] = (byte) (int) (l & 0xFF);
                     break;
                 case 3:
-                    for (i = 0; i < 2; ++i)
-                    {
+                    for (i = 0; i < 2; ++i) {
                         l = Integer.parseInt(elements[i]);
-                        if ((l < 0L) || (l > 255L))
-                        {
+                        if ((l < 0L) || (l > 255L)) {
                             return null;
                         }
                         bytes[i] = (byte) (int) (l & 0xFF);
                     }
                     l = Integer.parseInt(elements[2]);
-                    if ((l < 0L) || (l > 65535L))
-                    {
+                    if ((l < 0L) || (l > 65535L)) {
                         return null;
                     }
                     bytes[2] = (byte) (int) (l >> 8 & 0xFF);
                     bytes[3] = (byte) (int) (l & 0xFF);
                     break;
                 case 4:
-                    for (i = 0; i < 4; ++i)
-                    {
+                    for (i = 0; i < 4; ++i) {
                         l = Integer.parseInt(elements[i]);
-                        if ((l < 0L) || (l > 255L))
-                        {
+                        if ((l < 0L) || (l > 255L)) {
                             return null;
                         }
                         bytes[i] = (byte) (int) (l & 0xFF);
@@ -185,80 +173,25 @@ public class IpUtils
                 default:
                     return null;
             }
-        }
-        catch (NumberFormatException e)
-        {
+        } catch (NumberFormatException e) {
             return null;
         }
         return bytes;
     }
 
-    /**
-     * 获取IP地址
-     * 
-     * @return 本地IP地址
-     */
-    public static String getHostIp()
-    {
-        try
-        {
+    public static String getHostIp() {
+        try {
             return InetAddress.getLocalHost().getHostAddress();
-        }
-        catch (UnknownHostException e)
-        {
+        } catch (UnknownHostException e) {
         }
         return "127.0.0.1";
     }
 
-    /**
-     * 获取主机名
-     * 
-     * @return 本地主机名
-     */
-    public static String getHostName()
-    {
-        try
-        {
+    public static String getHostName() {
+        try {
             return InetAddress.getLocalHost().getHostName();
-        }
-        catch (UnknownHostException e)
-        {
+        } catch (UnknownHostException e) {
         }
         return "未知";
     }
-
-    /**
-     * 从多级反向代理中获得第一个非unknown IP地址
-     *
-     * @param ip 获得的IP地址
-     * @return 第一个非unknown IP地址
-     */
-    public static String getMultistageReverseProxyIp(String ip)
-    {
-        // 多级反向代理检测
-        if (ip != null && ip.indexOf(",") > 0)
-        {
-            final String[] ips = ip.trim().split(",");
-            for (String subIp : ips)
-            {
-                if (false == isUnknown(subIp))
-                {
-                    ip = subIp;
-                    break;
-                }
-            }
-        }
-        return ip;
-    }
-
-    /**
-     * 检测给定字符串是否为未知,多用于检测HTTP请求相关
-     *
-     * @param checkString 被检测的字符串
-     * @return 是否未知
-     */
-    public static boolean isUnknown(String checkString)
-    {
-        return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
-    }
 }

+ 1 - 1
base-modules/pom.xml

@@ -10,7 +10,7 @@
 
     <modules>
         <module>service-gen</module>
-        <module>service-job</module>
+<!--        <module>service-job</module>-->
         <module>service-file</module>
         <module>service-system</module>
     </modules>

+ 5 - 0
base-modules/service-system/service-system-biz/pom.xml

@@ -59,6 +59,11 @@
             <artifactId>hutool-all</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.json</groupId>
+            <artifactId>json</artifactId>
+            <version>20210307</version>
+        </dependency>
     </dependencies>
 
     <build>

+ 75 - 5
base-modules/service-system/service-system-biz/src/main/java/com/usky/system/service/util/AddressUtils.java

@@ -1,43 +1,113 @@
 package com.usky.system.service.util;
 
 import cn.hutool.http.HttpUtil;
+import com.alibaba.nacos.shaded.com.google.common.base.Strings;
 import com.ruoyi.common.core.utils.ip.IpUtils;
 import com.usky.system.domain.WjConfig;
+import org.json.JSONException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.util.StringUtils;
+import org.json.JSONObject;
 
-/**
+
+/*
  * 获取地址类
  *
  * @author xy
  */
+
+/*
 public class AddressUtils {
     private static final Logger log = LoggerFactory.getLogger(AddressUtils.class);
 
     // IP地址查询
-    public static  String IP_URL = "http://whois.pconline.com.cn/ip.jsp?ip=";
+    public static String IP_URL = "http://whois.pconline.com.cn/ip.jsp?ip=";
 
     // 未知地址
-    public static final String UNKNOWN = "未知地址";
+    public static final String UNKNOWN = "获取地理位置异常";
+
+    // 检查响应是否是503 Service Temporarily Unavailable
+    private static final String SERVICE_UNAVAILABLE_HTML = "503 Service Temporarily Unavailable";
 
     public static String getRealAddressByIP(String ip) {
         // 内网不查询
         if (IpUtils.internalIp(ip)) {
             return "内网IP";
         }
+        // 检查地址服务是否启用
         if (WjConfig.isAddressEnabled()) {
             try {
                 String url = IP_URL + ip;
                 String rspStr = HttpUtil.get(url);
                 log.info("ip is {}, repStr is {}, url is {}", ip, rspStr, url);
-                if (StringUtils.isEmpty(rspStr.trim())) {
+
+                // 检查响应是否为空或者503错误
+                if (Strings.isNullOrEmpty(rspStr) || rspStr.contains(SERVICE_UNAVAILABLE_HTML)) {
                     log.error("获取地理位置异常 {}, {}", ip, rspStr);
                     return UNKNOWN;
                 }
+                // 假设返回的字符串是直接的地理位置信息
                 return rspStr.trim();
             } catch (Exception e) {
-                log.error("获取地理位置异常 {}", ip);
+                log.error("获取地理位置异常 {}", ip, e);
+            }
+        }
+        return UNKNOWN;
+    }
+}
+*/
+
+public class AddressUtils {
+    private static final Logger log = LoggerFactory.getLogger(AddressUtils.class);
+
+    // 腾讯地图API URL
+    public static String IP_URL = "https://apis.map.qq.com/ws/location/v1/ip";
+    public static String API_KEY = "TSIBZ-NZSCU-H5SVQ-GUBLG-G6HFH-7LFSZ";
+
+    // 未知地址
+    public static final String UNKNOWN = "获取地理位置异常";
+
+    public static String getRealAddressByIP(String ip) {
+        // 内网不查询
+        if (IpUtils.internalIp(ip)) {
+            return "内网IP";
+        }
+        // 检查地址服务是否启用
+        if (WjConfig.isAddressEnabled()) {
+            try {
+                // 构建请求URL
+                String url = String.format("%s?ip=%s&key=%s", IP_URL, ip, API_KEY);
+                String rspStr = HttpUtil.get(url); // 使用GET请求发送数据
+                log.info("ip is {}, repStr is {}", ip, rspStr);
+
+                // 检查响应是否为空
+                if (rspStr == null || rspStr.isEmpty()) {
+                    log.error("获取地理位置异常 {}", ip);
+                    return UNKNOWN;
+                }
+
+                // 解析JSON响应
+                JSONObject jsonObject = new JSONObject(rspStr);
+                if (jsonObject.getInt("status") != 0) {
+                    log.error("获取地理位置失败: {}", jsonObject.getString("message"));
+                    return UNKNOWN;
+                }
+
+                // 提取地址信息
+                JSONObject adInfo = jsonObject.getJSONObject("result").getJSONObject("ad_info");
+                String nation = adInfo.getString("nation");
+                String province = adInfo.getString("province");
+                String city = adInfo.getString("city");
+                String district = adInfo.optString("district", "");
+
+                return String.format("%s%s%s%s", nation, province, city, district).trim();
+            } catch (JSONException e) {
+                log.error("JSON 解析异常", e);
+                return UNKNOWN;
+            } catch (Exception e) {
+                log.error("获取地理位置异常 {}", ip, e);
+                return UNKNOWN;
             }
         }
         return UNKNOWN;

+ 29 - 12
base-modules/service-system/service-system-biz/src/main/java/com/usky/system/service/util/AsyncManager.java

@@ -6,6 +6,7 @@ import org.springframework.stereotype.Component;
 import org.springframework.web.context.request.RequestContextHolder;
 import org.springframework.web.context.request.ServletRequestAttributes;
 
+import javax.annotation.PreDestroy;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
@@ -20,26 +21,42 @@ public class AsyncManager {
 
     private static final Logger logger = LoggerFactory.getLogger(AsyncManager.class);
 
-    /**
-     * 异步操作任务调度线程池
-     */
-
     private static final ThreadPoolExecutor executorEvent = new ThreadPoolExecutor(
             20, 30, 0L, TimeUnit.MILLISECONDS,
-            new ArrayBlockingQueue<Runnable>(1024),
+            new ArrayBlockingQueue<>(1024),
             new ThreadPoolExecutor.AbortPolicy()
     );
 
+    @PreDestroy
+    public void shutdown() {
+        executorEvent.shutdown();
+        try {
+            if (!executorEvent.awaitTermination(60, TimeUnit.SECONDS)) {
+                executorEvent.shutdownNow();
+            }
+        } catch (InterruptedException ex) {
+            executorEvent.shutdownNow();
+            Thread.currentThread().interrupt();
+        }
+    }
 
     public void insertLog(Integer tenantId, final String username, final String status, final String message, final Integer deptId) {
         ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
-        RequestContextHolder.setRequestAttributes(sra, true);
-        executorEvent.execute(() -> {
-            logger.info("new Log is {} , {}", username, message);
-            AsyncFactory.recordLoginInfo(tenantId, username, status, message, deptId);
-        });
+        if (sra != null) {
+            executorEvent.execute(() -> {
+                try {
+                    RequestContextHolder.setRequestAttributes(sra, true);
+                    logger.info("new Log is {} , {}", username, message);
+                    AsyncFactory.recordLoginInfo(tenantId, username, status, message, deptId);
+                } catch (Exception e) {
+                    logger.error("记录登录信息异常", e);
+                } finally {
+                    RequestContextHolder.resetRequestAttributes();
+                }
+            });
+        } else {
+            logger.warn("当前线程没有RequestContext,无法记录登录信息");
+        }
     }
-
-
 }