關於Struts2中Action從表單取值並且存到Web元素中(session)

来源:http://www.cnblogs.com/sageliu/archive/2017/11/01/7766793.html
-Advertisement-
Play Games

Struts2中Action從表單取值並且存到Web元素中(session) ...


聲明:本博客非原創,【轉載:http://blog.csdn.net/Cece_2012/article/details/7617775

在struts2中,Action不同於struts1.x中的Action。在struts2中Action並不需要繼承任何控制器類型或實現相應介面。比如struts1.x中的Action需要繼承Action或者DispatcherAction。

同時struts2中的Action並不需要藉助於像struts1.x中的ActionForm獲取表單的數據。可以直接通過與表單元素相同名稱的數據成員(需要存在符合命名規範的set和get方法)獲取頁面表單數據。

雖然struts2中的Action原則上不用繼承任何類型。但是一般需要實現com.opensymphony.xwork2.Action介面或者繼承com.opensymphony.xwork2.ActionSupport類型,然後重寫execute方法。通常更願意去繼承ActionSupport類型,這樣我們可以在我們的控制器中增加更多的功能。因為ActionSupport本身不但實現了Action介面,而且實現了其他的幾個介面,讓我們的控制器的功能更加強大,例如:

com.opensymphony.xwork2.Validateable:提供了validate方法,可以對action中的數據進行校驗

com.opensymphony.xwork2.ValidationAware:提供了addFieldError方法,可以存取action級別或者欄位級別的錯誤消息

com.opensymphony.xwork2.TextProvider:提供了獲取本地化信息文本的方法getText

com.opensymphony.xwork2.LocaleProvider:提供了getLocale方法,用於獲取本地信息

從以上我們可以看到,繼承ActionSupport,可以完成更多的工作。

例如上面的例子,例如我們需要判斷輸入文本框的內容,輸入的內容長度必須在6-10之間。那麼我們可以增加校驗工作,利用validate方法。更改後的代碼如下:

 

 1 package com.frank.action;
 2 
 3 import com.opensymphony.xwork2.ActionSupport;
 4 public class HelloWorldAction extends ActionSupport {
 5     private String message;
 6     private String username;
 7     @Override
 8     public String execute() throws Exception {
 9         this.message="Hello World:"+this.username;
10         return SUCCESS;
11     }
12     public String getUsername() {
13         return username;
14     }
15     public void setUsername(String username) {
16         this.username = username;
17     }
18     public String getMessage() {
19         return message;
20     }
21     public void setMessage(String message) {
22         this.message = message;
23     }
24     @Override
25     public void validate() {
26         if(this.username.trim().length()<6||this.username.trim().length()>10){
27             addFieldError("user.username","the length is invalid");
28         }
29     }
30 }
View Code

 

由於實現了validate方法,這樣當請求一個控制器(在這裡為helloWorld.action)的時候,首先執行validate方法,如果有錯誤信息增加到action中,那麼就不繼續執行Action,返回INPUT,否則就繼續執行Action。在本例中,首先判斷用戶名稱是否在合法的長度範圍,如果不在增加錯誤信息,返回INPUT(預設返回)。

因為有錯誤返回INPUT,所以此Action在配置文件中應該定義INPUT轉發路徑

<action name="helloWorld" class="com.frank.action.HelloWorldAction">
                <result name="success">display.jsp</result>
                <result name="input">helloWorld.jsp</result>
</action>

 

出現錯誤時,返回到helloWorld.jsp,併在此頁面中顯示控制器中所註冊的錯誤消息,更改後的頁面如下(黑色字體為增加的)

<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'helloWorld.jsp' starting page</title>

<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0"> 
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->

</head>

<body> 
<h1><s:fielderror/></h1><br>
<form action="helloWorld.action">
username:<s:textfield name="username"/>
<br>
<s:submit align="left"/>
</form>
</body>
</html>
View Code

 

當前Action執行的核心方法都是execute,有時我們可以能希望同一個控制器做不同的工作。例如在對一個表分別進行CRUD操作時,我們可能需要根據不同的情況執行4種操作,這樣一個execute做起來比較麻煩,我們可以定義我們自己的方法,然後控制器有選擇的執行。類似struts1.x中的DispatcherAction控制器一樣。

這時我們自定義的操作方法,必須和execute具有相同的簽名,只是名稱不同而已。例如在前面的例子中我們增加一個超鏈接,讓它同樣請求helloWorld.action,但是在控制器端執行自己定義的方法myExecute。註意在這裡先去掉驗證方法validate,取消驗證。修改後代碼如下:

package com.frank.action;

import com.opensymphony.xwork2.ActionSupport;
public class HelloWorldAction extends ActionSupport {
    private String message;
    private String username;
    @Override
    public String execute() throws Exception {
        this.message="Hello World:"+this.username;
        return SUCCESS;
    }
    public String myExecute() throws Exception{
        this.message="Good Morning !!!";
        return SUCCESS;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }    
}
View Code

 

此時我們需要增加新的Action配置,並指明調用的方法

<action name="otherHelloWorld" class="com.frank.action.HelloWorldAction" method="myExecute">
                <result name="success">display.jsp</result>
</action>

 

在helloWorld.jsp中增加超鏈接,強求新增加的Action

<a href="otherHelloWorld.action">OtherAction</a>

新的請求頁面:

點擊超鏈接後,請求新的Action,結果如下:

由於請求的新Action在配置中指明瞭所調用的方法為myExecute,所以在控制器端不再執行execute方法,轉而執行myExecute,所以輸出結果為

Good Morning !!!

同樣存在另外一種形式請求新的Action:

即:Action名!新的方法名.action,剛纔的超鏈接可以更改成:<a href="helloWorld!myExecute.action">OtherAction</a>

 

 

表單數據的提交

表單數據的提交在Web編程中是非常重要的。控制器需要獲取用戶在表示層(頁面)所提交的數據,然後進行下一步操作。比如在用戶登錄操作中,控制器需要獲取用戶在頁面中輸入的“用戶名稱”和“密碼”數據,來決定下一步的驗證。

獲取表單提交的數據有兩種方式:

第一種為使用中介對象(我通常把它稱為包裝表示層數據的包裹)。比如在strtus1.x中使用各種ActionForm來封裝頁面數據。使用中介對象可以同時在中介對象的裡面增加諸如:驗證、過濾、日誌記錄等附加工作。但是同樣帶來了類數量的膨脹,存在各種各樣的ActionForm類(LoginForm、PersonForm等等),不利於項目的維護管理。

第二種是直接使用控制器中的域對象,即直接使用控制器中的數據成員獲取表示層的數據,在struts2種支持此種方式。但必須保證相應的數據成員和表示層提交的數據名稱一致,並且具有符合命名規範的setter和getter方法。這樣可以達到“內省”。直接使用域對象可以減少類的膨脹,如果只是簡單的獲取提交的數據則建議直接使用域對象。

在此我們還是同一個非常簡單的(我經常採用的)登錄操作來體會開發過程。可以通過此操作擴展到複雜的操作,其實原理一樣。還是從頭開始(省去準備工作的步驟,直接進入開發過程):

首先創建一個登錄頁面login.jsp,代碼內容如下:

<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'login.jsp' starting page</title>

<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0"> 
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->

</head>

<body>

<h1><s:fielderror/></h1>
<h1>User Login</h1><br>
<form action="login.action">
    Username:<s:textfield name="username"/><br>
    Password:<s:textfield name="password"/><br>
    <input type="submit" value="Login"/>
</form>
</body>
</html>
View Code

<s:fielderror/>用於顯示所註冊的錯誤信息

接著建立Actiion類:LoginAction,在此我們通過域對象獲取表示層提交的數據,也就是在控制器中聲明兩個數據成員username和password來得到表示層的數據,然後在execute方法中進行驗證工作(當然,一般規範開發需要在業務類中進行實際驗證),在此簡便此操作。同時重寫validate方法在Action實際執行前進行驗證工作,具體的驗證方式由自己的業務決定。代碼如下:

package com.frank.action;

import com.opensymphony.xwork2.ActionSupport;

public class LoginAction extends ActionSupport {

    private String username;
    private String password;
    @Override
    public String execute() throws Exception {
        if(this.username.equals("admin")&&this.password.equals("admin")){
            return SUCCESS;
        }
        return INPUT;
    }

    @Override
    public void validate() {
        if(this.username==null||this.username.trim().length()<1){
            addFieldError("no.username","must input username");
        }
        if(this.password==null||this.password.trim().length()<1){
            addFieldError("no.password","must intpu 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;
    }

}
View Code

 

新建一個index.jsp頁面,用戶在用戶登錄成功後顯示,內容非常的簡單,就是一條“Login Success!!!”

<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0"> 
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>

<body>
<h1>Login Success!!!</h1>
</body>
</html>
View Code

 

現在可以開始配置Action了,在struts.xml中增加新的Action,配置如下:

<action name="login" class="com.frank.action.LoginAction">
                    <result>index.jsp</result>
                    <result name="input">login.jsp</result>
            </action>

可以部署和運行了,啟動login.jsp

如果在任意一個文本框中不輸入內容或者輸入空白內容,則返回當前頁面,並錯誤提示

如果輸入的用戶名和密碼錯誤,同樣返回到當前頁面

如果輸入的用戶和密碼正確,則到達index.jsp

註意以上所有的提交方式都為預設GET提交方式

封裝表示層數據到業務類中

在實際的開發過程中,我們可以用業務類對象獲取表示層數據,這樣我們可以在業務類中實現更多的業務方法(比如登錄、註冊)。而由控制器去調用業務類。因為struts2同樣遵循的是MVC模式,所以我們不應該讓控制器去做實際的業務工作,而是調用Model,而這裡同樣用Model獲取表示層的數據。

這樣我們可以新建一個類User,在這裡聲明數據成員username和password,並增加一個驗證方法login,用於驗證登錄。User類的代碼如下:

package com.frank.rule;

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;
}
public boolean login(){
if(this.username.equals("admin")&&password.equals("admin")){
return true;
}
return false;
}
}
View Code

 

既然我們用User獲取用戶的數據,這樣我們需要在Action增加User類型的數據成員,而去掉原來的username和password,重構的代碼如下:

package com.frank.action;

import com.opensymphony.xwork2.ActionSupport;
import com.frank.rule.User;
public class LoginAction extends ActionSupport {

private User user;
@Override
public String execute() throws Exception {
if(user.login()){
return SUCCESS;
}
return INPUT;
}

@Override
public void validate() {
if(user.getUsername()==null||user.getUsername().trim().length()<1){
addFieldError("no.username","must input username");
}
if(user.getPassword()==null||user.getPassword().trim().length()<1){
addFieldError("no.password","must intpu password");
}

}
public User getUser() {
return user;
}

public void setUser(User user) {
this.user = user;
}

}
View Code

在這裡頁面的數據不再由控制器的username和password數據成員獲取,轉而有其中的user對象進行封裝。所以應該修改login.jsp的提交表單,修改後的結果如下:

<form action="login.action">
        Username:<s:textfield name="user.username"/><br>
        Password:<s:textfield name="user.password"/><br>
        <input type="submit" value="Login"/>
</form>

 

註意此時提交表單中的文本框名稱必須為user.username和user.password,這樣所輸入的內容會由控制器的user對象獲取。

這裡可能有一個疑問,就是在控制器中並沒有在任何時候創建User對象,那麼內容是如何獲得的呢?難道不會拋出NullPointerException?此時當請求控制器,並設置user對象的username數據成員時,action依次調用下方法:

user.getUser();

user.setUser(new User());

user.getUser().setUsername("admin");

從上可以看出,首先struts2會嘗試獲取user對象,如果不存在則執行第二步創建一個新對象,然後將內賦給數據成員

重新部署,運行,所得到的效果和前一個相同。

使用Servlet相關對象

在進行Web編程時,很多時候需要使用Servlet相關對象,例如:HttpServletRequest、HttpServletResponse、HttpSession、ServletContext。我們可以將一些信息存放到session中,然後在需要的時候取出。

在struts1.x的Action中,可以通過HttpServletRequest和HttpServletResponse參數來得到Servlet相關對象,進而使用。那麼在struts2種如何獲取?

我們可以使用com.opensymphony.xwork2.ActionContext類來完成上述操作。此類的getContext方法可以得到當前Action的上下文,也就是當前Action所處的容器環境,進而得到相關對象。

同時也可以使用org.apache.struts2.ServletActionContext類獲得,例如:

HttpServletRequest req=ServletActionContext.getRequest();

下麵更改前面的登錄操作,在登錄成功後,將登錄人員的信息保存到session範圍中,在index.jsp頁面中取出,我們可以重構我們的Action,在重構前,首先新增一個BaseAction,作為所有Action的父類,在其中增加方法獲取Servlet相關對象,這樣所有的子類都擁有了相應的方法。代碼如下:

package com.frank.action;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;
public class BaseAction extends ActionSupport {
    public HttpServletRequest request(){
        return ServletActionContext.getRequest();
    }
    public HttpServletResponse response(){
        return ServletActionContext.getResponse();
    }
    public ServletContext application(){
        return ServletActionContext.getServletContext();
    }
    public HttpSession session(){
        return ServletActionContext.getRequest().getSession();
    }
}
View Code

 

然後重構LoginAction,繼承自BaseAction,併在登錄成功後再session範圍保存用戶名信息,以便index.jsp讀取,重構後代碼如下:

package com.frank.action;

import com.opensymphony.xwork2.ActionSupport;
import com.frank.rule.User;
public class LoginAction extends BaseAction {

private User user;
@Override
public String execute() throws Exception {
if(user.login()){
this.session().setAttribute("username", user.getUsername());
return SUCCESS;
}
return INPUT;
}

@Override
public void validate() {
if(user.getUsername()==null||user.getUsername().trim().length()<1){
addFieldError("no.username","must input username");
}
if(user.getPassword()==null||user.getPassword().trim().length()<1){
addFieldError("no.password","must intpu password");
}

}
public User getUser() {
return user;
}

public void setUser(User user) {
this.user = user;
}

}
View Code

 

在index.jsp中增加讀取session中保存內容的代碼,如下:

<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0"> 
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>

<body>
<h1>Login Success!!!</h1>
<br>
<h1>Username:<%=session.getAttribute("username") %></h1>
</body>
</html>
View Code

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • SVG作為時下比較新穎的技術標準,已經建立了很多基於SVG的前端項目。由於SVG在繪製路徑上非常靈活,我們將很多網頁上的元素使用SVG來繪製而成,有各種人物、小圖標、小動畫等等。今天我們收集了18個非常新奇有趣的SVG繪製動畫,這些動畫大部分都是使用SVG結合一定的CSS3特性實現而成,效果讓人大為 ...
  • localStorage 本地存儲 、對象、存數據 、取數據 存儲的數據量在20M左右 localStorage 是window下麵的屬性,用的時候可以省略window 數據只能存儲字元串類型的 localStorage沒有過期時間,只要不刪除就永遠存在 同一個瀏覽器的不同視窗數據可以通用 不同的瀏 ...
  • 引言 JavaScript不區分整數值和浮點數值,全部使用浮點數值表示。當一個數字直接出現在JavaScript程式中,我們稱之為數字直接量(numeric litertal)。JavaScript支持多種格式的數字直接量。 整型直接量 在JavaScript程式中,用一個程式序列表示一個十進位整數 ...
  • 【背景】 如果你是剛進入WEB前端研發領域,想試試這潭水有多深,看這篇文章吧; 如果你是做了兩三年WEB產品前端研發,迷茫找不著提高之路,看這篇文章吧; 如果你是四五年的前端開發高手,沒有難題能難得住你的寂寞高手,來看這篇文章吧; WEB前端研發工程師,在國內是一個朝陽職業,自07-08年正式有這個 ...
  • 前言 最近在看《高性能網站建設》,記錄一下所學。 現在很多網站都是圖片形式的導航,點擊圖片跳轉到對應的鏈接。如果導航項目很多的話,圖片的數量就會很多,每需要載入一張圖片就會多一個HTTP請求。優化的方式之一就是使用圖片地圖 標簽 圖片地圖要用到map和area標簽 map標簽用於客戶端的圖片映射;a ...
  • 介面及面向介面編程 介面 介面的實現 ...
  • 前臺: 支持四套模版, 可以在後臺切換 系統介紹: 1.網站後臺採用主流的 SSM 框架 jsp JSTL,網站後臺採用freemaker靜態化模版引擎生成html 2.因為是生成的html,所以訪問速度快,輕便,對伺服器負擔小 3.網站前端採用主流的響應式佈局,同一頁面同時支持PC、平板、手機(三 ...
  • ​ 一、背景概述 (一)產品背景 1.互聯網+的需要 在信息越來越繁雜的互聯網時代,公司所運行的項目越來越多,項目相關服務繁多,服務之間存在複雜的依賴關係,運維與管理任務越來越繁重,手工交付需要花費很多的人力與時間,且安全性和時效性均無法保證。對於多資源型分佈/分離式部署項目,Udeployer應運 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...