网页每发一个不同的请求都需要一个servlet去响应,这样servlet很多很乱。可以只写一个servlet对请求作响应,但是servlet内部可以有很多方法,对不同请求作响应。
如下,使用一个operation参数记录网页要求的操作,然后用switch语句转向不同函数进行处理:
- //设置编码方式防止汉字乱码
- req.setCharacterEncoding("UTF-8");
- //根据发送的请求中的operation字段选择方法
- String oper=req.getParameter("operation");
- if (oper==null){
- oper="index";
- }
- switch (oper){
- case "index":
- indexServlet(req,resp);
- break;
- case "edit":
- editServlet(req,resp);
- break;
- case "del":
- delServlet(req,resp);
- break;
- case "insert":
- insertServlet(req,resp);
- break;
- case "update":
- updateServlet(req,resp);
- break;
- default:
- throw new RuntimeException("illegal value for operation");
- }
一、dispatcherServlet
如果网页请求很多,那switch...case...语句会很长。使用反射改写:
- //获取当前类中的所有方法(反射),如果方法名和operation参数相同,就调用该方法
- Method[] methods=this.getClass().getDeclaredMethods();
- for (Method m:methods){
- System.out.println(m.getName());
- }
- for (Method m:methods){
- if(oper.equals(m.getName())){
- try {
- m.invoke(this,req,resp);
- return;
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }
- }
- }
Notations;(1)声明的方法名要和operation值相等;(2)getDeclaredMethods才是获取自己声明的方法。
而在实际中,会有很多servlet类,而每个之中会有很多方法。会有一个dispatcherServlet(中央控制器)来接收前端的请求,然后进行转发到各个类进行处理。可以将对某个请求的所有操作写在一个Controller里面,然后使用一个中央控制器将请求转发给处理它的Controller。
现在src下新建一个xml,将请求和Controller的对应关系写到一个标签里面:
- "1.0" encoding="UTF-8" ?>
- <beans>
-
- <bean id="fruit" class="com.controllers.FruitController"/>
- beans>
然后建立一个中央控制器,获得该文件中的bean标签的对应关系,用一个map存储,这个map称为容器。然后接收到请求后,通过反射查询相应Controller中的所有方法。
- //*是通配符。表示拦截所有结尾.do的请求
- //通配符不能只写一个*
- @WebServlet("*.do")
- public class DispatcherServlet extends ViewBaseServlet {
-
- //创建一个Map用来存放xml的bean标签中的id和class对应。Object是其中class的实例对象
- Map
beanMap=new HashMap(); - //在构造方法中解析xml配置文件
- public DispatcherServlet() throws ParserConfigurationException, IOException, SAXException, ClassNotFoundException, IllegalAccessException, InstantiationException {
- //打开配置文件的流
- InputStream is=getClass().getClassLoader().getResourceAsStream("applicationController.xml");
- //创建一个 DocumentBuilder对象
- DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
- DocumentBuilder db=dbf.newDocumentBuilder();
- //创建Document对象
- Document doc=db.parse(is);
- //获取xml中所有的bean节点
- NodeList beanList=doc.getElementsByTagName("bean");
- for(int i=0;i
- Node beanNode = beanList.item(i);
- //将beanNode强转为Element,为了使用里面的getAttribute方法
- if (beanNode.getNodeType()==Node.ELEMENT_NODE){
- Element nodeElement=(Element) beanNode;
- String beanId=nodeElement.getAttribute("id");
- String beanClass=nodeElement.getAttribute("class");
- //运用反射得到class对应的实例对象
- Object beanObj=Class.forName(beanClass).newInstance();
- beanMap.put(beanId,beanObj);
- }
- }
- }
-
- @Override
- protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- req.setCharacterEncoding("UTF-8");
- String servletPath=req.getServletPath();
- //把请求中的第一个/和后面的.do去掉
- servletPath=servletPath.substring(1,servletPath.lastIndexOf(".do"));
- //这就把beanMap里存放的xml文件里的对应关系给找了出来,也是找到了跟网页请求相对应的Controller对象
- Object beanObject=beanMap.get(servletPath);
-
- String oper=req.getParameter("operation");
- if (oper==null){
- oper="index";
- }
-
- //有了beanObject对象后,其对应的Controller应该有很多方法,对应执行不同的操作
- //通过反射查找该方法,传入参数为oper和req\resp对应的类
- try {
- //oper去匹配函数名字,后面是参数对象的class
- Method m=beanObject.getClass().getDeclaredMethod(oper,HttpServletRequest.class,HttpServletResponse.class);
- if(m!=null){
- m.invoke(beanObject,req,resp);
- }else{
- throw new RuntimeException("oper值非法");
- }
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }
-
- }
- }
二、提取视图资源
在经过Controller的方法处理请求后,一般方法最后会进行重定向或者对当前页面渲染。可以在中央控制器对此集中处理,让方法只返回一个字符串。这样方法可以少抛出异常,也可以不用传入response参数。如下所示:
- //oper去匹配函数名字,后面是参数对象的class
- Method m=beanObject.getClass().getDeclaredMethod(oper,HttpServletRequest.class);
- m.setAccessible(true);
- if(m!=null){
- if(m.invoke(beanObject,req)!=null){
- String redirectStr=(String) m.invoke(beanObject,req);
- //将该str截取,只保留后面的请求名称
- if(redirectStr.startsWith("redirect:")){
- redirectStr=redirectStr.substring("redirect:".length());
- //重定向
- resp.sendRedirect(redirectStr);
- }else{
- super.processTemplate(redirectStr,req,resp);
- }
- }
- }else{
- throw new RuntimeException("oper值非法");
- }
三、在中央控制器处理参数
在Controller的每个函数中都有获取请求中函数的操作,那么可以将此直接在中央控制器处理。如下:
- //获取参数,先反射获取所有参数
- Parameter[] p=m.getParameters();
- //保存参数请求request中各个参数的值,所以函数的参数名要和前端发射的请求的参数名称一样
- Object[] parameterValue=new Object[p.length];
- //如果参数是request,response,session就是直接获取
- for (int i=0;i
- if(p[i].getName().equals("request")){
- parameterValue[i]=req;
- }else if(p[i].getName().equals("response")){
- parameterValue[i]=resp;
- }else if(p[i].getName().equals("session")){
- parameterValue[i]=req.getSession();
- }else {
- parameterValue[i] = req.getParameter(p[i].getName());
- }
- }
-
相关阅读:
一文总结 Google I/O 2023
并发编程CompletableFuture用法
使用定时器按键扫描数码管制作一个可存储数据的秒表
常用js库和框架(jsPlumb)
Hive之函数
C++中为何需要函数
百度实习后端开发一二三面
【操作系统-进程】进程的概念
【LLM之KG】CoK论文阅读笔记
【动手学深度学习】--循环神经网络
-
原文地址:https://blog.csdn.net/small_py_trade/article/details/127528687