HarmonyOS Next调用高德api获取实时天气,api接口

需要修改的文件是:\springboot\src\main\java\com\example\controller的WeatherController.java文件

javascript 复制代码
//WeatherController.java
@RestController
@RequestMapping("/weather")
public class WeatherController {

    @Value("${amap.weather.key}") // 从配置文件读取 key
    private String amapKey;

    // 简化:直接传 adcode(推荐)
    @GetMapping("/getWeather")
    public ResponseEntity<String> getWeather(
            @RequestParam String city,      // 这里建议传 adcode,如 "310000"
            @RequestParam String key) {     // 或者直接用配置的 key,不从前端传

        // 安全起见:不要让前端传 key!应由后端固定使用自己的 key
        String url = "https://restapi.amap.com/v3/weather/weatherInfo" +
                     "?key=" + amapKey +
                     "&city=" + city +
                     "&extensions=base";

        try {
            RestTemplate restTemplate = new RestTemplate();
            String response = restTemplate.getForObject(url, String.class);
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            return ResponseEntity.status(500).body("{\"code\":\"500\",\"msg\":\"调用高德API失败\"}");
        }
    }
}

在运行java -jar qicai-1.0.jar之后访问http://localhost:9090/swagger-ui.html#/weather-controller

得到如下网站界面:

自行申请高德地图api之后填入key,填入city的代号,可以测试此处weather的api是否可用,此处显示"请求成功",在鸿蒙应用中才会显示相关的天气信息。

得到的结果如下:

当然这其中也要先打开虚拟器中的位置:

细节代码如下:

获取天气的WeatherDetailVO类:

TypeScript 复制代码
// WeatherDetailVO.ets
export class WeatherDetailVO {
  daytemp: string // 最高温度
  nighttemp: string // 最低温度
  temp: string // 实时温度
  wind: string // 风向
  power: string // 风力
  weather: string // 天气描述

  constructor(daytemp?: string, nighttemp?: string, temp?: string, wind?: string, power?: string, weather?: string) {
    this.daytemp = daytemp ?? ''
    this.nighttemp = nighttemp ?? ''
    this.temp = temp ?? ''
    this.wind = wind ?? ''
    this.power = power ?? ''
    this.weather = weather ?? ''
  }

}

indexweather.ets如下:

TypeScript 复制代码
import { STATUS_BAR_HEIGHT } from '../../entryability/EntryAbility'
import { BaseUtils } from '../../utils/BaseUtils'
import { geoLocationManager } from '@kit.LocationKit';
import { promptAction } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
import { HttpUtil } from '../../utils/http/HttpUtil';
import { Urls } from '../../utils/http/Urls';
import { WeatherDetailVO } from '../../vo/WeatherDetailVO';

@Preview
@Component
export struct IndexWeatherPage {

  @State bgImg: Resource = $r('app.media.bg_weather_qing')

  @State isRefreshing: boolean = false

  @State animationStatus: AnimationStatus = AnimationStatus.Initial

  @State address: string = '定位中'
  // 定位区域编码
  @State areaCode: string = '110000'
  // 天气详情
  @State weather: WeatherDetailVO = new WeatherDetailVO()

  aboutToAppear(): void {
    try {
      // 由于模拟器没无法获取定位,会出现错误,导致APP崩溃。
      // 所以需要使用try...catch语句
      this.getLocationAndWeather()
    } catch (e) {
      promptAction.showToast({
        message: JSON.stringify(e),
        duration: 2000
      });
    }
  }

  // 获取定位和天气
  getLocationAndWeather() {
    let request: geoLocationManager.SingleLocationRequest = {
      locatingPriority: 0x502,
      locatingTimeoutMs: 1000 * 10
    };
    geoLocationManager.getCurrentLocation(request).then((location: geoLocationManager.Location) => {
      geoLocationManager.getAddressesFromLocation({latitude: location.latitude, longitude: location.longitude})
        .then((addressArray: Array<geoLocationManager.GeoAddress>) => {
          this.address = addressArray[0].placeName ?? addressArray[0].locality ?? ''
          this.address = this.address.replace(addressArray[0].administrativeArea!,  "")
            .replace(addressArray[0].subAdministrativeArea!, "")// 将省份替换成空字符串
          console.log('定位地址', JSON.stringify(addressArray))
          // 获取天气
          //let localCode = '330602'
          // 处理天气接口需要的6位地理编码
          let localCode = addressArray[0]?.descriptions![1].substring(0, 6) ?? ''
          this.getWeather(localCode)
        })

    }).catch((err: BusinessError) => {
      promptAction.showToast({
        message: JSON.stringify(err),
        duration: 2000
      });
    });
  }

  /**
   * 获取天气详情
   */
  async getWeather(code: string) {
    let params: Record<string, string> = {
      'key': '********', //此处更换成自己的高德api
      'city': code
    }
    let result = await HttpUtil.get(Urls.GET_WEATHER, params)
    this.isRefreshing = false
    if (result.success) {
      this.weather = result.toObject<WeatherDetailVO>()
    } else {
      promptAction.showToast({message: '天气获取失败'})
    }
  }

/*  *//**
   * 获取天气详情
   * @param local 地址代码
   *//*
  async getWeather(local: string) {
    let params: Record<string, string> = { 'local': local }
    let result = await HttpUtil.get(Urls.GET_WEATHER, params)
    this.isRefreshing = false
    if (result.success) {
      this.weather = result.toObject<WeatherDetailVO>()
    } else {
      promptAction.showToast({message: '天气获取失败'})
    }
  }*/

  @Builder
  customRefreshComponent() {
    Stack() {
      Row() {
        LoadingProgress().height(32)
        Text("刷新中...").fontSize(16).margin({left:20})
      }
      .alignItems(VerticalAlign.Center)
    }
    .align(Alignment.Center)
    .clip(true)
    .constraintSize({minHeight:32}) // 设置最小高度约束保证自定义组件高度随刷新区域高度变化时自定义组件高度不会低于minHeight
    .width("100%")
  }

  build() {
    Column() {
      Refresh({refreshing: $$this.isRefreshing, builder: this.customRefreshComponent()}) {
        Column({space: 10}) {
          Row({space: 10}) {
            Text(this.address)
              .fontSize(18).fontColor(Color.White)
            SymbolGlyph($r('sys.symbol.location_up_fill'))
                .fontColor([Color.White])
          }.justifyContent(FlexAlign.Start)
          Blank().height(100)
          Row({space: 10}) {
            Text(`${this.weather.temp}℃`)
              .fontSize(90)
              .fontWeight(FontWeight.Bold)
              .fontColor(Color.White)

            Text(`${this.weather.weather}`)
              .fontSize(30)
              .fontColor(Color.White)
          }
          .alignItems(VerticalAlign.Bottom)
          Text(`${this.weather.wind} ${this.weather.power},温度${this.weather.nighttemp}~${this.weather.daytemp} ℃`)
            .fontSize(24)
            .fontColor(Color.White)
            .textOverflow({ overflow: TextOverflow.MARQUEE })
            .width(200)

          Row() {
            Image($r('app.media.gif_cartoon_bird'))
              .size({width: 160, height: 160})

            Button() {
              Row() {
                ImageAnimator()
                  .images([
                    {
                      src: $r('app.media.ic_wave3'),
                      duration: 500
                    },
                    {
                      src: $r('app.media.ic_wave1'),
                      duration: 500
                    },
                    {
                      src: $r('app.media.ic_wave2'),
                      duration: 500
                    },
                  ])
                  .state(this.animationStatus)
                  .width(30)
                  .height(30)
                  .iterations(-1)
              }
            }.onClick(async () => {
              if (this.animationStatus == AnimationStatus.Initial) {
                this.animationStatus = AnimationStatus.Running
                let avPlayer = await BaseUtils.playAudio(getContext(this), 'weather_bg_music.mp3')
                setTimeout(() => {
                  BaseUtils.say(`你好,七彩天气为您播报。当前,${this.address},${this.weather.weather},实时温度 ${this.weather.temp}摄氏度,${this.weather.wind} ${this.weather.power}。今天,最高温度${this.weather.daytemp}度,最低温度${this.weather.nighttemp}度。`, (requestId) => {
                    setTimeout(() => {
                      avPlayer.stop()
                      this.animationStatus = AnimationStatus.Initial
                    }, 2000)
                  })
                }, 5000)
              }
            })
            .padding(5)
            .backgroundColor(Color.White)
            .opacity(0.6)
          }.alignSelf(ItemAlign.End)
        }
        .alignItems(HorizontalAlign.Start)
        .width('100%')
      }
      .onStateChange((refreshStatus: RefreshStatus) => {
        console.info('Refresh onStatueChange state is ' + refreshStatus)
      })
      .onOffsetChange((value: number) => {
        console.info('Refresh onOffsetChange offset:' + value)
      })
      .onRefreshing(async () => {
        try {
          await this.getLocationAndWeather()
        } catch (e) {

        }
      })
      .refreshOffset(64)
      .pullToRefresh(true)

    }
    .padding({top: STATUS_BAR_HEIGHT, left: 20, right: 20})
    .backgroundImage(this.bgImg)
    .backgroundImageSize(ImageSize.FILL)
    .size({width: '100%', height: '100%'})
  }
}
相关推荐
爬山算法2 小时前
Netty(25)Netty的序列化和反序列化机制是什么?
开发语言·python
C+++Python2 小时前
Java 锁机制
java·开发语言
未知数Tel2 小时前
Dify离线安装插件
python·阿里云·pip·dify
龘龍龙2 小时前
Python基础学习(六)
开发语言·python·学习
未来之窗软件服务2 小时前
幽冥大陆(五十八)php1024位密码生成—东方仙盟筑基期
开发语言·算法·仙盟创梦ide·东方仙盟
热爱专研AI的学妹2 小时前
【搭建工作流教程】使用数眼智能 API 搭建 AI 智能体工作流教程(含可视化流程图)
大数据·数据库·人工智能·python·ai·语言模型·流程图
databook2 小时前
拒绝“凭感觉”:用回归分析看透数据背后的秘密
python·数据挖掘·数据分析
刺客xs2 小时前
Qt ----- QT线程
开发语言·qt
Psycho_MrZhang2 小时前
Flask 设计思想总结
后端·python·flask