完整的数据接口调用过程

📅 2026/7/18 22:01:20
完整的数据接口调用过程
整体架构Thymeleaf页面 ↔ SpringBoot代理接口 ↔ 数据网关1. 前端层!DOCTYPE html html langzh-CN xmlns:thhttp://www.thymeleaf.org head meta charsetUTF-8 title公共数据展示/title style body { padding: 30px; font-family: 微软雅黑; } button { padding: 8px 22px; font-size: 15px; cursor: pointer; } table { border-collapse: collapse; width: 90%; margin-top: 20px; } th,td { border:1px solid #ccc; padding:10px; text-align:center; } th { background:#f0f0f0; } .tip { color:#666; margin:10px 0; } .error { color:red; } /style /head body h3淄博公共开放数据查询天气预报/h3 div classtip button idqueryBtn查询7天天气/button /div div idresultBox/div script // WMO天气编码中文映射 const weatherMap { 0: 晴, 3: 多云, 51: 小雨/毛毛雨, 81: 阵雨 }; const queryBtn document.getElementById(queryBtn); const resultBox document.getElementById(resultBox); queryBtn.addEventListener(click, async (){ resultBox.innerHTML p classtip数据加载中.../p; try { // 调用后端代理接口天气接口无分页参数直接去掉page/start const res await fetch(/api/proxy/getW); const rawJson await res.json(); // 网关鉴权失败判断 if(rawJson.code ! 200){ resultBox.innerHTML p classerror接口调用失败${raw.msg}/p; return; } // 解析嵌套JSON字符串 const weatherData JSON.parse(rawJson.data); const daily weatherData.daily; // 拼接页面HTML let html p classtip 经度${weatherData.longitude}纬度${weatherData.latitude}时区${weatherData.timezone} /p table thead tr th日期/th th天气编码/th th天气/th th最高温℃/th th最低温℃/th /tr /thead tbody ; // 遍历日期数组渲染每行 daily.time.forEach((date, index) { const code daily.weathercode[index]; html tr td${date}/td td${code}/td td${weatherMap[code] || 未知天气}/td td${daily.temperature_2m_max[index]}/td td${daily.temperature_2m_min[index]}/td /tr ; }); html /tbody/table; resultBox.innerHTML html; }catch(err){ console.error(err); resultBox.innerHTML p classerror请求异常${err.message}/p; } }) /script /body /html2. SpringBoot后端代理层package demo.controller; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; import java.security.cert.X509Certificate; import java.util.Base64; import java.util.UUID; import javax.net.ssl.*; RestController public class GatewayProxyController { private static final String CLIENT_ID 972ee8d6d************2e521520184; private static final String CLIENT_SECRET f8f4d09*********e395224ebd96; private static final String API_URL https://data.sd.gov.cn/gateway/api/1/get_W; private static final String HMAC_ALGORITHM HmacSHA256; // 静态禁用SSL校验仅本地调试 static { try { TrustManager[] trustAllCerts new TrustManager[]{ new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } public void checkClientTrusted(X509Certificate[] certs, String authType) {} public void checkServerTrusted(X509Certificate[] certs, String authType) {} } }; SSLContext sslContext SSLContext.getInstance(TLS); sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); HostnameVerifier allHostsValid (hostname, session) - true; HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid); } catch (Exception e) { e.printStackTrace(); } } GetMapping(/api/proxy/getW) public String proxyGetW() { try { String timestamp String.valueOf(System.currentTimeMillis()); String nonce UUID.randomUUID().toString(); String textToSign CLIENT_ID timestamp nonce; Mac mac Mac.getInstance(HMAC_ALGORITHM); SecretKeySpec key new SecretKeySpec(CLIENT_SECRET.getBytes(StandardCharsets.UTF_8), HMAC_ALGORITHM); mac.init(key); byte[] hmacData mac.doFinal(textToSign.getBytes(StandardCharsets.UTF_8)); String signature Base64.getEncoder().encodeToString(hmacData); URL url new URL(API_URL); HttpURLConnection conn (HttpURLConnection) url.openConnection(); conn.setRequestMethod(GET); conn.setConnectTimeout(10000); conn.setReadTimeout(10000); conn.setRequestProperty(X-Client-Id, CLIENT_ID); conn.setRequestProperty(X-Timestamp, timestamp); conn.setRequestProperty(X-Nonce, nonce); conn.setRequestProperty(X-Signature, signature); int code conn.getResponseCode(); BufferedReader br new BufferedReader(new InputStreamReader( code 200 code 300 ? conn.getInputStream() : conn.getErrorStream(), StandardCharsets.UTF_8 )); StringBuilder sb new StringBuilder(); String line; while ((line br.readLine()) ! null) { sb.append(line); } br.close(); conn.disconnect(); return sb.toString(); } catch (Exception e) { e.printStackTrace(); return 代理接口异常 e.getMessage(); } } }3.页面跳转控制器Controller public class TestController { GetMapping(/huoqu) public String toHuoquList() { return huoqu-list; } }4.全局跨域配置import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/api/**) .allowedOrigins(*) .allowedMethods(GET) .maxAge(3600); } }