有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java使Wicket行为返回JSON结果,以便与jQuery FileUpload集成

为了将jQuery FileUpload集成到我的Wicket项目中,我注册了一个AbstractAjaxBehavior并将其URL传递给文件输入组件,这样就可以将它传递给jQuery FileUpload。即,在文件上载面板的构造函数中:

AbstractAjaxBehavior fileUploadBehavior = new AbstractDefaultAjaxBehavior() {
  @Override
  protected synchronized void respond(AjaxRequestTarget target) {
    // TODO Handle incoming file(s)...
  }
};
WebMarkupContainer file = new WebMarkupContainer("file") {
  @Override
  protected void onComponentTag(ComponentTag tag) {
    super.onComponentTag(tag);

    IValueMap attributes = tag.getAttributes();
    attributes.put("data-upload-url", fileUploadBehavior.getCallbackUrl());
  }
};
add(file);
file.add(fileUploadBehavior);

问题是,我似乎无法阻止该行为返回状态302重定向到我的“stale page”错误页面

因此,问题是:如何防止这种重定向,而不是返回jQuery FileUpload期望的JSON响应


共 (1) 个答案

  1. # 1 楼答案

    可以通过调用

    RequestCycle requestCycle = getRequestCycle();
    requestCycle.scheduleRequestHandlerAfterCurrent(null);
    

    然后可以使用

    WebResponse response = (WebResponse) requestCycle.getResponse();
    response.write(...);
    

    上传的文件可通过以下方式访问:

    ServletWebRequest request = (ServletWebRequest) requestCycle.getRequest();
    ServletFileUpload servletFileUpload = new ServletFileUpload(YourFileItemImpl::new);
    List<FileItem> fileItems = servletFileUpload.parseRequest(request.getContainerRequest());
    

    其中ServletFileUpload来自apachecommons文件上载库YourFileItemImpl是来自同一库的FileItem接口的一些实现。这个类至少应该包含getNamegetSizegetOutputStream方法的适当实现(后者是执行持久化的方法)

    现在可以迭代fileItems列表,以构建要传递给response.write(...)的适当响应

    总之,我们最终实现了以下行为:

    AbstractAjaxBehavior fileUploadBehavior = new AbstractDefaultAjaxBehavior() {
      @Override
      protected synchronized void respond(AjaxRequestTarget target) {
        RequestCycle requestCycle = getRequestCycle();
    
        // Prevent default redirection.
        requestCycle.scheduleRequestHandlerAfterCurrent(null);
    
        ServletWebRequest request = (ServletWebRequest) requestCycle.getRequest();
        ServletFileUpload servletFileUpload = new ServletFileUpload(YourFileItemImpl::new);
    
        try {
          // Initialize JSON response.
          JSONObject jsonResponse = new JSONObject();
          JSONArray jsonFiles = new JSONArray();
          jsonResponse.put("files", jsonFiles);
    
          // Parse and persist uploaded file(s).
          List<FileItem> fileItems = servletFileUpload.parseRequest(request.getContainerRequest());
          // Iterate file items to build JSON response.
          for (FileItem item : fileItems) {
            JSONObject jsonFile = new JSONObject();
            jsonFiles.put(jsonFile);
    
            jsonFile.put("name", item.getName());
            jsonFile.put("size", item.getSize());
    
            // TODO Perform validation, e.g. using Apache Tika for file type detection.
            //      Add any error using `jsonFile.put("error", "[error_message]")`. Should
            //      of course take care to not persist invalid files...
         }
    
         // Write JSON response.
         WebResponse response = (WebResponse) requestCycle.getResponse();
         response.setHeader("Content-Type", "text/html; charset=utf8"); // Because IE...
         response.write(jsonResponse.toString());
       } catch (FileUploadException | IOException | JSONException e) {
         // TODO Handle exception.
       }
     }
    

    您可能还希望捕获fileuploaddone事件,以便可以执行适当的UI更新(您不能再使用fileUploadBehavior执行此操作,但您也只希望每个文件批执行一次UI更新):

    file.add(new AjaxEventBehavior("fileuploaddone") {
      @Override
      protected void onEvent(AjaxRequestTarget target) {
        // Wait until behavior has completed.
        synchronized (fileUploadBehavior) {
          // TODO Add proper components to `target`.
        }
      }
    });
    

    同步respond方法有两个目的:

    1. 一次只接受一个(可能是多文件)上载。这可以防止单体面板最终接受多个文件的争用情况

    2. 确保在respond回调完成之前不处理fileuploaddone事件,即使它在此之前已触发。虽然在实践中不应该发生这种情况,但jQuery FileUpload可能存在错误,这确保了针对这种情况(以及恶意用户)的健壮性

    最后,可以通过添加

    file.add(new AttributeModifier("multiple", "multiple"));
    

    相反,如果需要单文件上传,行为应该验证这一点