intra-mart Accel Platform TERASOLUNA Server Framework for Java (5.x) プログラミングガイド 第17版 2022-12-01

Storage

Storageとは

Storageは分散システムで intra-mart Accel Platform を利用しているときに、アップロードされたファイルやシステムで
共有したいファイル(主にデータファイル)を一元管理します。

コラム

分散システムを構築する場合、各 Web Application Server で共有するディレクトリを設定しておく必要があります。
詳細はセットアップガイドを参照してください。

Storageの種類

  • SystemStorage

    システムで利用するファイルを保存する領域です。
    主に、 intra-mart Accel Platform の基盤APIやアプリケーション内の処理で利用されます。
  • PublicStorage

    アップロードされたファイルや利用者間で共有したいファイルを保存する領域です。
    Storageにファイルを保存する場合は、基本的にPublicStorageに保存します。
  • SessionScopeStorage

    一時的にファイルを保存する領域です。
    処理の途中でアップロードされたファイルや保存されたデータを一時的に保存したい場合に利用します。
    SessionScopeStorageに保存されたファイルは、セッションの有効期間が切れたタイミングで自動的に削除されます。

ストリーミング

intra-mart Accel Platform ではStorageの保存されているデータをストリームで扱うことができるようになりました。
ストリームを利用することで、従来のintra-mart WebPlatformのように一度 Web Application Server のメモリ上に
ファイルデータを持つ必要がなくなり、サイズの大きいファイルのアップロードやダウンロードが行えます。

コラム

Storage APIのload(),read(),save(),write()メソッドを使用するとファイルデータがAPサーバのメモリ上に展開されるため、メモリを圧迫します。
その為、これらのメソッドの利用は推奨しません。

プログラミング方法

ファイルアップロード

ここでは、PublicStorage内の”sample”ディレクトリにファイルをアップロードする例を示します。
  • Controller クラス
import java.io.IOException;
import java.io.OutputStream;

import jp.co.intra_mart.common.aid.jdk.java.io.IOUtil;
import jp.co.intra_mart.foundation.service.client.file.PublicStorage;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;
import org.terasoluna.gfw.common.exception.SystemException;

@Controller
@RequestMapping("upload")
public class UploadController {

    @RequestMapping
    public String index() {
        return "index.jsp";
    }

    @RequestMapping(value = "store", method = RequestMethod.POST)
    public String upload(final MultipartFile uploadFile) {

        if (!uploadFile.isEmpty()) {
            // ファイル保存先のpublic storageインスタンスを生成する。
            final PublicStorage storage = new PublicStorage("sample", "samplefile");
            OutputStream os = null;
            try {
                os = storage.create();
                IOUtil.transfer(uploadFile.getInputStream(), os);
            } catch (final IOException e) {
                throw new SystemException("io error code", e);
            } finally {
                try {
                    os.close();
                } catch (final IOException e) {
                    throw new SystemException("io error code", e);
                }
            }
            return "redirect:/upload";
        }
        return "redirect:/upload";
    }
}

ファイルダウンロード

ここでは、PublicStorage内のファイル”sample.txt”をダウンロードする例を示します。
AbstractFileDownloadViewの詳細については TERASOLUNA Server Framework for Java (5.x) Development Guideline の 任意のファイルのダウンロードの項 を参照してください。
  • Controller クラス
import static org.springframework.web.bind.annotation.RequestMethod.GET;

import java.io.FileNotFoundException;
import java.io.IOException;

import jp.co.intra_mart.foundation.service.client.file.PublicStorage;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.terasoluna.gfw.common.exception.SystemException;
import org.terasoluna.gfw.common.message.ResultMessage;
import org.terasoluna.gfw.common.message.ResultMessages;

@Controller
@RequestMapping("sample/tgfw/download")
public class DownloadController {

    @RequestMapping(value = "fetch", method = GET)
    public String download(final Model model) {

        // sample.txtを指定したPublicStorageのインスタンスを生成します。
        final PublicStorage storage = new PublicStorage("sample.txt");
        try {
            if (!storage.isFile()) {
                // ファイルが存在しない場合、エラーとしてindex.jspへ戻す。
                final ResultMessages rs = ResultMessages.warning().add(ResultMessage.fromText("file not found."));
                model.addAttribute(rs);
                return "sample/tgfw/download/index.jsp"; // index.jspへ戻す。
            }
            model.addAttribute("storage", storage);
            // download用のviewを指定する。
            return "sample.tgfw.app.download.DownloadView";
        } catch (final IOException e) {
            throw new SystemException("io error code", e);
        }
    }

    @RequestMapping
    public String index() {
        return "sample/tgfw/download/index.jsp";
    }
}
  • View クラス
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jp.co.intra_mart.foundation.http.ResponseUtil;
import jp.co.intra_mart.foundation.service.client.file.Storage;

import org.springframework.stereotype.Component;
import org.terasoluna.gfw.common.exception.SystemException;
import org.terasoluna.gfw.web.download.AbstractFileDownloadView;

// view name = sample.tgfw.app.download.DownloadView として登録する。
@Component("sample.tgfw.app.download.DownloadView")
public class DownloadView extends AbstractFileDownloadView {

    @Override
    protected void addResponseHeader(final Map<String, Object> model, final HttpServletRequest request, final HttpServletResponse response) {
        // textファイル用のヘッダを設定する。
        final String disposition;
        try {
            // サーバのcharacter encodingを第二引数に設定してください。
            disposition = ResponseUtil.encodeFileName(request, "UTF-8", "sample.txt");
        } catch (final UnsupportedEncodingException e) {
            throw new SystemException("download view error code", e);
        }
        response.setHeader("Content-Disposition", "attachment;" + disposition);
        response.setContentType("text/plain");
    }

    @Override
    protected InputStream getInputStream(final Map<String, Object> model, final HttpServletRequest request) throws IOException {
        // modelに設定した storage を取得し、InputStreamを返す。
        final Storage<?> storage = (Storage<?>) model.get("storage");
        return storage.open();
    }
}