Ver código fonte

Merge branch 'dev-V0.5.0-gaoyoulong' into dev-V0.5.0

* dev-V0.5.0-gaoyoulong:
  feat: 设备导入功能
  feat: 设备分组导入监听判断数据为空处理;导入后返回数据使用Response
  feat: 设备分组批量导入
gaoyoulong 1 ano atrás
pai
commit
c9d8a8ffd6

+ 49 - 4
iot-module/iot-manager/src/main/java/cc/iotkit/manager/controller/DeviceController.java

@@ -12,6 +12,8 @@ package cc.iotkit.manager.controller;
 import cc.iotkit.common.api.PageRequest;
 import cc.iotkit.common.api.Paging;
 import cc.iotkit.common.api.Request;
+import cc.iotkit.common.api.Response;
+import cc.iotkit.common.excel.utils.ExcelUtil;
 import cc.iotkit.common.thing.ThingModelMessage;
 import cc.iotkit.manager.dto.bo.device.*;
 import cc.iotkit.manager.dto.bo.deviceconfig.DeviceConfigAddBo;
@@ -19,7 +21,9 @@ import cc.iotkit.manager.dto.bo.devicegroup.DeviceAddGroupBo;
 import cc.iotkit.manager.dto.bo.devicegroup.DeviceGroupBo;
 import cc.iotkit.manager.dto.bo.thingmodel.ThingModelMessageBo;
 import cc.iotkit.manager.dto.vo.deviceconfig.DeviceConfigVo;
+import cc.iotkit.manager.dto.vo.devicegroup.DeviceGroupImportVo;
 import cc.iotkit.manager.dto.vo.devicegroup.DeviceGroupVo;
+import cc.iotkit.manager.dto.vo.deviceinfo.DeviceInfoImportVo;
 import cc.iotkit.manager.dto.vo.deviceinfo.DeviceInfoVo;
 import cc.iotkit.manager.dto.vo.deviceinfo.ParentDeviceVo;
 import cc.iotkit.manager.dto.vo.thingmodel.ThingModelVo;
@@ -32,17 +36,18 @@ import cc.iotkit.model.device.DeviceGroup;
 import cc.iotkit.model.device.DeviceInfo;
 import cc.iotkit.model.device.message.DeviceProperty;
 import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.hutool.core.util.IdUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 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 org.springframework.web.bind.annotation.*;
 import org.springframework.web.context.request.async.DeferredResult;
+import org.springframework.web.multipart.MultipartFile;
 
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
 import java.util.List;
 
 @Api(tags = {"设备"})
@@ -146,6 +151,26 @@ public class DeviceController {
         return deviceServiceImpl.batchDeleteDevice(request.getData());
     }
 
+
+    /**
+     * 导入设备-批量添加设备
+     */
+    @ApiOperation(value = "导入设备")
+    @SaCheckPermission("iot:device:add")
+    @PostMapping("/importData")
+    public Response importDevice(@RequestPart("file") MultipartFile file, @RequestParam("requestId") String requestId) {
+        return new Response(200, deviceServiceImpl.importDevice(file), null, requestId);
+    }
+
+    /**
+     * 获取导入设备模板
+     */
+    @ApiOperation("下载设备模板")
+    @PostMapping("/exportData")
+    public void exportDeviceTemplate(HttpServletResponse response) {
+        ExcelUtil.exportExcel(new ArrayList<>(), "设备分组", DeviceInfoImportVo.class, response);
+    }
+
     @ApiOperation("设备物模型日志")
     @SaCheckPermission("iot:deviceLog:query")
     @PostMapping("/deviceLogs/list")
@@ -232,6 +257,26 @@ public class DeviceController {
         return deviceServiceImpl.addGroup(group.getData().to(DeviceGroup.class));
     }
 
+
+    /**
+     * 导入设备分组-批量添加设备分组
+     */
+    @ApiOperation(value = "导入设备分组")
+    @SaCheckPermission("iot:deviceGroup:add")
+    @PostMapping("/group/importData")
+    public Response importGroup(@RequestPart("file") MultipartFile file, @RequestParam("requestId") String requestId) {
+        return new Response(200, deviceServiceImpl.importGroup(file), null, requestId);
+    }
+
+    /**
+     * 获取导入模板
+     */
+    @ApiOperation("下载设备分组模板")
+    @PostMapping("/group/exportData")
+    public void exportGroupTemplate(HttpServletResponse response) {
+        ExcelUtil.exportExcel(new ArrayList<>(), "设备分组", DeviceGroupImportVo.class, response);
+    }
+
     /**
      * 修改设备分组
      */

+ 27 - 0
iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/vo/devicegroup/DeviceGroupImportVo.java

@@ -0,0 +1,27 @@
+package cc.iotkit.manager.dto.vo.devicegroup;
+
+import cc.iotkit.model.device.DeviceGroup;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+
+@Data
+@NoArgsConstructor
+@AutoMapper(target = DeviceGroup.class, reverseConvertGenerate = false)
+public class DeviceGroupImportVo implements Serializable {
+
+    private static final long serialVersionUID = -1L;
+
+    @ExcelProperty(value = "设备组id")
+    private String id;
+
+    @ExcelProperty(value = "设备组名称")
+    private String name;
+
+    @ExcelProperty(value = "分组说明")
+    private String remark;
+}

+ 32 - 0
iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/vo/deviceinfo/DeviceInfoImportVo.java

@@ -0,0 +1,32 @@
+package cc.iotkit.manager.dto.vo.deviceinfo;
+
+import cc.iotkit.model.device.DeviceInfo;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serializable;
+
+
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = DeviceInfo.class,convertGenerate = false)
+public class DeviceInfoImportVo implements Serializable {
+    private static final long serialVersionUID = -1L;
+
+    @ExcelProperty(value = "设备名称")
+    private String deviceName;
+
+    @ExcelProperty(value = "设备型号")
+    private String model;
+
+    @ExcelProperty(value = "父级id")
+    private String parentId;
+
+    @ExcelProperty(value = "产品key")
+    private String productKey;
+
+    @ExcelProperty(value = "设备分组")
+    private String deviceGroup;
+}

+ 103 - 0
iot-module/iot-manager/src/main/java/cc/iotkit/manager/listener/DeviceGroupImportListener.java

@@ -0,0 +1,103 @@
+package cc.iotkit.manager.listener;
+
+import cc.iotkit.common.excel.core.ExcelListener;
+import cc.iotkit.common.excel.core.ExcelResult;
+import cc.iotkit.common.exception.BizException;
+import cc.iotkit.common.satoken.utils.LoginHelper;
+import cc.iotkit.common.utils.SpringUtils;
+import cc.iotkit.common.utils.StringUtils;
+import cc.iotkit.manager.dto.bo.devicegroup.DeviceGroupBo;
+import cc.iotkit.manager.dto.vo.devicegroup.DeviceGroupImportVo;
+import cc.iotkit.manager.dto.vo.devicegroup.DeviceGroupVo;
+import cc.iotkit.manager.service.IDeviceManagerService;
+import cc.iotkit.model.device.DeviceGroup;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.event.AnalysisEventListener;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Collections;
+import java.util.List;
+
+@Slf4j
+public class DeviceGroupImportListener extends AnalysisEventListener<DeviceGroupImportVo> implements ExcelListener<DeviceGroupImportVo> {
+
+    private final Boolean isUpdateSupport;
+
+    private int successNum = 0;
+    private int failureNum = 0;
+
+    private final String userId;
+
+    private IDeviceManagerService deviceManagerService;
+
+    private final StringBuilder successMsg = new StringBuilder();
+    private final StringBuilder failureMsg = new StringBuilder();
+
+    public DeviceGroupImportListener(Boolean isUpdateSupport) {
+        this.isUpdateSupport = isUpdateSupport;
+        this.userId = String.valueOf(LoginHelper.getUserId());
+        this.deviceManagerService = SpringUtils.getBean(IDeviceManagerService.class);
+    }
+
+    @Override
+    public ExcelResult<DeviceGroupImportVo> getExcelResult() {
+
+        return new ExcelResult<>() {
+            @Override
+            public String getAnalysis() {
+                if (failureNum > 0) {
+                    failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
+                    throw new BizException(failureMsg.toString());
+                } else {
+                    successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条");
+                }
+                return successMsg.toString();
+            }
+
+            @Override
+            public List<DeviceGroupImportVo> getList() {
+                return Collections.emptyList();
+            }
+
+            @Override
+            public List<String> getErrorList() {
+                return Collections.emptyList();
+            }
+        };
+    }
+
+    @Override
+    public void invoke(DeviceGroupImportVo deviceGroupImportVo, AnalysisContext analysisContext) {
+        if ( StringUtils.isEmpty(deviceGroupImportVo.getId()) || StringUtils.isEmpty(deviceGroupImportVo.getName()) ) {
+            failureNum++;
+            failureMsg.append("<br/>第").append(analysisContext.getCurrentRowNum()).append("行,设备分组ID或名称不能为空");
+            return;
+        }
+
+        DeviceGroupVo deviceGroupVo = this.deviceManagerService.getDeviceGroup(deviceGroupImportVo.getId());
+        try {
+            if (ObjectUtil.isNull(deviceGroupVo)) {
+                // 新增
+                DeviceGroup deviceGroup = BeanUtil.toBean(deviceGroupImportVo, DeviceGroup.class);
+                deviceGroup.setUid(this.userId);
+                this.deviceManagerService.addGroup(deviceGroup);
+            } else if (Boolean.TRUE.equals(isUpdateSupport)) {
+                // 修改
+                DeviceGroupBo deviceGroupBo = BeanUtil.toBean(deviceGroupImportVo, DeviceGroupBo.class);
+                deviceGroupBo.setUid(this.userId);
+                this.deviceManagerService.updateGroup(deviceGroupBo);
+            }
+            successNum++;
+        } catch (Exception e) {
+            failureNum++;
+            failureMsg.append("<br/>第").append(analysisContext.getCurrentRowNum()).append("行,导入失败:").append(e.getMessage());
+        }
+    }
+
+    @Override
+    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
+
+    }
+}

+ 117 - 0
iot-module/iot-manager/src/main/java/cc/iotkit/manager/listener/DeviceInfoImportListener.java

@@ -0,0 +1,117 @@
+package cc.iotkit.manager.listener;
+
+import cc.iotkit.common.excel.core.ExcelListener;
+import cc.iotkit.common.excel.core.ExcelResult;
+import cc.iotkit.common.exception.BizException;
+import cc.iotkit.common.satoken.utils.LoginHelper;
+import cc.iotkit.common.utils.SpringUtils;
+import cc.iotkit.common.utils.StringUtils;
+import cc.iotkit.manager.dto.bo.device.DeviceInfoBo;
+import cc.iotkit.manager.dto.bo.devicegroup.DeviceAddGroupBo;
+import cc.iotkit.manager.dto.vo.deviceinfo.DeviceInfoImportVo;
+import cc.iotkit.manager.service.IDeviceManagerService;
+import cc.iotkit.model.device.DeviceInfo;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.event.AnalysisEventListener;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class DeviceInfoImportListener extends AnalysisEventListener<DeviceInfoImportVo> implements ExcelListener<DeviceInfoImportVo> {
+
+    private Boolean isUpdateSupport;
+
+    private int successNum = 0;
+    private int failureNum = 0;
+
+    private final String userId;
+
+    private IDeviceManagerService deviceManagerService;
+
+    private final StringBuilder successMsg = new StringBuilder();
+    private final StringBuilder failureMsg = new StringBuilder();
+
+    public DeviceInfoImportListener(Boolean isUpdateSupport) {
+        this.isUpdateSupport = isUpdateSupport;
+        this.userId = String.valueOf(LoginHelper.getUserId());
+        this.deviceManagerService = SpringUtils.getBean(IDeviceManagerService.class);
+    }
+
+    @Override
+    public ExcelResult<DeviceInfoImportVo> getExcelResult() {
+        return new ExcelResult<>() {
+            @Override
+            public String getAnalysis() {
+                if (failureNum > 0) {
+                    failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
+                    throw new BizException(failureMsg.toString());
+                } else {
+                    successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条");
+                }
+                return successMsg.toString();
+            }
+
+            @Override
+            public List<DeviceInfoImportVo> getList() {
+                return Collections.emptyList();
+            }
+
+            @Override
+            public List<String> getErrorList() {
+                return Collections.emptyList();
+            }
+        };
+    }
+
+    @Override
+    public void invoke(DeviceInfoImportVo deviceInfoImportVo, AnalysisContext analysisContext) {
+        if (StringUtils.isBlank(deviceInfoImportVo.getProductKey())) {
+            failureMsg.append("<br/>第").append(analysisContext.getCurrentRowNum()).append("行,产品key不能为空!");
+            failureNum++;
+        }
+        if (StringUtils.isBlank(deviceInfoImportVo.getDeviceName())) {
+            failureMsg.append("<br/>第").append(analysisContext.getCurrentRowNum()).append("行,设备名称不能为空!");
+            failureNum++;
+        }
+        DeviceInfo deviceInfo = this.deviceManagerService.getByPkDn(deviceInfoImportVo.getProductKey(), deviceInfoImportVo.getDeviceName());
+        try {
+            // todo 处理groups
+            if(ObjectUtil.isNull(deviceInfo)) {
+                // 新增
+                DeviceInfoBo deviceInfoBo = BeanUtil.toBean(deviceInfoImportVo, DeviceInfoBo.class);
+                this.deviceManagerService.addDevice(deviceInfoBo);
+                // 新增后重新获取deviceInfo, 此操作冗余,是建立在不修改源码基础上的处理方式,可优化
+                deviceInfo = this.deviceManagerService.getByPkDn(deviceInfoImportVo.getProductKey(), deviceInfoImportVo.getDeviceName());
+            } else if (Boolean.TRUE.equals(isUpdateSupport)) {
+                // 修改
+                DeviceInfoBo deviceInfoBo = BeanUtil.toBean(deviceInfo, DeviceInfoBo.class);
+                this.deviceManagerService.saveDevice(deviceInfoBo);
+            }
+
+            // 设备分组处理
+            String group = deviceInfoImportVo.getDeviceGroup();
+            if (StringUtils.isNotBlank(group)) {
+                DeviceAddGroupBo deviceAddGroupBo = new DeviceAddGroupBo();
+                deviceAddGroupBo.setGroup(group);
+                String deviceId = deviceInfo.getDeviceId();
+                ArrayList<String> devices = new ArrayList<>();
+                devices.add(deviceId);
+                deviceAddGroupBo.setDevices(devices);
+                this.deviceManagerService.addDevice2Group(deviceAddGroupBo);
+            }
+
+            successNum++;
+        } catch (Exception e) {
+            failureNum++;
+            failureMsg.append("<br/>第").append(analysisContext.getCurrentRowNum()).append("行,导入失败:").append(e.getMessage());
+        }
+    }
+
+    @Override
+    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
+
+    }
+}

+ 7 - 0
iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/IDeviceManagerService.java

@@ -18,6 +18,7 @@ import cc.iotkit.model.device.DeviceGroup;
 import cc.iotkit.model.device.DeviceInfo;
 import cc.iotkit.model.device.message.DeviceProperty;
 import org.springframework.web.context.request.async.DeferredResult;
+import org.springframework.web.multipart.MultipartFile;
 
 import java.util.List;
 
@@ -75,4 +76,10 @@ public interface IDeviceManagerService {
     DeviceConfigVo getConfig(String deviceId);
 
     boolean saveDevice(DeviceInfoBo data);
+
+    String importGroup(MultipartFile file);
+
+    DeviceGroupVo getDeviceGroup(String id);
+
+    String importDevice(MultipartFile file);
 }

+ 30 - 0
iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/impl/DeviceManagerServiceImpl.java

@@ -4,6 +4,8 @@ import cc.iotkit.common.api.PageRequest;
 import cc.iotkit.common.api.Paging;
 import cc.iotkit.common.constant.Constants;
 import cc.iotkit.common.enums.ErrCode;
+import cc.iotkit.common.excel.core.ExcelResult;
+import cc.iotkit.common.excel.utils.ExcelUtil;
 import cc.iotkit.common.exception.BizException;
 import cc.iotkit.common.satoken.utils.AuthUtil;
 import cc.iotkit.common.thing.ThingModelMessage;
@@ -19,9 +21,13 @@ import cc.iotkit.manager.dto.bo.device.DeviceTagAddBo;
 import cc.iotkit.manager.dto.bo.devicegroup.DeviceAddGroupBo;
 import cc.iotkit.manager.dto.bo.devicegroup.DeviceGroupBo;
 import cc.iotkit.manager.dto.vo.deviceconfig.DeviceConfigVo;
+import cc.iotkit.manager.dto.vo.devicegroup.DeviceGroupImportVo;
 import cc.iotkit.manager.dto.vo.devicegroup.DeviceGroupVo;
+import cc.iotkit.manager.dto.vo.deviceinfo.DeviceInfoImportVo;
 import cc.iotkit.manager.dto.vo.deviceinfo.DeviceInfoVo;
 import cc.iotkit.manager.dto.vo.deviceinfo.ParentDeviceVo;
+import cc.iotkit.manager.listener.DeviceGroupImportListener;
+import cc.iotkit.manager.listener.DeviceInfoImportListener;
 import cc.iotkit.manager.service.DataOwnerService;
 import cc.iotkit.manager.service.DeferredDataConsumer;
 import cc.iotkit.manager.service.DeviceCtrlService;
@@ -34,12 +40,14 @@ import cc.iotkit.model.product.Product;
 import cc.iotkit.mq.MqProducer;
 import cc.iotkit.temporal.IDevicePropertyData;
 import cc.iotkit.temporal.IThingModelMessageData;
+import lombok.SneakyThrows;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.web.context.request.async.DeferredResult;
+import org.springframework.web.multipart.MultipartFile;
 
 import java.util.List;
 import java.util.stream.Collectors;
@@ -423,4 +431,26 @@ public class DeviceManagerServiceImpl implements IDeviceManagerService {
         return deviceInfoData.save(di) != null;
     }
 
+
+    @SneakyThrows
+    @Override
+    public String importGroup(MultipartFile file) {
+        ExcelResult<DeviceGroupImportVo> result = ExcelUtil.importExcel(file.getInputStream(), DeviceGroupImportVo.class, new DeviceGroupImportListener(true));
+        return result.getAnalysis();
+    }
+
+    @Override
+    public DeviceGroupVo getDeviceGroup(String id) {
+        DeviceGroup deviceGroup = deviceGroupData.findById(id);
+        return MapstructUtils.convert(deviceGroup, DeviceGroupVo.class);
+    }
+
+    @SneakyThrows
+    @Override
+    public String importDevice(MultipartFile file) {
+        ExcelResult<DeviceInfoImportVo> result = ExcelUtil.importExcel(file.getInputStream(), DeviceInfoImportVo.class, new DeviceInfoImportListener(true));
+        return result.getAnalysis();
+    }
+
+
 }