Struts2學習總結(1)--基本原理,開發步驟,配置詳解
本文包括以下三個部分:
- 模擬Struts2框架,瞭解基本原理。
- Struts2的開發步驟。
- Struts2的配置詳解
一、模擬Struts2框架,瞭解基本原理
在學習Struts2框架以前,我們一直採用servlet進行網站的開發。最開始是一個功能使用一個servlet程式;後來建立BaseServlet進行簡化,可以實現一個模組使用一個servlet程式;為了開發更加快捷,程式碼更加簡潔,達到一個專案只使用一個servlet程式的目的,我們可以模擬一個簡易的Struts2框架,並在此基礎上了解Struts2的基本原理。
具體步驟如下:
1、建立一個模擬使用者等錄和註冊的專案。
2、編寫entity包程式碼。
User.java
package edu.scut.entity; //使用者 public class Users { private int id; private String name; private String password; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Users() { super(); // TODO Auto-generated constructor stub } public Users(int id, String name, String password) { super(); this.id = id; this.name = name; this.password = password; } @Override public String toString() { return "Users [id=" + id + ", name=" + name + ", password=" + password + "]"; } }
3、編寫dao層程式碼。
UserDao.java
4、編寫service層程式碼。package edu.scut.dao; import edu.scut.entity.Users; public class UserDao { //查詢使用者 public Users findByName(String name){ Users users = null; if("jack".equals(name)){ users = new Users(1,"jack","666666"); } return users; } //新增使用者 public void addUser(Users users){ System.out.println("註冊成功! "+users); } }
UserService.java
package edu.scut.service;
import edu.scut.dao.UserDao;
import edu.scut.entity.Users;
import edu.scut.exception.LoginFailureException;
public class UserService {
UserDao userDao = new UserDao();
//登入
public Users Login(Users users) throws LoginFailureException{
Users loginUsers = userDao.findByName(users.getName());
//判斷name
if(loginUsers == null){
throw new LoginFailureException("使用者不存在!");
}
//判斷密碼
if(!loginUsers.getPassword().equals(users.getPassword())){
throw new LoginFailureException("密碼錯誤!");
}
return loginUsers;
}
//註冊
public void Reg(Users users){
userDao.addUser(users);
}
}
5、編寫exception包程式碼。
LoginFailureException.java
package edu.scut.exception;
public class LoginFailureException extends Exception {
public LoginFailureException() {
super();
// TODO Auto-generated constructor stub
}
public LoginFailureException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public LoginFailureException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public LoginFailureException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
}
6、編寫web層程式碼。
UserAction.java
package edu.scut.web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import edu.scut.entity.Users;
import edu.scut.exception.LoginFailureException;
import edu.scut.service.UserService;
//使用者模組的操作類
public class UserAction {
UserService userService = new UserService();
//URL:userLogin.action
public String login(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String name = request.getParameter("name");
String password = request.getParameter("password");
//封裝成物件
Users users = new Users();
users.setName(name);
users.setPassword(password);
try {
//呼叫登入方法
Users loginUsers = userService.Login(users);
//如果登入成功,將資料儲存在域物件
request.getSession().setAttribute("loginInfo", loginUsers);
//主頁
return "success";
} catch (LoginFailureException e) {
//如果登入失敗,將資訊儲存在域物件
request.setAttribute("msg", e.getMessage());
return "fail";
}
}
//URL:userReg.action
public String reg(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//獲取表單資料
String name = request.getParameter("name");
String password = request.getParameter("password");
//封裝成物件
Users users = new Users();
users.setName(name);
users.setPassword(password);
//執行方法
userService.Reg(users);
//儲存資料
request.setAttribute("regSuc", "註冊成功,請登入!");
//跳轉到登入頁面
return "success";
}
}
7、編寫配置檔案mystruts.xml。
mystruts.xml
<?xml version="1.0" encoding="UTF-8"?>
<struts>
<!-- 登入請求 -->
<!-- name:請求名稱
class:執行的操作類類名
method:執行操作類的方法
-->
<action name="userLogin" className="edu.scut.web.UserAction" method="login">
<result name="fail" type="dispatcher">/login.jsp</result>
<result name="success" type="redirect">/index.jsp</result>
</action>
<!-- 註冊請求 -->
<action name="userReg" className="edu.scut.web.UserAction" method="reg" >
<result name="success" type="dispatcher">/login.jsp</result>
</action>
</struts>
8、編寫framework包程式碼。
8.1、編寫Action的對映類即,ActionMapping.java
package edu.scut.framework;
import java.util.List;
//action類
public class ActionMapping {
private String name;
private String className;
private String method;
private List<Result> results;
public List<Result> getResults() {
return results;
}
public void setResults(List<Result> results) {
this.results = results;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
}
8.2、建立結果檢視的類,即Result.java
package edu.scut.framework;
//檢視型別
public class Result {
private String name;
private String type;
private String path;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
8.3、編寫ActionServlet.java,讀取配置檔案:mystruts.xml,UserAction的訪問,以及結果檢視的跳轉。
package edu.scut.framework;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.management.RuntimeErrorException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2RTFDTM;
import com.sun.org.apache.xml.internal.resolver.helpers.FileURL;
import edu.scut.web.UserAction;
public class ActionServlet extends HttpServlet {
//在Action初始化時就載入配置檔案並且將其封裝成物件
//建立Map集合封裝actionMapping
Map<String, ActionMapping> actionMappings = null;
@Override
public void init() throws ServletException {
//建立actionMappings的例項
actionMappings = new HashMap<String, ActionMapping>();
try {
//讀取mystruts.xml檔案
SAXReader reader = new SAXReader();
//獲取檔案
Document doc = reader.read(ActionServlet.class.getResourceAsStream("/mystruts.xml"));
//獲取根元素
Element root = doc.getRootElement();
//獲取所有的action標籤
List<Element> actionElements = (List<Element>)root.selectNodes("//action");
//遍歷action集合
for (Element actionElement : actionElements) {
//獲取屬性值
String name = actionElement.attributeValue("name");
String className = actionElement.attributeValue("className");
String method = actionElement.attributeValue("method");
//建立actionMapping的物件
ActionMapping actionMapping = new ActionMapping();
actionMapping.setName(name);
actionMapping.setClassName(className);
actionMapping.setMethod(method);
//獲取action當中的result物件
List<Element> resultElements = actionElement.elements("result");
//建立resultElements集合
List<Result> resultList = new ArrayList<Result>();
//遍歷集合
for (Element resultElement : resultElements) {
//獲取屬性值
String resName = resultElement.attributeValue("name");
String resType = resultElement.attributeValue("type");
String resPath = resultElement.getText();
//建立Result物件
Result result = new Result();
result.setName(resName);
result.setType(resType);
result.setPath(resPath);
//封裝進集合
resultList.add(result);
}
//將結果集封裝進物件
actionMapping.setResults(resultList);
//將actionMapping封裝進actionMappings集合
actionMappings.put(name, actionMapping);
System.out.println("mystruts.xml檔案載入完畢!");
}
} catch (DocumentException e) {
//e.printStackTrace();
System.out.println("配置檔案載入失敗!");
throw new RuntimeException("配置檔案讀取失敗!");
}
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//url /userLogin.action
//1 得到路徑 /day27_01_mystruts2_test/userLogin.action
String uri = request.getRequestURI();
//2 擷取action的名字
String pathName = uri.substring(uri.lastIndexOf("/")+1, uri.lastIndexOf(".action"));
//3 根據action的名字獲取className
ActionMapping actionMapping = actionMappings.get(pathName);
//建立一個變數接受返回值
String FURL = null;
try {
//4 根據action獲取類名稱
String className = actionMapping.getClassName();
//5 根據className建立例項
//獲取位元組碼檔案
Class clazz = Class.forName(className);
//建立物件
Object actionClass = clazz.newInstance();
//6 獲取方法名稱,呼叫響應的方法
String method = actionMapping.getMethod();
Method m = clazz.getDeclaredMethod(method, HttpServletRequest.class,HttpServletResponse.class);
//7 呼叫方法
FURL = (String) m.invoke(actionClass, request,response);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//8 根據返回值字串返回響應的檢視
List<Result> results = actionMapping.getResults();
//遍歷集合
for (Result result : results) {
if(FURL.equals(result.getName())){
//獲取返回檢視的型別
String type = result.getType();
//獲取返回檢視的路徑
String path = result.getPath();
//9 判斷檢視的型別執行響應的結果
if(type.equals("dispatcher")){
//轉發
request.getRequestDispatcher(path).forward(request, response);
}else if(type.equals("redirect")){
//重定向
response.sendRedirect(request.getContextPath()+path);
}
}
}
//3 判斷執行響應的方法
/*if("userLogin".equals(pathName)){
UserAction userAction = new UserAction();
userAction.login(request, response);
}else if("userReg".equals(pathName)){
UserAction userAction = new UserAction();
userAction.reg(request, response);
}*/
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
9、配置ActionServlet.java的訪問路徑。
web.xml
<servlet>
<servlet-name>ActionServlet</servlet-name>
<servlet-class>edu.scut.framework.ActionServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ActionServlet</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
10、登入、註冊和主頁的jsp。
login.jsp:
<body>
<font color="red">${msg}</font>
<form action="${pageContext.request.contextPath }/userLogin.action" method="post">
<%--<form action="${pageContext.request.contextPath }/users?action=login" method="post">--%>
使用者名稱:<input type="text" name="name"><br>
密碼:<input type="password" name="password"><br>
<input type="submit" value="登入"/>
</form>
</body>
reg.jsp:
<body>
<form action="${pageContext.request.contextPath }/userReg.action" method="post">
<%-- <form action="${pageContext.request.contextPath }/users?action=reg" method="post">--%>
使用者名稱:<input type="text" name="name"><br>
密碼:<input type="password" name="password"><br>
<input type="submit" value="註冊"/>
</form>
</body>
index.jsp:
<body>
歡迎您,使用者名稱:${sessionScope.loginInfo.name }
</body>
11、訪問。
註冊:http://localhost:8080/day27_01_mystruts2_test/reg.jsp
登入:http://localhost:8080/day27_01_mystruts2_test/login.jsp
訪問之後的執行過程:
a. 建立ActionServlet例項;
b. 呼叫ActionServlet的init()方法;
c. 載入mystruts.xml配置檔案,根據action的name找到對應的action,用反射的方式,建立UserAction的例項,再根據method的名稱呼叫UserAction的同名方法;
d. 根據方法的返回值和result標籤的name屬性,找到result,實現頁面跳轉。
二、Struts2的開發步驟
1、導jar包。8個jar包。
2、配置struts2的核心過濾器。注意:在web.xml檔案中配置,該核心過濾器用於處理專案的所有請求。
<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>
3、編寫操作類。
package edu.scut.web;
//使用者操作類,表現層
public class UserAction {
//構造方法
public UserAction(){
System.out.println("useraction物件建立了!");
}
//userLogin.action
//登入方法
public String login(){
System.out.println("登入成功!");
return "success";
}
//userReg.action
public String reg(){
System.out.println("註冊成功!");
return "success";
}
}
4、編寫struts2的業務配置檔案。 注意:名稱一定為struts.xml,位置一定放在src目錄下。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<package name="user" extends="struts-default" namespace="/user">
<!-- 登陸的action -->
<action name="userLogin" class="edu.scut.web.UserAction" method="login">
<result name="success" type="redirect">/index.jsp</result>
</action>
<!-- 註冊的action -->
<action name="userReg" class="edu.scut.web.UserAction" method="reg">
<result name="success">/index.jsp</result>
</action>
</package>
</struts>
Struts2的執行過程:
a. 專案啟動時:
1)載入web.xml檔案,建立org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter核心過濾器物件
2)呼叫核心過濾器中的init方法
2.1 讀取default.properties 【struts2的預設常量檔案】
(struts2-core.jar: /org/apache/struts2/default.properties)
2.2 讀取struts-default.xml 【struts2的預設核心配置檔案】
(struts2-core.jar:/struts-default.xml)
2.3 讀取struts-plugin.xml 【struts2的插入配置檔案】
(一般不會用到)
2.4 讀取struts.xml 【struts2的業務配置檔案,開發時經常修改】
(專案的src:struts.xml)
b. 發出請求:
1)根據請求名稱,在struts.xml檔案中對應的action標籤(根據action的name屬性值)
2)查詢結果
失敗:
如果沒有匹配成功,則頁面丟擲There is no Action mapped 異常
成功:
2.1 根據action標籤的class的字串去建立一個Action(操作)類例項
2.2 根據action標籤的method去呼叫Action類裡面對應的方法
2.3 執行完操作方法後,返回一個檢視標記的字串
3)根據檢視標記字串在當前action標籤中查詢對應的result標籤(根據result的name屬性值)
4)找到對應的result,則跳轉到對應的頁面
三、Struts2的配置詳解
1、struts-default.xml : struts2的核心預設配置檔案
第一部分:建立struts2框架自身需要的物件
<bean class="com.opensymphony.xwork2.ObjectFactory" name="xwork" />
。。。。。。
第二部分:一個預設包
<package name="struts-default" abstract="true">
name: 包名稱
abstract: 抽象包
1) 定義struts2支援的檢視型別
<result-types>
<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
。。。。。
常用的檢視型別:
dispatcher: 轉發到頁面 (預設型別) (可以通過request帶資料)
redirect:重定向到頁面
chain:轉發到其他Action (可以通過request帶資料)
redirectAction:重定向到其他Action
stream: 以流的形式進行輸出 (用於檔案下載)
plainText:以純文字方法進行輸出 (ajax技術)
2) 定義了struts2的支援的攔截器
<interceptors>
<interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
。。。。。。
struts2除了基本功能以外,還提供瞭如下實用功能:
傳遞頁面引數資料
檔案上傳
國際化
資料共享
型別轉換
表單資料校驗
....
攔截器只能攔截action
過濾器可以攔截任何請求
3)定義了預設的攔截器棧
<interceptor-stack name="basicStack">
攔截棧中包含多個攔截器
4)定義當前包使用的預設攔截器
<default-interceptor-ref name="defaultStack"/>
當前包下的所有action都可以使用該攔截器棧下的所有攔截器
5)定義當前包的預設操作類
<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
當前包下的action如果不寫class就使用預設類
2、 struts.xml: 業務配置檔案
<package>:區分不用的action
name:包名。通常不同的包使用不同的名稱(如果同名則報錯)
extends:當前包的父包的包名。通常為struts-default預設包,繼承了struts-default預設包就可以使用該包下定義的元素。
namespace: 名稱空間(名稱空間),為了區分不同包的訪問路徑。
注意:
有了namespace後,action的訪問路徑必須帶上namespace。
<action> : 操作配置
name(必須): 請求名稱,通常同一個包下不要出現同名的action。
class(可選): 操作類的全名(包+類名),預設類:com.opensymphony.xwork2.ActionSupport。
method(可選): 執行的操作方法,預設方法:execute。
<result> : 檢視
name: 檢視名稱。跟操作方法返回的字串匹配, 預設值:success。(其他名稱都需要寫)
type:檢視型別, 預設值:dispatcher。
內容:跳轉路徑,如果是頁面必須帶斜槓,如果是action不需要。(沒有預設值)