【黑马旅游网】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();
}
}
}
- 通过getRequestURI()来获取请求路径;
- 取最后的方法名;
- 通过getMethod()获取方法;
其中getDeclaredMethod()忽略访问权限修饰符,来获取方法,这种方法可以获取包括私有方法之内的所有方法,这是不合适的,毕竟人家私有的东西,就不要访问了。所以我们使用getMethod(),并将请求方法的修饰符改成public。 - 通过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了。
不过别忘了优化还有两重要步骤:
- 抽取UserService
- 修改前端页面的请求
看到这里,有了解SpringMVC或者SpringBoot的朋友应该明白了,Controller就是对BaseServlet的再次封装。不懂得朋友也不要紧,先混个眼熟,后面自然就明白了。