diff --git a/fys-modules/fys-equipment/pom.xml b/fys-modules/fys-equipment/pom.xml index fe09466..87cc0b3 100644 --- a/fys-modules/fys-equipment/pom.xml +++ b/fys-modules/fys-equipment/pom.xml @@ -116,12 +116,12 @@ com.alibaba easyexcel 3.3.1 - - - poi-ooxml-schemas - org.apache.poi - - + + + + org.apache.poi + ooxml-schemas + 1.4 diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/controller/DeviceController.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/controller/DeviceController.java index f93b997..d1cfb59 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/controller/DeviceController.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/controller/DeviceController.java @@ -3,7 +3,6 @@ package com.fuyuanshen.equipment.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.fuyuanshen.common.core.constant.ResponseMessageConstants; -import com.fuyuanshen.common.core.domain.PageResult; import com.fuyuanshen.common.core.domain.ResponseVO; import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; import com.fuyuanshen.equipment.domain.Device; @@ -12,6 +11,7 @@ import com.fuyuanshen.equipment.domain.form.DeviceForm; import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria; import com.fuyuanshen.equipment.domain.vo.CustomerVo; import com.fuyuanshen.equipment.service.DeviceService; +import com.fuyuanshen.equipment.service.impl.DeviceExportService; import com.fuyuanshen.system.domain.vo.SysOssVo; import com.fuyuanshen.system.service.ISysOssService; import io.swagger.v3.oas.annotations.Operation; @@ -43,19 +43,13 @@ public class DeviceController { private final ISysOssService ossService; private final DeviceService deviceService; + private final DeviceExportService exportService; + @Operation(summary = "分页查询设备列表", security = {@SecurityRequirement(name = "bearer-key")}) @GetMapping public TableDataInfo queryDevice(DeviceQueryCriteria criteria) throws IOException { Page page = new Page<>(criteria.getPage(), criteria.getSize()); - // PageResult devices = null; - // try { - // devices = deviceService.queryAll(criteria, page); - // } catch (IOException e) { - // log.error("queryDevice error: " + e.getMessage()); - // return ResponseVO.fail(""); - // } - // return ResponseVO.success(devices); return deviceService.queryAll(criteria, page); } @@ -102,7 +96,6 @@ public class DeviceController { @DeleteMapping(value = "/delete") public ResponseVO deleteDevice(@Parameter(name = "传ID数组[]") @RequestBody List ids) { deviceService.deleteAll(ids); - // deviceService.deleteAssign(ids); return ResponseVO.success(ResponseMessageConstants.DELETE_SUCCESS); } @@ -156,7 +149,8 @@ public class DeviceController { @Operation(summary = "导出数据设备") @GetMapping(value = "/download") public void exportDevice(HttpServletResponse response, DeviceQueryCriteria criteria) throws IOException { - + List devices = deviceService.queryAll(criteria); + exportService.export(devices, response); } diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/controller/DeviceTypeController.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/controller/DeviceTypeController.java index 4185f8d..100a44c 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/controller/DeviceTypeController.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/controller/DeviceTypeController.java @@ -1,7 +1,6 @@ package com.fuyuanshen.equipment.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.fuyuanshen.common.core.domain.PageResult; import com.fuyuanshen.common.core.domain.ResponseVO; import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; import com.fuyuanshen.equipment.domain.DeviceType; diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/converter/IgnoreFailedImageConverter.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/converter/IgnoreFailedImageConverter.java new file mode 100644 index 0000000..650bec9 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/converter/IgnoreFailedImageConverter.java @@ -0,0 +1,76 @@ +package com.fuyuanshen.equipment.converter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; + +/** + * @author: 默苍璃 + * @date: 2025-06-0618:56 + */ + +public class IgnoreFailedImageConverter implements Converter { + private static final Logger logger = LoggerFactory.getLogger(IgnoreFailedImageConverter.class); + + @Override + public Class supportJavaTypeKey() { + return URL.class; + } + + // @Override + // public CellDataTypeEnum supportExcelTypeKey() { + // return CellDataTypeEnum.STRING; + // } + + @Override + public WriteCellData convertToExcelData(URL value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (value == null) { + return null; + } + + try { + URLConnection conn = value.openConnection(); + conn.setConnectTimeout(2000); // 2秒超时 + conn.setReadTimeout(3000); // 3秒超时 + + try (InputStream inputStream = conn.getInputStream()) { + // byte[] bytes = FileUtils.readInputStream(inputStream, value.toString()); + // 替代 FileUtils.readInputStream 的自定义方法 + byte[] bytes = readInputStream(inputStream); + return new WriteCellData<>(bytes); + } + } catch (Exception e) { + // 静默忽略错误,只记录日志 + logger.debug("忽略图片加载失败: {}, 原因: {}", value, e.getMessage()); + // return null; // 返回null表示不写入图片 + return new WriteCellData<>(new byte[0]); // 返回空数组而不是 null + } + } + + /** + * 替代 FileUtils.readInputStream 的自定义方法 + * + * @param inputStream 输入流 + * @return 字节数组 + * @throws Exception 读取异常 + */ + private byte[] readInputStream(InputStream inputStream) throws Exception { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[8192]; + int bytesRead; + + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + + return outputStream.toByteArray(); + } +} \ No newline at end of file diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/converter/ImageReadConverter.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/converter/ImageReadConverter.java new file mode 100644 index 0000000..3e6d12f --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/converter/ImageReadConverter.java @@ -0,0 +1,44 @@ +package com.fuyuanshen.equipment.converter;// package com.fuyuanshen.modules.system.converter; +// +// import com.alibaba.excel.converters.Converter; +// import com.alibaba.excel.enums.CellDataTypeEnum; +// import com.alibaba.excel.metadata.GlobalConfiguration; +// import com.alibaba.excel.metadata.data.ReadCellData; +// import com.alibaba.excel.metadata.property.ExcelContentProperty; +// +// import java.io.ByteArrayOutputStream; +// import java.io.IOException; +// +// /** +// * @author: 默苍璃 +// * @date: 2025-06-0710:01 +// */ +// +// public class ImageReadConverter implements Converter { +// +// @Override +// public Class supportJavaTypeKey() { +// return byte[].class; +// } +// +// // @Override +// // public CellDataTypeEnum supportExcelTypeKey() { +// // return CellDataTypeEnum.IMAGE; +// // } +// +// @Override +// public byte[] convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws IOException { +// if (cellData.getType() == CellDataTypeEnum.IMAGE) { +// ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); +// cellData.getImageValueList().forEach(image -> { +// try { +// outputStream.write(image.getImageBytes()); +// } catch (IOException e) { +// throw new RuntimeException(e); +// } +// }); +// return outputStream.toByteArray(); +// } +// return null; +// } +// } \ No newline at end of file diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/Device.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/Device.java index 6a500a7..5536e1b 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/Device.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/Device.java @@ -99,4 +99,10 @@ public class Device extends TenantEntity { @Schema(name = "绑定状态") private Integer bindingStatus; + + /** + * 创建人名称 + */ + private String createByName; + } diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/dto/DeviceExcelExportDTO.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/dto/DeviceExcelExportDTO.java new file mode 100644 index 0000000..28aa32c --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/dto/DeviceExcelExportDTO.java @@ -0,0 +1,80 @@ +package com.fuyuanshen.equipment.domain.dto; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import com.alibaba.excel.annotation.write.style.ContentRowHeight; +import com.alibaba.excel.annotation.write.style.HeadRowHeight; +import com.fuyuanshen.equipment.converter.IgnoreFailedImageConverter; +import lombok.Data; + +import java.net.URL; + +/** + * @author: 默苍璃 + * @date: 2025-06-0618:16 + */ +@Data +@HeadRowHeight(20) // 表头行高 +@ContentRowHeight(100) // 内容行高 +public class DeviceExcelExportDTO { + + @ExcelProperty("ID") + private Long id; + + @ExcelProperty("设备类型") + private Long deviceType; + + // @ExcelProperty("客户号") + // private Long customerId; + + @ExcelProperty("所属客户") + private String customerName; + + @ExcelProperty("设备名称") + @ColumnWidth(20) + private String deviceName; + + @ExcelProperty(value = "设备图片", converter = IgnoreFailedImageConverter.class) + @ColumnWidth(15) // 设置图片列宽度 + private URL devicePic; // 使用URL类型 + + @ExcelProperty("设备MAC") + @ColumnWidth(20) + private String deviceMac; + + @ExcelProperty("设备IMEI") + @ColumnWidth(20) + private String deviceImei; + + @ExcelProperty("经度") + private String longitude; + + @ExcelProperty("纬度") + private String latitude; + + @ExcelProperty("备注") + @ColumnWidth(30) + private String remark; + + @ExcelProperty("设备类型名称") + @ColumnWidth(20) + private String typeName; + + /** + * 设备状态 + * 0 失效 + * 1 正常 + */ + @ExcelProperty("设备状态") + @ColumnWidth(20) + private String deviceStatus; + + @ExcelProperty("创建时间") + @ColumnWidth(20) + private String createTime; + + @ExcelProperty("创建人") + @ColumnWidth(20) + private String createBy; + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/DeviceService.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/DeviceService.java index af53adb..4990517 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/DeviceService.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/DeviceService.java @@ -28,6 +28,14 @@ public interface DeviceService extends IService { */ TableDataInfo queryAll(DeviceQueryCriteria criteria, Page page) throws IOException; + /** + * 查询所有数据不分页 + * + * @param criteria 条件参数 + * @return List + */ + List queryAll(DeviceQueryCriteria criteria); + /** * 查询所有设备信息 * diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceExportService.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceExportService.java new file mode 100644 index 0000000..22650e3 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceExportService.java @@ -0,0 +1,86 @@ +package com.fuyuanshen.equipment.service.impl; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.util.DateUtils; +import com.fuyuanshen.equipment.domain.Device; +import com.fuyuanshen.equipment.domain.dto.DeviceExcelExportDTO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author: 默苍璃 + * @date: 2025-06-0618:22 + */ +@Service +public class DeviceExportService { + + public void export(List devices, HttpServletResponse response) { + try { + String fileName = "设备列表_" + System.currentTimeMillis() + ".xlsx"; + // 使用URLEncoder进行RFC 5987编码 + String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()).replaceAll("\\+", "%20"); + + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + // 使用RFC 5987标准编码文件名 + response.setHeader("Content-disposition", "attachment;filename*=UTF-8''" + encodedFileName); + + // 转换为DTO列表 + List dtoList = devices.stream().map(device -> { + DeviceExcelExportDTO dto = new DeviceExcelExportDTO(); + dto.setId(device.getId()); + dto.setDeviceType(device.getDeviceType()); + dto.setCustomerName(device.getCustomerName()); + dto.setDeviceName(device.getDeviceName()); + dto.setDeviceMac(device.getDeviceMac()); + // 设备IMEI + dto.setDeviceImei(device.getDeviceImei()); + dto.setLongitude(device.getLongitude()); + dto.setLatitude(device.getLatitude()); + dto.setRemark(device.getRemark()); + dto.setTypeName(device.getTypeName()); + dto.setCreateBy(device.getCreateByName()); + Integer deviceStatus = device.getDeviceStatus(); + dto.setDeviceStatus(deviceStatus == 1 ? "正常" : "失效"); + // 时间戳转换 + dto.setCreateTime(DateUtils.format(device.getCreateTime(), "yyyy-MM-dd HH:mm:ss")); + + // 处理图片URL转换 + handleDevicePic(device, dto); + + return dto; + }).collect(Collectors.toList()); + + // 写入Excel + EasyExcel.write(response.getOutputStream(), DeviceExcelExportDTO.class).sheet("设备数据").doWrite(dtoList); + + } catch (IOException e) { + throw new RuntimeException("导出Excel失败", e); + } + } + + + private void handleDevicePic(Device device, DeviceExcelExportDTO dto) { + String picUrl = device.getDevicePic(); + if (picUrl != null && !picUrl.trim().isEmpty()) { + try { + // 尝试创建URL对象(会自动验证格式) + dto.setDevicePic(new URL(picUrl)); + } catch (MalformedURLException e) { + // 不是有效URL时设置为null + dto.setDevicePic(null); + } + } else { + dto.setDevicePic(null); + } + } + +} \ No newline at end of file diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceServiceImpl.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceServiceImpl.java index cd99a56..df9f271 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceServiceImpl.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceServiceImpl.java @@ -4,11 +4,11 @@ import cn.hutool.core.bean.BeanUtil; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.fuyuanshen.common.core.domain.PageResult; -import com.fuyuanshen.common.core.utils.PageUtil; +import com.fuyuanshen.common.core.domain.model.LoginUser; import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; import com.fuyuanshen.common.satoken.utils.LoginHelper; -import com.fuyuanshen.customer.domain.vo.ConsumerVo; +import com.fuyuanshen.customer.domain.Customer; +import com.fuyuanshen.customer.mapper.CustomerMapper; import com.fuyuanshen.equipment.constants.DeviceConstants; import com.fuyuanshen.equipment.domain.Device; import com.fuyuanshen.equipment.domain.DeviceType; @@ -19,8 +19,8 @@ import com.fuyuanshen.equipment.domain.vo.CustomerVo; import com.fuyuanshen.equipment.mapper.DeviceMapper; import com.fuyuanshen.equipment.mapper.DeviceTypeMapper; import com.fuyuanshen.equipment.service.DeviceService; -import com.fuyuanshen.customer.domain.Customer; -import com.fuyuanshen.customer.mapper.CustomerMapper; +import com.fuyuanshen.system.domain.vo.SysOssVo; +import com.fuyuanshen.system.service.ISysOssService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -55,6 +55,8 @@ public class DeviceServiceImpl extends ServiceImpl impleme private final CustomerMapper customerMapper; + private final ISysOssService ossService; + /** * 分页查询设备 @@ -83,6 +85,12 @@ public class DeviceServiceImpl extends ServiceImpl impleme } + @Override + public List queryAll(DeviceQueryCriteria criteria) { + return deviceMapper.findAll(criteria); + } + + /** * 查询所有设备 * @@ -113,13 +121,16 @@ public class DeviceServiceImpl extends ServiceImpl impleme } // 保存图片并获取URL - String imageUrl = saveDeviceImage(deviceForm.getFile(), deviceForm.getDeviceName()); + // String imageUrl = saveDeviceImage(deviceForm.getFile(), deviceForm.getDeviceName()); + SysOssVo upload = ossService.upload(deviceForm.getFile()); // 设置图片路径 - deviceForm.setDevicePic(imageUrl); + deviceForm.setDevicePic(upload.getUrl()); // 转换对象并插入数据库 Device device = new Device(); - device.setCurrentOwnerId(LoginHelper.getUserId()); + LoginUser loginUser = LoginHelper.getLoginUser(); + device.setCurrentOwnerId(loginUser.getUserId()); + device.setCreateByName(loginUser.getNickname()); BeanUtil.copyProperties(deviceForm, device, true); deviceMapper.insert(device); @@ -155,8 +166,10 @@ public class DeviceServiceImpl extends ServiceImpl impleme Device device = devices.get(0); // 处理上传的图片 - String imageUrl = saveDeviceImage(deviceForm.getFile(), device.getDeviceName()); - deviceForm.setDevicePic(imageUrl); + // String imageUrl = saveDeviceImage(deviceForm.getFile(), device.getDeviceName()); + SysOssVo upload = ossService.upload(deviceForm.getFile()); + // 设置图片路径 + deviceForm.setDevicePic(upload.getUrl()); // 更新字段 BeanUtil.copyProperties(deviceForm, device, true); @@ -253,14 +266,14 @@ public class DeviceServiceImpl extends ServiceImpl impleme devices.forEach((device) -> { deviceMapper.updateById(device); - device.setId( null); + device.setId(null); device.setCurrentOwnerId(customerId); - deviceMapper.insert( device); + deviceMapper.insert(device); DeviceType deviceType = deviceTypeMapper.selectById(device.getDeviceType()); - deviceType.setId( null); + deviceType.setId(null); device.setCurrentOwnerId(customerId); - deviceTypeMapper.insert( deviceType); + deviceTypeMapper.insert(deviceType); }); } diff --git a/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml b/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml index f071704..8879dae 100644 --- a/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml +++ b/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml @@ -38,10 +38,7 @@ - -