Spring: How to import data via CSV
In this article, I want to show you how you can import data via a CSV file in a cloud based application.
This request will be processed by my spring rest controller.
I will get the file via the request parameter with type :
If the file content is not empty, I can extract the bytes and encode them as Base64 encoding using java 8 utility.
In order to do the work outside of a user-facing request, I use the Google Cloud Platform (GCP)
I can pass the encoded content as a task parameter. In parallel to the user facing request, a servlet will do the job with the specified parameter.
Spring controller
In order to upload the CSV file, we will use an HTTP POST request with mime type as
multipart/form-data
.This request will be processed by my spring rest controller.
I will get the file via the request parameter with type :
MultipartFile
.If the file content is not empty, I can extract the bytes and encode them as Base64 encoding using java 8 utility.
In order to do the work outside of a user-facing request, I use the Google Cloud Platform (GCP)
task queues
mechanism.I can pass the encoded content as a task parameter. In parallel to the user facing request, a servlet will do the job with the specified parameter.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@RestController | |
@RequestMapping("/assessment-equipments") | |
public class AssessmentEquipmentController { | |
private final AssessmentEquipmentService assessmentEquipmentService; | |
private final AssessmentMeasureService assessmentMeasureService; | |
public AssessmentEquipmentController(AssessmentEquipmentService assessmentEquipmentService, | |
AssessmentMeasureService assessmentMeasureService) { | |
this.assessmentEquipmentService = assessmentEquipmentService; | |
this.assessmentMeasureService = assessmentMeasureService; | |
} | |
@PostMapping("/{id}/uncertainties") | |
public ResponseEntity<String> saveUncertainties(@NotNull @PathVariable Long id, | |
@RequestParam("file") MultipartFile file) { | |
if (file.isEmpty()) { | |
return new ResponseEntity<>("Please select a file!", HttpStatus.OK); | |
} | |
try { | |
byte[] content = file.getBytes(); | |
Queue queue = QueueFactory.getDefaultQueue(); | |
queue.add(TaskOptions.Builder.withUrl("/admin/assessment-measures") | |
.param("id", String.valueOf(id)) | |
.param("csv", Base64.getEncoder().encodeToString(content))); | |
return new ResponseEntity<>("The CSV file for the assessment equipment with ID [" + id + "] will be processed soon.", HttpStatus.OK); | |
} catch (IOException e) { | |
return new ResponseEntity<>("Oops something goes wrong!", HttpStatus.CONFLICT); | |
} | |
} | |
} |
Servlet Consumer
The servlet is pretty straightforward :- It extracts the encoded content
- It decode the encoded content
- It loads object list from the CSV content (jackson csv)
- It calls a service with the list of objects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@WebServlet( | |
name = "AssessmentMeasureImporter", | |
description = "Import CSV file for assessment measure", | |
urlPatterns = "/admin/assessment-measures" | |
) | |
public class AssessmentMeasureImporter extends HttpServlet { | |
@Autowired | |
private AssessmentMeasureService assessmentMeasureService; | |
public void init(ServletConfig config) throws ServletException { | |
super.init(config); | |
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, | |
config.getServletContext()); | |
} | |
public void doPost(HttpServletRequest request, HttpServletResponse response) { | |
Long id = ServletUtils.getLongParameter(request, "id"); | |
byte[] content = ServletUtils.getBytesParameter(request, "csv"); | |
List<AssessmentMeasureDto> assessmentMeasures = CsvUtils | |
.loadObjectList(AssessmentMeasureDto.class, content); | |
assessmentMeasureService.saveByAssessmentEquipment(id, assessmentMeasures); | |
response.setStatus(200); | |
} | |
} |
CSV Utility
In the servlet, I've called a utility method for reading the CSV content into an array of Objects.
I use for this purpose the Jackson library.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<dependency> | |
<groupId>com.fasterxml.jackson.dataformat</groupId> | |
<artifactId>jackson-dataformat-csv</artifactId> | |
<version>2.9.9</version> | |
</dependency> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static <T> List<T> loadObjectList(Class<T> type, byte[] content) { | |
Assert.notNull(type,"type must not be null"); | |
Assert.notNull(content,"content must not be null"); | |
try { | |
CsvSchema schema = CsvSchema.emptySchema().withHeader(); | |
CsvMapper mapper = new CsvMapper(); | |
MappingIterator<T> readValues = mapper.readerFor(type) | |
.with(schema).readValues(content); | |
return readValues.readAll(); | |
} catch (Exception e) { | |
return Collections.emptyList(); | |
} | |
} |
Happy learning...
Comments
Post a Comment