首先咱們先來直接配置,而後再來說原理:
第一步:jar包的引入:
咱們能夠到struts2的官網上下載:
http://struts.apache.org/download.cgi#struts2513css
而後解壓將裏面的app文件夾下的示例war文件解壓,將裏面的struts.xml複製到咱們新建立的src目錄下(特別說一下,struts2最新的Struts 2.5.13版本壓縮包裏面沒有示例的blank示例文件,我是在2.3.34裏面得到的)
配置文件大概是這樣的:html
<?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並無那麼複雜。java
第二步,咱們須要在web.xml中配置過濾器,將struts組件插入進來。
配置文件大概是這樣:web
<?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文件:apache
<%@ 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中,啓動。tomcat
而後用瀏覽器訪問:
http://localhost:8080/testStruts2/hello
瀏覽器就會跳轉到咱們寫好的Hello.jsp頁面。安全
咱們接着講原理:服務器
首先,瀏覽器發出一個url,這個url首先發送到服務器,也就是咱們的tomcat,發到tomcat事後,將交給web.xml,而後進入過濾器,經過過濾器將這個請求發送給StrutsPrepareAndExecuteFilter來處理,StrutsPrepareAndExecuteFilter調用主配置文件struts.xml中的namespace看是否與namespace吻合,找到與之吻合的package,而後找對應的action的name,而後轉到對應的頁面。app
其實上面過程還省略了一些過程:
就是一個請求到了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}找到對應的方法。
是否是很簡便?(這樣的作法叫作約定優於配置)
咱們怎麼樣用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對象 @Override public 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後邊介紹)。 未完待續。。