Struts2
A.Model2模型
1.Model1模型
所謂的Model1模型,其實就是純JSP頁面
在JSP頁面上既寫Java代碼,又寫HTML代碼
2.Model2模型
在java web開發中,基於Servlet+JSP+JavaBean的開發模型稱爲Model2模型
該模型完全遵守MVC模式:
JavaBean
模型層,既可以封裝數據,又可作爲業務邏輯模型
接收到控制器傳遞的更新請求後,執行邏輯處理返回響應的執行結果
JSP
表現層,負責提供用戶數據顯示頁面
並在適當時候(提交表單)向控制器請求模型更新
Servlet
控制器,接收用戶請求,然後獲取數據並轉換爲業務模型需要的模型
然後調用模型的業務方法,請求模型更新
同時根據執行結果選擇返回的視圖頁面
3.基本流程
a.用戶發出一個request請求,會被控制器servlet接收到
b.servlet將請求的數據轉換成數據模型javabean,然後調用模型的邏輯方法
c.servlet把業務邏輯模型返回的結果放到合適的地方,譬如request的屬性裏
d.根據邏輯模型返回結果,servlet選擇合適的jsp視圖
e.jsp視圖展示數據給用戶
4.缺點
a.流程凌亂
servlet既要處理請求,還要處理頁面流程,功能不單一
無法把握整個系統的頁面流程b.數據傳遞無序
使用javabean傳遞數據比較繁瑣,有時候無法滿足需求
c.缺乏輔助功能
沒有統一的分發調度,驗證框架 ,國際化,異常處理等等功能
B.Struts2
1.概述
基於mvc的輕量級web應用框架
所謂框架就是完成了一定功能的半成品軟件
在框架的基礎上開發,效率和質量更高
struts2應用場景是web應用,對web服務器資源消耗少,運行速度快
struts2致力於在mode view controller的各個部分爲開發者提供幫助
2.功能
a.POJO表單及POJO操作
可以用任何一POJO來接收表單輸入,可以把任一POJO視爲一個Action
b.標籤支持
改進了標籤表單,新標籤可減少代碼編寫量
c.AJAX支持
把AJAX支持整合進其結果中
d.易於整合
Struts有多種整合方式可使用
如Spring、Tiles、SiteMesh之類的,整合更爲容易了
e.模板支持
支持使用模板生成視圖
f.插件支持
有大量的插件增強和擴大Struts2 核心行爲
g.性能分析
Struts2 爲調試和配置應用程序提供綜合的性能分析
此外也以嵌入調試工具的形式提供集成調試
h.易於修改標籤
可使用Freemarker的模板對標籤標記進行調整
基本的HTML、XML和CSS知識就足夠了
i.促進減少配置
Struts2使用各種設置默認值減少配置
j.視圖技術
Struts2 爲多種視圖選項(JSP、Freemarker、Velocity、XSLT等)提供支持
3.Sturts2和MVC
a.控制器:StrutsPrepareAndExecuteFilter
用戶請求首先到達該前端控制器
該過濾器負責根據用戶提交的URL和struts.xml中的配置
來選擇合適的動作(Action),讓這個Action來處理用戶的請求
該控制器其實是一個過濾器(Filter,servlet規範中的一種web組件)
是Struts2內置類,只是要在項目的web.xml中配置一下即可
b.動作:Action模型
在用戶請求經過核心過濾器處理之後,被分發到了合適的動作Action對象
Action負責把用戶請求中的參數組裝成合適的數據模型
並調用相應的業務邏輯進行真正的功能處理
獲取下一個視圖展示所需要的數據,實現了與Servlet API的解耦,
不需要再直接引用和使用HttpServletRequest與HttpServletResponse等接口
使得Action的單元測試更加簡單
而且強大的類型轉換也使得我們少做了很多重複的工作
c.視圖:Result
視圖結果用來把動作中獲取到的數據展現給用戶
在Struts2中有多種優秀的結果展示方式
常規的jsp,模板 freemarker、velocity
還有各種其它專業的展示方式
如圖表jfreechart、報表JasperReports、將XML轉化爲 HTML的XSLT等等
而且各種視圖結果在同一個工程裏面可以混合出現
C.使用步驟
1.從官網下載struts-2.5.10.1-all.zip
2.創建web項目
拷貝必須jar文件,放置在WEB-INF下的lib目錄中
(可以從官網下載struts-2.5.10.1-min-lib.zip)
3.在web.xml中添加核心控制器配置
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>Struts2</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <!-- 過濾器 --> <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>
4.創建對應jsp文件
a.login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>登陸頁面</title> </head> <body> <form action="loginAction"> 用戶名:<input type="text" name="username" /><br /> 密 碼:<input type="password" name="password" /><br /> <input type="submit" value="提交" /> </form> <span><font style="color: red;font-size: 20px;">${ msg }</font></span> </body> </html>
b.success.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>登陸成功</title> </head> <body> <span><font style="color: green;font-size: 20px;">${ username },歡迎您!!!</font></span> </body> </html>
5.創建對應的Action模型類
LoginAction
package org.xxxx.web; import org.apache.struts2.ServletActionContext; public class LoginAction { // 與jsp中的name一致 private String username; private String password; public LoginAction() { super(); } public LoginAction(String username, String password) { super(); this.username = username; this.password = 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() { if ("zhangsan".equals(username) && "123456".equals(password)) { // 調取域對象 ServletActionContext.getRequest().setAttribute("username", username); return "success"; } else { ServletActionContext.getRequest().setAttribute("msg", "用戶名或密碼錯誤!"); return "fail"; } } }
6.在項目的src目錄下創建struts.xml文件
在struts2框架中使用包來管理Action
包的作用和java中的類包是非常類似的
它主要用於管理一組業務功能相關的action
在實際應用中,我們應該把一組業務功能相關的Action放在同一個包下
<?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="struts2" extends="struts-default"> <!-- name和jsp的action相一致 --> <!-- method可以不寫,默認調用name中的execute方法 --> <action name="loginAction" class="org.xxxx.web.LoginAction" method="login"> <!-- 判斷返回值 --> <result name="success">/success.jsp</result> <result name="fail">/login.jsp</result> </action> </package> </struts>
啓動tomcat服務器,運行
7.架構圖
D.Action的使用
1.Action
代表一次請求或調用,對應於一個Action類
在Struts2裏面充當着MVC中模型的角色
既封裝了業務數據,又要處理業務功能
但在實際的JavaEE開發中,邏輯部分會放到邏輯層去實現
Action只是去調用邏輯層來進行業務邏輯的處理
Action中方法實現的功能,是MVC中控制器部分的功能
因爲過濾器作爲核心控制器,Action常看做model層
2.Action的實現方式
在Struts2中,Action可以不實現任何特殊的接口或者繼承特殊的類
僅僅是一個POJO(Plain Old Java Object,簡單的Java對象)就可以
但要有一個公共的無參的構造方法
還可以有一個返回String類型的execute或其他方法
SUCCESS:表示Action執行成功,顯示結果視圖給用戶,值爲字符串"success"
NONE:表示Action執行成功,不需要顯示視圖給用戶,值爲字符串"none"
ERROR:表示Action執行失敗,顯示錯誤頁面給用戶,值爲字符串"error"
INPUT:表示執行Action需要更多的輸入信息,回到input頁面,值爲字符串"input"
LOGIN:表示因用戶沒有登陸而沒有正確執行,返回該登陸視圖,值爲字符串"login"
也可以自己定義的字符串,只要你在Action裏面返回的字符串
跟在struts.xml裏面配置的result的name屬性值一樣就可以了。
如果struts.xml配置文件中Action沒有method屬性,則execute方法是必須的
但實際開發的時候,Action實現方式
a.實現Action接口
僅僅定義了前面的execute方法
除外還有一系列預定義的字符串常量
可以用於返回一些預定的result
User類
package org.xxxx.web; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 1L; private String username; private String password; public User() { super(); // TODO Auto-generated constructor stub } public User(String username, String password) { super(); this.username = username; this.password = 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
package org.xxxx.web; import com.opensymphony.xwork2.Action; public class OrtherAction implements Action { private User user; public OrtherAction() { super(); } public OrtherAction(User user) { super(); this.user = user; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } @Override public String execute() throws Exception { if (user.getUsername().equals("zhangsan") && user.getPassword().equals("123456")) { return SUCCESS; } return ERROR; } }
b.繼承ActionSupport類
除實現了Action接口,還提供更多輔助功能,推薦使用
package org.xxxx.web; import java.util.List; import com.opensymphony.xwork2.ActionSupport; public class AnotherAction extends ActionSupport { private static final long serialVersionUID = 1L; private String username; private String password; // 如果前臺有複選框,用集合或數組接收 private List<String> hobby; public AnotherAction() { super(); } public AnotherAction(String username, String password, List<String> hobby) { super(); this.username = username; this.password = password; this.hobby = hobby; } 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 List<String> getHobby() { return hobby; } public void setHobby(List<String> hobby) { this.hobby = hobby; } @Override public String execute() throws Exception { // 查看數組 System.out.println(hobby); if (username.equals("zhangsan") && password.equals("123456")) { return SUCCESS; } return ERROR; } }
3.Action獲取頁面數據
在Struts2中,頁面的數據傳遞給Action有兩種基本方式
屬性驅動(FieldDriven)和模型驅動(ModelDriven)。
屬性驅動又有兩種情況:(代碼參考上一條兩段代碼)
a.基本數據類型的屬性對應:控件的name屬性,和Action的屬性對應
b.JavaBean風格的域對象對應: 控件的name屬性是域對象.屬性名方式
4.後臺Action處理複選框
成員變量名必須和web頁面name相同(代碼參考上一條兩段代碼)
方案1: 定義一個私有String數組類型的屬性,提供相應的getter/setter方法
方案2: 定義一個私有集合類型的屬性,比如List類型的,提供相應的getter/setter方法
E.Struts.xml配置
1.constant常量
a.所有匹配*.action的請求都由struts2處理
<constant name="struts.action.extension" value="action" />
b.是否啓用開發模式
使用開發者模式,會顯示錯誤信息
在項目提交發布前,應該爲非開發者模式
<constant name="struts.devMode" value="true" />
c.struts配置文件改動後,是否重新加載
<constant name="struts.configuration.xml.reload" value="true" />
d.指定Web應用的默認Locale
<constant name="struts.locale" value="zh_CN"/>
e.請求參數的編碼方式
<constant name="struts.i18n.encoding" value="utf-8" />
f.每次HTTP請求系統都重新加載資源文件,有助於開發
<constant name="struts.i18n.reload" value="true" /
2.package
<package>元素把邏輯上相關的一組Action等元素封裝起來
形成一個獨立的模塊,可以繼承其他的package
也可以作爲父包被其他的package繼承
核心屬性:
name:包的名稱,必須配置
extends:配置的是被繼承的包名稱,可選
3.action
<action>元素是<package>元素的子元素,應該配置在<package>元素裏面
<action>元素通常需要配置name和class屬性,其中name是必須的
method屬性對應Action實現類中對應方法名
<action>元素可以包含其他的子元素:比如<param>、<result>
4.result
<result>元素可有name屬性和type屬性,都是可選的
name屬性:默認值success
Action運行後跳轉的下一個頁面名,可以是任意字符串
但必須和Action方法返回值一致
type屬性:默認值dispatcher
在struts-default.xml中所定義的<result-type>的name屬性的值或合法的自定義值
F.Interceptor攔截器
1.概述
是Struts2最強大的特性之一
是一種可以在Action執行之前和Result執行之後進行一些功能處理的機制
2.優點
a.簡化Action的實現
把很多功能從Action中獨立出來,大量減少了Action的代碼
b.功能更單一
把功能從Action中分離出來,分散到不同的攔截器
這樣每個攔截器以及Action的功能都更單一了
c.通用代碼模塊化
攔截器能把一些在多個Action中通用的代碼進行模塊化
封裝在一個或幾個攔截器裏面
d.提高重用性
攔截器實現了代碼模塊化過後,就可以對不同的Action
根據功能需要來配置相同的攔截器了
e.攔截器和Filter
有相似之處,但是Interceptor相比於Filter具有更強大的功能
比如攔截器與Servlet的API無關,比如攔截器可以訪問到值棧等等
3.預定義攔截器
把用戶請求中的參數值和Action的屬性做了一個對應
並且把請求中的參數賦值到了Action的屬性上
這個功能就是由缺省配置的攔截器來實現的
Struts2的預定義攔截器都定義在struts-default.xml文件的struts-default包內
例如params攔截器,把請求參數設置到相應的Action的屬性,並自動進行類型轉換
4.自定義攔截器
開發人員實現的攔截器, 實現接口com.opensymphony.xwork2.interceptor.Interceptor
核心方法intercept() 定義攔截器執行的處理方法,即要實現的功
invocation.invoke():繼續執行其他攔截器方法
其之前代碼,會在Action運行之前執行
之後代碼,會在Result運行之後執行
其返回值是要返回的Result字符串
攔截器
package org.xxxx.web; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; // 實現接口 public class MyInterceptor implements Interceptor { private static final long serialVersionUID = 1L; @Override public void destroy() { System.out.println("攔截器被銷燬"); } @Override public void init() { System.out.println("攔截器初始化"); } @Override public String intercept(ActionInvocation invocation) throws Exception { System.out.println("action執行之前"); // 放行 String result = invocation.invoke(); System.out.println("result運行之後"); return result; } }
Action
package org.xxxx.web; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport { private static final long serialVersionUID = 1L; private String username; private String password; public LoginAction() { super(); // TODO Auto-generated constructor stub } public LoginAction(String username, String password) { super(); this.username = username; this.password = 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; } @Override public String execute() throws Exception { if ("zhangsan".equals(username) && "123456".equals(password)) { // 調取域對象 ServletActionContext.getRequest().setAttribute("username", username); return SUCCESS; } else { ServletActionContext.getRequest().setAttribute("msg", "用戶名或密碼錯誤!"); return ERROR; } } }
Sturts.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="struts2" extends="struts-default"> <!-- 攔截器 --> <interceptors> <interceptor name="myInterceptor" class="org.xxxx.web.MyInterceptor"></interceptor> </interceptors> <action name="loginAction" class="org.xxxx.web.LoginAction"> <result name="success">/success.jsp</result> <result name="error">/login.jsp</result> <!-- 添加攔截器 --> <interceptor-ref name="myInterceptor"></interceptor-ref> <interceptor-ref name="defaultStack"></interceptor-ref> </action> </package> </struts>
啓動tomcat服務器,查看控制檯信息
執行,查看控制檯信息
5.應用
使用攔截器實現登錄檢查,沒有登錄直接返回登錄頁面
分析:
要實現登錄檢查的功能
很明顯是在Action運行之前
就要判斷用戶是否登陸了
判斷方式是看session裏面是否有相關信息
如果有,則繼續操作;如果沒有,則要跳轉到預先制定好的登錄頁面
只有部分Action需要登陸錄檢查,另外一些Action(登陸)不需要
對於大多數Action都要進行登錄檢查的包
可以在包的默認攔截器引用上設置登錄檢查
而對於少數不需要登陸檢查的Action
可以讓它們直接引用默認的defaultStack攔截器棧
在之前基礎上添加以下代碼
LoginAction
package org.xxxx.web; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport { private static final long serialVersionUID = 1L; private String username; private String password; public LoginAction() { super(); } public LoginAction(String username, String password) { super(); this.username = username; this.password = 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; } @Override public String execute() throws Exception { if ("zhangsan".equals(username) && "123456".equals(password)) { // 封裝信息 LoginAction la = new LoginAction(username, password); // 存入session域中 ServletActionContext.getRequest().getSession().setAttribute("la", la); return SUCCESS; } else { ServletActionContext.getRequest().setAttribute("msg", "用戶名或密碼錯誤!"); return ERROR; } } }
AnotherAction.java
package org.xxxx.web; import com.opensymphony.xwork2.ActionSupport; public class AnotherAction extends ActionSupport { private static final long serialVersionUID = 1L; @Override public String execute() throws Exception { return SUCCESS; } }
another.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>其他頁面</title> </head> <body> 其他的展示信息頁面 </body> </html>
攔截器
package org.xxxx.web; import java.util.Map; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; // 實現接口 public class MyInterceptor implements Interceptor { private static final long serialVersionUID = 1L; @Override public void destroy() { } @Override public void init() { } @Override public String intercept(ActionInvocation invocation) throws Exception { // Struts2對Session封裝爲Map格式 // 獲取session對象 Map<String, Object> map = invocation.getInvocationContext().getSession(); // la鍵值對是否存在 if (map.get("la") == null) { // 不存在,跳轉登錄頁面 return "login"; } else { // 已登陸,放行 return invocation.invoke(); } } }
struts.xml
啓動tomcat,先在地址欄訪問/anotherAction,跳轉到登錄頁面<?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> <!-- 開發者模式 --> <constant name="struts.devMode" value="true"></constant> <package name="struts2" extends="struts-default"> <!-- 過濾器 --> <interceptors> <!-- 自定義攔截器 --> <interceptor name="myInterceptor" class="org.xxxx.web.MyInterceptor"></interceptor> <!-- 將自定義攔截器和預定義攔截器合在一起,調用方便 --> <interceptor-stack name="myStack"> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="myInterceptor"></interceptor-ref> </interceptor-stack> </interceptors> <!-- 默認攔截器聲明,對package範圍Action均生效 --> <default-interceptor-ref name="myStack"></default-interceptor-ref> <!-- package級別的Result,對所有Action均生效 --> <global-results> <!-- 沒有登陸,都去登錄頁面 --> <result name="login">/login.jsp</result> </global-results> <!-- 沒有method屬性,則默認調用Action的execute方法 --> <action name="loginAction" class="org.xxxx.web.LoginAction"> <result>/success.jsp</result> <result name="error">/login.jsp</result> <!-- 登陸Action不應被自定義攔截,只被預定義攔截 --> <interceptor-ref name="defaultStack"></interceptor-ref> </action> <!-- 其他頁面 --> <action name="anotherAction" class="org.xxxx.web.AnotherAction"> <result>/another.jsp</result> </action> </package> </struts>
如果先登錄成功,session域中就有數據
就無法驗證攔截,需要重啓瀏覽器和服務器
G.ONGL
1.概述
Object-Graph Navigation Language對象圖導航語言
是一種功能強大的表達式語言,通過簡單的語法
可以任意存取對象的屬性或者調用對象的方法
能夠遍歷整個對象的結構圖,實現對象屬性類型的轉換等功能
OGNL的計算是圍繞OGNL上下文進行的
上下文實際上是一個Map對象,裏面可以存放很多個JavaBean對象
OGNL上下文它有一個根對象
上下文中的根對象可以直接使用名稱來訪問它的屬性值
否則要加前綴“#key”
2.Struts
a.ActionContext
Action的上下文,是數據中心,充當OGNL的context
b.ValueStack
值棧,本質是一個ArrayList,充當ognl的root
當Struts2接受一個請求時
會迅速創建ActionContext,ValueStack,action
然後把action存放進ValueStack
OGNL會設定一個根對象,在Struts2中根對象就是ValueStack
要訪問ValueStack中對象的屬性,直接訪問即可
訪問上下文(Context)中的對象需要使用#符號標註命名空間
如#application、#session
改變上面的LoginAction和success.jsp代碼
LoginAction
package org.xxxx.web; import java.util.ArrayList; import java.util.List; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport { private static final long serialVersionUID = 1L; private String username; private String password; public LoginAction() { super(); } public LoginAction(String username, String password) { super(); this.username = username; this.password = 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; } @Override public String execute() throws Exception { List<LoginAction> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { LoginAction la = new LoginAction(); la.setUsername("user" + i); la.setPassword("pass" + i); list.add(la); } ServletActionContext.getRequest().setAttribute("la", list); return SUCCESS; } }
success.jsp
別忘了添加taglib標籤
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib prefix="s" uri="/struts-tags"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>登陸成功</title> </head> <body> <center> <table> <s:iterator value="#request.la" var="u"> <tr> <td style="border: 1px solid black;"><s:property value="#u.username" /></td> <td style="border: 1px solid black;"><s:property value="#u.password" /></td> </tr> </s:iterator> </table> </center> </body> </html>
struts.xml(上面的最近的一個struts.xml拿來就能用)
運行
H.Maven搭建Struts2項目
依賴dependency座標
<groupId>org.apache.struts</groupId> <artifactId>struts2-core</artifactId> <version>2.5.10.1</version>