BaseServlet 介绍

1. BaseServlet 的作用

  • 让一个Servlet可以处理多种不同的请求,不同的请求调用Servlet的不同方法.

2. 实现原理

  • 客户端发送请求时, 必须多给出一个参数, 用来说明要调用的方法!! 这样,BaseServlet 通过该参数来
    调用目标方法.
  • 请求处理方法的签名必须与 service 相同, 即方法的返回值和参数,以及声明的异常都相同.

// 代码示例
    public class AServlet extends HttpServlet{

        // service 方法
        public void service(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException{

                // 获取参数, 用来识别客户端想请求的方法
                // 然后判断是哪一个方法, 是哪一个方法,就调用哪一个方法.

                // 我们这里给参数的名字为 method
                String methodName = req.getParameter("method");

                if(methodName.equals("addUser")){
                    addUser(req,resp);
                }else if(methodName.equals("editUser")){
                    editUser(req,resp);
                }else if(methodName.equals("deleteUser")){
                    deleteUser(req,resp);
                }
        }

        // 添加客户的方法
        public void addUser(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException{

                System.out.println("addUser()....");
            }

        // 编辑客户的方法
        public void editUser(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException{

                System.out.println("addUser()....");
        }

        // 删除客户的方法
        public void deleteUser(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException{

                System.out.println("addUser()....");
        }
    }


// 升级版
    /*
     * 思路:
     *     得到方法名称, 是否可以通过反射来调用方法?
     * 步骤:
     *    1. 得到方法名, 通过方法名再得到 Method 类的对象
     *    2. 需要得到 class, 然后调用它的方法进行查询! 得到 Method
     *    3. 我们要查询的是当前类的方法, 所以我们需要得到当前类的 Class
     */

public abstact class BaseServlet extends HttpServlet{

    public void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException{

            // 获取参数, 用来识别用户想请求的方法
            String methodName = req.getParameter("method");

            // 判断该参数是否存在, 不存在,抛出异常
            if(methodName == null || methodName.trim().isEmpty()){
                throw new RuntimeException("您没有传递 method 参数! 无法确定您想调用的方法");
            }

            // 得到当前类的 class 对象
             Class c = this.getClass();

            // 查询方法, 参数需要: 方法名和该方法的参数类型
            // 该方法的参数类型必须与 service 中的参数类型一致
            Method method = null;
            try{
                method = c.getMethod(methodName,
                                HttpServletRequest.class, HttpServletResponse.class);
            } catch(Exception e){
                throw new RuntimeException("您要调用的方法"+methodName+",它不存在!");
            }

            // 调用 method 方法
            // 反射调用, 第一参数表示当前类,
            // 正常调用: this.method(req,resp)
            try{
                method.invoke(this,req,resp);  
            } catch(Exception e){                    
                throw new RuntimeException(e);
            }
}

// AServlet 继承 BaseServlet
public void class AServlet extends BaseServlet{
        // 添加客户的方法
        public void addUser(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException{

                System.out.println("addUser()....");
            }

        // 编辑客户的方法
        public void editUser(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException{

                System.out.println("addUser()....");
        }

        // 删除客户的方法
        public void deleteUser(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException{

                System.out.println("addUser()....");
        }    
}

// 处理转发和重定向问题
public void class BServlet extends BaseServlet{

        // 添加客户的方法
        public String addUser(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException{

                System.out.println("addUser()....");

                // 返回表示转发的字符串, "f" 表示 forward
                return "f:/index.jsp";
            }

        // 编辑客户的方法
        public String editUser(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException{

                System.out.println("addUser()....");

                // 返回表示重定向的字符串, "r" 表示 redirect
                return "r:/index.jsp";
        }

        // 删除客户的方法
        public String deleteUser(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException{

                System.out.println("addUser()....");

                return null;
        }    
}

// BaseServlet 升级
public void abstract BaseServlet extends HttpServlet{
    public void service(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException,IOException{

            String methdoName = req.getParameter("method");

            if(methodName == null || methodName.trim().isEmpty()){
                throw new RuntimeException("您没有传递method参数,无法确定要调用的方法!");
            }

            Class c = this.getClass();

            Method method=null;
            try{
                method = c.getMethod(methodName,
                            HttpServletRequest.class,HttpServletResponse.class);
            }catch(Exception e){
                throw new RuntimeException("您要调用的"+methodName+"方法,它不存在!");
            }

            // 调用 method 方法

            try{

                String result = (String)method.invoke(this,req,resp);

                /*
                 * 获取请求处理方法执行后返回的字符串, 它表示转发或重定向的路径!
                 * 完成转发或重定向.
                 *
                 *  如果用户返回的字符串为 null, 或为 "", 那么我们什么也不做!
                 *
                 * 查看返回的字符串中是否包含冒号, 如果没有, 表示转发
                 * 如果有, 使用冒号分割字符串, 得到前缀和后缀!!
                 * 其中前缀如果是 f, 表示转发, 如果是 r, 表示重定向, 后缀就是要转发或重定向的路径了!
                 */

                if(result == null || result.trim().isEmpty()){
                    return;
                }

                // 如果不为空
                if(result.contains(":")){
                    // 使用冒号分割字符串, 得到前缀和后缀
                    int index = result.indexOf(":"); // 获取冒号的位置
                    String s = result.substring(0,index);  // 获取前缀
                    String path = result.subString(index+1); // 获取后缀, 即路径

                    if(e.equalsIgnoreCase("r")){ // 如果前缀是 r, 重定向
                        resp.sendRedirect(req.getContextPath()+path);
                    }else if(e.equalsIgnoreCase("f")){
                        req.getRequestDispatcher(path).forward(req,resp);
                    } else {
                        throw new RuntimeException("您指定的操作:"+s+",当前版本不支持!");
                    }

                } else { // 没有冒号, 默认为转发
                    req.getRequestDispatcher(result).forward(req,resp);
                }


            }catch(Exception e){
                throw new RuntimeException(e);
            }
    }
}

参考资料:

原文地址:https://www.cnblogs.com/linkworld/p/7627132.html