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%'})
  }
}
相关推荐
weixin_440730502 分钟前
内置函数、json文本、pickle二进制
开发语言·python·json
殷色玫瑰9 分钟前
C++ string类详解:常用接口、字符串操作与模拟实现
java·linux·c语言·开发语言·数据结构·c++
李游Leo12 分钟前
HarmonyOS 7 + Spatial Recon Kit-C++:3DGS 高斯参数的非有限值隔离与可渲染性门禁【鸿蒙心迹】
开发语言·c++·3d·harmonyos
熊猫钓鱼>_>24 分钟前
Kotlin Multiplatform for OpenHarmony 实战:为 MVIKotlin 实现单向数据流适配
华为·ai编程·鸿蒙·openharmony·适配·数据流·mvkotlin
计算机毕业编程指导师36 分钟前
Python大数据毕设:基于Hadoop的病毒式社交媒体趋势和参与度分析系统怎么做 源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习
大数据·hadoop·python·计算机·毕业设计·课程设计·社交媒体
计算机毕业编程指导师39 分钟前
【计算机毕设选题推荐】基于Spark与Hadoop的AI就业收入区域差异分析系统 源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习 深度学习
大数据·python·数据分析·spark·毕业设计·课程设计·ai就业收入
小猴子爱上树43 分钟前
跨马翻译:批量图片翻译与视频字幕、智能抠图一站式在线图片翻译工具
大数据·人工智能·python·音视频
时间的拾荒人1 小时前
Qt 文件操作详解:从基础类到读写实战
开发语言·qt·面试
Wang's Blog1 小时前
Java 项目实战: 外卖平台优化-YApi接口管理平台与文档导入导出
java·开发语言·yapi