html5で複数ファイルアップロード(SAStruts)その2

チュートリアルに存在するファイルアップロードをベースとして機能を拡充していく。

Super Agile Struts - Tutorial

前回の導入編により、画面こそそれっぽくなったけど、 実際にアップロードされるファイルが1件だけという問題が発生した。

今回は問題特定編。 処理の内部を見てみる。

まず、送るパラメータがファイルだけだと調査しにくいので、 html(JSP)にダミーでテキストフィールドを用意しておく

input.jsp

<%@page pageEncoding="UTF-8"%>
<html>
<head>
<title>Tutorial: Upload</title>
<link rel="stylesheet" type="text/css" href="${f:url('/css/sa.css')}" />
</head>
<body>
    <h1>Tutorial: Upload</h1>
    <html:errors />
    <s:form enctype="multipart/form-data">
        <input type="file" name="formFile" multiple/><br/>
        <input type="text" name="dummyField" value="testValue1"/><br/>
        <input type="text" name="dummyField" value="testValue2"/><br/>
        <input type="submit" name="upload" value="アップロード" />
    </s:form>
</body>
</html>

※ここでname="dummyField"が二つあるのはちょっとした布石。

早速試しに2ファイル選択した状態でsubmitしてみる。

f:id:negiblog:20160612235119p:plain

そしてS2RequestProcessor#processPopulateの中で、いい感じのところで止める(抽象的) Strutsでパラメータの授受と言えばここしか思いつかん。

結果はこちら

f:id:negiblog:20160612235127p:plain

テキストパラメータは配列になって複数のパラメータを認識しているのに対して、 ファイルパラメータは一つしか認識していない!

この違いはいったい何だろう!

さらにソースコードを追っていくと、 テキストパラメータとファイルパラメータの扱いの違いはここにあった。

S2MultipartRequestHandler.java

    @SuppressWarnings("unchecked")
    @Override
    protected void addTextParameter(HttpServletRequest request, FileItem item) {
        String name = item.getFieldName();
        String value = null;
        boolean haveValue = false;
        String encoding = request.getCharacterEncoding();
        if (encoding != null) {
            try {
                value = item.getString(encoding);
                haveValue = true;
            } catch (Exception e) {
            }
        }
        if (!haveValue) {
            try {
                value = item.getString("ISO-8859-1");
            } catch (java.io.UnsupportedEncodingException uee) {
                value = item.getString();
            }
            haveValue = true;
        }
        if (request instanceof MultipartRequestWrapper) {
            MultipartRequestWrapper wrapper = (MultipartRequestWrapper) request;
            wrapper.setParameter(name, value);
        }
        String[] oldArray = (String[]) elementsText.get(name);
        String[] newArray;
        if (oldArray != null) {
            newArray = new String[oldArray.length + 1];
            System.arraycopy(oldArray, 0, newArray, 0, oldArray.length);
            newArray[oldArray.length] = value;
        } else {
            newArray = new String[] { value };
        }
        elementsText.put(name, newArray);
        elementsAll.put(name, newArray);
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void addFileParameter(FileItem item) {
        FormFile formFile = new S2FormFile(item);

        elementsFile.put(item.getFieldName(), formFile);
        elementsAll.put(item.getFieldName(), formFile);
    }

うーむ、同一のフィールド名でパラメータが送られてきた場合、 テキストパラメータは配列に格納してくれるのに対して、ファイルパラメータは、後勝ちになる模様。 (テキストパラメータは、同一のフィールド名が無くとも配列に詰め込む模様)

テキストパラメータは割と柔軟に対応できるんだねぇ・・・

次回、対策編へ!