首先我們先來直接配置,然后再來講原理:?
第一步:jar包的引入:?
我們可以到struts2的官網上下載:?
http://struts.apache.org/download.cgi#struts2513
然后解壓將里面的app文件夾下的示例war文件解壓,將里面的struts.xml復制到我們新創建的src目錄下(特別說一下,struts2最新的Struts 2.5.13版本壓縮包里面沒有示例的blank示例文件,我是在2.3.34里面獲得的)
配置文件大概是這樣的:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd"> <struts><constant name="struts.enable.DynamicMethodInvocation" value="false" /><constant name="struts.devMode" value="true" /><package name="default" namespace="/" extends="struts-default"><action name="hello"><result>/Hello.jsp</result></action></package> </struts>
?以上的配置文件是經過我的修改的,所以比較簡潔,因為我們第一步實現action并沒有那么復雜。
第二步,我們需要在web.xml中配置過濾器,將struts組件插入進來。?
配置文件大概是這樣:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"><display-name>testStruts2</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.ng.filter.StrutsPrepareAndExecuteFilter</filter-class></filter><filter-mapping><filter-name>struts2</filter-name><url-pattern>/*</url-pattern></filter-mapping> </web-app>
然后我們在根目錄下創建一個jsp文件:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html><head><base href="<%=basePath%>"><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>hello<br></body> </html>
里面不需要太多東西,我們只是做一個簡單的測試。
然后我們將項目部署到tomcat中,啟動。
然后用瀏覽器訪問:?
http://localhost:8080/testStruts2/hello?
瀏覽器就會跳轉到我們寫好的Hello.jsp頁面。
我們接著講原理:
首先,瀏覽器發出一個url,這個url首先發送到服務器,也就是我們的tomcat,發到tomcat過后,將交給web.xml,然后進入過濾器,通過過濾器將這個請求發送給StrutsPrepareAndExecuteFilter來處理,
StrutsPrepareAndExecuteFilter調用主配置文件struts.xml中的namespace看是否與namespace吻合,找到與之吻合的package,然后找對應的action的name,然后轉到對應的頁面。
其實上面過程還省略了一些過程:?
就是一個請求到了action的name的時候并不會直接轉到我們的頁面,而是會轉到action對應的類,
上面的struts省略了這一步,但是struts2幫我們默認執行了這一個過程,如果我們補充這個過程的話應該這樣:
<action name="hello" class="testStruts2.HelloAction">
package testStruts2;import com.opensymphony.xwork2.ActionSupport;public class HelloAction extends ActionSupport{public String execute() {return SUCCESS;} }
在struts2的主配置文件action中添加一個class=“”,并在項目的testStruts2中添加一個action類,這個action類可以有三種方法來寫,但是都要包含execute方法。?
我們給出剩下的兩種action類書寫方式:
package testStruts2;import com.opensymphony.xwork2.ActionSupport;public class HelloAction{public String execute() {return "success";} }
package testStruts2;import com.opensymphony.xwork2.ActionSupport;public class HelloAction implements Action{public String execute() {return SUCCESS;} }
以上的兩種方法,一個是不繼承和實現任何方法,但是包含一個execute方法,返回一個success字符串,另一個實現Action方法,返回SUCCESS。
Action里面已經封裝了一些變量,所以實現這個接口的類可以直接返回SUCCESS,同時我們還要知道ActionSupport也實現了Action,并且里面還封裝了大量的方法,這個以后我們將慢慢用到。
以上三種action書寫方式,建議使用第一種,因為我們以后將要經常使用到ActionSupport里面封裝的方法。
經過上面這個的Action返回一個success,然后StrutsPrepareAndExecuteFilter,將action里面的result里的頁面返回給瀏覽器。
?
如果留意的同學,還會發現我們從官網下載下來的blank范例里面action里面還有些其他的屬性,對就是method。
動態方法調用:
定義一個action并不一定實現Action接口,同時也可以不執行execute方法,我們只要將action里面的method屬性改為要執行的方法就行,就像這樣:
<action name="hello" class="testStruts2.HelloAction" method="ADD">
同時我們action里面的方法也要改為ADD,但是返回值類型一定要為String
package testStruts2; public class HelloAction {public String ADD() {return "success";} }
這樣對于不同的請求,我們可以根據需要在同一個Action類中用不同的方法處理。?
這樣可以減少創建Action類,并且安全,但是也會造成一個Action類太過龐雜。?
動態方法調用有三種方式,上面的算式一種。
?
繼續我們來說第二種:?
用“!”嘆號方式(不推薦使用)?
這種方法怎么使用呢?
<action name="helloadd" class="testStruts2.HelloAction" ><result>/Hello.jsp</result> </action>
就是這樣,理論上我們再Action類中含有execute方法不會產生什么影響,但是如果我們將Action類中的方法改為String Add()呢?
就會報錯,所以就用到可!了,我們的url地址應該為:
http://localhost:8080/testStruts2/hello/helloadd!ADD
這樣就會找到ADD方法了。
但是還要注意一點的是我們要將動態方法調用打開:
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
這里默認是關閉的,我們將它改為true就行了。
第三種就是通配符配置了:?
首先我們需要將上面的DMI改為false(不改也可以運行,但是建議改)。
<action name="hello_*" class="testStruts2.HelloAction" method="{1}"><result>/Hello_{1}.jsp</result></action>
然后就是這樣:用*代替未知的url
這里的{1}表示第一個 * 代表的內容 使用通配符可能有好幾個 * ,我們可以根據*的順序用{2}{3}…依次表示
http://localhost:8080/testStruts2/hello/hello_ADD.action用這個url來訪問我們的ADD方法,
當我們需要其他DELETE(刪除的時候)?
只需要輸入http://localhost:8080/testStruts2/hello/hello_DELETE.action?
并在Action類里面添加DELETE方法和添加響應的Hello_DELETE.jsp頁面。
使用通配符簡化了我們好多的配置,原來需要在配置文件中配置好多個action,現在只需要用通配符就可以解決這些,只需要添加響應的Action類(方法)和jsp頁面就行了。
?
<action name="*_*" class="testStruts2.{1}HelloAction" ><result> /{1}_{2}_hello.jsp</result> </action>
?
上面的是兩個通配符的范例,如果請求是這樣:
http://localhost:8080/testStruts2/hello/hello_DELETE.action
它就能夠根據{1}找到對應的Action類,根據{2}找到對應的方法。
是不是很簡便?(這樣的做法叫做約定優于配置)?
?
action接收參數:
? 我們怎么樣用struts接受客戶端發過來的參數呢?下面列舉四種方法:?
①屬性參數輸入
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd"> <struts><constant name="struts.enable.DynamicMethodInvocation" value="false" /><constant name="struts.devMode" value="true" /><package name="default" namespace="/" extends="struts-default"><action name="user" class="testStruts1.userAction"><result>/user.jsp</result></action></package> </struts>
上面是配置文件,沒什么好說的,和之前大同小異。?
我們接下來看看Action類:
package testStruts1;import com.opensymphony.xwork2.ActionSupport;public class userAction extends ActionSupport{String username;public userAction() {}public userAction(String username) {super();this.username = username;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String execute() {System.out.println(username);return SUCCESS;} }
首先這個類要符合javabean的命名規則,我們再Action類中添加了一個username屬性,并含有它的set get方法,并在execute里面將接收到的username輸出到控制臺來證實實驗。
當我們將項目部署到服務器上后,在瀏覽器中輸入一下URl:?
http://localhost:8080/testStruts1/user.action?username=aa?
控制臺便會將接受到的username參數輸出。
我們可以看到上面使用Action類的屬性來接收參數的,struts通過我們給出的set get 方法幫助我們完成賦值。
②同樣我們也可以定義一個實體類來來接收這些信息(官方叫DomainModel):?
例如?
這個是我們提交的信息:
<form action="login" method="post">用戶名:<input type="text" name="user.username"><br>密碼<input type="password" name="user.password"><br><input type="submit" value="登錄"></form> /*input里面一定要使用user.username和user.password和實體類對應,或者使用struts2提供的標簽,否則會出錯(不要問我是怎么知道的 哭臉.jpg)*/
這個是實體類:
package entity;public class User {String username;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;} }
package testStruts1;import com.opensymphony.xwork2.ActionSupport;import entity.User;public class userAction extends ActionSupport{User user;//不需要new對象,struts2幫我們完成了public User getUser() {return user;}public void setUser(User user) {this.user = user;}public String execute() {if(user.getUsername().equals("username")&&user.getPassword().equals("password")) {return SUCCESS;}return ERROR;} }
/*struts.xml*/<action name="login" class="testStruts1.userAction"><result name="success">/user.jsp</result><result name="error">/error.jsp</result></action>
?③還有一種使用DTO(date transfer object)數據傳輸對象來進行傳輸。?
這種方式主要是應對提交的參數和我們的實體對象不匹配的狀況:
比如用戶注冊的時候會輸入第二次密碼來進行確認,我們將接受兩個密碼,所以在這個類中我們接收三個參數:username ,password,confirmPassword。?
然后在Action類的execute方法中使用DTO對象來對User對象進行賦值:
User user = new User();//這里就需要我們實例化了,因為struts實例化的機會被下面的玩意搶了。 DTO dto ;public String execute(){user.setUserName(dto.getUserName()); user.setUserPassword(dto.getUserPassword()); //后面再利用user實例來進行一系列的操作。 }
當然現在我們有更為先進的技術就是我們完全可以用js來在客戶端確認是否相同,然后將數據傳輸過來。
?
④還有一種叫方法:ModelDriven
public class userAction extends ActionSupport implements ModelDriven<User>{User user = new User();//這里需要自己new對象 @Overridepublic User getModel() {return user;}public void setUser(User user) {this.user = user;}public User getModel() {return user;}public String execute() {if(user.getUsername().equals("username")&&user.getPassword().equals("password")) {return SUCCESS;}return ERROR;} }
就是這樣,實現ModelDriven接口,并實現getModel方法,直接獲得這個模型對象user。怎么實現這樣的原理的呢?
是通過一個缺省的攔截器ModelDrivenInterceptor這里面判斷一個Action對象是否實現ModelDriven,如果實現就返回這個User對象,并將User對象push到valueStack中(valueStack后邊介紹)。
?
?
版權聲明:本文為博主原創文章,如需轉載請表明出處。 https://blog.csdn.net/qq_39266910/article/details/78485739
?