SFDCのデータを抽出してAWSのS3にCSVを出力する(その3)
今回はapexの単体プログラムがメインです。apex用エディタの起動はつまづかないと思いますが念のため、管理コンソールにログインして歯車マークをクリックして[開発者]コンソールを選択します。デバッグ方法などはググってみてください。
ちなみにSFDCでapexを使って何かしようとするとリリース時にはテストで75%のカバレッジが必要という落とし穴があります。なのでがっつりある程度処理を網羅するテストを書く必要があります。自分はテストなど書いたことなかったので非常に苦労しました。
1)S3バケット作成
2)IAMポリシー設定
3)IAMユーザ追加
2.SFDC設定
1)環境変数関連設定
2)パラメータ入力
3)リモートサイト許可
3.プログラム作成(単体レベル)
1)環境変数抽出
2)SOQLを使用してデータ抽出
3)S3にCSVファイルをアップロード
4.バッチ設定
--------------------
GetEnvironmentTest
SoqlOperate
--------------------
SoqlOperateTest
--------------------
--------------------
PutFiletoS3Test
--------------------
https://developer.salesforce.com/jpblogs/2016/04/developer-edition-signup/
・apex基本
https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_dev_guide.htm
https://tyoshikawa1106.hatenablog.com/entry/2019/06/08/133844
http://tyoshikawa1.rssing.com/chan-55762271/all_p55.html
http://fioa.site/2019/04/14/apex%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%E3%81%AEhello-world/
https://tyoshikawa1106.hatenablog.com/entry/2019/05/04/073119
https://keneloper.com/2020/01/16/how-to-get-a-user-debug-log/
https://deferloader.blog.uhuru.co.jp/2185/
https://medium.com/nyle-engineering-blog/salesforce%E9%96%8B%E7%99%BA%E5%88%9D%E5%AD%A6%E8%80%85%E3%81%8C%E3%81%A4%E3%81%BE%E3%81%A5%E3%81%8D%E3%82%84%E3%81%99%E3%81%84%E3%81%84%E3%81%8F%E3%81%A4%E3%81%8B%E3%81%AE%E7%BD%A0-cbae46ae2ae1
https://tyoshikawa1106.hatenablog.com/entry/2014/12/10/195900
https://www.xgeek.net/ja/salesforce/kiss-principle-for-apex-code-with-list-and-map-in-salesforce/
・例外テスト関連
https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_classes_exception_methods.htm
https://tyoshikawa1106.hatenablog.com/entry/2013/06/23/120049
https://qiita.com/s_hayashida/items/b0e9da04833fd316d9d2
https://qiita.com/TaigarAndDragon/items/343dad5ed06fd538a711
https://trailhead.salesforce.com/ja/content/learn/modules/apex_testing/apex_testing_data
https://gist.github.com/tyoshikawa1106/162c07053c37d5313fc2
・CSV出力
http://daeheui.com/2019/07/05/salesforcevisualforce%E3%81%8B%E3%82%89csv%E5%87%BA%E5%8A%9B/
・apex、SOQL取得
https://developer.salesforce.com/docs/atlas.ja-jp.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_relationships_and_polymorph_keys.htm
https://qiita.com/yoshimatsu11/items/e84e20d97151b1124c7c
http://blog.flect.co.jp/salesforce/2011/02/soql-7d09.html
https://qiita.com/TaigarAndDragon/items/5932966e18cc4459da70
https://tyoshikawa1106.hatenablog.com/entry/2019/09/19/075843
https://qiita.com/yoshimatsu11/items/983b15e621d3238ca8dc
https://savepo.com/soql_summary
https://www.mg6.jp/archives/tag/salesforce
https://nontitle.xyz/archives/199
https://qiita.com/lalato/items/87107fee1fbd3dee4b8d
https://gawatari.com/soql-date-bind/
https://web.plus-idea.net/2019/04/salesforce-record-tracking-history/
http://nodding-off-programmer.blogspot.com/2017/06/blog-post_30.html
https://hub.appirio.jp/tech-blog/try-apex-like-java-dev
http://www30304u.sakura.ne.jp/blog/?p=532
・SOSL
https://trailhead.salesforce.com/ja/content/learn/modules/apex_database/apex_database_sosl
https://developer.salesforce.com/docs/atlas.ja-jp.soql_sosl.meta/soql_sosl/sforce_api_calls_sosl_syntax.htm
https://qiita.com/hankboe/items/8526edaedfd6fa9ae698
https://www.cnblogs.com/dlywang0411/articles/11458804.html
https://salesforce.oikeru.com/entry/querySOQL_SOSL
https://esp-labo.com/sosl_loop/
http://kayakuguri.github.io/blog/2016/05/13/database-upsert/
・CSV出力→S3アップロード
http://kayakuguri.github.io/blog/2017/04/10/put-s3-csv-file/
https://kayakuguri.github.io/blog/2016/02/01/custom-setting/
https://qiita.com/daichi_fukui/items/77c046f3d6115057f40c
ちなみにSFDCでapexを使って何かしようとするとリリース時にはテストで75%のカバレッジが必要という落とし穴があります。なのでがっつりある程度処理を網羅するテストを書く必要があります。自分はテストなど書いたことなかったので非常に苦労しました。
◆大枠の手順
1.AWSでS3を設定する1)S3バケット作成
2)IAMポリシー設定
3)IAMユーザ追加
2.SFDC設定
1)環境変数関連設定
2)パラメータ入力
3)リモートサイト許可
3.プログラム作成(単体レベル)
1)環境変数抽出
2)SOQLを使用してデータ抽出
3)S3にCSVファイルをアップロード
4.バッチ設定
◆プログラム群
1)環境変数抽出
GetEnvironment--------------------
public class GetEnvironment {
// 環境変数をカスタム設定から取得する
public Map GetEnv(){
try {
Map settingMap = EnvironmentVars__c.getAll();
Map MapEnv = new Map();
for (String key : settingMap.keySet()) {
EnvironmentVars__c env = settingMap.get(key);
MapEnv.put(key,env.EnvParam__c);
}
return MapEnv;
} catch(Exception e) {
System.debug('Exception caught: ' + e.getMessage());
system.debug(e.getLineNumber());
return null;
}
}
}
--------------------GetEnvironmentTest
--------------------
@isTest(SeeAllData=true)
private class GetEnvironmentTest {
@isTest static void testGetEnv() {
Map m1 = new Map();
GetEnvironment ge = new GetEnvironment();
m1 = ge.GetEnv();
for (String sKey:m1.keySet()){
if(sKey == 'S3Key'){
System.assertEquals(sKey ,'S3Key');
}
if(sKey == 'S3Token'){
System.assertEquals(sKey ,'S3Token');
}
if(sKey == 'S3Bucket'){
System.assertEquals(sKey ,'S3Bucket');
}
if(sKey == 'S3Domain'){
System.assertEquals(sKey ,'S3Domain');
}
}
System.debug(m1);
}
}
--------------------2)SOQLを使用してデータ抽出
--------------------
public class SoqlOperate{
//SOQLでデータを抽出
public List GetLeads(){
try{
String queryString = 'SELECT ' +
'LastName,FirstName,Phone,Email ' +
'FROM Lead ' +
'WHERE send_stat__c != \'SEND\'';
List leads = Database.query(queryString);
if(leads.isEmpty()){
leads = new List();
}
return leads;
}catch(Exception e){
System.debug('Exception caught: ' + e.getMessage());
System.debug(e.getLineNumber());
return null;
}
}
//送信ステータス更新
public Boolean UpdateLeadsStatus(List ids){
try{
List leads = [SELECT Id FROM Lead WHERE Id IN :ids];
for (Lead ld : leads){
ld.send_stat__c = 'SEND';
}
if(!leads.isEmpty()){
//一括更新
List srList = Database.update(leads, false);
//エラー処理
for (Integer i = 0; i < leads.size(); i++) {
Lead ld = leads.get(i);
Database.SaveResult sr = srList.get(i);
if (!sr.isSuccess()) {
System.debug('**** エラー発生:updateが失敗しました ****');
System.debug('Id:' + ld.Id);
for (Database.Error err : sr.getErrors()) {
System.debug(err.getStatusCode());
System.debug(err.getFields() + ' ' + err.getMessage());
}
}
}
}
return true;
}catch(Exception e){
System.debug('Exception caught: ' + e.getMessage());
System.debug(e.getLineNumber());
return false;
}
}
//抽出データをCSVに変換
public String RecordsTransferCsv(List OriginCsv){
try{
String str_body='';
Integer cnt = OriginCsv.size();
if(cnt==0){
throw new QueryException();
}
Integer i = 0;
for(Lead l : OriginCsv){
if(i==cnt-1){
str_body += '"'+l.LastName+'"'+','+'"'+l.FirstName +'"' +','+
'"'+l.Phone+'"' + ','+ '"'+l.Email+'"';
}else{
str_body += '"'+l.LastName+'"'+','+'"'+l.FirstName +'"' +','+
'"'+l.Phone+'"' + ',' + '"'+l.Email+'"'+'\r\n';
}
i+=1;
}
return str_body;
}catch(Exception e){
System.debug('Exception caught: ' + e.getMessage());
System.debug(e.getLineNumber());
return null;
}
}
//抽出データからIDを取得してリストにする
public List ReturnKeyId(List OriginData){
try{
List id_list = new List();
Integer cnt = OriginData.size();
if(cnt==0){
throw new QueryException();
}
for(Lead l : OriginData){
id_list.add(l.Id);
}
return id_list;
}catch(Exception e){
System.debug('Exception caught: ' + e.getMessage());
System.debug(e.getLineNumber());
return null;
}
}
}
--------------------SoqlOperateTest
--------------------
@isTest(SeeAllData=true)
private class SoqlOperateTest {
@isTest static void GetLeadsTest(){
SoqlOperate sq = new SoqlOperate();
List li = sq.GetLeads();
}
@isTest static void RecordsTransferCsvTest(){
SoqlOperate sq = new SoqlOperate();
List leads = [SELECT LastName,FirstName,Phone,Email FROM Lead];
String s11 = sq.RecordsTransferCsv(leads);
System.debug(s11);
List dm;
String s12 = sq.RecordsTransferCsv(dm);
}
@isTest static void ReturnKeyIdTest(){
SoqlOperate sq = new SoqlOperate();
List leads_id = [SELECT LastName,FirstName,Phone,Email FROM Lead];
List s21 = sq.ReturnKeyId(leads_id);
for (String s_id : s21){
System.debug(s_id);
}
}
@isTest static void UpdateLeadsStatusTest(){
SoqlOperate sq = new SoqlOperate();
List leads = [SELECT Id FROM Lead WHERE send_stat__c != 'SEND'];
List ids = new List();
for (Lead l : leads) {
ids.add(l.Id);
}
Boolean b = sq.UpdateLeadsStatus(ids);
System.debug(b);
}
}
--------------------3)S3にCSVファイルをアップロード
PutFiletoS3--------------------
public class PutFiletoS3 {
/* CSV抽出 */
private static String SaveCSV(String str_body){
try{
String csv_header = '"姓","名","電話番号","Email"\r\n';
//引数チェック
if(str_body == null){
throw new NullPointerException();
}
String csv_body = csv_header + str_body;
return csv_body;
}catch(QueryException e){
System.debug('Exception caught: ' + e.getMessage());
system.debug(e.getLineNumber());
return null;
}
}
/* S3にアップロード */
@future(callout=true)
public static void PutS3(String csv_body, String file_name,String s3access,String s3secret,
String s3bucketname,String s3domain, List ids){
try {
//引数チェック
if((csv_body == null)||(file_name == null)||(s3access == null)||(s3secret == null)||
(s3bucketname == null)||(s3domain == null)||(ids==null)){
throw new NullPointerException();
}
String csv = SaveCSV(csv_body);
//S3へのファイルアップロード
String dateString = Datetime.now().formatGmt('EEE, dd MMM yyyy HH:mm:ss Z');
String stringToSign = 'PUT\n\ntext/csv; charset=Shift_JIS\n' + dateString +'\n/' + s3bucketname + '/' + file_name;
Blob mac = Crypto.generateMac('hmacSHA1', Blob.valueOf(stringToSign), Blob.valueOf(s3secret));
String signature = EncodingUtil.base64Encode(mac);
//httpリクエスト
HttpRequest req = new HttpRequest();
req.setEndPoint('https://' + s3bucketname + '.' + s3domain + '/' + file_name);
req.setHeader('Content-Type', 'text/csv; charset=Shift_JIS');
req.setHeader('Content-Length', String.valueOf(csv.length()));
req.setHeader('Host', s3bucketName + '.' + s3domain);
req.setHeader('Date', dateString);
req.setHeader('Authorization','AWS ' + s3access + ':' + signature);
req.setBody(csv);
req.setMethod('PUT');
Http httpConnection = new Http();
HTTPResponse res = httpConnection.send(req);
if(res.getStatusCode()==200){
System.debug(res);
//ステータス更新
SoqlOperate sq = new SoqlOperate();
Boolean b = sq.UpdateLeadsStatus(ids);
}
} catch(Exception e) {
System.debug('Exception caught: ' + e.getMessage());
system.debug(e.getLineNumber());
//return null;
}
}
}
--------------------PutFiletoS3Test
--------------------
@isTest
private class PutFiletoS3Test {
@isTest static void testPutS3() {
//正常パターン
//PutFiletoS3 ps3 = new PutFiletoS3();
String body = '"テスト1","電話1"\r\n"テスト2","電話2"\r\n"テスト3","電話3"';
String s;
String S3Key= 'AWSのキー';
String S3Token='AWSのトークン';
String S3Bucket = 'バケット名';
String S3Domain = 's3-ap-northeast-1.amazonaws.com';
String fn = 'sample1.csv';
List ids = new List{
'value1', 'value2', 'value3'
};
PutFiletoS3.PutS3(body,fn,S3Key,S3Token,S3Bucket,S3Domain,ids);
System.debug('**DEBUG** ' + s);
//異常パターン
S3Key= '';
S3Token='';
PutFiletoS3.PutS3(body,fn,S3Key,S3Token,S3Bucket,S3Domain,ids);
System.debug('**DEBUG** ' + s);
}
}
--------------------◆参考サイト
・Developersサイトhttps://developer.salesforce.com/jpblogs/2016/04/developer-edition-signup/
・apex基本
https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_dev_guide.htm
https://tyoshikawa1106.hatenablog.com/entry/2019/06/08/133844
http://tyoshikawa1.rssing.com/chan-55762271/all_p55.html
http://fioa.site/2019/04/14/apex%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%E3%81%AEhello-world/
https://tyoshikawa1106.hatenablog.com/entry/2019/05/04/073119
https://keneloper.com/2020/01/16/how-to-get-a-user-debug-log/
https://deferloader.blog.uhuru.co.jp/2185/
https://medium.com/nyle-engineering-blog/salesforce%E9%96%8B%E7%99%BA%E5%88%9D%E5%AD%A6%E8%80%85%E3%81%8C%E3%81%A4%E3%81%BE%E3%81%A5%E3%81%8D%E3%82%84%E3%81%99%E3%81%84%E3%81%84%E3%81%8F%E3%81%A4%E3%81%8B%E3%81%AE%E7%BD%A0-cbae46ae2ae1
https://tyoshikawa1106.hatenablog.com/entry/2014/12/10/195900
https://www.xgeek.net/ja/salesforce/kiss-principle-for-apex-code-with-list-and-map-in-salesforce/
・例外テスト関連
https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_classes_exception_methods.htm
https://tyoshikawa1106.hatenablog.com/entry/2013/06/23/120049
https://qiita.com/s_hayashida/items/b0e9da04833fd316d9d2
https://qiita.com/TaigarAndDragon/items/343dad5ed06fd538a711
https://trailhead.salesforce.com/ja/content/learn/modules/apex_testing/apex_testing_data
https://gist.github.com/tyoshikawa1106/162c07053c37d5313fc2
・CSV出力
http://daeheui.com/2019/07/05/salesforcevisualforce%E3%81%8B%E3%82%89csv%E5%87%BA%E5%8A%9B/
・apex、SOQL取得
https://developer.salesforce.com/docs/atlas.ja-jp.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_relationships_and_polymorph_keys.htm
https://qiita.com/yoshimatsu11/items/e84e20d97151b1124c7c
http://blog.flect.co.jp/salesforce/2011/02/soql-7d09.html
https://qiita.com/TaigarAndDragon/items/5932966e18cc4459da70
https://tyoshikawa1106.hatenablog.com/entry/2019/09/19/075843
https://qiita.com/yoshimatsu11/items/983b15e621d3238ca8dc
https://savepo.com/soql_summary
https://www.mg6.jp/archives/tag/salesforce
https://nontitle.xyz/archives/199
https://qiita.com/lalato/items/87107fee1fbd3dee4b8d
https://gawatari.com/soql-date-bind/
https://web.plus-idea.net/2019/04/salesforce-record-tracking-history/
http://nodding-off-programmer.blogspot.com/2017/06/blog-post_30.html
https://hub.appirio.jp/tech-blog/try-apex-like-java-dev
http://www30304u.sakura.ne.jp/blog/?p=532
・SOSL
https://trailhead.salesforce.com/ja/content/learn/modules/apex_database/apex_database_sosl
https://developer.salesforce.com/docs/atlas.ja-jp.soql_sosl.meta/soql_sosl/sforce_api_calls_sosl_syntax.htm
https://qiita.com/hankboe/items/8526edaedfd6fa9ae698
https://www.cnblogs.com/dlywang0411/articles/11458804.html
https://salesforce.oikeru.com/entry/querySOQL_SOSL
https://esp-labo.com/sosl_loop/
http://kayakuguri.github.io/blog/2016/05/13/database-upsert/
・CSV出力→S3アップロード
http://kayakuguri.github.io/blog/2017/04/10/put-s3-csv-file/
https://kayakuguri.github.io/blog/2016/02/01/custom-setting/
https://qiita.com/daichi_fukui/items/77c046f3d6115057f40c

コメント