yml文件
yun:ip: port: username: password:
controller
package com.ruoyi.web.controller.materials;import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.materials.service.IYunService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;/*** Created with IntelliJ IDEA.** @Author: yxy* @Date: 2025/07/02/9:46* @Description:*/
@RestController
@RequestMapping("/yun")
public class YunController extends BaseController {@Autowiredprivate IYunService yunService;// 查询分组列表@GetMapping("/getGroupList")public AjaxResult getGroupList(){return success(yunService.getGroupList());}// 查询设备列表@GetMapping("/getDeviceList")public AjaxResult getDeviceList(@RequestParam(required = false) String groupId){return success(yunService.getDeviceList(groupId));}// 查询设备列表@GetMapping("/getDevice")public AjaxResult getDeviceListByDeviceAddr(@RequestParam Long deviceAddr){return success(yunService.getDeviceListByDeviceAddr(deviceAddr));}//根据设备地址获取设备继电器列表@GetMapping("/getRelayList")public AjaxResult getRelayList(@RequestParam Long deviceAddr){return success(yunService.getRelayList(deviceAddr));}}
ServiceImpl
package com.ruoyi.materials.service.impl;import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.redis.RedisCache;import com.ruoyi.materials.domain.yun.DeviceVo;
import com.ruoyi.materials.domain.yun.GroupVo;
import com.ruoyi.materials.domain.yun.RelayVo;
import com.ruoyi.materials.domain.yun.YunUtils;
import com.ruoyi.materials.service.IYunService;
import com.ruoyi.materials.until.SmsUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;/*** Created with IntelliJ IDEA.** @Author: yxy* @Date: 2025/07/02/9:48* @Description:*/
@Slf4j
@Service
public class YunServiceImpl implements IYunService {@Resourceprivate RedisCache redisCache;private static final String YUN_TOKEN_KEY = "yun_token";private final YunUtils yunUtils;// 构造函数注入public YunServiceImpl(YunUtils yunUtils) {this.yunUtils = yunUtils;}/*** @Description: 查询分组列表* @Author: yxy* @date: 2025/7/2 10:06*/@Overridepublic List<GroupVo> getGroupList() {// 获取tokenString token = redisCache.getCacheObject(YUN_TOKEN_KEY);// 尝试获取分组列表List<GroupVo> result = yunUtils.fetchGroupList(token);// 如果token无效,重新登录并再次尝试if (result == null || result.size()==0) {yunUtils.loginYun();token = redisCache.getCacheObject(YUN_TOKEN_KEY);result = yunUtils.fetchGroupList(token);}return result != null ? result : Collections.emptyList();}/*** @Description: 查询设备列表* @Author: yxy* @date: 2025/7/2 14:25*/@Overridepublic List<DeviceVo> getDeviceList(String groupId) {// 获取tokenString token = redisCache.getCacheObject(YUN_TOKEN_KEY);// 尝试获取分组列表List<DeviceVo> result = yunUtils.fetchDeviceList(token,groupId);// 如果token无效,重新登录并再次尝试if (result == null || result.size()==0) {yunUtils.loginYun();token = redisCache.getCacheObject(YUN_TOKEN_KEY);result = yunUtils.fetchDeviceList(token,groupId);}return result != null ? result : Collections.emptyList();}/*** @Description: 根据设备地址查询设备信息* @Author: yxy* @date: 2025/7/2 17:13*/@Overridepublic List<DeviceVo> getDeviceListByDeviceAddr(Long deviceAddr) {// 获取tokenString token = redisCache.getCacheObject(YUN_TOKEN_KEY);// 尝试获取分组列表List<DeviceVo> result = yunUtils.fetchDeviceListByDeviceAddr(token,deviceAddr);// 如果token无效,重新登录并再次尝试if (result == null || result.size()==0) {yunUtils.loginYun();token = redisCache.getCacheObject(YUN_TOKEN_KEY);result = yunUtils.fetchDeviceListByDeviceAddr(token,deviceAddr);}return result != null ? result : Collections.emptyList();}/*** @Description: 根据设备地址获取设备继电器列表* @Author: yxy* @date: 2025/7/3 9:56*/@Overridepublic List<RelayVo> getRelayList(Long deviceAddr) {// 获取tokenString token = redisCache.getCacheObject(YUN_TOKEN_KEY);// 尝试获取分组列表List<RelayVo> result = yunUtils.fetchRelayListByDeviceAddr(token,deviceAddr);// 如果token无效,重新登录并再次尝试if (result == null || result.size()==0) {yunUtils.loginYun();token = redisCache.getCacheObject(YUN_TOKEN_KEY);result = yunUtils.fetchRelayListByDeviceAddr(token,deviceAddr);}return result != null ? result : Collections.emptyList();}}
YunUtils
package com.ruoyi.materials.domain.yun;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.materials.until.SmsUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;/*** Created with IntelliJ IDEA.** @Author: yxy* @Date: 2025/07/02/9:53* @Description:*/
@Slf4j
@Component
public class YunUtils {@Resourceprivate RedisCache redisCache;@Resourceprivate RestTemplate restTemplate;@Value("${yun.ip}")private String yunIp;@Value("${yun.port}")private String yunPort;@Value("${yun.username}")private String yunUsername;@Value("${yun.password}")private String yunPassword;private static final String YUN_TOKEN_KEY = "yun_token";/*** @Description:登录yun系统 存 token 到 redis* @Author: yxy* @date: 2025/7/1 15:31*/public void loginYun() {try {ResponseEntity<String> response = SmsUtils.getForList(restTemplate,null,"/api/getToken",yunIp,yunPort,new YunLoginDto(yunUsername, yunPassword));String body = response.getBody();ObjectMapper objectMapper = new ObjectMapper();TokenResponse tokenResponse = objectMapper.readValue(body, TokenResponse.class);if (tokenResponse.getCode() == 1000) {String token = tokenResponse.getData().getToken();redisCache.setCacheObject(YUN_TOKEN_KEY, token, 5, TimeUnit.MINUTES);log.info("云平台登录成功,token已存入Redis");} else {log.error("云平台登录失败,错误码: {}, 错误信息: {}",tokenResponse.getCode(),tokenResponse.getMessage());}} catch (Exception e) {log.error("云平台登录异常", e);throw new RuntimeException("云平台登录失败", e);}}/*** 实际调用API获取分组列表的方法*/public List<GroupVo> fetchGroupList(String token) {if (StringUtils.isBlank(token)) {log.warn("调用fetchGroupList时token为空");return Collections.emptyList();}try {ResponseEntity<String> response = SmsUtils.getForList(restTemplate,token,"/api/device/getGroupList",yunIp,yunPort,null);if (!response.getStatusCode().is2xxSuccessful()) {log.error("获取分组列表失败,HTTP状态码: {}", response.getStatusCode());return Collections.emptyList();}String body = response.getBody();ObjectMapper objectMapper = new ObjectMapper();GroupResponse groupResponse = objectMapper.readValue(body, GroupResponse.class);if (groupResponse.getCode() == 1000 && groupResponse.getData() != null) {return groupResponse.getData();} else {log.error("获取分组列表失败,业务错误码: {}, 错误信息: {}",groupResponse.getCode(),groupResponse.getMessage());return Collections.emptyList();}} catch (JsonProcessingException e) {// 处理JSON解析异常log.error("解析API响应失败,响应内容: ", e);return Collections.emptyList();} catch (Exception e) {log.error("获取分组列表发生未知异常", e);return Collections.emptyList();}}/*** 实际调用API获取设备列表的方法*/public List<DeviceVo> fetchDeviceList(String token,String groupId) {if (StringUtils.isBlank(token)) {log.warn("调用fetchDeviceList时token为空");return Collections.emptyList();}DeviceVo deviceVo = new DeviceVo();if (groupId!=null){deviceVo.setGroupId(groupId);}try {ResponseEntity<String> response = SmsUtils.getForList(restTemplate,token,"/api/device/getDeviceList",yunIp,yunPort,deviceVo);if (!response.getStatusCode().is2xxSuccessful()) {log.error("获取设备列表失败,HTTP状态码: {}", response.getStatusCode());return Collections.emptyList();}String body = response.getBody();ObjectMapper objectMapper = new ObjectMapper();DeviceResponse deviceResponse = objectMapper.readValue(body, DeviceResponse.class);if (deviceResponse.getCode() == 1000 && deviceResponse.getData() != null) {return deviceResponse.getData();} else {log.error("获取设备列表失败,业务错误码: {}, 错误信息: {}",deviceResponse.getCode(),deviceResponse.getMessage());return Collections.emptyList();}} catch (JsonProcessingException e) {// 处理JSON解析异常log.error("解析API响应失败,响应内容: ", e);return Collections.emptyList();} catch (Exception e) {log.error("获取设备列表发生未知异常", e);return Collections.emptyList();}}/*** 根据设备地址查询设备信息*/public List<DeviceVo> fetchDeviceListByDeviceAddr(String token,Long deviceAddr) {if (StringUtils.isBlank(token)) {log.warn("调用fetchDeviceListByDeviceAddr时token为空");return Collections.emptyList();}DeviceVo deviceVo = new DeviceVo();if (deviceAddr!=null){deviceVo.setDeviceAddr(deviceAddr);}try {ResponseEntity<String> response = SmsUtils.getForList(restTemplate,token,"/api/device/getDevice",yunIp,yunPort,deviceVo);if (!response.getStatusCode().is2xxSuccessful()) {log.error("根据设备地址查询设备信息失败,HTTP状态码: {}", response.getStatusCode());return Collections.emptyList();}String body = response.getBody();ObjectMapper objectMapper = new ObjectMapper();DeviceResponse deviceResponse = objectMapper.readValue(body, DeviceResponse.class);if (deviceResponse.getCode() == 1000 && deviceResponse.getData() != null) {return deviceResponse.getData();} else {log.error("根据设备地址查询设备信息失败,业务错误码: {}, 错误信息: {}",deviceResponse.getCode(),deviceResponse.getMessage());return Collections.emptyList();}} catch (JsonProcessingException e) {// 处理JSON解析异常log.error("解析API响应失败,响应内容: ", e);return Collections.emptyList();} catch (Exception e) {log.error("根据设备地址查询设备信息发生未知异常", e);return Collections.emptyList();}}/*** 根据设备地址获取设备继电器列表*/public List<RelayVo> fetchRelayListByDeviceAddr(String token,Long deviceAddr) {if (StringUtils.isBlank(token)) {log.warn("调用 fetchRelayListByDeviceAddr 时token为空");return Collections.emptyList();}RelayVo relayVo = new RelayVo();if (deviceAddr!=null){relayVo.setDeviceAddr(deviceAddr);}try {ResponseEntity<String> response = SmsUtils.getForList(restTemplate,token,"/api/device/getRelayList",yunIp,yunPort,relayVo);if (!response.getStatusCode().is2xxSuccessful()) {log.error("根据设备地址获取设备继电器列表 信息失败,HTTP状态码: {}", response.getStatusCode());return Collections.emptyList();}String body = response.getBody();ObjectMapper objectMapper = new ObjectMapper();RelayResponse relayResponse = objectMapper.readValue(body, RelayResponse.class);if (relayResponse.getCode() == 1000 && relayResponse.getData() != null) {return relayResponse.getData();} else {log.error("根据设备地址获取设备继电器列表 信息失败,业务错误码: {}, 错误信息: {}",relayResponse.getCode(),relayResponse.getMessage());return Collections.emptyList();}} catch (JsonProcessingException e) {// 处理JSON解析异常log.error("解析API响应失败,响应内容: ", e);return Collections.emptyList();} catch (Exception e) {log.error("根据设备地址获取设备继电器列表 信息发生未知异常", e);return Collections.emptyList();}}}
实体类
@Data
public class DeviceResponse {private Integer code;private String message;private List<DeviceVo> data;
}@Data
public class DeviceVo {private Long deviceAddr; // 设备地址private String groupId; // 所属分组IDprivate String deviceName; // 设备名称private Integer offlineinterval; // 离线间隔private Integer savedatainterval; // 保存数据间隔private Integer alarmSwitch; // 报警开关状态private Integer alarmRecord; // 报警记录状态private Double lng; // 经度private Double lat; // 纬度private Boolean useMarkLocation; // 是否使用标记位置private Integer sort; // 排序号private String deviceCode; // 设备编码private List<FactorInfo> factors; // 监测因子列表@Datapublic static class FactorInfo {private String factorId; // 因子IDprivate Long deviceAddr; // 关联的设备地址private Integer nodeId; // 节点IDprivate Integer registerId; // 寄存器IDprivate String factorName; // 因子名称private String factorIcon; // 因子图标private Double coefficient; // 系数private Double offset; // 偏移量private Integer alarmDelay; // 报警延迟private Integer alarmRate; // 报警阈值比例private Integer backToNormalDelay;// 恢复正常延迟private Integer digits; // 小数位数private String unit; // 单位private Boolean enabled; // 是否启用private Integer sort; // 排序号private Integer maxVoiceAlarmTimes; // 最大语音报警次数private Integer maxSmsAlarmTimes; // 最大短信报警次数}}@Data
public class GroupResponse implements Serializable {private static final long serialVersionUID = 1L;private Integer code;private String message;private List<GroupVo> data;
}@Data
public class GroupVo {private String groupId;private String parentId;private String groupName;
}@Data
public class RelayResponse {private Integer code;private String message;private List<RelayVo> data;
}@Data
public class RelayVo {private Long deviceAddr; // 设备地址private String deviceName; // 设备名称private Boolean enabled; // 是否启用private String relayName; // 继电器名称private Integer relayNo; // 继电器编号private Integer relayStatus; // 继电器状态}@Data
public class ResponseVo implements Serializable {private static final long serialVersionUID = 1L;private int code;private String msg;private String token;private Object data;
}@Data
public class TokenResponse {private Integer code;private String message;private TokenData data;@Datapublic static class TokenData {private Integer expiration;private String token;}
}@Data
@AllArgsConstructor
@NoArgsConstructor
public class YunLoginDto {private String loginName;private String password;
}