1. 程式人生 > >【Struts】- Struts1.3 工作流程

【Struts】- Struts1.3 工作流程

浪費了“黃金五年”的Java程式設計師,還有救嗎? >>>   

MVC: 模型檢視控制器設計模式

  • M:Model 模型:主要作用域業務邏輯的實際處理
  • V:View 檢視:主要用於資料的展示
  • C:Controller 控制器:主要作為檢視和模型之間的邏輯控制,充當排程者的角色,不負責具體的業務邏輯處理

常見的MVC框架:struts 、springmvc

struts1.3配置檔案

:struts-config.xml(管理action和表單之間的對映關係),預設存放在/WEB-INF/struts-config.xml

Web容器配置struts1.3:只需要宣告struts1.3的攔截ActionServlet,如果struts-config.xml檔案未放在預設的位置,則需要手動配置檔案路徑

struts1.3工作流程:客戶端訪問Web伺服器,ActionServlet攔截所有的web請求並將請i去引數封裝進表單,作為呼叫內部的execute方法的形式引數,execute方法內部呼叫model處理頁面資料,然後通過struts-config.xml檔案檢視結果和跳轉路徑,直接頁面跳轉


基礎案例:頁面登陸驗證

struts總控配置檔案:struts-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" 
  "http://struts.apache.org/dtds/struts-config_1_3.dtd">
 <struts-config>
 <!-- 
 配置表單:
form-beans 可以存放多個表單
name:表示表單名字(建議小寫) type:用於指明表單類的全路徑(無java字尾)
  -->
 <form-beans>  
 <form-bean name="username" type="com.zhiwei.form.UserForm"></form-bean>
 </form-beans>
 
 <!-- 
  配置處理對應表單的Action 
 name:和對應的表單要一致相關聯 type:表示該action的全路徑(包名+類名) 
 path:表示訪問Action的資源名: http://localhost:8080/Web工程名稱/path
 scope:表示表單例項的訪問範圍在request裡面,也可以表示生命週期和request一個級別,
             將表單例項放置request作用域裡面:預設session
 forward:配置跳轉關係:Action完成表單處理會給ActionServlet反饋一個結果及跳轉介面
  -->
 <action-mappings>
 <action path="/login" name="username" scope="request" type="com.zhiwei.action.LoginAction">
	 <forward name="success" path="/WEB-INF/success.jsp"></forward>
	 <forward name="error" path="/WEB-INF/error.jsp"></forward>
 </action>
 </action-mappings>
 </struts-config>

web容器配置:web.xml

<?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_2_5.xsd" version="2.5">
  
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  
  <!-- 配置Struts1.3的攔截Servlet,Struts2攔截Servlet發生改變
       ActionServlet:預設配置檔案位置,如果一致省略不寫
       protected String config = "/WEB-INF/struts-config.xml";
   -->
  <servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
   <!--  <init-param>
      <param-name>config</param-name>
      <param-value>/WEB-INF/struts-config.xml</param-value>
    </init-param> -->
  </servlet>
  <servlet-mapping>
    <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>
 
 <!-- 統一專案的編碼形式 -->
  <filter>
    <filter-name>EncodingFilter</filter-name>
    <filter-class>com.zhiwei.filter.EncodingFilter</filter-class>
    <init-param>
	    <param-name>pageCoding</param-name>
	    <param-value>utf-8</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>EncodingFilter</filter-name>
    <url-pattern>*.do</url-pattern>
  </filter-mapping>
  
</web-app>

表單:UserForm

package com.zhiwei.form;
//建立表單,供actionservlet使用
import org.apache.struts.action.ActionForm;

@SuppressWarnings("serial")
public class UserForm extends ActionForm {
   
	private String username;
	private String passwd;
	
	//注意這裡的get和set方法中的方法名必須與JSP裡面的空間名相同,不然在執行過程中ActionAervlet會無法檢測(反射機制)
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPasswd() {
		return passwd;
	}
	public void setPasswd(String passwd) {
		this.passwd = passwd;
	}
}

控制器Controller:LoginAction

package com.zhiwei.action;
/**struts使用中文時會出現亂碼(過濾器),原因是在呼叫action時ActionServlet已經將資料儲存在表單中
Action ActionServlet都是單態的(在整個程式執行過程中始終保持是同一個物件服務),
任何傳送給actionservlet的請求在伺服器不關閉的情況下總是使用同一個action例項對業務邏輯進行處理
*/
import javax.servlet.http.HttpServletRequest;
import com.zhiwei.model.*;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import com.zhiwei.form.UserForm;

/**
 * Action:主要處理頁面傳遞過來的引數,並封裝進表單,統一呼叫其他的功能類控制業務邏輯處理,
 * 並更具處理的結果,對頁面進行相應的跳轉,Action需要在struts-config中進行action-form,result--forword配置
 * execute:Action預設的執行方法,類似Servlet的service方法
 * @author Yang Zhiwei
 */
public class LoginAction extends Action {
    
	@Override 
	public ActionForward execute(ActionMapping mapping, ActionForm form,HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		
		UserForm uf=(UserForm)form;  //轉換頁面請求表單引數
		if(UserBeanBO.checkUser(uf)){
			request.setAttribute("username", uf.getUsername()); 
			/**
			 *   原始碼分析:預設轉發,而不是重定向
			 *   public ActionForward(String path) {
			        this(path, false);
			    }
			 */
			return mapping.findForward("success");  //配置結果跳轉
		}else{
			request.setAttribute("Message", "輸入密碼不正確......");
			return mapping.findForward("error");
		}
	}
}

Model層:

package com.zhiwei.model;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.zhiwei.form.UserForm;

public class UserBeanBO {
	
    //定義資料庫基本引數
	private static Connection ct=null;
	private static PreparedStatement ps=null;
	private static ResultSet rs=null;
	private static int count=0;
	private static int defaultSize=50;
	
	//類似快取作用,緩解資料庫頻繁的IO操作(實際對於使用者個人私密資訊都會通過MD5等手段加密的)
	private static List<Map<String,String>> userInfos=new ArrayList<Map<String,String>>(defaultSize);;
	
	/**
	 * 核實使用者名稱和密碼
	 * 注意:預防SQL注入漏洞
	 * @param userName
	 * @param userPasswd
	 * @return
	 */
	public static boolean checkUser(UserForm uf){
		
		System.out.println(Thread.currentThread().getName()+"--->開始時間:"+System.currentTimeMillis());
		String userName=uf.getUsername();
		String password=uf.getPasswd();
		
		//快取預處理
		if(userInfos.size()>0){
			for(Map<String,String> user:userInfos){
				if(user.containsKey(userName) && user.get(userName).equals(password)){
					System.err.println(Thread.currentThread().getName()+"-->結束時間:"+System.currentTimeMillis());
					return true;
				}
			}
		}
		
		boolean mark=false;
		try{
			ct=getDBLink();
			ps=ct.prepareStatement("select *from student where stuname='"+userName+"' limit 1;");
			rs=ps.executeQuery();
			if(rs.next()){
				String passwd=rs.getString(3);
				if(passwd.equals(uf.getPasswd())){
					
					//快取重新整理次數:實際操作更復雜不會全部清除,通過某種快取策略處理
					if(userInfos.size()>=defaultSize){
						userInfos.clear();
						System.out.println("快取全部重新整理次數:"+count++);
					}
					
					Map<String,String> user=new HashMap<String,String>();
					user.put(uf.getUsername(),password);
					userInfos.add(user);
					mark=true;
				}
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			Close();
		}
		System.out.println(Thread.currentThread().getName()+"-->結束時間:"+System.currentTimeMillis());
		return mark;
	}
	
	/**
	 * 關閉資料庫資源
	 */
	public static void Close(){
		try {
			if(rs!=null){
				rs.close();
			}
			if(ps!=null){
				ps.close();
			}
			if(ct!=null){
				ct.close();
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 獲取資料庫連線:保證多執行緒的安全,使用同步鎖或者執行緒池
	 * @return
	 */
	 public static  synchronized Connection getDBLink(){
		   
		 try{
			   Class.forName("com.mysql.jdbc.Driver");  //JVM載入JDBC記憶體
			   ct=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test","squirrel","xiaoyang"); //獲取DB連線
		   }catch(Exception e){
			   e.printStackTrace();
		   }
		return ct;
	}
}

View層: login.jsp

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<!-- 
Struts開發步驟:
1:新建web專案並引入struts開發包
2:新建jsp介面和ActionForm和Action類
3:新建struts-config配置檔案並進行ActionForms和Action配置
4:配置web.xml:引入ActionServlet
 -->
  <body style="text-align: center;">
 
  <!-- 將請求交給對應的Action處理 :在struts-config中對映成path路徑:即login代表loginAction.java-->
   <form action="${pageContext.request.contextPath}/login.do" method="post">
   u:<input type="text" name="username"/><br>
   p:<input type="password" name="passwd"/><br>
   <input type="submit" value="submit"/>
   </form>
  </body>
</html>

success.jsp

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <body>
  <!-- EL表示式:param.username:request.getAttribute("username"); -->
    Welcome <font color="red">${param.username }</font> logining this page!<br>
   <a href="${pageContext.request.contextPath }">重新登陸</a>
  </body>
</html>

error.jsp

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <body>
  <font color="red">${Message }</font><br>
  Fail to this page!<br>
  <a href="${pageContext.request.contextPath }">重新登陸</a>
  </body>
</html>

測試SQL:

CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `StuName` varchar(100) NOT NULL,
  `StuPasswd` varchar(100) NOT NULL,
  `StuScore` int(11) DEFAULT NULL,
  `StuSex` char(1) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1

insert into student values(1,'squirrel','xiaoyang',100,'M');
insert into student values(2,'zhangsan','zhangsan',85,'F');
insert into student values(3,'lisi','lisi',95,'M');
insert into student values(4,'wangwu','wangwu',75,'F');
insert into student values(5,'maliu','maliu',68,'M');
insert into student values(6,'tianqi','tianqi',80,'F');
insert into student values(7,'wangba','wangba',83,'M');

Jmeter效能測試結果(200併發)

注意: 資料庫連線的IO操作比較消耗資源,為了安全起見最好使用執行緒同步控制,如果想進一步提高效能需要適應執行緒池管理,後臺mysql資料庫開啟快取等優化措施

補充:

  • struts1.3和struts2很多東西都是不一樣的,但是本質的思想一致,struts1.3概念比較少,入門比較簡單

  • ActionServlet可使用DispatchAction可實現一個servlet擁有多個服務方法,ActionServlet預設方法