詳解Java的Struts框架以及相關(guān)的MVC設(shè)計(jì)理念
struts簡(jiǎn)介
Struts是Apache軟件基金會(huì)(ASF)贊助的一個(gè)開(kāi)源項(xiàng)目。它最初是jakarta項(xiàng)目中的一個(gè)子項(xiàng)目,并在2004年3月成為ASF的頂級(jí)項(xiàng)目。它通過(guò)采用JavaServlet/JSP技術(shù),實(shí)現(xiàn)了基于JavaEEWeb應(yīng)用的MVC設(shè)計(jì)模式的應(yīng)用框架,是MVC經(jīng)典設(shè)計(jì)模式中的一個(gè)經(jīng)典產(chǎn)品。
Struts發(fā)展歷史
Struts是作為ApacheJakarta項(xiàng)目的組成部分,項(xiàng)目的創(chuàng)立者希望通過(guò)對(duì)該項(xiàng)目的研究,改進(jìn)和提高JavaServerPages、servlet、標(biāo)簽庫(kù)以及面向?qū)ο蟮募夹g(shù)水準(zhǔn)。
Struts這個(gè)名字的來(lái)源于在建筑和舊式飛機(jī)中使用的支持金屬架。之所以這個(gè)框架叫做“struts”,是為了提醒我們記住那些支撐我們房屋,建筑,橋梁,甚至我們踩高蹺的基礎(chǔ)支撐。這也是解釋struts在開(kāi)發(fā)web應(yīng)用程序中所扮演的角色的精彩描述。
Struts的含義是”支柱,枝干”,它的目的是為了減少程序開(kāi)發(fā)的時(shí)間,項(xiàng)目的創(chuàng)建者認(rèn)為JSP,servlet的存在雖然可以幫助用戶(hù)解決大部分問(wèn)題,但是由于它們的編碼對(duì)項(xiàng)目的開(kāi)發(fā)帶來(lái)了許多的不方便,可重用性也差,所以struts應(yīng)運(yùn)而生,幫助用戶(hù)在最短的時(shí)間內(nèi)解決這些問(wèn)題。Struts框架提供如下服務(wù):
(1)作為控制器的Servlet。
(2)提供大量的標(biāo)簽庫(kù)。
(3)提供了用于國(guó)際化的框架,利用不同的配置文件,可以幫助用戶(hù)選擇合適自己的語(yǔ)言。
(4)提供了JDBC的實(shí)現(xiàn),來(lái)定義數(shù)據(jù)源和數(shù)據(jù)庫(kù)連接池。
(5)XML語(yǔ)法分析工具。
(6)文件下載機(jī)制。
Struts原理
Struts是對(duì)JSPModel2設(shè)計(jì)標(biāo)準(zhǔn)的一種實(shí)現(xiàn),下面分別從模型(Model)、視圖(view)和控制器3個(gè)部分介紹Struts的體系結(jié)構(gòu)和工作原理。調(diào)用流程如下所示。

(1)視圖(view)
在Struts中,視圖層包含兩個(gè)部分,JSP頁(yè)面和ActionForm。
ActionForm封裝了用戶(hù)提交的表單信息,其實(shí)ActonForm本質(zhì)上就是JavaBean,這些JavaBean中沒(méi)有業(yè)務(wù)邏輯,只提供了所有屬性的getter和setter方法,這些屬性和用戶(hù)表單中的輸入項(xiàng)是一一對(duì)應(yīng)的。在Struts中就是通過(guò)ActionForm把用戶(hù)表單信息提交給控制器。
JSP頁(yè)面是經(jīng)典MVC中主要的視圖組件,主要是信息顯示和控制器處理結(jié)果顯示的功能。
除了以上,struts還提供了一個(gè)強(qiáng)大的struts標(biāo)簽庫(kù),來(lái)幫助用戶(hù)解決顯示邏輯,并且利用ActonForm組件將信息傳遞到控制層。
(2)控制器(Controller)
在控制層,struts提供了一個(gè)控制器組件ActionServlet,它繼承自HttpServlet,并重載了HttpServlet的doGet(),doPost()方法,可以接受HTTP的響應(yīng),并進(jìn)行轉(zhuǎn)發(fā),同時(shí)還提供了使用XML進(jìn)行轉(zhuǎn)發(fā)Mapping(映射)的功能。
(3)模型(Model)
模型表示狀態(tài)和業(yè)務(wù)邏輯的處理,在一般的web應(yīng)用程序中,用JavaBean或者EJB來(lái)實(shí)現(xiàn)系統(tǒng)的業(yè)務(wù)邏輯。在Struts中,struts提供Action對(duì)象,來(lái)管理業(yè)務(wù)邏輯的調(diào)用,幫助用戶(hù)分離業(yè)務(wù)邏輯,也就是說(shuō)struts本身不實(shí)現(xiàn)業(yè)務(wù)邏輯,但可以調(diào)用已完成的業(yè)務(wù)邏輯。
Struts工作流程
Struts工作流程如下所示。

ActionServlet是struts中核心的控制器,所有的用戶(hù)請(qǐng)求都必須通過(guò)ActionServlet的處理,而struts-config.xml是struts中核心的配置文件,在這個(gè)文件中配置了用戶(hù)請(qǐng)求URL和控制器Action的映射關(guān)系,ActionServlet通過(guò)這個(gè)配置文件把用戶(hù)的請(qǐng)求發(fā)送到對(duì)應(yīng)的控制器中。
在struts web應(yīng)用程序中,當(dāng)web應(yīng)用程序啟動(dòng)的時(shí)候,就會(huì)初始化ActionServlet在初始化ActionServlet的時(shí)候會(huì)加載struts-config.xml配置文件,在加載成功后會(huì)把這些URL和控制器映射關(guān)系存放在ActionMapping對(duì)象或者其他對(duì)象中。當(dāng)ActionServlet接收到用戶(hù)請(qǐng)求的時(shí)候,就會(huì)按照下面的流程對(duì)用戶(hù)請(qǐng)求進(jìn)行處理。
(1)ActionServlet接收到用戶(hù)的請(qǐng)求后,會(huì)根據(jù)請(qǐng)求URL尋找匹配的ActionMapping對(duì)象,如果匹配失敗,說(shuō)明用戶(hù)請(qǐng)求的URL路徑信息有誤,所以返回請(qǐng)求路徑無(wú)效的信息,當(dāng)找到匹配的ActionMapping的時(shí)候,進(jìn)入到下一步。
(2)當(dāng)ActionServlet找到匹配的ActionMapping對(duì)象的時(shí)候,會(huì)根據(jù)ActionMapping中的映射信息判斷對(duì)應(yīng)的ActionForm對(duì)象是否存在,如果不存在對(duì)應(yīng)的ActionForm對(duì)象就創(chuàng)建一個(gè)新的ActionForm對(duì)應(yīng),并把用戶(hù)提交的表單信息保存到這個(gè)ActionForm對(duì)象中。
(3)在struts-config.xml中這個(gè)配置文件,可以配置表單是否需要驗(yàn)證,如果需要驗(yàn)證,就調(diào)用ActionForm中的validate()方法對(duì)用戶(hù)輸入的表單進(jìn)行驗(yàn)證。
(4)如果ActionForm的validate()方法返回了ActionErrors對(duì)象,則表明驗(yàn)證失敗,ActionServlet把這個(gè)頁(yè)面返回到用戶(hù)輸入的界面,提示用戶(hù)重新輸入。如果方法的返回值為null,就表明驗(yàn)證已經(jīng)通過(guò),可以進(jìn)入下一步處理。
(5)ActionServlet可以根據(jù)ActionMapping對(duì)象查找用戶(hù)請(qǐng)求轉(zhuǎn)發(fā)給哪個(gè)控制器Action,如果對(duì)應(yīng)的Action對(duì)象不存在,就創(chuàng)建這個(gè)對(duì)象,并調(diào)用這個(gè)Action的excute()方法。
(6)業(yè)務(wù)邏輯控制器Action的execute()方法就會(huì)返回一個(gè)ActionForward對(duì)象,ActionServlet把控制器處理的結(jié)果轉(zhuǎn)發(fā)到ActionForward對(duì)象指定的JSP頁(yè)面。
(7)ActionForward對(duì)象指定的JSP頁(yè)面根據(jù)返回的處理結(jié)果,用合適形式把服務(wù)器處理的結(jié)果展示給用戶(hù),到這里為止,一個(gè)客戶(hù)請(qǐng)求的整個(gè)過(guò)程完畢。
以上初步struts框架進(jìn)行了介紹,和對(duì)原理進(jìn)行了簡(jiǎn)單的分析。至于struts是如何實(shí)現(xiàn)MVC的,ActionServlet屬于Controller部分,Action和ActionForm屬于Model層,還是Action屬于Controller層,不同的人對(duì)struts有不同的理解。接下來(lái)真正的運(yùn)用到實(shí)踐中,在實(shí)踐中深刻去體會(huì),原理固然重要,重要的是運(yùn)用,是能駕馭和使用這個(gè)框架。就像學(xué)習(xí)開(kāi)車(chē)一樣,不是一蹴而就的。
MVC向struts MVC框架演變過(guò)程
版本一 基本的MVC
首先是創(chuàng)建一個(gè)jsp索引頁(yè)面index.jsp,index.jsp創(chuàng)建一個(gè)表單。
如果我們完成添加用戶(hù)的模塊,我們提交表單的時(shí)候要把這個(gè)表單提交給一個(gè)servlet,于是我們?cè)趕rc自己的包中建立自己的servlet繼承HttpServlet,TestServlet同時(shí)覆蓋父類(lèi)的doGet和doPost方法。
提交的的表單信息,我們可以在TestServlet中通過(guò)request.getParameter(“username”);取出來(lái)。之后把從表單中的數(shù)據(jù)提交到數(shù)據(jù)庫(kù),我們的servlet作為控制器沒(méi)有添加到數(shù)據(jù)庫(kù)的職責(zé),于是我們把訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)的業(yè)務(wù)邏輯放到UserManager.java類(lèi)中。在這個(gè)類(lèi)中實(shí)現(xiàn)添加用戶(hù)的任務(wù)。
package com.bjpowernode.servlet;
public class UserManager {
public void add(String username)
{
System.out.println("UserManager.add()-->>"+ username);
}
}
在TestServlet中調(diào)用UserManager中的方法。同時(shí)讓頁(yè)面轉(zhuǎn)向到添加成功的頁(yè)面add_success.jsp。
TestServlet代碼以及在web.xml中配置TestServlet.
<servlet>
<servlet-name>TestServlet</servlet-name>
<servlet-class>com.bjpowernode.servlet.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TestServlet</servlet-name>
<url-pattern>/servlet/TestServlet</url-pattern>
</servlet-mapping>
Testservlet代碼如下所示:
package com.bjpowernode.servlet;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
public class TestServlet extendsHttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter(“username”);
UserManager userManager = new UserManager();
userManager.add(username);
request.getRequestDispatcher(“/add_success.jsp”).forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request,response);
}
}
索引頁(yè)面index.jsp代碼,通過(guò)servlet/TestServlet來(lái)轉(zhuǎn)到TestServlet。
<form action="servlet/queryUser.action" method="post">
姓名:<input type="text" name="username"><br>
<input type="submit" value="提交"><br>
</form>
這樣采用MVC完成了用戶(hù)的添加任務(wù)。
版本二 通過(guò)判斷標(biāo)識(shí)變量
當(dāng)我們不僅要完成用戶(hù)的添加而是要完成用戶(hù)的增刪改查的時(shí)候我們可以在servlet中進(jìn)行判斷,是添加還是刪除等。并且在傳遞字符串的時(shí)候要加上一個(gè)標(biāo)識(shí)表示相應(yīng)的操作。這樣在servlet中會(huì)有很多的if和else語(yǔ)句。
版本三 servlet模式匹配 截取字符串判斷
我們可以在配置servlet的時(shí)候配置成為匹配模式<url-pattern>*.action</url-pattern>任何的*.action的都會(huì)轉(zhuǎn)到到TestServlet,這樣我們可以截取URL來(lái)判斷轉(zhuǎn)到哪個(gè)頁(yè)面。但在TestServlet中仍然有很多的ifelse語(yǔ)句進(jìn)行判斷。這樣我們的TestServlet代碼如下所示。
import java.io.IOException;
import java.util.List;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
public class TestServlet extendsHttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//截取url.
String requestURI = request.getRequestURI();
//System.out.println("requestURI="+ requestURI);
//截取http://localhost:8080/test_servlet/servlet/addUser.action test_servlet后面的東西。
String path = requestURI.substring(requestURI.indexOf("/", 1),requestURI.indexOf("."));
//截取得到虛目錄。/servlet/addUser
System.out.println("path="+ path);
String username = request.getParameter("username");
UserManager userManager = new UserManager();
String forward = "";
//判斷截取的path和哪個(gè)要加載的頁(yè)面相等.
if("/servlet/delUser".equals(path))
{
userManager.del(username);
forward = "del_success.jsp";
//request.getRequestDispatcher("/del_success.jsp").forward(request,response);
}else if("/servlet/addUser".equals(path))
{
userManager.add(username);
forward= "add_success.jsp";
//request.getRequestDispatcher("/add_success.jsp").forward(request,response);
}else if("/servlet/modifyUser".equals(path))
{
userManager.modify(username);
forward= "modify_success.jsp";
//request.getRequestDispatcher("/modify_success.jsp").forward(request,response);
}else if("/servlet/queryUser".equals(path))
{
List userList = userManager.query(username);
request.setAttribute("userList",userList);
forward= "query_success.jsp";
//request.getRequestDispatcher("/query_success.jsp").forward(request,response);
}else
{
throw new RuntimeException("請(qǐng)求失敗!");
}
request.getRequestDispatcher(forward).forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throwsServletException, IOException {
doGet(request,response);
}
}
UserManager代碼如下所示:
package com.bjpowernode.servlet;
import java.util.ArrayList;
import java.util.List;
public class UserManager {
public void add(String username)
{
System.out.println("UserManager.add()-->>"+ username);
}
public void del(String username)
{
System.out.println("UserManager.del()-->>"+ username);
}
public void modify(String username)
{
System.out.println("UserManager.modify()-->>"+ username);
}
public List query(String username)
{
System.out.println("UserManager.query()-->>"+ username);
List userList = new ArrayList();
userList.add("a");
userList.add("b");
userList.add("c");
return userList;
}
}
同時(shí)建立查詢(xún)成功,刪除成功,修改成功jsp頁(yè)面。
這樣在index.jsp頁(yè)面中通過(guò)表單的action屬性來(lái)轉(zhuǎn)到相應(yīng)的頁(yè)面。
<body>
<form action="servlet/queryUser.action" method="post">
姓名:<input type="text" name="username"><br>
<input type="submit" value="提交"><br>
</form>
</body>
版本三的缺點(diǎn)是if太多,不穩(wěn)定,當(dāng)我們添加或者刪除一個(gè)if的時(shí)候還需要重新編譯源程序。這樣無(wú)法適應(yīng)變化的需求。所以我們?cè)诖嘶A(chǔ)上進(jìn)行改進(jìn)就需要去掉if語(yǔ)句,可以把改變的部分分離出來(lái),變成可配置的,這樣就變得靈活的,需要改動(dòng)jsp的文件名,在配置文件中配置一下就可以了。
版本四 if else抽象出接口和類(lèi)+配置文件
首先我們把轉(zhuǎn)到的地址字符串放到一個(gè)字符串變量中,這樣TestServlet中的doGet方法,代碼如下。
String username = request.getParameter("username");
UserManager userManager = new UserManager();
String forward = "";
//判斷截取的path和哪個(gè)要加載的頁(yè)面相等.
if("/servlet/delUser".equals(path))
{
userManager.del(username);
forward= "del_success.jsp";
}else if("/servlet/addUser".equals(path))
{
userManager.add(username);
forward= "add_success.jsp";
}elseif("/servlet/modifyUser".equals(path))
{
userManager.modify(username);
forward= "modify_success.jsp";
}else if("/servlet/queryUser".equals(path))
{
List userList = userManager.query(username);
request.setAttribute("userList",userList);
forward= "query_success.jsp";
}else
{
thrownew RuntimeException("請(qǐng)求失敗!");
}
request.getRequestDispatcher(forward).forward(request,response);
統(tǒng)一完成了轉(zhuǎn)向。當(dāng)if語(yǔ)句是滿(mǎn)足某種條件,條件不同的時(shí)候轉(zhuǎn)到不同的頁(yè)面,添加有添加的邏輯,修改有修改的邏輯,這樣我們可以抽象出接口。對(duì)添加的action操作添加,對(duì)刪除的action做出刪除任務(wù),對(duì)修改的action做出修改。把每一個(gè)if語(yǔ)句中的變成為類(lèi)去實(shí)現(xiàn),抽象出一個(gè)Action接口,接口中方法execute()方法,返回轉(zhuǎn)向路徑字符串。類(lèi)圖如下所示。

共同的Action接口,不同的實(shí)現(xiàn)。
Action接口代碼。
package com.bjpowernode.servlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
public interface Action {
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
AddUserAction代碼。
package com.bjpowernode.servlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
public class AddUserActionimplements Action {
@Override
public String execute(HttpServletRequest request,HttpServletResponse response) throws Exception {
String username = request.getParameter("username");
//Stringsex = request.getParameter("sex");
//...........
//調(diào)用業(yè)務(wù)邏輯.
UserManager userManager = new UserManager();
userManager.add(username);
return"/add_success.jsp";
}
}
DelUserAction代碼。
package com.bjpowernode.servlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
public class DelUserActionimplements Action {
@Override
public String execute(HttpServletRequest request,HttpServletResponse response) throws Exception {
String username = request.getParameter("username");
//String sex = request.getParameter("sex");
//...........
//調(diào)用業(yè)務(wù)邏輯.
UserManager userManager = new UserManager();
try
{
userManager.del(username);
}catch(Exceptione)
{
return"del_error.jsp";
}
return"/del_success.jsp";
}
}
ModifyUserAction代碼。
package com.bjpowernode.servlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
public class ModifyUserActionimplements Action {
@Override
public String execute(HttpServletRequest request,HttpServletResponse response) throwsException {
String username = request.getParameter("username");
//String sex = request.getParameter("userId");
//...........等其他...
//調(diào)用業(yè)務(wù)邏輯.
UserManager userManager = new UserManager();
userManager.modify(username);
return"/modify_success.jsp";
}
}
QueryUserAction代碼。
package com.bjpowernode.servlet;
import java.util.List;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
public class QueryUserActionimplements Action {
@Override
public String execute(HttpServletRequest request,HttpServletResponse response) throwsException {
String username = request.getParameter("username");
//Stringsex = request.getParameter("userId");
//其他查詢(xún)條件.
//...........等其他...
//調(diào)用業(yè)務(wù)邏輯.
UserManager userManager = new UserManager();
List userList = userManager.query(username);
request.setAttribute("userList",userList);
return"/query_success.jsp";//轉(zhuǎn)向路徑都可以通過(guò)配置文件讀取。
}
}
這樣使用多態(tài)方式調(diào)用不同的Action,轉(zhuǎn)向代碼如下所示。
//用多態(tài)的方式.
Action action = null;
if("/servlet/delUser".equals(path))
{
action= new DelUserAction();
}else if("/servlet/addUser".equals(path))
{
action= new AddUserAction();
}else if("/servlet/modifyUser".equals(path))
{
action= new ModifyUserAction();
}else if("/servlet/queryUser".equals(path))
{
action= new QueryUserAction();
}else
{
throw new RuntimeException("請(qǐng)求失敗!");
}
//取得action后傳遞過(guò)去。動(dòng)態(tài)調(diào)用ACtion中的execute方法。
String forward = null;
try{
forward= action.execute(request,response);
}catch (Exception e) {
e.printStackTrace();
}
//根據(jù)路徑完成轉(zhuǎn)向。
request.getRequestDispatcher(forward).forward(request, response);
上述調(diào)用不同的action,我們可以把不同的請(qǐng)求和對(duì)應(yīng)的action配置到自己的xml文件中。配置哪個(gè)請(qǐng)求對(duì)應(yīng)哪個(gè)Action。
<action-config>
<action path="/servlet/delUser" type="com.bjpowernode.servlet.DelUserAction">
<forward name="success">/del_success.jsp</forward>
<forward name="error">/del_error.jsp</forward>
</action>
<action path="/servlet/addUser" type="com.bjpowernode.servlet.AddUserAction">
<forward name="success">/add_success.jsp</forward>
<forward name="error">/add_error.jsp</forward>
</action>
<action path="/servlet/modifyUser" type="com.bjpowernode.servlet.ModifyUserAction">
<forward name="success">/modify_success.jsp</forward>
<forward name="error">/modify_error.jsp</forward>
</action>
<action path="/servlet/queryUser" type="com.bjpowernode.servlet.QueryUserAction">
<forward name="success">/query_success.jsp</forward>
<forward name="error">/query_error.jsp</forward>
</action>
</action-config>
這樣我們就可以讀取配置文件來(lái)進(jìn)行相應(yīng)的操作。每個(gè)action對(duì)應(yīng)著一些信息,它的class,執(zhí)行成功以及執(zhí)行失敗的配置。我們?cè)谧x取配置文件的時(shí)候可以把這些放到Map對(duì)象中。代碼如下所示。
ActionMapping
{
private String path;
private String type;
Map forwardMap;
}
forwardMap
{
key="success";
value="/del_success.jsp"
key="error";
value="/del_error.jsp";
}
Map map = new HashMap();
map.put("/servlet/delUser",);
map.put("/servlet/addUser",);
map.put("/servlet/modifyUser",);
map.put("/servlet/queryUser",);
//如果是刪除的ActionMapping存儲(chǔ)如下:
actionMapping
{
path="/servlet/delUser";
type="com.bjpowernode.servlet.DelUserAction";
forwardMap
{
key="success",value="/del_success.jsp";
key="error",value="/del_error.jsp";
}
}
String path ="/servlet/delUser";
//根據(jù)截取的URL請(qǐng)求,到Map中取得本次請(qǐng)求對(duì)應(yīng)的Action。
ActionMapping actionMapping =(ActionMappint)map.get(path);
// 取得本次請(qǐng)求對(duì)應(yīng)的Action類(lèi)的完成路徑。
String type =actionMappint.getType();//com.bjpowernode.servlet.DelUserAction
//通過(guò)反射動(dòng)態(tài)實(shí)例化Action
Aciton action =(Action)class.forName(type).newInstance();
//取得action后傳遞過(guò)去。動(dòng)態(tài)調(diào)用ACtion中的execute方法。
String forward =action.execute(request,response);
//根據(jù)路徑完成轉(zhuǎn)向。
request.getRequestDispatcher(forward).forward(request,response);
我們用時(shí)序圖來(lái)描述上述調(diào)用過(guò)程(如圖)。

Struts就是采用上述思路。Struts框架是把上圖中前端控制器servlet進(jìn)行了封裝,我們只要繼承struts的Action去調(diào)用業(yè)務(wù)邏輯和轉(zhuǎn)向。讀取配置文件的工作也是封裝到了struts框架中。前篇講解了struts框架的應(yīng)用實(shí)例,我們可以進(jìn)行對(duì)比。
- Java的Struts框架中配置國(guó)際化的資源存儲(chǔ)的要點(diǎn)解析
- 深入解析Java的Struts框架中的控制器DispatchAction
- Java的Struts框架中登陸功能的實(shí)現(xiàn)和表單處理器的使用
- Java的Struts框架中append標(biāo)簽與generator標(biāo)簽的使用
- 簡(jiǎn)單說(shuō)明Java的Struts框架中merge標(biāo)簽的使用方法
- 總結(jié)Java的Struts框架的異常處理方法
- 詳解Java的Struts框架中注釋的用法
- Java的Struts框架中Action的編寫(xiě)與攔截器的使用方法
- Java下Struts框架中的ActionForm類(lèi)詳解
相關(guān)文章
Java GZip 基于內(nèi)存實(shí)現(xiàn)壓縮和解壓的方法
這篇文章主要介紹了Java GZip 基于內(nèi)存實(shí)現(xiàn)壓縮和解壓的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
druid多數(shù)據(jù)源配置+Datasurce動(dòng)態(tài)切換方式
這篇文章主要介紹了druid多數(shù)據(jù)源配置+Datasurce動(dòng)態(tài)切換方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
Mybatis之@ResultMap,@Results,@Result注解的使用
這篇文章主要介紹了Mybatis之@ResultMap,@Results,@Result注解的使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
全面解析Java支持的數(shù)據(jù)類(lèi)型及Java的常量和變量類(lèi)型
java數(shù)據(jù)結(jié)構(gòu)和算法中數(shù)組的簡(jiǎn)單入門(mén)

