Challenge Java EE !

Java EEを中心に趣味や仕事における開発メモを書いています。

2016年に最も読まれた記事 TOP10 Java EE少ない…

2016年で分析してみました。ページビューの総数は317,337でした。

f:id:kikutaro777:20170114191333p:plain

ちなみにブログの総アクセス数は2016年で100万アクセスを超えました(^^)!(逆にこわい)

ということで2016年のTop10

1位 アクセス数 11,601

なぜこれが1位!?びっくりです。
kikutaro777.hatenablog.com

2位 アクセス数 11,174

はじめてAdvent Calendarに参加した記事で想い入れが強い記事です。ちょくちょく昔のPrimeFaces記事に質問もらったりするので、わりと使われてるのかなー。
kikutaro777.hatenablog.com

3位 アクセス数 10,217

この辺は懐かしくもあり、未だにちゃんとわかってない気がするところ(^^;
kikutaro777.hatenablog.com

4位 アクセス数 9,916

小ネタ系が多い(^^;
kikutaro777.hatenablog.com

5位 アクセス数 7,189

キター!Twitter4J!長期的にみるとこれが一番アクセス多いんですよね(^^;ホント便利。@yusukeさんありがとうございます!
kikutaro777.hatenablog.com

と、ここでちょっと番外編として、はてブが多くついた記事を振り返ってみます。が、2016年は2つしかないwww 悲しい(>_<;けど書いてる量も質問下がりまくりなので仕方がない。(常駐してて全然書けねー時期モゴモゴ

番外編

はてブ1位

間違いなく2016年で一番感動したプレゼン。噂では聴いていたけど生でみてびっくりしました。気が付けばエバンジェリストスクールを毎週欠かさず聴いて、日々刺激をもらってます。
kikutaro777.hatenablog.com

はてブ2位

2位にあげるのも…ってレベルですが(^^;そして、どちらもJava EEじゃないっていうwww
kikutaro777.hatenablog.com

番外編 その2

2016年は執筆に参加させていただいたパーフェクト Java EEが発売にもなった年でした。JavaOneでまたJava EE少し盛り上がらないかなぁと期待していましたが、うーん(^^;;本は売れているのだろうか(汗
でもホント素晴らしい方々と書かせていただいて、良い経験になりました。恐縮しまくり…。

kikutaro777.hatenablog.com

ではでは戻ります。

6位 アクセス数 6,874

やっとこガチな感じのJSFネタ!でももうJSFは時代じゃない気も。
kikutaro777.hatenablog.com

7位 アクセス数 6,466

Azureこれはもうダッシュボードとか含めて古い情報になってしまってますね(^^;今年はまたAzureも触っていきたいです。
kikutaro777.hatenablog.com

8位 アクセス数 5,136

6位に続いて、こちらもJSFネタ。現場からお届けしてた感じのやつです。
kikutaro777.hatenablog.com

9位 アクセス数 4,669

Active Directoryかー、わりと読まれるんだなぁ(^^;
kikutaro777.hatenablog.com

10位 アクセス数 4,183

最後もJSFですか。JPAは全然入ってないんだな…。
kikutaro777.hatenablog.com

ということでこんな感じで、Java EEネタは3,4割くらいですかね(^^;;最近はQiitaにも書いてるのでご興味あれば是非フォローお願いしますm(_ _)m

qiita.com

NetBeansでSpring Boot + Doma

最近、はじめてDomaを触りました。前々からあちこちで「Doma、いいよ!Doma!」と聞いていて存在は知っていたのですが。

私は長らくJava EEをやってたので、IDEはNetBeansが馴染んでいて、他のフレームワークを触るときでも、ついNetBeansを使いたくなります。で、Domaを調べていると、EclipseとIntelliJ IDEAの情報がほとんどでNetBeans関連が見当たりませんでした。

Spring Bootと組み合わせて使いたいなと思って、調べたところ@makingさんが作ったdoma-spring-boot-starterが出てきて、ここのGitHubのページがIntelliJ IDEAを使った丁寧なチュートリアルになっていました。

github.com

で、このチュートリアルを参考にNetBeansで少し試してみたら、SQLファイルを配置したとき以下のようなコンパイルエラーがでました。

-------------------------------------------------------------
COMPILATION ERROR : 
-------------------------------------------------------------
jp/co/kke/doma/dao/MagazineDao.java:[18,20] 
[DOMA4019] ファイル[META-INF/jp/co/kke/doma/dao/MagazineDao/
selectAll.sql]がクラスパスから見つかりませんでした。
ファイルの絶対パスは
"C:\Users\kikuta\Documents\NetBeansProjects
\SpringBootDomaSample\target\classes\META-INF\jp\co\kke
\doma\dao\MagazineDao\selectAll.sql"です。
1 error
-------------------------------------------------------------
-------------------------------------------------------------
BUILD FAILURE
-------------------------------------------------------------

Domaではapt(Annotation Processing Tool)によってソースを自動生成してくれるようなのですが、sqlファイルをみつけられないようです。コードも以下のようにエラーとなっています。

f:id:kikutaro777:20161228000545p:plain

そこで、maven-apt-pluginで以下を追加しました。

<plugin>
    <groupId>com.mysema.maven</groupId>
    <artifactId>maven-apt-plugin</artifactId>
    <version>1.0.4</version>
    <executions>
        <execution>
            <goals>
                <goal>process</goal>
            </goals>
            <configuration>
                <outputDirectory>src/main/resources/META-INF/jp/co/kke/doma/dao/MagazineDao</outputDirectory>
                <processor>org.seasar.doma.boot.ConfigAutowireable</processor>
            </configuration>
        </execution>
    </executions>
</plugin>

これでビルドが通って、Domaが動かせました。

Java EEやってる人はNetBeansに慣れている人が多いと思いますが、自分みたいに「最近SpringBootが気になるので、Spring Boot + Domaやってみたいなぁ、できればNetBeansで」と思ってる人がいれば、以下試した手順が参考になれば幸いです。

環境

自分の試した環境は

  • Windows 10 Pro 64bit
  • JDK 8u112 64bit
  • NetBeans 8.2

です。

NB Spring Boot

Spring Bootにはプロジェクトのひな型を作ってくれるSpring Initializrがあります。Webで作ってもいいのですが、NetBeansから使えると楽です。そこで、NB Spring Bootというプラグインを利用します。

「ツール」の「プラグイン」メニューを選択します。
f:id:kikutaro777:20161228001639p:plain

NB Spring Bootにチェックを入れてインストールします。
f:id:kikutaro777:20161228001955p:plain

f:id:kikutaro777:20161228002038p:plain

f:id:kikutaro777:20161228002126p:plain

Spring Bootのプロジェクト作成

NB Spring Bootプラグインを入れた後、「ファイル」「新規プロジェクト」の「Maven」から「Spring Boot Initializr project」を選びます。
f:id:kikutaro777:20161228004421p:plain

プロジェクト情報を入れます。
f:id:kikutaro777:20161228004432p:plain

RESTを使ってDBの値を取得するため、Webにチェックを入れます(ここではLombokも選びました)。
f:id:kikutaro777:20161228004542p:plain

DBはPostgres(Heroku上の)を使うのでチェックし、JDBCもチェックしました。
f:id:kikutaro777:20161228004551p:plain

f:id:kikutaro777:20161228004558p:plain

ちなみに今回サンプルで作ったDBは以下簡単なcreate文で作ったテーブルです。

create table magazine
(
    id serial not null,
    mail text
)

Domaの利用

プロジェクトができたら、pom.xmlのdependenciesに以下追加します。

<dependency>
    <groupId>org.seasar.doma.boot</groupId>
    <artifactId>doma-spring-boot-starter</artifactId>
    <version>1.1.0</version>
</dependency>

application.propertiesファイルにDB接続情報を入れます。

doma.dialect = postgres
spring.datasource.initialize=true
spring.datasource.url=	jdbc:postgresql://hogehoge?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory
spring.datasource.username=hogehoge
spring.datasource.password=hogehoge
spring.datasource.driverClassName=org.postgresql.Driver

コードは、Entityクラス、DAO、ServiceとControllerをそれぞれ追加しました。

Entityクラス「Magazine.java」

import org.seasar.doma.Entity;
import org.seasar.doma.GeneratedValue;
import org.seasar.doma.GenerationType;
import org.seasar.doma.Id;

@Entity
public class Magazine {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Integer id;
    public String mail;
}

DAO

import jp.co.kke.doma.entity.Magazine;
import java.util.List;
import org.seasar.doma.Dao;
import org.seasar.doma.Select;
import org.seasar.doma.boot.ConfigAutowireable;

@ConfigAutowireable
@Dao
public interface MagazineDao {
    @Select
    List<Magazine> selectAll();
}

DAOに合わせてDoma用のSQLファイル「selectAll.sql」を作成し

src/main/resources/META-INF/jp/co/kke/spring/dao/MagazineDao/

に配置しました。

sqlファイルの中は

SELECT id, mail FROM magazine

と単純に全取得するものです。

続けてServiceクラスを作ります。

import jp.co.kke.doma.entity.Magazine;
import java.util.List;
import jp.co.kke.doma.dao.MagazineDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MagazineService {
    @Autowired
    private MagazineDao magazineDao;
    
    public List<Magazine> getMagazines() {
        return magazineDao.selectAll();
    }
}

最後にRest用のコントローラを追加します。

import java.util.List;
import jp.co.kke.doma.entity.Magazine;
import jp.co.kke.doma.service.MagazineService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MagazineController {
    @Autowired
    private MagazineService magazineService;
    
    @GetMapping("/magazines")
    public List<Magazine> getMagazines() {
        return magazineService.getMagazines();
    }
}

NetBeansのキャプチャはこんな感じです。

f:id:kikutaro777:20161228005912p:plain

MagazineDaoは残念ながら赤いエラーが出てしまうのですが、実際にはコンパイルできます。

で、実行して「http://localhost:8080/magazines」へアクセスすると

f:id:kikutaro777:20161228011506p:plain

とDBの中身が表示されました!

ということで、NetBeansでしばらく触っていこうと思います。

SalesforceからSendGridを利用してメール送信する!

この記事は「SendGrid Advent Calendar 2016」の13日目の記事です。
昨日は @azumakuniyuki さんの「SendGridへリレーする方法、MTA3種盛り。」でした。
明日は @nakansukeさん の「Amazon SESとの比較」です。

Salesforce World Tour Tokyo 2016

本日からSalesforce World Tour Tokyo 2016が開催されますね。SendGridチームは明日12/14(水)、開発者向けの「Developer Forest*1に出展します!私もスタッフとして立っていると思うので、もしご興味ある方は是非ご参加ください!

ということで、今日はSalesforceにおけるメール送信について書いてみたいと思います。

なお、私自身、Salesforceを触ったり、連携するシステム開発の経験はありますが、Salesforce系の資格とか、ゴリゴリApex書いたとか、の経験はありません(>_<;今回のエントリは、自分で調べた範囲の知識にて、もし間違いがあった場合などはご指摘いただけると嬉しいです(^^;

Salesforceにおけるメール送信

Salesforceでは、リードや取引先責任者へメールを送ったり、ワークフローの承認でメールを送ったり、様々な用途、タイミングでメールが利用されます。メール送信に関しては、ざっと調べた範囲でも以下の選択肢があると思います。

機能カテゴリ 機能
Salesforce標準*のメール送信機能 リードへの一括メール送信
取引先責任者への一括メール送信
ワークフロー・承認申請のメールアラート
メール to ケース
メール to Salesforce
Apex(メールサービス) Apexプログラムによるメール送信
メールリレー 既存SMTPサーバをリレーサーバとして利用
AppExchange Sendmail(Salesforce Labs)
Autobahn for AppExchange
Synergy!LEAD
外部サービス(Lightning限定) Gmail
Office 365

他にもあるかもしれません。

せっかくなので、表の中のいくつか試してみます。

取引先責任者への一括メール送信

取引先責任者のツールメニューに「取引先責任者の一括メール送信」があります。

f:id:kikutaro777:20161212162253p:plain

宛先にする責任者をビューから選択します。

f:id:kikutaro777:20161212162307p:plain

メールテンプレートはSalesforceで標準にあったものから適当に選びました。

f:id:kikutaro777:20161212162323p:plain

一括メール送信名を入れて、「送信」ボタンを押すだけです。

f:id:kikutaro777:20161212162334p:plain

ちなみにこの一括メール送信名によって、管理メニューの「監視」->「一括メール送信」の一覧を識別できるようです。

f:id:kikutaro777:20161212183308p:plain

f:id:kikutaro777:20161212183336p:plain

送信完了を確認したら

f:id:kikutaro777:20161212162352p:plain

メールが届いているか確認します。おー、来てますね。

f:id:kikutaro777:20161212162454p:plain

さすが標準機能、手軽です。

外部サービス(Gmail)

表の一番下に入れた「外部サービス」はLightningだけで使える機能なんですね。せっかくなので、これもちょっと試してみました。管理メニューの「メール管理」から「外部サービス」メニューを選択します。

f:id:kikutaro777:20161212161442p:plain:w100

GmailとOffice 365が選べるのですが、今回はGmailを選択しました。右のボタンを「ON」に切り替えます。

f:id:kikutaro777:20161212160921p:plain

あとは「Lightning Experienceに切り替え」ます。

f:id:kikutaro777:20161212161206j:plain

ちなみにLightningへの切替は事前に環境を確認して行ってくださいm(_ _)mまぁSalesforce側で設定変更前に色々確認メニューでるので、ここではこの程度にしておきます。

切り替えた後、取引先責任者一覧へ。

f:id:kikutaro777:20161212165442p:plain

Lightningめっちゃ綺麗(/・ω・)/

メールの部分をみると、Gmailの選択肢がでます!

f:id:kikutaro777:20161212165730p:plain

メールエディタが組み込まれます。
f:id:kikutaro777:20161212170204p:plain

試しに送信すると、ちゃんと届きます。
f:id:kikutaro777:20161212170416p:plain

すごい。便利w

これらの機能はSalesforceで標準的に用意されており、統合された機能として使いやすいです。一方で、一部ガバナ制限を受けるケースがあったり、テンプレートを作成する際に、Web上でのエディタのようなものがなく少し手間だったり、という点もあるかと思います。ここはここでAppExchangeでカバーされる製品もあるとは思います。

なお、どういう制限があるのか、などQA的なものは以下が良さそうでした。

Salesforceのメール送信 ポイント集
help.salesforce.com

では次に、ここに挙げた選択肢以外でどのようなものがあるのか?というところで、SendGridを利用した方法を試したいと思います。

SalesforceでSendGridを利用したメール送信

SalesforceでSendGridを利用する方法としては、以下の選択肢があると思っています。

方式 方法 利用可能有無 補足
メールリレー × 一番シンプルな方法と思いますが、こちらにあるようにSalesforce側がID/Passの認証対応が現状できないようです。このスレ、相当みなさん文句言っていて面白い…
Apex sendgrid-apex 実はSendGridからApex用のラッパーライブラリがGitHubで公開されてます。詳細は後程。
SendGrid APIを直接叩く 今回時間がなくて試せなかったのですが、Apexでhttpコールができるのであれば、普通にSendGridのAPIをコールすることも
API連携 一番堅実で、SalesforceのSOAPかRESTのAPIで取引先責任者とかメアド取ってきて、SendGridのAPIで送信という形です。

Salesforceのメールリレーの設定は以下のようになっていています。

f:id:kikutaro777:20161212172412j:plain

SendGridでは、SMTPサーバにログインして直接使うこともできるのですが、当然ながらSMTPサーバのユーザIDとパスワードが必要です。しかし、Salesforceの設定ページでは特にそういう設定部がなく…現状、以下ページに書かれているように対応されていないようです。

success.salesforce.com

3つ目のApexでREST APIをコールする部分は今回調べきれなかったです。JavaでいうHttpClientとかJersey Clientみたいなライブラリがつかえると楽なのでしょうが…この辺Apexはどうなっているんでしょうか。。。

また、4つ目のAPI連携は下図のようなイメージです。

f:id:kikutaro777:20161213151606p:plain

今回のAdventでは細かく触れませんが、SalesforceのAPIをJavaで触ったとき(SOAP APIですが)のエントリは前に書いたので、興味ある方はどうぞm(_ _)m

kikutaro777.hatenablog.com

この方法が一番堅実だと個人的には思います。

Apex with SendGrid

さきほど、Apexで利用可能なライブラリがGitHubにあると書きましたが、以下となります。ただ、最終コミットの日付をみていただくとわかるのですが、数年前で止まったままとなっております。

github.com

以降で書くのは、あくまでも私がサンプル的に試したものであり、公式に利用可能であるということは保証できないのでよろしくお願い致します。実際、SendGridでは既にv3というAPIに移行していますが、このApexラッパーのコードを確認すると、v2のラッパーとなっていたりします。

色々ガードはってしまいましたが、早速、試してみましょう。

Salesforceにログインした状態で、GitHubのInstallationの下に表示されているURLをクリックします。
f:id:kikutaro777:20161212171942j:plain

今回は管理者のみでインストールしました。
f:id:kikutaro777:20161212173316j:plain

アクセスの承認をします。ここの2個目はちょっとよくわからず、とりあえず1個目だけチェックしています。
f:id:kikutaro777:20161212173329j:plain

「インストール完了!」と出ればOKです。
f:id:kikutaro777:20161212173340j:plain

開発者は通常EclipseとかでApex触るのだと思いますが、今回は簡単なサンプルなので「開発者コンソール」で進めます。
f:id:kikutaro777:20161212173504j:plain

Apexクラスを作成します。「SendGridController」クラスにしました。
f:id:kikutaro777:20161212173534j:plain

中身は以下のような感じ。お試しされる方は、ID/パスワード/メアドは本物に置き換えてください。
f:id:kikutaro777:20161212173544j:plain

public class SendGridController {

    public void sendMail() {
        SendGrid sendgrid 
            = new SendGrid('sendgridのログインID', 'sendgridのログインパスワード');
        
        SendGrid.Email email = new SendGrid.Email();
        email.addTo('テストで送る宛先メールアドレス');
        email.setFrom('送信元fromのメールアドレス');
        email.setSubject('SalesforceのApexからテスト送信');
        email.setText('Salesforceからこんにちは');
        
        sendgrid.send(email);
    }

}

続いてページを作成します。「Visualforce Page」を選択します。
f:id:kikutaro777:20161212173655j:plain

「SendGridPage」という名前にしました。
f:id:kikutaro777:20161212173703j:plain

中身は以下のように定義。Java EEなどでJSFに慣れていると楽ですね(^^;

<apex:page controller="SendGridController">
    <apex:form>
        <apex:commandButton id="btnSendMail" 
            action="{!sendMail}" value="SendGridでメール送信" />
    </apex:form>
</apex:page>

ページを開いてみます。URLで「https://x.xx2.visual.force.com/apex/SendGridPage」のようにページ名を直接打ってもいいです(xxの辺りはSandboxごとに異なる)し、設定メニューの「ビルド」->「開発」->「Visualforceページ」を選択して
f:id:kikutaro777:20161213141717p:plain:w100

矢印マークからページを起動することもできます。
f:id:kikutaro777:20161213141728p:plain

こんな感じ。
f:id:kikutaro777:20161212174109p:plain

ボタンを押すと、宛先で指定したメールアドレスに送信されます。簡単ですね。

ただ、実際の業務系では、メアドを直接Apexに埋め込むようなコードは書かないですし、こんな画面のユースケースはないと思います。

そこで、取引先責任者のテーブルを作り、メール送信用ボタンをカラムに配置してみたいと思います。その前に、素のままだと見た目があまりにもダサすぎるので、今回VisualStrapを使いました。BootstrapをVisualforceで簡単に使えるようにしてくれるものです。以下ブログが詳しかったです。

tyoshikawa1106.hatenablog.com

先ほどと同じようにApexのクラス(コントローラ)とVisualforceページを以下のように作成しました。今度は先にビューの定義から

<apex:page controller="SendGridTableController">
    <vs:importvisualstrap />
    <vs:visualstrapblock >
        <vs:pageheader title="SendGridによるメール送信" subtitle="デモ" />
        <apex:form >
            <vs:panel >
                <apex:dataTable value="{!contacts}" var="contact" styleClass="table table-striped table-bordered">
                    <apex:column >
                        <apex:facet name="header">取引先担当責任者名</apex:facet>
                        <apex:outputText >{!contact.name}</apex:outputText>
                    </apex:column>
                    <apex:column >
                        <apex:facet name="header">メールアドレス</apex:facet>
                        <apex:outputText >{!contact.email}</apex:outputText>
                    </apex:column>
                    <apex:column >
                        <apex:commandLink styleClass="btn-sm btn-primary" id="btnSendMail" action="{!sendMail}" value="SendGridでメール送信">
                            <apex:param name="email" value="{!contact.email}"/>
                            <apex:param name="name" value="{!contact.name}"/>
                        </apex:commandLink>
                    </apex:column>
                </apex:dataTable>
            </vs:panel>
        </apex:form>
    </vs:visualstrapblock>
</apex:page>
public class SendGridTableController {
    public List<Contact> listContacts;
    
    public void sendMail() {
        String mailTo = System.currentPageReference().getParameters().get('email');
        String name = System.currentPageReference().getParameters().get('name');
        
        //ホントはここで毎回newしないようにするべき
        SendGrid sendgrid
            = new SendGrid('sendgridのログインID', 'sendgridのログインパスワード');
        
        SendGrid.Email email = new SendGrid.Email();
        email.addTo(mailTo);
        
        email.setFrom('送信元fromのメールアドレス');
        email.setSubject('SalesforceのApexからテスト送信');
        
        List<String> subs = new List<String> {name};
        email.addSubstitution('name', subs);
        
        email.addCategory('Salesforce');
        
        email.setHtml('メールコンテンツ');
        sendgrid.send(email);
    }
    
    public List<Contact> getContacts() {
        if(listContacts == null) {
            listContacts = [SELECT Name, Email FROM Contact];
        }
        return listContacts;
    }
}

上記コードにありますが、差し込み(Substitution)カテゴリなどもちゃんと使えます。

で、画面を開くと以下のように取引先責任者一覧が表示されて、各行にメール送信のボタンが付きます。これで送りたい相手のボタンを押せば送れます。ホントはチェックボックス付けたり、がいいのでしょうけど…。
f:id:kikutaro777:20161212182129p:plain

よく考えたらVisualStrapじゃなくて、Lightningで作ってみればよかったな(^^;このVisualforceページをLightningでみたらどうなるんだろう‥と思って切り替えてみたのですがLightning内から開くとVisualforceページが別ウィンドウで呼ばれるんですね(^^;なるほど。

ちなみに、メールの中身ですが、このApexを利用して、以下のようなレスポンシブメールも送信できました!(上記コード内の「email.setHtml('メールコンテンツ');」の部分を変えて)

PC
f:id:kikutaro777:20161213154615j:plain

モバイル

f:id:kikutaro777:20161213142401p:plain:w250

ホントはこの部分もどのようにやったか書こうと思ったのですが、この辺はまたどこかで別途紹介したいと思います。

ちなみに上のサンプルメールはSendGridのマーケティングキャンペーンに関するものをサンプルとしたのですが、最近リリースされた機能なので是非お試しください。以下関連ブログですー。

sendgrid.kke.co.jp

sendgrid.kke.co.jp

*1:SendGridブースへお越しいただく方は、虎ノ門ヒルズフォーラム5Fなので、プリンスパークタワーへ行かないようご注意ください…

にほんブログ村 IT技術ブログへ
にほんブログ村 にほんブログ村 IT技術ブログ Javaへ
にほんブログ村