Бэкенд (Spring)
Код: Выделить всё
public ResponseEntity downloadFeedbackCsv(String search, HttpServletRequest request) {
List rows = feedbackService.findAllForExport(search, request);
String csvContent = generateFeedbackCsv(rows);
byte[] bytes = csvContent.getBytes(StandardCharsets.UTF_8);
ByteArrayResource resource = new ByteArrayResource(bytes);
String fileName = "feedback" + nowStamp() + ".csv";
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"");
headers.add("File-Name", fileName);
headers.add("Access-Control-Expose-Headers", "File-Name");
return ResponseEntity.ok()
.headers(headers)
.contentType(MediaType.parseMediaType("text/csv"))
.contentLength(resource.contentLength())
.body(resource);
}
private String generateFeedbackCsv(List rows) {
StringWriter writer = new StringWriter();
try (CSVPrinter csv = new CSVPrinter(writer, CSVFormat.DEFAULT
.withHeader("Id", "Date", "Creation Date", "Sensor Code", "Reading Value",
"Latitude", "Longitude", "Altitude", "Status value",
"Battery level", "Sensor state"))) {
for (Feedback f : rows) {
csv.printRecord(
f.getFeedbackId(),
f.getFeedDate(),
f.getFeedCreationDate(),
f.getSensCode(),
f.getFeedValue(),
f.getLatitude(),
f.getLongitude(),
f.getAltitude(),
f.getFeedAlphanumericValue(),
f.getFeedBattery(),
f.getFeedState()
);
}
} catch (Exception e) {
log.error("Error while generating feedback list CSV", e);
}
return writer.toString();
}
@GetMapping("/download")
@Operation(summary = "Download feedback list", description = "Returns a CSV file with feedback data")
public ResponseEntity downloadFeedbackList(
@RequestParam(defaultValue = "", name = "search") String search,
HttpServletRequest request) {
return utilitiesService.downloadFeedbackCsv(search, request);
}
JWT добавляется перехватчиком HTTP (токен-носитель)
Код: Выделить всё
public onDownloadFeedbacks(): void {
const filterString = this.dataSource.filterToString(this.filters);
this.feedbackService.downloadFeedbacks(filterString)
.pipe(takeUntil(this.destroy$))
.subscribe(event => {
if (event.type == HttpEventType.Response) {
saveAs(
new File(
[event.body!],
event.headers.get('File-Name')!,
{ type: `${event.headers.get('Content-Type')};charset=utf-8` }
)
);
} else {
console.log(event);
}
});
}
downloadFeedbacks(filterString: string): Observable {
const url = `${config.apiUrl}/api/feedback/download`;
return this.http.get(url, {
reportProgress: true,
observe: 'events',
responseType: 'blob',
params: new HttpParams().set('search', filterString)
})
.pipe(tap(() => console.log(`fetched feedbacks file`)));
}
- Сохраняя текущий подход HttpClient + FileSaver. Но перед сохранением всегда требуется полный BLOB-объект.
- Использую ссылку, но у меня проблема с аутентификацией; также по-прежнему имеет тенденцию загружаться первым при использовании XHR/Blob.
Подробнее здесь: https://stackoverflow.com/questions/797 ... ds-save-as