JSPday05(Servlet)
Servlet是什么
Servlet就是一个类,试运行在服务器端的一个程序。当jsp翻译之后就是Servlet。Servlet自身为了能够提高更好的并发性,所以将自身设计为了单实例、多线程的一个类,所以会有线程安全性问题。一般解决方式:
1.将所有的具有一定的危险性的字段放置在方法之中。
2.将doXXX方法加入Synchronization(及其不推荐 这会造成无法并发执行)
Servlet架构
Servlet接口
源码:
通过对该接口进行观察,发现在接口下面包含了几个重要的方法:
init():当前Servlet初始化
service(ServletRequest,ServletResponse) :完成
请求的服务响应,处理请求
destroy(): 销毁Servlet
ServletConfig接口
源码:
通过观察该接口,能够发现其中的方法主要作用就是获取到Servlet名称、获取上下文、获取初始化参数及获取所有参数的名称的枚举。
GenericServlet
源码:
1 // 2 // Source code recreated from a .class file by IntelliJ IDEA 3 // (powered by Fernflower decompiler) 4 // 5 6 package javax.servlet; 7 8 import java.io.IOException; 9 import java.io.Serializable; 10 import java.util.Enumeration; 11 import java.util.ResourceBundle; 12 13 public abstract class GenericServlet implements Servlet, ServletConfig, Serializable { 14 private static final String LSTRING_FILE = "javax.servlet.LocalStrings"; 15 private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.LocalStrings"); 16 private transient ServletConfig config; 17 18 public GenericServlet() { 19 } 20 21 public void destroy() { 22 } 23 24 public String getInitParameter(String name) { 25 ServletConfig sc = this.getServletConfig(); 26 if (sc == null) { 27 throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized")); 28 } else { 29 return sc.getInitParameter(name); 30 } 31 } 32 33 public Enumeration<String> getInitParameterNames() { 34 ServletConfig sc = this.getServletConfig(); 35 if (sc == null) { 36 throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized")); 37 } else { 38 return sc.getInitParameterNames(); 39 } 40 } 41 42 public ServletConfig getServletConfig() { 43 return this.config; 44 } 45 46 public ServletContext getServletContext() { 47 ServletConfig sc = this.getServletConfig(); 48 if (sc == null) { 49 throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized")); 50 } else { 51 return sc.getServletContext(); 52 } 53 } 54 55 public String getServletInfo() { 56 return ""; 57 } 58 59 public void init(ServletConfig config) throws ServletException { 60 this.config = config; 61 this.init(); 62 } 63 64 public void init() throws ServletException { 65 } 66 67 public void log(String msg) { 68 this.getServletContext().log(this.getServletName() + ": " + msg); 69 } 70 71 public void log(String message, Throwable t) { 72 this.getServletContext().log(this.getServletName() + ": " + message, t); 73 } 74 75 public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException; 76 77 public String getServletName() { 78 ServletConfig sc = this.getServletConfig(); 79 if (sc == null) { 80 throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized")); 81 } else { 82 return sc.getServletName(); 83 } 84 } 85 }
通过观察源代码,发现该抽象类实现了ServletConfig下的接口所声明的方法,而Servlet接口下的方法,都下沉到子类HttpServlet之中了。
HttpServlet
源码:
1 // 2 // Source code recreated from a .class file by IntelliJ IDEA 3 // (powered by Fernflower decompiler) 4 // 5 6 package javax.servlet.http; 7 8 import java.io.IOException; 9 import java.lang.reflect.Method; 10 import java.text.MessageFormat; 11 import java.util.Enumeration; 12 import java.util.ResourceBundle; 13 import javax.servlet.GenericServlet; 14 import javax.servlet.ServletException; 15 import javax.servlet.ServletOutputStream; 16 import javax.servlet.ServletRequest; 17 import javax.servlet.ServletResponse; 18 19 public abstract class HttpServlet extends GenericServlet { 20 private static final String METHOD_DELETE = "DELETE"; 21 private static final String METHOD_HEAD = "HEAD"; 22 private static final String METHOD_GET = "GET"; 23 private static final String METHOD_OPTIONS = "OPTIONS"; 24 private static final String METHOD_POST = "POST"; 25 private static final String METHOD_PUT = "PUT"; 26 private static final String METHOD_TRACE = "TRACE"; 27 private static final String HEADER_IFMODSINCE = "If-Modified-Since"; 28 private static final String HEADER_LASTMOD = "Last-Modified"; 29 private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings"; 30 private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings"); 31 32 public HttpServlet() { 33 } 34 35 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 36 String protocol = req.getProtocol(); 37 String msg = lStrings.getString("http.method_get_not_supported"); 38 if (protocol.endsWith("1.1")) { 39 resp.sendError(405, msg); 40 } else { 41 resp.sendError(400, msg); 42 } 43 44 } 45 46 protected long getLastModified(HttpServletRequest req) { 47 return -1L; 48 } 49 50 protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 51 NoBodyResponse response = new NoBodyResponse(resp); 52 this.doGet(req, response); 53 response.setContentLength(); 54 } 55 56 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 57 String protocol = req.getProtocol(); 58 String msg = lStrings.getString("http.method_post_not_supported"); 59 if (protocol.endsWith("1.1")) { 60 resp.sendError(405, msg); 61 } else { 62 resp.sendError(400, msg); 63 } 64 65 } 66 67 protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 68 String protocol = req.getProtocol(); 69 String msg = lStrings.getString("http.method_put_not_supported"); 70 if (protocol.endsWith("1.1")) { 71 resp.sendError(405, msg); 72 } else { 73 resp.sendError(400, msg); 74 } 75 76 } 77 78 protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 79 String protocol = req.getProtocol(); 80 String msg = lStrings.getString("http.method_delete_not_supported"); 81 if (protocol.endsWith("1.1")) { 82 resp.sendError(405, msg); 83 } else { 84 resp.sendError(400, msg); 85 } 86 87 } 88 89 private Method[] getAllDeclaredMethods(Class<? extends HttpServlet> c) { 90 Class<?> clazz = c; 91 92 Method[] allMethods; 93 for(allMethods = null; !clazz.equals(HttpServlet.class); clazz = clazz.getSuperclass()) { 94 Method[] thisMethods = clazz.getDeclaredMethods(); 95 if (allMethods != null && allMethods.length > 0) { 96 Method[] subClassMethods = allMethods; 97 allMethods = new Method[thisMethods.length + allMethods.length]; 98 System.arraycopy(thisMethods, 0, allMethods, 0, thisMethods.length); 99 System.arraycopy(subClassMethods, 0, allMethods, thisMethods.length, subClassMethods.length); 100 } else { 101 allMethods = thisMethods; 102 } 103 } 104 105 return allMethods != null ? allMethods : new Method[0]; 106 } 107 108 protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 109 Method[] methods = this.getAllDeclaredMethods(this.getClass()); 110 boolean ALLOW_GET = false; 111 boolean ALLOW_HEAD = false; 112 boolean ALLOW_POST = false; 113 boolean ALLOW_PUT = false; 114 boolean ALLOW_DELETE = false; 115 boolean ALLOW_TRACE = true; 116 boolean ALLOW_OPTIONS = true; 117 118 for(int i = 0; i < methods.length; ++i) { 119 String methodName = methods[i].getName(); 120 if (methodName.equals("doGet")) { 121 ALLOW_GET = true; 122 ALLOW_HEAD = true; 123 } else if (methodName.equals("doPost")) { 124 ALLOW_POST = true; 125 } else if (methodName.equals("doPut")) { 126 ALLOW_PUT = true; 127 } else if (methodName.equals("doDelete")) { 128 ALLOW_DELETE = true; 129 } 130 } 131 132 StringBuilder allow = new StringBuilder(); 133 if (ALLOW_GET) { 134 allow.append("GET"); 135 } 136 137 if (ALLOW_HEAD) { 138 if (allow.length() > 0) { 139 allow.append(", "); 140 } 141 142 allow.append("HEAD"); 143 } 144 145 if (ALLOW_POST) { 146 if (allow.length() > 0) { 147 allow.append(", "); 148 } 149 150 allow.append("POST"); 151 } 152 153 if (ALLOW_PUT) { 154 if (allow.length() > 0) { 155 allow.append(", "); 156 } 157 158 allow.append("PUT"); 159 } 160 161 if (ALLOW_DELETE) { 162 if (allow.length() > 0) { 163 allow.append(", "); 164 } 165 166 allow.append("DELETE"); 167 } 168 169 if (ALLOW_TRACE) { 170 if (allow.length() > 0) { 171 allow.append(", "); 172 } 173 174 allow.append("TRACE"); 175 } 176 177 if (ALLOW_OPTIONS) { 178 if (allow.length() > 0) { 179 allow.append(", "); 180 } 181 182 allow.append("OPTIONS"); 183 } 184 185 resp.setHeader("Allow", allow.toString()); 186 } 187 188 protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 189 String CRLF = "\r\n"; 190 StringBuilder buffer = (new StringBuilder("TRACE ")).append(req.getRequestURI()).append(" ").append(req.getProtocol()); 191 Enumeration reqHeaderEnum = req.getHeaderNames(); 192 193 while(reqHeaderEnum.hasMoreElements()) { 194 String headerName = (String)reqHeaderEnum.nextElement(); 195 buffer.append(CRLF).append(headerName).append(": ").append(req.getHeader(headerName)); 196 } 197 198 buffer.append(CRLF); 199 int responseLength = buffer.length(); 200 resp.setContentType("message/http"); 201 resp.setContentLength(responseLength); 202 ServletOutputStream out = resp.getOutputStream(); 203 out.print(buffer.toString()); 204 } 205 206 protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 207 String method = req.getMethod(); 208 long lastModified; 209 if (method.equals("GET")) { 210 lastModified = this.getLastModified(req); 211 if (lastModified == -1L) { 212 this.doGet(req, resp); 213 } else { 214 long ifModifiedSince = req.getDateHeader("If-Modified-Since"); 215 if (ifModifiedSince < lastModified) { 216 this.maybeSetLastModified(resp, lastModified); 217 this.doGet(req, resp); 218 } else { 219 resp.setStatus(304); 220 } 221 } 222 } else if (method.equals("HEAD")) { 223 lastModified = this.getLastModified(req); 224 this.maybeSetLastModified(resp, lastModified); 225 this.doHead(req, resp); 226 } else if (method.equals("POST")) { 227 this.doPost(req, resp); 228 } else if (method.equals("PUT")) { 229 this.doPut(req, resp); 230 } else if (method.equals("DELETE")) { 231 this.doDelete(req, resp); 232 } else if (method.equals("OPTIONS")) { 233 this.doOptions(req, resp); 234 } else if (method.equals("TRACE")) { 235 this.doTrace(req, resp); 236 } else { 237 String errMsg = lStrings.getString("http.method_not_implemented"); 238 Object[] errArgs = new Object[]{method}; 239 errMsg = MessageFormat.format(errMsg, errArgs); 240 resp.sendError(501, errMsg); 241 } 242 243 } 244 245 private void maybeSetLastModified(HttpServletResponse resp, long lastModified) { 246 if (!resp.containsHeader("Last-Modified")) { 247 if (lastModified >= 0L) { 248 resp.setDateHeader("Last-Modified", lastModified); 249 } 250 251 } 252 } 253 254 public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { 255 if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) { 256 HttpServletRequest request = (HttpServletRequest)req; 257 HttpServletResponse response = (HttpServletResponse)res; 258 this.service(request, response); 259 } else { 260 throw new ServletException("non-HTTP request or response"); 261 } 262 } 263 }
该类中实现了Servlet接口中的一些方法,同时声明处理了大量的HTTP请求相关信息。
除了实现了doXXX方法之外,还重点实现了service方法,该方法的作用通过源码可以发现,就是处理所有请求的主方法,在该方法中通过使用request.getMethod()获取到请求的方式,然后调用对应的doXXX来处理。
Servlet生命周期
实例化对象,Servlet本就是一个单例设计的对象,所以全局只有1个
init()初始化,能够获取到初始化一些参数,对Servlet进行一些初始设置。
service()进行处理请求以及响应服务
destroy():在容器关闭或清空内存时,会调用该方法,执行后销毁当前的servlet方法
使用Servlet完成控制层
将原有的JSP中的控制层代码转移到Servlet中。需要考虑Servlet自身的特性以及请求的方式,是Get还是Post,在其中request、response、application都不是内置对象,需要自己手动获取。
手动获取session对象:
手动获取application:
作为控制层需要完成的任务:
验证数据
封装数据对象
承上启下的请求和响应的处理
登录Servlet代码演示: