Java之struts2框架學習

Zh1z3ven 發表於 2022-07-17
Java 框架

Java之struts2框架學習

About Struts2

Struts也是一款MVC框架 , Struts2是Struts的下一代產品,是在Struts1和WebWork的技術基礎上進行了合併的全新的Struts2框架
其全新的Struts2的體系結構與Struts1的體系結構差別巨大。Struts2以WebWork為核心
Struts2=Struts1+WebWork,而WebWork的核心就是XWork。

XWork提供了很多核心功能:前端攔截機(interceptor),執行時表單屬性驗證,型別轉換,強大的表示式語言(OGNL—the Object Navigation Language),IOC(Inversion of Control 反轉控制)容器等。

Struts2 路由配置方式

1、StrutsPrepareAndExecuteFilter

第一種是通過StrutsPrepareAndExecuteFilter,它是Struts2的核心控制器,也是一個Filter,配置/*會攔截所有請求,通過之後轉發給Struts2框架做請求處理

<filter>
        <filter-name>struts</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
        <filter-name>struts</filter-name>
        <url-pattern>/*</url-pattern>
</filter-mapping>

而這樣就是全域性都是走struts2的路由了

2、ActionServlet

還有一種配置如下,通過ActionServlet並配置*.do字尾來匹配請求,將.do的請求交給ActionServlet做處理,最終交給Struts2框架

  <servlet-mapping>
    <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>
 <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>application</param-name>
      <param-value>ApplicationResources</param-value>
    </init-param>
  </servlet>

這樣操作,就可以自定義一些servlet,從而不走struts2框架進行處理,同時也可以融入SpringMVC,審計時也會遇到SpringMVC+Struts2兩個MVC框架做路由的處理。application的配置是說明你的資源包的名字是ApplicationResources.properties,這個一般有關於struts-config.xml檔案中的message-resources標籤

struts-config.xml

<struts-config>是struts的根元素,它主要有8個子元素,DTD定義如下:

<!ELEMENT struts-config
(data-sources?,form-beans?,global-exceptions?,global-forwards?,action-mappings?,controller?,message-resources*,plug-in*)
>

data-sources

Data-sources元素用來配置應用程式所需要的資料來源。java語言提供了javax.sql.DateSource介面,所有資料來源必須實現該介面。如下配置:

<data-sources>
  <data-source type="org.apached.commons.dbcp.BasicDataSource">
    ………………
  </data-source>
</data-sources>

在action中訪問方式如下: ataSource = getDataSource(request,"a");

javax.sql.DataSource dataSource;
java.sql.Connection myConnection;
try
{
  dataSource = getDataSource(request);
  myConnection = dataSource.getConnection();
}

form-beans

該元素主要用來配置表單驗證的類。它包含如下屬性:
  1. classname:一般用得少,指定和form-bean無素對應的配置類,預設為org.apache.struts.config.FormBeanConfig,如果自定義,則必須擴充套件FormBeanConfig類。可有可無。
  2. name:ActionForm Bean的惟一標識。必須。
  3. type:ActionForm的完整類名。必須。

<form-beans>
  <form-bean 
      name="Loign"
      type="com.ForumActionForm">
  </form-bean>
</form-beans>

像是表單名稱與type指定的類進行一個繫結,一般type指定的類會繼承ActionForm類,ActionForm是struts2中的核心元件之一,用來處理表單資料,本質是一個javabean。

其中自帶validate()方法和reset()方法是 ActionForm中兩種可以覆蓋的方法。validate()方法中定義具體的 ActionForm驗證規則。reset()方法則是在初始化時被呼叫。

action-mappings

描述從特定的請求路徑到相應的Action類的對映。該元素用於將Action元素定義到ActionServlet類中,它含有0到多個<action/>元素

其格式如下:

<action-mappings>
  <action path="Action請求的相對路徑,與頁面<html:form>的Action屬性值一致" type="該Action的對應類的全路徑" name="該Action繫結的FormBean,與<form-bean >的Name屬性值一致"
  	<forward name="與Action類中mapping.findForward("mapname")返回的mapname值一致" path="頁面跳轉的相對路徑"/>
  </action>
</action-mappings>

每個action子元素可包含一個或多個forward子元素。除了path、type和name屬性外,action還具有如下屬性:

scope:指定ActionForm Bean的作用域(session和request),預設為session。(可選);

input:當Bean發生錯誤時返回的路徑,在validate驗證框架中錯誤顯示的頁面(可選);

classname:指定一個呼叫這個Action類的ActionMapping類的全名。預設用org.apache.struts.action.ActionMapping(可選);

include:如果沒有forward的時候,它起forward的作用(可選);

validate:若為true,則會呼叫ActionForm的validate()方法或呼叫validate驗證,否則不呼叫,預設為true(可選)。

forward屬性也是可選的。
例如

<action path="/LoginAction" type="com.action.LoginAction" validate="true">
    <forward name="a" path="/a/a.jsp"/>
		<forward name="b" path="/b/b.jsp"/>
		<forward name="v" path="/c/c.jsp"/>
</action>

首先當我們訪問/LoginAction.do時會找到對應的com.action.LoginAction#execute()方法做邏輯處理,一般其中以action來做為具體功能的名稱來指定forward路由和功能邏輯,比如訪問/LoginAction.do?action=a就會進入LoginAction#execute()方法做處理,一般會有if等邏輯,比如判斷當action=a時在處理完當前邏輯後,最終會return mapping.findForward("list");會轉發到在struts-config.xmlforward下配置的路由也就是path="/a/a.jsp"

global-forwards

該元素主要用來宣告全域性的轉發關係,它具有以下四個屬性:

  1. className:和forward元素對應的配置類,預設為:org.apache.struts.action.ActionForward。可有可無。
  2. contextRelative:此項為true時,表時path屬性以"/"開頭,相對於當前上下文的URL,預設為false.可有可無。 
  3. name:轉發路徑的邏輯名.必填。
  4. path:轉發或重定向的URL,當contextRelative=false時,URL路徑相對於當前應用(application),當為ture時,表示URL路徑相對於當前上下文(context)。
  5. redirect:當此項為ture時,表示執行重定向操作。當此項為false時表示轉向操作。預設為false。

<global-forwards>
  <forward  name="forms1"  path="/a.do"/>
  <forward  name="forms2"  path="/nb.jsp"/>
<global-forwards>

和action-mappings的區別是,global是全域性轉發

message-resources元素

主要配置本地化訊息文字,它具有以下屬性。

  1. className:和message-resources元素對應的配置類,預設為org.apache.struts.config.MessageResourcesConfig。
  2. factory:指定訊息資源的工廠類,預設為:org.apache.struts.util.PropertyMessageResourcesFactory類
  3. key:指定Resource Bundle存放的ServletContext物件中時採用的屬性Key,預設由Globals.MESSAGES_KEY定義的字串常量,只允許一個Resource Bundle採用預設的屬性Key。
  4. null:指定MessageSources類如何處理未知訊息的key,如果為true,則返回空字串,如果為false,則返回相關字串,預設為false
  5. prameter:指定MessageSources的資原始檔名,如果為:a.b.ApplicationResources,則實際對應的檔案路徑為:WEB-INF/classes/a/b/ApplicationResources.properties.

<message-resources null="false" parameter="defaultResource"/>
<message-resources key="num1" null="false" parameter="test"/>

訪問為:

<bean:message  key="zxj"/>
<bean:message  key="zxj"  bundle="num1"/>

Action

一個Action業務裡可以實現Action介面,也可以繼承ActionSupport類。在ActionSupport中提供了一些實現好的業務方法。在以後的程式設計中,建議全部繼承ActionSupport類。
Action中的方法必須返回一個String型別的字串,這個字串與struts.xml中result標籤的name屬性相對應,struts.xml會根據返回的字串查詢對應的頁面。

Action中execute方法必須返回一個String型別字串,用於後續與struts.xml配置中的result標籤的name屬性對應完成對應的頁面返回

預設提供了5個常用的結果常量 String SUCCESS = "success"; String NONE = "none"; String ERROR = "error"; String INPUT = "input"; String LOGIN = "login";

import com.opensymphony.xwork2.Action;
  
  public class HelloWorldAction implements Action{
    //請求中傳遞的引數和返回給頁面的值都定義成屬性

    private String username;
    private String message;
    //getter/setter方法
    @0verride
    public String execute()throws Exception{
      //檢視請求中傳遞的引數
      System.out.println(username);



      //改變這個message,會自動傳遞給頁面	
      message="hello:"+username;
        //SUCCESS是Action中的常量,值是success 
        return SUCCESS;
    }

下面來看下在StrutsPrepareAndExecuteFilter下如何配置路由,假如有如下action類

package action;

import com.opensymphony.xwork2.Action;

public class HelloWorldAction implements Action{
    //請求中傳遞的引數和返回給頁面的值都定義成屬性
    private String username
    private String password  
//getter/setter方法
@Override
public String execute() throws Exception{
//檢視請求中傳遞的引數
System.out.print1n(username);
//改變這個message,會自動傳遞給頁面
    message="hello:"+username;
//SUCCESS是Action中的常量,值是success
    return SUCCESS;
}}

Struts.xml

這種配置方式一般會存在一個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>
<!--所有的action都放在package中,必須繼承struts-default-->
<!--struts-default中有預設的攔截器配置,能處理引數等資訊-->
<package name="default" extends="struts-default">
    <!--name對應的是請求的地址,class是處理請求的類-->
    <action name="hello" class="action.HelloWorldAction">
        <!--success是Action類中返回的字串,根據不同字串返回不同的頁面-->
        <result name="success">index.jsp</result>
    </action>
</package>
</struts>

而比如在login.jsp中有如下表單,當在登陸時提交表單,action觸發的事件會將請求交給HelloWorldAction#execute()處理,而如果登陸驗證成功,返回success就會根據struts.xml的配置會返回index.jsp

<form action="hello" method="post">
    id:<input name="user.id">
    username:<input name="user.username">
    <input type="submit" value="提交">
</form>

關於字尾,struts2預設支援.action字尾,需要配置其他字尾則需要在struts.xml進行如下配置

<constant name="struts.action.extension" value="do, html"/>

同時在struts.xml可以配置預設action,當找不到對應的action時則匹配預設action

對當前的package有效。
action標籤的clas省略將呼叫ActionSupport類。result的name省略將預設為success。
注意default-action-re必須在所有的action標籤上面。

<default-action-ref name="default"/>
<action name="default">
<result>error.jsp</result>
</action>

constant標籤

constant用來配置常量。name屬性是常量名,value屬性是常量值。

<!--設定請求字尾-->
<constant name="struts.action.extension"value="do,html"/>
<!--設定編碼,解決中文亂碼-->
<constant name="struts.i18n.encoding"value="utf-8"/>
<!--設定struts標籤主題-->
<constant name="struts.ui.theme"value="simple"/>

package標籤

package是包。Struts2的package與java中的package類似,可以把同一個業務模組的action和result集中到一個包中,方便管理。不同的是Struts2的包可以繼承。通常都會繼承struts-default。在struts-default中定義了大量的struts特性,如攔截器和引數處理的功能,如果不繼承struts-default,會遇到引數無法繫結或找不到action類。

name屬性是包的名字,一個struts.xml中可以有很多個package,通過name屬性進行區分。

namespace是名稱空間,/代表的是根目錄。namespace的作用類似於SpringMVC中在Controller類上加@RequestMapping註解。相當於此包中所有的action前都加一個父路徑。

比如下面第一行配置了跟路徑是/而後續訪問action就是/login.cation

<package name="default" namespace="/" extends="struts-default">
<action name="login"class="action.LoginAction">

action標籤

action標籤用來處理請求和響應結果。
name屬性是請求的名字,此處不需要加.action。同一個package下的action不能重名。
class屬性指定處理該請求的類,是類的全路徑。預設的處理請求時會去類中找名為execute的方法。如果不指定class,將預設ActionSupport為處理請求的類。
result標籤用來處理請求結果,name屬性是Action類中返回的字串。標籤的值是要跳轉的頁面地址。name如果不寫的話,預設是success。

<action name="1ogin"class="action.LoginAction">
<--success是Action類中返回的字串,根據不同字串返回不同的頁面-->
<result name="success">index.jsp</result>
<result name="error">error.jsp</result><result name="input">1ogin.jsp</result>
</action>

Action配置自定義業務

Action預設以execute為入口方法處理,當然也可以通過struts.xml修改配置來達到不用execute方法

package action;import com.opensymphony.xwork2.ActionSupport;
/∥繼承ActionSupport類
public class UserAction extends ActionSupport{
//處理登入
public String 1ogin(){
//引數和業務略
System.out.println("我是登入");
    return SUCCESS;
//處理註冊
public String regist(){
//引數和業務略
System.out.println("我是註冊");
        return SUCCESS;
}

Struts.xml配置,method="login"表示要呼叫類中的login方法處理請求。如果找不到login0方法,Struts2會在類中查詢doLogin)方法。如果都找不到,將會報錯。

<package name="user"namespace="/user"extends="struts-
default">
<!--通過method指定呼叫類中的哪個方法-->
<action name="login"class="action.UserAction"
method="1ogin">
<result name="success">index.jsp</result><!--登入成功去首頁-->
<result name="error">1ogin.jsp</result><!--登入失敗回登入頁-->
</action>
<action name="reg"class="action.UserAction"
method="regist">
<result name="success">index.jsp</result><!--註冊成功去首頁-->
<result name="error">regist.jsp</result><!--註冊失敗回登入頁-->
</action>
</package>

Action動態方法與萬用字元

如果一個類中有多個業務方法,又不想給每個業務方法都配置一個action標籤,可以使用動態黨法呼叫,

語法:請求名!方法名.action

當請求的格式是user!login.action時,代表呼叫UserAction中的login方法處理當前請求。

<!--允許呼叫動態方法-->
<constant name="struts.enable.DynamicMethodInvocation"
value="true"/>

action配置

<!--允許動態呼叫的方法,新版裡新增的設定-->
<g1obal-a1lowed-methods>1ogin,regist</g1obal-a1lowed-methods>
<action name="user"class="action.UserAction">
<result name="success">/index.jsp</result><!--成功去首頁-->
<result name="error">/error.jsp</result><!--失敗去錯誤-->
</action>

萬用字元

<!--設定useraction中允許萬用字元匹配的方法-->
<global-allowed-methods>login,regist</global-allowed-methods>
  <!--method屬性中匹配方法名-->
<action name="*User" class="action.UserAction" method="{1}">
<result name="success">/index.jsp</result>
<result name="error">{1}.jsp</result><!--失敗了就返回原來的頁面-->
</action>

User匹配所有以User結尾的請求,method={1}中的{1}匹配的就是 User中的。如果請求的地址是loginUser.action,那麼{1}匹配的就是login,就會去類中呼叫login方法,並返回相應的結果。

Result

型別有dispatcher、redirect、redirectAction、chain

dispatcher

result的預設型別就是dispatcher。就是轉發,在result標籤的type屬性中設定

<result name="success"type="dispatcher">index.jsp</result>
<result name="success">index.jsp</result>

redirect

redirect是重定向,重定向之後,當前請求中的引數和屬性在下一個頁面或請求中將不能使用。

<result name="success"type="redirect">index.jsp</result>

redirectAction

redirectAction與redirect類似,不過redirectAction是重定向到某一個action

<action name="reg"class="action.UserAction"method="regist">
<result name="success"
type="redirectAction">1ogin.action</result>
<result name="error">regist.jsp</result>
</action>

如果要呼叫不同package下的action,需要在result中傳引數:

<action name="login"class="action.UserAction"method="login">
<result name="success"type="redirectAction">
<!--呼叫不同package下的action-->
<param name="namespace">/</param>
<param name="actionName">hel1o.action</param>
<!--傳遞其它引數-->
<param name="username">123</param>
</result>
    <result name="error">login.jsp</result>
</action>

chain

chain型別可以共享當前request

<action name="reg"class="action.UserAction"method="regist">
<!--注意chain的action後面沒有字尾-->
<result name="success"type="chain">login</result>
<result name="error">regist.jsp</result>
</action>

動態獲取返回結果

private String username;private String page;
//getter/setter方法略
public String 1ogin(){
//引數和業務略
System.out.print1n("我是登入")
  if("admin".equals(username))
{
    //管理員去管理頁
    page="admin-page";
    
    }else{//其他人去使用者頁
    page="user-page";
    return SUCCESS;
}

result配置

<action name="login"class="action.UserAction"method="1ogin">
<!--讀取action中的屬性值,返回不同頁面-->
<result name="success">${page}.jsp</result>
<result name="error">login.jsp</result>
</action>

validate方法

ActionSupport,ActionSupport中有一個validate方法可以進行校驗操作,只需要重寫該方法即可實現校驗功能。

public class ValidateAction extends ActionSupport {
    private String username;//使用者名稱不能為空,並且長度要大於6

    @Override
    public void validate() {
        System.out.println("validate()");
        if (username == null || username.trim().length() < 6) {
            addFieldError("username", "必須輸入使用者名稱,長度大於6");
        }
    }
}

addFieldError要求必須給result配置一個input型別的結果。所以在呼叫logout方法時,會報找不到result input。

<action name="valLogin" class="action.ValidateAction" method="login">
  <result name="success">main.jsp</result>
  <result name="input">val.jsp</result>
</action>

validate方法會驗證當前Action類中所有的方法,如果只想驗證其中的一個方法,可以使用validatexxx方法,其中xxx是被驗證的方法名,首字母大寫。

//只驗證1ogin方法,不驗證其它方法
public void validatelogin(){
if(username==nul1 ll username.1ength()==0){
//向頁面中新增錯誤資訊
addFieldError("username",“使用者名稱不能為空”);

對某一個Action類進行校驗會用到驗證框架

驗證框架是把驗證資訊都寫在xm檔案中,對某一個Action類進行驗證,需要在Action類的同一個包下建立xml檔案,檔案命名為Action類的類名validation.xml

validators標籤:在校驗框架中,所有的驗證都寫在validators標籤中field標籤:每一個需要驗證的屬性都是一個field標籤,name指定要驗證那個屬性。
field-validator標籤:代表一種驗證規則,通過type指定規則。

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN"

        "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">

<validators>
    <field name="username">
        <field-validator type="requiredstring">
            <message>必須輸入使用者名稱</message>
        </field-validator>
        <field-validator type="stringlength">
            <param name="minLength">6</param>
            <message>長度必須大於${minLength}</message>
        </field-validator>
    </field>
</validators>

interceptor攔截器

類似於filter在請求進入action前作預處理

自定義攔截器類需要實現Interceptor介面或者繼承AbstractIntercepter,攔截邏輯主要在intercept方法中,該方法返回一個字串作為邏輯檢視,系統根據返回的字串跳轉到對應的檢視資源。每攔截一個動作請求,該方法就會被呼叫一次。

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

public class TimeInterceptor implements Interceptor {

    @Override
    public void destroy() {

    }

    @Override
    public void init() {

    }

    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {
        		//前處理
            System.out.println("MyInterceptor3 的前處理!");
            //放行
            String result = invocation.invoke();
            //後處理
            System.out.println("MyInterceptor3 的後處理!");
        return result;
    }

在struts.xml中配置攔截器

<package name="test" namespace="/" extends="struts-default,json-default">
  <interceptors>
    定義攔截器
    <interceptor name="time" class="interceptor.TimeInterceptor"/>
    <interceptor name="login" class="interceptor.LoginInterceptor"/>
    定義攔截器棧
    將多個攔截器繫結到一起,只需要引用攔截器棧即可。
    <interceptor-stack name="time-stack">
      <interceptor-ref name="time"/>
      <interceptor-ref name="login"/>
      <interceptor-ref name="defaultStack"/>
    </interceptor-stack>
  </interceptors>
  <global-results>
    <result name="login">/login.jsp</result>
  </global-results>

給action新增攔截器飲用

<action name="hello"class="action.HelloWorldAction">
<interceptor-ref name="time"/>
<result name="success">index.jsp</result>
</action>

使用自定義攔截器會造成引數無法讀取,這時候可以引入struts自帶的攔截器。

<default-interceptor-ref name="time"/>

Reference

https://www.cnblogs.com/nice0e3/p/14800343.html

https://blog.csdn.net/cold___play/article/details/102651720