【MVC框架系列】(一)——Struts,让我把你看得明明白白

前言

  这几天一大波MVC框架侵袭我的大脑,Struts1,Struts2,Spring MVC……,让我有种战斗的欲望,要把它们各个攻克。可是,如果把每个都当做一个新的敌人的来对抗的话,就会消耗我很多的能量值,哈哈。于是乎,我决定从最简单的开始,对“敌人”有个清楚的了解,这样才能举一反三哦。

Struts产生原因

以“添加用户”这个简单功能举例:
我们需要建一个Web Project,然后写3个JSP(添加用户,添加成功,添加失败),1个UserServlet,1个UserManager…… 


当我们还要实现“修改用户”,“删除用户”,“查询用户”这些功能怎么办?
【1】第一种(建立不同的Servlet处理不同的用户请求)
  处理添加用户请求——–AddUserServlet
  处理修改用户请求——–ModifyUserServlet
  处理修改用户请求——–DeleteUserServlet
  处理查询用户请求——–QueryUserServlet
【2】第二种(只有一个Servlet,增加一个参数来标识请求的类型)
  请求的链接如:http://localhost:8080/test_servlet/servlet/UserServlet?command=add
【3】第三种(将同一类的请求转发给一个Servlet来处理)
  我们知道当用户发出请求,Tomcat容器接收到请求,会把该请求发给对应的servlet来处理。容器会通过四种方式来寻找对应的Servlet.(关于Servlet路径匹配)
  这里我们采用扩展名匹配的方式,让请求的连接有一定的规律:
  addUser.do
  modifyUser.do
  deleteUser.do
  queryUser.do
  然后配置文件中配置UserServlet的匹配路径为:

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

  这样的话,这些请求都会到达UserServlet中。

问题来了

  第一种:系统中功能多时,如:除了用户管理,还有商品管理,店铺管理……,就会产生很多Servlet。
  而第二种和第三种都免不了要在Servlet中对用户的请求进行处理并做判读,来确定用户的真正请求时什么,进而调用不同的业务逻辑。如下面一段代码:

@Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //获得用户的请求路径
        String requestURI = request.getRequestURI();
        //截取路径中的部分字段
        String path = requestURI.substring(requestURI.indexOf("/", 1), requestURI.indexOf("."));
        System.out.println("path=" + path);

        String username = request.getParameter("username");
        UserManager userManager = new UserManager();

        //具体要转发到哪个页面
        String forward = "";
        //根据请求分别进行处理
        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";
        }else if ("/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 {
            throw new RuntimeException("请求失败");
        }
        request.getRequestDispatcher(forward).forward(request, response);

}

以上代码存在什么问题呢?
1.if…else分支多,当请求增多时,要要修改代码,破坏开闭原则。
2.当转发的页面换成其他的页面时,需要修改代码,破坏开闭原则。
除此之外,Servlet中接收的参数都是String类型的,我们需要在Servlet中自己做类型转换
所以我们为什么要封装成Struts?它要帮我们做两件事:
(1).把可变的东西进行抽象并可灵活配置以适应变化。
(2).把重复的公共的东西进行封装,统一处理,减少代码冗余,提高程序员开发效率。
所以,我们经常说框架,那什么是框架?
框架:它提供一些基础性的服务,功能,特别是一些共性的东西,使开发变得简单。从开发角度讲,用框架就会有约束(如:一些配置),适合大型项目,多人开发,这样大家基本按同样的模式开发,便于维护。所以,框架不是真正的产品不是给客户用的,他是给开发者用的。

解决现有问题的思路

1.如何去掉分支?
解决if…else分支问题,让我想到了状态模式,职责链模式,配置文件+反射这三种方式。但是状态模式和职责链模式虽然把每个分支都放到了一个类中,但是我们会发现在每个分支中还会有一部分判断,因为它要决定是否交给其他的分支进行处理。但是实际上在咱们这个场景中,添加删除修改查询之间并没有什么联系,既没有完整的状态切换,也没有什么职责等级之类的处理流程。所以配置文件+反射还是大家常用的方式。
2.类在哪里?
此种方式是让我们来通过读配置文件的方式,来动态生成相应的类。所以我们接下来要做的就是封装。在Servlet中,不管是添加修改删除还是查询,每个分支下要做的事情都是:获得参数,调用业务逻辑,将请求转向结果页面。我们可以抽象出一个接口,然后把具体的实现分别封装到不同的类中。
小结:以上的分析中我们会回顾起很多的设计原则和模式,它们真的是经典啊!

MVC思想

  我个人的理解就是通过C(Controller:控制器)将M(Model:业务模型)和V(View:视图)分离,即将业务逻辑和具体显示的页面进行分离。其实如果不用Struts,我们可以实现MVC这种思想的,即:JSP + servlet + javabean。那么Struts作为MVC思想的实现框架,它优秀的地方在哪里呢?——它解决了上文中提到的那些问题,其实这些问题我们开发人员可以自己写代码解决,但是用了框架我们就省事了很多啊。

      这里写图片描述

Struts的实现思路

  1. 有一个中央控制器,Struts1中是ActionServlet,Struts2中是StrutsPrepareAndExecuteFilter负责把请求转发给相应的Action来处理
    (中央控制器如何拦截所有请求?通过配置匹配模式,如:*.do,Struts2是利用Filter,道理一样的)
  2. 把变化的都放到配置文件中,包括每个请求对应的Action,以及处理之后要显示的页面。
  3. 解析XML文件,并将XML文件解析成Java中的Map—ActionMapping
  4. 根据请求的URI,截取一部分,作为key值,从集合ActionMapping中找出应该处理的Action的class类型,利用反射动态生成具体的Action,然后到具体的Action中执行方法execute(Struts2中默认是此方法,可以配置其他方法),然后根据Action中的执行结果ActionForward(Struts中是Result)(如:success,error……)从配置文件中读取要显示的页面信息。

        这里写图片描述

总结

  感觉现在要学的东西很多,但是学的东西越多,越需要去回顾基础的东西。在这个学习的过程中,我思考得更多的是一种学习方式。如何才能以“不变”应“万变”?只有理解思想和原理,抓住本质,这样才能让学习轻松,也能快速地学会更多的东西。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值