| 名前: | 土居俊彦(どいとしひこ) |
| メール: | t-doi@ohns.co.jp |
| 勤務先: | 沖縄日立ネットワークシステムズ(株) http://www.ohns.co.jp 沖縄県内では唯一の日立系ソフトウェア会社。 |
今日の講義では、大まかに以下の3点について講義を行います。
StrutsはWebアプリケーションの画面制御のためのフレームワークです。Seasar2は今日は本来の利用方法とは 異なりますが、DBアクセスのためのフレームワークとしての利用方法を解説します。
また、課題として問題1から問題10を用意しています。課題の回答はメールにてt-doi@ohns.co.jp まで送付してください。 提出形式はtext、PDFなどでかまいません。
Framework 和英辞典では、「体制、組織、フレームワーク、骨組み、枠組み」と訳されています。
(ソフトウェア開発における)フレームワークとは、様々なシステム開発で毎回必要になるような処理を提供するものです。 各システムの土台やひな形として機能します。 土台やひな形となる部分を用意することで、各システム開発では独自に必要な部分のみを提供すれば良く、ミス(バグ)の低減、開発効率の 向上が見込めます。
各システム開発では、そのシステム毎に独自に作成しなくてはいけないものと、各システムで共通しているものがあります。 各システムで共通している処理を毎回作成していると、保守性が悪い、工数(お金)の無駄、ミス(バグ)を新たに作り込んでしまうと言った 問題があります。
有名な言葉があります。「Don't call me! I call you.」(呼び出すんじゃねぇ!俺がお前を呼ぶから)
フレームワークを使わない開発では、大抵なんらかのライブラリを使用します。
ライブラリを使用したプログラミングモデルは、我々プログラム作成者が各ライブラリの機能を呼び出して処理を行います。
授業で何らかのプログラムを作った事があると思います。たとえば、C言語でプログラムを作る場合、mainから始まる一連の処理の流れを作成したと思います。
一方、フレームワークを使った開発では、基本的な処理の制御はフレームワークが行います。我々プログラム作成者は、フレームワーク
によって呼び出される処理の一部を作成することになります。
※もちろん、作成する処理の一部の中で、ライブラリを呼び出す事もあります。
デザインパターンという言葉を聞いた事がありますか?デザインパターンとは、ソフトウェアの設計&製造時に現れる似た解決方法(パターンを)
カタログとして集めておきます。問題が発生した場合に、このカタログより解決方法(パターン)を探し出します。
アーキテクチャパターンという言葉があります。デザインパターンが主に設計/製造時の問題を扱うのに対し、アーキテクチャパターンは
アプリケーションの基本構造に関する問題を扱います。
たいていのフレームワークは、何らかのアーキテクチャパターンの構造になっています。たとえば、これから皆さんが学習するStrutsと
言うフレームワークは、MVC(MVC2)パターン(モデル)を実装しています。
MVCパターン(モデル)以外に、どのようなアーキテクチャパターンがあるか調べよ。
モデル(Model)、ビュー(View)、コントローラ(Controller)の頭文字をとったパターンの事です。アプリケーションを モデル、ビュー、コントローラの構成により構築します。モデル、ビュー、コントローラはそれぞれ、 アプリケーションの状態、画面の表示、制御フローに相当します。
モデルは、開発するアプリケーションのデータに相当します。これにはビジネスロジックも含まれます。 モデルは、ビューにもコントローラにも依存しません。
ビューは、モデルをどのようにユーザに見せるのか?を担当します。1つのモデルを1つのビューで見せるだけとは限りません。 たとえば、あるモデルをHTMLで表示することもあれば、JavaのSwingアプリケーションで表示することもあるでしょう。 ビューはモデルに依存します。
コントローラは、ビューからの入力値をモデルに渡します。 コントローラはビュー、モデルに依存します。
もともとSmalltalkと言うオブジェクト指向言語でのアプリケーション開発にてもちいられました。 機能をモデル、ビュー、コントローラの各コンポーネントに分割することで事で、役割を明確にし、保守性、再利用性を向上させること ができます。
従来のMVCパターン(モデル)は、Windowsアプリケーションの開発等でもちいられていました。モデルでの変更通知をモデル自身が そのモデルを参照しているViewに対して行うことで、Viewの描画が行われていました。(Observerパターン) しかし、Webアプリケーションでは、クライアントのアクションなしに、サーバー側からクライアントに対してデータを送付することができません。 そのため、Webアプリケーションで採用しているパターン(J2EEパターン)では、コントローラにてモデルの変更をビューに対して通知する MVCパターン(モデル)2と言われるパターンが採用されています。
一般的にはWindowsアプリケーション等で採用されているのがMVCモデル、Webアプリケーションで採用されているのがMVCモデル2と考えれば 良いと思います。(これに関しては諸説ある。)
MVCパターンとObserverの関係について調べよ。
Java向けのWebアプリケーションフレームワークの事です。Apache Software Foundationにより管理/開発されています。 アーキテクチャとして、MVCモデル2が採用されています。
StrutsはJSP/HTML、ActionServlet、ActionForm、Action、struts-config.xmlにより構成されます。 JSP/HTMLから送信されたデータはActionServletが受け取ります。ActionServletはリクエストを受け取ると、 そのリクエストのURIより実行すべきActionを決定します。 Actionは入力内容を検証したり、データベースへのアクセスと言った処理を行います。 ActionFormはActionが実行されるときに引数として渡されます。 ActionFormにはJSP/HTMLから送信されたデータが設定されます。 URIによりAction、ActionFormが決定されますが、これらを決定するための情報はstruts-config.xmlにて定義します。
実はStrutsは、MVCパターンのうち、VとC、ビューとコントローラのみしか扱いません。たいていの場合、モデルへのアクセスはデータベース上のデータを操作する 事になります。これについては、Seasarの所で説明します。
Javaの講義でも解説があったと思いますが、もう一度おさらいです。JavaのWebApplicationの構成は 規約により決められています。以下のような構成になります。
JavaWebApplicationの配備記述はweb.xmlに行うことが決められています。web.xmlの記述を元に、 Tomcatなどのサーブレットコンテナ(サーブレットを動かすアプリケーション)はアプリケーションの ロードと構成を行います。
Strutsを利用する場合、このweb.xmlにStrutsを利用するための定義を記述する必要があります。 具体的には、ActionServlet、Servlet-mappingの定義を追記します。
<?xml version="1.0" encoding="Shift_JIS"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<display-name>Struts Application</display-name>
<!-- Seaser2初期化のためのサーブレット -->
<servlet>
<servlet-name>s2container</servlet-name>
<servlet-class>org.seasar.framework.container.servlet.S2ContainerServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- ActionServletの定義 -->
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>2</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>s2container</servlet-name>
<url-pattern>/s2container</url-pattern>
</servlet-mapping>
<!-- .doで終わるURIをStrutsのアクションとする -->
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- Strutsで使用するタグライブラリの定義 -->
<taglib>
<taglib-uri>/tags/struts-bean</taglib-uri>
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/tags/struts-html</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/tags/struts-logic</taglib-uri>
<taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/tags/struts-nested</taglib-uri>
<taglib-location>/WEB-INF/struts-nested.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/tags/struts-tiles</taglib-uri>
<taglib-location>/WEB-INF/struts-tiles.tld</taglib-location>
</taglib>
</web-app>
ActionFormは、org.apache.struts.action.ActionFormを継承して作成します。ActionFormには、JSP/HTMLより送信されたパラメータ と一致するSetter/Getterメソッドおよびフィールドを定義します。
package ospi_sample.form;
import org.apache.struts.action.ActionForm;
public class LogonForm extends ActionForm {
private String userid;
private String passwd;
public String getPasswd() {
return passwd;
}
public void setPasswd(String passwd) {
this.passwd = passwd;
}
public String getUserid() {
return userid;
}
public void setUserid(String userid) {
this.userid = userid;
}
}
入力値の検証は、ActionFormにて行うか、validation.xmlに検証内容を記述することで行います。 ここでは、validation.xmlに記述する方法を紹介します。
validation.xmlには、検証したいActionFormを記述します。アクションフォームのフィールド毎に どのような検証を行うかを記述します。ここで指定するActionFormはstruts-config.xml(後述)にて指定した フォーム名です。
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE form-validation PUBLIC
"-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.2.0//EN"
"http://jakarta.apache.org/commons/dtds/validator_1_2_0.dtd">
<form-validation>
<!--
This is a minimal Validator form file with a couple of examples.
-->
<global>
</global>
<formset>
<form name="logonForm">
<field
property="userid"
depends="required">
<arg key="logonForm.userid"/>
</field>
<field
property="passwd"
depends="required,mask">
<arg key="logonForm.passwd"/>
<var>
<var-name>mask</var-name>
<var-value>^[0-9a-zA-Z]*$</var-value>
</var>
</field>
</form>
</formset>
</form-validation>
Actionは、org.apache.struts.action.Actionを継承して作成します。Actionには、入力の検証、モデルへのアクセス(データベースアクセス) ActionForwardの決定を行います。ActionForwardの決定とは、遷移先画面を決定することです。
package ospi_sample.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.SingletonS2ContainerFactory;
import ospi_sample.beans.OspiUser;
import ospi_sample.dao.OspiUserDao;
import ospi_sample.form.LogonForm;
public class LogonAction extends Action {
@Override
public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm, HttpServletRequest request, HttpServletResponse response) throws Exception {
//入力値の受け取り
LogonForm logonForm = (LogonForm)actionForm;
//Seasar2のコンテナ取得
S2Container container = SingletonS2ContainerFactory.getContainer();
//DAO(DataAccessObject)の取得
OspiUserDao dao = (OspiUserDao)container.getComponent(OspiUserDao.class);
//ユーザデータの取得
OspiUser user = dao.getUser(logonForm.getUserid());
//パスワードの検証
if (!logonForm.getPasswd().equals(user.getPasswd())) {
ActionMessages messages = new ActionMessages();
messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("errors.logon.invalide"));
saveErrors(request, messages);
//パスワードの検証に失敗
return actionMapping.findForward("retry");
}
//ログインに成功!
return actionMapping.findForward("success");
}
}
struts-config.xmlには、使用するActionForm、URI毎のAction、遷移先を記述します。 Strutsは、struts-config.xmlの定義情報とActionの実行結果により、繊維先画面(JSP/HTML)を決定します。
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">
<struts-config>
<!-- ======================================== Form Bean Definitions -->
<form-beans>
<form-bean
name="logonForm"
type="ospi_sample.form.LogonForm"/>
</form-beans>
<!-- ================================= Global Exception Definitions -->
<global-exceptions>
<exception
key="errors.global.runtime"
type="java.lang.RuntimeException"
path="/jsp/error.jsp" />
</global-exceptions>
<!-- =================================== Global Forward Definitions -->
<global-forwards>
<forward
name="welcome"
path="/index.html"/>
</global-forwards>
<!-- =================================== Action Mapping Definitions -->
<action-mappings>
<action
path="/LogonSubmit"
type="ospi_sample.action.LogonAction"
name="logonForm"
scope="request"
validate="true"
input="/jsp/login_input.jsp">
<forward name="retry" path="/jsp/login_input.jsp" />
<forward name="success" path="/jsp/login_success.jsp" />
</action>
</action-mappings>
<!-- ===================================== Controller Configuration -->
<controller
processorClass="org.apache.struts.action.RequestProcessor"/>
<!-- ================================ Message Resources Definitions -->
<message-resources parameter="application"/>
<!-- ======================================= Plug Ins Configuration -->
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property
property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>
</struts-config>
Strutsで出力するエラーメッセージなどは、application.propertiesに記述します。 実は、このファイル名は任意で、struts-config.xmlで指定することが可能です。
# -- standard errors --
errors.header=<UL>
errors.prefix=<LI>
errors.suffix=</LI>
errors.footer=</UL>
# -- validator --
errors.invalid={0} is invalid.
errors.maxlength={0} can not be greater than {1} characters.
errors.minlength={0} can not be less than {1} characters.
errors.range={0} is not in the range {1} through {2}.
errors.required={0} is required.
errors.byte={0} must be an byte.
errors.date={0} is not a date.
errors.double={0} must be an double.
errors.float={0} must be an float.
errors.integer={0} must be an integer.
errors.long={0} must be an long.
errors.short={0} must be an short.
errors.creditcard={0} is not a valid credit card number.
errors.email={0} is an invalid e-mail address.
errors.url={0} is an invalid url (web address).
errors.minbytelength={0} can not be less than {1} bytes.
errors.maxbytelength={0} can not be greater than {1} bytes.
# -- other --
errors.cancel=Operation cancelled.
errors.detail={0}
errors.general=The process did not complete. Details should follow.
errors.token=Request could not be completed. Operation is not in sequence.
# -- business --
errors.bad.criteria=Corresponding data to the retrieval condition is not found
errors.employee.exist=Employee({0}) already exist
# -- exception --
errors.global.runtime=System error.
errors.logon.invalide=Logon error.
######
# -- other --
#
#
# -- welcome --
#
welcome.title=Struts Blank Application
welcome.heading=Welcome!
welcome.message=To get started on your own application, copy the struts-blank.war to a new WAR file using the name for your application. Place it in your container's "webapp" folder (or equivalent), and let your container auto-deploy the application. Edit the skeleton configuration files as needed, restart your container, and you are on your way! (You can find the application.properties file with this message in the /WEB-INF/src/java/resources folder.)
sample.title=S2Struts Sample Calculate Application
mod.title=S2Struts Mod Application
add.title=S2Struts Add Application
subtract.title=S2Struts Subtract Application
multiply.title=S2Struts Multiply Application
divide.title=S2Struts Divide Application
echo.title=S2Struts Echo Application
changeCase.title=S2Struts ChangeCase Application
calc=calculate
result.title=S2Struts Application Result
result=result
echo=echo
toUpperCase=toUpperCase
toLowerCase=toLowerCase
system.back=back
system.error=error
#
# -- button --
#
button.prev=previous
button.next=next
button.create=create
button.search=search
button.edit=edit
button.delete=delete
button.inquire=inquire
button.confirm=confirm
button.store=store
button.back=back
#
# -- form --
#
struts-config.xmlの要素を調べよ。
Struts Tilesとは何か?その役割、使用方法を答えよ。
Strutsではさまざまな標準Actionが提供されている。どのような標準Actionが存在するか調べよ。
DI(Dependency Injection)とAOP(Aspect Oriented Programming)をサポートした軽量コンテナ。 沖縄県出身の「ひがやすを」氏を中心に開発が行われている国産のフレームワークです。
Dpendency Injection(依存性注入)とはオブジェクトのインスタンスの生成および設定を自動的に行ってくれる ソフトウェアの事でありまた、設計思想でもあります。
Javaではオブジェクトの生成をnewによって行いますが、DIコンテナは、例えばXMLの定義 情報を元に、インスタンスの生成および設定を自動的に行ってくれます。
また、DIは、以前はIoC(Inversion of Control)、制御の逆転などとも呼ばれていました。これは、 処理の制御事態はDIコンテナにて行い、我々利用社が実装するのは、各コンポーネントで良いと言うことです。 フレームワークの説明でもふれましたが、「Don't call me! I call you.」 (呼び出すんじゃねぇ!俺がお前を呼ぶから) と言う事と同じです。
Seasar2以外にどのようなDIコンテナが存在するか調べよ。
Aspect Oriented Programming。オブジェクト指向の登場によって、オブジェクトの継承を利用して 処理の共通化が行えるようになりました。しかし、継承関係のを越えた共通処理をどのようにして 記述するか?と言う問題が残りました。(横断的関心事[Cross-Cutting Concerns])
AOPでは、散らばる共通処理を1カ所で定義しておき、コンパイル時やDIコンテナによるオブジェクト生成時に 処理を埋め込む事を可能にします。
散らばる共通処理とは、例えば以下のような物があります。
Seasar2以外にどのようなAspectシステムが存在するか調べよ。
Javaでは、長らく、J2EEと言う規格に沿ってアプリケーション開発が行われてきました。J2EEでは、JSP、Servlet 、EJB(Enterprise JavaBeans)などが規定されています。
データベースへのアクセスはパフォーマンスや再利用性の観点から、JDBC(Java DataBase Connectivity)を利用するのではなく、 このEJBを利用することが多かったのですが、EJBを利用するためには複雑な実装、複雑な定義、アプリケーションサーバ が必要でした。
EJBに対するアンチテーゼとして、IoC、DIと言った考えたが出現してきました。
Seasarを利用した開発では、アプリケーションサーバなど特殊な環境が必要ありません。また、実装もPOJO(Plain Old Java Object) であれば良く、余計な継承など必要ありません。定義ファイルについても、diconと呼ばれるファイルを記述する必要がありますが、 規約により、diconファイルの記述を極力行わなくても良い工夫がなされています。
Seasarでは、管理するクラスやオブジェクトをコンポーネント(Component)と呼びます。 dicon(ダイコン)と呼ばれるファイルに、管理するコンポーネントの情報を記述します。
<?xml version="1.0" encoding="Shift_JIS"?> <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN" "http://www.seasar.org/dtd/components21.dtd"> <components> <include path="dao.dicon"/> <component class="ospi_sample.dao.OspiUserDao"> <aspect>dao.interceptor</aspect> </component> </components>
diconファイルにどのような要素があるか調べよ。
Seasarのサブプロジェクトで、O/RMapper(オブジェクトとリレーショナルデータベースのマッピングを行う) の一種です。DTO(Data Transfer Object)としてのJavaBeansとDAO(Data Access Object)としてのインターフェイス を定義するだけで、データベースへのアクセスが容易に行えるようになります。
まず、データベースのレコードと対応するJavaBeanを容易します。JavaBeansには、定数にて アノテーション(注釈、付加情報)を記述する事で、データベースのどのテーブル、カラムと 対応するのかを記述します。このアノテーションは定数以外にもJ2SE5.0から採用された、Javaの アノテーションにて記述することもできます。
JavaBeansは慣例としてjava.io.Serializableをimplementsする事となっていますので注意してください。
package ospi_sample.beans;
import java.io.Serializable;
public class OspiUser implements Serializable{
/** S2Dao */
public static final String TABLE = "ospi_user";
public static final String userid_COLUMN = "userid";
public static final String passwd_COLUMN = "passwd";
private String userid;
private String passwd;
public String getPasswd() {
return passwd;
}
public void setPasswd(String passwd) {
this.passwd = passwd;
}
public String getUserid() {
return userid;
}
public void setUserid(String userid) {
this.userid = userid;
}
}
DAO(Data Access Object)としてInterfaceを定義します。S2Daoでは、InterfaceにAspectを適用することで データベースにアクセスするための実装を行う必要がありません。
package ospi_sample.dao;
import ospi_sample.beans.OspiUser;
public interface OspiUserDao {
public static final Class BEAN = OspiUser.class;
public static final String getUser_ARGS = "userid";
public static final String getUser_QUERY = "userid = ?";
public OspiUser getUser(String userid);
}
S2Daoにどのようなアノテーションがあるか調べよ。
S2Dao以外にどのようなO/RMappingのフレームワークがあるか調べよ。
今日の講義では、説明しませんでしたが、SeasarにはStrutsと連携するためのS2Strutsと言うサブプロジェクト もあります。これを利用すると、もっと簡単にSeasarとStrutsの連携ができます。 また、今日の講義では省略しましたが、データベースを利用したアプリケーション開発では、トランザクションの 制御をどのように行うかが非常に重要になります。Strutsを利用する場合、各Actionの処理がトランザクション制御 単位になりますが、S2Strutsを利用すると、こういった制御も簡単に行うことができます。
無設定Strutsと呼ばれる物を利用すれば、複雑なstruts-config.xmlを記述することなく、Strutsを動作させる事ができます。
また、JavaはC/C++などと異なり、PCやOSと言った環境の影響を受けにくく、オープンソースの開発 が行いやすいと言った特徴を持っています。そのおかげか、Struts、Seasar以外にも便利なフレームワーク やオープンソースのソフトウェアがたくさんあります。是非どのような物があるか、みなさん自身で色々 調べてみてください。
以上お疲れ様でした。



