我们知道Servlet接口中有5个方法,通过其中一个方法getServletConfig()又可以拓展出四个方法,具体如下:
而开发Servlet的第二种方式,即继承GenericServlet。观察API,可知该类实现 Servlet, ServletConfig接口。所以该类依然有以上所有方法,不过不同的是,类与方法直接的关系是直接调用。
如果我们需要调用ServletConfig类的方法,就不需要像实现Servlet接口那样先去创建ServletConfig对象,然后再去调用该对象的方法。而现在只需要直接调用想要的方法即可,是不是简便了一些。
这就是开发Serlvet的第二种方式。
不管是实现Servlet接口还是继承GenericServlet类,我们需要做的便是重写public void service(ServletRequest req, ServletResponse res) 方法,而ServletRequest及ServletResponse都是接口,为了实现更加强大的功能,我们需要进行向下转型。
public void service(ServletRequest req, ServletResponse res) {
//多态:分为向上转型与向下转型
//上转型:将子类引用赋值给父类应用
//下转型:将父类引用赋值给子类引用,但Java中式不支持真正的下转型。
// 但若父类对象本身使用子类对象上转型而来,那么,可以通过强转的方式,将其赋值给子类对象
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
//在子类或实现类中我们可以定义增加一个方法,利用重载,调用下面这个方法
service(request, response);
}
private void service(HttpServletRequest request, HttpServletResponse response) { }
我们将业务逻辑代码写入上面的方法中即可。
而开发Servlet的第三种方式恰好替我们完成了这种操作,即
作为子类,我们只需要重写 service(HttpServletRequest request, HttpServletResponse response),完成业务逻辑的处理。除此之外,我们还可以通过该类判断请求是以什么方式进行的提交。
同时该类与GenericServlet一样实现Servlet接口和ServletConfig接口,所以其具有GenericServlet的方法。显而易见,HttpServlet的功能更加强大,所以我们可以选择继承HttpServlet去开发。以下为service(HttpServletRequest req, HttpServletResponse resp)的源代码:
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) {
doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
} catch (IllegalArgumentException iae) {
ifModifiedSince = -1;
}
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
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 {
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);
}
}
观察源代码,我们可知,通过判断请求的方式,调用不同的方法。那么子类是去重写service(HttpServletRequest req, HttpServletResponse resp)方法,还是去重写doXXX()方法?答案是不唯一的,你可以去只重写doXXX()方法,但我更让更倾向于重写service(HttpServletRequest req, HttpServletResponse resp),然后根据自己的选择是否需要区分请求方式,若要区分,则重写doXXX()方法,并在你所重写的service()方法中调用doXXX()方法。
以上几节内容便是开发Servlet的三种方式,但Servlet依然有很多知识需要我们去学习。