From 3ef9ade8902a63bb560892453eeca02bfddefc78 Mon Sep 17 00:00:00 2001 From: Lukasz Lenart Date: Tue, 12 Dec 2023 08:35:31 +0100 Subject: [PATCH] WW-5371 Document how to use the new file upload logic --- .../struts2/action/UploadedFilesAware.java | 2 +- .../JakartaStreamMultiPartRequest.java | 13 +- .../ActionFileUploadInterceptor.java | 113 ++++++------------ .../interceptor/FileUploadInterceptor.java | 3 + 4 files changed, 43 insertions(+), 88 deletions(-) diff --git a/core/src/main/java/org/apache/struts2/action/UploadedFilesAware.java b/core/src/main/java/org/apache/struts2/action/UploadedFilesAware.java index 635e0b2d4..92ec9c98b 100644 --- a/core/src/main/java/org/apache/struts2/action/UploadedFilesAware.java +++ b/core/src/main/java/org/apache/struts2/action/UploadedFilesAware.java @@ -33,7 +33,7 @@ public interface UploadedFilesAware { * Notifies action about the multiple uploaded files, when a single file is uploaded * the list will have just one element * - * @param uploadedFiles a list of {@link UploadedFile}. + * @param uploadedFiles a list of {@link UploadedFile}, cannot be null. It can be empty. */ void withUploadedFiles(List uploadedFiles); diff --git a/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaStreamMultiPartRequest.java b/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaStreamMultiPartRequest.java index 2618d6ace..763b5d634 100644 --- a/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaStreamMultiPartRequest.java +++ b/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaStreamMultiPartRequest.java @@ -44,6 +44,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.stream.Collectors; /** * Multi-part form data request adapter for Jakarta Commons FileUpload package that @@ -109,16 +110,12 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest { return null; } - List files = new ArrayList<>(infos.size()); - for (FileInfo fileInfo : infos) { - UploadedFile file = StrutsUploadedFile.Builder.create(fileInfo.getFile()) + return infos.stream().map(fileInfo -> + StrutsUploadedFile.Builder.create(fileInfo.getFile()) .withContentType(fileInfo.contentType) .withOriginalName(fileInfo.originalName) - .build(); - files.add(file); - } - - return files.toArray(new UploadedFile[0]); + .build() + ).toArray(UploadedFile[]::new); } /* (non-Javadoc) diff --git a/core/src/main/java/org/apache/struts2/interceptor/ActionFileUploadInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/ActionFileUploadInterceptor.java index 1642a890b..c42d125af 100644 --- a/core/src/main/java/org/apache/struts2/interceptor/ActionFileUploadInterceptor.java +++ b/core/src/main/java/org/apache/struts2/interceptor/ActionFileUploadInterceptor.java @@ -33,105 +33,62 @@ import java.util.Enumeration; import java.util.List; /** - * *

* Interceptor that is based off of {@link MultiPartRequestWrapper}, which is automatically applied for any request that - * includes a file. It adds the following parameters, where [File Name] is the name given to the file uploaded by the - * HTML form: - *

- *
    - * - *
  • [File Name] : File - the actual File
  • - * - *
  • [File Name]ContentType : String - the content type of the file
  • - * - *
  • [File Name]FileName : String - the actual name of the file uploaded (not the HTML name)
  • - * - *
- * - *

You can get access to these files by merely providing setters in your action that correspond to any of the three - * patterns above, such as setDocument(File document), setDocumentContentType(String contentType), etc. - *
See the example code section. + * includes a file when the support for multi-part request is enabled, + * see Disabling file upload. *

* - *

This interceptor will add several field errors, assuming that the action implements {@link ValidationAware}. + *

+ * You can get access to these files by implementing {@link UploadedFilesAware} interface. The interceptor will then + * call {@link UploadedFilesAware#withUploadedFiles(List)} when there are files which were accepted during the upload process. + *

+ * + *

+ * This interceptor will add several field errors, assuming that the action implements {@link ValidationAware}. * These error messages are based on several i18n values stored in struts-messages.properties, a default i18n file * processed for all i18n requests. You can override the text of these messages by providing text for the following * keys: *

* *
    - * *
  • struts.messages.error.uploading - a general error that occurs when the file could not be uploaded
  • - * *
  • struts.messages.error.file.too.large - occurs when the uploaded file is too large
  • - * *
  • struts.messages.error.content.type.not.allowed - occurs when the uploaded file does not match the expected * content types specified
  • - * *
  • struts.messages.error.file.extension.not.allowed - occurs when the uploaded file does not match the expected * file extensions specified
  • - * *
- *

- * - * - *

Interceptor parameters:

- *

- * * + *

Interceptor parameters:

*
    - * *
  • maximumSize (optional) - the maximum size (in bytes) that the interceptor will allow a file reference to be set * on the action. Note, this is not related to the various properties found in struts.properties. * Default to approximately 2MB.
  • - * *
  • allowedTypes (optional) - a comma separated list of content types (ie: text/html) that the interceptor will allow * a file reference to be set on the action. If none is specified allow all types to be uploaded.
  • - * *
  • allowedExtensions (optional) - a comma separated list of file extensions (ie: .html) that the interceptor will allow * a file reference to be set on the action. If none is specified allow all extensions to be uploaded.
  • *
- *

- *

- * * - *

Extending the interceptor:

- *

- *

- *

- * - *

- * You can extend this interceptor and override the acceptFile method to provide more control over which files - * are supported and which are not. - *

- * - * - *

Example code:

+ *

Example code:

* *
- * 
  * <action name="doUpload" class="com.example.UploadAction">
- *     <interceptor-ref name="fileUpload"/>
+ *     <interceptor-ref name="actionFileUpload"/>
  *     <interceptor-ref name="basicStack"/>
  *     <result name="success">good_result.jsp</result>
  * </action>
- * 
  * 
*

- * *

* You must set the encoding to multipart/form-data in the form where the user selects the file to upload. *

- * - * *
- * 
  *   <s:form action="doUpload" method="post" enctype="multipart/form-data">
  *       <s:file name="upload" label="File"/>
  *       <s:submit/>
  *   </s:form>
- * 
  * 
*

* And then in your action code you'll have access to the File object if you provide setters according to the @@ -139,35 +96,33 @@ import java.util.List; *

* *
- * 
- *    package com.example;
+ *  package com.example;
  *
- *    import java.io.File;
- *    import com.opensymphony.xwork2.ActionSupport;
+ *  import java.io.File;
+ *  import com.opensymphony.xwork2.ActionSupport;
+ *  import org.apache.struts2.action.UploadedFilesAware;
  *
- *    public UploadAction extends ActionSupport {
- *       private File file;
- *       private String contentType;
- *       private String filename;
+ *  public UploadAction extends ActionSupport implements UploadedFilesAware {
+ *    private UploadedFile uploadedFile;
+ *    private String contentType;
+ *    private String fileName;
+ *    private String originalName;
  *
- *       public void setUpload(File file) {
- *          this.file = file;
- *       }
+ *    @Override
+ *    public void withUploadedFiles(List uploadedFiles) {
+ *        if (!uploadedFiles.isEmpty() > 0) {
+ *            this.uploadedFile = uploadedFiles.get(0);
+ *            this.fileName = uploadedFile.getName();
+ *            this.contentType = uploadedFile.getContentType();
+ *            this.originalName = uploadedFile.getOriginalName();
+ *        }
+ *    }
  *
- *       public void setUploadContentType(String contentType) {
- *          this.contentType = contentType;
- *       }
- *
- *       public void setUploadFileName(String filename) {
- *          this.filename = filename;
- *       }
- *
- *       public String execute() {
- *          //...
- *          return SUCCESS;
- *       }
+ *    public String execute() {
+ *       //...
+ *       return SUCCESS;
+ *    }
  *  }
- * 
  * 
*/ public class ActionFileUploadInterceptor extends AbstractFileUploadInterceptor { diff --git a/core/src/main/java/org/apache/struts2/interceptor/FileUploadInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/FileUploadInterceptor.java index 287e66078..86f8a64be 100644 --- a/core/src/main/java/org/apache/struts2/interceptor/FileUploadInterceptor.java +++ b/core/src/main/java/org/apache/struts2/interceptor/FileUploadInterceptor.java @@ -172,7 +172,10 @@ import java.util.Map; * } * * + * + * @deprecated since Struts 6.4.0, use {@link ActionFileUploadInterceptor} instead */ +@Deprecated public class FileUploadInterceptor extends AbstractFileUploadInterceptor { private static final long serialVersionUID = -4764627478894962478L;