根据经纬度查询天气

文章描述了一个Java服务实现,该服务使用VisualCrossing的天气API来获取并缓存当前天气信息。服务通过经度和纬度作为输入参数,返回天气状况、温度和图标等信息。代码中包含了从Redis缓存获取数据以及处理摄氏度和华氏度转换的逻辑。
摘要由CSDN通过智能技术生成

官网:https://www.visualcrossing.com/

//获取天气
@PostMapping
	@ApiOperation(value = "Visual Crossing 天气查询接口")
	public Result<WeatherResult> getTodayWeatherByVC(@RequestBody CurrentWeatherReq currentWeatherReq) {
		return Result.ok(weatherService.getTodayWeatherByVC(currentWeatherReq));
	}
@Data

//入参
@ApiModel(value = "CurrentWeatherReq", description = "查询实时天气")
public class CurrentWeatherReq {

	@ApiModelProperty(value = "经度")
	private BigDecimal longitude;

	@ApiModelProperty(value = "纬度")
	private BigDecimal latitude;
}
//出参
@Data
@ToString
public class WeatherResult{

	@ApiModelProperty(value = "天气情况")
	private String text;

	@ApiModelProperty(value = "温度")
	private BigDecimal temperature;

	@ApiModelProperty(value = "温度单位")
	private String tempUnit = "℃";

	@ApiModelProperty(value = "天气图标")
	private String icon;
}



package com.autel.cloud.hems.service.impl;

import com.alibaba.fastjson.JSON;
import com.autel.cloud.hems.api.dto.CurrentWeatherReq;
import com.autel.cloud.hems.api.vo.visualcrossing.CurrentConditions;
import com.autel.cloud.hems.api.vo.visualcrossing.VCWeatherSearchResult;
import com.autel.cloud.hems.api.vo.visualcrossing.WeatherResult;
import com.autel.cloud.hems.constant.Constants;
import com.autel.cloud.hems.constant.ErrorCode;
import com.autel.cloud.hems.constant.VCUnitEnum;
import com.autel.cloud.hems.exception.CustomServiceException;
import com.autel.cloud.hems.service.WeatherService;
import com.autel.cloud.hems.utils.LoginUserUtil;
import com.autel.cloud.hems.utils.MapUtils;
import com.autel.cloud.hems.utils.MathematicsUtil;
import com.autel.cloud.hems.utils.RedisUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.CharArrayBuffer;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Objects;

/**
 * @Description 天气查询
 * @Author X22028
 * @DateTime 2023/1/8 14:40
 **/
@Slf4j
@Service
@RefreshScope
public class WeatherServiceImpl implements WeatherService {

	@Value("${weather.visualcrossing.weatherUrl}")
	private String vcWeatherUrl;

	@Value("${weather.visualcrossing.key}")
	private String vcKey;

	@Value("${weather.visualcrossing.cacheTime:600}")
	private Long vcCacheTime;

	@Value("${weather.visualcrossing.fahrenheitCountry}")
	private String fahrenheitCountry;

	@Autowired
	private RedisUtil redisUtil;

	@Override
	public WeatherResult getTodayWeatherByVC(CurrentWeatherReq currentWeatherReq) {

		WeatherResult weatherResult = new WeatherResult();
		VCWeatherSearchResult vcWeatherSearchResult;
		//BigDecimal 转 String
		String longitude = getFormatAddressStr(currentWeatherReq.getLongitude());
		String latitude = getFormatAddressStr(currentWeatherReq.getLatitude());
		//判断温度返回单位(摄氏/华氏)
		boolean changeUnit = needChangeUnit();
        
		String redisKey = String.format("weather:%s:%s", longitude, latitude);
         //redis中有直接返回
		Map<Object, Object> redisMap = redisUtil.hmget(redisKey);
		if (CollectionUtils.isNotEmpty(redisMap)) {
			log.info("redis get [{},{}]", longitude, latitude);
			weatherResult = JSON.parseObject(JSON.toJSONString(redisMap), WeatherResult.class);
			checkAndChangeUnit(weatherResult, changeUnit);
			return weatherResult;
		}
         //查询
		vcWeatherSearchResult = getVCWeatherSearchResult(longitude, latitude);

		if (Objects.isNull(vcWeatherSearchResult)) {
			return weatherResult;
		}
        //转换对象
		convertWeatherResult(vcWeatherSearchResult, weatherResult);
        //存入redis 设置过期时间
		redisUtil.hmset(redisKey, MapUtils.objectToMap(weatherResult), vcCacheTime);
		log.info("redis weather data set [{},{}] ", longitude, latitude);
        //转换温度返回单位
		checkAndChangeUnit(weatherResult, changeUnit);

		return weatherResult;
	}

	private VCWeatherSearchResult getVCWeatherSearchResult(String longitude, String latitude) {
		String weatherUrl = vcWeatherUrl
				.replace("{apiKey}", vcKey)
				.replace("{lon}", longitude)
				.replace("{lat}", latitude);

		log.info("visual crossing weather url is ---{}", weatherUrl);
		HttpGet weatherGet = new HttpGet(weatherUrl);
		CloseableHttpResponse response;
		HttpEntity entity;
		String result;
		try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
			response = httpClient.execute(weatherGet);
			entity = response.getEntity();
			result = entityToString(entity);
			log.info("weather api response is --- {}", result);
			return JSON.parseObject(result, VCWeatherSearchResult.class);
		} catch (IOException e) {
			log.error("weather url {} get data error!", weatherUrl);
			throw new CustomServiceException(ErrorCode.FAIL);
		}
	}

	private void convertWeatherResult(VCWeatherSearchResult vcWeatherSearchResult, WeatherResult weatherResult) {
		CurrentConditions conditions = vcWeatherSearchResult.getCurrentConditions();
		if (Objects.nonNull(conditions)) {
			weatherResult.setIcon(conditions.getIcon());
			weatherResult.setTemperature(new BigDecimal(conditions.getTemp()));
			weatherResult.setText(conditions.getConditions());
		}
	}

	private boolean needChangeUnit() {
		String userCountryCode = LoginUserUtil.getUserCountryCode();
		log.info("userCountryCode------>{}", userCountryCode);
		if (StringUtils.isNotBlank(userCountryCode)) {
			String[] countryCode = fahrenheitCountry.split(Constants.COMMA);
			for (String s : countryCode) {
				if (userCountryCode.equals(s)) {
					return true;
				}
			}
		}

		return false;
	}

	private String getFormatAddressStr(BigDecimal value) {
		return MathematicsUtil.getBigDecimalRoundDownValue(value, Constants.DEFAULT_SCALE).toString();
	}

	private void checkAndChangeUnit(WeatherResult weatherResult, boolean changeUnit) {
		if (changeUnit) {
			changeTemperature(weatherResult);
			weatherResult.setTempUnit(VCUnitEnum.US.getUnit());
		}
	}

	private void changeTemperature(WeatherResult weatherResult) {
		BigDecimal temperature = weatherResult.getTemperature();
		temperature = MathematicsUtil.getBigDecimalValue(temperature.multiply(new BigDecimal("1.8")).add(new BigDecimal("32")), 2);
		weatherResult.setTemperature(temperature);
	}

	private String entityToString(HttpEntity entity) throws IOException {
		String result = null;
		if (entity != null) {
			long lenth = entity.getContentLength();
			if (lenth != -1 && lenth < 2048) {
				result = EntityUtils.toString(entity, StandardCharsets.UTF_8);
			} else {
				InputStreamReader reader1 = new InputStreamReader(entity.getContent(), StandardCharsets.UTF_8);
				CharArrayBuffer buffer = new CharArrayBuffer(2048);
				char[] tmp = new char[1024];
				int l;
				while ((l = reader1.read(tmp)) != -1) {
					buffer.append(tmp, 0, l);
				}
				result = buffer.toString();
			}
		}
		return result;
	}
}


//请求官网返回对象
package com.autel.cloud.hems.api.vo.visualcrossing;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.List;

@Data
public class VCWeatherSearchResult {

	@ApiModelProperty(value = "所在城市名")
	private String address;

	@ApiModelProperty(value = "所在地区名")
	private String resolvedAddress;

	@ApiModelProperty(value = "当前温度")
	private CurrentConditions currentConditions;

	@ApiModelProperty(value = "天气文本")
	private List<Day> days;
}

package com.autel.cloud.hems.api.vo.visualcrossing;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

/**
 * @Description TODO
 * @Author X22028
 * @DateTime 2023/1/14 16:20
 **/
@Data
public class CurrentConditions {

	@ApiModelProperty(value = "时间")
	String datetime;
	@ApiModelProperty(value = "时间戳")
	String datetimeEpoch;
	@ApiModelProperty(value = "温度")
	String temp;
	@ApiModelProperty(value = "体感温度")
	String feelslike;
	@ApiModelProperty(value = "相对湿度")
	String humidity;
	@ApiModelProperty(value = "所在城市名")
	String dew;
	@ApiModelProperty(value = "降雨量")
	String precip;
	@ApiModelProperty(value = "所在城市名")
	String precipprob;
	@ApiModelProperty(value = "降雪量")
	String snow;
	@ApiModelProperty(value = "雪深")
	String snowdepth;
	@ApiModelProperty(value = "所在城市名")
	String preciptype;
	@ApiModelProperty(value = "所在城市名")
	String windgust;
	@ApiModelProperty(value = "风速")
	String windspeed;
	@ApiModelProperty(value = "风向")
	String winddir;
	@ApiModelProperty(value = "压强")
	String pressure;
	@ApiModelProperty(value = "能见度")
	String visibility;
	@ApiModelProperty(value = "云量")
	String cloudcover;
	@ApiModelProperty(value = "所在城市名")
	String solarradiation;
	@ApiModelProperty(value = "太阳能")
	String solarenergy;
	@ApiModelProperty(value = "紫外线强度")
	String uvindex;
	@ApiModelProperty(value = "天气情况文本")
	String conditions;
	@ApiModelProperty(value = "天气图标")
	String icon;
}


#nacos配置
weather:
  visualcrossing:
    key: UCSRD3H7BX7UHPK8DBBKQV6CL
    weatherUrl: https://weather.visualcrossing.com/VisualCrossingWebServices/rest/services/timeline/{lat},{lon}/today?key={apiKey}&contentType=json&lang=en&include=current&unitGroup=metric
    cacheTime: 600
    fahrenheitCountry: US

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值