Servlet是如何实现MVC的

jopen 10年前

Servlet是一种服务器端的编程语言,是J2EE中比较关键的组成部分,Servlet技术的推出,扩展了Java语言在服务器端开发的功能,巩固了Java语言在服务器端开发中的地位,而且现在使用非常广泛的JSP技术也是基于Servlet的原理.

JSP+JavaBeans+Servlet成为实现MVC模式的一种有效的选择。

Servlet是如何实现MVC的

如果我们要实现一个对用户的增删改查,并且要求符合对扩展开发,对修改关闭的原则,该怎么做呢?

首先,这是我们的类图以及类与类之间调用的时序图。

Servlet是如何实现MVC的

Servlet是如何实现MVC的

根据UML图来实现代码:

TestServlet类

package com.bjpowernode.servlet;    import java.io.IOException;  import java.util.List;    import javax.servlet.ServletException;  import javax.servlet.http.HttpServlet;  import javax.servlet.http.HttpServletRequest;  import javax.servlet.http.HttpServletResponse;    public class TestServlet extends HttpServlet {        protected void doGet(HttpServletRequest request, HttpServletResponse response)     throws ServletException, IOException {    String requestURI = request.getRequestURI();    System.out.println("requestURI=" + requestURI);    String path = requestURI.substring(requestURI.indexOf("/",1),requestURI.indexOf("."));    System.out.println("path = " +path);        String username = request.getParameter("username");        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 ModifyAction();    }else if("/servlet/queryUser".equals(path)){     action = new QueryUserAction();    }else{     throw new RuntimeException("请求失败");    }    String forward ="";    try {     forward= action.execute(request, response);    } catch (Exception e) {     e.printStackTrace();    }    request.getRequestDispatcher(forward).forward(request, response);         }       protected void doPost(HttpServletRequest request, HttpServletResponse response)     throws ServletException, IOException {    doGet(request,response);   }    }

抽象接口Action

package com.bjpowernode.servlet;    import javax.servlet.http.HttpServletRequest;  import javax.servlet.http.HttpServletResponse;    public interface Action {     public String execute(HttpServletRequest request, HttpServletResponse response)   throws Exception;     }

添加类,这里就只写添加类了,其他类一样

package com.bjpowernode.servlet;    import javax.servlet.http.HttpServletRequest;  import javax.servlet.http.HttpServletResponse;    public class AddUserAction implements Action {     public String execute(HttpServletRequest request,     HttpServletResponse response) throws Exception {    String username = request.getParameter("username");    //int age = Integer.parseInt(request.getParameter("username"));    //String sex = request.getParameter("sex");        //调用业务逻辑    UserManager userManager = new UserManager();    userManager.add(username);        return "/add_success.jsp";   }    }

Web.xml配置

<welcome-file-list>      <welcome-file>index.jsp</welcome-file>    </welcome-file-list>        <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>        -->        <url-pattern>*.do</url-pattern>    </servlet-mapping>

这里我们发现,在testAction类中,用到了大量的if和else,而当我们需要扩展一个上传类的时候,就需要修改if/else,所以,这就不符合对扩展开发,对修改关闭原则,所以,我们需要把这部分提取出来,配置到配置文件里,用反射进行配置。

 

我们需要先配置配置文件

<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.ModifyAction">         <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>

需要获取actionMapping对象

  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",actionMapping);      map.put("/servlet/addUser",actionMapping);      map.put("/servlet/modifyUser",actionMapping);      map.put("/servlet/queryUser",actionMapping);          // 如果是删除ActionMapping存储如下:      actionMapping{       path ="/servlet/delUser";       type ="com.bjpowernode.servlet.DelUserAction"        forwardMap{         key ="success",value ="/del_success.jsp"         key ="error",value"/del_error.jsp"        }      }

最后根据获取的对象采用反射来动态实例化Action,达到我们的目的。

  String path = "/servlet/delUser";         //  根据截取的URL请求,到Map中取得本次请求对应的Action       ActionMapping actionMapping =(ActionMapping)map.get(path);           //取得本次请求对应的Action类的完整路径      String type = actionMapping.getType();  //com.bjpowernode.servlet.DelUserAction          // 采用反射动态实例化Action      Action action  = (Action)class.forName(type).newInstance();         //动态待用Action中的execute方法      String forward = action.execute(request.response);           //根据路径完成转向        request.getRequestDispatcher(forward).forward(request, response);

这样,我们基本就是实现了对扩展开发,对修改封闭的原则,但是,这仅仅是一个功能我们就需要做这么多事情,写这么多代码,对程序员来说这是一项不小的工作量,那么我们有没有其他的办法让我们的工作量小一点呢?