strutsは、JavaのMVCデザインパターンに基づくWebアプリケーションフレームワークです。Struts1とウェブワークの吸収に基づいて開発された新しいフレームワーク。その動作原理を次の図に示します。
- HTTP要求が到着すると、最初にActionContextCleanUpフィルターを渡して属性を削除し、アクションの属性のライフサイクルを延長します。SiteMeshなどの他のフィルターを通過した後、リクエストはStrutsPrepareAndExecuteFilterコア制御フィルターに渡されます。
- StrutsPrepareAndExecuteFilterは、ActionMapperマッパーを介して呼び出すアクションを決定し、制御をActionProxyプロキシに転送します
- ActionProxyは構成マネージャーConfigurationManagerを呼び出して、構成ファイルstruts.xmlから構成情報を読み取り、ActionInvocationオブジェクトを作成します
- ActionInvocationは、インターセプターチェーンを順番に通過してから、Actionによって返された結果文字列に従ってActionを呼び出し、対応するResultを見つけます。
- 結果はビューテンプレートを呼び出し、逆の順序でインターセプターチェーンを実行し、HttpServlet応答を返します
- HTTP応答は、Strutsとユーザー定義のフィルターを逆の順序で通過し、結果をクライアントに返します。
Strutsプロジェクトを作成する
新しいJava Webプロジェクトを作成した後、まず必要なjarパッケージをインポートし、Struts 公式Webサイトhttps://struts.apache.org/download.cgiから必要な依存パッケージをダウンロードし、最新バージョン2.5.22を選択し、すべての依存パッケージを抽出します。複数のjarパッケージの場合、以下の必要なコピーをそれらからプロジェクトlibフォルダーに選択し、依存関係に追加します。プロジェクトのディレクトリ構造は以下の通りです
次に、web.xmlファイルでstruts2フィルターStrutsPrepareAndExecuteFilterを構成して、すべてのパスをフィルターに掛けます。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
次に、Actionクラスを定義し、ActionSupportクラスから継承したsrcディレクトリに新しいaction.FirstActionを作成します。
package action;
import com.opensymphony.xwork2.ActionSupport;
public class FirstAction extends ActionSupport {
@Override
public String execute() throws Exception {
System.out.println("Action执行");
return SUCCESS; //返回字符串SUCCESS
}
}
struts2のコア構成ファイルであるsrcディレクトリーにstruts.xmlファイルを作成し、アクションの構成、および対応する結果定義とその他の関数を完成させます。
<package>はパッケージです。パッケージには複数のアクションを含めることができます。name属性はパッケージ名、extends属性は継承されたパッケージ名、namespaceはネームスペースです。URLレベルでアクションにアクセスする場合は、ネームスペースを追加する必要があります。たとえば、namespaceは/ダウンロード、アクセス時のURLはhttp:// localhost:8080:projectname / download / xxxです。「/」がルート名前空間を表す場合は省略できます。
<action>のname属性はアクセスされるURLパスです。たとえば、ここでは/ firstactionで、classは対応するJavaクラスです。
<result>返される結果セットページを定義し、さまざまな名前属性に応じてさまざまなインターフェイスを返します。名前属性のデフォルトはSUCCESSであるため、ここではデフォルトの戻りインターフェイスsuccess.jsp
<constant>タグは、キーと値のペアの形式で定数を定義できます。ここで、名前はキー、値は値です
さらに、<include>タグを使用して、他のstruts xml構成ファイルをインポートできます。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<package name="default" namespace="/" extends="struts-default">
<action name="firstaction" class="action.FirstAction">
<result>/success.jsp</result>
</action>
</package>
<constant name="struts.url.http.port" value="8080"></constant>
</struts>
プロジェクトを開始してfirstactionにアクセスし、「アクションの実行」をコンソールに出力して、success.jspページにジャンプします。このような基本的なStrutsプロジェクトが実行されます。
アクション
サーブレットAPIにアクセスする
HTTPリクエストはフィルターを介して動作し、操作を実行した後に結果を返すので、RequestオブジェクトとResponseオブジェクトを取得する方法は?Strutsは3つのメソッドを提供します
1つ目は、対応するAwareインターフェースを実装することにより、インターフェースの setXxx()メソッドで要求、応答、およびコンテキストオブジェクトを取得することです。次に、対応するメソッドを使用してプロパティを設定および取得します。このメソッドは、サーブレットAPIと密接に関連しており、推奨されません。
public class FirstAction extends ActionSupport
implements ServletRequestAware, ServletResponseAware, ServletContextAware { //实现相应接口
HttpServletRequest request;
HttpServletResponse response;
ServletContext application;
@Override
public void setServletRequest(HttpServletRequest httpServletRequest) {
this.request=httpServletRequest; //获取request对象
}
@Override
public void setServletResponse(HttpServletResponse httpServletResponse) {
this.response=httpServletResponse; //获取response对象
}
@Override
public void setServletContext(ServletContext servletContext) {
this.application=servletContext; //获取application对象
}
@Override
public String execute() throws Exception {
request.setAttribute("key1","value1"); //设置属性
System.out.println(request.getAttribute("key1")); //获取属性
return SUCCESS;
}
}
2番目の方法は、ServletActionContextクラスの静的メソッドgetXxx()を介して実際のサーブレット関連のAPI を取得することです。その後、リクエスト、セッション、およびアプリケーションオブジェクトのsetAttributeメソッドとgetAttributeメソッドを使用して、属性を設定および取得します。
HttpServletRequest request= ServletActionContext.getRequest(); //获取request对象
HttpSession session=request.getSession(); //获取session对象
ServletContext context=ServletActionContext.getServletContext();//获取全局application对象
session.setAttribute("key3","value3"); //设置属性值
System.out.println(session.getAttribute("key3")); //获取属性值
3番目は、ActionContextクラスを介してサーブレットAPI にアクセスすることです。Struts2は、Mapコレクションを使用してサーブレットオブジェクトを再度カプセル化します。Mapコレクションを介して、アプリケーション、セッション、およびリクエストオブジェクトの共有データを直接操作できます。アクセス値の方が便利で推奨されています。片道。ActionContextオブジェクトを通じて、get / putメソッドを直接呼び出して、リクエストに保存されたオブジェクトを取得および設定できます。getApplication()、getSession()、getParameters()を使用すると、リクエストリクエストのアプリケーションオブジェクト、セッションオブジェクト、およびパラメータパラメータを取得できます。このメソッドは実際のサーブレットAPIオブジェクトを取得しないため、返されるデータはMapタイプであるため、データはMapのput / getメソッドを介して設定および取得できます。
ActionContext actionContext=ActionContext.getContext(); //创建Context对象
actionContext.put("key1","value1"); //向request中存储对象
System.out.println(actionContext.get("key1")); //获取request中存储的信息
Map application=actionContext.getApplication(); //获取application
application.put("key2","value2"); //向application对象存对象
System.out.println(application.get("key2")); //从application中取出对象
アクションURLの順序にアクセスする
strutsのパッケージはネストできるため、アクセスするURLパスには複数のレイヤーを含めることもできます。たとえば、package1にはfirstactionを含むサブパッケージサブパッケージがあり、そのアクセスパスはhttp:// localhost:8080 / Struts2Demo / package1 /サブパッケージ/ firstaction。firstactionがサブパッケージで見つからない場合は、上位パッケージ1に戻って検索します。それでも上位レベルのルートディレクトリに戻っていない場合は、見つからない場合はエラー404を報告します。
アクションメソッドを動的に呼び出す
異なるURLに対して同じアクションで異なるメソッドを呼び出す場合は、それらを動的に呼び出す必要があります。1つ目は、<action>タグのmethod属性を通じて呼び出すアクションクラスのメソッドを指定できます。以下に示すように、アクセスURLがloginactionの場合、strutsはaction.FirstActionでlogin()メソッドを実行し、SUCCESSに戻った後でlogin.jspページにジャンプします
<action name="loginaction" class="action.FirstAction" method="login">
<result>/login.jsp</result>
</action>
ただし、URLごとにアクションを定義する必要がある場合は、繰り返しが多く面倒なので、ワイルドカードを使用して、URLごとに異なる呼び出し方法を定義できます。たとえば、アクションの名前を「hello_ *」として定義し、*を使用してワイルドカードを表し、それらを他のURLから分離し、メソッドで{1}を使用してワイルドカードの最初の位置を表します。アクセスするURLがhello_loginの場合、{1}はログインを表し、FirstActionのloginメソッドの実装に対応します。login()は文字列をloginとして返し、名前が<result>のloginであるラベルを見つけ、/ login.jspを返しますページ。hello_logoutにアクセスすると、logout()が実行され、/ logout.jspが返されます。動的にアクションを呼び出す機能と動的にページに戻る機能は、異なる着信URLに従って実現されていることがわかります。
<package name="default" namespace="/" extends="struts-default">
<global-allowed-methods>regex:.*</global-allowed-methods>
<action name="hello_*" method="{1}" class="action.FirstAction">
<result name="{1}">/{1}.jsp</result>
</action>
</package>
public class FirstAction extends ActionSupport{
public String login(){
return "login";
}
public String logout(){
return "logout";
}
}
デフォルトのアクション
default-action-refタグを使用してパッケージのデフォルトアクセスパスを指定できます。つまり、定義された通常のパスに加えて他のリクエストがアクションにジャンプします。たとえば、デフォルトのアクションをエラーとして定義し、アクションをエラーとして定義して、error.jspページにジャンプします。
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="error"></default-action-ref>
<action name="error">
<result>/error.jsp</result>
</action>
......
</packge>
URLサフィックスを追加
アクションのデフォルトのサフィックスは.actionです。このサフィックスは、URLにアクセスするときに書き込むかどうかを指定できます。struts構成ファイルで、定数struts.action.extensionを介してアクセスページにサフィックスを追加します。たとえば、サフィックスがhtmlに設定されている場合、正常にアクセスするには、すべてのURLを.htmlで追加する必要があります。
<constant name="struts.action.extension" value="html"></constant>
受信パラメータ
リクエストを使用してリクエスト内のパラメーターを受け取ることに加えて、次の3つの方法でフロントエンドページでパラメーターを受け取ることもできます。
1つは、Action属性を介して直接受け取る方法です。Actionクラスで属性変数を定義し、そのget / setメソッドを実装すると、属性変数をアクションメソッドで直接使用できます。たとえば、フロントエンドフォームの送信には、usernameとpasswordという名前の2つのパラメーターがあります。LoginActionで対応する変数とget / setメソッドを定義すると、login()メソッドで2つのパラメーター値を直接取得できます。
<form action="login.action" method="post">
姓名:<input type="text" name="username">
密码:<input type="password" name="password">
<input type="submit" value="提交">
</form>
public class LoginAction extends ActionSupport {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String login(){
System.out.println(username+":"+password); //直接通过Action属性获取参数
return SUCCESS;
}
}
プロパティをアクションクラスに直接配置しても、オブジェクトのカプセル化と管理にはつながりません。2つ目のメソッドDomainModelは、オブジェクトを使用してパラメータを受け取ります。ユーザー名とパスワードの属性を格納する新しいJavaBeanクラスUserを作成し、アクションでユーザーオブジェクトをインスタンス化して、set / getメソッドを定義します。フロントエンドフォームでプロパティ名を設定するときに、オブジェクト名userを追加します。user.username、user.passwordです。このようにして、属性がアクションファイルに自動的に割り当てられ、ユーザーオブジェクトを直接使用できます。
//JavaBean类User
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
//Action中使用user对象接收参数
public class LoginAction extends ActionSupport {
private User user; //新建user对象
public User getUser() { //设置get方法
return user;
}
public void setUser(User user) {
this.user = user;
}
public String login(){ //通过User对象获取参数
System.out.println(user.getUsername()+":"+user.getPassword());
return SUCCESS;
}
}
<form action="login.action" method="post">
姓名:<input type="text" name="user.username"> <!--通过user对象传递属性-->
密码:<input type="password" name="user.password">
<input type="submit" value="提交">
</form>
3番目の方法は、ModelDrivenインターフェイスを使用することです。Actionクラスは、ModelDrivenインターフェイスを実装し、そのgetModel()メソッドを実装して、ユーザーオブジェクトを取得します。この方法では、ユーザーオブジェクトのget / setメソッドを定義する必要がなく、フロントページのフォーム属性にユーザーオブジェクトプレフィックスを追加する必要がないため、カップリングが減少します。この方法をお勧めします。
public class LoginAction extends ActionSupport implements ModelDriven<User> { //实现接口
private User user=new User(); //需要实例化user对象
@Override
public User getModel() { //实现接口方法
return user;
}
public String login(){ //可以使用user对象获取参数
System.out.println(user.getUsername()+":"+user.getPassword());
return SUCCESS;
}
}
<form action="login.action" method="post">
姓名:<input type="text" name="username"> <!--不必添加user对象前缀-->
密码:<input type="password" name="password">
<input type="submit" value="提交">
</form>
結果
<result>タグは、アクションによって返されるさまざまな文字列文字列に応じてさまざまな名前属性と一致し、フレームワークモジュール間の分離に役立つさまざまな結果セットを実行します。文字列「success」を表すSUCCESSを返す前に、strutsには他のデフォルトの文字列があります。
フロントエンドで渡されたパラメータは、アクションで受け取った変数と一致できません。アクションは自動的にINPUTに戻るか、手動でINPUTに戻ることができます。たとえば、受信したユーザー名を判断するには、空の場合、FiledErrorを追加してINPUTを返します。フロントエンドページのstruts-tagsを介してfielderroタグを表示できます。アクションがFieldErrorをスローしてINPUTを返し、再度login.jspにジャンプすると、fielderrorタグはFieldErrorにエラー情報を表示します。
public class LoginAction extends ActionSupport implements ModelDriven<User> {
private User user=new User();
@Override
public User getModel() {
return user;
}
public String login(){
if (user.getUsername()==null||user.getUsername().isEmpty()) {
this.addFieldError("username", "用户名不能为空"); //添加错误信息
return INPUT;
}
System.out.println(user.getUsername()+":"+user.getPassword());
return SUCCESS;
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %> <!--引入struts-tags标签-->
<html>
<head>
<title>登录界面</title>
</head>
<body>
<form action="login.action" method="post">
姓名:<input type="text" name="username"><s:fielderror name="username"/> <!--错误提示-->
密码:<input type="password" name="password">
<input type="submit" value="提交">
</form>
</body>
</html>
以下に示すように、struts-tagsはプロンプト情報を表示します。
<result>タグの位置に応じて、結果ビューをローカル結果とグローバル結果に分けることができます。<result>が<global-result>タグで直接定義されている場合、それはグローバルな結果です。<result>が<action>で定義されている場合、それは部分的な結果です。
<package>
<global-results>
<result name="404error">/404.jsp</result>
</global-results>
......
</package>
<result>の属性タイプは、返される結果のタイプを指定できます。デフォルトはJSPです。ValocityやFreeMarkerなどの他のテンプレートエンジンを使用することもできます。リダイレクトとプレーンテキストプレーンテキストもサポートしています。
インターセプター
Strutsの概略図では、インターセプター(Interceptor)がリクエストにアクションを実行する前に動作し、Result結果を返した後、インターセプターを介して戻ることがわかります。複数のインターセプターがインターセプタースタックを形成し、インターセプタースタックの実行はスタックと同じように順番に行われ、最初に実行されます。そのため、インターセプターを使用して、アクションに到達する前にリクエストを前処理し、結果を返す前にさらに操作を実行できます。
インターセプターを定義する
最初の方法は、Interceptorインターフェースを実装することです。インターフェイスには3つのメソッドがあります。
- init()はインターセプターが必要とするリソースを初期化します
- destroy()は割り当てられたリソースを解放します
- 文字列インターセプト(ActionInvocation ai)、ActionInvocationを介してアクションステータスを取得し、インターセプターのメイン操作を完了して、結果文字列を返します。
2番目のメソッドは、abstractInterceptorクラスを継承することです。これは、init()メソッドとdestroy()メソッドの空の実装を提供するため、intercept()メソッドのみを実装する必要があるため、このメソッドがより一般的に使用されます。以下に示すように、ユーザーログインを確認するインターセプターを定義します。セッションでユーザー名が空でない場合、インターセプターは次のレイヤーに渡されます。それ以外の場合、インターセプターは文字列「login」を返し、ログインインターフェースにジャンプします。
public class AuthLog extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation actionInvocation) throws Exception {
System.out.println("Action执行之前");
ActionContext actionContext=ActionContext.getContext();
Map session =actionContext.getSession();
if (session.get("username")!=null){
//执行下一个拦截器,若为最后一个则执行目标Action,然后返回结果
String result=actionInvocation.invoke();
System.out.println("执行Action之后");
//将结果返回上一层
return result;
}else {
return "login";
}
}
}
インターセプターの登録
まず、インターセプターをstruts.xmlファイルに登録してから、使用するアクションでインターセプターを参照します。複数のインターセプターを1つのインターセプタースタックに結合することもできます。
以下に示すように、まずAuthLogクラスを指すインターセプターauthlogを定義します。次に、デフォルトのインターセプターとmyStackインターセプタースタックとして組み合わされます。次に、actionをpersonalPageとして定義し、それにインターセプターmyStackを追加します。ユーザーがアクションにアクセスすると、最初にmyStackインターセプタースタックのdefaultStackを渡し、次にログイン検証が完了するauthlogインターセプターを渡します。検証が成功した場合は、success.jspを返し、そうでない場合は、login.jspを返します。
<interceptors>
<interceptor name="authlog" class="interceptor.AuthLog"></interceptor>
<!--定义拦截器栈-->
<interceptor-stack name="myStack">
<interceptor-ref name="defaultStack"></interceptor-ref> <!--引用默认拦截器-->
<interceptor-ref name="authlog"></interceptor-ref>
</interceptor-stack>
</interceptors>
<action name="personalPage">
<result>/success.jsp</result>
<result name="login">/login.jsp</result>
<interceptor-ref name="myStack"></interceptor-ref> <!--引用拦截器-->
</action>
組み込みインターセプター
strutsには、その機能を実現するために多くのインターセプターが組み込まれています。
- paramsインターセプターは、リクエストされたparamsパラメーターをaction属性に渡します。以前は、このアクションは、このインターセプターを介してparams属性を直接受け取るために使用されていました。
- servletConfigインターセプターは、サーブレットのインターフェースをアクションに挿入するので、リクエスト、セッション、およびその他のサーブレットオブジェクトをアクションで使用できます。
- fileUploadインターセプターは、ファイルのアップロード、ファイルおよびメタデータのアクション属性への設定をサポートします。
- 例外インターセプターは例外をキャッチし、ユーザー定義のページにマップします
- 検証インターセプターは検証フレームワークを通じてデータ検証を実行します
これらのインターセプターはstruts-core.jarパッケージのstruts-default.xmlファイルに登録され、デフォルトのインターセプタースタック<interceptor-stack name = "defaultStack">としてまとめてパッケージ化されます。また、デフォルトの参照<default-interceptor-ref name = "defaultStack" />に設定します。つまり、ユーザーがインターセプターを参照しない場合、デフォルトのインターセプタースタックdefaultStackが参照されます。ただし、ユーザーがインターセプターをカスタマイズすると、defaultStackは参照されなくなるため、手動で参照する必要があります。