在不使用 DispatcherServlet 之前我们通常在 web.xml 文件中注册 Servlet 接口实现类来完成对客户请求的处理,且每一个请求对应一个 Servlet接口实现类
Demo01Servlet
com.Servlet.www.Demo01Servlet
Demo01Servlet
/demo01
同时每个Servlet 接口实现类都需要继承 HttpServlet 并重写 doGet 和 doPost 方法,
public class Demo01Servlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//处理get请求,获取参数
String user = req.getParameter("user");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//处理post请求,获取参数
String user = req.getParameter("user");
}
}
如果这样配置,如果 Servlet 的数目少还可以接受,否则会导致配置繁琐且 Servlet的数目过多,我们会写一大堆的Sevlet 类以及 getParameter("") 来获取参数。有没有更好的方法呢??
Servlet 版本二:为了避免 Servlet 的数目过多,我们把对同一个表的不同 *** 作请求都对应一个 Servlet,如:IndexServlet /AddUserServlet /EditUserServlet /DelUserServlet /UpdateUserServlet -> 合并成 UserServlet,同时把请求都指向 UserServlet,通过在请求体中添加 operate 键值对指明请求方法使用 switch-case 通过 operate 的值来决定调用 UserServlet 中的哪一个方法。
String operate = req.getParameter("operate");
方法一:通过switch方法:适用于方法少的 Servlet 类
switch(operate){
case"index": index(req,resp); break;
case"add": add(req,resp); break;
case"del": del(req,resp); break;
case"edit": edit(req,resp); break;
case"update": update(req,resp); break;
default: throw new RuntimeException("operate错误");
}
Servlet 版本三:
在上一个版本中, UserServlet 中充斥着大量的 switch-case,如果项目的业务规模扩大,那么会有很多的 Servlet 方法,也就意味着会有很多的 switch-case,这是一种代码冗余。所以我们可以在 UserServlet 中使用反射技术,通过反射获取 UserServlet 的所有方法,并一一于 operate 的值进行对比,如果operate 的值和方法名一致,那么接收到operate的值是什么就表明我们需要调用对应的方法进行响应,如果找不到对应的方法,则抛异常
String operate = req.getParameter("operate");
Method[] methods = this.getClass().getDeclaredMethods();
label:while(true){
for(Method method : methods){
String name = method.getName();
if(operate.equals(name)){
try{
method.invoke(this,req,resp);
break label;
}catch(IllegalAccessException e){
e.printStackTrace();
}catch(InvocationTargetException e){
e.printStackTrace();
}
}
}
throw new RuntimeException("operate错误");
}
DispatcherServlet :
在 Servlet 版本三中我们使用了反射技术,但是其实还是存在一定的问题:每一个Servlet中都有类似的反射技术的代码。存在代码冗余,因此继续抽取,设计了中央控制器类:DispatcherServlet
DispatcherServlet 这个类的工作分为两大部分:
1.根据URL定位到能够处理这个请求的 controller组件:从URL中提取servletPath : /user-> user
String servletPath = req.getServletPath();
servletPath = servletPath.substring(1);
根据 user 找到对应的组件: UserController , 这个对应的依据我们存储在applicationContext.xml中
通过DOM技术我们去解析 applicationContext.xml 文件,在中央控制器中形成一个beanMap容器,用来存放所有的Controller组件
private Map beanMap = new HashMap<>();
@Override
public void init(){
try{
InputStream applicationContext = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Documentdocument = documentBuilder.parse(applicationContext);
NodeList beansNodeList = document.getElementsByTagName("bean");
for(int i=0; i
根据获取到的 operate 的值定位到我们 UserController中需要调用的方法
Object obj = beanMap.get(servletPath);
Stringoperate=req.getParameter("operate");
if(Utils.isEmpty(operate)){
operate="index";
}
try{
Method method=obj.getClass().getDeclaredMethod(operate,HttpServletRequest.class,HttpServletResponse.class);
if(method!=null){
method.setAccessible(true);
method.invoke(obj,req,resp);
}else{
throw new RuntimeException("operate错误");
}
}catch(NoSuchMethodExceptione){
e.printStackTrace();
}catch(IllegalAccessExceptione){
e.printStackTrace();
}catch(InvocationTargetExceptione){
e.printStackTrace();
}
2.调用Controller组件中的方法:
这个时候我们要考虑一个问题,如果方法需要参数怎么办?
我们可以通过反射来获取要调用的方法的参数签名信息,Parameter[] parameters = method.getParameters();
通过parameter.getName()获取参数的名称,参数名称默认是arg0...样式,因为在编译字节码文件时,舍弃了参数的名称,此时需要在构建执行部署——>编译器——>java编译器中输入parameters;
准备了Object[] parameterValues 这个数组用来存放对应参数的参数值。
另外,我们需要考虑参数的类型问题,需要做类型转化的工作。通过parameter.getType()获取参数的类型。
@Override
protected void service( HttpServletRequest req , HttpServletResponse resp ) throws ServletException , IOException{
req.setCharacterEncoding("UTF-8");
//获取servlet路径
String servletPath = req.getServletPath();
servletPath = servletPath.substring(1);
//通过servlet路径获取相应的对象
Object obj = beanMap.get(servletPath);
String operate = req.getParameter("operate");
if(Utils.isEmpty(operate)){
operate="index";
}
try{
//通过servlet对象获取servlet对象全部方法
Method[] declaredMethods = obj.getClass().getDeclaredMethods();
for(Method method: declaredMethods){
if(operate.equals(method.getName())){
if(method!=null){
//获取请求参数
Parameter[] parameters = method.getParameters();
Object[] parametersValues = new Object[parameters.length];
for(int i=0;i
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)