【发布时间】:2018-08-28 03:26:10
【问题描述】:
环境 jhipster,角度 5, 弹簧靴
我的应用程序具有上传和下载文件功能。文件作为二进制 blob 存储在 db 中。
我可以下载小文件。但是,大文件(例如 35M)会出现此错误。 (这些大文件是应用上传的)
根据堆栈跟踪,java.util.Arrays.copyOf 正在引发错误。 hibernate 将此数组称为 fn。我假设尝试将 35M 的二进制数据(以 blob 形式)放置在可以容纳 2M 左右的数组中。
是否有解决方法或解决方法来处理大数据?我们可以告诉hibernate将数据分块吗?
通过堆栈跟踪扫描还给出了指向 com.neemshade.sniper.security.jwt.JWTFilter.doFilter(JWTFilter.java:36) 的指针 第36行是
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String jwt = resolveToken(httpServletRequest);
if (StringUtils.hasText(jwt) && this.tokenProvider.validateToken(jwt)) {
Authentication authentication = this.tokenProvider.getAuthentication(jwt);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(servletRequest, servletResponse); <-- this code
}
如果这个过滤器是错误的根源,它会是休眠问题吗?
我的代码说明。 afterDownload() 调用服务器 api 下载二进制文件。一旦数据可用,将调用 saveToLocal() 以弹出“另存为”对话框以将二进制数据存储在文件中。
这是我的客户端代码:
afterDownload(event) {
this.pending = true;
this.extTaskService.downloadFiles(this.source, this.id, this.selectedTasks)
.subscribe(
(data) => {
this.jhiAlertService.success('success! downloaded files. ');
console.log(data);
this.saveToLocal(data);
this.uponCompletion(true);
this.pending = false;
},
(err) => {
this.jhiAlertService.error('error in download! ' + err.message, null, null);
console.log(JSON.stringify(err));
this.pending = false;
},
() => this.jhiAlertService.success('downloaded files', null, null)
);
}
saveToLocal(response) {
console.log('inside saveToLocal');
const ieEDGE = navigator.userAgent.match(/Edge/g);
const ie = navigator.userAgent.match(/.NET/g); // IE 11+
const oldIE = navigator.userAgent.match(/MSIE/g);
const blob = new Blob([response], { type: 'application/octet-stream'});
const fileName = 'files.zip';
if (ie || oldIE || ieEDGE) {
console.log('got to ie');
window.navigator.msSaveBlob(blob, fileName);
} else {
const reader = new FileReader();
reader.onloadend = function() {
console.log('onloadend');
window.location.href = reader.result;
};
console.log('readAsDataURL');
reader.readAsDataURL(blob);
}
}
客户服务:
downloadFiles(source: string, id: number, selectedTasks: Task[]): Observable<any> {
const finalUrl: string = this.resourceUrl + 'download-files/' + source + '/' + id + '/' +
(selectedIds == null || selectedIds === '' ? '0' : selectedIds);
return this.http.get(finalUrl, { responseType: 'blob' });
}
服务器端: extDownloaderService.downloadFiles() 准备输出二进制数据。我将小块的数据刷新到响应中。
@GetMapping(value="download-files/{source}/{id}/{selectedIds}", produces="application/zip")
@ResponseBody
public void downloadFiles(
@PathVariable String source, @PathVariable(value = "id") Long id,
@PathVariable(value = "selectedIds") String selectedIds, HttpServletResponse response) throws Exception {
byte[] bytes = extDownloaderService.downloadFiles(source, id, selectedIds);
// headers.add("Content-Type", "application/octet-stream");
response.setHeader("Content-Type", "application/zip");
response.setHeader("Content-Disposition", "attachment; filename=\"files.zip\"");
OutputStream os = response.getOutputStream();
try
{
ByteArrayInputStream byteIs = new ByteArrayInputStream(bytes);
byte[] buf=new byte[8192];
int bytesread = 0, bytesBuffered = 0;
while( (bytesread = byteIs.read( buf )) > -1 ) {
os.write( buf, 0, bytesread );
bytesBuffered += bytesread;
if (bytesBuffered > 1024 * 1024) { //flush after 1MB
bytesBuffered = 0;
os.flush();
}
}
}
finally {
if (os != null) {
os.flush();
}
}
os.close();
// return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
}
当使用大文件运行应用程序时,我得到了这个堆栈跟踪。
@400000005aaeaf751478b324 原因:java.lang.OutOfMemoryError: Java 堆空间@400000005aaeaf751478baf4 在 java.util.Arrays.copyOf(java.base@9-internal/Arrays.java:3744) @400000005aaeaf751478bedc 在 java.lang.AbstractStringBuilder.ensureCapacityInternal(java.base@9-internal/AbstractStringBuilder.java:146) @400000005aaeaf751478bedc 在 java.lang.AbstractStringBuilder.append(java.base@9-internal/AbstractStringBuilder.java:510) @400000005aaeaf751478c2c4 在 java.lang.StringBuilder.append(java.base@9-internal/StringBuilder.java:141) @400000005aaeaf751478ca94 在 java.util.Arrays.toString(java.base@9-internal/Arrays.java:4958) @400000005aaeaf751478ca94 在 org.hibernate.type.descriptor.java.PrimitiveByteArrayTypeDescriptor.extractLoggableRepresentation(PrimitiveByteArrayTypeDescriptor.java:63) @400000005aaeaf751478ce7c 在 org.hibernate.type.descriptor.java.PrimitiveByteArrayTypeDescriptor.extractLoggableRepresentation(PrimitiveByteArrayTypeDescriptor.java:26) @400000005aaeaf751478de1c 在 org.hibernate.type.AbstractStandardBasicType.toLoggableString(AbstractStandardBasicType.java:296) @400000005aaeaf751478e204 在 org.hibernate.type.TypeHelper.toLoggableString(TypeHelper.java:439) @400000005aaeaf751478e204 在 org.hibernate.cache.spi.entry.StandardCacheEntryImpl.(StandardCacheEntryImpl.java:60) @400000005aaeaf751478e9d4 在 org.hibernate.persister.entity.AbstractEntityPersister$StandardCacheEntryHelper.buildCacheEntry(AbstractEntityPersister.java:5307) @400000005aaeaf751478edbc 在 org.hibernate.persister.entity.AbstractEntityPersister.buildCacheEntry(AbstractEntityPersister.java:4307) @400000005aaeaf751478edbc 在 org.hibernate.engine.internal.TwoPhaseLoad.doInitializeEntity(TwoPhaseLoad.java:196) @400000005aaeaf751478f58c 在 org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:125) @400000005aaeaf751478f58c 在 org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.performTwoPhaseLoad(AbstractRowReader.java:238) @400000005aaeaf751478f974 在 org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishUp(AbstractRowReader.java:209) @400000005aaeaf751478fd5c 在 org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:133) @400000005aaeaf7514790cfc 在 org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:122) @400000005aaeaf7514790cfc 在 org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:86) @400000005aaeaf75147910e4 在 org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:167) @400000005aaeaf75147918b4 在 org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4083) @400000005aaeaf7514791c9c 在 org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:508) @400000005aaeaf7514791c9c 在 org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:478) @400000005aaeaf751479246c 在 org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:219) @400000005aaeaf751479246c 在 org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:278) @400000005aaeaf7514792854 在 org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:121) @400000005aaeaf75147937f4 在 org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:89) @400000005aaeaf7514793bdc 在 org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1239) @400000005aaeaf7514793bdc 在 org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1122) @400000005aaeaf7514793fc4 在 org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:646) @400000005aaeaf7514794f64 在 org.hibernate.type.EntityType.resolve(EntityType.java:431) @400000005aaeaf7514794f64 在 org.hibernate.engine.internal.TwoPhaseLoad.doInitializeEntity(TwoPhaseLoad.java:165)
任何帮助表示赞赏。
【问题讨论】:
-
不要将文件读入内存。而是直接将其流式传输到
OutputStream。` -
二进制数据来自db。它存储为 blob。我正在接受并流式传输响应
-
@M.Deinum,有没有办法从数据库中获取 blob 字段作为流?
标签: angular hibernate spring-boot jhipster