参考( TERASOLUNA Global Framework on Accel Platform アーキテクチャ )¶
TERASOLUNA Global Framework (http://terasoluna.org/) は、Spring Framework (http://projects.spring.io/spring-framework/) をベースに構成されるJavaフレームワークです。TERASOLUNA Global Framework の詳細については TERASOLUNA Global Framework Development Guideline にて公開されています。本項では、 intra-mart Accel Platform と TERASOLUNA Global Framework によるフルスタックフレームワークについて説明します。
TERASOLUNA Global Framework on Accel Platform アーキテクチャ
TERASOLUNA Global Framework on Accel Platform の構成¶
intra-mart Accel Platform 上に TERASOLUNA Global Framework を組み込んだ「フルスタックフレームワーク」のイメージは下図の通りです。
TERASOLUNA Global Framework は、下記の通り、Spring Framework がベースで構成され、トランザクショントークンチェック、コードリスト、例外ハンドリングやロギング等の機能を提供し、その活用方法を「 TERASOLUNA Global Framework Development Guideline 」として提供しています。
アプリケーション層 Spring MVC / Bean Validation ドメイン層 Spring Framework インフラストラクチャ層 Spring Data JPA (Hibernate) / MyBatis TERASOLUNA Global Framework on Accel Platform では、intra-mart Accel Platform が提供する以下の機能を利用して、TERASOLUNA Global Framework のアプリケーションを効率よく開発することができます。
- 認可
- アクセスコンテキスト
- 認証機能
- 国際化
- データベース
- ログ
- UI(デザインガイドライン)
- UI(スマートフォン開発ガイドライン)
- エラー処理
- Storage
- 非同期処理
- ジョブスケジューラ
- Lockサービス
- Cacheサービス
- ショートカットアクセス機能
- ポートレット
- IM-Workflow (準備中)
- etc...
コラム
intra-mart Accel Platform が提供する各機能の使い方については上記リンクより参照にしてください。
TERASOLUNA Global Framework との対応¶
TERASOLUNA Global Framework Development Guideline で想定している TERASOLUNA Global Framework のアーキテクチャの TERASOLUNA Global Framework on Accel Platform 上での対応は以下の通りです。
機能 対応 備考 データアクセス(共通編) シンプルなCRUD操作で動作確認を行っております。 データアクセス(JPA編) シンプルなCRUD操作で動作確認を行っております。 データアクセス(Mybatis2編) シンプルなCRUD操作で動作確認を行っております。 排他制御 入力チェック ロギング Logger, MDCは intra-mart Accel Platform のものを使用してください。 また、 ログ を参照してください。 TraceLoggingInterceptor, ExceptionLoggerについては、 TERASOLUNA Global Framework Development Guideline を参照してください。 例外ハンドリング セッション管理 Spring Securityを使うものについては対象外です。 メッセージ管理 IntramartMessageSource を使用してください。 また、 多言語化されたメッセージを取得する を参照してください。 プロパティ管理 ページネーション imuiTableを使用してください。 二重送信防止 国際化 IntramartMessageSource, AccountLocaleResolverを使用してください。 また、 国際化 を参照してください。 コードリスト Bean定義 applicationContext-im_tgfw_web.xml にコードリストの設定を記述しています。 <mvc:mapping>のpath属性は、適用対象のパスを設定してください。 Ajax ファイルアップロード Servlet 3.0の機能は非対応です。 multipartResolverにはCommonsMultipartResolverを設定しています。 また、 Storage を参照してください。 ファイルダウンロード Storage を参照してください。 Tiles intra-mart Accel Platform のテーマ機能を使用してください。 システム時刻 org.terasoluna.gfw.common.date.JdbcAdjustedDateFactory を使用する場合、 dataSourceプロパティにはシェアードデータソースを指定してください。 シェアードデータソースの設定は、 DataSource や Spring Data JPAを使用したプログラミング方法 、 MyBatisを使用したプログラミング方法 を参照してください。 ユーティリティ(dozer) ユーティリティ(joda time) joda-timeのjarは %RESIN_HOME%/lib に配置してください。 TERASOLUNA Global Framework Development Guideline に記載されている TERASOLUNA Global Framework のセキュリティ対策についての TERASOLUNA Global Framework on Accel Platform 上での対応は以下の通りです。
セキュリティ対策 対応 備考 Spring Security (認証、パスワードハッシュ化、認可) 認証、パスワードハッシュ化、認可機能については、 intra-mart Accel Platform の認証、認可を使用してください。 intra-mart Accel Platform でもパスワードのハッシュ化を行っています。 XSS対策 CSRF対策 intra-mart Accel Platform のimSecureToken タグを使用してください。
TERASOLUNA Global Framework on Accel Platform におけるBean定義の既定値¶
Spring MVC では、DispatcherServlet というサーブレットクラスが提供されています。DispatcherServletは、クライアントからの要求に対して、要求情報からコントローラを探し、コントローラを呼び出す役割を担います。intra-mart Accel Platform では、クライアントからの要求に対して、該当するプログラムを探し、認可のチェックをし、見つかったプログラムを呼び出す「ルーティング機構」があります。intra-mart Accel Platform では、この「ルーティング機構」からSpring MVCのコントローラを呼び出す機構が組み込まれています。コラム
「ルーティング機構」の仕組みについては、「認可」ページを参考にしてください。Spring MVCでは通常、1つのWebアプリケーションに複数のDispatcherServletを登録し、サーブレットごとにBean定義を行うことができますが、intra-mart Accel Platform では、DispatcherServletを拡張したサーブレットクラスが1つだけ登録されており、このサーブレットクラスを複数登録することはできません。そのため、intra-mart Accel Platform ではすべてのBean定義はWebアプリケーション上で共有されることになります。intra-mart Accel Platform では、あらかじめ下記ファイルにてBean定義が行われています。
- <Jugglingプロジェクト>/classes/META-INF/spring/applicationContext-im_tgfw_common.xml
- <Jugglingプロジェクト>/classes/META-INF/spring/applicationContext-im_tgfw_web.xml
- <Jugglingプロジェクト>/classes/META-INF/spring/SpringMVCServlet-servlet.xml
- <Jugglingプロジェクト>/classes/META-INF/spring/applicationContext-jpa.xml
- <Jugglingプロジェクト>/classes/META-INF/spring/applicationContext-mybatis.xml
これらのBean定義は、intra-mart Accel Platform のテナント上で共有されるため、セットアップガイドに記載のない内容以外は基本変更しないようにしてください。以下、intra-mart Accel Platform へのSpring MVCの組込み内容と上記Bean定義ファイルの初期値について示します。
web.xml¶
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" metadata-complete="false" version="3.0" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> : (省略) <!-- Web アプリケーション起動時に、クラスパス上の/META-INF/spring/内のapplicationContextで始まるBean定義ファイルをロード させる設定--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:/META-INF/spring/applicationContext*.xml</param-value> </context-param> <listener> <listener-class>jp.co.intra_mart.framework.extension.spring.web.servlet.SpringServletContextListener</listener-class> </listener> : (省略) <!-- 「ルーティング機構」用にDispatcherServletを拡張したサーブレットを登録 --> <servlet> <servlet-name>SpringMVCServlet</servlet-name> <servlet-class>jp.co.intra_mart.framework.extension.spring.web.servlet.IntramartDispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/META-INF/spring/SpringMVCServlet-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> <multipart-config/> </servlet> : (省略) </web-app>
applicationContext-im_tgfw_common.xml¶
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- a bean which holds the root application context --> <bean class="jp.co.intra_mart.system.extension.spring.context.ApplicationContextHolder" /> <!-- message source which loads from 'WEB-INF/conf/message/**/*.properties' --> <bean id="messageSource" class="jp.co.intra_mart.framework.extension.spring.message.IntramartMessageSource" /> <!-- bean validation (JSR-303) --> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <property name="validationMessageSource" ref="messageSource" /> </bean> <!-- transaction manager (JTA) --> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" /> <!-- enable the configuration of transactional behavior based on annotations --> <tx:annotation-driven transaction-manager="transactionManager"/> <!-- intra-mart tenant datasource --> <bean id="dataSource" class="jp.co.intra_mart.framework.extension.spring.datasource.TenantDataSource" /> <!-- intra-mart shared datasource --> <!-- [Note] If you use the shared datasource, please uncomment/enable the following setting and set the bean's id and the connectId's value. --> <!-- <bean id="sharedDataSource" class="jp.co.intra_mart.framework.extension.spring.datasource.SharedDataSource"> <constructor-arg name="connectId" value="xxxxxxxxxxxxxx" /> </bean> --> <!-- property placeholder setting --> <context:property-placeholder location="classpath*:/META-INF/spring/*.properties" /> <!-- dozer setting --> <bean class="org.dozer.spring.DozerBeanMapperFactoryBean"> <property name="mappingFiles" value="classpath*:/META-INF/dozer/**/*-mapping.xml" /> </bean> <!-- Exception Code Resolver. --> <bean id="exceptionCodeResolver" class="org.terasoluna.gfw.common.exception.SimpleMappingExceptionCodeResolver"> <!-- Setting and Customization by project. --> <property name="exceptionMappings"> <map> <entry key="ResourceNotFoundException" value="w.im.fw.0001" /> <entry key="BusinessException" value="w.im.fw.0002" /> <entry key="InvalidTransactionTokenException" value="w.im.fw.0004" /> </map> </property> <property name="defaultExceptionCode" value="e.im.fw.0001" /> </bean> <!-- Exception Logger. --> <bean id="exceptionLogger" class="org.terasoluna.gfw.common.exception.ExceptionLogger"> <property name="exceptionCodeResolver" ref="exceptionCodeResolver" /> </bean> </beans>
applicationContext-im_tgfw_web.xml¶
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- locale resolver --> <bean id="localeResolver" class="jp.co.intra_mart.framework.extension.spring.web.servlet.i18n.AccountLocaleResolver" /> <!-- SpringMVCRoute needs HandlerSelector bean. --> <bean id="handlerSelector" class="jp.co.intra_mart.system.router.spring.HandlerSelector" init-method="init" /> <!-- view components --> <context:component-scan base-package="jp.co.intra_mart.framework.extension.spring.web.servlet.view" /> <bean class="org.springframework.web.servlet.view.BeanNameViewResolver"> <property name="order" value="0" /> </bean> <!-- prefix for InternalResourceViewResolver --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/" /> <property name="order" value="1" /> </bean> <!-- multipart resolver --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" /> <!-- support for annotation-driven MVC controllers --> <mvc:annotation-driven conversion-service="conversionService"> <!-- transaction token --> <mvc:argument-resolvers> <bean class="org.terasoluna.gfw.web.token.transaction.TransactionTokenContextHandlerMethodArgumentResolver" /> </mvc:argument-resolvers> <!-- jackson message converter --> <mvc:message-converters register-defaults="true"> <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"> <property name="objectMapper"> <bean class="jp.co.intra_mart.framework.extension.spring.http.converter.json.AccountDateObjectMapper" /> </property> </bean> </mvc:message-converters> </mvc:annotation-driven> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="formatters"> <set> <bean class="jp.co.intra_mart.framework.extension.spring.format.datetime.AccountDateFormatAnnotationFormatterFactory"/> <bean class="jp.co.intra_mart.framework.extension.spring.format.datetime.AccountDateTimeFormatAnnotationFormatterFactory"/> <bean class="jp.co.intra_mart.framework.extension.spring.format.datetime.AccountTimeFormatAnnotationFormatterFactory"/> </set> </property> </bean> <!-- MVC interceptors --> <mvc:interceptors> <!-- transaction token --> <mvc:interceptor> <mvc:mapping path="/**" /> <!-- configure the path to specify the package of controllers. --> <bean class="org.terasoluna.gfw.web.token.transaction.TransactionTokenInterceptor"> <constructor-arg value="10" /> </bean> </mvc:interceptor> <!-- code list --> <mvc:interceptor> <mvc:mapping path="/**" /> <!-- configure the path to specify the package of controllers. --> <bean class="org.terasoluna.gfw.web.codelist.CodeListInterceptor"> <property name="codeListIdPattern" value="CL_.+" /> </bean> </mvc:interceptor> <!-- [Note] If you use the JPA, please uncomment/enable the following setting. Please see the following link for more detail. > http://static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/orm/jpa/support/OpenEntityManagerInViewInterceptor.html [Note] configure the path to specify the package of controllers. --> <!-- <mvc:interceptor> <mvc:mapping path="/**" /> <bean class="org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor" /> </mvc:interceptor> --> </mvc:interceptors> <!-- transaction token --> <bean name="requestDataValueProcessor" class="org.terasoluna.gfw.web.mvc.support.CompositeRequestDataValueProcessor"> <constructor-arg> <util:list> <bean class="org.terasoluna.gfw.web.token.transaction.TransactionTokenRequestDataValueProcessor" /> </util:list> </constructor-arg> </bean> <!-- Setting Exception Handling. --> <!-- Exception Resolver. --> <bean class="org.terasoluna.gfw.web.exception.SystemExceptionResolver"> <property name="exceptionCodeResolver" ref="exceptionCodeResolver" /> <!-- Setting and Customization by project. --> <property name="order" value="3" /> <property name="exceptionMappings"> <map> <entry key="ResourceNotFoundException" value="im_tgfw/common/error/resourceNotFoundError.jsp" /> <entry key="BusinessException" value="im_tgfw/common/error/businessError.jsp" /> <entry key="InvalidTransactionTokenException" value="im_tgfw/common/error/transactionTokenError.jsp" /> </map> </property> <property name="statusCodes"> <map> <entry key="im_tgfw/common/error/resourceNotFoundError" value="404" /> <entry key="im_tgfw/common/error/businessError" value="200" /> <entry key="im_tgfw/common/error/transactionTokenError" value="409" /> </map> </property> <property name="defaultErrorView" value="im_tgfw/common/error/systemError.jsp" /> <property name="defaultStatusCode" value="500" /> </bean> <!-- AOP. --> <bean id="handlerExceptionResolverLoggingInterceptor" class="org.terasoluna.gfw.web.exception.HandlerExceptionResolverLoggingInterceptor"> <property name="exceptionLogger" ref="exceptionLogger" /> </bean> <aop:config> <aop:advisor advice-ref="handlerExceptionResolverLoggingInterceptor" pointcut="execution(* org.springframework.web.servlet.HandlerExceptionResolver.resolveException(..))" /> </aop:config> </beans>
SpringMVCServlet-servlet.xml¶
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> </beans>
applicationContext-jpa.xml¶
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd" > <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="showSql" value="false" /> <property name="database"> <value>POSTGRESQL</value> <!-- <value>DB2</value> <value>DEFAULT</value> <value>HSQL</value> <value>INFORMIX</value> <value>MYSQL</value> <value>ORACLE</value> <value>POSTGRESQL</value> <value>SQL_SERVER</value> <value>SYBASE</value> --> </property> </bean> <util:map id="hibernateProperties"> <entry key="hibernate.hbm2ddl.auto" value="none" /> <entry key="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" /> <entry key="hibernate.connection.charSet" value="UTF-8" /> <entry key="hibernate.show_sql" value="false" /> <entry key="hibernate.format_sql" value="false" /> <entry key="hibernate.use_sql_comments" value="true" /> <entry key="hibernate.jdbc.batch_size" value="30" /> <entry key="hibernate.jdbc.fetch_size" value="100" /> <entry key="hibernate.temp.use_jdbc_metadata_defaults" value="false" /> <entry key="hibernate.transaction.jta.platform"> <value>org.hibernate.service.jta.platform.internal.ResinJtaPlatform</value> <!-- <value>org.hibernate.service.jta.platform.internal.ResinJtaPlatform</value> <value>org.hibernate.service.jta.platform.internal.WeblogicJtaPlatform</value> <value>org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform</value> --> </entry> </util:map> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="packagesToScan" value="jp.co.intra_mart.framework.extension.spring.entity" /> <property name="jtaDataSource" ref="dataSource" /> <property name="jpaVendorAdapter" ref="jpaVendorAdapter" /> <property name="jpaPropertyMap" ref="hibernateProperties" /> <property name="persistenceUnitName" value="tenant" /> </bean> <!-- <bean id="sharedEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="packagesToScan" value="jp.co.intra_mart.framework.extension.spring.entity" /> <property name="jtaDataSource" ref="sharedDataSource" /> <property name="jpaVendorAdapter" ref="jpaVendorAdapter" /> <property name="jpaPropertyMap" ref="hibernateProperties" /> <property name="persistenceUnitName" value="shared" /> </bean> --> </beans>
applicationContext-mybatis.xml¶
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean" scope="singleton"> <property name="configLocations" value="classpath*:/META-INF/mybatis/config/*sqlMapConfig.xml" /> <property name="mappingLocations" value="classpath*:/META-INF/mybatis/sql/**/*-sqlmap.xml" /> <property name="dataSource" ref="dataSource" /> </bean> <bean id="queryDAO" class="jp.terasoluna.fw.dao.ibatis.QueryDAOiBatisImpl"> <property name="sqlMapClient" ref="sqlMapClient" /> </bean> <bean id="updateDAO" class="jp.terasoluna.fw.dao.ibatis.UpdateDAOiBatisImpl"> <property name="sqlMapClient" ref="sqlMapClient" /> </bean> <bean id="spDAO" class="jp.terasoluna.fw.dao.ibatis.StoredProcedureDAOiBatisImpl"> <property name="sqlMapClient" ref="sqlMapClient" /> </bean> <bean id="queryRowHandleDAO" class="jp.terasoluna.fw.dao.ibatis.QueryRowHandleDAOiBatisImpl"> <property name="sqlMapClient" ref="sqlMapClient" /> </bean> <!-- <bean id="sharedSqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean" scope="singleton"> <property name="configLocations" value="classpath*:/META-INF/mybatis/config/*sqlMapConfig.xml" /> <property name="mappingLocations" value="classpath*:/META-INF/mybatis/sql/**/*-sqlmap.xml" /> <property name="dataSource" ref="sharedDataSource" /> </bean> <bean id="sharedQueryDAO" class="jp.terasoluna.fw.dao.ibatis.QueryDAOiBatisImpl"> <property name="sqlMapClient" ref="sharedSqlMapClient" /> </bean> <bean id="sharedUpdateDAO" class="jp.terasoluna.fw.dao.ibatis.UpdateDAOiBatisImpl"> <property name="sqlMapClient" ref="sharedSqlMapClient" /> </bean> <bean id="sharedSpDAO" class="jp.terasoluna.fw.dao.ibatis.StoredProcedureDAOiBatisImpl"> <property name="sqlMapClient" ref="sharedSqlMapClient" /> </bean> <bean id="sharedQueryRowHandleDAO" class="jp.terasoluna.fw.dao.ibatis.QueryRowHandleDAOiBatisImpl"> <property name="sqlMapClient" ref="sharedSqlMapClient" /> </bean> --> </beans>