1. 程式人生 > >Struts2學習總結(1)--基本原理,開發步驟,配置詳解

Struts2學習總結(1)--基本原理,開發步驟,配置詳解

本文包括以下三個部分:

  1. 模擬Struts2框架,瞭解基本原理。
  2. Struts2的開發步驟。
  3. 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

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);
	}
}
         4、編寫service層程式碼。

              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不需要。(沒有預設值)