提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
在学习servlet时会面临一个问题,一个servlet文件只能处理一个请求,针对一个用户的CURD操作,就需要创建许多servlet,看着项目文件目录树,感觉不是很清爽,所以想让一个servlet可以处理多个请求。
当然实现这个需求的方式很多,我讲解的是利用反射
来实现。
先上代码
-
使用反射的类
import javax.servlet.*; import javax.servlet.http.*; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class ForumBaseServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { StringBuffer url = req.getRequestURL(); int i = url.lastIndexOf("/"); String methodName = url.substring(i + 1); System.out.println(methodName); Class<? extends ForumBaseServlet> aClass = this.getClass(); try { Method method = aClass.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); method.invoke(this,req,resp); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } }
-
实现CRUD方法的类
import com.fasterxml.jackson.databind.ObjectMapper; import com.zgx.servlet_day05.entity.ForumUser; import com.zgx.servlet_day05.entity.Message; import com.zgx.servlet_day05.entity.User; import com.zgx.servlet_day05.service.impl.ForumUserServiceImpl; import com.zgx.servlet_day05.service.impl.UserServiceImpl; import com.zgx.servlet_day05.utils.MsgUtils; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; /** * @Description: * @ClassName:Servlet02 * @Author:。。。。 * @CreateDate:2022-08-11 13:33:47 **/ @WebServlet(name = "ForumBaseServlet", value = "/forumuser/*") public class ForumServlet extends ForumBaseServlet{ public void queryAll(HttpServletRequest request, HttpServletResponse response) throws IOException { request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); //接受参数 int limit = Integer.parseInt(request.getParameter("limit")); int page = Integer.parseInt(request.getParameter("page")); String username = request.getParameter("username"); String name = request.getParameter("name"); int startIndex = page * limit - limit; System.out.println("page=" + page + ",limit=" + limit + ",index=" + startIndex); ForumUserServiceImpl service = new ForumUserServiceImpl(); //查询总数 ArrayList<ForumUser> users1 = service.queryAll(); if(username == null && name ==null){ ArrayList<ForumUser> users2 = service.queryAllLimit(startIndex, limit); String msg = MsgUtils.getTabMsg(0, users2.size() > 0 ? "查询成功" : "查询失败", users1.size(), users2); response.getWriter().write(msg); }else { ForumUser forumUser = new ForumUser(); forumUser.setUser_name(username); forumUser.setName(name); ArrayList<ForumUser> users = service.queryAllLike(startIndex,limit,forumUser); String msg = MsgUtils.getTabMsg(0, users.size() > 0 ? "查询成功" : "查询失败", users.size(), users); response.getWriter().write(msg); } } }
分析
-
继承关系
-
原理:因为
ForumServlet
继承了ForumBaseServlet
并配置了映射到该类(ForumServlet
),而ForumBaseServlet
继承HttpServlet
并重写了其中的service()
。那么请求就会先到达
ForumServlet
类,寻找可以处理请求的方法,如doGet()/doPost()
方法,而service()
不分请求方式,而当前类没有找到对应方法,但父类中有,就调用父类中的service()
。在父类
ForumBaseServlet
中先处理URL地址,获取方法名(所以前端传递的URL地址中要包含方法名,如user/queryAll
),通过this.getClass()
获取反射对象,再通过URL地址中获得的方法名,得到一个Method对象,通过invoke(this,方法参数1,方法参数2)
调用方法。 -
this解释:在
ForumBaseServlet
中使用到了this
,代表的含义是谁调用该方法,this就该表谁。因为是在ForumServlet
中配置的映射关系,所以请求先到它,然后再调用父类的service()
,因此this代表的就是子类ForumServlet
注意:配置映射关系的时候,最后面记得是/*
,比如/user/*
,处理所有有关user的请求。
总结:
该方法对比传统通过传参(传递方法名),每次都要获取对应参数,然后判断传递过来的是哪个方法对应的字符串。
而反射形式只需要写一个继承HttpServlet
并重写service(),在里面写通过反射调用方法的代码,就不用管了,只需要在继承该类的子类中写各种CRUD方法就行了。
当然在没有使用框架的阶段可以使用,使用了框架就不用这么麻烦了。