看兩個JSP模型
一、Model1模型
這是model1模型,用戶在瀏覽器端輸入,發送請求,JSP頁面收集用戶輸入的數據,並通過調用JavaBean操作(增、刪、改、查)數據庫。將操作數據庫的結果返回給JSP頁面,JSP頁面接收返回的數據,在頁面上顯示給用戶。
Model1模型分析:
優點:這樣的結構簡單,JSP頁面接收了用戶的請求,並調用了操作數據庫的類,又收集了操作數據庫的類返回的結果,顯示在JSP頁面上。這些,都是JSP頁面完成的。
缺點:JSP頁面既將顯示邏輯和業務邏輯放到了一起,頁面上嵌入了驗證和控制流轉以及大量的java代碼,jsp頁面需要做的工作量很大,頁面也很亂。
二、Model2模型
這是Model2模型,用戶在瀏覽器輸入,發送請求,Servlet創建resquest收集用戶在JSP頁面上輸入的信息,經過處理,通過調用JavaBeans操作(增、刪、改、查)數據庫,實現邏輯處理。最後Servelt得到操作數據庫的結果信息,調用返回的JSP頁面,將數據呈現給用戶。
Model2模型分析:
優點:與Model1結構相比,Model1是將頁面邏輯和業務邏輯都放在了JSP頁面上,Model2是將二者分開。頁面邏輯放在JSP頁面上,業務邏輯放在了Servlet類中,頁面邏輯和業務邏輯分開了,各部分的職責和明確。調理很清晰,益於擴展。
缺點:添加了新類,結構比Model1複雜。
兩種模型比較:
Model1和Model2都完成了用戶請求,Model1結構雖簡單,JSP頁面兼併了頁面邏輯和業務邏輯的功能,分工並不明確,適合小型項目開發。相比之下,Model2將頁面邏輯和業務邏輯分開,分別放在了JSP頁面和Servlet類中,雖然複雜了些,但是分工明確,邏輯很清晰,適合大型項目開發。
三、struts1模型
有了Model2這種MVC的結構,來了解struts1結構,就很容易瞭解了。
通過MVC設計模式來分析Struts1的結構,如上圖:Mode(M)l業務邏輯處理,View(V)視圖,ActionServlet(C)即中央控制器Controller。用戶在瀏覽器端輸入,發送請求。中央控制器ActionServlet收集用戶請求,並訪問對應的Action,Action處理用戶請求,調用Model操作數據庫,Action得到操作數據庫的結果信息,並指定要訪問的JSP頁面。通過JSP頁面顯示給用戶。
四、詳細對比Model2和Struts1的對比
通過上面的分析,從宏觀上了解了Modle2和Struts1的結構設計,好像看不出Struts1和Model2相比,struts1的優勢在哪裏。下面通過詳細的調用流程來分析。
Model2:用戶發送請求,Servlet收集用戶的請求信息,放到request中,讀取web.xml中的配置信息。
web.xml配置文件:
<servlet>
<servlet-name>TestServlet</servlet-name>
<servlet-class>com.powernode.servlet.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TestServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
根據<Servlet>配置信息,找到Servlet類(TestServlet)。在TestSevlet中根據用戶請求的地址,調用相應的Action。
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 截取用戶請求的地址
String userURI = request.getRequestURI();
System.out.println("requestURI=" + userURI);
String path = userURI.substring(userURI.indexOf("/",1),userURI.indexOf("."));
System.out.println("path=" + path);
//固定的請求地址和截取到的請求地址,比較,調用Action對象
Action action = null;
if("/servlet/addUser".equals(path)){
action = new AddUserAction();
}else if("/servlet/delUser".equals(path)){
action = new DelUserAction();
}else if("/servlet/modifyUser".equals(path)){
action = new ModifyUserAction();
}else if("/servlet/queryUser".equals(path)){
action = new QueryUserAction();
}else{
throw new RuntimeException("請求失敗!");
};
String forward = null;
try{ //在action中業務處理,操作數據庫的結果放到request,並返回要訪問的JSP頁面地址
forward = action.execute(request, response);
}catch(Exception e){
e.printStackTrace();
}
//轉發到要訪問的JSP頁面 request.getRequestDispatcher(forward).forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request,response);
}
}
看了上面的代碼片段和註釋,就知道了在action中調用了Model,進行業務處理,操作數據得到結果以及要訪問的JSP頁面。
在Servlet中,我們可以看到兩個缺點:1.多個IF..ELSE..分支判斷。if...else..很不穩定,如果要進行擴展,就需要修改這裏的代碼,違反了對修改關閉,對擴展開放的原則。
2.分支判斷中,比較用戶訪問的請求地址時,是固定的字符串。如果要修改,也還得修改這裏的代碼。
Struts1結構:
用戶在瀏覽器端發送請求,ActionServlet收集用戶請求,讀取struts-config.xml配置文件。
struts-config.xml配置文件:
<struts-config>
<form-beans>
<form-bean name="loginForm" type="com.bjpowernode.struts.LoginActionForm"></form-bean>
</form-beans>
<action-mappings>
<action path="/login"
type="com.bjpowernode.struts.LoginAction"
name="loginForm"
scope="request"
>
<forward name="success" path="/login_success.jsp"></forward>
<forward name="error" path="/login_error.jsp"></forward>
</action>
</action-mappings>
</struts-config>
ActionServlet通過比較用戶請求地址和配置文件中的<action>中的path屬性。調用相應的Action。因爲在配置文件<action-mapping>中配置好了path和Action的對應。有了用戶的請求地址,就能找到要調用的Action。
public class LoginAction extends Action {
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
LoginActionForm laf = (LoginActionForm)form;
String username = laf.getUsername();
String password = laf.getPassword();
UserManager userManager = new UserManager();
try{
//調用相應的業務邏輯處理類
userManager.login(username, password);
//跳轉到登錄成功頁面
return mapping.findForward("success");
//用自己封裝的異常類捕獲異常——用戶不能找到
}catch(UserNotFoundException e){
e.printStackTrace();
//將錯誤信息存放到request中
request.setAttribute("msg", "用戶不能找到,用戶名稱=【" + username +"】");
//用自己封裝的異常類捕獲異常——密碼錯誤
}catch(PasswordErrorException e){
//將錯誤信息放到request中
request.setAttribute("msg", "密碼錯誤!");
}
//跳轉到錯誤頁面
return mapping.findForward("error");
}
}
Action中調用Model,進行業務處理,操作數據庫,得到操作結果。以及返回要訪問的JSP頁面。在配置文件中,通過<forward>標籤頁定義了要跳轉的JSP頁面。
對比Model2,Struts1裏邊,沒有了If。。else。。判斷語句,配置文件解決了這個問題,通過配置文件,將請求地址和要調用的Action匹配好了。通過這樣的綁定,有了請求地址,就找到了要訪問的Action。(其實是ActionServlet操作了這個跳轉的過程ActionServlet讀取配置文件,將<action-mapping>中的信息放到map中,以鍵值對的形式存在。ActionServlet分析截取用戶的請求地址,得到key,通過這個key從map中拿到value.即要跳轉到的action)。
再看剛纔Model2中分析的兩個缺點,f。。else。。判斷語句的問題就這樣被解決掉了。那第二個問題,分支判斷中都是用的固定的字符串比較的。這個在struts1中是通過模糊匹配的方式解決的。可以參看http://blog.csdn.net/xujiaolf/article/details/43968399。這篇博客了說明了Struts1中的模糊匹配。
以上就是Model1,Model2和Struts1的對比,每一次的演變都帶來巨大的便利。都是智慧的結晶啊,前人怎麼就這麼聰明呢?!