1. GenericServlet 抽象类:
1). 是一个 Serlvet. 是 Servlet 接口和 ServletConfig 接口的实现类. 但是一个抽象类. 其中的 service 方法为抽象方法
2). 如果新建的 Servlet 程序直接继承 GenericSerlvet 会使开发更简洁.
3). 具体实现:
①. 在 GenericServlet 中声明了一个 SerlvetConfig 类型的成员变量, 在 init(ServletConfig) 方法中对其进行了初始化
②. 利用 servletConfig 成员变量的方法实现了 ServletConfig 接口的方法
③. 还定义了一个 init() 方法, 在 init(SerlvetConfig) 方法中对其进行调用, 子类可以直接覆盖 init() 在其中实现对 Servlet 的初始化.
④. 不建议直接覆盖 init(ServletConfig), 因为如果忘记编写 super.init(ServletConfig); 而还是用了 SerlvetConfig 接口的方法,则会出现空指针异常.
⑤. 新建的 init(){} 并非 Serlvet 的生命周期方法. 而 init(ServletConfig) 是生命周期相关的方法.
注:为什么添加一个无参的init()方法?相信你有JavaSE的基础就会明白了!在此就不在赘述了,如果你不知道你可以去看一下关于方法的重载、方法的重写、类与父 类的关系之super的用法。
GenericServlet的源码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 public abstract class GenericServletimplements Servlet, ServletConfig, java.io.Serializable{ 2 3 private transient ServletConfig config; 4 5 public GenericServlet() { } 6 /** 7 * 下面的方法是实现Servlet接口中的方法。 8 */ 9 public void destroy() { 10 } 11 12 public ServletConfig getServletConfig() { 13 return config; 14 } 15 16 public String getServletInfo() { 17 return ""; 18 } 19 20 public abstract void service(ServletRequest req, ServletResponse res) 21 throws ServletException, IOException; 22 23 public void init(ServletConfig config) throws ServletException { 24 this.config = config; 25 this.init(); 26 } 27 28 public void init() throws ServletException { 29 30 } 31 32 /** 33 * 下面的方法是实现ServletConfig接口中的方法。 34 */ 35 36 public String getInitParameter(String name) { 37 return getServletConfig().getInitParameter(name); 38 } 39 40 public Enumeration getInitParameterNames() { 41 return getServletConfig().getInitParameterNames(); 42 } 43 44 public ServletContext getServletContext() { 45 return getServletConfig().getServletContext(); 46 } 47 48 public String getServletName() { 49 return config.getServletName(); 50 } 51 52 public void log(String msg) { 53 getServletContext().log(getServletName() + ": "+ msg); 54 } 55 /** 56 * 下面的方法是GenericServlet抽象类自己定义的方法。 57 */ 58 59 public void log(String message, Throwable t) { 60 getServletContext().log(getServletName() + ": " + message, t); 61 } 62 }
2. HttpServlet 抽象类:
1). 是一个 Servlet, 继承自 GenericServlet. 针对于 HTTP 协议所定制.
2). 在service(ServletRequest, ServletResponse) 方法中直接把 ServletReuqest和ServletResponse 转为 HttpServletRequest 和 HttpServletResponse.并调用了重载的 service(HttpServletRequest, HttpServletResponse)方法,在 重载的 service(HttpServletRequest, HttpServletResponse) 获取了请求方式: request.getMethod(). 根据请求方式有创建了doXxx() 方法(xxx 为具体的请求方式, 比如 Get, Post等等方式。)
HttpServlet源码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 public abstract class HttpServlet extends GenericServlet 2 implements java.io.Serializable { 3 4 private static final String METHOD_DELETE = "DELETE"; 5 private static final String METHOD_HEAD = "HEAD"; 6 private static final String METHOD_GET = "GET"; 7 private static final String METHOD_OPTIONS = "OPTIONS"; 8 private static final String METHOD_POST = "POST"; 9 private static final String METHOD_PUT = "PUT"; 10 private static final String METHOD_TRACE = "TRACE"; 11 12 private static final String HEADER_IFMODSINCE = "If-Modified-Since"; 13 private static final String HEADER_LASTMOD = "Last-Modified"; 14 15 private static final String LSTRING_FILE = 16 "javax.servlet.http.LocalStrings"; 17 private static ResourceBundle lStrings = 18 ResourceBundle.getBundle(LSTRING_FILE); 19 public HttpServlet() { } 20 21 protected void doGet(HttpServletRequest req, HttpServletResponse resp) 22 throws ServletException, IOException 23 { 24 String protocol = req.getProtocol(); 25 String msg = lStrings.getString("http.method_get_not_supported"); 26 if (protocol.endsWith("1.1")) { 27 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); 28 } else { 29 resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); 30 } 31 } 32 protected long getLastModified(HttpServletRequest req) { 33 return -1; 34 } 35 36 protected void doHead(HttpServletRequest req, HttpServletResponse resp) 37 throws ServletException, IOException { 38 39 NoBodyResponse response = new NoBodyResponse(resp); 40 41 doGet(req, response); 42 response.setContentLength(); 43 } 44 45 protected void doPost(HttpServletRequest req, HttpServletResponse resp) 46 throws ServletException, IOException { 47 48 String protocol = req.getProtocol(); 49 String msg = lStrings.getString("http.method_post_not_supported"); 50 if (protocol.endsWith("1.1")) { 51 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); 52 } else { 53 resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); 54 } 55 } 56 57 protected void doPut(HttpServletRequest req, HttpServletResponse resp) 58 throws ServletException, IOException { 59 60 String protocol = req.getProtocol(); 61 String msg = lStrings.getString("http.method_put_not_supported"); 62 if (protocol.endsWith("1.1")) { 63 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); 64 } else { 65 resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); 66 } 67 } 68 protected void doDelete(HttpServletRequest req, 69 HttpServletResponse resp) 70 throws ServletException, IOException { 71 72 String protocol = req.getProtocol(); 73 String msg = lStrings.getString("http.method_delete_not_supported"); 74 if (protocol.endsWith("1.1")) { 75 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); 76 } else { 77 resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); 78 } 79 } 80 private static Method[] getAllDeclaredMethods(Class c) { 81 82 if (c.equals(javax.servlet.http.HttpServlet.class)) { 83 return null; 84 } 85 86 Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass()); 87 Method[] thisMethods = c.getDeclaredMethods(); 88 89 if ((parentMethods != null) && (parentMethods.length > 0)) { 90 Method[] allMethods = 91 new Method[parentMethods.length + thisMethods.length]; 92 System.arraycopy(parentMethods, 0, allMethods, 0, 93 parentMethods.length); 94 System.arraycopy(thisMethods, 0, allMethods, parentMethods.length, 95 thisMethods.length); 96 97 thisMethods = allMethods; 98 } 99 100 return thisMethods; 101 } 102 protected void doOptions(HttpServletRequest req, HttpServletResponse resp) 103 throws ServletException, IOException { 104 105 Method[] methods = getAllDeclaredMethods(this.getClass()); 106 107 boolean ALLOW_GET = false; 108 boolean ALLOW_HEAD = false; 109 boolean ALLOW_POST = false; 110 boolean ALLOW_PUT = false; 111 boolean ALLOW_DELETE = false; 112 boolean ALLOW_TRACE = true; 113 boolean ALLOW_OPTIONS = true; 114 115 for (int i=0; i<methods.length; i++) { 116 Method m = methods[i]; 117 118 if (m.getName().equals("doGet")) { 119 ALLOW_GET = true; 120 ALLOW_HEAD = true; 121 } 122 if (m.getName().equals("doPost")) 123 ALLOW_POST = true; 124 if (m.getName().equals("doPut")) 125 ALLOW_PUT = true; 126 if (m.getName().equals("doDelete")) 127 ALLOW_DELETE = true; 128 } 129 130 String allow = null; 131 if (ALLOW_GET) 132 if (allow==null) allow=METHOD_GET; 133 if (ALLOW_HEAD) 134 if (allow==null) allow=METHOD_HEAD; 135 else allow += ", " + METHOD_HEAD; 136 if (ALLOW_POST) 137 if (allow==null) allow=METHOD_POST; 138 else allow += ", " + METHOD_POST; 139 if (ALLOW_PUT) 140 if (allow==null) allow=METHOD_PUT; 141 else allow += ", " + METHOD_PUT; 142 if (ALLOW_DELETE) 143 if (allow==null) allow=METHOD_DELETE; 144 else allow += ", " + METHOD_DELETE; 145 if (ALLOW_TRACE) 146 if (allow==null) allow=METHOD_TRACE; 147 else allow += ", " + METHOD_TRACE; 148 if (ALLOW_OPTIONS) 149 if (allow==null) allow=METHOD_OPTIONS; 150 else allow += ", " + METHOD_OPTIONS; 151 152 resp.setHeader("Allow", allow); 153 } 154 protected void doTrace(HttpServletRequest req, HttpServletResponse resp) 155 throws ServletException, IOException 156 { 157 158 int responseLength; 159 160 String CRLF = "\r\n"; 161 String responseString = "TRACE "+ req.getRequestURI()+ 162 " " + req.getProtocol(); 163 164 Enumeration reqHeaderEnum = req.getHeaderNames(); 165 166 while( reqHeaderEnum.hasMoreElements() ) { 167 String headerName = (String)reqHeaderEnum.nextElement(); 168 responseString += CRLF + headerName + ": " + 169 req.getHeader(headerName); 170 } 171 172 responseString += CRLF; 173 174 responseLength = responseString.length(); 175 176 resp.setContentType("message/http"); 177 resp.setContentLength(responseLength); 178 ServletOutputStream out = resp.getOutputStream(); 179 out.print(responseString); 180 out.close(); 181 return; 182 } 183 184 protected void service(HttpServletRequest req, HttpServletResponse resp) 185 throws ServletException, IOException { 186 187 String method = req.getMethod(); 188 189 if (method.equals(METHOD_GET)) { 190 long lastModified = getLastModified(req); 191 if (lastModified == -1) { 192 // servlet doesn't support if-modified-since, no reason 193 // to go through further expensive logic 194 doGet(req, resp); 195 } else { 196 long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); 197 if (ifModifiedSince < (lastModified / 1000 * 1000)) { 198 // If the servlet mod time is later, call doGet() 199 // Round down to the nearest second for a proper compare 200 // A ifModifiedSince of -1 will always be less 201 maybeSetLastModified(resp, lastModified); 202 doGet(req, resp); 203 } else { 204 resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); 205 } 206 } 207 208 } else if (method.equals(METHOD_HEAD)) { 209 long lastModified = getLastModified(req); 210 maybeSetLastModified(resp, lastModified); 211 doHead(req, resp); 212 213 } else if (method.equals(METHOD_POST)) { 214 doPost(req, resp); 215 216 } else if (method.equals(METHOD_PUT)) { 217 doPut(req, resp); 218 219 } else if (method.equals(METHOD_DELETE)) { 220 doDelete(req, resp); 221 222 } else if (method.equals(METHOD_OPTIONS)) { 223 doOptions(req,resp); 224 225 } else if (method.equals(METHOD_TRACE)) { 226 doTrace(req,resp); 227 228 } else { 229 // 230 // Note that this means NO servlet supports whatever 231 // method was requested, anywhere on this server. 232 // 233 234 String errMsg = lStrings.getString("http.method_not_implemented"); 235 Object[] errArgs = new Object[1]; 236 errArgs[0] = method; 237 errMsg = MessageFormat.format(errMsg, errArgs); 238 239 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); 240 } 241 } 242 private void maybeSetLastModified(HttpServletResponse resp, 243 long lastModified) { 244 if (resp.containsHeader(HEADER_LASTMOD)) 245 return; 246 if (lastModified >= 0) 247 resp.setDateHeader(HEADER_LASTMOD, lastModified); 248 } 249 public void service(ServletRequest req, ServletResponse res) 250 throws ServletException, IOException { 251 252 HttpServletRequest request; 253 HttpServletResponse response; 254 255 try { 256 request = (HttpServletRequest) req; 257 response = (HttpServletResponse) res; 258 } catch (ClassCastException e) { 259 throw new ServletException("non-HTTP request or response"); 260 } 261 service(request, response); 262 } 263 } 264 265 266 /* 267 * A response wrapper for use in (dumb) "HEAD" support. 268 * This just swallows that body, counting the bytes in order to set 269 * the content length appropriately. All other methods delegate to the 270 * wrapped HTTP Servlet Response object. 271 */ 272 // file private 273 class NoBodyResponse extends HttpServletResponseWrapper { 274 private NoBodyOutputStream noBody; 275 private PrintWriter writer; 276 private boolean didSetContentLength; 277 278 // file private 279 NoBodyResponse(HttpServletResponse r) { 280 super(r); 281 noBody = new NoBodyOutputStream(); 282 } 283 284 // file private 285 void setContentLength() { 286 if (!didSetContentLength) 287 super.setContentLength(noBody.getContentLength()); 288 } 289 290 291 // SERVLET RESPONSE interface methods 292 293 public void setContentLength(int len) { 294 super.setContentLength(len); 295 didSetContentLength = true; 296 } 297 298 public ServletOutputStream getOutputStream() throws IOException { 299 return noBody; 300 } 301 302 public PrintWriter getWriter() throws UnsupportedEncodingException { 303 304 if (writer == null) { 305 OutputStreamWriter w; 306 307 w = new OutputStreamWriter(noBody, getCharacterEncoding()); 308 writer = new PrintWriter(w); 309 } 310 return writer; 311 } 312 } 313 314 315 /* 316 * Servlet output stream that gobbles up all its data. 317 */ 318 319 // file private 320 class NoBodyOutputStream extends ServletOutputStream { 321 322 private static final String LSTRING_FILE = 323 "javax.servlet.http.LocalStrings"; 324 private static ResourceBundle lStrings = 325 ResourceBundle.getBundle(LSTRING_FILE); 326 327 private int contentLength = 0; 328 329 // file private 330 NoBodyOutputStream() {} 331 332 // file private 333 int getContentLength() { 334 return contentLength; 335 } 336 337 public void write(int b) { 338 contentLength++; 339 } 340 341 public void write(byte buf[], int offset, int len) 342 throws IOException 343 { 344 if (len >= 0) { 345 contentLength += len; 346 } else { 347 // XXX 348 // isn't this really an IllegalArgumentException? 349 350 String msg = lStrings.getString("err.io.negativelength"); 351 throw new IOException(msg); 352 } 353 } 354 }
3). 实际开发中, 直接继承 HttpServlet, 并根据请求方式复写 doXxx() 方法即可.
4). 优点: 直接由针对性的覆盖 doXxx() 方法; 直接使用 HttpServletRequest 和 HttpServletResponse, 不再需要强转.