当前位置: 首页 > news >正文

若依项目天气模块

在若依项目里添加了一个天气模块,记录一下过程。

一、功能结构与组件布局

天气模块以卡片形式(el-card)展示,包含以下核心功能:

  1. 实时天气:显示当前城市、温度、天气状况(如晴、多云)、湿度、空气质量(AQI)。
  2. 三天预报:展示未来三天的最高 / 最低温、天气图标及状况。
  3. 加载状态:数据获取中显示加载动画,失败时提示错误。

模板结构(template部分)

<el-card class="weather-module"><div slot="header">实时天气</div><div class="weather-info"><!-- 加载中状态 --><div v-else class="weather-loading">获取天气中...</div><!-- 实时天气数据 --><div v-if="weatherData"><div class="location-area">城市名 + 预报提示</div><div class="current-weather">温度 + 天气状况 + 详情(湿度、AQI)</div><!-- 三天预报 --><el-row v-if="dailyForecast.length>0"><el-col v-for="day in dailyForecast" :key="index"><div>日期</div><div>温度范围</div><div>天气图标 + 状况</div></el-col></el-row></div></div>
</el-card>

二、数据获取与状态管理

我这里选择的第三方接口是彩云天气,也考虑过和风天气和OpenWeatherMap但注册流程不是很顺利,相比而言彩云天气更便利而且免费。

1. 数据来源与 API 调用

  • 地理位置获取:通过getIpLocation接口获取用户 IP 对应的经纬度和城市(优先使用定位,失败则用默认城市 “保定市”)。
  • 天气数据接口:调用彩云天气 API(api.caiyunapp.com),通过代理处理跨域问题(vue.config.js中配置/weather-proxy代理)。
// API调用示例(传入经纬度)
export function getWeatherByLocation(lon, lat) {return request({url: `/weather-proxy/v2.6/XXXXXXXXXXXX/${lon},${lat}/weather`,params: { dailysteps: 3, hourlysteps: 48 }, // 三天预报});
}

2. 核心数据字段

  • weatherData:存储实时天气(realtime)和预报(daily)数据。
data() {return {weatherData: {realtime: {}, // 实时数据(温度、天气状况、湿度、AQI等)daily: [],    // 三天预报数据数组result: { forecast_keypoint: '' } // 天气提示},cityName: '默认城市', // 默认城市longitude: null,    // 经度(定位获取)latitude: null      // 纬度(定位获取)};
}

三、关键逻辑实现

 定位与天气数据获取流程

  • 定位逻辑fetchLocation):

    async fetchLocation() {try {const { data } = await getIpLocation(); // 获取IP定位this.longitude = data.point.x;this.latitude = data.point.y;this.cityName = data.address_detail.city || '保定市';await this.fetchWeatherByLocation(); // 定位成功后请求天气} catch (error) {this.$message.error('定位失败,使用默认城市');this.fetchDefaultWeather(); // 定位失败,用默认城市}
    }
    
  • 默认天气逻辑fetchDefaultWeather):

    async fetchDefaultWeather() {// 使用XX市固定坐标(125.4833, 32.8500)请求天气await getWeatherByLocation(125.4833, 32.8500).then(res => {this.weatherData = res.result;this.cityName = 'XX市';});
    }

 数据处理与格式化

  • 计算属性:用于动态处理数据,避免模板中复杂逻辑。
    computed: {// 实时温度(保留一位小数)currentTemp() {return this.weatherData.realtime.temperature.toFixed(1) || '-';},// 天气状况文本(如“晴”“多云”)currentSkycon() {return this.formatSkycon(this.weatherData.realtime.skycon);},// 三天预报(截取前三天并格式化温度)dailyForecast() {return this.weatherData.daily.slice(0, 3).map(day => ({temp: [day.temp.max.toFixed(0), day.temp.min.toFixed(0)],skycon: day.skycon}));}
    },
    methods: {// 天气状况映射(如CLEAR_DAY→晴)formatSkycon(skycon) {const map = { CLEAR_DAY: '晴', PARTLY_CLOUDY_DAY: '多云', ... };return map[skycon] || '未知';},// 天气图标类名(如el-icon-sunny)getSkyconIcon(skycon) {return `el-icon-${skycon.toLowerCase()}`;}
    }
    

    四、代理配置(vue.config.js

    为解决跨域问题,配置天气 API 代理:

  • devServer: {proxy: {"/weather-proxy": {target: "https://api.caiyunapp.com", // 目标域名changeOrigin: true,pathRewrite: { "^/weather-proxy": "" }, // 去除路径前缀}}
    }

结果

用户坐标定位的实现

系统通过 IP 地址定位 实现用户坐标获取

前端实现(Vue 组件) 

1. 核心方法 fetchLocation

async fetchLocation() {this.loading = true; // 显示加载状态try {// 调用后端接口获取IP定位信息const response = await getIpLocation(); // 无参数时默认获取客户端IPif (response.code === 200) {const locationData = response.data; // 后端返回的定位数据// 提取经纬度(字符串转浮点数)this.longitude = parseFloat(locationData.point.x); // 经度(x坐标)this.latitude = parseFloat(locationData.point.y); // 纬度(y坐标)// 提取城市名称(优先使用区级,否则取市级)this.cityName = locationData.address_detail.city || '保定市';// 定位成功后请求天气数据await this.$nextTick(); // 确保DOM更新完毕this.fetchWeatherByLocation(); // 调用天气接口} else {throw new Error(response.msg || '定位失败'); // 抛出异常,触发错误处理}} catch (error) {console.error('获取位置失败:', error);this.$message.error('定位失败,使用默认城市天气');this.fetchDefaultWeather(); // 定位失败时使用默认城市(保定)} finally {this.loading = false; // 隐藏加载状态}
}

2. 关键接口调用

定位接口getIpLocation 来自 @/api/system/record.js,封装了后端请求

// api/system/record.js
export function getIpLocation(ip) {return request({url: '/map/ip/location', // 后端接口路径method: 'get',params: { ip } // 可选IP参数,为空时后端自动获取客户端IP});
}

后端实现(Spring Boot 控制器)

1. 百度地图 API 集成

后端通过 百度地图 IP 定位 API 获取坐标,核心代码在 BaiduMapController 中:

@RestController
@RequestMapping("/map/ip")
public class BaiduMapController {private static final String BAIDU_MAP_URL = "https://api.map.baidu.com/location/ip?";private static final String AK = "XXXXXXXX"; // 百度地图开发者密钥(需替换为有效AK)@GetMapping("/location")public AjaxResult getIpLocation(@RequestParam(required = false) String ip) {try {// 构造请求参数Map<String, String> params = new LinkedHashMap<>();params.put("ip", ip != null ? ip : ""); // 传入客户端IP(可选,留空时百度自动获取)params.put("coor", "bd09ll"); // 坐标类型(百度经纬度坐标)params.put("ak", AK); // 开发者密钥// 发送GET请求到百度地图APIString responseJson = sendGetRequest(BAIDU_MAP_URL, params);BaiduIpLocation location = new ObjectMapper().readValue(responseJson, BaiduIpLocation.class);// 检查返回状态if (location.getStatus() != 0) {return AjaxResult.error("定位失败: " + location.getMessage());}// 返回定位结果(经纬度、城市等)return AjaxResult.success("定位成功", location.getContent());} catch (Exception e) {return AjaxResult.error("定位异常: " + e.getMessage());}}// 发送GET请求工具方法private String sendGetRequest(String url, Map<String, String> params) throws IOException {StringBuilder query = new StringBuilder(url);params.forEach((k, v) -> query.append(k).append("=").append(URLEncoder.encode(v, "UTF-8")).append("&"));query.deleteCharAt(query.length() - 1); // 移除最后一个&HttpURLConnection conn = (HttpURLConnection) new URL(query.toString()).openConnection();conn.setRequestMethod("GET");BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));String line;StringBuilder result = new StringBuilder();while ((line = reader.readLine()) != null) {result.append(line);}reader.close();return result.toString();}
}

 后端调用百度地图 IP 定位 API 的核心逻辑,主要分为参数构造、API 请求发送和结果解析三个步骤。

1. 参数构造
// 构造请求参数
Map<String, String> params = new LinkedHashMap<>();
params.put("ip", ip != null ? ip : ""); // 传入客户端IP(可选,留空时百度自动获取)
params.put("coor", "bd09ll"); // 坐标类型(百度经纬度坐标)
params.put("ak", AK); // 开发者密钥
参数说明:
  • ip:需要定位的 IP 地址。
    • 如果为空字符串,百度 API 会自动获取请求来源的 IP 地址进行定位(推荐方式)
    • 如果传入特定 IP(如 "202.108.22.5"),则定位该指定 IP
  • coor:返回的坐标类型
    • "bd09ll" 表示百度经纬度坐标(BD-09 坐标系)
    • 其他可选值:"wgs84"(GPS 原始坐标)、"bd09mc"(百度墨卡托坐标)
  • ak:开发者密钥(Access Key)
    • 用于标识调用者身份,需要在百度地图开放平台申请
    • 申请地址:控制台 | 百度地图开放平台
LinkedHashMap 的作用:
  • 保证参数的顺序,虽然百度 API 通常不依赖参数顺序,但某些场景下顺序可能影响签名计算
  • 与百度官方文档示例保持一致的参数顺序
2. 发送 HTTP 请求
// 发送GET请求到百度地图API
String responseJson = sendGetRequest(BAIDU_MAP_URL, params);
底层实现方法:
private String sendGetRequest(String url, Map<String, String> params) throws IOException {StringBuilder query = new StringBuilder(url);params.forEach((k, v) -> query.append(k).append("=").append(URLEncoder.encode(v, "UTF-8")).append("&"));query.deleteCharAt(query.length() - 1); // 移除最后一个&HttpURLConnection conn = (HttpURLConnection) new URL(query.toString()).openConnection();conn.setRequestMethod("GET");BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));String line;StringBuilder result = new StringBuilder();while ((line = reader.readLine()) != null) {result.append(line);}reader.close();return result.toString();
}
关键步骤解析:
  1. 构建 URL 参数
    • 将参数 Map 转换为 URL 查询字符串(如 "ip=&coor=bd09ll&ak = 你的密钥")
    • 使用 URLEncoder 处理特殊字符(如中文、空格等)
  2. 发送 HTTP 请求
    • 使用 HttpURLConnection 发送 GET 请求
    • 默认使用系统代理,如果需要配置代理可添加以下代码:
      System.setProperty("http.proxyHost", "proxy.example.com");
      System.setProperty("http.proxyPort", "8080");
      
  3. 读取响应
    • 按行读取响应内容并拼接成完整 JSON 字符串
    • 百度 API 返回格式示例:
      {"status": 0,"content": {"address": "北京市海淀区","point": {"x": "116.31104","y": "39.99123"},"address_detail": {"province": "北京市","city": "北京市","district": "海淀区","street": "中关村大街","street_number": "59号"}}
      }
      
3. JSON 解析与对象映射
BaiduIpLocation location = new ObjectMapper().readValue(responseJson, BaiduIpLocation.class);
核心组件:
  • ObjectMapper:Jackson 库的核心类,用于 JSON 与 Java 对象的相互转换
  • BaiduIpLocation:自定义的 Java 类,用于映射百度 API 返回的 JSON 结构
数据模型定义:
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class BaiduIpLocation {private Integer status; // 状态码(0表示成功)private Content content; // 定位结果@Datapublic static class Content {private String address; // 简要地址描述private Point point; // 坐标点private AddressDetail address_detail; // 详细地址@Datapublic static class Point {@JsonProperty("x")private String lng; // 经度@JsonProperty("y")private String lat; // 纬度}@Datapublic static class AddressDetail {private String province; // 省份private String city; // 城市private String district; // 区县private String street; // 街道private String street_number; // 门牌号}}
}
关键注解说明:
  • @Data:Lombok 注解,自动生成 getter、setter、toString 等方法
  • @JsonIgnoreProperties(ignoreUnknown = true):忽略 JSON 中存在但 Java 类中没有的字段
  • @JsonProperty("x"):指定 JSON 字段与 Java 属性的映射关系
4. 定位结果处理

后续代码中会检查状态码并返回结果:

// 检查返回状态
if (location.getStatus() != 0) {return AjaxResult.error("定位失败: " + location.getMessage());
}// 返回定位结果(经纬度、城市等)
return AjaxResult.success("定位成功", location.getContent());
常见状态码说明:
  • 0:成功
  • 1:服务器内部错误
  • 2:请求参数非法
  • 101:AK 参数不存在
  • 102:Mcode 参数不存在(移动端需要)
  • 200:APP 不存在,AK 有误请检查再重试
  • 201:APP 被用户自己禁用
  • 202:APP 被管理员删除
  • 203:IP 校验失败(需要在百度控制台配置白名单)
5. 注意事项
  1. AK 密钥安全

    • 不要将 AK 硬编码在代码中,建议使用配置文件或环境变量管理
    • 生产环境应启用 IP 白名单限制,防止密钥被滥用
  2. 请求频率限制

    • 百度地图 API 免费版有 QPS(每秒请求次数)限制(通常为 1-100 次 / 秒)
    • 超出限制会返回状态码 401,需要进行限流或升级 API 套餐
  3. 坐标转换

    • BD-09 坐标(百度坐标系)与 WGS-84 坐标(GPS 原始坐标)不同
    • 如果需要与其他地图服务(如高德、谷歌)互操作,需要进行坐标转换
    • 百度提供了坐标转换 API:坐标转换 | 百度地图API SDK
  4. 错误处理

    • 网络异常、JSON 解析失败等情况需要捕获并处理
    • 示例代码中使用了 try-catch 包裹整个方法,实际项目中建议使用统一异常处理

2. 定位结果数据结构

百度地图 API 返回的 BaiduIpLocation.Content 包含关键信息:

public class BaiduIpLocation {@Datapublic static class Content {private Point point; // 坐标点private AddressDetail address_detail; // 地址详情@Datapublic static class Point {private String lng; // 经度(x坐标)private String lat; // 纬度(y坐标)}@Datapublic static class AddressDetail {private String city; // 城市(如“北京市”)private String district; // 区(如“朝阳区”)}}
}

关键逻辑说明

1. IP 地址获取方式
  • 自动获取:后端未传入ip参数时,百度地图 API 会基于请求来源自动识别客户端 IP(推荐方式)。
  • 手动传入:如需自定义 IP(如代理场景),前端可通过getIpLocation('目标IP')传入。
2. 坐标转换
  • 百度地图返回的坐标为 BD09LL 格式(百度经纬度坐标),直接用于天气 API(如彩云天气)时需确认是否兼容。
  • 若天气 API 要求其他坐标格式(如 WGS84),需额外添加坐标转换逻辑。
3. 错误处理
  • 定位失败场景
    1. 用户网络限制或 IP 无法解析 → 提示 “定位失败,使用默认城市”。
    2. 百度地图 API 密钥失效 → 检查AK是否有效,重新申请。
  • 默认城市逻辑
    async fetchDefaultWeather() {// 使用保定固定坐标(115.4833, 38.8500)await getWeatherByLocation(115.4833, 38.8500);this.cityName = '保定市'; // 明确显示默认城市
    }
    

相关文章:

  • PHP中文网文章内容提取免费API接口教程
  • Cypress API 中文详解
  • Python基于Django的校园打印预约系统(附源码,文档说明)
  • LangChain实战:MMR和相似性搜索技术应用
  • 01 redis 的环境搭建
  • 第六章 进阶14 项目周报的妙用
  • 湖北理元理律师事务所:债务优化服务的流程透明度建设
  • 基于Matlab实现卫星轨道模拟仿真
  • 抗辐照加固CANFD芯片:以车规级设计提升商业航天系统可靠性
  • MySQL高可用集群
  • 小黑大语言模型应用探索:langchain智能体构造源码demo搭建1(初步流程)
  • QEMU/KVM课程大纲暨学习路线(1)
  • 通义灵码2.5——基于编程智能体开发Wiki多功能搜索引擎
  • 多卡训练核心技术详解
  • 【Go语言】Fyne GUI 库使用指南 (面向有经验开发者)
  • 1,QT的编译教程
  • Go语言结构体:数据组织的艺术
  • STL_stack和queue(deque priority_queue)
  • HTML网页-练习float
  • Java 注解式限流教程(使用 Redis + AOP)
  • 网站开发完以后交付源代码/排名检测
  • 深圳市龙岗区建设局官网网站/百度热搜榜排名今日p2p
  • 接工程平台/商丘seo教程
  • avada主题做网站/河北百度推广电话
  • 央视网商城网站建设/潍坊网站建设咨询
  • 建设网站英语/2023适合小学生的新闻事件