ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
上一篇提出了问题,使用Struts框架比不使用struts框架的好处在哪里的问题。以及由此讲述了[静态](http://blog.csdn.net/lovesummerforever/article/details/18951649)[ActionForm和动态ActionForm](http://blog.csdn.net/lovesummerforever/article/details/18951649)。本篇就第一个问题,以一个示例对用户信息的增删改查来展示基本的MVC框架到strutsMVC的过程。 ### 版本一 基本的MVC 首先是创建一个jsp索引页面index.jsp,index.jsp创建一个表单。 如果我们完成添加用户的模块,我们提交表单的时候要把这个表单提交给一个servlet,于是我们在src自己的包中建立自己的servlet继承HttpServlet,TestServlet同时覆盖父类的doGet和doPost方法。 提交的的表单信息,我们可以在TestServlet中通过request.getParameter(“username”);取出来。之后把从表单中的数据提交到数据库,我们的servlet作为控制器没有添加到数据库的职责,于是我们把访问数据库的业务逻辑放到UserManager.java类中。在这个类中实现添加用户的任务。 ~~~ package com.bjpowernode.servlet; public class UserManager { public void add(String username) { System.out.println("UserManager.add()-->>"+ username); } } ~~~ 在TestServlet中调用UserManager中的方法。同时让页面转向到添加成功的页面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); } } ~~~ 索引页面index.jsp代码,通过servlet/TestServlet来转到TestServlet。      ~~~ <form action="servlet/queryUser.action" method="post"> 姓名:<input type="text" name="username"><br> <input type="submit" value="提交"><br> </form> ~~~ 这样采用MVC完成了用户的添加任务。 ### 版本二 通过判断标识变量 当我们不仅要完成用户的添加而是要完成用户的增删改查的时候我们可以在servlet中进行判断,是添加还是删除等。并且在传递字符串的时候要加上一个标识表示相应的操作。这样在servlet中会有很多的if和else语句。 ### 版本三 servlet模式匹配 截取字符串判断 我们可以在配置servlet的时候配置成为匹配模式<url-pattern>*.action</url-pattern>任何的*.action的都会转到到TestServlet,这样我们可以截取URL来判断转到哪个页面。但在TestServlet中仍然有很多的ifelse语句进行判断。这样我们的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和哪个要加载的页面相等. 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("请求失败!"); } 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; } } ~~~ 同时建立查询成功,删除成功,修改成功jsp页面。 这样在index.jsp页面中通过表单的action属性来转到相应的页面。 ~~~ <body> <form action="servlet/queryUser.action" method="post"> 姓名:<input type="text" name="username"><br> <input type="submit" value="提交"><br> </form> </body> ~~~ 版本三的缺点是if太多,不稳定,当我们添加或者删除一个if的时候还需要重新编译源程序。这样无法适应变化的需求。所以我们在此基础上进行改进就需要去掉if语句,可以把改变的部分分离出来,变成可配置的,这样就变得灵活的,需要改动jsp的文件名,在配置文件中配置一下就可以了。 ### 版本四 if else抽象出接口和类+配置文件 首先我们把转到的地址字符串放到一个字符串变量中,这样TestServlet中的doGet方法,代码如下。                                           ~~~ String username = request.getParameter("username"); UserManager userManager = new UserManager(); String forward = ""; //判断截取的path和哪个要加载的页面相等. 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("请求失败!"); } request.getRequestDispatcher(forward).forward(request,response); ~~~ 统一完成了转向。当if语句是满足某种条件,条件不同的时候转到不同的页面,添加有添加的逻辑,修改有修改的逻辑,这样我们可以抽象出接口。对添加的action操作添加,对删除的action做出删除任务,对修改的action做出修改。把每一个if语句中的变成为类去实现,抽象出一个Action接口,接口中方法execute()方法,返回转向路径字符串。类图如下所示(图4.1)。 ![](https://box.kancloud.cn/2016-06-21_5769087e70429.jpg) 图4.1 共同的Action接口,不同的实现。 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"); //........... //调用业务逻辑. 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"); //........... //调用业务逻辑. 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"); //...........等其他... //调用业务逻辑. 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"); //其他查询条件. //...........等其他... //调用业务逻辑. UserManager userManager = new UserManager(); List userList = userManager.query(username); request.setAttribute("userList",userList); return"/query_success.jsp";//转向路径都可以通过配置文件读取。 } } ~~~ 这样使用多态方式调用不同的Action,转向代码如下所示。 ~~~ //用多态的方式. 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("请求失败!"); } //取得action后传递过去。动态调用ACtion中的execute方法。 String forward = null; try{ forward= action.execute(request,response); }catch (Exception e) { e.printStackTrace(); } //根据路径完成转向。 request.getRequestDispatcher(forward).forward(request, response); ~~~ 上述调用不同的action,我们可以把不同的请求和对应的action配置到自己的xml文件中。配置哪个请求对应哪个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> ~~~ 这样我们就可以读取配置文件来进行相应的操作。每个action对应着一些信息,它的class,执行成功以及执行失败的配置。我们在读取配置文件的时候可以把这些放到Map对象中。代码如下所示。 ~~~ 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存储如下: 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"; //根据截取的URL请求,到Map中取得本次请求对应的Action。 ActionMapping actionMapping =(ActionMappint)map.get(path); // 取得本次请求对应的Action类的完成路径。 String type =actionMappint.getType();//com.bjpowernode.servlet.DelUserAction //通过反射动态实例化Action Aciton action =(Action)class.forName(type).newInstance(); //取得action后传递过去。动态调用ACtion中的execute方法。 String forward =action.execute(request,response); //根据路径完成转向。 request.getRequestDispatcher(forward).forward(request,response); ~~~ 我们用时序图来描述上述调用过程(如图4.2)。                    ![](https://box.kancloud.cn/2016-06-21_5769087e8e6e9.jpg) 图4.2 Struts就是采用上述思路。Struts框架是把上图中前端控制器servlet进行了封装,我们只要继承struts的Action去调用业务逻辑和转向。读取配置文件的工作也是封装到了struts框架中。前篇讲解了struts框架的应用实例,我们可以进行对比。 ### 版本五 采用struts框架 [采用struts框架完成登录示例](http://blog.csdn.net/lovesummerforever/article/details/17348871)。 这样我们对struts由来,以及struts封装了哪些东西从而方便了程序员,不再重复的写重复的代码。下一篇[struts控制器DispatchAction.](http://blog.csdn.net/lovesummerforever/article/details/18967831)