基于反射抽取父类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";
}
}