Explorar o código

使用yauaa代替bitwalker

RuoYi hai 6 meses
pai
achega
eb6878e18f

+ 4 - 4
pom.xml

@@ -20,7 +20,7 @@
         <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
         <spring-boot.version>2.5.15</spring-boot.version>
         <druid.version>1.2.23</druid.version>
-        <bitwalker.version>1.21</bitwalker.version>
+        <yauaa.version>7.32.0</yauaa.version>
         <swagger.version>3.0.0</swagger.version>
         <kaptcha.version>2.3.3</kaptcha.version>
         <pagehelper.boot.version>1.4.7</pagehelper.boot.version>
@@ -109,9 +109,9 @@
 
             <!-- 解析客户端操作系统、浏览器等 -->
             <dependency>
-                <groupId>eu.bitwalker</groupId>
-                <artifactId>UserAgentUtils</artifactId>
-                <version>${bitwalker.version}</version>
+                <groupId>nl.basjes.parse.useragent</groupId>
+                <artifactId>yauaa</artifactId>
+                <version>${yauaa.version}</version>
             </dependency>
 
             <!-- pagehelper 分页插件 -->

+ 2 - 8
ruoyi-common/pom.xml

@@ -77,12 +77,6 @@
             <artifactId>poi-ooxml</artifactId>
         </dependency>
 
-        <!-- yml解析器 -->
-        <dependency>
-            <groupId>org.yaml</groupId>
-            <artifactId>snakeyaml</artifactId>
-        </dependency>
-
         <!-- Token生成与解析-->
         <dependency>
             <groupId>io.jsonwebtoken</groupId>
@@ -109,8 +103,8 @@
 
         <!-- 解析客户端操作系统、浏览器等 -->
         <dependency>
-            <groupId>eu.bitwalker</groupId>
-            <artifactId>UserAgentUtils</artifactId>
+            <groupId>nl.basjes.parse.useragent</groupId>
+            <artifactId>yauaa</artifactId>
         </dependency>
 
         <!-- servlet包 -->

+ 254 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/http/UserAgentUtils.java

@@ -0,0 +1,254 @@
+package com.ruoyi.common.utils.http;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import com.ruoyi.common.utils.StringUtils;
+import nl.basjes.parse.useragent.UserAgent;
+import nl.basjes.parse.useragent.UserAgentAnalyzer;
+
+/**
+ * UserAgent解析工具类
+ * 
+ * @author ruoyi
+ */
+public class UserAgentUtils
+{
+    public static final String UNKNOWN = "";
+
+    // 浏览器正则表达式模式
+    private static final Pattern CHROME_PATTERN = Pattern.compile("Chrome/(\\d+)(?:\\.\\d+)*");
+    private static final Pattern FIREFOX_PATTERN = Pattern.compile("Firefox/(\\d+)(?:\\.\\d+)*");
+    private static final Pattern EDGE_PATTERN = Pattern.compile("Edg(?:e)?/(\\d+)(?:\\.\\d+)*");
+    private static final Pattern SAFARI_PATTERN = Pattern.compile("Version/(\\d+)(?:\\.\\d+)*");
+    private static final Pattern OPERA_PATTERN = Pattern.compile("Opera/(\\d+)(?:\\.\\d+)*");
+    private static final Pattern IE_PATTERN = Pattern.compile("(?:MSIE |Trident/.*rv:)(\\d+)(?:\\.\\d+)*");
+    private static final Pattern SAMSUNG_PATTERN = Pattern.compile("SamsungBrowser/(\\d+)(?:\\.\\d+)*");
+    private static final Pattern UC_PATTERN = Pattern.compile("UCBrowser/(\\d+)(?:\\.\\d+)*");
+    private static final Pattern QQ_PATTERN = Pattern.compile("QQBrowser/(\\d+)(?:\\.\\d+)*");
+    private static final Pattern WECHAT_PATTERN = Pattern.compile("MicroMessenger/(\\d+)(?:\\.\\d+)*");
+    private static final Pattern BAIDU_PATTERN = Pattern.compile("baidubrowser/(\\d+)(?:\\.\\d+)*");
+
+    // 操作系统正则表达式模式
+    private static final Pattern WINDOWS_PATTERN = Pattern.compile("Windows NT (\\d+\\.\\d+)");
+    private static final Pattern MACOS_PATTERN = Pattern.compile("Mac OS X (\\d+[_\\d]*)");
+    private static final Pattern ANDROID_PATTERN = Pattern.compile("Android (\\d+)(?:\\.\\d+)*");
+    private static final Pattern IOS_PATTERN = Pattern.compile("OS[\\s_](\\d+)(?:_\\d+)*");
+    private static final Pattern LINUX_PATTERN = Pattern.compile("Linux");
+    private static final Pattern CHROMEOS_PATTERN = Pattern.compile("CrOS");
+
+    private static final UserAgentAnalyzer userAgentAnalyzer = UserAgentAnalyzer
+            .newBuilder().hideMatcherLoadStats()
+            .withCache(5000)
+            .showMinimalVersion()
+            .withField(UserAgent.AGENT_NAME_VERSION)
+            .withField(UserAgent.OPERATING_SYSTEM_NAME_VERSION)
+            .build();
+
+    /**
+     * 获取客户端浏览器
+     */
+    public static String getBrowser(String userAgent)
+    {
+        UserAgent.ImmutableUserAgent iua = userAgentAnalyzer.parse(userAgent);
+        String agentNameVersion = iua.get(UserAgent.AGENT_NAME_VERSION).getValue();
+        if (StringUtils.isBlank(agentNameVersion) || agentNameVersion.contains("??"))
+        {
+            return formatBrowser(userAgent);
+        }
+        return agentNameVersion;
+    }
+
+    /**
+     * 获取客户端操作系统
+     */
+    public static String getOperatingSystem(String userAgent)
+    {
+        UserAgent.ImmutableUserAgent iua = userAgentAnalyzer.parse(userAgent);
+        String operatingSystemNameVersion = iua.get(UserAgent.OPERATING_SYSTEM_NAME_VERSION).getValue();
+        if (StringUtils.isBlank(operatingSystemNameVersion) || operatingSystemNameVersion.contains("??"))
+        {
+            return formatOperatingSystem(userAgent);
+        }
+        return operatingSystemNameVersion;
+    }
+
+    /**
+     * 全面浏览器检测
+     */
+    private static String formatBrowser(String browser)
+    {
+        // Chrome系列浏览器
+        Matcher chromeMatcher = CHROME_PATTERN.matcher(browser);
+        if (chromeMatcher.find() && (browser.contains("Chrome") || browser.contains("CriOS")))
+        {
+            return "Chrome" + chromeMatcher.group(1);
+        }
+        // Firefox
+        Matcher firefoxMatcher = FIREFOX_PATTERN.matcher(browser);
+        if (firefoxMatcher.find())
+        {
+            return "Firefox" + firefoxMatcher.group(1);
+        }
+        // Edge浏览器
+        Matcher edgeMatcher = EDGE_PATTERN.matcher(browser);
+        if (edgeMatcher.find())
+        {
+            return "Edge" + edgeMatcher.group(1);
+        }
+        // Safari浏览器(需排除Chrome)
+        Matcher safariMatcher = SAFARI_PATTERN.matcher(browser);
+        if (safariMatcher.find() && !browser.contains("Chrome"))
+        {
+            return "Safari" + safariMatcher.group(1);
+        }
+        // 微信内置浏览器
+        Matcher wechatMatcher = WECHAT_PATTERN.matcher(browser);
+        if (wechatMatcher.find())
+        {
+            return "WeChat" + wechatMatcher.group(1);
+        }
+        // UC浏览器
+        Matcher ucMatcher = UC_PATTERN.matcher(browser);
+        if (ucMatcher.find())
+        {
+            return "UC Browser" + ucMatcher.group(1);
+        }
+        // QQ浏览器
+        Matcher qqMatcher = QQ_PATTERN.matcher(browser);
+        if (qqMatcher.find())
+        {
+            return "QQ Browser" + qqMatcher.group(1);
+        }
+        // 百度浏览器
+        Matcher baiduMatcher = BAIDU_PATTERN.matcher(browser);
+        if (baiduMatcher.find())
+        {
+            return "Baidu Browser" + baiduMatcher.group(1);
+        }
+        // Samsung浏览器
+        Matcher samsungMatcher = SAMSUNG_PATTERN.matcher(browser);
+        if (samsungMatcher.find())
+        {
+            return "Samsung Browser" + samsungMatcher.group(1);
+        }
+        // Opera浏览器
+        Matcher operaMatcher = OPERA_PATTERN.matcher(browser);
+        if (operaMatcher.find())
+        {
+            return "Opera" + operaMatcher.group(1);
+        }
+        // IE浏览器
+        Matcher ieMatcher = IE_PATTERN.matcher(browser);
+        if (ieMatcher.find())
+        {
+            return "Internet Explorer" + ieMatcher.group(1);
+        }
+        return UNKNOWN;
+    }
+
+    /**
+     * 检测操作系统
+     */
+    private static String formatOperatingSystem(String operatingSystem)
+    {
+        // Windows系统
+        Matcher windowsMatcher = WINDOWS_PATTERN.matcher(operatingSystem);
+        if (windowsMatcher.find())
+        {
+            return "Windows" + getWindowsVersionDisplay(windowsMatcher.group(1));
+        }
+        // macOS系统
+        Matcher macMatcher = MACOS_PATTERN.matcher(operatingSystem);
+        if (macMatcher.find())
+        {
+            String version = macMatcher.group(1).replace("_", ".");
+            return "macOS" + extractMajorVersion(version);
+        }
+        // Android系统
+        Matcher androidMatcher = ANDROID_PATTERN.matcher(operatingSystem);
+        if (androidMatcher.find())
+        {
+            return "Android" + extractMajorVersion(androidMatcher.group(1));
+        }
+        // iOS系统
+        Matcher iosMatcher = IOS_PATTERN.matcher(operatingSystem);
+        if (iosMatcher.find() && (operatingSystem.contains("iPhone") || operatingSystem.contains("iPad")))
+        {
+            return "iOS" + extractMajorVersion(iosMatcher.group(1));
+        }
+        // Linux系统
+        if (LINUX_PATTERN.matcher(operatingSystem).find() && !operatingSystem.contains("Android"))
+        {
+            return "Linux";
+        }
+        // Chrome OS
+        if (CHROMEOS_PATTERN.matcher(operatingSystem).find())
+        {
+            return "Chrome OS";
+        }
+        return UNKNOWN;
+    }
+
+    /**
+     * 提取优化的主版本号
+     */
+    private static String extractMajorVersion(String fullVersion)
+    {
+        if (StringUtils.isEmpty(fullVersion))
+        {
+            return StringUtils.EMPTY;
+        }
+        try
+        {
+            // 清理版本号中的非数字字符
+            String cleanVersion = fullVersion.replaceAll("[^0-9.]", "");
+            String[] parts = cleanVersion.split("\\.");
+            if (parts.length > 0)
+            {
+                String firstPart = parts[0];
+                if (firstPart.matches("\\d+"))
+                {
+                    int version = Integer.parseInt(firstPart);
+
+                    // 处理三位数版本号(如142 -> 14)
+                    if (version >= 100)
+                    {
+                        return String.valueOf(version / 10);
+                    }
+                    return firstPart;
+                }
+            }
+        }
+        catch (NumberFormatException e)
+        {
+            // 版本号解析失败,返回原始值
+        }
+        return fullVersion;
+    }
+
+    /**
+     * Windows版本号显示优化
+     */
+    private static String getWindowsVersionDisplay(String version)
+    {
+        switch (version)
+        {
+            case "10.0":
+                return "10";
+            case "6.3":
+                return "8.1";
+            case "6.2":
+                return "8";
+            case "6.1":
+                return "7";
+            case "6.0":
+                return "Vista";
+            case "5.1":
+                return "XP";
+            case "5.0":
+                return "2000";
+            default:
+                return extractMajorVersion(version);
+        }
+    }
+}

+ 4 - 4
ruoyi-framework/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java

@@ -7,6 +7,7 @@ import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.utils.LogUtils;
 import com.ruoyi.common.utils.ServletUtils;
 import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.http.UserAgentUtils;
 import com.ruoyi.common.utils.ip.AddressUtils;
 import com.ruoyi.common.utils.ip.IpUtils;
 import com.ruoyi.common.utils.spring.SpringUtils;
@@ -14,7 +15,6 @@ import com.ruoyi.system.domain.SysLogininfor;
 import com.ruoyi.system.domain.SysOperLog;
 import com.ruoyi.system.service.ISysLogininforService;
 import com.ruoyi.system.service.ISysOperLogService;
-import eu.bitwalker.useragentutils.UserAgent;
 
 /**
  * 异步工厂(产生任务用)
@@ -37,7 +37,7 @@ public class AsyncFactory
     public static TimerTask recordLogininfor(final String username, final String status, final String message,
             final Object... args)
     {
-        final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
+        final String userAgent = ServletUtils.getRequest().getHeader("User-Agent");
         final String ip = IpUtils.getIpAddr();
         return new TimerTask()
         {
@@ -54,9 +54,9 @@ public class AsyncFactory
                 // 打印信息到日志
                 sys_user_logger.info(s.toString(), args);
                 // 获取客户端操作系统
-                String os = userAgent.getOperatingSystem().getName();
+                String os = UserAgentUtils.getOperatingSystem(userAgent);
                 // 获取客户端浏览器
-                String browser = userAgent.getBrowser().getName();
+                String browser = UserAgentUtils.getBrowser(userAgent);
                 // 封装对象
                 SysLogininfor logininfor = new SysLogininfor();
                 logininfor.setUserName(username);

+ 4 - 4
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java

@@ -15,10 +15,10 @@ import com.ruoyi.common.core.domain.model.LoginUser;
 import com.ruoyi.common.core.redis.RedisCache;
 import com.ruoyi.common.utils.ServletUtils;
 import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.http.UserAgentUtils;
 import com.ruoyi.common.utils.ip.AddressUtils;
 import com.ruoyi.common.utils.ip.IpUtils;
 import com.ruoyi.common.utils.uuid.IdUtils;
-import eu.bitwalker.useragentutils.UserAgent;
 import io.jsonwebtoken.Claims;
 import io.jsonwebtoken.Jwts;
 import io.jsonwebtoken.SignatureAlgorithm;
@@ -161,12 +161,12 @@ public class TokenService
      */
     public void setUserAgent(LoginUser loginUser)
     {
-        UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
+        String userAgent = ServletUtils.getRequest().getHeader("User-Agent");
         String ip = IpUtils.getIpAddr();
         loginUser.setIpaddr(ip);
         loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
-        loginUser.setBrowser(userAgent.getBrowser().getName());
-        loginUser.setOs(userAgent.getOperatingSystem().getName());
+        loginUser.setBrowser(UserAgentUtils.getOperatingSystem(userAgent));
+        loginUser.setOs(UserAgentUtils.getBrowser(userAgent));
     }
 
     /**