【JavaWeb】-- Servlet优化(dispatcherServlet)

一、Servlet最初使用方法

一个请求对应一个servlet,但是这样存在的问题是servlet会越来越多。

二、优化1(合并成一个servlet)

将一系列的请求都对应一个servlet,通过一个operate的值来决定调用servlet中的哪个方法,使用switch,但是随着项目的业务规模扩大,会有很多servlet,这样就会充斥着大量的switch,效率低下。

    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {       
        request.setCharacterEncoding("utf-8");
        String operate = request.getParameter("operate");
        if(StringUtil.isEmpty(operate)){
            operate = "index";
        }
        switch (operate){
            case "index":index(request,response);break;
            case "edit":edit(request,response);break;
            case "add":add(request,response);break;
            case "del":del(request,response);break;
            case "update":update(request,response);break;
            default:throw new RuntimeException("operate非法");
        }
    }

三、优化2(反射)

在servlet中使用反射技术,规定operate的值和方法名一致,那么接收到operate的值是什么就表明我们需要调用对应的方法相应,如果找不到对应方法则抛出异常,但是还是存在一定问题:每个servlet都存在类似的反射方法。

  protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        String operate = request.getParameter("operate");
        if(StringUtil.isEmpty(operate)){
            operate = "index";
        }
        //获取当前类所有方法
        Method[] methods = this.getClass().getDeclaredMethods();
        for (Method m :methods){
            //获取方法名称
            String methodName = m.getName();
            if(operate.equals(methodName)){
                //找到方法,通过反射调用
                try {
                    m.invoke(this,request,response);
                    return;
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        throw new RuntimeException("operate非法");
    }

四、优化3(dispatcherServlet)

设计中央控制器:dispatcherServlet。

多个servlet改为controller(去掉注解),由dispatcher统一控制;

所以需要先根据请求的网址/xxx找到对应的controller,再调用其中的方法。

 

1、根据url定位到能够处理这个请求的controller组件

新建DispatcherServlet类

1)从url中提取servletPath:/fruit.do -> fruit;

 protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");

        //例url:http://localhost:8080/1/hello.do
        //那么servletPath是:/hello.do
        String servletPath = request.getServletPath();

        //1、使用截取,获得hello
        servletPath = servletPath.substring(1);
        int lastDotIndex = servletPath.lastIndexOf(".do");
        servletPath = servletPath.substring(0,lastDotIndex);

2)根据fruit找到对应的组件:FruitController,这个对应的依据存储在applicationContext.xml中,通过DOM技术解析XML文件,在中央控制器中形成一个beanMap容器,用来存放所有Controller组件;

以下方法解析xml文件,根据bean节点找到id和class,使用Map集合保存。

   private Map<String,Object> beanMap = new HashMap<>();
 public void init() throws ServletException {
        super.init();
        try {
            InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
            //1、创建DocumentBuilderFactory
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            //2、创建DocumentBuilder对象
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            //3、创建Document对象
            Document document = documentBuilder.parse(inputStream);
            //4、获取所有bean节点
            NodeList beanNodeList = document.getElementsByTagName("bean");
            for(int i = 0;i<beanNodeList.getLength();i++){
                Node beanNode = beanNodeList.item(i);
                if(beanNode.getNodeType() == Node.ELEMENT_NODE){
                    Element beanElement = (Element) beanNode;
                    String beanId = beanElement.getAttribute("id");
                    String className = beanElement.getAttribute("class");
                    Object beanObj = Class.forName(className).newInstance();
                    beanMap.put(beanId,beanObj);
                }
            }
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (SAXException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

applicationContext.xml文件:

<?xml version="1.0" encoding="UTF-8" ?>
<beans>
<!--    bean作用:servletPath中涉及的名字对应的是fruit,那么就要用FruitController来处理-->
    <bean id="fruit" class="com.fruit.controllers.FruitController"/>
</beans>

3)根据获取到的operate的值定位到FruitController中需要的方法。

先拿到所有的方法,再遍历找到和operate相同的方法

  //2、根据hello对应到HelloController

        Object controllerBeanObj = beanMap.get(servletPath);

        String operate = request.getParameter("operate");
        if(StringUtil.isEmpty(operate)){
            operate = "index";
        }
        try {
            Method[] methods = controllerBeanObj.getClass().getDeclaredMethods();
            for (Method method : methods) {
                if (operate.equals(method.getName())) {

2、调用Controller组件中的方法

由以前在每个方法里获取值,优化为传入参数;

由以前在每个方法里进行服务器重定向或跳转页面,优化为返回String值,后面进行视图处理。

1)获取参数

获取即将要调用的方法的参数信息:Parameter[] parameters = method.getParameters();

通过parameter.getName()获取参数的名称;

准备Object[] parameterValues 数组用来存放对应参数的参数值;

需要考虑参数类型问题,需要做类型转化工作,parameter.getType()获取参数类型。

                    //1、统一获取请求参数
                    //获取当前方法参数,返回参数数组
                    Parameter[] parameters = method.getParameters();
                    //承载参数值
                    Object[] parameterValues = new Object[parameters.length];
                    for(int i = 0;i<parameterValues.length;i++){
                        Parameter parameter = parameters[i];
                        String parameterName = parameter.getName();
                        if("request".equals(parameterName)){
                            parameterValues[i] = request;
                        }else if("request".equals(parameterName)){
                            parameterValues[i] = response;
                        }else if("session".equals(parameterName)){
                            parameterValues[i] = request.getSession();
                        }else{
                            String parameterValue = request.getParameter(parameterName);
                            String typeName = parameter.getType().getName();
                            Object parameterObj = parameterValue;
                            if(parameterObj!=null){
                                if("java.lang.Integer".equals(typeName)){
                                    parameterObj = Integer.parseInt(parameterValue);
                                }
                            }
                            parameterValues[i] = parameterObj;
                        }

                    }
                  

2)执行方法

                     //2、controller组件方法调用
                    method.setAccessible(true);
                    Object returnObj = method.invoke(controllerBeanObj,parameterValues);

3)视图处理

                      //3、视图处理
                    String methodReturnStr = (String) returnObj;
                    if (methodReturnStr.startsWith("redirect:")) {
                        String redirectStr = methodReturnStr.substring("redirect:".length());
                        response.sendRedirect(redirectStr);
                    } else {
                        super.processTemplate(methodReturnStr, request, response);
                    }
                }
            }

//            else {
//                throw new RuntimeException("operate非法");
//            }
        }catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }

理解servlet优化对以后学习mvc会有帮助。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

四月天行健

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值