简单的MVC框架流程

根据MVC的设计思想,自己动手做一个简单的MVC流程。从而加深对Spring MVC的理解。

我们知道MVCModel-View-Controller)即模型-视图-控制器, Struts,Spring MVC都是采用了这种模式。

根据MVC的设计思想,一个完整的HTTP请求需要经过以下几步。

1,所有的HTTP请求都将映射到一个Servlet上。

2, Servlet根据URL选择合适的Controller来处理请求,获得返回的ModeView

3, ServletModel绑定到Request中,然后交给View渲染。

4, View将渲染后的页面返回给用户,完成请求处理。

由于存在多个控制器,如果直接用Servlet作为控制器,则需要实现多个Servlet,这会导致非常复杂的配置和大量的重复代码。因此,通常将Servlet作为一个请求入口,或者称之为前置控制器,然后根据URL选择一个合适的控制器处理。

下面,我们在Eclipse中建立一个SimpleMVC项目,自己动手实现一个最简单的MVC流程.

我们知道所有的请求会映射到一个Servlet上,然后这个Servlet根据URL与控制器的映射关系在选择合适的控制器来处理。所有我们可以先抽象出一个Controller接口。所有的控制器都实现这一接口,这也面向接口编程的好习惯。

public interface Controller {

    //只有一个方法.处理请求的方法

    ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response);

}

Controller需要返回视图和将要由视图渲染的Model。视图通常是JSP页面,因此,返回JSP页面的路径即可,而Model可以简单地使用Map来实现。由于一个方法只能返回一个对象,因此,有必要将ModelView一起返回。设计ModelAndView如下。

public class ModelAndView {

    private String view;

    private Map<String, Object> model;

    public ModelAndView(String view, Map<String, Object> model) {

       this.view = view;

       this.model = model;

    }

    public String getView() {

       return view;

    }

    public Map<String, Object> getModel() {

       return model;

    }

}

下面设计具体的控制器。我们先设计一个LoginController,这是用来处理登录请求的控制器。

public class LoginController implements Controller {

    public ModelAndView handleRequest(HttpServletRequest request,

           HttpServletResponse response) {

       String username = request.getParameter("username");

        String password = request.getParameter("password");

        if("123".equals(username) && "123".equals(password)) {

            // 登录成功,将转入/welcome.jsp:

            Map<String, Object> model = new HashMap<String, Object>();

            model.put("username", username);

            model.put("password", password);

            model.put("time", new Date().toString());

            return new ModelAndView("/welcome.jsp", model);

        }

        // 登录失败,将转入/loginFailed.jsp:

        Map<String, Object> error = new HashMap<String, Object>();

        error.put("message", "Login failed.");

        error.put("time", new Date().toString());

        return new ModelAndView("/loginFailed.jsp", error);

    }

}

这个控制器实现了Controller接口,当我们以http://xxxxxx/login.do这种请求时。

Servlet根据url映射关系(下面会说到)会调用LoginController来处理。

String username = request.getParameter("username");

取得/login.do?username=xxx这种形式传来的参数。进行用户名密码验证,如果成功就返回model(返回页面展示用的数据)和view(返回的页面名称),我们在这里用Map封装了返回的数据并和view(/welcome.jsp)一起返回给前置控制器(Servlet),最终由前置控制器来完成将页面传回给用户。

    接下来我们设计另一个控制器LogoutController,主要用来处理用户退出

public class LogoutController implements Controller {

    public ModelAndView handleRequest(HttpServletRequest request,

           HttpServletResponse response) {

        Map<String, Object> model = new HashMap<String, Object>();

        model.put("message", "loguot success...");

        model.put("time", new Date().toString());

        // 返回的JSP视图路径是"/logout.jsp":

        return new ModelAndView("/logout.jsp", model);

    }

}

    这个控制器和上面一样,也是返回一个modelview.view其实就是返回给用户的页面。Model就是页面上要用来显示的数据。

    接下来我们设计最重要的前端控制器servlet,它主要用来处理请求转发,根择不同的url选择合适的控制器来进行处理。我们给这个控制器命保为DispatcherServlet;

public class DispatcherServlet extends HttpServlet {

    private ServletContext context;

    private Map<String, Controller> controllers;

    //初始化DispatcherServet

    public void init(ServletConfig config) throws ServletException {

       context = config.getServletContext();

       // URL和对应的Controller关联起来:

       controllers = new HashMap<String, Controller>();

       //login.do的请求将交由LoginController控制器处理

       controllers.put("/login.do", new LoginController());

       //logou.do的请求将交由LogoutController控制器处理

       controllers.put("/logout.do", new LogoutController());

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)

           throws ServletException, IOException {

       String contextPath = request.getContextPath();

       String uri = request.getRequestURI().substring(contextPath.length());

       Controller controller = controllers.get(uri);

       ModelAndView mv = controller.handleRequest(request, response);

       // Model绑定到Request:

       Map<String, Object> model = mv.getModel();

       Set<String> keys = model.keySet();

       for (String key : keys)

           request.setAttribute(key, model.get(key));

       // 获得JSP视图的路径:

       String jsp = mv.getView();

       // 转发给JSP视图渲染:

       context.getRequestDispatcher(jsp).forward(request, response);

      

    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)

           throws ServletException, IOException {

       doGet(request, response);

    }

}

从代码中可以看出DispatcherServlet继承HttpServet

里面的初始化方法中(init),创建了一个Map,controllers.put("/login.do", new LoginController());这句说明了url和控制器的映射关系。当/login.do的请求过来时。就会用LoginController来进行处理

String contextPath = request.getContextPath();

取得当前系统的路径。如你的访问是http://localhsot:8080/SampleMvc/login.do,那么会返回/SampleMvcString uri = request.getRequestURI().substring(contextPath.length());request.getRequestURI()取得当前系统请求的url,如你的访问是http://localhsot:8080/SampleMvc/login.do,那么会返回/SampleMvc/login.do调用.substring方法后就得到了/login.do.还记得我们上面controllers.put("/login.do", new LoginController())这句吗,这样我们得到了/login.do的请求,servlet根据此关系就能知道调用那个控制器来处理了

Controller controller = controllers.get(uri);

ModelAndView mv = controller.handleRequest(request, response);

得到具体的控制器。调用控制器进行处理后返回modelview。接下来把model中的数据绑定在request中,供页面展示这此数据。

context.getRequestDispatcher(jsp).forward(request, response);返回页面给用户

web.xml中的配置

<servlet>

       <servlet-name>dispatcherservlet</servlet-name>

       <servlet-class>com.lee.DispatcherServlet</servlet-class>

</servlet>

<servlet-mapping>

       <servlet-name>dispatcherservlet</servlet-name>

       <url-pattern>*.do</url-pattern

</servlet-mapping>

接下来我们可以分别用

http://localhost/SampleMvc/login.do?username=123&password=123

http://localhost/SampleMvc/logout.do测试

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在刚刚步入“多层结构”Web应用程序开发的时候,我阅读过几篇关于“asp.net三层结构开发”的文章。但其多半都是对PetShop3.0和Duwamish7的局部剖析或者是学习笔记。对“三层结构”通体分析的学术文章几乎没有。 2005年2月11日,Bincess BBS彬月论坛开始试运行。不久之后,我写了一篇题目为《浅谈“三层结构”原理与用意》的文章。旧版文章以彬月论坛程序中的部分代码举例,通过全局视角阐述了什么是“三层结构”的开发模式?为什么要这样做?怎样做?……而在这篇文章的新作中,配合这篇文章我写了7个程序实例(TraceLWord1~TraceLWord7留言板)以帮助读者理解“三层结构”应用程序。这些程序示例可以在随带的CodePackage目录中找到——   对于那些有丰富经验的Web应用程序开发人员,他们认为文章写的通俗易懂,很值得一读。可是对于asp.net初学者,特别是没有任何开发经验的人,文章阅读起来就感到非常困难,不知文章所云。甚至有些读者对“三层结构”的认识更模糊了……   关于“多层结构”开发模式,存在这样一种争议:一部分学者认为“多层结构”与“面向对象的程序设计思想”有着非常紧密的联系。而另外一部分学者却认为二者之间并无直接联系。写作这篇文章并不是要终结这种争议,其行文目的是希望读者能够明白:在使用asp.net进行Web应用程序开发时,实现“多层结构”开发模式的方法、原理及用意。要顺利的阅读这篇文章,希望读者能对“面向对象的程序设计思想”有一定深度的认识,最好能懂一些“设计模式”的知识。如果你并不了解前面这些,那么这篇文章可能并不适合你现在阅读。不过,无论这篇文章面对的读者是谁,我都会尽量将文章写好。我希望这篇文章能成为学习“三层结构”设计思想的经典文章!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值