apex:pageBlockTableの幅を画面幅以上にする方法

apex:pageBlockTableを使うとTableの幅が画面幅に設定されてしまい、列の数が多い際には、一列あたりの表示幅が狭くなってしまいます。

apex:pageBlockTable を

で囲ってやってdivのstyleで幅を指定してやれば、画面幅以上にTableの幅を広げられます。

<div style="width:140%">
   <apex:pageBlockTable value="{!accs}" var="acc" >
   ....
   </apex:pageBlockTable>
</div>

Apex Data Loaderで使用される文字コード

CSVファイルを利用してSalesforceへデータをアップロードする。もしくはSalesforceのデータをCSVファイルとしてダウンロードする際には、Apex Data Loaderが便利です。このApex Data Loaderで利用可能なCSVファイルの文字コード(エンコーディング)として、以下のものが利用可能です。

  • UTF-8
    Data Loaderのメニューから[setting] > [settings]と移動し、[Read all CSVs with UTF-8 encoding]を選択すると、ファイルがUTF-8であるものとしてCSVファイルが読み込まれます。
  • MS932(Shift_JIS)
    日本語Windows環境では、なにも設定を行わなければ、CSVファイルがMS932であるものとして読み込まれます。これは、DataLoaderが内部的にJavaの標準ライブラリのjava.io.FileReaderをつかっているからです。FileReaderは、JVMのデフォルト・エンコーディング(file.encoding)を利用してファイルを読み込みます。

もし、日本語OS以外でData Loaderを利用する場合は、Shift_JISのファイルを読み込めませんので注意が必要です。そのような場合は、CSVファイルをUTF-8で用意した上で、[Read all CSVs with UTF-8 encoding]にチェックをつけます。

[参考情報]
Apex Data Loaderのソースコード
http://sforce-app-dl.cvs.sourceforge.net/viewvc/sforce-app-dl/apexdataloader/src/com/salesforce/dataloader/dao/csv/CSVFileReader.java?revision=1.1&view=markup
152行目のopenというメソッドでファイルの読み取りをおこなっています。

XMLデータの処理

目的

Apexコードのなかで、XMLを処理する方法をとりあげます。
例として、前回取り上げた、Kakaku.comAPIのデータ取得結果(XML)を処理してみます。

ポイント

XMLを扱うためのApex標準クラスとして、XMLStreamReader/XMLStreamWriterが用意されていますが、これらは比較的低レイヤのAPIのためこれらのクラスをそのまま利用するのは煩雑です。
オープンソースのライブラリとしてXML Dom parserというのがあり、これを使うとXMLのDOM APIを利用できますので、今回はこのXMLDomを使ってみましょう。

XML Dom parser
http://developer.force.com/codeshare/apex/ProjectPage?id=a0630000002ahp5AAA

以下のURLから、XMLDom.clsとXMLDomTest.clsをダウンロードし、各クラスを環境に作成しておきます(現時点でのDeveloper Editionでは、初期状態からXML Domがインストールされています)。
http://code.google.com/p/visualforce-components/source/browse/trunk/XmlDom/src/unpackaged/classes/

サンプルコード

以下のXMLを処理するコードを書いてみます。

<BBSInfo> 
  <ProductID>01309511986</ProductID>
  <NumOfResult>5</NumOfResult>
  <Item> 
    <ThreadTitle>バッテリー消費激しい</ThreadTitle> 
    <ThreadId>9687067</ThreadId> 
    <ThreadClass>0</ThreadClass>
    <ThreadUrl>http://bbs.kakaku.com/bbs/-/SortID=9687067/</ThreadUrl>
    <ThreadSummary>アプリ利用時のバッテリー消費が著しいように思います。バッテリログというアプリを入れて確認したところネット非接続・位置情報サービスオフでも20分程度の使用で残量が20〜30%程度減ります。…</ThreadSummary> 
    <NickName>passatb5</NickName>
    <NumOfResponse>7</NumOfResponse> 
    <WrittenDate>2009/06/12 9:16:43</WrittenDate> 
  </Item> 
  <Item> 
    <ThreadTitle>Mac版ネットブック的な利用をしたいのですが…。</ThreadTitle> 
    <ThreadId>9573279</ThreadId> 
    <ThreadClass>0</ThreadClass>
    <ThreadUrl>http://bbs.kakaku.com/bbs/-/SortID=9573279/</ThreadUrl>
    <ThreadSummary>おはようございます。Mac版ネットブック的な利用をしようと考えて、購入しました。がしかし、自分の使用したい建物が無線LANスポットではないので、上手く活用できません…。ソフトバン…</ThreadSummary> 
    <NickName>ぶっち624</NickName>
    <NumOfResponse>3</NumOfResponse> 
    <WrittenDate>2009/05/20 7:09:16</WrittenDate> 
  </Item> 
</BBSInfo> 

このXMLが文字列変数contentに格納されている場合に、XMLから各要素の情報を取り出すコードです。

public void parseContent(String content){
  // XMLをStringの変数に格納する
  // XMLの文字列を与えて、XMLDomを初期化する
  XMLDom dom  = new XMLDom(content);
  // XMLの中から、Item要素を抽出する(複数返ってくる可能性あり)
  List<XMLDom.Element> items = dom.getElementsByTagName('Item');
  for (XMLDom.Element item:items){
    // item要素の子要素からThreadTitleとThreadIdを取得し、ノード値を取得
    System.out(item.getElementByTagName('ThreadTitle').nodeValue);
    System.out(item.getElementByTagName('ThreadId').nodeValue);
....

制限

現時点で、XML Dom parserは名前空間を無視する作りになっていますので、複数の名前空間を含むXMLを扱う場合には注意が必要です。

HTTPで外部サイトから情報を取得する

目的

Webサービスでなく、REST形式のAPI経由で情報を取得できるサイトが増えてきました。今回は、HTTPで外部サイトから情報を取得する方法をご紹介します。

ポイント

サンプルコードを実行する前に、実行する組織でリモート・サイトの登録を行っておく必要がある。
[設定] > [管理者設定] > [セキュリティのコントロール] > [リモートサイトの設定]
ここで、接続先のURLを設定する。今回は価格.comAPIにアクセスするので、リモートサイトのURLとして

http://api.kakaku.com を登録する。

サンプルコード

public class ProductMessage {
  public String getMessageContent(){
    // HTTP接続に必要名HTTP、HTTPRequestクラスを初期化する
    HTTP h = new HTTP();
    HTTPRequest req = new HTTPRequest();
    
    // 指定したURLにGETメソッドで接続する
    String url= 'http://api.kakaku.com/Ver1/BBSInfo.asp?ProductId=01309511986&SortOrder=Code&Filter=1';
    req.setEndpoint(url);
    req.setMethod('GET');
    
    // 実際に接続を行う
    HTTPResponse res = h.send(req);
    
    // HTTP Bodyを取得する
    return res.getBody();
  }  
}

制限事項

接続先のポート番号には、以下の制限があります。
- 80: このポートは、HTTP 接続のみを受け付けます。
- 443: このポートは、HTTPS 接続のみを受け付けます。
-7000-10000 (7000 と 10000 も含む): これらのポートは、HTTP 接続または HTTPS 接続を受け付けます

ポータルユーザとして登録されている取引先責任者のIDから、ユーザ情報を取得する

目的

ポータルユーザとして登録されている取引先責任者のIDがわかっている時に、対応するユーザ情報を取得するSOQLの書き方

サンプルコード

contId = [取引先責任者のID];
// ポータルユーザの場合、contactIdに対応する取引先責任者のIDが入っている
User u = [select id, name from User where cantactId = :contId];

ページ表示時にデータ更新を行いたい

目的

Visualforceのページが表示されたタイミングでデータの更新処理を行いたい

ポイント

一見、Controllerのコンストラクタに、更新(update/insert)処理をいれればよいように思われるが、Visualforceの制約で、コンストラクタに更新処理をいれても、正常に更新されない。
pageタグのaction属性で、更新処理を行うメソッドを指定すれば、ページ読み込み時に更新処理が実行される

サンプル・コード

ページが表示されたタイミングで、既読フラグをtrueに設定する

<apex:page showHeader="false" controller="TestController" action="{!setReadFlag}">
  ....
</apex:page>
public class TestController {  
  .....
  // pageタグのaction属性に指定したメソッドを実装
  public PageReference setReadFlag(){
    TestObject__c obj = [select id , ReadMessage__c from TestObject__c where Id = :testId];
    if(obj != null){
      //既読フラグをtrueに設定
      obj.ReadMessage__c = true;
      update(obj);
    }
    return null;
  }
  ....

制限事項

参考資料

Triggerで添付ファイルを含めたメールを送信する

目的

オブジェクトが更新されたタイミングで、レコードに紐付いた添付ファイル(Attachment)をメールの添付ファイルとして送信したい。

ポイント

メールの送信は、ApexのMessagingクラスを利用します。添付ファイルの扱い方に関しては、サンプル・コードを参照してください。

サンプル・コード

trigger SendMailTrigger on TestObject__c (after insert, after update) {
  for (TestObject__c obj: Trigger.new){
    if (/** メールが送信される条件 **/){
      // メール送信のためのクラス SingleEmailMessage を初期化
      Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
      
      // 宛先を設定
      String[] toAddress = new String[]{obj.email__c};
      mail.setToAddresses(toAddress);
      
      // メールの件名を設定
      mail.setSubject(obj.title__c);
      
      // メールで利用するエンコーディングを指定
      mail.setCharset('ISO-2022-JP');
      
      // 本文を設定
      mail.setPlainTextBody(obj.comment__c);
      
      // レコードにひもずく添付ファイルを取得 
      List<Attachment> atts = [select name, body from attachment where parentId = :obj.id];
      
      // メールの添付ファイルを設定
      List<Messaging.Emailfileattachment> fas = new List<Messaging.Emailfileattachment>();
      for (Attachment att : atts){        
        Messaging.Emailfileattachment fa = new Messaging.Emailfileattachment();
        fa.setFileName(att.name);
        fa.setBody(att.body);
        fas.add(fa);
      }
      mail.setFileAttachments(fas);
      
      // ReplyToで設定するEmailアドレスの設定
      mail.setReplyTo(REPLY_TO);
      
      // メールの送信
      Messaging.sendEmail(new List<Messaging.Email>{mail});
    }
  }
}

制限事項

Apexコードからのメール送信は、一括メール送信扱いになりますので、一日1000通までという制限が課せられます。