0
0

VisualforceでContent-Type=text/plain;charset=Shift-JISで出力する方法

Posted at

概要

全銀データ形式でデータを出力する必要があり、Visualforceで実装した。
MIMEタイプがtext/plain形式(拡張子が「.txt」)で文字コードをShift-JISで出力する必要があった。
MIMEタイプがcsv形式で文字コードをShift-JISで出力するケースはよくあるが、plainテキスト形式で出力するのはあまりないと思われる。
今回色々試行錯誤して一つの実現方法にたどり着いたので、こちらに備忘として記録する。

やりたいこと

  • Salesforceから下記の出力形式を設定し、全銀データ形式でデータを出力する
  • 出力形式

課題

  • plainテキストはcsvやExcelのように<apex:outputText>タグでダウンロードできない。(普通に出力内容が画面に表示されてしまう)
  • LWCやVisualforce内でJavascriptを使って<a>タグ要素を用いてダウンロードリンクを作って、普通にダウンロードすると文字コードはUTF-8などのUnicodeで扱われてしまう(参考)

解決方法

  • 外部ライブラリを使用する
  • 使用するライブラリ
    • encoding.js

  • ライブラリのREADME_ja.mdから簡単な説明を引用

encoding.js は、文字コードの変換や判定をする JavaScript ライブラリです。
Shift_JIS や EUC-JP、ISO-2022-JP など日本語の文字コードや、 UTF-8、UTF-16 などの Unicode に対応しています。

実装

  • LWCからダウンロードボタン押下時にテキストファイルを出力する
lwc
const windowFeatures = 'left=100,top=100,width=320,height=320'
// ダウンロード後にページを削除するためポップアップを使用
window.open('/apex/ExportBankData', 'データ出力', windowFeatures)
  • window.open関数によって開かれたVisualforceページが読み込まれた際にApex=>JSで定義した関数を実行させたいので、addEventListenerのDOMContentLoadedイベントにハンドラーを設定
  • やっていること
    • 出力する文字列を文字コード(Unicode)に変換
    • Unicode=>Shift-JISに変換
    • 文字コードをバイト配列に変換してblobデータを作成
    • aタグ要素を作成して、ダウンロード
    • ポップアップした新規ウィンドウを閉じる
ExportBankData.page
<apex:page controller="ExportBankDataController" cache="false" readOnly="true">
    <!-- cdnでライブラリをインポートする -->
    <apex:includeScript value="https://unpkg.com/encoding-japanese@2.1.0/encoding.min.js" />
 
    <div style="display: none;">
        <apex:form>
            <apex:actionFunction name="initAction" action="{!doExport}" oncomplete="doExport('{!fileName}', '{!fileData}', '{!mimeType}');"
            />
        </apex:form>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function () {
            initAction(); // actionFunctionを呼び出す
        });

        function doExport(fileName, fileData, mimeType) {
            // データがないなら処理を実行しない
            if (!fileData) {
                return;
            }

            // 文字列から文字コード値の配列に変換
            const unicodeArray = Encoding.stringToCode(fileData);

            // Shift-JISのバイト配列にエンコード
            const sjisArray = Encoding.convert(unicodeArray, 'SJIS', 'UNICODE');

            // バイト配列からBlobオブジェクトを生成
            // Uint8Array:0~255の値を格納するTypedArrayオブジェクトの一つ
            const blobData = new Blob([new Uint8Array(sjisArray)], { type: mimeType });

            // ダウンロードを実行
            const link = document.createElement("a");
            link.download = fileName;
            link.href = window.URL.createObjectURL(blobData);
            link.click();
            URL.revokeObjectURL(link.href);
            window.close();
        }
    </script>
</apex:page>
  • 出力するデータやファイル名、Mimeタイプなどを設定する
ExportBankDataController
public with sharing class ExportBankDataController {
    public String fileName { get; set; }

    transient public String fileData { get; set; }

    public String mimeType { get; set; }

    public ExportBankDataController() {
    }

    public void doExport() {
        this.fileData = 'ホゲホゲ';
        this.fileName = 'hogehoge.txt';
        this.mimeType = 'text/plain';
    }
}

動作確認

  • ダウンロードボタンを押下して.txtでファイルがダウンロードされる
    image.png

  • 文字コードの確認は、encode.jsが用意しているファイルから文字コードを判定するツールを使用
    image.png

  • 一応VSCodeでも確認すると、Shift-JIS形式でエンコードした際に文字化けしていない
    image.png

まとめ

今回はユースケースとしては少ないと思われるため、参考記事があまりない中で辿り着いた解決方法を記載しました。なので、おそらく他にもっとより良いやり方もあるのでは?と思っています。
私と同様の要件で出力する必要などがあり、困っている方の一助になれば幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0