From c1dc82c70ef0f79ee657166c562dd86d06c58cde Mon Sep 17 00:00:00 2001 From: guoxiang <18841845137@163.com> Date: Thu, 21 Jul 2022 14:20:19 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A6=96=E6=AC=A1=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- pom.xml | 69 ++++++++++++++++ .../example/demo/ImportDemoApplication.java | 13 +++ .../demo/controller/ImportController.java | 44 ++++++++++ .../com/example/demo/dto/ExampleData.java | 42 ++++++++++ src/main/java/com/example/demo/dto/R.java | 75 ++++++++++++++++++ .../com/example/demo/service/DataService.java | 66 +++++++++++++++ src/main/resources/application.properties | 1 + src/main/resources/导入模板.xlsx | Bin 0 -> 8844 bytes .../demo/ImportDemoApplicationTests.java | 13 +++ 10 files changed, 326 insertions(+), 1 deletion(-) create mode 100644 pom.xml create mode 100644 src/main/java/com/example/demo/ImportDemoApplication.java create mode 100644 src/main/java/com/example/demo/controller/ImportController.java create mode 100644 src/main/java/com/example/demo/dto/ExampleData.java create mode 100644 src/main/java/com/example/demo/dto/R.java create mode 100644 src/main/java/com/example/demo/service/DataService.java create mode 100644 src/main/resources/application.properties create mode 100644 src/main/resources/导入模板.xlsx create mode 100644 src/test/java/com/example/demo/ImportDemoApplicationTests.java diff --git a/README.md b/README.md index 7eff1a1..773a678 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ # import-demo -数据导入demo \ No newline at end of file +数据导入demo + +启动后访问:http://localhost:8080/doc.html#/default/%E5%AF%BC%E5%85%A5/importDetailUsingPOST \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..a2ea92e --- /dev/null +++ b/pom.xml @@ -0,0 +1,69 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.1 + + + com.fly + import-demo + 0.0.1-SNAPSHOT + import-demo + Demo project for Spring Boot + + 17 + + + + org.springframework.boot + spring-boot-starter-web + + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + com.github.xiaoymin + knife4j-spring-boot-starter + 3.0.3 + + + cn.afterturn + easypoi-spring-boot-starter + 4.2.0 + + + org.springframework.boot + spring-boot-starter-validation + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + diff --git a/src/main/java/com/example/demo/ImportDemoApplication.java b/src/main/java/com/example/demo/ImportDemoApplication.java new file mode 100644 index 0000000..979b591 --- /dev/null +++ b/src/main/java/com/example/demo/ImportDemoApplication.java @@ -0,0 +1,13 @@ +package com.example.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ImportDemoApplication { + + public static void main(String[] args) { + SpringApplication.run(ImportDemoApplication.class, args); + } + +} diff --git a/src/main/java/com/example/demo/controller/ImportController.java b/src/main/java/com/example/demo/controller/ImportController.java new file mode 100644 index 0000000..8e150e4 --- /dev/null +++ b/src/main/java/com/example/demo/controller/ImportController.java @@ -0,0 +1,44 @@ +package com.example.demo.controller; + +import com.example.demo.dto.ExampleData; +import com.example.demo.dto.R; +import com.example.demo.service.DataService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.PostMapping; +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 java.util.List; + +/** + * @author guoxiang + * @see 简书TinyThing + * @since 2022/7/21 13:33 + */ +@RestController +@RequestMapping("/importTest") +@Api(tags = "导入") +@RequiredArgsConstructor +@Slf4j +public class ImportController { + + private final DataService dataService; + + @PostMapping("/import") + @ApiOperation("导入") + R> importDetail(@RequestPart MultipartFile file) { + + log.info("- import data..."); + + R> data = dataService.importData(file); + + log.info("- import finish"); + return data; + } + +} diff --git a/src/main/java/com/example/demo/dto/ExampleData.java b/src/main/java/com/example/demo/dto/ExampleData.java new file mode 100644 index 0000000..b8a7cbf --- /dev/null +++ b/src/main/java/com/example/demo/dto/ExampleData.java @@ -0,0 +1,42 @@ +package com.example.demo.dto; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import cn.afterturn.easypoi.handler.inter.IExcelDataModel; +import cn.afterturn.easypoi.handler.inter.IExcelModel; +import lombok.Data; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; + +/** + * @author guoxiang + * @see 简书TinyThing + * @since 2022/7/21 13:58 + */ +@Data +public class ExampleData implements IExcelModel, IExcelDataModel { + @NotBlank(message = "不能为空") + @Excel(name = "证件号码") + private String id; + + @Excel(name = "名称") + @NotBlank(message = "名称不能为空") + private String name; + + @Excel(name = "年龄") + @Max(value = 150, message = "年龄不能超过150") + @Min(value = 1, message = "年龄不能小于1") + private Integer age; + + @Excel(name = "学校") + private String college; + + @Excel(name = "职位") + private String position; + + @Excel(name = "导入错误信息") + private String errorMsg; + + private Integer rowNum; +} diff --git a/src/main/java/com/example/demo/dto/R.java b/src/main/java/com/example/demo/dto/R.java new file mode 100644 index 0000000..27738dc --- /dev/null +++ b/src/main/java/com/example/demo/dto/R.java @@ -0,0 +1,75 @@ +package com.example.demo.dto; + +import lombok.*; +import lombok.experimental.Accessors; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 响应信息主体 + * + * @param + */ +@ToString +@NoArgsConstructor +@AllArgsConstructor +@Accessors(chain = true) +public class R implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Getter + @Setter + private int code; + + @Getter + @Setter + private String msg; + + @Getter + @Setter + private T data; + + public static R ok() { + return restResult(null, 0, null); + } + + public static R ok(T data) { + return restResult(data, 0, null); + } + + public static R ok(T data, String msg) { + return restResult(data, 0, msg); + } + + public static R failed() { + return restResult(null, 1, null); + } + + public static R failed(String msg) { + return restResult(null, 1, msg); + } + + public static R failed(T data,int code, String msg) { + return restResult(data, code, msg); + } + + public static R failed(T data) { + return restResult(data, 1, null); + } + + public static R failed(T data, String msg) { + return restResult(data, 1, msg); + } + + private static R restResult(T data, int code, String msg) { + R apiResult = new R<>(); + apiResult.setCode(code); + apiResult.setData(data); + apiResult.setMsg(msg); + return apiResult; + } + +} diff --git a/src/main/java/com/example/demo/service/DataService.java b/src/main/java/com/example/demo/service/DataService.java new file mode 100644 index 0000000..d695c45 --- /dev/null +++ b/src/main/java/com/example/demo/service/DataService.java @@ -0,0 +1,66 @@ +package com.example.demo.service; + +import cn.afterturn.easypoi.excel.ExcelImportUtil; +import cn.afterturn.easypoi.excel.entity.ImportParams; +import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult; +import com.example.demo.dto.ExampleData; +import com.example.demo.dto.R; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + * @author guoxiang + * @see 简书TinyThing + * @since 2022/7/21 13:43 + */ +@Service +@Slf4j +public class DataService { + + /** + * 导入数据 + * @param file excel文件 + * @return 结果 + */ + public R> importData(MultipartFile file) { + //导入的基本配置 + ImportParams params = new ImportParams(); + //代表导入这里是需要验证的(根据字段上的注解校验) + params.setNeedVerify(true); + params.setTitleRows(0); + //使用框架自身导入工具 + ExcelImportResult result; + try { + result = ExcelImportUtil.importExcelMore(file.getInputStream(), ExampleData.class, params); + } catch (Exception e) { + log.error("导入数据错误", e); + throw new IllegalArgumentException(); + } + + //如果存在校验失败的数据,则返回给用户 + if (result.isVerifyFail()) { + //失败结果集 + List failList = result.getFailList(); + return R.failed(failList); + } + + //校验成功的数据 + List list = result.getList(); + //将数据保存到数据库 + saveToDataBase(list); + + return R.ok(); + } + + /** + * 保存到数据库 + * + * @param list 数据 + */ + private void saveToDataBase(List list) { + list.forEach(data -> log.info("data = {}", data)); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..82d4f8d --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.mvc.pathmatch.matching-strategy=ant_path_matcher \ No newline at end of file diff --git a/src/main/resources/导入模板.xlsx b/src/main/resources/导入模板.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..2a03290865a92b9852b3eaa63dc62c6633a973f2 GIT binary patch literal 8844 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 z