- 環境
- 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
やりたいこと
- アップロードされたファイルの拡張子が指定のもの以外の場合はエラーにしたい
- アップロードされたファイルのサイズが指定より大きかった場合はエラーにしたい
- エラーメッセージは親画面で指定したい
Fileインターフェースから名前やサイズを取り出してチェック
File オブジェクトは特別な種類の Blob オブジェクトであり、 Blob が利用できる場面ではどこでも利用できます。
File - Web API | MDN
ファイルの拡張子が指定のもの以外の場合はエラーにしたい
upload.js
/**
* 拡張子が正しいか判定する.
* @param {string} ファイル名.
* @return {Boolean} true:正しい.
*/
function isCorrectExtension(name) {
// スペース以外の文字で始まって「.jpg」「.png」「.gif」「.psf」で終わる文字(大文字・小文字を区別しない[i])
var format = new RegExp('([^\s]+(\\.(jpg|png|gif|pdf))$)', 'i');
return format.test(name);
}
特殊文字 | 意味 |
---|---|
^ | 入力の先頭にマッチ |
$ | 入力の末尾にマッチ |
\s | スペース、タブ、改ページ、改行を含むホワイトスペース文字にマッチ |
- 参考
ファイルのサイズが指定より大きかった場合はエラーにしたい
upload.js
/**
* ファイルサイズが正しいかを判定する.
* @param {number} ファイルサイズ(バイト単位).
* @return {Boolean} true:正しい.
*/
function isCorrectSize(size) {
/** @type {number} 許容する最大サイズ(1MB). */
var maxSize = 1024 * 1024;
return size <= maxSize;
}
- 参考 : バイト換算 - 高精度計算サイト
エラーメッセージは親画面で指定したい
状況に合わせて使えるように思い付いた方法3つ
方法1. JavaScriptのwindow.openerで親画面から取得する
- エラーメッセージを親画面の隠し項目で設定しておく
- 子画面のJavaScript処理で
window.opener
を使って取得する
親画面
...省略...
<h:inputHidden id="extErrMessage" value="拡張子が対象外だよ。" />
<h:inputHidden id="sizeErrMessage" value="ファイルサイズが大きすぎるよ。" />
...省略...
upload.js
...省略...
if (!isCorrectExtension(file.name)) {
errMessage += window.opener.$('#extErrMessage').text();
}
if (!isCorrectSize(file.size)) {
if (errMessage != '') {
errMessage += '<br />';
}
errMessage += window.opener.$('#sizeErrMessage').text();
}
...省略...
方法2. 子画面を表示するときにパラメータでメッセージを渡す
- 親画面で子画面を表示するJavaSctiptを生成するときにエラーメッセージをGETのパラメータで設定する
- 子画面を開いたらパラメータを
f:viewParam
で受け取ってバッキングビーンに設定する - バッキングビーンのエラーメッセージをJSON形式で置いておく
- JavaScriptで
parseJSON
を使ってエラーメッセージを取得する
親画面
...省略...
<input type="button" value="アップロード" onclick="#{uploadBean.onClick}" />
...省略...
UploadBean.java
/**
* onClick属性用に出力するJavaScriptコードを取得する.
* @return JavaScriptコード.
*/
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("拡張子が対象外だよ。"));
builder.append("&sizeErrMessage=");
builder.append(urlEncode("ファイルサイズが大きすぎるよ。"));
builder.append("', '', 'width=500,height=100'); return false;");
return builder.toString();
}
/**
* orgをURLエンコードして返す.
* @param org
* @return
*/
private String urlEncode(String org) {
try {
return URLEncoder.encode(org, "utf-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
upload.xml(子画面)
...省略...
<f:metadata>
<ui:remove>GETのパラメータを受け取る</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>エラーメッセージをJSON形式で置いておく</ui:remove>
<script id="errMessage" type="application/json">
{"ext" : "#{uploadBean.extErrMessage}", "size" : "#{uploadBean.sizeErrMessage}"}
</script>
...省略...
upload.js
...省略...
/** @type {array} headタグ内に置いておいたエラーメッセージ. */
var message = $.parseJSON($('#errMessage').html());
/** @type {object} 選択されたファイル. */
var file = inputFile.files[0];
if (!isCorrectExtension(file.name)) {
errMessage += message.ext;
}
if (!isCorrectSize(file.size)) {
if (errMessage != '') {
errMessage += '<br />';
}
errMessage += message.size;
}
...省略...
方法3. 親子画面で同じバッキングビーンを使う
- 親子画面で共通のバッキングビーンにエラーメッセージ取得処理を実装する
- あとは「方法2. 子画面を表示するときにパラメータでメッセージを渡す」の「バッキングビーンのエラーメッセージをJSON形式で置いておく」以降と同じ
UploadBean.java
...省略...
/**
* 拡張しでエラーになった時のエラーメッセージを取得する.
* @return エラーメッセージ.
*/
public String getExtErrMessage() {
return "拡張子が対象外だよ。";
}
/**
* サイズでエラーになった時のエラーメッセージを取得する.
* @return エラーメッセージ.
*/
public String getSizeErrMessage() {
return "ファイルサイズが大きすぎるよ。";
}
...省略...
upload.xml(子画面)
<ui:remove>エラーメッセージをJSON形式で置いておく</ui:remove>
<script id="errMessage" type="application/json">
{"ext" : "#{uploadBean.extErrMessage}", "size" : "#{uploadBean.sizeErrMessage}"}
</script>
実装全体
親画面
<?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>ファイルの入力チェックをしてみる</h3>
<h:form id="formId">
<div id="uploadArea">
<ui:fragment rendered="#{!uploadBean.upload}">
<h:button value="アップロード" 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="削除">
<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(子画面)
<?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>アップロードするファイル</title>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<h:outputScript library="js" name="upload.js"/>
<ui:remove>エラーメッセージをJSON形式で置いておく</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="閉じる" onclick="window.close();" />
</div>
</body>
</html>
upload.js
/** ポップアップ画面を表示する. */
function showPopup() {
window.open('upload.jsf', '', 'width=500,height=100');
}
/**
* アップロードされたファイルをチェックする.
* @param {Object} Fileオブジェクト.
*/
function checkFile(inputFile) {
// エラーメッセージを削除する.
$('.errMessage').remove();
/** @type {String} 表示するエラーメッセージ. */
var errMessage = '';
if (inputFile.files && inputFile.files[0]) {
/** @type {array} headタグ内に置いておいたエラーメッセージ. */
var message = $.parseJSON($('#errMessage').html());
/** @type {object} 選択されたファイル. */
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 != '') {
// エラーメッセージを追加する.
$('#inputFile').after('<br /><span class="errMessage" style="color: red;">' + errMessage + '</span>');
// ファイルを削除する.
inputFile.value = null;
}
}
/**
* 拡張子が正しいか判定する.
* @param {string} ファイル名.
* @return {Boolean} true:正しい.
*/
function isCorrectExtension(name) {
var format = new RegExp('([^\s]+(\\.(jpg|png|gif|pdf))$)', 'i');
return format.test(name);
}
/**
* ファイルサイズが正しいかを判定する.
* @param {number} ファイルサイズ(バイト単位).
* @return {Boolean} true:正しい.
*/
function isCorrectSize(size) {
/** @type {number} 許容する最大サイズ(1MB). */
var maxSize = 1024 * 1024;
return size <= maxSize;
}
/**
* 親画面の要素を更新して画面を閉じる.
* @param {string} key 更新する親画面要素のid.
*/
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;
/** ファイルデータ. */
private Part file;
/**
* ファイルがアップロードされているかを判定する.
* @return true:アップロードされている.
*/
public boolean isUpload() {
return this.file != null;
}
/**
* 拡張しでエラーになった時のエラーメッセージを取得する.
* @return エラーメッセージ.
*/
public String getExtErrMessage() {
return "拡張子が対象外だよ。";
}
/**
* サイズでエラーになった時のエラーメッセージを取得する.
* @return エラーメッセージ.
*/
public String getSizeErrMessage() {
return "ファイルサイズが大きすぎるよ。";
}
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();
}
}
/**
* アップロードしたファイルを削除する.
* @throws IOException エラーが起きた.
*/
public void deleteFile() throws IOException {
this.file.delete();
}
/**
* 拡張子が正しいか判定する.
* @param name ファイル名.
* @return true:正しい.
*/
private boolean isCorrectExtension(String name) {
if (name != null) {
return name.matches("([^\\s]+(\\.(?i)(jpg|png|gif|pdf))$)");
}
return true;
}
/**
* ファイルサイズが正しいかを判定する.
* @param size ファイルサイズ(バイト).
* @return true:正しい.
*/
private boolean isCorrectSize(long size) {
long maxSize = 1024 * 1024;
return size <= maxSize;
}
}