我假设您希望用户从某个 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;
}
然后您可以选择执行实际验证调用的位置:
- 服务级别。这是我个人在这种情况下推荐的方法,因为它很容易设置并且会尽早执行验证。为此,您在控制器和存储库之间引入了一个简单的
@Service 类。
@Service
@Validated
@RequiredArgsConstructor
class UserService {
private final UserRepository repository;
public void saveAll(@Valid List<User> users) {
repository.saveAll(users);
}
}
然后您将使用此服务类而不是控制器类中的存储库。
存储库级别:在这里您实际上不需要执行任何操作。如果您使用验证约束对实体类进行注释,Hibernate 会自动在预插入侦听器 (BeanValidationEventListener) 中调用验证。
控制器级别。这设置起来比较棘手。在自定义 HttpMessageConverter 中移动 CSV 反序列化。您还应该将此转换器添加到FormHttpMessageConverter(以便它可以使用它来反序列化多部分请求的一部分)。然后,理论上您可以将@Valid List<User> 声明为控制器方法的输入,Spring 会根据 mime 类型自动调用消息转换器,然后调用验证器。示例见Add JSON message converter for multipart/form-data。
最后,您可以随时手动调用验证:Manually call Spring Annotation Validation。