Servlet开发 | 利用 Filter + 反射 处理 URL, 精简 servlet-mapping

Posted bukong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Servlet开发 | 利用 Filter + 反射 处理 URL, 精简 servlet-mapping相关的知识,希望对你有一定的参考价值。

1.提要

  在原生 Servlet 开发中,如果采用一个 url 对应一个 servlet-mapping,那么web.xml将会十分冗长难以维护。其实,我们其实可以通过 Filter + 反射 来 使 一个 servlet 处理 多个 url ,并且根据不同url调用到 servlet 中的不同方法 (类似SpringMVC)

  根据下面的代码实现之后,可以实现 用户访问 /test的时候,就会自动调用 FrontServlet 下面 的 test() 方法,并且根据 该 方法的返回值 来 返回 jsp 文件 或者是 跳转,用户访问 /test2 的时候,就会调用 test2() 方法,以此类推。

  本文是 小小商城-Servlet版的 细节详解系列 之一,项目 github:https://github.com/xenv/S-mall-servlet/ 本文代码大部分在 github 中 可以找到

 

2.具体实现

  完整的实现代码见:https://github.com/xenv/S-mall-servlet/blob/master/src/filter/BackServletFilter.java

  1. 创建 Filter 文件,implements Filter ,override doFilter 方法

  2. 在doFilter 方法中获取 uri

//获取根容器目录
String contextPath = request.getServletContext().getContextPath();
//获取完整 uri
String uri  = request.getRequestURI();
//除根 uri 根目录
uri = StringUtils.remove(uri,contextPath);

  3. 根据不同的 uri ,获取到对应的 函数 名,插入到request中,比如,我们简单在这里直接把根目录下的 uri 直接 转成 函数 名

if(!(uri.contains(".") || (uri.lastIndexOf(‘/‘)>0))){ // 根目录 不含.的 uri
  String method = uri.substring(1);
  request.setAttribute("method",method);
  String servletPath = "front.servlet";
  request.getRequestDispatcher(servletPath).forward(request,response);
...
}
//其他请求放行
filterChain.doFilter(request,response);

 

  4. 根据不同的uri,调用 Servlet,比如,我们简单在这里直接 调用 一个固定的 servlet

String servletPath = "front.servlet";
request.getRequestDispatcher(servletPath).forward(request,response);

  5. 在Servlet中,重写service方法,我们读取 刚刚传进来的 method ,反射调用相关方法,并把  request 和 responce 传进去

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws xception {
        String method = (String)req.getAttribute("method");
        
        //利用反射把url中的方法文本转化为方法进行调用
        req.setCharacterEncoding("utf-8");
        Method m = this.getClass().getMethod(method,HttpServletRequest.class,HttpServletResponse.class);
        String redirect = m.invoke(this,req,resp).toString();
        if(redirect.startsWith("@")){
            resp.sendRedirect(redirect.substring(1));
        }else if(redirect.startsWith("%"))
            resp.getWriter().print(redirect.substring(1));
        else
            req.getRequestDispatcher(redirect).forward(req, resp);

    }

 

  在这里,我们的method会返回一个String,如果这个String是 @ 开头,那么是跳转,相当于 Springmvc 的 (redirect:) ,如果是 %开头,则是返回纯文本,其他开头则 调用那个 JSP (相当于 Springmvc 的视图定位)

  对于非法访问的情况,可能会出错,我们必须要进行错误处理,这里只是简单一个简单演示

  6.在具体method中,我们需要接受 request 和 responce,返回String,例如

public String delete(HttpServletRequest request , HttpServletResponse response){
        int id = Integer.parseInt(request.getParameter("id"));
        service.delete(id);
        return "@/admin/category_list";
}

  7.在web.xml配置 filter 和 servlet

    <filter>
        <filter-name>BackServletFilter</filter-name>
        <filter-class>filter.BackServletFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>BackServletFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <servlet>
        <servlet-name>FrontServlet</servlet-name>
        <servlet-class>servlet.FrontServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>FrontServlet</servlet-name>
        <url-pattern>/front.servlet</url-pattern>
    </servlet-mapping>

  这样,用户访问 /test的时候,就会自动调用 Frontservlet 下面 的 test() 方法,并且根据 该 方法的返回值 来 返回 jsp 文件 或者是 跳转

3.重新理顺一次

  用户访问 url ,先到 Filter ,filter 根据 url ,获取相应的 method 和 servlet ,然后 filter 把控制权交给 servlet, serlvet再根据 method 调用 具体的方法,返回要加载 jsp 文件 或者 跳转,这样我们就实现了和 SpringMVC 大致一样的效果。

 


以上是关于Servlet开发 | 利用 Filter + 反射 处理 URL, 精简 servlet-mapping的主要内容,如果未能解决你的问题,请参考以下文章

java动态注册Filter,Servlet,Listener

java动态注册Filter,Servlet,Listener

Servlet中的Filter怎么使用?

Servlet Filter 过滤器

Filter的开发和使用

Servlet组件之一——Filter过滤器