zoukankan      html  css  js  c++  java
  • 对 Servlet 的改进

      通过上一篇博客:Servlet 的详解 http://www.cnblogs.com/ysocean/p/6912191.html,我们大致知道了 Servlet 的基本用法。但是稍微分析一下 Servlet 的用法,我们还是发现其存在很多缺点:

      ①、一个请求对应一个 Servlet,即每一个请求我们都需要在 web.xml 文件中配置映射。如果项目大,请求很多,那么会造成 web.xml 很大,很难维护。

      ②、即便在好几个请求对应一个 Servlet,即在 service() 方法中,通过 if--else 语句来判断执行的代码块。那这样就会造成 service() 方法很拥挤。

      ③、一个项目只存在一个 web.xml 文件,如果一个项目是多人开发,那么整合代码开发过程中会有很多问题。不适合团队开发。

      ④、Servlet中doGet方法和doPost方法中的两个参数reqeust,response拥有严重的容器依赖性。

      ⑤、如果页面上表单中的元素比较复杂,则在Servlet的方法中获取表单元素的数据比较繁琐。

      ⑥、Servlet是单线程的,只要在Servlet中的声明一个实例变量,那么该变量在多线程访问时就会有线程安全问题。

      ⑦、在Servlet中处理异常,如果Servlet中有N个方法,则这N个方法必须都要try--catch。因为子类抛的异常不能大于父类。

    那么接下来我们用一个例子来解决上面的问题。

      1、新建一个 Web 工程,名为 ServletIncreased。并在 web.xml 中配置一个过滤器 ServletFilter,这个过滤器会过滤所有以 .do 结尾的 URL 链接

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns="http://java.sun.com/xml/ns/javaee"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
       id="WebApp_ID" version="3.0">
        
      <filter>
        <filter-name>ServletFilter</filter-name>
        <filter-class>com.ys.filter.ServletFilter</filter-class>
      </filter>
      <filter-mapping>
        <filter-name>ServletFilter</filter-name>
        <url-pattern>*.do</url-pattern>
      </filter-mapping>
       
    </web-app>

      2、创建一个 UserServlet,里面有两个方法,insert()和update()方法,调用 insert() 方法会跳转到 insert.jsp 页面,调用 update() 方法会调转到 update.jsp 页面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    package com.ys.servlet;
    import java.io.IOException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    public class UserServlet {
        //用户插入方法
        public void insert(HttpServletRequest req,HttpServletResponse resp) throws Exception, IOException{
            req.getRequestDispatcher("insert.jsp").forward(req, resp);
        }
         
        //用户更新方法
        public void update(HttpServletRequest req,HttpServletResponse resp) throws Exception, IOException{
            req.getRequestDispatcher("update.jsp").forward(req, resp);
        }
         
    }

      3、创建一个配置文件类,里面存放配置文件的关系,通过一个 Map 集合,保存 Servlet 的类名和全类名

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    package com.ys.config;
    import java.util.HashMap;
    import java.util.Map;
    public class ServletNameConfig {
        //定义一个 Servlet 配置文件,Map<key,value>
        //key:表示 Servlet 的类名
        //value:表示 Servlet 类名的全称
        public static Map<String, String> servletMap = new HashMap<>();
         
        static {
            servletMap.put("UserServlet""com.ys.servlet.UserServlet");
        }
    }

      4、回头看我们配置的过滤器,ServletFilter

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    package com.ys.filter;
    import java.io.IOException;
    import java.lang.reflect.Method;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import com.ys.config.ServletNameConfig;
    public class ServletFilter implements Filter{
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            HttpServletRequest req = (HttpServletRequest) request;
            HttpServletResponse resp = (HttpServletResponse) response;
             
            String reqURL = req.getRequestURI(); //  /ServletIncreased/UserServlet.do
            String[] strs = reqURL.split("/");
            //定义 Servlet 的全类名
            String servletAllName = null;
            if(strs[2] != null){
                //得到 请求路径的 servlet 类名
                String servletName = strs[2].substring(0, strs[2].indexOf("."));
                //根据获取的 Servlet 类名,由配置文件 ServletNameConfig 里面的map 得到 全类名
                servletAllName = ServletNameConfig.servletMap.get(servletName);
            }
            //获取请求方法名
            String methodName = req.getParameter("method");
            System.out.println(servletAllName+"---"+methodName);
            try {
                //通过反射调用执行方法
                Class obj = Class.forName(servletAllName);
                Method method = obj.getDeclaredMethod
                        (methodName, HttpServletRequest.class,HttpServletResponse.class);
                method.invoke(obj.newInstance(), req,resp);
            catch (Exception e) {
                e.printStackTrace();
            }      
        }
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
        }
        @Override
        public void destroy() {
        }
    }

      整体的项目结构如下:

      

    然后将整个项目发布到 tomcat 服务器运行,发布的方法可以如下:

      http://www.cnblogs.com/ysocean/p/6893446.html

    然后我们在浏览器输入如下链接:http://localhost:8080/ServletIncreased/UserServlet.do?method=insert

      那么就会调用 UserServlet 的 insert 方法,进而跳转到 insert.jsp 页面

      

    如果我们在浏览器输入如下链接:将 insert 改为 update

       http://localhost:8080/ServletIncreased/UserServlet.do?method=update

    那么就会调用 UserServlet 的update 方法,进而调转到 update.jsp 页面

      

    分析:这个改进主要是配置了一个过滤器,然后通过过滤器的 doFilter() 方法,我们可以通过请求路径获得请求URL,然后通过字符串的截取方法得到 Servlet 的名称。通过配置文件保存的 Servlet类名和全类名的对应关系得到全类名;然后利用反射的原理,通过 invoke() 方法来动态调用方法。这里我们并没有解决上面所有的问题,比如严重的容器依赖性我们这里还有。如果想真正解决,请看下一篇博客:Struts2 详解

  • 相关阅读:
    SpringCloud系列二:Restful 基础架构(搭建项目环境、创建 Dept 微服务、客户端调用微服务)
    SpringCloud系列一:SpringCloud的简介和架构
    SpringBoot系列十二:SpringBoot整合 Shiro
    SpringBoot系列十一:SpringBoot整合Restful架构(使用 RestTemplate 模版实现 Rest 服务调用、Swagger 集成、动态修改日志级别)
    SpringBoot系列十:SpringBoot整合Redis
    SpringBoot系列九:SpringBoot服务整合(整合邮件服务、定时调度、Actuator监控)
    SpringBoot系列八:SpringBoot整合消息服务(SpringBoot 整合 ActiveMQ、SpringBoot 整合 RabbitMQ、SpringBoot 整合 Kafka)
    SpringBoot系列七:SpringBoot 整合 MyBatis(配置 druid 数据源、配置 MyBatis、事务控制、druid 监控)
    SpringBoot系列六:SpringBoot整合Tomcat
    SpringBoot系列五:SpringBoot错误处理(数据验证、处理错误页、全局异常)
  • 原文地址:https://www.cnblogs.com/yechanglv/p/6931444.html
Copyright © 2011-2022 走看看