How to check the extension and size of uploaded files

--Environment - CentOS Linux release 7.8.2003 (Core) - Eclipse IDE for Enterprise Java Developers.Version: 2020-03 (4.15.0) - openjdk version "11.0.7" 2020-04-14 LTS - JSF 2.3.9

Thing you want to do

  1. I want to make an error if the extension of the uploaded file is not the specified one
  2. I want to make an error if the size of the uploaded file is larger than specified
  3. I want to specify the error message on the parent screen

Extract name and size from File interface and check

The File object is a special kind of Blob object that can be used wherever Blobs are available. File - Web API | MDN

I want to make an error if the file extension is not the specified one

upload.js


/**
 *Determine if the extension is correct.
 * @param  {string}file name.
 * @return {Boolean} true:correct.
 */
function isCorrectExtension(name) {
    //Starting with a character other than a space, ".jpg」「.png」「.gif」「.Characters ending in "psf"(Case insensitive[i])
    var format = new RegExp('([^\s]+(\\.(jpg|png|gif|pdf))$)', 'i');
    return format.test(name);
}
special character meaning
^ Match to the beginning of the input
$ Match at the end of the input
\s Matches whitespace characters including spaces, tabs, page breaks, and line breaks

--Reference -How to validate the extension of an image file with a regular expression -Regular expression --JavaScript | MDN -Regular expression (RegExp)-Introduction to Tohoho's WWW -Regular expression escaping in Javascript-Qiita

I want to make an error if the file size is larger than specified

upload.js


/**
 *Determine if the file size is correct.
 * @param  {number}file size(Byte unit).
 * @return {Boolean} true:correct.
 */
function isCorrectSize(size) {
    /** @type {number}Maximum size allowed(1MB). */
    var maxSize = 1024 * 1024;
    return size <= maxSize;
}

--Reference: Byte conversion --High-precision calculation site

I want to specify the error message on the parent screen

Three methods that I came up with so that I can use it according to the situation

Method 1. Get from the parent screen with JavaScript window.opener

  1. Set the error message as a hidden item on the parent screen
  2. Get using window.opener in JavaScript processing of child screen

--Reference -Operating the parent window from the child window | Private miscellaneous notes -[JavaScript] Refer to the parent window from the subwindow (window.opener) | JavaScript reverse lookup that can be used with copy and paste

Parent screen


...abridgement...
<h:inputHidden id="extErrMessage" value="The extension is out of scope." />
<h:inputHidden id="sizeErrMessage" value="The file size is too large." />
...abridgement...

upload.js


...abridgement...
        if (!isCorrectExtension(file.name)) {
            errMessage += window.opener.$('#extErrMessage').text();
        }
        if (!isCorrectSize(file.size)) {
            if (errMessage != '') {
                errMessage += '<br />';
            }
            errMessage += window.opener.$('#sizeErrMessage').text();
        }
...abridgement...

Method 2. Pass a message as a parameter when displaying a child screen

  1. Set the error message with the GET parameter when generating JavaSctipt that displays the child screen on the parent screen.
  2. After opening the child screen, receive the parameter with f: viewParam and set it as the backing bean
  3. Put the backing bean error message in JSON format
  4. Get the error message using parseJSON in JavaScript

Parent screen


...abridgement...
<input type="button" value="upload" onclick="#{uploadBean.onClick}" />
...abridgement...

UploadBean.java


    /**
     *Get the JavaScript code to output for the onClick attribute.
     * @return JavaScript code.
     */
    public String getOnClick() {
        StringBuilder builder = new StringBuilder();
        builder.append("window.open('upload.jsf");
        builder.append("?key=");
        builder.append(urlEncode("formId:file"));
        builder.append("&extErrMessage=");
        builder.append(urlEncode("The extension is out of scope."));
        builder.append("&sizeErrMessage=");
        builder.append(urlEncode("The file size is too large."));
        builder.append("', '', 'width=500,height=100'); return false;");
        return builder.toString();
    }

    /**
     *URL-encoded org and returned.
     * @param org
     * @return
     */
    private String urlEncode(String org) {
        try {
            return URLEncoder.encode(org, "utf-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

upload.xml(Child screen)


...abridgement...
  <f:metadata>
    <ui:remove>Receive GET parameters</ui:remove>
    <f:viewParam name="key" value="#{uploadBean.key}"/>
    <f:viewParam name="extErrMessage" value="#{uploadBean.extErrMessage}" />
    <f:viewParam name="sizeErrMessage" value="#{uploadBean.sizeErrMessage}" />
  </f:metadata>
  <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
  <h:outputScript library="js" name="upload.js"/>
  <ui:remove>Put the error message in JSON format</ui:remove>
  <script id="errMessage" type="application/json">
    {"ext" : "#{uploadBean.extErrMessage}", "size" : "#{uploadBean.sizeErrMessage}"}
  </script>
...abridgement...

upload.js


...abridgement...
        /** @type {array}Error message placed in the head tag. */
        var message = $.parseJSON($('#errMessage').html());
        /** @type {object}Selected file. */
        var file = inputFile.files[0];
        if (!isCorrectExtension(file.name)) {
            errMessage += message.ext;
        }
        if (!isCorrectSize(file.size)) {
            if (errMessage != '') {
                errMessage += '<br />';
            }
            errMessage += message.size;
        }
...abridgement...

Method 3. Use the same backing bean on the parent-child screen

  1. Implement error message acquisition processing in the common backing bean on the parent and child screens
  2. The rest is the same as after "Put the backing bean error message in JSON format" in "Method 2. Pass the message by parameter when displaying the child screen".

UploadBean.java


...abridgement...
    /**
     *Get the error message when an error occurs in the extension.
     * @return error message.
     */
    public String getExtErrMessage() {
        return "The extension is out of scope.";
    }

    /**
     *Get the error message when an error occurs in the size.
     * @return error message.
     */
    public String getSizeErrMessage() {
        return "The file size is too large.";
    }
...abridgement...

upload.xml(Child screen)


  <ui:remove>Put the error message in JSON format</ui:remove>
  <script id="errMessage" type="application/json">
    {"ext" : "#{uploadBean.extErrMessage}", "size" : "#{uploadBean.sizeErrMessage}"}
  </script>

Whole implementation

Parent screen


<?xml version='1.0' encoding='UTF-8' ?>
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
  xmlns:h="http://xmlns.jcp.org/jsf/html"
  xmlns:f="http://xmlns.jcp.org/jsf/core">
<ui:composition template="template.xhtml">
<ui:define name="js">
  <h:outputScript library="js" name="upload.js"/>
</ui:define>
<ui:define name="content">
  <h3>Try to check the input of the file</h3>
  <h:form id="formId">
    <div id="uploadArea">
      <ui:fragment rendered="#{!uploadBean.upload}">
        <h:button value="upload" onclick="showPopup();"/>
        <h:inputText id="file" style="display:none;">
          <f:ajax event="change" execute="@form" render="@form" listener="#{uploadBean.uploadFile}" />
        </h:inputText>
      </ui:fragment>
      <ui:fragment rendered="#{uploadBean.upload}">
        <h:outputText value="#{uploadBean.file.name}" />
        <h:commandButton value="Delete">
          <f:ajax execute="@form" render="@form" listener="#{uploadBean.deleteFile}" />
        </h:commandButton>
      </ui:fragment>
      <div><h:message for="uploadArea" errorClass="error" warnClass="warn" infoClass="info" /></div>
    </div>
  </h:form>
</ui:define>
</ui:composition>
</html>

upload.xhtml(Child screen)


<?xml version='1.0' encoding='UTF-8' ?>
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
  xmlns:h="http://xmlns.jcp.org/jsf/html"
  xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
  <title>File to upload</title>
  <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
  <h:outputScript library="js" name="upload.js"/>
  <ui:remove>Put the error message in JSON format</ui:remove>
  <script id="errMessage" type="application/json">
    {"ext" : "#{uploadBean.extErrMessage}", "size" : "#{uploadBean.sizeErrMessage}"}
  </script>
</h:head>
<body>
  <div>
    <h:inputFile id="inputFile" onchange="checkFile(this)" value="uploadBean.file" />
  </div>
  <div>
    <h:button value="OK" onclick="submit('#{uploadBean.key}');" />
    <h:button value="close" onclick="window.close();" />
  </div>
</body>
</html>

upload.js


/**Display a pop-up screen. */
function showPopup() {
    window.open('upload.jsf', '', 'width=500,height=100');
}
/**
 *Check uploaded files.
 * @param {Object}File object.
 */
function checkFile(inputFile) {
    //Delete the error message.
    $('.errMessage').remove();
    /** @type {String}Error message to display. */
    var errMessage = '';
    if (inputFile.files && inputFile.files[0]) {
        /** @type {array}Error message placed in the head tag. */
        var message = $.parseJSON($('#errMessage').html());
        /** @type {object}Selected file. */
        var file = inputFile.files[0];
        if (!isCorrectExtension(file.name)) {
            errMessage += message.ext;
        }
        if (!isCorrectSize(file.size)) {
            if (errMessage != '') {
                errMessage += '<br />';
            }
            errMessage += message.size;
        }
    }
    if (errMessage != '') {
        //Add error message.
        $('#inputFile').after('<br /><span class="errMessage" style="color: red;">' + errMessage + '</span>');
        //Delete file.
        inputFile.value = null;
    }
}

/**
 *Determine if the extension is correct.
 * @param  {string}file name.
 * @return {Boolean} true:correct.
 */
function isCorrectExtension(name) {
    var format = new RegExp('([^\s]+(\\.(jpg|png|gif|pdf))$)', 'i');
    return format.test(name);
}

/**
 *Determine if the file size is correct.
 * @param  {number}file size(Byte unit).
 * @return {Boolean} true:correct.
 */
function isCorrectSize(size) {
    /** @type {number}Maximum size allowed(1MB). */
    var maxSize = 1024 * 1024;
    return size <= maxSize;
}

/**
 *Update the elements of the parent screen and close the screen.
 * @param  {string}key id of the parent screen element to update.
 */
function submit(key) {
    window.opener.$('#'+key.replace(/:/g,"\\:")).change();
    window.close();
}

UploadBean.java


package brans;

import java.io.IOException;
import java.io.Serializable;

import javax.faces.view.ViewScoped;
import javax.inject.Named;
import javax.servlet.http.Part;

import lombok.Data;

@Named
@ViewScoped
@Data
public class UploadBean implements Serializable {
    /** serialVersionUID. */
    private static final long serialVersionUID = -355651229394801584L;
    /**File data. */
    private Part file;

    /**
     *Determine if the file has been uploaded.
     * @return true:Have been uploaded.
     */
    public boolean isUpload() {
        return this.file != null;
    }

    /**
     *Get the error message when an error occurs in the extension.
     * @return error message.
     */
    public String getExtErrMessage() {
        return "The extension is out of scope.";
    }

    /**
     *Get the error message when an error occurs in the size.
     * @return error message.
     */
    public String getSizeErrMessage() {
        return "The file size is too large.";
    }

    public String getKey() {
        return "formId:file";
    }

    public void uploadFile() throws IOException {
        if (!isUpload()) {
            return;
        }
        if (!isCorrectExtension(this.file.getName())) {
            deleteFile();
        }
        if (!isCorrectSize(this.file.getSize())) {
            deleteFile();
        }
    }

    /**
     *Delete the uploaded file.
     * @throws IOException error occurred.
     */
    public void deleteFile() throws IOException {
        this.file.delete();
    }

    /**
     *Determine if the extension is correct.
     * @param name file name.
     * @return true:correct.
     */
    private boolean isCorrectExtension(String name) {
        if (name != null) {
            return name.matches("([^\\s]+(\\.(?i)(jpg|png|gif|pdf))$)");
        }
        return true;
    }

    /**
     *Determine if the file size is correct.
     * @param size file size(Part-Time Job).
     * @return true:correct.
     */
    private boolean isCorrectSize(long size) {
        long maxSize = 1024 * 1024;
        return size <= maxSize;
    }
}

Recommended Posts

How to check the extension and size of uploaded files
Command to check the number and status of Java threads
How to check the database of apps deployed on Heroku
[Rails] How to get the URL of the transition source and redirect
[Swift5] How to get an array and the complement of arrays
How to set the IP address and host name of CentOS8
How to place and share SwiftLint config files on the server
How to check for the contents of a java fixed-length string
[Java] How to output and write files!
How to determine the number of parallels
How to sort the List of SelectItem
How to find the tens and ones
Method definition location Summary of how to check When defined in the project and Rails / Gem
How to change the maximum and maximum number of POST data in Spark
[Java improvement case] How to reach the limit of self-study and beyond
Android development, how to check null in the value of JSON object
JDBC promises and examples of how to write
How to find the cause of the Ruby error
Check the version of the JDK installed and the version of the JDK enabled
How to check the logs in the Docker container
Customize how to divide the contents of Recyclerview
How to get today's day of the week
Output of how to use the slice method
How to display the result of form input
How to find the total score and average score
How to build parquet-tools and merge Parquet files
[Java] How to get the authority of the folder
How to check Rails commands in the terminal
How to check the latest version of io.spring.platform to describe in pom.xml of Spring (STS)
Differences between Java, C # and JavaScript (how to determine the degree of obesity)
[Java] How to get the URL of the transition source
How to delete / update the list field of OneToMany
How to write Scala from the perspective of Java
Convert the array of errors.full_messages to characters and output
[Ruby] How to find the sum of each digit
How to install the root certificate of Centos7 (Cybertrust)
[Java] How to get the maximum value of HashMap
[Rails] How to change the column name of the table
[SwiftUI] How to specify the abbreviated position of Text
[Android] How to get the setting language of the terminal
How to handle TSV files and CSV files in Ruby
How to check CircleCI code and automatically deploy to Heroku
[Rails] How to get the contents of strong parameters
How to judge the click of any area of the image
How to download the old version of Apache Tomcat
[Ruby] How to get the tens place and the ones place
[Swift] How to get the document ID of Firebase
[Linux] Easy commentary! How to check and change permissions
If you use SQLite with VSCode, use the extension (how to see the binary file of sqlite3)
Do you really understand? How to check the library and license used by the app
A memo about the types of Java O/R mappers and how to select them
How to use UsageStatsManager in Android Studio (How to check the startup time of other apps)
[ruby] How to assign a value to a hash by referring to the value and key of another hash
How to set the retry limit of sidekiq and notify dead queues with slack
[Rough explanation] How to separate the operation of the production environment and the development environment with Rails
How to correctly check the local HTML file in the browser
[Ruby On Rails] How to search and save the data of the parent table from the child table
[AWS] How to check logs
[Swift5] How to analyze complex JSON and get the index of the element that satisfies the condition
How to display the select field of time_select every 30 minutes
How to handle uploaded images