1. 程式人生 > >Java進階學習第十五天(Struts框架)

Java進階學習第十五天(Struts框架)

一、自定義一個Struts框架

1、MVC模式包括
Model:模型
View:檢視
Control:控制器

2、傳統mvc開發總結
① 跳轉程式碼寫死,不靈活
② 每次都去寫servlet,要web.xml中配置servlet!

3、自定義一個Struts框架
① 配置檔案mystruts.xml

<?xml version="1.0" encoding="UTF-8"?>
<mystruts>
	<package>
		<!-- 配置請求路徑,與處理action類的關係,處理方法 -->
		<action name="login" class="cn.itcast.framework.action.LoginAction" method="login">
			<result name="loginSuccess" type="redirect">/index.jsp</result>
			<result name="loginFaild">/login.jsp</result>
		</action>
		
		<action name="register" class="cn.itcast.framework.action.RegisterAction" method="register">
			<result name="registerSuccess">/login</result>
			<result name="registerFaild">/login</result>
		</action>	
	</package>
</mystruts>

② ActionServlet.java

/**
 * 核心控制器,此專案只有這一個servlet
 * 1. 攔截所有的*.action為字尾的請求
 * 2. 請求:http://localhost:8080/mystruts/login.action
 * 		  http://localhost:8080/mystruts/register.action
 */
public class ActionServlet extends HttpServlet{
	private ActionMappingManager actionMappingManager;
	// 只執行一次,第一次訪問時候執行  (希望啟動時候執行)
	@Override
	public void init() throws ServletException {
		System.out.println("1111111111111111ActionServlet.init()");
		actionMappingManager = new ActionMappingManager();
	}

	// http://localhost:8080/mystruts/login.action
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
		try {
			// 1. 獲取請求uri, 得到請求路徑名稱   【login】
			String uri = request.getRequestURI();
			// 得到 login
			String actionName=uri.substring(uri.lastIndexOf("/")+1, uri.indexOf(".action"));
			// 2. 根據路徑名稱,讀取配置檔案,得到類的全名   【cn..action.LoginAction】
			ActionMapping actionMapping = actionMappingManager.getActionMapping(actionName);
			String className = actionMapping.getClassName();
			// 當前請求的處理方法   【method="login"】
			String method = actionMapping.getMethod();
			// 3. 通過反射:建立物件,呼叫方法;獲取方法返回的標記
			Class<?> clazz = Class.forName(className);
			Object obj = clazz.newInstance();  //LoginAction loginAction = new LoginAction();
			Method m = clazz.getDeclaredMethod(method, HttpServletRequest.class,HttpServletResponse.class );
			// 呼叫方法返回的標記
			String returnFlag =  (String) m.invoke(obj, request, response);
			// 4. 拿到標記,讀取配置檔案得到標記對應的頁面、跳轉型別
			Result result = actionMapping.getResults().get(returnFlag);
			// 型別
			String type = result.getType();
			// 頁面
			String page = result.getPage();
			// 跳轉
			if ("redirect".equals(type)) {
				response.sendRedirect(request.getContextPath() + page);
			} else {
				request.getRequestDispatcher(page).forward(request, response);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		doGet(req, resp);
	}
}

③ Result.java、ActionMapping.java、ActionMappingManager.java

/**
 * 封裝結果檢視
 * <result name="success" type="redirect">/index.jsp</result>
 */
public class Result {
	// 跳轉的結果標記
	private String name;
	// 跳轉型別,預設為轉發;"redirect"為重定向
	private String type;
	// 跳轉的頁面
	private String page;
	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 getPage() {
		return page;
	}
	public void setPage(String page) {
		this.page = page;
	}
}
/**
 * 封裝action節點
 *      <action name="login" class="cn.itcast.framework.action.LoginAction" method="login">
 *			<result name="success" type="redirect">/index.jsp</result>
 *			<result name="loginFaild">/login.jsp</result>
 *		</action>
 */
public class ActionMapping {
	// 請求路徑名稱
	private String name;
	// 處理aciton類的全名
	private String className;
	// 處理方法
	private String method;
	// 結果檢視集合
	private Map<String,Result> 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;
	}
	public Map<String, Result> getResults() {
		return results;
	}
	public void setResults(Map<String, Result> results) {
		this.results = results;
	}
}
/**
 * 載入配置檔案, 封裝所有的整個mystruts.xml
 */
public class ActionMappingManager {
	// 儲存action的集合
	private Map<String,ActionMapping> allActions ;
	public ActionMappingManager(){
		allActions = new HashMap<String,ActionMapping>();
		// 初始化
		this.init();
	}
	
	/**
	 * 根據請求路徑名稱,返回Action的對映物件
	 * @param actionName   當前請求路徑
	 * @return             返回配置檔案中代表action節點的AcitonMapping物件
	 */
	public ActionMapping getActionMapping(String actionName) {
		if (actionName == null) {
			throw new RuntimeException("傳入引數有誤,請檢視mystruts.xml配置的路徑。");
		}
		ActionMapping actionMapping = allActions.get(actionName);
		if (actionMapping == null) {
			throw new RuntimeException("路徑在mystruts.xml中找不到,請檢查");
		}
		return actionMapping;
	}
	
	// 初始化allActions集合
	private void init() {
		/********DOM4J讀取配置檔案***********/
		try {
			// 1. 得到解析器
			SAXReader reader = new SAXReader();
			// 得到src/mystruts.xml  檔案流
			InputStream inStream = this.getClass().getResourceAsStream("/mystruts.xml");
			// 2. 載入檔案
			Document doc = reader.read(inStream);
			// 3. 獲取根
			Element root = doc.getRootElement();
			// 4. 得到package節點
			Element ele_package = root.element("package");
			// 5. 得到package節點下所有的action子節點
			List<Element> listAction = ele_package.elements("action");
			// 6.遍歷 ,封裝
			for (Element ele_action : listAction) {
				// 6.1 封裝一個ActionMapping物件
				ActionMapping actionMapping = new ActionMapping();
				actionMapping.setName(ele_action.attributeValue("name"));
				actionMapping.setClassName(ele_action.attributeValue("class"));
				actionMapping.setMethod(ele_action.attributeValue("method"));
				// 6.2 封裝當前aciton節點下所有的結果檢視
				Map<String,Result> results = new HashMap<String, Result>();
				// 得到當前action節點下所有的result子節點
				 Iterator<Element> it = ele_action.elementIterator("result");
				 while (it.hasNext()) {
					 // 當前迭代的每一個元素都是 <result></result>
					 Element ele_result = it.next();
					 // 封裝物件
					 Result res = new Result();
					 res.setName(ele_result.attributeValue("name"));
					 res.setType(ele_result.attributeValue("type"));
					 res.setPage(ele_result.getTextTrim());
					 // 新增到集合
					 results.put(res.getName(), res);
				 }
				// 設定到actionMapping中
				actionMapping.setResults(results);
				// 6.x actionMapping新增到map集合
				allActions.put(actionMapping.getName(), actionMapping);
			}			
		} catch (Exception e) {
			throw new RuntimeException("啟動時候初始化錯誤",e);
		}
	}
}

④ LoginAction.java、RegisterAction.java

/**
 * Action表示動作類 1. 一個servlet對應一個action 2. action中負責處理具體的請求
 */
public class LoginAction {	
	public Object execute(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
		return null;
	}

	/**
	 * 處理登陸請求
	 */
	public Object login(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		Object uri = null;

		// 1. 獲取請求資料,封裝
		String name = request.getParameter("name");
		String pwd = request.getParameter("pwd");
		User user = new User();
		user.setName(name);
		user.setPwd(pwd);

		// 2. 呼叫Service
		UserService userService = new UserService();
		User userInfo = userService.login(user);
		// 3. 跳轉
		if (userInfo == null) {
			// 登陸失敗
			// request.getRequestDispatcher("/login.jsp").forward(request,response);
			// uri = request.getRequestDispatcher("/login.jsp");
			uri = "loginFaild";   // loginFaild  = /login.jsp
		} else {
			// 登陸成功
			request.getSession().setAttribute("userInfo", userInfo);
			// 首頁
			// response.sendRedirect(request.getContextPath() + "/index.jsp");
			// uri = "/index.jsp";
			uri = "loginSuccess";  // loginSuccess = /index.jsp
		}
		return uri;
	}
}
public class RegisterAction {
	public Object register(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
		Object uri;

		// 1. 獲取請求資料,封裝
		String name = request.getParameter("name");
		String pwd = request.getParameter("pwd");
		User user = new User();
		user.setName(name);
		user.setPwd(pwd);

		// 2. 呼叫Service
		UserService userService = new UserService();
		userService.register(user);
		// 3. 跳轉
		// request.getRequestDispatcher("/login.jsp").forward(request, response);
		//uri = request.getRequestDispatcher("/login.jsp");
		return "registerSuccess"; //返回註冊的標記;   registerSuccess = /login.jsp
	}
}

二、基於MVC模式的應用框架之Struts

1、Struts就是基於mvc模式的框架!
struts其實也是servlet封裝,提高開發效率!

2、Struts開發步驟
① web專案,引入struts - jar包8個jar檔案
② web.xml中,引入struts的核心功能配置過濾器

<!-- 引入struts核心過濾器 -->
	<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>

注意:如果引用其他攔截器一定要放在Struts攔截器上面
③ 開發action

// 開發action: 處理請求
public class HelloAction extends ActionSupport {
	// 處理請求
	public String execute() throws Exception {
		System.out.println("訪問到了action,正在處理請求");
		System.out.println("呼叫service");
		return "success";
	}
}

④ 配置actionsrc/struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
          "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
    <package name="xxxx" extends="struts-default">
    	<action name="hello" class="cn.itcast.action.HelloAction" method="execute">
    		<result name="success">/success.jsp</result>
    	</action>
    </package> 
</struts>

三、Struts框架學習

1、框架學習概述
SSH框架在mvc模式的的位置作用:
SSH

2、框架:
軟體中的框架,是一種半成品; 我們專案開發需要在框架的基礎上進行!
因為框架已經實現了一些功能,這樣就可以提高開發效率!

3、Struts2框架
① Struts1最早的一種基於mvc模式的框架
② Struts2 是在Struts1的基礎上,融合了xwork的功能
也可以說,Struts2 = struts1 + xwork

4、Struts2框架預先實現了一些功能:
① 請求資料自動封裝
② 檔案上傳的功能
③ 對國際化功能的簡化
④ 資料效驗功能
……

5、Struts2(版本: 2.3)開發流程【重點】
① 引入jar檔案
◆ commons-fileupload-1.2.2.jar 【檔案上傳相關包】
◆ commons-io-2.0.1.jar
◆ struts2-core-2.3.4.1.jar 【struts2核心功能包】
◆ xwork-core-2.3.4.1.jar 【Xwork核心包】
◆ ognl-3.0.5.jar 【Ognl表示式功能支援表】
◆ commons-lang3-3.1.jar 【struts對java.lang包的擴充套件】
◆ freemarker-2.3.19.jar 【struts的標籤模板庫jar檔案】
◆ javassist-3.11.0.GA.jar 【struts對位元組碼的處理相關jar】
② 配置web.xml
Tomcat啟動 > 載入自身web.xml > 載入所有專案的web.xml
通過在專案的web.xml中引入過濾器,Struts的核心功能的初始化,通過過濾器完成( filter 【init/ doFilter/ destroy】)

<!-- 引入struts核心過濾器 -->
	<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>

struts2-core-2.3.4.1.jar
StrutsPrepareAndExecuteFilter 即為核心過濾器
注意:使用的struts的版本不同,核心過濾器類是不一樣的!
③ 開發Action
注意:
◆ action類,也叫做動作類,一般繼承ActionSupport類,即處理請求的類 (struts中的action類取代之前的servlet)
◆ action中的業務方法,處理具體的請求( 必須返回String、方法不能有引數)

public class HelloAction extends ActionSupport {
	// 處理請求
	public String execute() throws Exception {}
}

④ 配置struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
          "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
    <package name="xxxx" extends="struts-default">
    	<action name="hello" class="cn.itcast.action.HelloAction" method="execute">
    		<result name="success">/success.jsp</result>
    	</action>
    </package> 
</struts>

6、Struts2執行流程
① 伺服器啟動:
◆ 載入專案web.xml
◆ 建立Struts核心過濾器物件, 執行filter > init()
struts-default.xml:核心功能的初始化
struts-plugin.xml:struts相關外掛
struts.xml:使用者編寫的配置檔案
② 訪問:
◆ 使用者訪問Action, 伺服器根據訪問路徑名稱,找對應的aciton配置,建立action物件
◆ 執行預設攔截器棧中定義的18個攔截器
◆ 執行action的業務處理方法

7、struts-default.xml 詳解
① 目錄:struts2-core-2.3.4.1.jar/ struts-default.xml
② 內容:
◆ bean節點指定struts在執行的時候建立的物件型別
◆ 指定struts-default包 【使用者寫的package(struts.xml)一樣要繼承此包 】
package:struts-default 包中定義了:
◇ 跳轉的結果型別

	dispatcher      轉發,不指定預設為轉發
	redirect        重定向
	redirectAction  重定向到action資源
	stream          (檔案下載的時候用)

◇ 定義了所有32個攔截器
為了攔截器引用方便,可以通過定義棧的方式引用攔截器,此時如果引用了棧,棧中的攔截器都會被引用!
defaultStack:預設的棧,其中定義預設要執行的18個攔截器(按順序執行)!
預設執行的攔截器棧、預設執行的action

<default-interceptor-ref name="defaultStack"/>
<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
<interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>

8、攔截器(先睹為快):
攔截器功能與過濾器功能類似。
① 共同點: 都攔截資源!
② 區別 :
◆ 過濾器,攔截器所有資源都可以(/index.jsp/servlet/img/css/js)
◆ 攔截器,只攔截action請求。
◆ 攔截器是struts的概念,只能在struts中用。
◆ 過濾器是servlet的概念,可以在struts專案、servlet專案用。
③ 面試題: 攔截器什麼時候執行? (訪問/啟動) 先執行action類建立,還是先執行攔截器?
答:使用者訪問時候按順序執行18個攔截器;先執行Action類的建立,再執行攔截器; 最後攔截器執行完,再執行業務方法。

9、共性問題
① 問題1:Struts.xml配置檔案沒有提示
◆ 解決a:找到struts-2.0.dtd檔案, 拷貝到某個目錄(不要用中文目錄),讓MyEclipse關聯到上面dtd檔案(windows > preferences > 搜尋xml catalog):

配置:
Location:上面配置的dtd目錄
Key:-//Apache Software Foundation//DTD Struts Configuration 2.0//EN

◆ 解決b:讓機器連線網際網路,工具會自動下載dtd檔案,快取到MyEclipse中!
② 問題2
◆ 如果檢視struts原始碼,需要關聯原始碼包檔案:struts-2.3.4.1-all
◆ 如果檢視xwork原始碼,需要再單獨下載xwork原始碼jar檔案:xwork-core-2.3.4.1-sources,並再次關聯

10、
① package:定義一個包,包的作用:管理action(通常一個業務模組用一個包)
② name:包的名字,包名不能重複
③ extends:當前包繼承哪個包,在struts中,包一定要繼承struts-default
struts-default是在struts-default.xml中定義的
④ abstract:表示當前包為抽象包,抽象包不能有action的定義,否則執行時會報錯
只有當前包被其他包繼承時,abstract=true
⑤ namespace:名稱空間,預設為“/”,作為路徑
⑥ action:配置請求路徑與action類的對映關係(name請求路徑名稱,class請求處理action類全名,method請求處理方法)
⑦ result:name是action處理方法返回值,type是跳轉的結果型別,標籤體中指定跳轉的介面

<struts>
    <package name="xxxx" extends="struts-default">
    	<action name="hello" class="cn.itcast.action.HelloAction" method="execute">
    		<result name="success">/success.jsp</result>
    	</action>
    </package> 
</struts>