فهرست منبع

feat: 实现不动产导入数据和获取模板接口

weijianghai 1 سال پیش
والد
کامیت
52260fafc9

+ 12 - 0
pom.xml

@@ -75,6 +75,18 @@
             <artifactId>minio</artifactId>
             <version>8.5.6</version>
         </dependency>
+        <!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi</artifactId>
+            <version>5.2.5</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+            <version>5.2.5</version>
+        </dependency>
     </dependencies>
 
     <build>

+ 19 - 0
src/main/java/com/nokia/financeapi/config/ImportHouseDataConfig.java

@@ -0,0 +1,19 @@
+package com.nokia.financeapi.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@Data
+@ConfigurationProperties("house.import-data")
+public class ImportHouseDataConfig {
+    /**
+     * 维修预算保存目录
+     */
+    private String wxys;
+    /**
+     * 出租预算保存目录
+     */
+    private String czys;
+}

+ 20 - 2
src/main/java/com/nokia/financeapi/config/web/MyDispatcherServlet.java

@@ -1,14 +1,32 @@
 package com.nokia.financeapi.config.web;
 
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.servlet.DispatcherServlet;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
+@Slf4j
 public class MyDispatcherServlet extends DispatcherServlet {
+    /**
+     * 上传和返回文件流的接口uri,不替换request和response
+     */
+    public static final Set<String> UN_WRAPPER = Stream.of(
+            "/house-car/house/report/api/importData"
+    ).collect(Collectors.toSet());
+
     @Override
     protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
-        // 替换request和response
-        super.doDispatch(new MyHttpServletRequestWrapper(request), new MyHttpServletResponseWrapper(response));
+        String uri = request.getRequestURI();
+        if (UN_WRAPPER.contains(request.getRequestURI())) {
+            super.doDispatch(request, response);
+        } else {
+            // 替换request和response
+            log.info("替换 {} 的request和response", uri);
+            super.doDispatch(new MyHttpServletRequestWrapper(request), new MyHttpServletResponseWrapper(response));
+        }
     }
 }

+ 25 - 19
src/main/java/com/nokia/financeapi/config/web/RequestLogHandlerInterceptor.java

@@ -53,20 +53,22 @@ public class RequestLogHandlerInterceptor implements HandlerInterceptor {
         }
         log.info("请求头参数: {}", new ObjectMapper().writeValueAsString(headers));
         // 查询参数
-//        Map<String, String> parameters = new HashMap<>();
-//        Enumeration<String> parameterNames = request.getParameterNames();
-//        while (parameterNames.hasMoreElements()) {
-//            String k	= parameterNames.nextElement();
-//            String v = request.getParameter(k);
-//            parameters.put(k, v);
-//        }
-//        log.info("查询参数: {}", new ObjectMapper().writeValueAsString(parameters));
-        // 请求体参数
-        String body = StringUtils.trimAllWhitespace(StreamUtils.copyToString(request.getInputStream(),
-                Charset.forName(request.getCharacterEncoding())));
-        log.info("请求参数: {}", body);
+        Map<String, String> parameters = new HashMap<>();
+        Enumeration<String> parameterNames = request.getParameterNames();
+        while (parameterNames.hasMoreElements()) {
+            String k	= parameterNames.nextElement();
+            String v = request.getParameter(k);
+            parameters.put(k, v);
+        }
+        log.info("查询参数: {}", new ObjectMapper().writeValueAsString(parameters));
+        String body = null;
+        if (!MyDispatcherServlet.UN_WRAPPER.contains(request.getRequestURI())) {
+            // 请求体参数
+            body = StreamUtils.copyToString(request.getInputStream(), Charset.forName(request.getCharacterEncoding()));
+            log.info("请求体参数: {}", StringUtils.trimAllWhitespace(body));
+        }
         // todo: 记录日志
-        String token = request.getHeader("Token");
+        String token = request.getHeader("token");
         log.info("token: {}", token);
         if (!StringUtils.hasText(token)) {
             return forbidden(response);
@@ -97,12 +99,16 @@ public class RequestLogHandlerInterceptor implements HandlerInterceptor {
     @Override
     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                 @Nullable Exception ex) throws Exception {
-        MyHttpServletResponseWrapper wrapper = (MyHttpServletResponseWrapper) response;
-        String responseString = new String(wrapper.toByteArray());
-        // 返回结果打印前1000个字符
-//        log.info("返回 {}: {}", wrapper.getStatus(),
-//                org.apache.commons.lang3.StringUtils.substring(responseString, 0, 1000));
-        log.info("返回 {}: {}", wrapper.getStatus(), responseString);
+        if (!MyDispatcherServlet.UN_WRAPPER.contains(request.getRequestURI())) {
+            MyHttpServletResponseWrapper wrapper = (MyHttpServletResponseWrapper) response;
+            String responseString = new String(wrapper.toByteArray());
+            log.info("响应 {}: {}", wrapper.getStatus(), responseString);
+            // 返回结果打印前1000个字符
+//            log.info("返回 {}: {}", wrapper.getStatus(),
+//                    org.apache.commons.lang3.StringUtils.substring(responseString, 0, 1000));
+        } else {
+            log.info("响应 {}", response.getStatus());
+        }
         StopWatch stopWatch = STOP_WATCH_THREAD_LOCAL.get();
         stopWatch.stop();
         log.info("耗时 {} ms", stopWatch.getTotalTimeMillis());

+ 17 - 0
src/main/java/com/nokia/financeapi/controller/house/HouseReportController.java

@@ -2,16 +2,21 @@ package com.nokia.financeapi.controller.house;
 
 import com.nokia.financeapi.common.R;
 import com.nokia.financeapi.pojo.dto.GetHouseReportDto;
+import com.nokia.financeapi.pojo.dto.ImportHouseDataDto;
 import com.nokia.financeapi.pojo.vo.GetHouseReportVo;
+import com.nokia.financeapi.pojo.vo.GetHouseTemplatesVo;
 import com.nokia.financeapi.service.house.HouseReportService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 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.RequestPart;
 import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
 
 import javax.validation.Valid;
+import java.util.List;
 
 @Tag(name = "不动产报告")
 @RestController
@@ -34,4 +39,16 @@ public class HouseReportController {
     public R<GetHouseReportVo> getReportWord(@Valid @RequestBody GetHouseReportDto dto) {
         return houseReportService.getReportWord(dto);
     }
+
+    @Operation(summary = "获取不动产模板")
+    @PostMapping("/getTemplates")
+    public R<List<GetHouseTemplatesVo>> getTemplates() {
+        return houseReportService.getTemplates();
+    }
+
+    @Operation(summary = "导入数据")
+    @PostMapping("/importData")
+    public R<Object> importData(@Valid ImportHouseDataDto dto, @RequestPart("file") MultipartFile file) {
+        return houseReportService.importData(dto, file);
+    }
 }

+ 17 - 0
src/main/java/com/nokia/financeapi/pojo/dto/ImportHouseDataDto.java

@@ -0,0 +1,17 @@
+package com.nokia.financeapi.pojo.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class ImportHouseDataDto {
+    @Schema(description = "模板id")
+    @NotBlank(message = "id不能为空")
+    private String id;
+    @Schema(description = "账期", example = "2023")
+    @NotNull(message = "year不能为空")
+    private Integer year;
+}

+ 14 - 0
src/main/java/com/nokia/financeapi/pojo/vo/GetHouseTemplatesVo.java

@@ -0,0 +1,14 @@
+package com.nokia.financeapi.pojo.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+public class GetHouseTemplatesVo {
+    @Schema(description = "模板id")
+    private String id;
+    @Schema(description = "模板名称")
+    private String name;
+    @Schema(description = "模板链接")
+    private String url;
+}

+ 97 - 1
src/main/java/com/nokia/financeapi/service/house/HouseReportService.java

@@ -1,21 +1,42 @@
 package com.nokia.financeapi.service.house;
 
 import com.nokia.financeapi.common.R;
+import com.nokia.financeapi.config.ImportHouseDataConfig;
 import com.nokia.financeapi.dao.house.HouseReportDao;
 import com.nokia.financeapi.pojo.dto.GetHouseReportDto;
+import com.nokia.financeapi.pojo.dto.ImportHouseDataDto;
 import com.nokia.financeapi.pojo.po.house.HouseReportsPo;
 import com.nokia.financeapi.pojo.vo.GetHouseReportVo;
+import com.nokia.financeapi.pojo.vo.GetHouseTemplatesVo;
 import com.nokia.financeapi.service.common.file.FileService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.FileUtils;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
 
+import java.io.File;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+@Slf4j
 @Service
 public class HouseReportService {
     private final FileService fileService;
     private final HouseReportDao houseReportDao;
+    private final ImportHouseDataConfig importHouseDataConfig;
 
-    public HouseReportService(FileService fileService, HouseReportDao houseReportDao) {
+    public HouseReportService(FileService fileService, HouseReportDao houseReportDao,
+                              ImportHouseDataConfig importHouseDataConfig) {
         this.fileService = fileService;
         this.houseReportDao = houseReportDao;
+        this.importHouseDataConfig = importHouseDataConfig;
     }
 
     public R<GetHouseReportVo> getReportWord(GetHouseReportDto dto) {
@@ -48,4 +69,79 @@ public class HouseReportService {
         vo.setUrl(url);
         return R.ok(vo);
     }
+
+    public R<List<GetHouseTemplatesVo>> getTemplates() {
+        List<GetHouseTemplatesVo> vos = new ArrayList<>();
+        GetHouseTemplatesVo wxys = new GetHouseTemplatesVo();
+        wxys.setId("wxys");
+        wxys.setName("维修费用预算(第二年预算)");
+        wxys.setUrl(fileService.getBucket() + "/" + "oss/public/template/house/wxys.xlsx");
+        vos.add(wxys);
+        GetHouseTemplatesVo czys = new GetHouseTemplatesVo();
+        czys.setId("czys");
+        czys.setName("对外出租费用预算(第二年预算)");
+        czys.setUrl(fileService.getBucket() + "/" + "oss/public/template/house/czys.xlsx");
+        vos.add(czys);
+        return R.ok(vos);
+    }
+
+    public R<Object> importData(ImportHouseDataDto dto, MultipartFile file) {
+        if ("wxys".equals(dto.getId())) {
+            return importWxys(dto, file);
+        }
+        if ("czys".equals(dto.getId())) {
+            return importCzys(dto, file);
+        }
+        return R.ok();
+    }
+
+    public synchronized R<Object> importWxys(ImportHouseDataDto dto, MultipartFile file) {
+        try {
+            Files.createDirectories(Paths.get(importHouseDataConfig.getWxys()));
+            File fileNew = new File(importHouseDataConfig.getWxys() + dto.getYear() + ".xlsx");
+            FileUtils.copyInputStreamToFile(file.getInputStream(), fileNew);
+            try(InputStream inputStream = Files.newInputStream(fileNew.toPath());
+                Workbook workbook = new XSSFWorkbook(inputStream)
+            ) {
+                // 读取第一个工作表
+                Sheet sheet = workbook.getSheetAt(0);
+                // 表头行
+                Row headerRow = sheet.getRow(0);
+                // 列数
+                int columnCount = headerRow.getPhysicalNumberOfCells();
+                if (5 != columnCount) {
+                    return R.error("列数和模板不一致");
+                }
+            }
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            return R.error("导入失败");
+        }
+        return R.ok();
+    }
+
+    public synchronized R<Object> importCzys(ImportHouseDataDto dto, MultipartFile file) {
+        try {
+            Files.createDirectories(Paths.get(importHouseDataConfig.getCzys()));
+            File fileNew = new File(importHouseDataConfig.getCzys() + dto.getYear() + ".xlsx");
+            FileUtils.copyInputStreamToFile(file.getInputStream(), fileNew);
+            try(InputStream inputStream = Files.newInputStream(fileNew.toPath());
+                Workbook workbook = new XSSFWorkbook(inputStream)
+            ) {
+                // 读取第一个工作表
+                Sheet sheet = workbook.getSheetAt(0);
+                // 表头行
+                Row headerRow = sheet.getRow(0);
+                // 列数
+                int columnCount = headerRow.getPhysicalNumberOfCells();
+                if (5 != columnCount) {
+                    return R.error("列数和模板不一致");
+                }
+            }
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            return R.error("导入失败");
+        }
+        return R.ok();
+    }
 }

+ 2 - 0
src/main/resources/application-prod.properties

@@ -16,3 +16,5 @@ springdoc.swagger-ui.enabled=false
 knife4j.production=true
 # 一房产一局址页面url
 pages.house.siteUrl=house-car/house/dist/index.html#/administrative/overview
+house.import-data.wxys=/data/import-data/house/wxys/
+house.import-data.czys=/data/import-data/house/czys/

+ 2 - 0
src/main/resources/application-test.properties

@@ -12,3 +12,5 @@ minio.secretKey=EGqIq7zKZwfasMQ5eLIoLId631vmLaal
 minio.expiry=15
 # 一房产一局址页面url
 pages.house.siteUrl=house-car/house/dist/index.html#/administrative/overview
+house.import-data.wxys=data/import-data/house/wxys/
+house.import-data.czys=data/import-data/house/czys/