1.rquest
import lombok.Data;
@Data
public class WeatherRequest {
private String lang;
private String lat;
private String lon;
private String city;
}
2.Controller
import com.engwe.app.api.request.weather.WeatherRequest;
import com.engwe.app.trigger.controller.http.weather.service.WeatherService;
import com.engwe.common.frame.types.dto.R;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Map;
@RestController
@RequestMapping("/api/app/weather")
@Validated
public class WeatherController {
@Resource
private WeatherService weatherService;
@PostMapping("/index")
public R<Map<String, Object>> index(@RequestBody @Valid WeatherRequest request) {
return R.ok(weatherService.weather(request));
}
}
3 service
package com.engwe.app.trigger.controller.http.weather.service;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.signers.JWTSigner;
import cn.hutool.jwt.signers.JWTSignerUtil;
import com.engwe.app.api.IWeatherApi;
import com.engwe.app.api.request.weather.WeatherRequest;
import com.engwe.app.trigger.controller.http.weather.properties.WeatherProperties;
import com.engwe.common.redis.utils.RedisUtils;
import com.engwe.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.Duration;
import java.util.*;
@Slf4j
@Service
public class WeatherService {
@Resource
private WeatherProperties weatherProperties;
@Resource
private IWeatherApi weatherApi;
public Map<String, Object> weather(WeatherRequest request) {
try {
String cityWeatherCacheKey = StringUtils.joinWith(":", "weather", request.getCity());
Map<String, Object> cacheObject = getWeatherFromCache(cityWeatherCacheKey);
if (Objects.nonNull(cacheObject) && !cacheObject.isEmpty()) {
return cacheObject;
}
String token = getToken();
Map<String, String> requestParams = new HashMap<>();
requestParams.put("countryCode", request.getCity());
requestParams.put("dataSets", "currentWeather,forecastHourly");
cacheObject = weatherApi.getWeatherByLocation("Bearer " + token, request.getLang(), request.getLat(), request.getLon(), requestParams);
RedisUtils.setCacheObject(cityWeatherCacheKey, cacheObject, Duration.ofSeconds(weatherProperties.getTokenTTL() - 60));
return cacheObject;
} catch (Exception e) {
log.error("get weather info error", e);
return null;
}
}
private Map<String, Object> getWeatherFromCache(String cityWeatherCacheKey) {
Object cacheObject = RedisUtils.getCacheObject(cityWeatherCacheKey);
return Objects.nonNull(cacheObject) ? (Map<String, Object>) cacheObject : null;
}
private String getToken() throws Exception {
final String cacheKey = StringUtils.joinWith(":", "weather", "token");
Object cacheObject = RedisUtils.getCacheObject(cacheKey);
if (Objects.isNull(cacheObject)) {
long currentTimeMillis = System.currentTimeMillis();
Date now = new Date(currentTimeMillis);
Date expiration = new Date(currentTimeMillis + weatherProperties.getTokenTTL() * 1000L);
byte[] keyBytes = Base64.getDecoder().decode(weatherProperties.getKey());
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
JWTSigner signer = JWTSignerUtil.createSigner("ES256", privateKey);
Map<String, Object> header = new HashMap<>();
header.put("alg", "ES256");
header.put("kid", weatherProperties.getKeyId());
Map<String, Object> payload = new HashMap<>();
payload.put("iss", weatherProperties.getTeamId());
payload.put("sub", weatherProperties.getBundleId());
payload.put("iat", now.getTime() / 1000);
payload.put("exp", expiration.getTime() / 1000);
String token = JWTUtil.createToken(header, payload, signer);
RedisUtils.setCacheObject(cacheKey, token, Duration.ofSeconds(weatherProperties.getTokenTTL() - 60));
return token;
}
return (String) cacheObject;
}
}
4.WeatherProperties
package com.engwe.app.trigger.controller.http.weather.properties;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "weather.auth.config")
@Getter
@Setter
public class WeatherProperties {
private String key;
private String keyId;
private String teamId;
private String bundleId;
private Integer tokenTTL;
private String languageCode;
private String timezone;
private String weatherEndpoint;
private String availabilityEndpoint;
}
5.nacos配置
拥有自己的苹果账号去苹果第三方的那个网址获取key这些东西
weather:
auth:
config:
key: MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgHtq+c5C71dUVFQc5RWHzRRxjRqmnxpQ45pMakniZ2uugCgYIKoZIzj0DAQehRANCAAQkGzFLpI+WYcI13yunuPu1qQHBospCyVlxKaWKomCNli9ncA3HFr65qccqwk11AUPIetd5K0hh4MoNANRE94hH
keyId: JC75LXPCZ5
teamId: M8PTMPM89H
bundleId: com.engwe.app
tokenTTL: 3600
languageCode: en
timezone: Asia/Shanghai
domain: https://weatherkit.apple.com
weatherEndpoint: /api/v1/weather
availabilityEndpoint: /api/v1/availability
6 IWeatherApi
import feign.Headers;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Map;
@FeignClient(name = "weather-service", url = "${weather.auth.config.domain}")
public interface IWeatherApi {
@GetMapping("${weather.auth.config.weatherEndpoint}/{lang}/{lat}/{lon}")
Map<String, Object> getWeatherByLocation(@RequestHeader("Authorization") String token, @PathVariable("lang") String lang, @PathVariable("lat") String lat, @PathVariable("lon") String lon, @RequestParam Map<String, String> params);
}