ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/GpsCollectController.java
New file @@ -0,0 +1,36 @@ package com.ruoyi.web.controller.system; import com.ruoyi.common.annotation.Anonymous; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.system.domain.GpsLoginRequest; import com.ruoyi.system.domain.GpsLoginResponse; import com.ruoyi.system.service.IGpsCollectService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; /** * GPS采集接口 */ @RestController @RequestMapping("/system/gpscollect") public class GpsCollectController extends BaseController { @Autowired private IGpsCollectService gpsCollectService; /** * 测试登录接口 */ @Anonymous() @GetMapping("/testLogin") public AjaxResult testLogin() { GpsLoginRequest request = new GpsLoginRequest(); request.setType("USER"); request.setFrom("WEB"); request.setBrowser("Chrome/104.0.0.0"); GpsLoginResponse response = gpsCollectService.login(request); return success(response); } } ruoyi-admin/src/main/resources/application.yml
@@ -12,10 +12,7 @@ addressEnabled: false # 验证码类型 math 数字计算 char 字符验证 captchaType: math # 匿名访问配置 anonymous: appId: appId1 securityKey: your_security_key # 开发环境配置 server: @@ -131,3 +128,10 @@ excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* # GPS服务配置 gps: service: domain: https://gps51.com username: 王某人 password: Aa1357 ruoyi-common/pom.xml
@@ -46,7 +46,11 @@ <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> </dependency> <!--常用工具类 --> <dependency> <groupId>org.apache.commons</groupId> ruoyi-common/src/main/java/com/ruoyi/common/utils/HttpUtil.java
New file @@ -0,0 +1,119 @@ package com.ruoyi.common.utils; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Map; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.security.cert.X509Certificate; import com.alibaba.fastjson.JSON; /** * HTTP工具类 */ public class HttpUtil { private static final int CONNECT_TIMEOUT = 5000; private static final int READ_TIMEOUT = 5000; static { try { // 创建信任所有证书的TrustManager TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) { } public void checkServerTrusted(X509Certificate[] certs, String authType) { } } }; // 初始化SSLContext SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); // 设置主机名验证器 HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true); } catch (Exception e) { throw new RuntimeException("初始化SSL上下文失败", e); } } /** * 发送POST请求 * @param url 请求URL * @param params 请求参数 * @return 响应内容 */ public static String post(String url, Map<String, String> params) { StringBuilder response = new StringBuilder(); HttpURLConnection conn = null; try { // 创建连接 URL requestUrl = new URL(url); boolean isHttps = url.toLowerCase().startsWith("https"); // 根据协议类型创建连接 if (isHttps) { conn = (HttpsURLConnection) requestUrl.openConnection(); } else { conn = (HttpURLConnection) requestUrl.openConnection(); } // 设置请求属性 conn.setRequestMethod("POST"); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); conn.setRequestProperty("Content-Type", "application/json"); conn.setRequestProperty("Accept", "application/json"); // 设置超时时间 conn.setConnectTimeout(CONNECT_TIMEOUT); conn.setReadTimeout(READ_TIMEOUT); // 构建JSON参数字符串 String jsonParams = JSON.toJSONString(params); // 发送请求参数 try (OutputStream os = conn.getOutputStream()) { os.write(jsonParams.getBytes(StandardCharsets.UTF_8)); os.flush(); } // 获取响应码 int responseCode = conn.getResponseCode(); if (responseCode != HttpURLConnection.HTTP_OK) { throw new RuntimeException("HTTP请求失败,响应码: " + responseCode); } // 读取响应 try (BufferedReader reader = new BufferedReader( new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) { String line; while ((line = reader.readLine()) != null) { response.append(line); } } } catch (Exception e) { throw new RuntimeException("HTTP请求失败: " + e.getMessage(), e); } finally { if (conn != null) { conn.disconnect(); } } return response.toString(); } } ruoyi-common/src/main/java/com/ruoyi/common/utils/MD5Util.java
New file @@ -0,0 +1,37 @@ package com.ruoyi.common.utils; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * MD5加密工具类 */ public class MD5Util { /** * MD5加密(32位小写) * @param plainText 明文 * @return 32位小写MD5 */ public static String md5(String plainText) { try { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(plainText.getBytes()); byte[] b = md.digest(); StringBuilder buf = new StringBuilder(""); for (int offset = 0; offset < b.length; offset++) { int i = b[offset]; if (i < 0) { i += 256; } if (i < 16) { buf.append("0"); } buf.append(Integer.toHexString(i)); } return buf.toString(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return ""; } } } ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java
@@ -214,7 +214,7 @@ String urlNameString = url + "?" + param; try { log.info("sendSSLPost - {}", urlNameString); // log.info("sendSSLPost - {}", urlNameString); SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom()); URL console = new URL(urlNameString); @@ -240,25 +240,26 @@ result.append(new String(ret.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8)); } } log.info("recv - {}", result); // log.info("recv - {}", result); conn.disconnect(); br.close(); } catch (ConnectException e) { log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e); // log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e); } catch (SocketTimeoutException e) { log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e); // log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e); } catch (IOException e) { log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e); // log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e); } catch (Exception e) { log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e); // log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e); } return result.toString(); } ruoyi-system/pom.xml
@@ -32,6 +32,12 @@ <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> <!-- FastJSON --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> </dependency> </dependencies> ruoyi-system/src/main/java/com/ruoyi/system/config/GpsServiceConfig.java
New file @@ -0,0 +1,39 @@ package com.ruoyi.system.config; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; /** * GPS服务配置 */ @Component @ConfigurationProperties(prefix = "gps.service") public class GpsServiceConfig { private String domain; private String username; private String password; public String getDomain() { return domain; } public void setDomain(String domain) { this.domain = domain; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } } ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLoginRequest.java
New file @@ -0,0 +1,63 @@ package com.ruoyi.system.domain; import com.fasterxml.jackson.annotation.JsonProperty; /** * GPS登录请求实体 */ public class GpsLoginRequest { @JsonProperty("username") private String username; @JsonProperty("password") private String password; @JsonProperty("from") private String from; @JsonProperty("type") private String type; @JsonProperty("browser") private String browser; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getFrom() { return from; } public void setFrom(String from) { this.from = from; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getBrowser() { return browser; } public void setBrowser(String browser) { this.browser = browser; } } ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLoginResponse.java
New file @@ -0,0 +1,24 @@ package com.ruoyi.system.domain; import lombok.Data; /** * GPS登录响应 */ @Data public class GpsLoginResponse { /** * 是否成功 */ private boolean success; /** * 消息 */ private String message; /** * Token */ private String token; } ruoyi-system/src/main/java/com/ruoyi/system/service/IGpsCollectService.java
New file @@ -0,0 +1,16 @@ package com.ruoyi.system.service; import com.ruoyi.system.domain.GpsLoginRequest; import com.ruoyi.system.domain.GpsLoginResponse; /** * GPS采集服务接口 */ public interface IGpsCollectService { /** * GPS登录 * @param request 登录请求 * @return 登录响应 */ GpsLoginResponse login(GpsLoginRequest request); } ruoyi-system/src/main/java/com/ruoyi/system/service/impl/GpsCollectServiceImpl.java
New file @@ -0,0 +1,144 @@ package com.ruoyi.system.service.impl; import com.ruoyi.common.utils.http.HttpUtils; import com.ruoyi.system.domain.GpsLoginRequest; import com.ruoyi.system.domain.GpsLoginResponse; import com.ruoyi.system.service.IGpsCollectService; import com.ruoyi.system.config.GpsServiceConfig; import com.ruoyi.common.utils.MD5Util; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import java.util.HashMap; import java.util.Map; import org.springframework.util.StringUtils; import com.ruoyi.common.utils.HttpUtil; import com.alibaba.fastjson.JSONObject; import com.ruoyi.common.exception.ServiceException; /** * GPS采集服务实现 */ @Service public class GpsCollectServiceImpl implements IGpsCollectService { private final RestTemplate restTemplate; private final GpsServiceConfig gpsServiceConfig; public GpsCollectServiceImpl(GpsServiceConfig gpsServiceConfig) { this.restTemplate = new RestTemplate(); this.gpsServiceConfig = gpsServiceConfig; } @Override public GpsLoginResponse login(GpsLoginRequest request) { // 参数校验 if (StringUtils.isEmpty(request.getType()) || StringUtils.isEmpty(request.getFrom())) { throw new ServiceException("参数不能为空"); } // 构建请求URL String url = gpsServiceConfig.getDomain() + "/webapi?action=login"; // 设置请求参数 Map<String, String> params = new HashMap<>(); params.put("username", gpsServiceConfig.getUsername()); params.put("password", MD5Util.md5(gpsServiceConfig.getPassword())); params.put("type", request.getType()); params.put("from", request.getFrom()); params.put("browser", request.getBrowser()); StringBuilder paramStr = new StringBuilder(); for (Map.Entry<String, String> entry : params.entrySet()) { if (paramStr.length() > 0) { paramStr.append("&"); } paramStr.append(entry.getKey()).append("=").append(entry.getValue()); } // 发送请求 String response = HttpUtil.post(url,params); // 解析响应 GpsLoginResponse loginResponse = new GpsLoginResponse(); try { JSONObject jsonResponse = JSONObject.parseObject(response); int status = jsonResponse.getIntValue("status"); String username = jsonResponse.getString("username"); // 根据返回码设置响应信息 switch (status) { case 0: loginResponse.setSuccess(true); loginResponse.setMessage("登录成功"); loginResponse.setToken(jsonResponse.getString("token")); break; case -1: loginResponse.setSuccess(false); loginResponse.setMessage("登录失败"); break; case 1: loginResponse.setSuccess(false); loginResponse.setMessage("密码错误"); break; case 2: loginResponse.setSuccess(false); loginResponse.setMessage("禁止登录"); break; case 3: loginResponse.setSuccess(false); loginResponse.setMessage("账号已禁用"); break; case 4: loginResponse.setSuccess(false); loginResponse.setMessage("设备到期"); break; case 5: loginResponse.setSuccess(false); loginResponse.setMessage("设备过期"); break; case 9903: loginResponse.setSuccess(false); loginResponse.setMessage("Token过期"); break; case 9906: loginResponse.setSuccess(false); loginResponse.setMessage("账号在其他地方登录"); break; default: loginResponse.setSuccess(false); loginResponse.setMessage("未知错误"); break; } } catch (Exception e) { loginResponse.setSuccess(false); loginResponse.setMessage("解析响应失败:" + e.getMessage()); } return loginResponse; } /** * 校验登录来源 */ private boolean isValidFrom(String from) { if (from == null) { return false; } return "ANDROID".equals(from) || "IPHONE".equals(from) || "WEB".equals(from) || "WEIXIN".equals(from); } /** * 校验登录类型 */ private boolean isValidType(String type) { if (type == null) { return false; } return "USER".equals(type) || "DEVICE".equals(type); } }