問題
- Liferay フォームのネイティブメール通知を使用しています。
- このメールの内容と外観を変更したいと考えています。
イメージです:Liferayのネイティブメール通知
環境
- Liferay DXP 7.0+
解決
- 現在、メール通知をより簡単にカスタマイズできるようにするために、オープンな機能リクエストがあります。 この機能を今後のLiferayのバージョンに求める場合は、必ず投票してください。
- 独自のメールテンプレートを作成し、ネイティブのテンプレートより優先的に使用することが可能です。 効果的な方法については、以下のガイドを参照してください:
まず、 com.liferay.dynamic.data.mapping.service OSGi bundleをホストとして、Liferayモジュールフラグメントを作成する必要があります。 このフラグメントの目的は、内部パッケージ com.liferay.dynamic.data.mapping.internal.notificationをエクスポートすることで、電子メール通知を送信するクラスを拡張し、新しいカスタム電子メールテンプレートを保存することです(次のパラグラフのモジュールにテンプレートを保存することもできます。)
Bundle-Name: ddm-service-fragment
Bundle-SymbolicName: ddm.service.fragment
Bundle-Version: 1.0.0
Export-Package: com.liferay.dynamic.data.mapping.internal.notification
Fragment-Host: com.liferay.dynamic.data.mapping.service;bundle-version="5.3.12"
Portal-Bundle-Version: 7.3.10
コード:フラグメントのbnb.bndファイルの例(Liferay DXP 7.3 GA1使用時
これを作成したら、カスタムEメールテンプレートをフラグメントの src/main/resources/META-INF/ フォルダ内に配置します。(ホストのテンプレートと同じ修飾パスを使わないようにしてください。OSGiは、フラグメントを経由する前に、まずホスト内のリソースを探すように設計されています)
画像:カスタムメール本文テンプレートの例
このフラグメントが完成したら、新しい Liferay サービスモジュールを作成します。このモジュールの内部では、 DDMFormEmailNotificationSenderを拡張すべき新しいクラスを用意します。新しい拡張機能をサービス DDMFormEmailNotificationSender.class のOSGi コンポーネントとして設定し、サービスのランキングを上げます。これにより、サーバーを起動するたびに、カスタム サービスが Liferay のサービスよりも優先されることが保証されます。 (モジュールをホット デプロイすると、 デフォルトのサービスを指します)
@Component(
immediate = true, property = "service.ranking:Integer=" + Integer.MAX_VALUE,
service = DDMFormEmailNotificationSender.class
)
public class DDMCustomNotificationSender extends DDMFormEmailNotificationSender {
...
}
コード:カスタムDDMFormEmailNotificationSenderサービス構成例
あとは、カスタムサービスで必要なものをカスタマイズするだけです(テンプレートパスの変更など)。 しかし、メソッドをオーバーライドしてテンプレートパスをハードコードし、カスタマイズが正しいクラスローダーからテンプレートを見つけるために、getClass()コールをDDMFormEmailNotificationSender.classに変更するだけではうまくいかないことに気づくかもしれません。
@Override
protected TemplateResource getTemplateResource(String templatePath) {
Class<?> clazz = DDMFormEmailNotificationSender.class;
ClassLoader classLoader = clazz.getClassLoader();
URL templateURL = classLoader.getResource("/META-INF/resources/email/notification.soy");
return new URLTemplateResource(templateURL.getPath(), templateURL);
}
コード:これ単体では動作しません
次々と修正しようとすると、実行中に NullPointerExceptions が多数発生します。 これは、スーパークラスのメソッドが、カスタムエクステンションを最初にデプロイした時点ではまだ参照されていなかったいくつかのLiferayサービスを使用しているために起こります。 したがって、それらのサービスを参照し、それらを使用するすべてのメソッドをあらかじめオーバーライドしておく必要があります。
private DDMFormFieldTypeServicesTracker _ddmFormFieldTypeServicesTracker; @Reference private GroupLocalService _groupLocalService; private MailService _mailService; @Reference private Portal _portal; @Reference private SoyDataFactory _soyDataFactory; private UserLocalService _userLocalService;
コード: DDMFormEmailNotificationSender で使用されているサービスで、お客様のサービスから参照する必要があるもの
その後、カスタムメール通知を受け取ることができるようになります。
Tips.
開発時間を短縮したい場合は、スーパークラス全体をコピーして拡張機能に貼り付けることをお勧めします。 スーパー クラスを指す必要がある getClass() 呼び出しと、カスタム テンプレート パスを指す必要があるプライベート定数 _TEMPLATE_PATH に注意してください。
ResourceBundle resourceBundle = ResourceBundleUtil.getBundle("content.Language", locale, getClass());
コード:カスタムクラスにコピーするときに DDMFormEmailNotificationSender.classに置き換える必要がある元のクラスのgetClass()呼び出しの例
private static final String _TEMPLATE_PATH = "/META-INF/resources/notification/form_entry_add_body.soy";
コード:_TEMPLATE_PATH定数のオリジナル値
Soyテンプレート言語とLiferayの組み込みテンプレート処理APIを使用すると、実行時に処理されるので、 .soy ファイルをコンパイルする必要はありません。そのため、コンパイルスクリプトでは省くことができます。
transpileJS {
enabled = false
}
コード:Gradleを使用している場合は、フラグメントのbuild.gradleファイルに以下を追加します。
Liferay Workspace を使ってプロジェクトを開発している場合、バンドルで必要なパッケージをすべて手動で宣言するつもりなら、サービスモジュール bnd.bnd'の Import-Package ヘッダーだけを設定します。
Bundle-Name: ddm-custom-notification-sender
Bundle-SymbolicName: ddm.custom.notification.sender
Bundle-Version: 1.0.0
コード:サービスモジュールのbnb.bndファイルが動作するはずの例。 Bndtoolsは、Import-Packageヘッダを宣言しない場合、最終的なMANIFEST.MFに自動的にセットします。
DXP 7.4に関する具体的な注意事項
- Liferay モジュールフラグメントは内部パッケージ com.liferay.dynamic.data.mapping.internal.notificationを公開すればよいのです。 カスタムテンプレートを含める必要はありません:それはカスタムサービスの中にあります。
- カスタムサービスには、必要なものがあります:
- カスタムテンプレートは、 src/main/resources/META-INF/resources/notificationのようなパスに配置します。
-
DDMFormEmailNotificationSender を拡張したカスタムクラス. 最も簡単な方法は、元のクラス全体をコピーし、属性
_TEMPLATE_PATH
を修正し、上記のようにカスタムテンプレートのパスを指すようにすることです。
-
再デプロイ後にカスタムサービスが使用されるようにするには、元のコンポーネント com.liferay.dynamic.data.mapping.internal.notification.DDMFormEmailNotificationSender をドキュメント Blacklisting OSGi Componentsに従ってブラックリスト化することを確認します。
- これは、 DDMFormInstanceRecordLocalServiceImpl の元のコンポーネント
_ddmFormEmailNotificationSender
への参照が、デフォルトで reluctant policy-option を持つため、同じ実装に固執する傾向があるために起こる可能性があります。
- これは、 DDMFormInstanceRecordLocalServiceImpl の元のコンポーネント