fix (farm): 高德天气

- 获取天气信息
This commit is contained in:
达富斌
2025-10-13 14:52:20 +08:00
parent 4ff2b18aa2
commit 0470e0a6e8
18 changed files with 501 additions and 41 deletions

View File

@@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.farm.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* @description:
* @author: binda
* @date: 2025/10/11 20:45
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "weather")
public class WeatherConf {
private String webkey;
private String url1;
private String url2;
}

View File

@@ -180,8 +180,11 @@ public class DigitalCockpitController {
@GetMapping("/device-info/monitor-data")
@Operation(summary = "监测数据")
@Parameter(name = "baseId", description = "基地ID", required = true)
public CommonResult<String> getMonitoringData(@RequestParam("baseId") String baseId) {
return success("暂时不做");
public CommonResult<DeviceMonitorDataRespVO> getMonitoringData(@RequestParam("baseId") String baseId) {
DeviceMonitorDataRespVO res = new DeviceMonitorDataRespVO();
return success(res);
}
@GetMapping("/species/get")

View File

@@ -0,0 +1,55 @@
package cn.iocoder.yudao.module.farm.controller.admin.digitalcockpit.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @description: TODO
* @author: binda
* @date: 2025/10/11 19:55
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DeviceMonitorDataRespVO {
private Soil soilInfo;
private Wf wfInfo;
private VideoMonitor videoMonitorInfo;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Soil {
private String deviceTypeName;
private List<Row> data;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Wf {
private String deviceTypeName;
private List<Row> data;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class VideoMonitor {
private String deviceTypeName;
private List<Row> data;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Row {
private String name;
private String status;
}
}

View File

@@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.farm.controller.admin.home.vo.BaseNameVO;
import cn.iocoder.yudao.module.farm.controller.admin.home.vo.HomeInfo;
import cn.iocoder.yudao.module.farm.controller.admin.home.vo.QrDetailsRespVO;
import cn.iocoder.yudao.module.farm.service.home.HomeService;
import cn.iocoder.yudao.module.farm.utils.WeatherUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -31,6 +32,8 @@ public class HomeController {
@Resource
private HomeService homeService;
@Resource
private WeatherUtil weatherUtil;
@Operation(summary = "农场首页")
@GetMapping("")
@@ -45,11 +48,28 @@ public class HomeController {
return success(homeService.getBaseNameList());
}
@Operation(summary = "农场首页-天气信息-获取天气信息")
@GetMapping("/weather/{lng}/{lat}")
public CommonResult<String> getBaseNameList(@PathVariable("lng") String lng,
@PathVariable("lat") String lat) {
String res = weatherUtil.getWeatherInfo(lng, lat);
return success(res);
}
// @Operation(summary = "农场首页-天气信息-获取天气信息")
// @GetMapping("/weather/{city}")
// public CommonResult<String> getBaseNameList(@PathVariable("city") String city) {
//
// return success("天气信息!");
// }
@PermitAll
@Operation(summary = "农场首页-扫描二维码")
@GetMapping("/scan-qr")
@Parameter(name = "baseId", description = "基地ID")
public CommonResult<QrDetailsRespVO> scanQrCodes(@RequestParam("baseId") String baseId) {
// TODO: 2025/10/11 待实现
QrDetailsRespVO mockData = new QrDetailsRespVO();
// 设置基地基本信息

View File

@@ -0,0 +1,142 @@
package cn.iocoder.yudao.module.farm.controller.admin.home.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 逆地理编码响应数据封装类
*/
@Data
public class GeocodeResponse {
@JsonProperty("status")
private String status;
@JsonProperty("regeocode")
private Regeocode regeocode;
@JsonProperty("info")
private String info;
@JsonProperty("infocode")
private String infocode;
/**
* 判断请求是否成功
* @return true-成功, false-失败
*/
public boolean isSuccess() {
return "1".equals(this.status);
}
/**
* 获取adcode
* @return adcode
*/
public String getAdcode() {
if (regeocode != null && regeocode.getAddressComponent() != null) {
return regeocode.getAddressComponent().getAdcode();
}
return null;
}
/**
* 获取格式化地址
* @return 格式化地址
*/
public String getFormattedAddress() {
if (regeocode != null) {
return regeocode.getFormattedAddress();
}
return null;
}
@Data
public static class Regeocode {
@JsonProperty("addressComponent")
private AddressComponent addressComponent;
@JsonProperty("formatted_address")
private String formattedAddress;
}
@Data
public static class AddressComponent {
@JsonProperty("city")
private String city;
@JsonProperty("province")
private String province;
@JsonProperty("adcode")
private String adcode;
@JsonProperty("district")
private String district;
@JsonProperty("towncode")
private String towncode;
@JsonProperty("streetNumber")
private StreetNumber streetNumber;
@JsonProperty("country")
private String country;
@JsonProperty("township")
private String township;
@JsonProperty("businessAreas")
private Object businessAreas;
@JsonProperty("building")
private Building building;
@JsonProperty("neighborhood")
private Neighborhood neighborhood;
@JsonProperty("citycode")
private String citycode;
}
@Data
public static class StreetNumber {
@JsonProperty("number")
private String number;
@JsonProperty("location")
private String location;
@JsonProperty("direction")
private String direction;
@JsonProperty("distance")
private String distance;
@JsonProperty("street")
private String street;
}
@Data
public static class Building {
@JsonProperty("name")
private Object name;
@JsonProperty("type")
private Object type;
}
@Data
public static class Neighborhood {
@JsonProperty("name")
private Object name;
@JsonProperty("type")
private Object type;
}
}

View File

@@ -0,0 +1,41 @@
package cn.iocoder.yudao.module.farm.controller.admin.managementcenter.farmnews;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.farm.controller.admin.managementcenter.farmnews.vo.FarmInformationPageRespVO;
import cn.iocoder.yudao.module.farm.service.farminformation.FarmInformationService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @description:
* @author: binda
* @date: 2025/10/13 10:23
*/
@Tag(name = "管理中心 - 农业资讯")
@RestController
@RequestMapping("/farm/news")
@Validated
public class FarmInformationController {
private final FarmInformationService farmInformationService;
public FarmInformationController(FarmInformationService farmInformationService) {
this.farmInformationService = farmInformationService;
}
@GetMapping("/page")
@Operation(summary = "资讯信息-分页")
public CommonResult<PageResult<FarmInformationPageRespVO>> pageInfo() {
PageResult<FarmInformationPageRespVO> res = null;
return CommonResult.success(res);
}
}

View File

@@ -0,0 +1,16 @@
package cn.iocoder.yudao.module.farm.controller.admin.managementcenter.farmnews.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import lombok.Data;
/**
* @description: TODO
* @author: binda
* @date: 2025/10/13 10:58
*/
@Data
public class FarmInformationPageReqVO extends PageParam {
private String id;
}

View File

@@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.farm.controller.admin.wx.vo;
package cn.iocoder.yudao.module.farm.controller.admin.managementcenter.farmnews.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
@@ -13,7 +13,7 @@ import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FarmInformationRespVO {
public class FarmInformationPageRespVO {
@Schema(description = "资讯类型 (1: 要闻; 99:其他)")
private String infoType;

View File

@@ -30,7 +30,7 @@ public class PersonnelManagementSaveReqVO {
@Schema(description = "头像集合")
private List<String> pictureList;
@Schema(description = "0=启用,1=停用", example = "2")
@Schema(description = "0=启用,1=停用")
private Integer accountStatus;
@Schema(description = "基地id", example = "30077")

View File

@@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.farm.controller.admin.wx;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.farm.controller.admin.api.vo.DeviceStateRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.managementcenter.farmnews.vo.FarmInformationPageReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.managementcenter.farmnews.vo.FarmInformationPageRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.wx.vo.*;
import cn.iocoder.yudao.module.farm.dal.dataobject.baseinfo.BaseInfoDO;
import cn.iocoder.yudao.module.farm.dal.dataobject.deviceinfo.DeviceInfoDO;
@@ -65,8 +67,8 @@ public class WxController {
@Operation(summary = "农业资讯")
@GetMapping("/farm-information/page")
public CommonResult<PageResult<FarmInformationRespVO>> getFarmInformation(@Valid FarmInformationReqVO req) {
PageResult<FarmInformationRespVO> result = farmInformationService.getFarmInformationPage(req);
public CommonResult<PageResult<FarmInformationPageRespVO>> getFarmInformation(@Valid FarmInformationPageReqVO req) {
PageResult<FarmInformationPageRespVO> result = farmInformationService.getFarmInformationPage(req);
return CommonResult.success(result);
}

View File

@@ -1,18 +0,0 @@
package cn.iocoder.yudao.module.farm.controller.admin.wx.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description:
* @author: binda
* @date: 2025/9/25 17:33
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FarmInformationReqVO extends PageParam {
private String id;
}

View File

@@ -16,6 +16,7 @@ public class DeviceConf {
private FourSituations fourSituations;
private WaterAndFertilizer waterAndFertilizer;
private VideoMonitor videoMonitor;
@Data
public static class FourSituations {
@@ -60,5 +61,12 @@ public class DeviceConf {
private String url4; // 更新设备属性 POST
}
@Data
public static class VideoMonitor{
private String url1;
private String state1;
private String url2;
private String state2;
}
}

View File

@@ -94,7 +94,7 @@ public abstract class TokenCacheService {
/**
* 定期清除过期token
*/
@Scheduled(fixedRate = 1000 * 60 * 60 ) // 每1小时执行一次
@Scheduled(fixedRate = 1000 * 60 * 6 ) // 每6分钟执行一次
public void cleanupExpiredTokens() {
long currentTime = System.currentTimeMillis();

View File

@@ -1,8 +1,8 @@
package cn.iocoder.yudao.module.farm.service.farminformation;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.farm.controller.admin.wx.vo.FarmInformationReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.wx.vo.FarmInformationRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.managementcenter.farmnews.vo.FarmInformationPageReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.managementcenter.farmnews.vo.FarmInformationPageRespVO;
/**
* @description:
@@ -10,5 +10,6 @@ import cn.iocoder.yudao.module.farm.controller.admin.wx.vo.FarmInformationRespVO
* @date: 2025/9/25 17:27
*/
public interface FarmInformationService {
PageResult<FarmInformationRespVO> getFarmInformationPage(FarmInformationReqVO req);
PageResult<FarmInformationPageRespVO> getFarmInformationPage(FarmInformationPageReqVO req);
}

View File

@@ -1,8 +1,9 @@
package cn.iocoder.yudao.module.farm.service.farminformation;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.farm.controller.admin.wx.vo.FarmInformationReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.wx.vo.FarmInformationRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.managementcenter.farmnews.vo.FarmInformationPageReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.managementcenter.farmnews.vo.FarmInformationPageRespVO;
import cn.iocoder.yudao.module.farm.dal.mysql.farminformation.FarmInformationMapper;
import org.springframework.stereotype.Service;
/**
@@ -13,10 +14,18 @@ import org.springframework.stereotype.Service;
@Service
public class FarmInformationServiceImpl implements FarmInformationService{
private final FarmInformationMapper farmInformationMapper;
public FarmInformationServiceImpl(FarmInformationMapper farmInformationMapper) {
this.farmInformationMapper = farmInformationMapper;
}
@Override
public PageResult<FarmInformationRespVO> getFarmInformationPage(FarmInformationReqVO req) {
public PageResult<FarmInformationPageRespVO> getFarmInformationPage(FarmInformationPageReqVO req) {
return null;
}
}

View File

@@ -0,0 +1,147 @@
package cn.iocoder.yudao.module.farm.utils;
import cn.iocoder.yudao.module.farm.config.WeatherConf;
import cn.iocoder.yudao.module.farm.controller.admin.home.vo.GeocodeResponse;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.text.MessageFormat;
/**
* @description: 高德天气
* @date: 2025/10/13 11:34
*/
@Slf4j
@Component
public class WeatherUtil {
private final WeatherConf weatherConf;
private final RestTemplate restTemplate;
public WeatherUtil(WeatherConf weatherConf, RestTemplate restTemplate) {
this.weatherConf = weatherConf;
this.restTemplate = restTemplate;
}
private static final ObjectMapper objectMapper = new ObjectMapper();
/**
* 根据经纬度获取天气信息
* @param lng 经度
* @param lat 纬度
* @return 天气信息JSON字符串
*/
public String getWeatherInfo(String lng, String lat) {
try {
// 1. 逆地理编码获取adcode
String adcode = getAdcodeByLocation(lng, lat);
if (adcode == null || adcode.isEmpty()) {
log.error("根据经纬度获取adcode失败: lng={}, lat={}", lng, lat);
return buildErrorResult("获取地区编码失败");
}
// 2. 根据adcode获取天气信息
return getWeatherByAdcode(adcode);
} catch (Exception e) {
log.error("获取天气信息异常: lng={}, lat={}, error={}", lng, lat, e.getMessage(), e);
return buildErrorResult("获取天气信息异常: " + e.getMessage());
}
}
/**
* 根据经纬度获取地区编码(adcode)
* @param lng 经度
* @param lat 纬度
* @return adcode
*/
private String getAdcodeByLocation(String lng, String lat) {
String webKey = weatherConf.getWebkey();
String url_1 = weatherConf.getUrl1();
String url = MessageFormat.format(url_1, lng, lat, webKey);
try {
log.info("调用逆地理编码API: {}", url.replace(webKey, "***"));
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
if (response.getStatusCode().is2xxSuccessful()) {
String result = response.getBody();
log.debug("逆地理编码响应: {}", result);
// 解析响应数据 - 使用新的GeocodeResponse类
GeocodeResponse geocodeResponse = objectMapper.readValue(result, GeocodeResponse.class);
if (geocodeResponse.isSuccess() && geocodeResponse.getAdcode() != null) {
return geocodeResponse.getAdcode();
} else {
log.error("逆地理编码API返回错误: status={}, info={}", geocodeResponse.getStatus(), geocodeResponse.getInfo());
return null;
}
} else {
log.error("逆地理编码HTTP请求失败,状态码: {}", response.getStatusCode());
return null;
}
} catch (Exception e) {
log.error("逆地理编码查询异常: {}", e.getMessage(), e);
return null;
}
}
/**
* 根据adcode获取天气信息
* @param adcode 地区编码
* @return 天气信息JSON字符串
*/
private String getWeatherByAdcode(String adcode) {
String webKey = weatherConf.getWebkey();
String url_2 = weatherConf.getUrl2();
String url = MessageFormat.format(url_2, adcode, webKey);
try {
log.info("调用天气信息API: {}", url.replace(webKey, "***"));
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
if (response.getStatusCode().is2xxSuccessful()) {
String result = response.getBody();
log.debug("天气信息响应: {}", result);
return result;
} else {
log.error("天气信息HTTP请求失败,状态码: {}", response.getStatusCode());
return buildErrorResult("天气信息请求失败,状态码: " + response.getStatusCode());
}
} catch (Exception e) {
log.error("天气信息查询异常: {}", e.getMessage(), e);
return buildErrorResult("天气信息查询异常: " + e.getMessage());
}
}
/**
* 构建错误结果
* @param errorMsg 错误信息
* @return JSON格式的错误结果
*/
private static String buildErrorResult(String errorMsg) {
try {
ErrorResult errorResult = new ErrorResult();
errorResult.setCode(1);
errorResult.setMsg(errorMsg);
return objectMapper.writeValueAsString(errorResult);
} catch (Exception e) {
return "{\"code\":1,\"msg\":\"构建错误结果异常\"}";
}
}
@Data
public static class ErrorResult {
@JsonProperty("code")
private Integer code = 1;
@JsonProperty("msg")
private String msg;
}
}