Page側にファイルアップロードして、Salesforceオブジェクトに登録する実装例。
- Visualforce側Pageの実装(関連部分の実装のみ表現)
Sample.v
<div class="file_drop_area">
<div class="file_drop">
<input type="file" class="file_drop" id="upload" accept="image/*, application/pdf" data-action-name="uploadFileAction" data-drop-area-class="file_drop_area" />
</div>
<apex:actionFunction action="{!pageUploadFile}" name="uploadFileAction" oncomplete="completeMsg();" rerender="refreshArea">
<apex:param name="fileBody" value="" assignTo="{!fileBody}"/>
<apex:param name="fname" value="" assignTo="{!fileName}" />
<apex:param name="fileClass" value="" assignTo="{!fileClass}"/>
<apex:param name="fileSize" value="" assignTo="{!fileSize}" />
</apex:actionFunction>
</div>
- JSの実装
Sample.js
$(function(){
// ファイルドロップ時の設定
$(document).on('dragenter', ".file_drop", function (e) {
e.stopPropagation();
e.preventDefault();
});
$(document).on('dragover', ".file_drop", function (e) {
e.stopPropagation();
e.preventDefault();
e.originalEvent.dataTransfer.dropEffect = 'copy';
});
$(document).on('drop', ".file_drop", function (e) {
e.stopPropagation();
e.preventDefault();
uploadFile(e.originalEvent.dataTransfer.files.item(0), $(this).data("action-name"), $(this).data("drop-area-class"));
});
// ファイル選択ダイアログの設定
$(document).on('change', ".upload_file", function () {
uploadFile($(this).prop('files')[0], $(this).data("action-name"), $(this).data("drop-area-class"));
// ファイル選択状態を解除
$(this).val("");
});
});
/**
* ファイルアップロード処理を行う大本。
* ファイルアップロード時はこちらをまず呼び出す。
* file:アップロードするファイル
* actionName: アップロード時に実行する関数。apex:actionFunctionにて指定。
* className: ファイルアップロードエリア(ファイルをドラッグするエリア)のクラス名。
*/
function uploadFile(file, actionName, className) {
if (!validateUploadFile(file, className)) { // validateUploadFileの処理内容はここで割愛
// バリデーションエラー時の処理
return;
}
// 画像ファイルとPDFは処理が異なる
if (file.type != "application/pdf") {
uploadImageFile(actionName, file, className, file.type, file.size);
} else {
// 画像を読み込み
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = event => {
submitFile(actionName, event.target.result, file.name, className, file.type, file.size);
};
}
}
/**
* 画像ファイル用アップロード処理。
* 画像ファイルはアップロード時にファイルサイズを80%に落とす。
* actionName: アップロード時に実行する関数。apex:actionFunctionにて指定。
* file:アップロードするファイル
* className: ファイルアップロードエリア(ファイルをドラッグするエリア)のクラス名。
*/
function uploadImageFile(actionName, file, className) {
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = event => {
var img = new Image();
img.src = event.target.result;
img.onload = () => {
var width = img.width;
var height = img.height;
var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext('2d');
// img.width and img.height will contain the original dimensions
// 画像を再描する
ctx.drawImage(img, 0, 0, width, height);
submitFile(actionName, canvas.toDataURL(file.type, 0.8), file.name, className, file.type, file.size);
},
reader.onerror = error => console.log(error);
};
}
/**
* ファイルアップロード処理。
* apex:actionFunctionで設定したcontrollerの処理を実行する関数を呼び出す。
* actionName: アップロード時に実行する関数。apex:actionFunctionにて指定。
* base64File:アップロードするファイルを変換したbase64文字列。
* fileName: ユーザーがアップロードするファイルのファイル名。
* className: ファイルアップロードエリア(ファイルをドラッグするエリア)のクラス名。
*/
function submitFile(actionName, base64File, fileName, className, fileType, fileSize) {
//サーバ処理pageUploadFileを実行する
Function('return this')()[actionName](base64File, fileName, fileType, fileSize);
//ファイルドロップエリアの画像差し替え
// 処理内容割愛(アップロードされた画像を画面にプレビュー)
$("." + className).show();
}
- Apex側の実装
ガバナ制限を超えないように、ファイル内容を格納するプロパティをtransientで定義
Sample.cls
// ※ここが重要※ ガバナ制限を超えないように、ファイル内容を格納するプロパティをtransientで定義
public transient String fileBody {get; set;}// 添付ファイルデータ
public String fileName {get; set;}// 添付ファイル名
public String fileClass {get; set;}// ファイルタイプ
public String fileSize {get; set;}// ファイルサイズ
/**
* 画面からアップロード処理を行う.
* @return PageReference
*/
public PageReference pageUploadFile(){
try {
// 添付書類を保存する(カスタムオブジェクトです。Contactとアップロード画像との紐付く関係を持っているためのオブジェクト)
AttachedFile__c attFile = new AttachedFile__c(
Test_Column__c = 'testColumn',
File_Type__c = 'testType',
Contact_Id__c = contact.Id);
insert attachedFile;
// 画像データ保存のため、取得したデータを処理する
String fileData = fileBody.substring(fileBody.indexOf(',') + 1, fileBody.length());
// コンテンツバージョンを保存する
ContentVersion conVer = new ContentVersion();
conVer.Title = fileName;// タイトル
conVer.PathOnClient = fileName;// クライアントでのパス
conVer.VersionData = EncodingUtil.Base64Decode(fileData);// バージョンデータ
conVer.IsMajorVersion = true;// メジャーバージョン
insert conVer;
// ContentDocumentIdを取得する
String recordId = conVerData.Id;
String query = 'SELECT ContentDocumentId FROM ContentVersion WHERE Id IN :recordId';
ContentVersion conVerNew = Database.query(query);
// コンテンツドキュメントリンクを保存する
ContentDocumentLink conDocLink = new ContentDocumentLink();
conDocLink.ContentDocumentId = conVerNew.ContentDocumentId;
conDocLink.LinkedEntityId = attFileData.Id;
conDocLink.ShareType = 'I'; // 必須 V、C、I(詳細の意味はAPI参照)
conDocLink.Visibility = 'AllUsers'; // (他の設定値はAPI参照)
insert conDocLink;
// ContentDocumentオブジェクトの登録処理もありますが、その登録が自動で登録されるので、意識しなくて大丈夫です。
// Contactデータを保存する(処理を省略)
return null;
} catch (Exception e) {
// エラー処理
}