【黑马旅游网】Servlet优化

我们刚刚完成登录模块,每一个功能都对应了一个Servlet,非常的复杂。为了减少Servlet的数量,将其优化为一个模块一个Servlet,相当于在数据库中一张表对应一个Servlet,在Servlet中提供不同的方法,完成用户的请求。

这个方法的核心就在于HttpServlet.service()方法。如下:

 /**
     * Receives standard HTTP requests from the public
     * <code>service</code> method and dispatches
     * them to the <code>do</code><i>XXX</i> methods defined in 
     * this class. This method is an HTTP-specific version of the 
     * {@link javax.servlet.Servlet#service} method. There's no
     * need to override this method.
     *
     * @param req   the {@link HttpServletRequest} object that
     *                  contains the request the client made of
     *                  the servlet
     *
     * @param resp  the {@link HttpServletResponse} object that
     *                  contains the response the servlet returns
     *                  to the client                                
     *
     * @exception IOException   if an input or output error occurs
     *                              while the servlet is handling the
     *                              HTTP request
     *
     * @exception ServletException  if the HTTP request
     *                                  cannot be handled
     * 
     * @see javax.servlet.Servlet#service
     */
    protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String method = req.getMethod();

        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
            
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);
            
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
            
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);
            
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);
            
        } else {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //

            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);
            
            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }

可以看出,这个方法会根据请求类型的不同,进行不同的调用。而我们的Servlet中只是用get和post请求,get请求也是调用post的函数,所以使用它来进行提取,再合适不过。所以我们需要做的就是建立一个公共提取Servlet,来进行不同请求方法的分发。

以下是BaseServlet的代码:

//@WebServlet(name = "BaseServlet")
//不需要被访问到
public class BaseServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("BaseServlet的service方法被执行了");
        //完成方法分发
        //1. 获取请求路径
        String uri = req.getRequestURI();
        System.out.println(uri);
        //2. 获取请求方法名称
        String methodName = uri.substring(uri.lastIndexOf("/") + 1);
        System.out.println(methodName);
        //3. 获取方法对象Method
        //谁调用我,我代表谁
        System.out.println(this);//UserServlet的对象
        try {
//            //getDeclaredMethod()忽略访问权限修饰符,来获取方法
//            Method method = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
//            //4. 执行方法
//            //暴力反思
//            method.setAccessible(true);
            Method method = this.getClass().getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
            method.invoke(this, req, resp);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }
}
  1. 通过getRequestURI()来获取请求路径;
  2. 取最后的方法名;
  3. 通过getMethod()获取方法;
    其中getDeclaredMethod()忽略访问权限修饰符,来获取方法,这种方法可以获取包括私有方法之内的所有方法,这是不合适的,毕竟人家私有的东西,就不要访问了。所以我们使用getMethod(),并将请求方法的修饰符改成public。
  4. 通过invoke()执行。

这样我们就可以通过UserServlet来继承BaseServlet,来实现一个模块对应一个Servlet。代码如下:

@WebServlet("/user/*") // /user/add /user/find
public class UserServlet extends BaseServlet {
    public void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("UserServlet的add方法");
    }

    public void find(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("UserServlet的find方法");
    }
}

到这里,我们就可以把之前的方法全部集成到UserServlet了。

不过别忘了优化还有两重要步骤:

  1. 抽取UserService
  2. 修改前端页面的请求

看到这里,有了解SpringMVC或者SpringBoot的朋友应该明白了,Controller就是对BaseServlet的再次封装。不懂得朋友也不要紧,先混个眼熟,后面自然就明白了。

posted @ 2021-02-03 16:33  朱李洛克  阅读(174)  评论(0编辑  收藏  举报
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css