Die Durchführung eines direkten Upgrades der Anwendung auf Servlet 3.1 verlief einwandfrei, wobei ich die Tatsache ignorierte, dass ich die Antwort sofort zurückgab, da es mir mehr darum ging, zu testen, ob die Datei selbst korrekt hochgeladen wurde und onDataAvailable() wurde mehrmals korrekt aufgerufen. Das Problem tritt auf, wenn ich das DeferredResult-Objekt verwende (das anscheinend mehr oder weniger für diesen Zweck erfunden wurde), um den Ansichtsnamen an den Controller zurückzugeben, da ich den Client offensichtlich darüber informieren muss, ob der Upload erfolgreich war oder nicht, und ich sehe keine andere Möglichkeit, dies in dieser asynchronen Umgebung zu tun.
Wenn ich das DeferredResult-Objekt zurückgebe, wird es fälschlicherweise direkt an den Client zurückgegeben und beim ersten onDataAvailable()-Aufruf des inputStream kann nicht gelesen werden, da ich die Ausnahme „java.io.IOException: Stream geschlossen“ erhalte. Ein Aufruf von getDispatcherType() hier sagt mir, dass der Typ jetzt zu DispatcherType.ERROR gewechselt ist, während der Typ immer noch DispatcherType.REQUEST ist, wenn ich den Code ohne das DeferredResult-Objekt ausführe (und trotzdem sofort antworte). Ich hatte gedacht, dass irgendwo im Stapel der InputStream früh gelesen wird (nicht von mir) und dies verursacht, aber das scheint nicht der Fall zu sein und das Seltsame ist, dass inputStream.isReady() true und inputStream.isFinished() false zurückgibt und ich den Text aus der Datei im Puffer beim ersten onDataAvailable() sehen kann, aber ich kann einfach nicht direkt aus dem inputStream lesen, ohne die Ausnahme java.io.IOException: Stream geschlossen zu bekommen.
Kein Testaufwand Bei kleinen oder wirklich großen Dateien ändert sich das Verhalten. Hat jemand das DeferredResult erfolgreich in Spring MVC und dem Servlet 3.1 verwendet? Ich bin jetzt schon seit ein paar Tagen ratlos und habe mehr Code debuggt, als ich wieder tun möchte!
Hier kommt mein Code (ein paar geschäftliche Dinge abgeschnitten, falls Sie denken, dass er etwas blutleer aussieht)
Code: Select all
@Controller
public class ContentController {
@RequestMapping(value = “/upload/“, method = POST)
public DeferredResult upload(ServletRequest request) throws IOException, InterruptedException {
DeferredResult deferredResult = new DeferredResult();
final AsyncContext asyncContext = httpServletRequest.startAsync();
ServletInputStream servletInputStream = httpServletRequest.getInputStream();
NioReadListener readListener = new NioReadListener(servletInputStream, asyncContext, deferredResult, size);
servletInputStream.setReadListener(readListener);
return deferredResult
}
public class NioReadListener implements ReadListener {
private final ServletInputStream _input;
private final AsyncContext _context;
private final DeferredResult deferredResult;
public NioReadListener(ServletInputStream servletInputStream, AsyncContext asyncContext, DeferredResult deferredResult, Long size) throws IOException {
this._input = servletInputStream;
this._context = asyncContext;
this.deferredResult = deferredResult;
}
@Override
public void onDataAvailable() throws IOException {
try {
int bytesRead;
byte b[] = new byte[_size.intValue()];
while (_input.isReady() && (bytesRead = _input.read(b)) != -1) {
_totalBytesRead += bytesRead;
}
} catch (IOException e) {
_log.error(e);
}
}
@Override
public void onAllDataRead() throws IOException {
this._context.complete();
deferredResult.setResult("VIEW_NAME");
}
}
Mobile version