基于反射抽取父类Servlet实现请求处理

基于反射抽取父类Servlet实现请求处理

学习于:https://www.bilibili.com/video/BV1Dh41197mE?share_source=copy_web

背景:

​ 由于在web项目中,Servlet会对于前端传过来的请求携带的method参数(有可能叫其他名字),进行if...else if ...的判断,实现Servlet复用,但是如果每个模块的Servlet都先获得参数,再多轮判断,就会产生很多冗余的代码,于是想到提取出一个父类,来简化代码。至此,我们再创建新的Servlet模块的时候,只需要继承这个父类,然后实现对应的方法就可以完整请求的处理。

分析:

  • Servlet层的共同点:
    • 都会获取前端请求来的路径中的参数,以判断请求方法名;
    • 在处理完请求之后,都会进行相应的后续处理,可以大致分为4种:
      • 1、请求转发----forward
      • 2、重定向----redirect
      • 3、向页面输出内容----write/print;(例如与ajax进行交互)
      • 4、没有任何的处理,这种情形下,可以默认重新回到首页

分析得到这些控制层的共同点之后,就可以根据这些共同点,抽取出方法,由于具体的很多参数都是在实例化的具体Servlet类中才能够得知要调用什么方法,所以利用反射机制,动态的获取处理方法!

父类代码实例:BaseController

package com.wxy.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import com.wxy.util.Constants;

/**
 * @Description: 基于反射实现的父类Servlet,动态的执行子类的处理方法;
 */
public class BaseController extends HttpServlet {

    /**
     * 子类中,只需要重写doGet/doPost 方法,不重写service方法,所以子类会自动调用父类的方法,也就是下面的方法;
     *
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     * @Description: 内容详细介绍;
     * 1、获取方法名:前端提交的url请求中携带着关于请求处理的参数,例如---> url: "/user?method=check...";
     * 2、判断方法名:此时无法得知具体的  method  等于什么,所以对method进行判断;
     * 3、通过反射机制获得当前类的字节码;
     * 4、获得方法对象,执行方法,invoke(执行对象,传入参数)  执行对象:this --->就是当前调用的子类;
     * 5、统一规定方法返回一个String类型的result;供判断处理后的输出或跳转方法;
     * 6、根据方法的返回值,分别处理:请求转发、重定向、向页面输出内容  3种响应方式;
     * 7、在catch异常的时候,向页面携带一个信息,告诉客户出错了,并且让网页自动跳转会首页;
     * 8、在此类中,另外专门写一个index() 方法,专门处理前端传递过来的没有携带method参数的请求;
     */
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //req.setCharacterEncoding("utf-8");

        //获取一个方法名,method="check/login/register.....(req,resp)
        String methodName = req.getParameter(Constants.TAG);//  常量类中定义:Constants.TAG="method"
        //此时无法得知具体的  method  等于什么,所以对method进行判断
        if (methodName == null && "".equals(methodName)) {
            //若前端没有传回method参数,默认前往index页面,
            methodName = Constants.INDEX;   //  Constants.INDEX="index"
        }
        try {
            //获得当前类的字节码
            Class<? extends BaseController> clazz = this.getClass();
            //check(req,resp)
            Method method = clazz.getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
            //result=this.check(req,resp)
            Object result = method.invoke(this, req, resp);
            if (result != null) {
                //返回值:要么带"forward:xxxx",或者"redirect:xxxx",要么是其他
                String str = (String) result;

                //请求转发的请求地址
                String path = str.substring(str.indexOf(Constants.FLAG) + 1);   //  Constants.FLAG=":"
                if (str.startsWith(Constants.FOWARD)) {
                    req.getRequestDispatcher(path).forward(req, resp);
                } else if (str.startsWith(Constants.REDIRECT)) {
                    resp.sendRedirect(path);
                } else {
                    //若不请求也不转发,就向页面输出返回值str
                    resp.getWriter().print(str);
                }
            }
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
            //加入出现异常,就传回一个msg值
            req.setAttribute("msg", "网络异常,请检查自己的网络");
            req.getRequestDispatcher("/message.jsp").forward(req, resp);
        }

    }

    /*
     * 跳转到首页
     *  为默认情况设置方法,如果method=index   就走当前类的这个方法
     */
    public String index(HttpServletRequest req, HttpServletResponse resp) {
        return Constants.FOWARD + "/index.jsp";
    }

}

posted @ 2022-06-24 10:48  devynlime  阅读(62)  评论(0编辑  收藏  举报