src/main/kotlin/com/flightfeather/uav/common/utils/FileExchange.kt
@@ -2,6 +2,7 @@ import com.alibaba.fastjson.JSONObject import com.flightfeather.uav.common.exception.BizException import com.flightfeather.uav.domain.entity.GridDataDetail import com.flightfeather.uav.domain.entity.RealTimeData import com.flightfeather.uav.domain.entity.RealTimeDataVehicle import com.flightfeather.uav.socket.bean.AirData @@ -93,6 +94,52 @@ } /** * 转æ¢ä¸ºPM2.5è¡¨æ ¼æ°æ® */ fun exchangeGridData(file: InputStream): List<GridDataDetail> { val headers = listOf( "pointid", "PM2.5" ) val result = mutableListOf<GridDataDetail>() try { ExcelUtil.readXLXS(file, headerCheck = { val cellIterator = it.cellIterator() val headIterator = headers.iterator() while (headIterator.hasNext()) { val head = headIterator.next() if (cellIterator.hasNext()) { val cellText = cellIterator.next().stringCellValue if (!cellText.equals(head)) { throw BizException("æä»¶æ ¼å¼é误, 表头[${head}]åºè¯¥ä¸º[${cellText}]") } } else { throw BizException("æä»¶æ ¼å¼é误, 表头[${head}]缺失") } } true }, onRow = { val data = GridDataDetail().apply { try { this.cellId = it.getCell(0)?.numericCellValue?.toInt() } catch (e: Exception) { throw BizException("åå æ ¼[${it.rowNum}${0}]䏿¯æ°åç±»å") } try { this.pm25 = it.getCell(1)?.numericCellValue?.toFloat() } catch (e: Exception) { throw BizException("åå æ ¼[${it.rowNum}${1}]䏿¯æ°åç±»å") } } result.add(data) }) } catch (e: BizException) { throw e } return result } /** * 转æ¢è½¦è½½èµ°èªæ°æ® */ fun exchangeVehicleData(deviceCode: String, file: InputStream): List<RealTimeDataVehicle> { src/main/kotlin/com/flightfeather/uav/domain/entity/GridData.java
@@ -6,6 +6,7 @@ @Table(name = "grid_data") public class GridData { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; /** src/main/kotlin/com/flightfeather/uav/domain/mapper/GridDataDetailMapper.kt
@@ -5,4 +5,6 @@ import org.apache.ibatis.annotations.Mapper @Mapper interface GridDataDetailMapper : MyMapper<GridDataDetail?> interface GridDataDetailMapper : MyMapper<GridDataDetail?> { fun updatePM25Batch(gridDataDetails: List<GridDataDetail>) } src/main/kotlin/com/flightfeather/uav/domain/repository/SatelliteGridRep.kt
@@ -59,4 +59,17 @@ orderBy("cellId") }) } fun insertGridDataAndDetail(data: GridData, gridDataDetails: List<GridDataDetail>) { gridDataMapper.insert(data) gridDataDetails.forEach { it.dataId = data.id it.groupId = data.groupId } gridDataDetailMapper.insertList(gridDataDetails) } fun updatePM25Batch(gridDataDetails: List<GridDataDetail>) { gridDataDetailMapper.updatePM25Batch(gridDataDetails) } } src/main/kotlin/com/flightfeather/uav/lightshare/bean/GridDataImportResult.kt
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,12 @@ package com.flightfeather.uav.lightshare.bean import com.fasterxml.jackson.annotation.JsonInclude /** * ç½æ ¼æ°æ®å¯¼å ¥å¤çç»æ */ @JsonInclude(JsonInclude.Include.NON_NULL) data class GridDataImportResult( val success: Boolean, val result: String ) src/main/kotlin/com/flightfeather/uav/lightshare/service/SatelliteTelemetryService.kt
@@ -1,12 +1,16 @@ package com.flightfeather.uav.lightshare.service import com.flightfeather.uav.common.exception.BizException import com.flightfeather.uav.domain.entity.GridCell import com.flightfeather.uav.domain.entity.GridData import com.flightfeather.uav.domain.entity.GridDataDetail import com.flightfeather.uav.domain.entity.GridGroup import com.flightfeather.uav.lightshare.bean.AreaVo import com.flightfeather.uav.lightshare.bean.DataHead import com.flightfeather.uav.lightshare.bean.GridDataImportResult import org.springframework.web.multipart.MultipartFile import java.time.LocalDateTime import javax.servlet.http.HttpServletResponse /** * @@ -22,4 +26,9 @@ fun fetchGridData(groupId: Int, dataTime: LocalDateTime?, type: Int?): List<GridData?> fun fetchGridDataDetail(dataId: Int, groupId: Int?, cellId: Int?): List<GridDataDetail?> @Throws(BizException::class) fun importGridData(groupId: Int, type: Int?, dataTime: LocalDateTime?, update: Int?, file: MultipartFile): GridDataImportResult? fun downloadTemplate(response: HttpServletResponse): Boolean } src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteTelemetryServiceImpl.kt
@@ -1,5 +1,7 @@ package com.flightfeather.uav.lightshare.service.impl import com.flightfeather.uav.common.exception.BizException import com.flightfeather.uav.common.utils.FileExchange import com.flightfeather.uav.domain.entity.GridCell import com.flightfeather.uav.domain.entity.GridData import com.flightfeather.uav.domain.entity.GridDataDetail @@ -7,10 +9,17 @@ import com.flightfeather.uav.domain.repository.SatelliteGridRep import com.flightfeather.uav.lightshare.bean.AreaVo import com.flightfeather.uav.lightshare.bean.DataHead import com.flightfeather.uav.lightshare.bean.GridDataImportResult import com.flightfeather.uav.lightshare.service.SatelliteTelemetryService import com.github.pagehelper.PageHelper import org.springframework.stereotype.Service import org.springframework.web.multipart.MultipartFile import java.io.ByteArrayInputStream import java.io.File import java.time.LocalDateTime import java.time.ZoneId import java.util.* import javax.servlet.http.HttpServletResponse /** * @@ -20,6 +29,7 @@ @Service class SatelliteTelemetryServiceImpl(private val satelliteGridRep: SatelliteGridRep) : SatelliteTelemetryService { private val fileExchange = FileExchange() override fun fetchGridGroup(areaVo: AreaVo, page: Int?, perPage: Int?): Pair<DataHead, List<GridGroup?>> { val pageInfo = PageHelper.startPage<GridGroup>(page ?: 1, perPage ?: 100) val res = satelliteGridRep.fetchGridGroup(areaVo) @@ -37,4 +47,65 @@ override fun fetchGridDataDetail(dataId: Int, groupId: Int?, cellId: Int?): List<GridDataDetail?> { return satelliteGridRep.fetchGridDataDetail(dataId, groupId, cellId) } override fun importGridData(groupId: Int, type: Int?, dataTime: LocalDateTime?, update: Int?, file: MultipartFile): GridDataImportResult? { val gridData = satelliteGridRep.fetchGridData(groupId, dataTime, type) if (!file.contentType!!.startsWith("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) { throw BizException("æä»¶ç±»åé误ï¼è¯·ä¸ä¼ xlsxç±»åæä»¶") } if (gridData.isNotEmpty() && update == 0) { return GridDataImportResult(false, "æ°æ®åºå¯¹åºç½æ ¼ç»åæ¥æä¸å·²åå¨é¥æµæ°æ®") } val exchangeGridDataDetails = fileExchange.exchangeGridData(ByteArrayInputStream(file.bytes)) val gridCellsInDB = satelliteGridRep.fetchGridCell(groupId) val setA = gridCellsInDB.asSequence().map { it?.id ?: -1 }.toSet() val setB = exchangeGridDataDetails.asSequence().map { it.cellId ?: -1 }.toSet() // excel ä¸ç¼ºå°ççåå æ ¼ val onlyInA = setA - setB // excel ä¸å¤åºççåå æ ¼ val onlyInB = setB - setA if (onlyInA.isNotEmpty()) { throw BizException("å¯¼å ¥æ°æ®ä¸ç¼ºå°ä»¥ä¸ç½æ ¼åå æ ¼ï¼${onlyInA.joinToString(",")}") } if (onlyInB.isNotEmpty()) { throw BizException("å¯¼å ¥æ°æ®ä¸æå¤ä½ç½æ ¼åå æ ¼ï¼${onlyInB.joinToString(",")}") } if (update == 1) { exchangeGridDataDetails.forEach { it.dataId = gridData[0]?.id it.groupId = gridData[0]?.groupId } satelliteGridRep.updatePM25Batch(exchangeGridDataDetails) return GridDataImportResult(true, "è¦çæå") } val gridDataEntity = GridData() gridDataEntity.groupId = groupId gridDataEntity.dataTime = dataTime?.atZone(ZoneId.systemDefault())?.toInstant()?.toEpochMilli() ?.let { Date(it) } gridDataEntity.type = type?.toByte() satelliteGridRep.insertGridDataAndDetail(gridDataEntity, exchangeGridDataDetails) return GridDataImportResult(true, "å¯¼å ¥æå") } override fun downloadTemplate(response: HttpServletResponse): Boolean { val fileName = "GridData-PM2.5-Template.xlsx" val path = (Thread.currentThread().contextClassLoader?.getResource("/")?.path ?: "src/main/resources") + "/templates/" + fileName val file = File(path) if (file.exists()) { val fName = Base64.getEncoder().encodeToString(fileName.toByteArray()) response.apply { setHeader("Content-Disposition", "attachment;filename=$fName") setHeader("fileName", fName) addHeader("Access-Control-Expose-Headers", "fileName") contentType = "application/vnd.ms-excel;charset=UTF-8" setHeader("Pragma", "no-cache") setHeader("Cache-Control", "no-cache") setDateHeader("Expires", 0) } response.outputStream.write(file.readBytes()) } return true } } src/main/kotlin/com/flightfeather/uav/lightshare/web/SatelliteTelemetryController.kt
@@ -7,7 +7,11 @@ import io.swagger.annotations.ApiOperation import io.swagger.annotations.ApiParam import org.springframework.web.bind.annotation.* import org.springframework.web.multipart.MultipartFile import springfox.documentation.annotations.ApiIgnore import java.time.LocalDateTime import java.time.format.DateTimeFormatter import javax.servlet.http.HttpServletResponse /** * 嫿饿µ @@ -49,4 +53,22 @@ @ApiParam("ç½æ ¼ç»id") @RequestParam(required = false) groupId: Int?, @ApiParam("ç½æ ¼åå æ ¼id") @RequestParam(required = false) cellId: Int?, ) = resPack { satelliteTelemetryService.fetchGridDataDetail(dataId, groupId, cellId) } @ApiOperation(value = "å¯¼å ¥å«æé¥æµPM2.5ç»ææ°æ®") @PostMapping("/import/grid/data") fun importGridData( @ApiParam("ç½æ ¼ç»id") @RequestParam groupId: Int, @ApiParam("饿µæ°æ®ç±»å", allowableValues = "0ï¼åå§å«æé¥æµæ°æ®ï¼1ï¼èåæ°æ®") @RequestParam(required = false) type: Int?, @ApiParam("饿µæ°æ®æ¶é´") @RequestParam @JsonFormat(pattern = "YYYY-MM-DD HH:mm:ss") dateTime: String?, @ApiParam("è¦çæ§æ°æ® 0: ä¸è¦ç 1: è¦ç") @RequestParam update: Int?, @RequestParam("excel") file: MultipartFile, ) = resPack { satelliteTelemetryService.importGridData(groupId, type, LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), update, file) } @ApiOperation(value = "ä¸è½½å«æé¥æµPM2.5ç»ææ°æ®å¯¼å ¥æ¨¡æ¿") @GetMapping("/import/grid/data/download/template") fun downloadTemplate(@ApiIgnore response: HttpServletResponse) = satelliteTelemetryService.downloadTemplate(response) } src/main/resources/mapper/GridDataDetailMapper.xml
@@ -18,4 +18,15 @@ --> id, data_id, group_id, cell_id, PM25, rank </sql> <!-- æ·»å æ¹éæ´æ°PM25ç彿° --> <update id="updatePM25Batch" parameterType="java.util.List"> <foreach collection="list" item="item" separator=";"> UPDATE grid_data_detail SET PM25 = #{item.pm25} WHERE data_id = #{item.dataId} AND group_id = #{item.groupId} AND cell_id = #{item.cellId} </foreach> </update> </mapper> src/main/resources/templates/GridData-PM2.5-Template.xlsxBinary files differ
src/test/kotlin/com/flightfeather/uav/common/utils/FileExchangeTest.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,198 @@ package com.flightfeather.uav.common.utils; import com.flightfeather.uav.common.exception.BizException; import com.flightfeather.uav.domain.entity.GridDataDetail; import com.flightfeather.uav.lightshare.service.SatelliteTelemetryService; import org.apache.commons.fileupload.disk.DiskFileItem; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.web.multipart.commons.CommonsMultipartFile; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URL; import java.time.LocalDateTime; import java.util.List; import java.util.Objects; import java.util.function.Function; import static org.junit.Assert.assertEquals; @RunWith(SpringRunner.class) @SpringBootTest public class FileExchangeTest { @Autowired private SatelliteTelemetryService satelliteTelemetryService; public void start() throws BizException, IOException { test1(); test2(); test3(); test4(); test5(); test6(); test7(); } // 第ä¸åæ°åç±»åé误 @Test public void test1() throws IOException, BizException { URL resource = getClass().getClassLoader().getResource("templates/GridData-1_type_error.xlsx"); if (resource != null) { System.out.println(resource.getPath()); // å建æä»¶è¾å ¥æµ FileInputStream inputStream = new FileInputStream(new File(resource.getPath())); // å建MockMultipartFile对象 MockMultipartFile multipartFile = new MockMultipartFile("file", "111.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", inputStream); try { satelliteTelemetryService.importGridData(1, 1, LocalDateTime.of(2029, 7, 29, 0, 0), 0, multipartFile); }catch (BizException e) { // éªè¯å¼å¸¸æ¶æ¯æ¯å¦ä¸é¢æç¸ç¬¦ if (!e.getMessage().contains("䏿¯æ°åç±»å")) { System.out.println(e.getMessage()); throw e; } } } else { System.out.println("èµæºæä»¶æªæ¾å°"); } } // 第äºåæ°åç±»åé误 @Test public void test2() throws IOException, BizException { URL resource = getClass().getClassLoader().getResource("templates/GridData-2_type_error.xlsx"); if (resource != null) { System.out.println(resource.getPath()); // å建æä»¶è¾å ¥æµ FileInputStream inputStream = new FileInputStream(new File(resource.getPath())); // å建MockMultipartFile对象 MockMultipartFile multipartFile = new MockMultipartFile("file", "111.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", inputStream); try { satelliteTelemetryService.importGridData(1, 1, LocalDateTime.of(2029, 7, 29, 0, 0), 0, multipartFile); }catch (BizException e) { // éªè¯å¼å¸¸æ¶æ¯æ¯å¦ä¸é¢æç¸ç¬¦ if (!e.getMessage().contains("䏿¯æ°åç±»å")) { System.out.println(e.getMessage()); throw e; } } } else { System.out.println("èµæºæä»¶æªæ¾å°"); } } // ç½æ ¼ç¼å·è¶çé误 @Test public void test3() throws IOException, BizException { URL resource = getClass().getClassLoader().getResource("templates/GridData-index_out.xlsx"); if (resource != null) { System.out.println(resource.getPath()); // å建æä»¶è¾å ¥æµ FileInputStream inputStream = new FileInputStream(new File(resource.getPath())); // å建MockMultipartFile对象 MockMultipartFile multipartFile = new MockMultipartFile("file", "111.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", inputStream); try { satelliteTelemetryService.importGridData(1, 1, LocalDateTime.of(2029, 7, 29, 0, 0), 0, multipartFile); }catch (BizException e) { // éªè¯å¼å¸¸æ¶æ¯æ¯å¦ä¸é¢æç¸ç¬¦ if (!e.getMessage().contains("å¯¼å ¥æ°æ®ä¸æå¤ä½ç½æ ¼åå æ ¼")) { System.out.println(e.getMessage()); throw e; } } } else { System.out.println("èµæºæä»¶æªæ¾å°"); } } // ç½æ ¼ç¼å·ç¼ºå¤±é误 @Test public void test4() throws IOException, BizException { URL resource = getClass().getClassLoader().getResource("templates/GridData-index_short.xlsx"); if (resource != null) { System.out.println(resource.getPath()); // å建æä»¶è¾å ¥æµ FileInputStream inputStream = new FileInputStream(new File(resource.getPath())); // å建MockMultipartFile对象 MockMultipartFile multipartFile = new MockMultipartFile("file", "111.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", inputStream); try { satelliteTelemetryService.importGridData(1, 1, LocalDateTime.of(2029, 7, 29, 0, 0), 0, multipartFile); }catch (BizException e) { // éªè¯å¼å¸¸æ¶æ¯æ¯å¦ä¸é¢æç¸ç¬¦ if (!e.getMessage().contains("å¯¼å ¥æ°æ®ä¸ç¼ºå°ä»¥ä¸ç½æ ¼åå æ ¼")) { System.out.println(e.getMessage()); throw e; } } } else { System.out.println("èµæºæä»¶æªæ¾å°"); } } // æä»¶ç±»åé误 @Test public void test5() throws IOException, BizException { URL resource = getClass().getClassLoader().getResource("templates/GridData-fileType-error.txt"); if (resource != null) { System.out.println(resource.getPath()); // å建æä»¶è¾å ¥æµ FileInputStream inputStream = new FileInputStream(new File(resource.getPath())); // å建MockMultipartFile对象 MockMultipartFile multipartFile = new MockMultipartFile("file", "111.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", inputStream); try { satelliteTelemetryService.importGridData(1, 1, LocalDateTime.of(2029, 7, 29, 0, 0), 0, multipartFile); }catch (BizException e) { // éªè¯å¼å¸¸æ¶æ¯æ¯å¦ä¸é¢æç¸ç¬¦ if (!e.getMessage().contains("å¯¼å ¥æ°æ®ä¸ç¼ºå°ä»¥ä¸ç½æ ¼åå æ ¼")) { System.out.println(e.getMessage()); throw e; } } } else { System.out.println("èµæºæä»¶æªæ¾å°"); } } // æ°å¢æ°æ®å¯¼å ¥æå @Test public void test6() throws IOException, BizException { URL resource = getClass().getClassLoader().getResource("templates/GridData-success-insert.xlsx"); if (resource != null) { System.out.println(resource.getPath()); // å建æä»¶è¾å ¥æµ FileInputStream inputStream = new FileInputStream(new File(resource.getPath())); // å建MockMultipartFile对象 MockMultipartFile multipartFile = new MockMultipartFile("file", "111.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", inputStream); try { satelliteTelemetryService.importGridData(1, 1, LocalDateTime.of(2029, 7, 29, 0, 0), 0, multipartFile); }catch (BizException e) { throw e; } } else { System.out.println("èµæºæä»¶æªæ¾å°"); } } // æ´æ°æ°æ®å¯¼å ¥æå @Test public void test7() throws IOException, BizException { URL resource = getClass().getClassLoader().getResource("templates/GridData-success-update.xlsx"); if (resource != null) { System.out.println(resource.getPath()); // å建æä»¶è¾å ¥æµ FileInputStream inputStream = new FileInputStream(new File(resource.getPath())); // å建MockMultipartFile对象 MockMultipartFile multipartFile = new MockMultipartFile("file", "111.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", inputStream); try { satelliteTelemetryService.importGridData(1, 1, LocalDateTime.of(2029, 7, 29, 0, 0), 1, multipartFile); }catch (BizException e) { throw e; } } else { System.out.println("èµæºæä»¶æªæ¾å°"); } } } src/test/resources/templates/GridData-1_type_error.xlsxBinary files differ
src/test/resources/templates/GridData-2_type_error.xlsxBinary files differ
src/test/resources/templates/GridData-fileType-error.txtBinary files differ
src/test/resources/templates/GridData-index_out.xlsxBinary files differ
src/test/resources/templates/GridData-index_short.xlsxBinary files differ
src/test/resources/templates/GridData-success-insert.xlsxBinary files differ
src/test/resources/templates/GridData-success-update.xlsxBinary files differ