【问题标题】:How to read data from csv file and store it in the database ? Spring Boot如何从 csv 文件中读取数据并将其存储在数据库中?弹簧靴
【发布时间】:2018-12-01 21:03:20
【问题描述】:

例如,我有一个由用户名、电话号码和地址组成的用户实体。 我想从 csv 文件中读取所有这些字段并将其存储在数据库中的相应表中?

谁能帮我描述一下如何做到这一点?或者有没有关于如何做到这一点的文档?

【问题讨论】:

  • 查看 spring-batch
  • 做到了。但是他们在那里专门从一个文件中获取数据。我想打一个 api,允许用户从包含数据的系统中选择 csv 文件

标签: file csv spring-boot upload


【解决方案1】:

我假设您希望用户从某个 UI 上传文件。根据您构建 UI 的具体方式,您可能会:

使用 Spring 可以很容易地解决这两个问题。

假设我们有以下实体:

@Data
@Entity
public class User {
    @Id
    private String username;
    private String phoneNumber;
    private String address;
}

我们定义了一个用于访问数据库的 Spring Data 存储库:

public interface UserRepository extends JpaRepository<User, String> {

}

对于 CSV 反序列化,我建议使用 Jackson。 Spring Boot 已经自带 Jackson,但是我们需要在你的 pom 中为 CSV 添加数据格式扩展:

    <dependency>
        <groupId>com.fasterxml.jackson.dataformat</groupId>
        <artifactId>jackson-dataformat-csv</artifactId>
    </dependency>

这样,我们可以创建一个简单的实用方法,该方法知道读取给定 POJO 类的 CSV:

public class CsvUtils {
    private static final CsvMapper mapper = new CsvMapper();
    public static <T> List<T> read(Class<T> clazz, InputStream stream) throws IOException {
        CsvSchema schema = mapper.schemaFor(clazz).withHeader().withColumnReordering(true);
        ObjectReader reader = mapper.readerFor(clazz).with(schema);
        return reader.<T>readValues(stream).readAll();
    }
}

然后我们创建一个简单的 Rest Controller 来处理上传:

@RestController
@RequiredArgsConstructor
public class UserController {
    private final UserRepository repository;

    @PostMapping(value = "/upload", consumes = "text/csv")
    public void uploadSimple(@RequestBody InputStream body) {
        repository.saveAll(CsvUtils.read(User.class, body));
    }

    @PostMapping(value = "/upload", consumes = "multipart/form-data")
    public void uploadMultipart(@RequestParam("file") MultipartFile file) {
        repository.saveAll(CsvUtils.read(User.class, file.getInputStream()));
    }
}

如果您还需要一些 HTML 来进行上传,以下 sn-p 是一个最小的工作示例:

<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="file" id="file" />
    <input type="submit" name="submit" value="Submit" />
</form>

稍后编辑:如果您还想验证传入的数据,请首先使用javax.validation 约束来注释您的实体类属性。例如:

@Data
@Entity
class User {
    @Id
    @Email
    @NotEmpty
    private String username;
    @Pattern(regexp = "[0-9 ()-]{4,12}")
    private String phoneNumber;
    private String address;
}

然后您可以选择执行实际验证调用的位置:

  1. 服务级别。这是我个人在这种情况下推荐的方法,因为它很容易设置并且会尽早执行验证。为此,您在控制器和存储库之间引入了一个简单的 @Service 类。
@Service
@Validated
@RequiredArgsConstructor
class UserService {
    private final UserRepository repository;
    public void saveAll(@Valid List<User> users) {
        repository.saveAll(users);
    }
}

然后您将使用此服务类而不是控制器类中的存储库。

  1. 存储库级别:在这里您实际上不需要执行任何操作。如果您使用验证约束对实体类进行注释,Hibernate 会自动在预插入侦听器 (BeanValidationEventListener) 中调用验证。

  2. 控制器级别。这设置起来比较棘手。在自定义 HttpMessageConverter 中移动 CSV 反序列化。您还应该将此转换器添加到FormHttpMessageConverter(以便它可以使用它来反序列化多部分请求的一部分)。然后,理论上您可以将@Valid List&lt;User&gt; 声明为控制器方法的输入,Spring 会根据 mime 类型自动调用消息转换器,然后调用验证器。示例见Add JSON message converter for multipart/form-data

最后,您可以随时手动调用验证:Manually call Spring Annotation Validation

【讨论】:

【解决方案2】:

您可以使用 openCSV 轻松实现这一目标。 对于已知的 POJO 用户,您只需将 CSV 列(在您的案例中为标题)映射到 POJO 中的相应字段。

只需将以下内容添加到您的依赖项中,但请检查您的应用程序的最新版本。

<dependency> 
<groupId>com.opencsv</groupId> 
<artifactId>opencsv</artifactId> 
<version>4.1</version> 
</dependency> 

此链接将引导您浏览https://www.geeksforgeeks.org/mapping-csv-to-javabeans-using-opencsv/

【讨论】:

    猜你喜欢
    • 2018-03-05
    • 2015-07-19
    • 2019-05-03
    • 1970-01-01
    • 1970-01-01
    • 2019-05-15
    • 2019-12-10
    • 1970-01-01
    相关资源
    最近更新 更多