Prechádzať zdrojové kódy

增加文件上传2

gjs 4 rokov pred
rodič
commit
5ce177084a
29 zmenil súbory, kde vykonal 893 pridanie a 27 odobranie
  1. 9 0
      pom.xml
  2. 1 1
      src/main/java/com/macro/mall/tiny/common/api/ResultCode.java
  3. 24 0
      src/main/java/com/macro/mall/tiny/common/config/WebConfig.java
  4. 29 0
      src/main/java/com/macro/mall/tiny/common/util/CommonUtils.java
  5. 2 2
      src/main/java/com/macro/mall/tiny/common/util/MyFileUtils.java
  6. 1 1
      src/main/java/com/macro/mall/tiny/common/util/UploadUtils.java
  7. 192 0
      src/main/java/com/macro/mall/tiny/common/util/ZipUtils.java
  8. 45 0
      src/main/java/com/macro/mall/tiny/config/AsyncConfig.java
  9. 21 0
      src/main/java/com/macro/mall/tiny/modules/business/controller/BLineUploadLogController.java
  10. 38 9
      src/main/java/com/macro/mall/tiny/modules/business/controller/FileController.java
  11. 46 0
      src/main/java/com/macro/mall/tiny/modules/business/converter/EnumConvertFactory.java
  12. 9 0
      src/main/java/com/macro/mall/tiny/modules/business/dto/FileUploadParam.java
  13. 28 0
      src/main/java/com/macro/mall/tiny/modules/business/enume/DirectoryEnum.java
  14. 10 0
      src/main/java/com/macro/mall/tiny/modules/business/enume/IEnum.java
  15. 16 0
      src/main/java/com/macro/mall/tiny/modules/business/mapper/BLineUploadLogMapper.java
  16. 5 2
      src/main/java/com/macro/mall/tiny/modules/business/model/BLine.java
  17. 49 0
      src/main/java/com/macro/mall/tiny/modules/business/model/BLineUploadLog.java
  18. 1 1
      src/main/java/com/macro/mall/tiny/modules/business/model/BProvince.java
  19. 5 2
      src/main/java/com/macro/mall/tiny/modules/business/model/BTower.java
  20. 26 0
      src/main/java/com/macro/mall/tiny/modules/business/model/TowerExcelModel.java
  21. 16 0
      src/main/java/com/macro/mall/tiny/modules/business/service/BLineUploadLogService.java
  22. 2 1
      src/main/java/com/macro/mall/tiny/modules/business/service/FileService.java
  23. 216 0
      src/main/java/com/macro/mall/tiny/modules/business/service/impl/AsyncHandler.java
  24. 20 0
      src/main/java/com/macro/mall/tiny/modules/business/service/impl/BLineUploadLogServiceImpl.java
  25. 49 5
      src/main/java/com/macro/mall/tiny/modules/business/service/impl/FileServiceImpl.java
  26. 11 1
      src/main/resources/application.yml
  27. BIN
      src/main/resources/excel-template/杆塔信息录入.xlsx
  28. 7 2
      src/main/resources/mapper/business/BLineMapper.xml
  29. 15 0
      src/main/resources/mapper/business/BLineUploadLogMapper.xml

+ 9 - 0
pom.xml

@@ -142,6 +142,15 @@
             <artifactId>velocity-engine-core</artifactId>
             <version>${velocity.version}</version>
         </dependency>
+
+        <!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>easyexcel</artifactId>
+            <version>2.2.6</version>
+        </dependency>
+
+
     </dependencies>
 
     <build>

+ 1 - 1
src/main/java/com/macro/mall/tiny/common/api/ResultCode.java

@@ -13,7 +13,7 @@ public enum ResultCode implements IErrorCode {
     private long code;
     private String message;
 
-    private ResultCode(long code, String message) {
+    ResultCode(long code, String message) {
         this.code = code;
         this.message = message;
     }

+ 24 - 0
src/main/java/com/macro/mall/tiny/common/config/WebConfig.java

@@ -0,0 +1,24 @@
+package com.macro.mall.tiny.common.config;
+
+import com.macro.mall.tiny.modules.business.converter.EnumConvertFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.format.FormatterRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * @author gjs
+ * @description
+ * @date 2021/3/27 15:54
+ */
+@Configuration
+public class WebConfig implements WebMvcConfigurer {
+
+    @Autowired
+    private EnumConvertFactory enumConvertFactory;
+
+    @Override
+    public void addFormatters(FormatterRegistry registry) {
+        registry.addConverterFactory(enumConvertFactory);
+    }
+}

+ 29 - 0
src/main/java/com/macro/mall/tiny/common/util/CommonUtils.java

@@ -0,0 +1,29 @@
+package com.macro.mall.tiny.common.util;
+
+import org.apache.logging.log4j.util.Strings;
+
+import java.math.BigDecimal;
+
+/**
+ * @author gjs
+ * @description
+ * @date 2021/3/28 15:51
+ */
+public class CommonUtils {
+
+    public static BigDecimal Dms2D(String jwd) {
+        if (Strings.isNotEmpty(jwd) && (jwd.contains("°"))) {//如果不为空并且存在度单位
+            //计算前进行数据处理
+            jwd = jwd.replace("E", "").replace("N", "").replace(":", "").replace(":", "");
+            //使用BigDecimal进行加减乘除
+            BigDecimal bd = new BigDecimal("60");
+            BigDecimal d = new BigDecimal(jwd.contains("°") ? jwd.split("°")[0] : "0");
+            BigDecimal m = new BigDecimal(jwd.contains("′") ? jwd.split("°")[1].split("′")[0] : "0");
+            BigDecimal s = new BigDecimal(jwd.contains("″") ? jwd.split("′")[1].split("″")[0] : "0");
+            //divide相除可能会报错(无限循环小数),要设置保留小数点
+            return d.add(m.divide(bd, 7, BigDecimal.ROUND_HALF_UP)
+                    .add(s.divide(bd.multiply(bd), 7, BigDecimal.ROUND_HALF_UP)));
+        }
+        return new BigDecimal(jwd);
+    }
+}

+ 2 - 2
src/main/java/com/macro/mall/tiny/common/util/FileUtils.java → src/main/java/com/macro/mall/tiny/common/util/MyFileUtils.java

@@ -9,7 +9,7 @@ import java.util.UUID;
 /**
  * 文件操作工具类
  */
-public class FileUtils {
+public class MyFileUtils {
 
     /**
      * 写入文件
@@ -38,7 +38,7 @@ public class FileUtils {
      * @param chunk
      * @throws IOException
      */
-    public static void writeWithBlok(String target, Long targetSize, InputStream src, Long srcSize, Integer chunks, Integer chunk) throws IOException {
+    public static void writeWithBlock(String target, Long targetSize, InputStream src, Long srcSize, Integer chunks, Integer chunk) throws IOException {
         RandomAccessFile randomAccessFile = new RandomAccessFile(target,"rw");
         randomAccessFile.setLength(targetSize);
         if (chunk == chunks - 1 && chunk != 0) {

+ 1 - 1
src/main/java/com/macro/mall/tiny/common/util/UploadUtils.java

@@ -3,7 +3,7 @@ package com.macro.mall.tiny.common.util;
 import java.util.HashMap;
 import java.util.Map;
 
-import static com.macro.mall.tiny.common.util.FileUtils.generateFileName;
+import static com.macro.mall.tiny.common.util.MyFileUtils.generateFileName;
 
 
 /**

+ 192 - 0
src/main/java/com/macro/mall/tiny/common/util/ZipUtils.java

@@ -0,0 +1,192 @@
+package com.macro.mall.tiny.common.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.nio.file.*;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.LinkedList;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+public class ZipUtils {
+
+    public static void main(String[] args) throws IOException {
+        ZipUtils.unPacket(Paths.get("E:/WorkSpace/doc-manager-master/temp/四川.zip"), Paths.get("E:/WorkSpace/doc-manager-master/power"), "gbk");
+    }
+
+    /**
+     * 解压文件并录入对应目录
+     *
+     * @param file      压缩文件
+     * @param targetDir 解压文件输出的目录
+     * @throws IOException
+     */
+    public static void unPacket(Path file, Path targetDir, String charset) throws IOException {
+        if (!Files.exists(targetDir)) {
+            Files.createDirectories(targetDir);
+        }
+        // 创建zip对象
+        try (ZipFile zipFile = new ZipFile(file.toFile(), Charset.forName(charset))) {
+            // 读取zip流
+            try (ZipInputStream zipInputStream = new ZipInputStream(Files.newInputStream(file), Charset.forName(charset))) {
+                ZipEntry zipEntry;
+                // 遍历每一个zip项
+                while ((zipEntry = zipInputStream.getNextEntry()) != null) {
+                    // 获取zip项目名称
+                    String entryName = zipEntry.getName();
+                    System.out.println(entryName);
+                    // 构建绝对路径
+                    Path entryFile = targetDir.resolve(entryName);
+                    if (zipEntry.isDirectory()) {    // 文件夹
+                        if (!Files.isDirectory(entryFile)) {
+                            Files.createDirectories(entryFile);
+                        }
+                    } else {                            // 文件
+                        if (Files.exists(entryFile)) {
+                            continue;
+                        }
+                        // 读取zip项数据流
+                        try (InputStream zipEntryInputStream = zipFile.getInputStream(zipEntry)) {
+                            try (OutputStream fileOutputStream = Files.newOutputStream(entryFile, StandardOpenOption.CREATE_NEW)) {
+                                byte[] buffer = new byte[2048];
+                                int length;
+                                while ((length = zipEntryInputStream.read(buffer)) != -1) {
+                                    fileOutputStream.write(buffer, 0, length);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 压缩指定的文件
+     *
+     * @param files   目标文件
+     * @param zipFile 生成的压缩文件
+     * @throws IOException
+     */
+    public static void packet(Path[] files, Path zipFile) throws IOException {
+        OutputStream outputStream = Files.newOutputStream(zipFile, StandardOpenOption.CREATE_NEW);
+        ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
+        try {
+            for (Path file : files) {
+                if (Files.isDirectory(file)) {
+                    continue;
+                }
+                try (InputStream inputStream = Files.newInputStream(file)) {
+                    // 创建一个压缩项,指定名称
+                    ZipEntry zipEntry = new ZipEntry(file.getFileName().toString());
+                    // 添加到压缩流
+                    zipOutputStream.putNextEntry(zipEntry);
+                    // 写入数据
+                    int len = 0;
+                    byte[] buffer = new byte[1024 * 10];
+                    while ((len = inputStream.read(buffer)) > 0) {
+                        zipOutputStream.write(buffer, 0, len);
+                    }
+                    zipOutputStream.flush();
+                }
+            }
+            // 完成所有压缩项的添加
+            zipOutputStream.closeEntry();
+        } finally {
+            zipOutputStream.close();
+            outputStream.close();
+        }
+    }
+
+    /**
+     * 压缩指定的目录
+     *
+     * @param folder
+     * @param zipFile
+     * @throws IOException
+     */
+    public static void packet(Path folder, Path zipFile) throws IOException {
+        if (!Files.isDirectory(folder)) {
+            throw new IllegalArgumentException(folder.toString() + " 不是合法的文件夹");
+        }
+        OutputStream outputStream = Files.newOutputStream(zipFile, StandardOpenOption.CREATE_NEW);
+        ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
+
+        LinkedList<String> path = new LinkedList<>();
+
+        try {
+            Files.walkFileTree(folder, new FileVisitor<Path>() {
+
+                @Override
+                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
+
+                    if (!dir.equals(folder)) {
+                        // 开始遍历目录
+                        String folder = dir.getFileName().toString();
+                        path.addLast(folder);
+                        // 写入目录
+                        ZipEntry zipEntry = new ZipEntry(path.stream().collect(Collectors.joining("/", "", "/")));
+                        try {
+                            zipOutputStream.putNextEntry(zipEntry);
+                            zipOutputStream.flush();
+                        } catch (IOException e) {
+                            throw new RuntimeException(e);
+                        }
+                    }
+                    return FileVisitResult.CONTINUE;
+                }
+
+                @Override
+                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                    // 开始遍历文件
+                    try (InputStream inputStream = Files.newInputStream(file)) {
+
+                        // 创建一个压缩项,指定名称
+                        String fileName = path.size() > 0
+                                ? path.stream().collect(Collectors.joining("/", "", "")) + "/" + file.getFileName().toString()
+                                : file.getFileName().toString();
+
+                        ZipEntry zipEntry = new ZipEntry(fileName);
+
+                        // 添加到压缩流
+                        zipOutputStream.putNextEntry(zipEntry);
+                        // 写入数据
+                        int len = 0;
+                        byte[] buffer = new byte[1024 * 10];
+                        while ((len = inputStream.read(buffer)) > 0) {
+                            zipOutputStream.write(buffer, 0, len);
+                        }
+
+                        zipOutputStream.flush();
+                    } catch (IOException e) {
+                        throw new RuntimeException(e);
+                    }
+                    return FileVisitResult.CONTINUE;
+                }
+
+                @Override
+                public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
+                    return FileVisitResult.CONTINUE;
+                }
+
+                @Override
+                public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+                    // 结束遍历目录
+                    if (!path.isEmpty()) {
+                        path.removeLast();
+                    }
+                    return FileVisitResult.CONTINUE;
+                }
+            });
+            zipOutputStream.closeEntry();
+        } finally {
+            zipOutputStream.close();
+            outputStream.close();
+        }
+    }
+}

+ 45 - 0
src/main/java/com/macro/mall/tiny/config/AsyncConfig.java

@@ -0,0 +1,45 @@
+package com.macro.mall.tiny.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.AsyncConfigurer;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadPoolExecutor;
+
+@Component
+@Slf4j
+public class AsyncConfig implements AsyncConfigurer {
+
+    @Value("${thread.pool.corePoolSize:10}")
+    private int corePoolSize;
+
+    @Value("${thread.pool.maxPoolSize:20}")
+    private int maxPoolSize;
+
+    @Value("${thread.pool.keepAliveSeconds:5}")
+    private int keepAliveSeconds;
+
+    @Value("${thread.pool.queueCapacity:512}")
+    private int queueCapacity;
+
+    @Override
+    public Executor getAsyncExecutor() {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        executor.setCorePoolSize(corePoolSize);
+        executor.setMaxPoolSize(maxPoolSize);
+        executor.setKeepAliveSeconds(keepAliveSeconds);
+        executor.setQueueCapacity(queueCapacity);
+        executor.setRejectedExecutionHandler((Runnable r, ThreadPoolExecutor exe) -> log.warn("当前任务线程池队列已满."));
+        executor.initialize();
+        return executor;
+    }
+
+    @Override
+    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
+        return (ex, method, params) -> log.error("线程池执行任务发生未知异常.", ex);
+    }
+}

+ 21 - 0
src/main/java/com/macro/mall/tiny/modules/business/controller/BLineUploadLogController.java

@@ -0,0 +1,21 @@
+package com.macro.mall.tiny.modules.business.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author macro
+ * @since 2021-03-28
+ */
+@RestController
+@RequestMapping("/business/bLineUploadLog")
+public class BLineUploadLogController {
+
+}
+

+ 38 - 9
src/main/java/com/macro/mall/tiny/modules/business/controller/FileController.java

@@ -2,18 +2,26 @@ package com.macro.mall.tiny.modules.business.controller;
 
 import com.macro.mall.tiny.common.api.CommonResult;
 import com.macro.mall.tiny.config.UploadConfig;
+import com.macro.mall.tiny.modules.business.dto.FileUploadParam;
 import com.macro.mall.tiny.modules.business.service.FileService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.apache.tomcat.util.http.fileupload.IOUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.ClassPathResource;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
+import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.*;
+import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
+import java.security.Principal;
 
 /**
  * 大文件上传
@@ -38,20 +46,24 @@ public class FileController {
      */
     @ApiOperation("文件上传接口")
     @PostMapping("/upload")
-    public void upload(String name,
-                       Long size,
-                       Integer chunks,
-                       Integer chunk,
-                       MultipartFile file) throws IOException {
+    public void upload(FileUploadParam fileUploadParam, Principal principal) throws IOException {
+        String name = fileUploadParam.getName();
+        String lineName = fileUploadParam.getLineName();
+        Long provinceId = fileUploadParam.getProvince();
+        Long size = fileUploadParam.getSize();
+        Integer chunks = fileUploadParam.getChunks();
+        Integer chunk = fileUploadParam.getChunk();
+        MultipartFile file = fileUploadParam.getFile();
+
         if (chunks != null && chunks != 0) {
-            fileService.uploadWithBlock(name, size, chunks, chunk, file);
+            fileService.uploadWithBlock(name, lineName, provinceId, size, chunks, chunk, file, principal);
         } else {
             fileService.upload(file);
         }
     }
 
     @ApiOperation("文件下载接口")
-    @PostMapping("/download")
+    @GetMapping("/download")
     public Object downloadFile(@RequestParam String fileName, final HttpServletResponse response) {
         OutputStream os = null;
         InputStream is = null;
@@ -61,8 +73,7 @@ public class FileController {
             // 清空输出流
             response.reset();
             response.setContentType("application/x-download;charset=UTF-8");
-            response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
-//            response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
+            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
             //读取流
             File f = new File(UploadConfig.path + fileName);
             is = new FileInputStream(f);
@@ -91,4 +102,22 @@ public class FileController {
         }
         return null;
     }
+
+    /**
+     * 下载模板
+     */
+    @ApiOperation("下载杆塔信息录入模板")
+    @GetMapping("/downloadTemplate")
+    public void downloadTemplate(HttpServletResponse response) throws Exception {
+        ClassPathResource classPathResource = new ClassPathResource("excel-template/杆塔信息录入.xlsx");
+        InputStream inputStream = classPathResource.getInputStream();
+        Workbook workbook = new XSSFWorkbook(inputStream);
+        response.setContentType("application/vnd.ms-excel");
+        response.setHeader("content-Disposition", "attachment;filename=" + URLEncoder.encode("杆塔信息录入.xlsx", "utf-8"));
+        response.setHeader("Access-Control-Expose-Headers", "content-Disposition");
+        OutputStream outputStream = response.getOutputStream();
+        workbook.write(outputStream);
+        outputStream.flush();
+        outputStream.close();
+    }
 }

+ 46 - 0
src/main/java/com/macro/mall/tiny/modules/business/converter/EnumConvertFactory.java

@@ -0,0 +1,46 @@
+package com.macro.mall.tiny.modules.business.converter;
+
+import com.macro.mall.tiny.modules.business.enume.IEnum;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.core.convert.converter.ConverterFactory;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author gjs
+ * @description
+ * @date 2021/3/27 15:51
+ */
+@Component
+public class EnumConvertFactory implements ConverterFactory<String, IEnum> {
+
+    @Override
+    public <T extends IEnum> Converter<String, T> getConverter(Class<T> targetType) {
+        return new StringToIEum<>(targetType);
+    }
+
+    @SuppressWarnings("all")
+    private static class StringToIEum<T extends IEnum> implements Converter<String, T> {
+        private Class<T> targetType;
+        public StringToIEum(Class<T> targetType) {
+            this.targetType = targetType;
+        }
+
+        @Override
+        public T convert(String source) {
+            if (StringUtils.isEmpty(source)) {
+                return null;
+            }
+            return (T) EnumConvertFactory.getIEnum(this.targetType, source);
+        }
+    }
+
+    public static <T extends IEnum> Object getIEnum(Class<T> targetType, String source) {
+        for (T enumObj : targetType.getEnumConstants()) {
+            if (source.equals(String.valueOf(enumObj.getType()))) {
+                return enumObj;
+            }
+        }
+        return null;
+    }
+}

+ 9 - 0
src/main/java/com/macro/mall/tiny/modules/business/dto/FileUploadParam.java

@@ -16,6 +16,15 @@ import javax.validation.constraints.NotNull;
 @Setter
 public class FileUploadParam {
 
+    @ApiModelProperty(value = "上传压缩包所属省份ID")
+    private Long province;
+
+    @ApiModelProperty(value = "上传文件名称")
+    private String name;
+
+    @ApiModelProperty(value = "上传线路名称")
+    private String lineName;
+
     @ApiModelProperty(value = "原始文件总大小(Byte)")
     private Long size;
 

+ 28 - 0
src/main/java/com/macro/mall/tiny/modules/business/enume/DirectoryEnum.java

@@ -0,0 +1,28 @@
+package com.macro.mall.tiny.modules.business.enume;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author gjs
+ * @description
+ * @date 2021/3/27 15:15
+ */
+@Getter
+@AllArgsConstructor
+public enum DirectoryEnum implements IEnum<Integer> {
+    FINISH_DES(1, "1竣工说明"),
+    TOWER_FORM(2, "2杆塔明细表"),
+    TOWER_PIC(3, "3杆塔图纸"),
+    CROSS_SEC_PIC(4, "4平断面图"),
+    EARTH_WIRE_POW_PIC(5, "5地线放线张力图"),
+    EARTH_WIRE_HARD_PIC(6, "6地线金具串图"),
+    TEAM_CHECK_PIC(7, "7班组巡检照片"),
+    SITE_INVEST(8, "8现场勘察"),
+    LON_LAT_INFO(9, "9经纬度信息"),
+    HARDWARE_DES(10, "10金具设计资料"),
+    ;
+
+    private final Integer type;
+    private final String name;
+}

+ 10 - 0
src/main/java/com/macro/mall/tiny/modules/business/enume/IEnum.java

@@ -0,0 +1,10 @@
+package com.macro.mall.tiny.modules.business.enume;
+
+/**
+ * @author gjs
+ * @description
+ * @date 2021/3/27 15:49
+ */
+public interface IEnum<T> {
+    T getType();
+}

+ 16 - 0
src/main/java/com/macro/mall/tiny/modules/business/mapper/BLineUploadLogMapper.java

@@ -0,0 +1,16 @@
+package com.macro.mall.tiny.modules.business.mapper;
+
+import com.macro.mall.tiny.modules.business.model.BLineUploadLog;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author macro
+ * @since 2021-03-28
+ */
+public interface BLineUploadLogMapper extends BaseMapper<BLineUploadLog> {
+
+}

+ 5 - 2
src/main/java/com/macro/mall/tiny/modules/business/model/BLine.java

@@ -30,13 +30,16 @@ public class BLine implements Serializable {
 
     @ApiModelProperty(value = "线路ID")
     @TableId(value = "id", type = IdType.AUTO)
-    private Integer id;
+    private Long id;
 
     @ApiModelProperty(value = "线路名称")
     private String name;
 
     @ApiModelProperty(value = "线路所属省份")
-    private Integer provinceId;
+    private Long provinceId;
+
+    @ApiModelProperty(value = "创建者ID")
+    private Long creatorId;
 
 
     @ApiModelProperty(value = "包含铁塔")

+ 49 - 0
src/main/java/com/macro/mall/tiny/modules/business/model/BLineUploadLog.java

@@ -0,0 +1,49 @@
+package com.macro.mall.tiny.modules.business.model;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import java.util.Date;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author macro
+ * @since 2021-03-28
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@TableName("b_line_upload_log")
+@ApiModel(value="BLineUploadLog对象", description="线路上传记录表")
+public class BLineUploadLog implements Serializable {
+
+    private static final long serialVersionUID=1L;
+
+    @ApiModelProperty(value = "上传记录表")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "上传线路名称")
+    private Long lineId;
+
+    @ApiModelProperty(value = "上传者ID")
+    private Long uploaderId;
+
+    @ApiModelProperty(value = "上传日期")
+    private Date uploadTime;
+
+    @ApiModelProperty(value = "上传状态:0-失败,1-成功")
+    private Boolean status;
+
+    @ApiModelProperty(value = "警告信息")
+    private String warnMsg;
+
+
+}

+ 1 - 1
src/main/java/com/macro/mall/tiny/modules/business/model/BProvince.java

@@ -26,7 +26,7 @@ public class BProvince implements Serializable {
     private static final long serialVersionUID=1L;
 
     @TableId(value = "id", type = IdType.AUTO)
-    private Integer id;
+    private Long id;
 
     @ApiModelProperty(value = "省份名称")
     private String province;

+ 5 - 2
src/main/java/com/macro/mall/tiny/modules/business/model/BTower.java

@@ -29,7 +29,10 @@ public class BTower implements Serializable {
 
     @ApiModelProperty(value = "杆塔表")
     @TableId(value = "id", type = IdType.AUTO)
-    private Integer id;
+    private Long id;
+
+    @ApiModelProperty(value = "序号")
+    private Integer sort;
 
     @ApiModelProperty(value = "杆塔号")
     private String name;
@@ -41,7 +44,7 @@ public class BTower implements Serializable {
     private String hardwareType;
 
     @ApiModelProperty(value = "线路ID")
-    private Integer lineId;
+    private Long lineId;
 
     @ApiModelProperty(value = "经度")
     private BigDecimal lon;

+ 26 - 0
src/main/java/com/macro/mall/tiny/modules/business/model/TowerExcelModel.java

@@ -0,0 +1,26 @@
+package com.macro.mall.tiny.modules.business.model;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.metadata.BaseRowModel;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class TowerExcelModel extends BaseRowModel implements Serializable {
+
+    @ExcelProperty(value = "序号", index = 0)
+    private Integer sort;
+
+    @ExcelProperty(value = "杆塔号", index = 1)
+    private String name;
+
+    @ExcelProperty(value = "杆塔设备坐标", index = 2)
+    private String lonLat;
+
+    @ExcelProperty(value = "型号", index = 3)
+    private String shape;
+
+    @ExcelProperty(value = "金具串型号", index = 4)
+    private String hardware;
+}

+ 16 - 0
src/main/java/com/macro/mall/tiny/modules/business/service/BLineUploadLogService.java

@@ -0,0 +1,16 @@
+package com.macro.mall.tiny.modules.business.service;
+
+import com.macro.mall.tiny.modules.business.model.BLineUploadLog;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author macro
+ * @since 2021-03-28
+ */
+public interface BLineUploadLogService extends IService<BLineUploadLog> {
+
+}

+ 2 - 1
src/main/java/com/macro/mall/tiny/modules/business/service/FileService.java

@@ -3,6 +3,7 @@ package com.macro.mall.tiny.modules.business.service;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.io.IOException;
+import java.security.Principal;
 
 /**
  * @author gjs
@@ -13,5 +14,5 @@ public interface FileService {
 
     void upload(MultipartFile file) throws IOException;
 
-    void uploadWithBlock(String name, Long size, Integer chunks, Integer chunk, MultipartFile file) throws IOException;
+    void uploadWithBlock(String name, String lineName, Long provinceId, Long size, Integer chunks, Integer chunk, MultipartFile file, Principal principal) throws IOException;
 }

+ 216 - 0
src/main/java/com/macro/mall/tiny/modules/business/service/impl/AsyncHandler.java

@@ -0,0 +1,216 @@
+package com.macro.mall.tiny.modules.business.service.impl;
+
+import com.alibaba.excel.EasyExcel;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.macro.mall.tiny.common.exception.ApiException;
+import com.macro.mall.tiny.common.exception.Asserts;
+import com.macro.mall.tiny.common.util.CommonUtils;
+import com.macro.mall.tiny.config.UploadConfig;
+import com.macro.mall.tiny.modules.business.enume.DirectoryEnum;
+import com.macro.mall.tiny.modules.business.model.*;
+import com.macro.mall.tiny.modules.business.service.BLineService;
+import com.macro.mall.tiny.modules.business.service.BLineUploadLogService;
+import com.macro.mall.tiny.modules.business.service.BTowerService;
+import com.macro.mall.tiny.modules.ums.model.UmsAdmin;
+import com.macro.mall.tiny.modules.ums.model.UmsRole;
+import com.macro.mall.tiny.modules.ums.service.UmsAdminService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigDecimal;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.security.Principal;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
+
+/**
+ * @author gjs
+ * @description
+ * @date 2021/3/28 17:44
+ */
+@Component
+@Slf4j
+public class AsyncHandler {
+
+    @Value("${system.charset:gbk}")
+    private String charset;
+
+    @Autowired
+    private UmsAdminService adminService;
+
+    @Autowired
+    private BProvinceServiceImpl provinceService;
+
+    @Autowired
+    private BLineService lineService;
+
+    @Autowired
+    private BLineUploadLogService lineUploadLogService;
+
+    @Autowired
+    private BTowerService towerService;
+
+    @Async
+    @Transactional
+    public void handleDocument(Long provinceId, String fileSource, String lineName, Principal principal) {
+        StringBuilder warnMsg = new StringBuilder();
+        try {
+            if (provinceId == null) Asserts.fail("上传失败,省份不能为空,provinceId:" + provinceId);
+            if (principal == null) Asserts.fail("上传失败,未获取到当前用户");
+
+            BProvince province = provinceService.getById(provinceId);
+            String provinceName = province.getProvince();
+
+            String username = principal.getName();
+            UmsAdmin umsAdmin = adminService.getAdminByUsername(username);
+            Long userId = umsAdmin.getId();
+            boolean canCover = false;
+            List<UmsRole> roleList = adminService.getRoleList(umsAdmin.getId());
+            for (UmsRole umsRole : roleList) {
+                if (umsRole.getName().equals("超级管理员")) {
+                    canCover = true;
+                    break;
+                }
+            }
+            // 查看是否为线路创建者
+            QueryWrapper<BLine> wrapper = new QueryWrapper<>();
+            wrapper.lambda().eq(BLine::getName, lineName);
+            BLine line = lineService.getOne(wrapper);
+            if (line == null) {
+                // 如果为空,则创建新线路
+                BLine newLine = new BLine();
+                newLine.setCreatorId(userId);
+                newLine.setName(lineName);
+                newLine.setProvinceId(provinceId);
+                lineService.save(newLine);
+                line = newLine;
+
+                canCover = true;
+            } else if (line.getCreatorId().equals(userId)) {
+                canCover = true;
+            }
+
+            // 先获取根目录
+            Path rootPath = Paths.get(UploadConfig.powerPath + provinceName);
+            if (!Files.exists(rootPath)) {
+                Files.createDirectories(rootPath);
+            }
+
+            // 获取暂存文件Path
+            Path filePath = Paths.get(fileSource);
+
+            // 获取枚举类判断
+            DirectoryEnum[] enums = DirectoryEnum.values();
+            HashMap<String, Boolean> booleanHashMap = new HashMap<>();
+            for (DirectoryEnum directory : enums) {
+                booleanHashMap.put(directory.getName(), false);
+            }
+
+            try (ZipFile zipFile = new ZipFile(filePath.toFile(), Charset.forName(charset))) {
+                // 读取zip流
+                try (ZipInputStream zipInputStream = new ZipInputStream(Files.newInputStream(filePath), Charset.forName(charset))) {
+                    ZipEntry zipEntry;
+                    // 遍历每一个zip项
+                    while ((zipEntry = zipInputStream.getNextEntry()) != null) {
+                        // 获取zip项目名称
+                        String entryName = zipEntry.getName();
+
+                        // 解析各项路径
+                        String[] pathStr = entryName.split("/");
+                        if (pathStr.length < 2) {
+                            continue;
+                        }
+                        String SecDirectoryName = pathStr[1].charAt(0) == '#' ? pathStr[1].substring(1) : pathStr[1];
+                        if (booleanHashMap.get(SecDirectoryName) != null) {
+                            booleanHashMap.put(SecDirectoryName, true);
+                        } else if ("杆塔信息录入.xlsx".equals(SecDirectoryName) || "杆塔信息录入.xls".equals(SecDirectoryName)) {
+                            List<TowerExcelModel> modelArrayList = EasyExcel.read(zipFile.getInputStream(zipEntry), TowerExcelModel.class, null).sheet().doReadSync();
+                            BLine finalLine = line;
+                            List<BTower> towerList = modelArrayList.stream().map(model -> {
+                                BTower tower = new BTower();
+                                tower.setName(model.getName());
+                                tower.setShape(model.getShape());
+                                tower.setSort(model.getSort());
+                                tower.setHardwareType(model.getHardware());
+                                // 经纬度设置
+                                String lonLat = model.getLonLat();
+                                String[] lonLats = lonLat.split(",");
+                                BigDecimal lon = CommonUtils.Dms2D(lonLats[0]);
+                                BigDecimal lat = CommonUtils.Dms2D(lonLats[1]);
+                                tower.setLon(lon);
+                                tower.setLat(lat);
+                                tower.setLineId(finalLine.getId());
+                                return tower;
+                            }).collect(Collectors.toList());
+                            towerService.saveBatch(towerList);
+                            continue;
+                        } else {
+                            warnMsg.append(entryName).append("第二层目录解析出错;");
+                            continue;
+                        }
+
+
+                        // 构建绝对路径
+                        Path entryFile = rootPath.resolve(entryName);
+                        if (zipEntry.isDirectory()) {    // 文件夹
+                            if (!Files.isDirectory(entryFile)) {
+                                Files.createDirectories(entryFile);
+                            }
+                        } else if (!canCover && Files.exists(entryFile)) {
+                            warnMsg.append(entryName).append("已存在,无权覆盖;");
+                        } else {                            // 文件
+                            // 读取zip项数据流
+                            try (InputStream zipEntryInputStream = zipFile.getInputStream(zipEntry)) {
+                                try (OutputStream fileOutputStream = Files.newOutputStream(entryFile, StandardOpenOption.CREATE)) {
+                                    byte[] buffer = new byte[2048];
+                                    int length;
+                                    while ((length = zipEntryInputStream.read(buffer)) != -1) {
+                                        fileOutputStream.write(buffer, 0, length);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            booleanHashMap.forEach((key, val) -> {
+                if (!val) {
+                    warnMsg.append("缺少").append(key).append("文件夹;");
+                }
+            });
+            // 存储上传记录
+            BLineUploadLog lineUploadLog = new BLineUploadLog();
+            lineUploadLog.setLineId(line.getId());
+            lineUploadLog.setStatus(true);
+            lineUploadLog.setUploaderId(userId);
+            lineUploadLog.setUploadTime(new Date());
+            lineUploadLog.setWarnMsg(warnMsg.toString());
+            lineUploadLogService.save(lineUploadLog);
+        } catch (ApiException e) {
+            log.error("上传文件抛出业务异常", e);
+        } catch (Exception e) {
+            log.error("上传文件抛出异常", e);
+        } finally {
+            File file = new File(fileSource);
+            if (file.exists()) {
+                file.delete();
+            }
+        }
+    }
+}

+ 20 - 0
src/main/java/com/macro/mall/tiny/modules/business/service/impl/BLineUploadLogServiceImpl.java

@@ -0,0 +1,20 @@
+package com.macro.mall.tiny.modules.business.service.impl;
+
+import com.macro.mall.tiny.modules.business.model.BLineUploadLog;
+import com.macro.mall.tiny.modules.business.mapper.BLineUploadLogMapper;
+import com.macro.mall.tiny.modules.business.service.BLineUploadLogService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author macro
+ * @since 2021-03-28
+ */
+@Service
+public class BLineUploadLogServiceImpl extends ServiceImpl<BLineUploadLogMapper, BLineUploadLog> implements BLineUploadLogService {
+
+}

+ 49 - 5
src/main/java/com/macro/mall/tiny/modules/business/service/impl/FileServiceImpl.java

@@ -1,14 +1,47 @@
 package com.macro.mall.tiny.modules.business.service.impl;
 
-import com.macro.mall.tiny.common.util.FileUtils;
+import com.alibaba.excel.EasyExcel;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.macro.mall.tiny.common.exception.ApiException;
+import com.macro.mall.tiny.common.exception.Asserts;
+import com.macro.mall.tiny.common.util.CommonUtils;
+import com.macro.mall.tiny.common.util.MyFileUtils;
 import com.macro.mall.tiny.config.UploadConfig;
+import com.macro.mall.tiny.modules.business.enume.DirectoryEnum;
+import com.macro.mall.tiny.modules.business.model.*;
+import com.macro.mall.tiny.modules.business.service.BLineService;
+import com.macro.mall.tiny.modules.business.service.BLineUploadLogService;
+import com.macro.mall.tiny.modules.business.service.BTowerService;
 import com.macro.mall.tiny.modules.business.service.FileService;
+import com.macro.mall.tiny.modules.ums.model.UmsAdmin;
+import com.macro.mall.tiny.modules.ums.model.UmsRole;
+import com.macro.mall.tiny.modules.ums.service.UmsAdminService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.aop.framework.AopContext;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.io.File;
 import java.io.IOException;
-import java.util.Date;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigDecimal;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.security.Principal;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
 
 import static com.macro.mall.tiny.common.util.UploadUtils.*;
 
@@ -17,8 +50,13 @@ import static com.macro.mall.tiny.common.util.UploadUtils.*;
  * 文件上传服务
  */
 @Service
+@Slf4j
+@EnableAsync
 public class FileServiceImpl implements FileService {
 
+    @Autowired
+    private AsyncHandler asyncHandler;
+
     /**
      * 上传文件
      *
@@ -26,7 +64,7 @@ public class FileServiceImpl implements FileService {
      */
     public void upload(MultipartFile file) throws IOException {
         String path = UploadConfig.path + file.getOriginalFilename();
-        FileUtils.write(path, file.getInputStream());
+        MyFileUtils.write(path, file.getInputStream());
     }
 
     /**
@@ -39,15 +77,21 @@ public class FileServiceImpl implements FileService {
      * @throws IOException
      */
     public void uploadWithBlock(String name,
+                                String lineName,
+                                Long provinceId,
                                 Long size,
                                 Integer chunks,
                                 Integer chunk,
-                                MultipartFile file) throws IOException {
+                                MultipartFile file,
+                                Principal principal) throws IOException {
         putChunkMap(name, chunks);
-        FileUtils.writeWithBlok(UploadConfig.tempPath + name, size, file.getInputStream(), file.getSize(), chunks, chunk);
+        String target = UploadConfig.tempPath + name;
+        MyFileUtils.writeWithBlock(target, size, file.getInputStream(), file.getSize(), chunks, chunk);
         addChunk(name, chunk);
         if (isUploaded(name)) {
             removeKey(name);
+            asyncHandler.handleDocument(provinceId, target, lineName, principal);
         }
     }
+
 }

+ 11 - 1
src/main/resources/application.yml

@@ -58,4 +58,14 @@ secure:
 upload:
   temp-path: ./temp/
   path: ./upload/ #文件上传路径
-  power-path: ./power/
+  power-path: ./power/
+
+thread:
+  pool:
+    corePoolSize: 10
+    maxPoolSize: 20
+    keepAliveSeconds: 5
+    queueCapacity: 512
+
+system:
+  charset: gbk

BIN
src/main/resources/excel-template/杆塔信息录入.xlsx


+ 7 - 2
src/main/resources/mapper/business/BLineMapper.xml

@@ -6,6 +6,7 @@
         SELECT l.id,
                l.name,
                t.id            t_id,
+               t.sort          t_sort,
                t.name          t_name,
                t.shape         t_shape,
                t.hardware_type t_hardware_type,
@@ -13,13 +14,15 @@
                t.lon           t_lon,
                t.lat           t_lat
         FROM b_line l
-                 LEFT JOIN b_tower t ON l.id = t.line_id;
+                 LEFT JOIN b_tower t ON l.id = t.line_id
+        ORDER BY t_sort;
     </select>
 
     <select id="findListByKey" resultMap="BaseResultMap" parameterType="string">
         SELECT l.id,
                l.name,
                t.id            t_id,
+               t.sort          t_sort,
                t.name          t_name,
                t.shape         t_shape,
                t.hardware_type t_hardware_type,
@@ -30,7 +33,8 @@
                  LEFT JOIN b_tower t ON l.id = t.line_id
                  LEFT JOIN b_province p on l.province_id = p.id
         WHERE l.name like concat('%', #{key}, '%')
-           OR p.province like concat('%', #{key}, '%');
+           OR p.province like concat('%', #{key}, '%')
+        ORDER BY t_sort;
     </select>
 
     <!-- 通用查询映射结果 -->
@@ -40,6 +44,7 @@
         <result column="province_id" property="provinceId"/>
         <collection property="towerList" ofType="com.macro.mall.tiny.modules.business.model.BTower" column="id">
             <id column="t_id" property="id"/>
+            <result column="t_sort" property="sort"/>
             <result column="t_name" property="name"/>
             <result column="t_shape" property="shape"/>
             <result column="t_hardware_type" property="hardwareType"/>

+ 15 - 0
src/main/resources/mapper/business/BLineUploadLogMapper.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.macro.mall.tiny.modules.business.mapper.BLineUploadLogMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.macro.mall.tiny.modules.business.model.BLineUploadLog">
+        <id column="id" property="id" />
+        <result column="line_name" property="lineName" />
+        <result column="uploader_id" property="uploaderId" />
+        <result column="upload_time" property="uploadTime" />
+        <result column="status" property="status" />
+        <result column="warn_msg" property="warnMsg" />
+    </resultMap>
+
+</mapper>