1. 概要
Java/JSPを利用して実装されたサンプルアプリケーションです。
Java/JSPのカスタマイズする方法はチュートリアル(カスタマイズ)Java/JSPをご参照ください。
2. セットアップ
サンプルアプリケーションのセットアップ説明です。
もし、既にiPLASSの開発環境の構築とチュートリアルを実行できた方で、サンプルアプリケーションを動かしたい場合、以下の手順に従って実施してみてください。
それ以外の方は開発環境の構築を先に実施することをお勧めします。
-
サンプルアプリケーションのプロジェクトをGitHubから取得してプロジェクトを作成します。プロジェクトの作成手順はプロジェクトの作成を参照してください。
サンプルコードで Java8 より上のバージョンのスタイルでコーディングする場合は build.gradle の javaVersion を使用したい Java のバージョンに書き換えてください。
書き換えた後はGradleプロジェクトのリフレッシュを行い、エラーが出ないことを確認してください。build.gradleapply plugin: 'java' apply plugin: 'war' apply plugin: 'eclipse-wtp' ext { javaVersion = JavaVersion.VERSION_1_8 (1) } ----------------------------------------以下略----------------------------------------
1 必要に応じて使用したい Java のバージョンに書き換えます。
-
テナントの作成
このサンプルアプリは開発環境の構築の章で作成したテナントで動かすことを想定しています。もし新規テナントで サンプルアプリを起動したい場合、以下の手順を実施してください。それ以外の場合、次の サンプルアプリの起動手順 を参照してくだい。 -
service-configに以下の設定を入れ替えます。
<!-- Rdb Connection Settings --> <service> <interface>org.iplass.mtp.impl.rdb.connection.ConnectionFactory</interface> <!-- DataSource base ConnectionFactory --> <!-- <class>org.iplass.mtp.impl.rdb.connection.DataSourceConnectionFactory</class> --> (1) <!-- <property name="dataSourceName" value="java:comp/env/jdbc/iplass" /> --> (1) <!-- DriverManager base ConnectionFactory --> <class>org.iplass.mtp.impl.rdb.connection.DriverManagerConnectionFactory</class> (2) <!-- for mysql --> <property name="url" value="jdbc:mysql://[host]:[port]/[schema]" /> <property name="user" value="XXXXX" /> (3) <property name="password" value="XXXXX" /> (3) <property name="driver" value="com.mysql.cj.jdbc.Driver" /> (4) <!-- if sql execution exceeds this milliseconds, log sql by warn level.(0 means no log by warn level) --> <property name="warnLogThreshold" value="0" /> <!-- If change transaction isolation level on create connection, set below. --> <!-- <property name="transactionIsolationLevel" value="READ_COMMITTED" /> --> </service>
1 データソース利用に関する設定項目をコメントアウトします。 2 ドライバ利用に関する設定項目を追加します。 3 テナント作成時はDBA権限を持つユーザーを設定してください。 4 クラスパスが通っている場所にJDBCドライバを配置します。 -
サンプルアプリのルートパスの下で 、
-
Gradleタスクの
runTenantBatch
を実行します。 -
起動した画面で
Create Default Tenant
をクリックします。 -
ダイアログで
name(テナント名)
、AdminUserId(管理者ユーザーID)
、AdminUserPassword(管理者ユーザーパスワード)
を入力し、Create
をクリックします。
-
-
サンプルアプリではデータベースへの接続方法がデータソースを利用することを想定していますが、テナントを作成する処理の runTenantBatch タスクではデータソースに関する設定を利用できないため、一時的に接続方法をデータソース利用からドライバ利用に変えます。 +
テナント作成が完了しましたら、データソースを利用する設定に戻してください。
|
-
以下のサンプルアプリの起動手順を順に実施してください。
-
サンプルではデータソースを利用しますので、Tomcatのコンテキスト設定にmtp-service-config.xmlに書いてあるデータソースに対する定義を入れます。
それに、Tomcatのlib
フォルダに該当するjdbcドライバーを入れます。ファイル名
/src/main/resources/mtp-service-config.xml
<!-- Rdb Connection Settings --> <service> <interface>org.iplass.mtp.impl.rdb.connection.ConnectionFactory</interface> <!-- DataSource base ConnectionFactory --> <class>org.iplass.mtp.impl.rdb.connection.DataSourceConnectionFactory</class> <property name="dataSourceName" value="java:comp/env/jdbc/iplass" /> (1) <!-- if sql execution exceeds this milliseconds, log sql by warn level.(0 means no log by warn level) --> <property name="warnLogThreshold" value="0" /> <!-- If change transaction isolation level on create connection, set below. --> <!-- <property name="transactionIsolationLevel" value="READ_COMMITTED" /> --> </service>
1 サンプルアプリ実行用のデータソース名 開発環境の構築の章で作成したデータベースの接続情報をインストールしたTomcatの次の設定ファイルに入れます。
%CATALINA_HOME%\conf\context.xml
<?xml version="1.0" encoding="UTF-8"?> <WatchedResource>WEB-INF/web.xml</WatchedResource> <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource> <Resource name="jdbc/iplass" auth="Container" type="javax.sql.DataSource" maxTotal="100" maxIdle="30" maxWaitMillis="10000" username="XXXXX" password="XXXXX" driverClassName="com.mysql.cj.jdbc.Driver" url="jdbc:mysql://[host]:[port]/[schema]"/> (1) </Context>
1 Tomcatのコンテキスト設定に該当するデータソースの設定を入れます。 -
サンプルが全文検索機能(lucene)を利用しますので、mtp-service-config.xmlに書いてあるINDEXデータファイルの仮の保存場所をローカル環境の適当な場所に変えます。
ファイル名
/src/main/resources/mtp-service-config.xml
<service> <interface>org.iplass.mtp.impl.fulltextsearch.FulltextSearchService</interface> <property name="useFulltextSearch" value="true" /> (1) <property name="maxRows" value="1000" /> <property name="throwExceptionWhenOverLimit" value="true"/> <!-- lucene利用 --> <class>org.iplass.mtp.impl.fulltextsearch.lucene.LuceneFulltextSearchService</class> <property name="directory" value="[set your lucene index file store path. eg: D:\tmp\lucene]" /> (2) <property name="analyzer" value="org.apache.lucene.analysis.ja.JapaneseAnalyzer" /> <property name="indexWriterRAMBufferSizeMB" value="64.0"/> <property name="redundantTimeMinutes" value="10"/> </service>
1 useFulltextSearchをtrueに設定します。 2 INDEXファイル保存場所をローカルパスに設定します。 -
Tomcatを起動し、
http://localhost:8080/コンテキスト名/テナント名/gem/
にアクセスすると、ログイン画面が表示されます。管理者ユーザーIDとパスワードでログインします。 -
Admin Consoleの
Packaging
機能を利用してプロジェクトのsample-dataフォルダにあるサンプル実行用のデータをインポートします。「entitydata.zip」ファイルを、AdminConsoleの「Packaging」ツールで取り込んでください。
デフォルトの設定で「import」ボタンを押下してください。
Importを実行すると「Log」パネルに処理状況が表示されます。処理が終了したタイミングでエラーが発生していないことを確認してください。
新たに作成したロールなどを反映させるために、MetaDataSettingsメニューの右上の「MetaDataの一覧を更新にします。」ボタンをクリックします。
-
Admin ConsoleでTenant多言語利用設定で「日本語」と「英語」にチェックを入れます。
「Save」ボタンを押してください。
-
Admin ConsoleでEntityExplorerの
Entity Crawl
機能を利用してINDEXデータを作成します。
本ドキュメントでは以下の手順で説明しますが、詳細を知りたい方はデータ管理 6.全文検索を参照してください。ToolsのEntityExplorerを選択します。
全文検索を利用する設定になっている場合、「Entity Crawl」タブが表示されます。
A) 任意のEntityのみを対象としてクローリングしたい場合はリストのEntityにチェックをいれ、「Start Crawl」ボタンをクリックして下さい。
B) クローリング対象Entityを全てクローリングしたい場合は「Re Crawl All Entity」ボタンをクリックして下さい。この場合、チェックをいれていないEntityも全てが対象となります。
C) クローリングが完了しましたら、最新のINDEXデータを反映させるために、「Refresh」ボタンをクリックして下さい。
-
上記起動手順の実施が完了しましたら、サンプルアプリのグローバル設定を確認してください。
3. 機能
3.1. Top画面の作成
-
Layoutの利用
Top画面の構成は下図のようになっています。画面共通で利用するレイアウト用テンプレートdefaultLayout
とshippingLayout
を用意し、画面右部分はそれぞれの機能に併せて呼びだす形にしています。ここでは"top"テンプレートを呼び出して利用しています。ファイル
src/main/webapp/jsp/samples/ec01/layout/defaultLayout.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ page import="org.iplass.mtp.web.template.TemplateUtil"%> <%@ page import="samples.ec01.utils.URLHelper" %> <%@ taglib prefix="m" uri="http://iplass.org/tags/mtp"%> (1) <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> ----------------------------------------以上略---------------------------------------- <!-- 小さい画面で表示 end--> <div class="row layout-container"> <div class="col-md-3 d-none d-md-block"> <div class="row"> <div class="col-12"> <div class="list-group list-group-item-dark list-group-flush"> <a href="${m:tcPath()}/samples/ec01/top" class="list-group-item list-group-item-action font-weight-bold border-top">${m:rs('iplass-wtp-messages', 'samples.ec01.layout.defaultLayout.home')}</a> <c:forEach var="category" items="${categoryList}"> <a href="${URLHelper.getCategoryPath(category.oid)}" class="list-group-item list-group-item-action">${category.name}</a> </c:forEach> </div> </div> </div> </div> <div class="col-sm-12 col-md-9"> <m:renderContent /> (2) </div> </div> <hr> <div class="row"> <div class="col-12"> <ul class="list-group"> <li class="list-group-item border-0 font-weight-bold">Links</li> <li class="list-group-item border-0"> <a href="${m:tcPath()}/samples/ec01/news/newInfo" class="text-dark">${m:rs('iplass-wtp-messages','samples.ec01.layout.defaultLayout.news')}</a> </li> <li class="list-group-item border-0"> <a href="${m:tcPath()}/samples/ec01/search/search" class="text-dark">${m:rs('iplass-wtp-messages','samples.ec01.layout.defaultLayout.search')}</a> </li> <li class="list-group-item border-0"> <a href="${m:tcPath()}/samples/ec01/inquiry/inquiry" class="text-dark">${m:rs('iplass-wtp-messages','samples.ec01.layout.defaultLayout.inquiry')}</a> </li> <li class="list-group-item border-0"> <a href="${m:tcPath()}/samples/ec01/shop/tradeLaw" class="text-dark">${m:rs('iplass-wtp-messages','samples.ec01.layout.defaultLayout.SCTAInfo')}</a> </li> </ul> </div> </div> ----------------------------------------以下略----------------------------------------
1 iPLAssのJSPタグライブラリ 2 LayoutアクションのJSPにおいて、実際のコンテンツを表示する箇所を指定するJSPタグです。 -
メタデータ定義ファイル
ファイル名
samples-ec01-ce-metadata.xml
<contextPath name="/template"> ----------------------------------------以上略---------------------------------------- <!-- レイアウト --> <metaDataEntry> <metaData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="metaJspTemplate"> <name>samples/ec01/layout/defaultLayout</name> <displayName>標準レイアウト</displayName> <path>/jsp/samples/ec01/layout/defaultLayout.jsp</path> (1) <contentType>text/html; charset=utf-8</contentType> </metaData> </metaDataEntry> ...... <metaDataEntry> <metaData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="metaJspTemplate"> <name>samples/ec01/top</name> <displayName>Top画面</displayName> <path>/jsp/samples/ec01/top.jsp</path> (2) <layoutId>/action/samples/ec01/layout/defaultLayout</layoutId> (3) <contentType>text/html; charset=utf-8</contentType> </metaData> </metaDataEntry> ----------------------------------------以下略----------------------------------------
1 レイアウト用のテンプレートファイルを指定しています。 2 Top画面のテンプレートファイルをJSPファイルにしています。 3 読みこまれる側(この例だとTop用テンプレート)ではLayoutIdをレイアウトテンプレートに指定しています。
3.2. Bean/Bean Validation
iPLAssのBean/Bean Validation機能を利用する場合、チェックしたいBeanクラスのプロパティにアノテーションをつけることで、バリデーションが自動に実行されます。それに、バリデーション結果を画面に表示できます。
サンプルアプリの問い合わせ登録画面で入力された値に対してバリデーションが実行される機能を例として説明していきます。
-
必要なJavaクラスを作成しています。
プロジェクトのフォルダ src/main/java/samples/ec01/beanを開きます。src.main.java ┗ samples.ec01 ┣ bean ┗ annotation (1) ┃ ┣ Kana.java ┃ ┗ ...... ┣ ui ┣ validator (2) ┃ ┣ group (3) ┃ ┃ ┗ JapaneseChecks.java ┃ ┣ KanaValidator.java ┃ ┗ ...... ┣━ UserBean.java (4) ┗ ......
1 カスタムのバリデーション
カスタムのバリデーションをsamples.ec01.bean.annotation.Kana
に記述して、それがカスタムのバリデーターを利用しています。2 カスタムのバリデーター
カスタムのバリデーターをsamples.ec01.bean.validator.KanaValidator
に記述して、それがカスタムのバリデーションで利用されています。3 カスタムのバリデーショングループ
カスタムのバリデーショングループをsamples.ec01.bean.validator.group.JapaneseChecks
に記述して、それがBeanクラスのアノテーションで利用されています。4 JavaBeanクラス
samples.ec01.bean.UserBean
でカスタムのバリデーションとバリデーショングループを利用しています。 -
バリデーションエラーメッセージを定義する
Bean Validationエラーメッセージはプロパティファイルに定義し、多言語利用が可能です。 -
コマンドクラスでBean Validationを利用する
ファイル名
/src/main/java/samples/ec01/command/inquiry/RegistInquiryCommand.java
...... @ActionMapping( name = "samples/ec01/inquiry/doInquiry", displayName = "お問合せ登録", privileged = true, tokenCheck = @TokenCheck( executeCheck = true, consume = true, exceptionRollback = true), result = { @Result( exception = MappingException.class, (1) type = Type.TEMPLATE, value = "samples/ec01/inquiry/inquiry"), @Result( status = Constants.CMD_EXEC_SUCCESS, type = Type.TEMPLATE, value = "samples/ec01/inquiry/inquirySuccess")}) @CommandClass( name = "samples/ec01/inquiry/RegistInquiryCommand", displayName = "お問合せ登録コマンド") public class RegistInquiryCommand implements Command { private final BeanParamMapper mapper = new BeanParamMapper().withValidation() .whitelistPropertyNameRegex("^(mail|content|familyName(Kana)?|firstName(Kana)?)$"); (2) public static final String RESULT_INQUIRY_BEAN = "inquiryBean"; @Override public String execute(RequestContext request) { // 入力チェック InquiryBean inquiryBean = new InquiryBean(); request.setAttribute(RESULT_INQUIRY_BEAN, inquiryBean); // 日本語専用"name_kana"取得フォーム if (Consts.LANGUAGE_JA.equals(TemplateUtil.getLanguage()) || TemplateUtil.getLanguage() == null) { mapper.populate(inquiryBean, request.getParamMap(), Default.class, JapaneseChecks.class); (3) } else { mapper.populate(inquiryBean, request.getParamMap(), Default.class); (4) } Inquiry inquiry = inquiryBean.toEntity(); // 問い合わせステータス // 1 : 未対応 // 2 : 対応中 // 3 : 対応完了 // 4 : 終了 SelectValue inquiryStatus = new SelectValue(InquiryStatus.NOT_DEAL.getValue()); inquiry.setInquiryStatus(inquiryStatus); // 請求の登録 EntityDaoHelper.insert(inquiry); return Constants.CMD_EXEC_SUCCESS; } }
1 MappingExceptionが発生した場合、遷移先のTemplateを指定します。※RequestスコープにWebRequestConstants.EXCEPTIONをキーにMappingExceptionを登録してくれます。 2 Beanクラスに画面からの入力値をマッピングするためのユーティリティクラスを初期化します。
※ whitelistPropertyNameRegexメソッドにセット可能な項目の正規表現式を指定します。3 多言語利用で「日本語」が選択されているまたは多言語利用の設定が取得できなかった場合、 samples.ec01.bean.validator.group.JapaneseChecks
グループとデフォルトグループに属する項目に対してバリデーションが実行されます。
※ populate(Object, Map, Class)メソッドはスレッドセーフですが、それ以外の delimiters(char, char, char)等の設定用メソッドがスレッドセーフではありません。 詳しい説明はorg.iplass.mtp.command.beanmapper.BeanParamMapper
のJavaDocを参照してください。4 多言語利用で「日本語」以外が選択されている場合、デフォルトグループに属する項目のみに対してバリデーションが実行されます。 -
JSPテンプレートファイル
ファイル名
/jsp/samples/ec01/inquiry/registInquiry.jsp
----------------------------------------以上略---------------------------------------- <m:bind bean="${inquiryBean}"> (1) <form class="custom-form mt-3" action="${m:tcPath()}/samples/ec01/inquiry/doInquiry" method="post"> <input type="hidden" name="_t" value="${m:token()}"> <div class="form-group row"> ...... <div class="col-12 col-md-6 mt-3"> <div> <m:bind prop="familyNameKana"> (2) <label for="${name}" class="col-form-label label-hidden">${m:rs('iplass-wtp-messages', 'samples.ec01.inquiry.regist.familyNameKana')}</label> <input type="text" class="form-control border rounded input-hint-visible" name="${name}" value="${value}" placeholder="${m:rs('iplass-wtp-messages', 'samples.ec01.inquiry.regist.familyNameKana')}"> (3) <small class="form-text text-danger"><m:errors /></small> (4) </m:bind> </div> </div> ...... </form> </m:bind> ----------------------------------------以下略----------------------------------------
1 PageContext
にBeanインスタンスをバインドします。2 PageContext
にBeanインスタンスに格納されているプロパティ名と値をバインドします。autoDetectErrors=true(デフォルトがtrue)の場合、WebRequestConstants.EXCEPTIONをキーにMappingExceptionを取得し、MappingResultのインスタンスが自動解決されます。当該Bean、プロパティに紐付くエラーがバインドされます。3 バインドされたプロパティの名前と値をテキストボックスにバインドします。 4 バインドされたエラーメッセージを画面に出力します。 ※ 詳しい設定する方法を
org.iplass.mtp.web.template.tags.BindTag
とorg.iplass.mtp.web.template.tags.ErrorsTag
のJavaDocをご参照してください。 -
動作確認
-
「姓」と「名」を空文字として登録しようとしたら、バリデーションエラーが発生することを画面から確認できます。
-
「セイ」と「メイ」に全角カタカナ以外の値を入れて登録しようとしたら、バリデーションエラーが発生することを画面から確認できます。
-
多言語利用で「英語」が選択された場合、英語のバリデーションエラーメッセージが表示されることを確認できます。
※ 英語用の画面にカタカナの「セイ」と「メイ」の入力項目がないので、日本語用の画面と比べてレイアウトに少し違いがあります。
-
3.3. Entity作成
-
Admin ConsoleのEntity定義で
Mapping Class
機能の利用でEntityのJavaクラスを自動生成することができます。パッケージ
samples.ec01.entity
-
Entity多言語対応をしています。
Admin Console部分の設定でEntity多言語対応をご参照してください。
3.4. ErrorUrlSelector
エラー画面Template制御スクリプトクラスです。
-
Tokenエラーを例として説明していきます。
ファイル名
src/main/java/samples/ec01/web/EcErrorUrlSelector.java
public class EcErrorUrlSelector extends GemErrorUrlSelector { private final String ROOT_PATH = "samples/ec01"; private final String TEMPURL_TOKEN_ERROR = ROOT_PATH + "/error/tokenError"; private final String TEMPURL_ENTITY_ERROR = ROOT_PATH + "/error/entityError"; private final String TEMPURL_USER_EXISTS_ERROR = ROOT_PATH + "/error/userExistsError"; private final String TEMPURL_SESSION_VALUE_NOT_FOUND_ERROR = ROOT_PATH + "/error/sessionValueNotFoundError"; private final String TEMPURL_SYSTEM_ERROR = ROOT_PATH + "/error/systemError"; @Override public String getErrorTemplateName(Throwable exception, RequestContext request, String path) { Exception error = (Exception) request.getAttribute(WebRequestConstants.EXCEPTION); // ECサイト用 if (path != null && path.startsWith(ROOT_PATH)) { // TokenValidationException用 if (error instanceof TokenValidationException) { return TEMPURL_TOKEN_ERROR; (1) // EntityValidationException用 } else if (error instanceof EntityValidationException) { return TEMPURL_ENTITY_ERROR; // UserExistsException } else if (error instanceof UserExistsException) { return TEMPURL_USER_EXISTS_ERROR; // SessionValueNotFoundException } else if (error instanceof SessionValueNotFoundException) { return TEMPURL_SESSION_VALUE_NOT_FOUND_ERROR; // その他のエラー用 } else { return TEMPURL_SYSTEM_ERROR; } } return super.getErrorTemplateName(exception, request, path); } }
1 TokenValidationExceptionが発生した場合、カスタムのsamples/ec01/error/tokenErrorテンプレートが呼び出されます。 -
カスタムのErrorUrlSelectorをservice-configに登録する必要が有ります。設定ファイルをご参照ください。
-
メタデータ定義ファイル
ファイル名
samples-ec01-ce-metadata.xml
<contextPath name="/template"> ----------------------------------------以上略---------------------------------------- <!-- エラー画面 --> <metaDataEntry> <metaData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="metaJspTemplate"> <name>samples/ec01/error/tokenError</name> (1) <displayName>トークンエラー画面</displayName> <path>/jsp/samples/ec01/error/genericError.jsp</path> (2) <layoutId>/action/samples/ec01/layout/defaultLayout</layoutId> <contentType>text/html; charset=utf-8</contentType> </metaData> </metaDataEntry> ----------------------------------------以下略----------------------------------------
1 tokenエラーテンプレート名 2 エラーテンプレートファイルをJSPファイルに指定してます。 -
共通エラーテンプレートファイル
ファイル名
/src/main/webapp/jsp/samples/ec01/error/genericError.jsp
-
動作確認
-
TokenValidationExceptionが発生した場合、カスタムのテンプレートが表示されること。
Consoleで出力されたエラーログです。
org.iplass.mtp.web.actionmapping.TokenValidationException: 不正な画面遷移が発生しました(一連の登録処理中にブラウザの戻るボタン等を押下してしまいますと正常に処理を継続できない場合があります)。 at org.iplass.mtp.impl.web.interceptors.TokenInterceptor.doError(TokenInterceptor.java:84) at org.iplass.mtp.impl.web.interceptors.TokenInterceptor.intercept(TokenInterceptor.java:114) at org.iplass.mtp.impl.command.InvocationImpl.proceedCommand(InvocationImpl.java:115) at org.iplass.mtp.impl.web.actionmapping.WebInvocationImpl.proceedCommand(WebInvocationImpl.java:171) at org.iplass.mtp.impl.command.interceptors.TransactionInterceptor.lambda$intercept$0(TransactionInterceptor.java:34) at org.iplass.mtp.transaction.TransactionManager.doTransaction(TransactionManager.java:114) at org.iplass.mtp.transaction.Transaction.with(Transaction.java:303) at org.iplass.mtp.impl.command.interceptors.TransactionInterceptor.intercept(TransactionInterceptor.java:33)
-
エラー内容表示画面
-
3.5. ReportOutput(注文明細ダウンロード)
-
POIを用いてExcel形式の注文明細帳票の出力機能を実装しています。
-
Java/JSP版では、Javaクラスを用いてTemplateのOutput Logicを実装しています。
ファイル名
samples.ec01.template.report.OrderOutputLogic
-
帳票テンプレート
作成方法は、開発者ガイド帳票出力(Jasper/JXLS/POI)の章をご参照ください。 -
POI帳票出力機能の動作確認
-
管理用画面で注文検索一覧画面を開き、詳細リンクをクリックします。
-
「注文明細ダウンロード」ボタンをクリックします。
-
ダウンロードしたExcel帳票を確認します。
このサンプルでは、英語用の帳票テンプレートも別途用意しています。
-
3.6. Buildin EL関数
-
iPLAssのJSPタグライブラリに定義されているBuildin EL関数を利用しています。
<%@ taglib prefix="m" uri="http://iplass.org/tags/mtp"%> (1) ----------------------------------------以上略---------------------------------------- <div class="row"> <div class="col-12"> <div class="border-top"></div> <nav class="breadcrumb all-breadcrumb"> <a class="breadcrumb-item text-primary" href="${m:tcPath()}/samples/ec01/top"> (2) ${m:rs('iplass-wtp-messages', 'samples.ec01.all.breadcrumb.home')} (3) </a> <span class="breadcrumb-item active"> ${m:rs('iplass-wtp-messages', 'samples.ec01.inquiry.regist.title')} </span> </nav> </div> <div class="col-12"> <span class="h4">${m:rs('iplass-wtp-messages', 'samples.ec01.inquiry.regist.title')}</span> <m:bind bean="${inquiryBean}"> <form class="custom-form mt-3" action="${m:tcPath()}/samples/ec01/inquiry/doInquiry" method="post"> <input type="hidden" name="_t" value="${m:token()}"> (4) <div class="form-group row"> <div class="col-12 col-md-6 mt-3"> <div> <m:bind prop="familyName"> <label for="${name}" class="col-form-label label-hidden">${m:rs('iplass-wtp-messages', 'samples.ec01.inquiry.regist.familyName')}</label> <input type="text" class="form-control border rounded input-hint-visible" name="${name}" value="${value}" placeholder="${m:rs('iplass-wtp-messages', 'samples.ec01.inquiry.regist.familyName')}"> <small class="form-text text-danger"><m:errors /></small> </m:bind> </div> </div> ----------------------------------------以下略----------------------------------------
1 iPLAssのJSPタグライブラリ 2 tcPath(): tenant名まで含むコンテキストパスを取得します。 3 rs(): 指定された基底名、キーからResourceBundleに定義された文字列を返します。多言語メッセージを併せて利用できます。 4 token(): トランザクショントークンを出力します。 ※ 他のEL関数の使い方について、
org.iplass.mtp.web.template.ELFunctions
のJavaDocを参照してください。
3.7. WebApiとの連携
Ajaxを利用することで、WebApiと連携することが出来ます。一般消費者向け画面で全文検索処理を例として説明していきます。
-
開発者ガイド WebApiの作成方法を参照してください。
以下はここで利用しているWebApiです。WebApi名
samples/ec01/search/fulltextSearch
-
WebApiを利用しているJSPテンプレート
ファイル名
/src/main/webapp/jsp/samples/ec01/search/search.jsp
----------------------------------------JSP部分略---------------------------------------- <script type="text/javascript"> function fullTextSearch() { var productName = $("#productName").val(); var categoryOid = $("#categoryList").attr("category-item-selected"); if(productName == "") { $("#helpId").html("${m:rs('iplass-wtp-messages', 'samples.ec01.search.nokeyword')}"); return false; } var param = "{\"productName\":\"" + productName + "\",\"categoryOid\":\"" + categoryOid +"\"}"; $.ajax({ type: "POST", contentType: "application/json", url:"${m:tcPath()}/api/samples/ec01/search/fulltextSearch", (1) dataType: "json", data: param, success: function(commandResult){ if (commandResult.exceptionType != null) { (2) alert("${m:rs('iplass-wtp-messages', 'samples.ec01.search.jsError')}"+ commandResult.exceptionType +"\\n"+commandResult.exceptionMessage); return; } if(commandResult.status == "SUCCESS"){ if(commandResult.defaultResult != null && commandResult.defaultResult.length > 0){ var resultHtml = ListSearchResult(commandResult.defaultResult, productName); (3) $("#searchResultDiv").html(resultHtml); } else{ $("#helpId").html("${m:rs('iplass-wtp-messages', 'samples.ec01.search.keyword')}: " + productName + ", " + "${m:rs('iplass-wtp-messages', 'samples.ec01.search.noResult')}"); } } } }); } function dropdownSelect(item){ var t = $(item); var v = t.attr("category-item-value"); $("#categoryList").text(t.html()).attr("category-item-selected", v); } function ListSearchResult(entities, productName){ (4) var yen = "${m:rs('iplass-wtp-messages', 'samples.ec01.all.yen')}"; var html = "<div class=\"col-12 mb-2\">"; html += " <h4>${m:rs('iplass-wtp-messages', 'samples.ec01.search.result')}" + productName + "</h4>"; html += "</div>"; for(var i =0; i < entities.length; i++){ var name = entities[i].name; var price = isNaN(entities[i].price)? "" : entities[i].price; var imageUrl = "${m:tcPath()}/samples/ec01/resource/bin?id=" + entities[i].productImg.lobId + "&type=${Consts.BIN_TYPE_PRODUCT_IMG}"; var detailUrl = "${m:tcPath()}/samples/ec01/product/detail?productId=" + entities[i].oid; html += "<div class=\"col-12 col-md-4\">"; html += " <div class=\"card border-light border-0\">"; html += " <a href=\"" + detailUrl + "\" class=\"h-100\">"; html += " <img class=\"card-img-top img-thumbnail img-fluid all-product-img\" src=" + imageUrl + " alt=\"" + name + "\">"; html += " </a>"; html += " <div class=\"card-body pt-md-1 text-center\">"; html += " <div>"; html += " <a href=\""+ detailUrl +"\" class=\"card-link text-dark\">" + name + "</a>"; html += " </div>"; html += " <div class=\"all-price\">"; html += " <span>" + price + "</span>" + yen; html += " </div>"; html += " </div>"; html += " </div>"; html += "</div>"; } return html; } </script>
1 WebApiによる検索処理を呼び出します。 2 検索処理でエラーが発生した場合、クライアント側での処理。 3 返された検索処理の結果を取得し、クライアント側の描画処理を呼び出します。 4 検索結果の描画処理。
-
動作確認
-
キーワードを入力し、検索ボタンをクリックします。
-
返却値の例
{"status":"SUCCESS","defaultResult":[{"definitionName":"samples.ec01.products.Product","price":2709,"name":"Javaルールブック ~読みやすく効率的なコードの原則","productImg":{"lobId":195,"name":"wolf.png","type":"image/png","definitionName":"samples.ec01.products.Product","propertyName":"productImg","oid":"EC011","size":13872},"oid":"EC011"},{"definitionName":"samples.ec01.products.Product","price":2300,"name":"超図解 Javaルールブック (超図解シリーズ) [単行本]","productImg":{"lobId":208,"name":"bear.png","type":"image/png","definitionName":"samples.ec01.products.Product","propertyName":"productImg","oid":"EC019","size":12051},"oid":"EC019"}]}
-
検索結果を画面から確認できます。
-
3.8. セキュリティ対策
画面、処理、ともにオレンジ色の部分を例にセキュリティ対策を解説していきます。
ここでは会員登録を例としてiPLAssで利用できる以下のセキュリティ対策について説明します。
・ エスケープ機能 XSS対策 : ユーザーの入力内容を正常に画面表示させる
・ TokenCheck機能 CSRF対策/トランザクション重複起動対策 : 画面表示時に正常な画面遷移が行われているかをチェックする
会員登録処理の中でそれぞれの機能は下記のように利用されます。
-
エスケープの導入
Templateの作成
入力された値を出力する会員情報確認画面にて、該当箇所に${m:esc()}
エスケープを導入する。表示名 Template名 会員情報確認画面
samples/ec01/member/confirmMemberInfo
<%@ taglib prefix="m" uri="http://iplass.org/tags/mtp"%> (1) ----------------------------------------以上略---------------------------------------- <div class="card col-12 bg-light"> <div class="card-body"> <div class="row mt-3 border-bottom"> <div class="col-12 col-md-4"> <span class="text-muted font-weight-bold">${m:rs('iplass-wtp-messages', 'samples.ec01.member.regist.userId')}</span> </div> <div class="col-12 col-md-8">${m:esc(userBean.userId)}</div> </div> <div class="row mt-3 border-bottom"> <div class="col-12 col-md-4"> <span class="text-muted font-weight-bold">${m:rs('iplass-wtp-messages', 'samples.ec01.member.registConfirm.fullName')}</span> </div> <div class="col-12 col-md-4"> <span class="text-muted font-weight-bold">${m:rs('iplass-wtp-messages', 'samples.ec01.member.regist.familyName')}</span> ${m:esc(userBean.familyName)} (2) </div> <div class="col-12 col-md-4"> <span class="text-muted font-weight-bold">${m:rs('iplass-wtp-messages', 'samples.ec01.member.regist.firstName')}</span> ${m:esc(userBean.firstName)} (2) </div> </div> <% if (Consts.LANGUAGE_JA.equals(TemplateUtil.getLanguage()) || TemplateUtil.getLanguage() == null) { %> <div class="row mt-3 border-bottom"> <div class="col-12 col-md-4"> <span class="text-muted font-weight-bold">${m:rs('iplass-wtp-messages', 'samples.ec01.member.registConfirm.fullNameKana')}</span> </div> <div class="col-12 col-md-4"> <span class="text-muted font-weight-bold">${m:rs('iplass-wtp-messages', 'samples.ec01.member.regist.familyNameKana')}</span> ${m:esc(userBean.familyNameKana)} (2) </div> <div class="col-12 col-md-4"> <span class="text-muted font-weight-bold">${m:rs('iplass-wtp-messages', 'samples.ec01.member.regist.firstNameKana')}</span> ${m:esc(userBean.firstNameKana)} (2) </div> </div> <% } %> <div class="row mt-3 border-bottom"> <div class="col-12 col-md-4"> <span class="text-muted font-weight-bold">${m:rs('iplass-wtp-messages', 'samples.ec01.member.regist.mail')}</span> </div> <div class="col-12 col-md-8">${m:esc(userBean.mail)}</div> (2) </div> </div> </div> ----------------------------------------以下略----------------------------------------
1 iPLAssのJSPタグライブラリ 2 今回は出力先がHTML形式であるため全て${m:esc(変数名)}の形式でエスケープを行っている。 -
TokenCheckの導入
この機能では、iPLAssで実装されている正常に画面遷移してきたことを証明する"Token"というオブジェクトを利用します。不正な画面遷移を禁止するActionでTokenをチェックすることにより、正常な画面遷移が行われたかを判断します。-
Actionの設定
不正な画面遷移を禁止するActionでTokenをチェックする設定を行います。表示名 Action名 会員情報確認アクション
samples/ec01/member/confirmMemberInfo
@ActionMapping( name = "samples/ec01/member/confirmMemberInfo", displayName = "会員情報確認アクション", privileged = true, tokenCheck = @TokenCheck( (1) executeCheck = true, consume = true, exceptionRollback = true), result = { @Result( status = Constants.CMD_EXEC_ERROR, type = Type.TEMPLATE, value = "samples/ec01/member/inputMemberInfo"), @Result( status = Constants.CMD_EXEC_SUCCESS, type = Type.TEMPLATE, value = "samples/ec01/member/confirmMemberInfo") }) @CommandClass( name = "samples/ec01/member/ConfirmMemberInfoCommand", displayName = "会員情報確認コマンド") public class ConfirmMemberInfoCommand implements Command { ----------------------------------------以下略----------------------------------------
1 ActionMapping定義にTokenCheckのアノテーションを利用してます。 以下の設定が可能です。
executeCheck
false チェックを行わない true チェックを行う
useFixedToken
チェック→セッション単位に固定に払いだされるTokenをチェックする
consume
true→Tokenは再利用されません。
exceptionRollback
チェック→現在のTokenを再設定
この設定により直接この画面へ遷移するとエラーページが表示されます。
-
TemplateでTokenを作成
不正な画面遷移を禁止するActionへ遷移する画面でTokenを作成します。表示名 Template名 会員情報入力画面
samples/ec01/member/inputMemberInfo
----------------------------------------以上略---------------------------------------- <%@ taglib prefix="m" uri="http://iplass.org/tags/mtp"%> <div class="row"> <div class="col-12"> <div class="border-top"></div> <nav class="breadcrumb all-breadcrumb"> <a class="breadcrumb-item text-primary" href="${m:tcPath()}/samples/ec01/top"> ${m:rs('iplass-wtp-messages', 'samples.ec01.all.breadcrumb.home')} </a> <span class="breadcrumb-item active"> ${m:rs('iplass-wtp-messages', 'samples.ec01.member.regist.title')} </span> </nav> </div> <div class="col-12"> <span class="h4">${m:rs('iplass-wtp-messages', 'samples.ec01.member.regist.title')}</span> <form class="custom-form mt-3" action="${m:tcPath()}/samples/ec01/member/confirmMemberInfo" method="post"> <input type="hidden" name="_t" value="${m:token()}"> (1) <m:bind bean="${userBean}" mappingResult="${result}"> <div class="form-group row"> <div class="col-12"> <div> <m:bind prop="userId"> <label for="${name}" class="col-form-label label-hidden"> ${m:rs('iplass-wtp-messages', 'samples.ec01.member.regist.userId')} </label> <input type="text" class="form-control border rounded input-hint-visible" name="${name}" value="${value}" placeholder="${m:rs('iplass-wtp-messages', 'samples.ec01.member.regist.userId')}"> <small class="form-text text-danger"><m:errors/></small> </m:bind> </div ----------------------------------------以下略----------------------------------------
1 EL関数を利用してTokenを生成します。
-
3.9. 多言語対応
多言語を利用するために、サンプルアプリで以下の対応を行っています。
-
言語別にメッセージプロパティファイルの作成
-
言語別にBean Validationエラーメッセージプロパティファイルの作成
4. 設定ファイル
4.1. service-config
ファイル名 |
/src/main/resources/mtp-service-config.xml |
---|
-
カスタムのErrorUrlSelectorの登録
<!-- Web App Settings --> <service> <interface>org.iplass.mtp.impl.web.WebFrontendService</interface> <!-- ■ your error url selector ■ --> <property name="errorUrlSelector" class="samples.ec01.web.EcErrorUrlSelector" /> (1) </service>
1 カスタムのErrorUrlSelectorを登録しています。 -
メタデータ定義の登録
<!-- XmlResource MetaData and Annotation MetaData Settings --> <service> <interface>org.iplass.mtp.impl.metadata.MetaDataRepository</interface> <!-- ■ your app metadata xml file name (additional="true) ■ --> <property name="resourcePath" value="/samples-ec01-ce-metadata.xml" additional="true" /> (1) <!-- ■ your app command list class (additional="true) ■ --> <property name="annotatedClass" value="samples.ec01.command.metadata.CommandList" additional="true"/> (2) </service>
1 メタデータの定義ファイル 2 アノテーションでコマンドのメタデータ定義を作っています。 -
全文検索機能
<!-- Fulltext Search Service Settings --> <service> <interface>org.iplass.mtp.impl.fulltextsearch.FulltextSearchService</interface> <property name="useFulltextSearch" value="true" /> (1) <property name="maxRows" value="1000" /> <property name="throwExceptionWhenOverLimit" value="true"/> <!-- lucene利用 --> <class>org.iplass.mtp.impl.fulltextsearch.lucene.LuceneFulltextSearchService</class> <property name="directory" value="[set your lucene index file store path. eg: D:\tmp\lucene]" /> (2) <property name="analyzer" value="org.apache.lucene.analysis.ja.JapaneseAnalyzer" /> <property name="indexWriterRAMBufferSizeMB" value="64.0"/> <property name="redundantTimeMinutes" value="10"/> </service>
1 全文検索機能を有効化にしてます。 2 インデックスファイルの作成場所を指定してください。
5. リソースファイル
5.1. メタデータ定義
-
コマンドのメタデータ定義。
ここではJava/JSPを利用してカスタマイズを行っています。コマンドのメタデータ定義ファイル
ファイル名
/src/main/java/samples/ec01/command/metadata/CommandList.java
-
他のメタデータ定義
ファイル名
/src/main/resources/samples-ec01-ce-metadata.xml
ここでは二種類のメタデータが用意されています。
metaDataList ┣ contextPath (name=/entity) (1) ┣ contextPath (name=/property/select) (1) ┣ contextPath (name=/template) ※ 帳票出力機能と管理トップ画面 (1) ┣ contextPath (name=/view/calendar) (1) ┣ contextPath (name=/view/generic) (1) ┣ contextPath (name=/view/menu/item) (1) ┣ contextPath (name=/view/menu/tree) (1) ┣ contextPath (name=/view/top) (1) ┣ contextPath (name=/view/treeview) (1) ┣ contextPath (name=/view/filter) (1) ┗ contextPath (name=/template) (2)
1 Admin Consoleで作成したメタデータ定義です。Packaging機能もしくはMetaDataExplorer機能を利用することでエクスポートしたものです。 2 Templateのメタデータ定義は手で作成しています。
※ 帳票出力機能と管理トップ画面のTemplate定義はAdmin Consoleで作成し、エクスポートしてます。手で作成したTemplate定義の例。
----------------------------------------以上略---------------------------------------- <contextPath name="/template"> <!-- エラー画面 --> <metaDataEntry> <metaData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="metaJspTemplate"> <name>samples/ec01/error/loginError</name> <displayName>認証エラー画面</displayName> <path>/jsp/samples/ec01/error/genericError.jsp</path> <layoutId>/action/samples/ec01/layout/defaultLayout</layoutId> <contentType>text/html; charset=utf-8</contentType> </metaData> </metaDataEntry> ----------------------------------------以下略----------------------------------------
5.2. メッセージファイル
-
JSPテンプレートで特定のResourceBundleに定義された文字列を取得することが出来るので、言語別にプロパティファイルを作成することで多言語利用が可能です。
ファイル名
iplass-wtp-messages_ja.properties
samples.ec01.all.breadcrumb.home = ホーム samples.ec01.all.pagination.next = 次へ samples.ec01.all.pagination.prev = 前へ samples.ec01.all.yen = 円 samples.ec01.backoffice.stockUpdate.doUpdate = 一括更新 samples.ec01.backoffice.stockUpdate.product = 商品名 samples.ec01.backoffice.stockUpdate.stock = 在庫数 samples.ec01.backoffice.stockUpdate.title = 在庫一括更新 samples.ec01.cart.info.checkOut = お会計 samples.ec01.cart.info.emptyMsg.p1 = カートが空になっています。 ----------------------------------------以下略----------------------------------------
ファイル名
iplass-wtp-messages_en.properties
samples.ec01.all.breadcrumb.home = Home samples.ec01.all.pagination.next = Next samples.ec01.all.pagination.prev = Prev samples.ec01.all.yen = Yen samples.ec01.backoffice.stockUpdate.doUpdate = Bulk update samples.ec01.backoffice.stockUpdate.product = Product name samples.ec01.backoffice.stockUpdate.stock = Stock samples.ec01.backoffice.stockUpdate.title = Stock bulk update samples.ec01.cart.info.checkOut = Check out samples.ec01.cart.info.emptyMsg.p1 = Your cart is currently empty. ----------------------------------------以下略----------------------------------------
5.3. Bean Validationエラーメッセージ
-
言語別にプロパティファイルを作成することで多言語利用が可能です。
ファイル名
/src/main/resources/ValidationMessages_ja.properties
samples.ec01.bean.validation.Tel.invalidChar = 「数字」および「-」のみ利用可能です。(1) samples.ec01.bean.validation.UserId.invalidChar = 「英数字」および「-」(ハイフン)「@」「_」「.」(ピリオド)のみ利用可能です。 samples.ec01.bean.validation.UserId.outOfLength = ユーザーIDは{min}文字以上{max}文字以下です (2) samples.ec01.bean.validation.isBlank = 値を入力してください。 samples.ec01.bean.validation.notKana = 全角カタカナを入力してください。 ......
ファイル名
/src/main/resources/ValidationMessages_en.properties
samples.ec01.bean.validation.Tel.invalidChar = Please enter alphanumeric characters or "-"(hypen) . (1) samples.ec01.bean.validation.UserId.invalidChar = Please enter alphanumeric characters or "-"(hypen), "@", "_"(underscore), "."(dot) . samples.ec01.bean.validation.UserId.outOfLength = User ID must be in range between {min} and {max} characters. (2) samples.ec01.bean.validation.isBlank = Please enter value. samples.ec01.bean.validation.notKana = Please enter Katakana. ......
1 多言語を利用するので、英語と日本語のバリデーションエラーメッセージを用意しています。 2 メッセージにパラメーターの利用が可能です。
6. テストコード
-
プロジェクトの
src/test/
フォルダを開き、以下の構成になっています。src.test ┣ java ┃ ┗ samples.ec01.test.command (1) ┃ ┣ inquiry ┃ ┃ ┗ RegistInquiryCommandTest.java ┃ ┗ TopCommandTest.java ┗ resources (2) ┣ mtptest.properties ┗ test-mtp-service-config.xml
1 テストクラス 2 テストクラス実行用の設定ファイル -
テストクラス
パッケージ クラス名 samples.ec01.test.command
TopComamnd.java
samples.ec01.test.command.inquiry
RegistInquiryCommandTest.java
-
テスト実行用の設定ファイル
ファイル名
/src/test/resources/mtptest.properties
configFileName=/test-mtp-service-config.xml (1) rollbackTransaction=true (2) tenantName= (3) userId= (4) password= (5)
1 テスト実行用のデータベース接続とメタデータ定義が記述されたファイル 2 トランザクションロールバックの設定 3 テストを実行するテナント 4 テストを実行するユーザー 5 テストを実行するユーザーのパスワード ※ プロパティによる指定以外に、クラスレベルアノテーションとメソッドレベルアノテーションによる指定も可能です。詳しい設定方法は
org.iplass.mtp.test.MTPJUnitTestRule
のJavaDocをご参照ください。ファイル名
/src/test/resources/test-mtp-service-config.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE serviceDefinition> <serviceDefinition> <!-- If use oracle, inherits mtp-service-config-mysql.xml for convenience. --> <!-- <inherits>/mtp-core-service-config-oracle.xml</inherits> --> <inherits>/mtp-web-service-config.xml</inherits> <inherits>/gem-service-config.xml</inherits> <inherits>/mtp-core-service-config-mysql.xml</inherits> <!-- Rdb Connection Settings --> <service> <interface>org.iplass.mtp.impl.rdb.connection.ConnectionFactory</interface> <class>org.iplass.mtp.impl.rdb.connection.DriverManagerConnectionFactory</class> <property name="url" value="jdbc:mysql://[host]:[port]/[schema]" /> (1) <property name="user" value="[user]" /> (2) <property name="password" value="[password]" /> (3) <property name="driver" value="com.mysql.cj.jdbc.Driver" /> </service> <!-- XmlResource MetaData and Annotation MetaData Settings --> <service> <interface>org.iplass.mtp.impl.metadata.MetaDataRepository</interface> <property name="resourcePath" value="/samples-ec01-ce-metadata.xml" additional="true" /> (4) <property name="annotatedClass" value="samples.ec01.command.metadata.CommandList" additional="true"/> (5) </service> </serviceDefinition>
1 テスト実行用のデータベース接続 2 データベース接続ユーザー 3 データベース接続ユーザーのパスワード 4 メタデータの定義ファイル 5 コマンドのメタデータ定義 -
動作確認
-
Gradleでテストコードを実行する場合、プロジェクトのルートパスで以下のコマンドを実行してください。
gradlew test
-
実行結果
:compileJava UP-TO-DATE :processResources UP-TO-DATE :classes UP-TO-DATE :compileTestJava UP-TO-DATE :processTestResources UP-TO-DATE :testClasses UP-TO-DATE :test UP-TO-DATE BUILD SUCCESSFUL Total time: 1.855 secs
-
Eclipseでテストコードを実行する場合、
src.test.java
パッケージを右クリックしてRun as
を選択し、Junit Test
を実行してください。
-