Salesforce。VisualforceでCSV出力してみた話。

googleで、「Visualforce、CSV出力」で検索すると情報がわんさか出てくるのですが、ちょっとはまってしまったので自身のためにメモ。


要件としては、全銀協データフォーマット形式のCSVを出せと。。。
フォーマットはどの銀行もほぼ同じっぽいので、検索して見つけたものをリンクします。
http://www.boy.co.jp/hojin/eb/bsd/pdf/manual-001.pdf

こんな感じでヘッダレコード、データレコード、トレーラーレコード、エンドレコードと、カラムの長さが違うCSV形式。
ってことで、レポートでCSV出力してそれをデータ部。ヘッダ・トレーラ・エンドExcelマクロとか、javaのバッチとかで植え付ける。
なんてことも考えたのですが、VisualforceでCSVを出せるってことで、技術検証として試してみたのです。

でやってみたら、なかなかうまく出てきませんでした。
<Script>タグが出てきたり、文字コードが違ったり。

最終的に以下のようにしまして、なんとかうまく出ました。

<apex:page controller="CreateCSV" cache="true"
contentType="text/csv;charset=Shift-JIS;#test.csv" readOnly="true">
<apex:repeat value="{!csvRows}" var="row">
<apex:outputText value="{!row.columns}" />
</apex:repeat>
</apex:page>

ContentTypeが第1のポイント。
"text/csv"にします。
charsetはそのときのお好み。
#test.csvっていうのはファイル名。
ファイル名は変数を渡すなど工夫すればシステム日付にすることもできるっぽい。

CSVはrepeatタグを使ってひたすら出力します。


次にコントローラクラス。
/** CSVの出力を行うためのコントローラクラスです。*/
public with sharing class CreateCSV {

    /** CSVデータ(ファイル出力用)*/
    public List<CSVRow> csvRows{get; private set;}

    /**
     * コンストラクタです。各プロパティの初期化を行います。
     */
    public CreateCSV(){
        csvRows = new List<CSVRow>();
    }

    /**
     * 検索ボタンの処理を行います。
     */
    public PageReference searchButton(){
        //検索結果の初期化。
        csvRows = new List<CSVRow>();

        //データ部を検索し、リストに格納。
        List<Account> acList = [select id, name from Account];

        //データ部の検索結果が0件の場合、CSVの出力を行わない。
        if(acList.isEmpty()){
            return null;
        }


        for(Accout ac : acList){
            //行データを格納するリスト
            List<String> l = new List<String>();

            //データ部を順番に格納していく。
            l.add(escapeCsv(ac.id)); 
            l.add(escapeCsv(ac.name));

            //ファイル出力用のリストへ格納
            CSVRow r = new CSVRow();
            r.columns = editCsvRow(l);
            csvRows.add(r);
        }

        return Page.CSVPage;
    }

    /**
     * テキストが格納されているリストクラスからCSV形式の行の形にしたテキストに変換します。
     * @param l CSVにしたいテキストのリスト
     * @return CSV形式にカンマ区切りにしたテキスト
     */
    private String editCsvRow(List<String> l){
        String str = '';
        for(integer i = 0; i<l.size(); i++){
            if(i != l.size() - 1){
                str += l.get(i) + ',';
            }else{
                str += l.get(i) + '\n';
            }
        }
        return str;
    }


    /**
     * テキストをCSVエスケープします。
     * nullの場合は空文字に変換します。
     * @param str テキスト
     * @return CSVエスケープ処理したテキスト
     */
    private String escapeCsv(String str){
        if (str != null){
            return str.escapeCsv();
        }

        return '';
    }

    /**
     * 数値を文字列に変換しCSVエスケープします。
     * nullの場合は空文字に変換します。
     * @param d 数値
     * @return CSVエスケープ処理したテキスト
     */
    private String escapeCsv(Decimal d){
        if (d != null){
            return String.valueOf(d).escapeCsv();
        }

        return '';
    }

    /** CSV出力用のクラスです */
    public class CSVRow{
        /** 行データ */
        public String columns{get;set;}
        /** コンストラクタです。初期化処理を行います。*/
        public CSVRow(){
            columns = '';
        }
    }
}

StringクラスのescapeCsvメソッドというのを使えば、ダブルクオーテーション、カンマ、改行の考慮をしてくれるみたい。
でもなぜかstaticではなかったので、nullだった場合は空文字に変換なんてことをしてます。

内部にclassを作ることで、repeatタグを使いやすいようにしています。
この辺りは、検索一覧を出す手法と同じですね。
関連記事


--------------------------------------------------------------------------------------

コメントの投稿

非公開コメント

このブログについて
  • 全記事一覧(時間順)
  • このブログについて
  • 私のプロフィール
  • 当ブログで扱っている動画について
  • 記事違いなコメントのお返事

  • カテゴリー
    twitter
    カレンダー
    05 | 2017/06 | 07
    - - - - 1 2 3
    4 5 6 7 8 9 10
    11 12 13 14 15 16 17
    18 19 20 21 22 23 24
    25 26 27 28 29 30 -
    Amazon
    でたらめな当ブログにぴったりな商品を自動で表示するみたいです。



    月別アーカイブ
    プロフィール

    たづみ

    Author:たづみ
    ・1981年生まれの男
    ・もう少し詳細なプロフィールはこちらで

    最新コメント
    アクセスランキング
    [ジャンルランキング]
    日記
    1109位
    アクセスランキングを見る>>

    [サブジャンルランキング]
    会社員・OL
    236位
    アクセスランキングを見る>>