マイペースなプログラミング日記

DTMやプログラミングにお熱なd-kamiがマイペースに書くブログ

簡単なアップローダ その4

簡単なアップローダ その3ではアップロードするファイル数の上限がなかったり、排他制御は無かったので取り入れてみた。また、ファイルの削除用リンクも入れてみた。

UploadPage.html

<html>
  <head>
    <title></title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  </head>
  <body>
      <span wicket:id="feedback"></span>
      <form wicket:id="uploadForm">
          アップロードファイル: 
          <input type="file" value="" wicket:id="uploadField" />
          <input type="submit" value="送信" wicket:id="uploadButton" />
      </form>
      
      <hr/>
      <!--上に表示するナビゲータ-->
      <div wicket:id="navigator1" style="width:100%; text-align:center"/>
      <hr/>
      <table wicket:id="table" style="width:100%">
          <tr>
             <td>ファイル名</td>
             <td style="text-align:right; padding-right:10px">ファイルサイズ</td>
             <td>更新日</td>
             <td></td>
          </tr>
          <tr wicket:id="uploadList">
              <td style="width:100px">
                  <a wicket:id="downloadLink">
                      <span wicket:id="fileName">a.txt</span>
                  </a>
              </td>
              <td wicket:id="fileSize" style="text-align:right;padding-right:10px">
                  1024B
              </td>
              <td wicket:id="uploadTime">2008/03/30</td>
              <td>
                  <!-- 削除用のリンク -->
                  <a wicket:id="deleteLink">削除</a>
              </td>
          </tr>
      </table>
      
      <hr/>
      <!--下に表示するナビゲータ-->
      <div wicket:id="navigator2" style="width:100%; text-align:center"/>
      <hr/>
  </body>
</html>

UploadPage.java

package d_kami.upload;

import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.link.PageLink;
import org.apache.wicket.markup.html.link.DownloadLink;
import org.apache.wicket.markup.html.panel.FeedbackPanel;

import org.apache.wicket.markup.html.form.upload.FileUploadField;
import org.apache.wicket.markup.html.form.upload.FileUpload;

import org.apache.wicket.markup.html.list.PageableListView;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.ajax.markup.html.navigation.paging.AjaxPagingNavigator;
import org.apache.wicket.ajax.AjaxRequestTarget;

import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;

import org.apache.wicket.util.lang.Bytes;

import java.util.Arrays;
import java.util.Date;
import java.util.Comparator;
import java.text.SimpleDateFormat;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class UploadPage extends WebPage{
    Form form;
    private final FileUploadField uploadField;
    private final File uploadDir;
    
    //上に表示するページ移動用のナビゲータ
    AjaxPagingNavigator navigator1;
    //下に表示するページ移動用のナビゲータ
    AjaxPagingNavigator navigator2;

    //ファイルは100個までアップロード可能(それを越えるなら古いものから削除)
    private static final int MAX_FILE_COUNT = 100;
    
    //排他制御用のロックオブジェクト
    private static final Object LOCK = new Object();
    
    public UploadPage(){
        FeedbackPanel feedback = new FeedbackPanel("feedback");
        
        form = new Form("uploadForm");
        //ファイルのアップロードに必要な設定
        form.setMultiPart(true);
        //アップロードできるのは10キロバイトまで
        form.setMaxSize(Bytes.kilobytes(10));
        
        
        uploadField = new FileUploadField("uploadField");
        
        //アップロードされたファイルを保存するディレクトリを決める
        uploadDir = getDirectory("upload");
        
        //ファイルのアップロードを行うSubmitボタンを作成する
        Button submitButton = createSubmitButton();
        
        //ファイルの一覧を表示するテーブル(ListViewの親コンポーネント)
        WebMarkupContainer table = new WebMarkupContainer("table");
        //Ajaxで更新可能にする
        table.setOutputMarkupId(true);
        
        //アップロードされたファイルの一覧を表示するListViewを作成する
        PageableListView listView = createFileListView();
        
        //リストビューの上に表示するナビゲータ
        navigator1 = new AjaxPagingNavigator("navigator1", listView){
            @Override
            protected void onAjaxEvent(AjaxRequestTarget target){
                super.onAjaxEvent(target);
                
                //下のナビゲータを更新する
                target.addComponent(navigator2);
            }
        };
        navigator1.setOutputMarkupId(true);
        
        //リストビューの下に表示するナビゲータ
        navigator2 = new AjaxPagingNavigator("navigator2", listView){
            @Override
            protected void onAjaxEvent(AjaxRequestTarget target){
                super.onAjaxEvent(target);
                
                //上のナビゲータを更新する
                target.addComponent(navigator1);
            }
        };
        navigator2.setOutputMarkupId(true);
        
        add(feedback);
        
        form.add(uploadField);
        form.add(submitButton);
        add(form);
        
        add(navigator1);
        
        table.add(listView);
        add(table);
        
        add(navigator2);
    }
    
    //ファイルのアップロードを行うSubmitボタンを作成する
    private Button createSubmitButton(){
        Button submitButton = new Button("uploadButton"){
            @Override
            public void onSubmit(){
                FileUpload upload = uploadField.getFileUpload();
                if(upload == null){
                    //アップロードするファイルが見つからなければエラーメッセージ表示
                    //して後は何もしない

                    error("アップロードするファイルが見つかりません");
                    return;
                }
               
                //アップロードしたファイルの名前を取得
                String fileName = upload.getClientFileName();
                File uploadFile = new File(uploadDir, fileName);
                
                synchronized(LOCK){
                    try{
                        //アップロードされたクライアントのファイルをサーバーのファイルに書き込む
                        upload.writeTo(uploadFile);
                    }catch(IOException e){
                        //例外がでたら、FeedbackPanelにエラーメッセージを表示する
                      this.error(e.getMessage());
                    }finally{
                        upload.closeStreams();
                    }
                
                    //アップロードされたファイルのリスト(一覧)を返す
                    File[] fileList = uploadDir.listFiles();
                
                    //新しいファイルが前にくるようにソートする
                    Arrays.sort(fileList, new FileSortRule());
                
                    //ファイルの数が一定数を越えていたら古いファイルから削除
                    int fileCount = fileList.length;
                    while(fileCount > MAX_FILE_COUNT){
                        fileCount--;
                        fileList[fileCount].delete();
                    }
                }
            }
        };
        
        return submitButton;
    }
    
    //アップロードされたファイルの一覧を表示するListViewを作成する
    private PageableListView createFileListView(){
        
        //ファイル一覧を返すモデルを作成する
        IModel uploadListModel = new LoadableDetachableModel(){
            @Override
            protected Object load() {
                //アップロードされたファイルのリスト(一覧)を返す
                File[] fileList = uploadDir.listFiles();

                
                //新しいファイルが前にくるようにソートする
                Arrays.sort(fileList, new FileSortRule());
                    
                //Fileの配列をリストに変換して返す
                return Arrays.asList(fileList);
            }
        };
        
        PageableListView listView =
                new PageableListView("uploadList", uploadListModel, 5){
            
            @Override
            protected void populateItem(ListItem listItem){
                final File file = (File)listItem.getModelObject();
                
                //ファイルダウンロード用のリンクを作成
                DownloadLink link = new DownloadLink("downloadLink", file);
                link.add(new Label("fileName", file.getName()));
                listItem.add(link);
                
                //ファイルサイズを表示する
                listItem.add(new Label("fileSize", file.length() +"B"));
                
                //日付を表示する
                Date date = new Date(file.lastModified());
                SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm");
                listItem.add(new Label("uploadTime", format.format(date)));
                
                //ファイル削除用のリンク
                listItem.add(new PageLink("deleteLink", UploadPage.class){
                    @Override
                    public void onClick(){
                        synchronized(LOCK){
                            file.delete();
                        }
                    }
                });
            }
        };
        
        return listView;
    }
    
    //コンテキストパス上にあるdirNameのディレクトリの絶対パスを求める
    private File getDirectory(String dirName){
        WebApplication application = (WebApplication)getApplication();
        String uploadPath = application.getServletContext().getRealPath(dirName);
        File dir = new File(uploadPath);

        //ディレクトリが存在しなければ作成する
        if(!dir.exists())
            dir.mkdir();
        
        return dir;
    }

    //Fileの配列をソートするためのルール
    class FileSortRule implements Comparator<File>{
        public int compare(File src, File target){
            //更新した時間が新しい順に並べる
            int diff = (int)(target.lastModified() - src.lastModified());
            
            //更新した時間が同じ場合はファイル名でソート
            if(diff == 0)
                diff = src.getName().compareTo(target.getName());
                        
            return diff;
        }
    }
}