继续我们这次的优化,上次是request, 这次是response,同时request,response 针对 引入门面模式,把负责的逻辑隐藏起来,展示一个 好的好的门面给servlet 。
先看下 response
public class JxdResponse implements HttpServletResponse { private static final int BUFFER_SIZE = 1024; JxdRequest request; OutputStream output; PrintWriter writer; String contentType = null; long contentLength = -1; String charset = null; String characterEncoding = null; String protocol = "HTTP/1.1"; public OutputStream getOutput() { return output; } public void setOutput(OutputStream output) { this.output = output; } public JxdResponse(OutputStream output) { this.output = output; } public void setRequest(JxdRequest request) { this.request = request; } //headers是一个保存头信息的map Mapheaders = new ConcurrentHashMap<>(); //默认返回OK String message = getStatusMessage(HttpServletResponse.SC_OK); int status = HttpServletResponse.SC_OK; @Override public void addHeader(String name, String value) { headers.put(name, value); if (name.toLowerCase() == DefaultHeaders.CONTENT_LENGTH_NAME) { setContentLength(Integer.parseInt(value)); } if (name.toLowerCase() == DefaultHeaders.CONTENT_TYPE_NAME) { setContentType(value); } } @Override public void setHeader(String name, String value) { headers.put(name, value); if (name.toLowerCase() == DefaultHeaders.CONTENT_LENGTH_NAME) { setContentLength(Integer.parseInt(value)); } if (name.toLowerCase() == DefaultHeaders.CONTENT_TYPE_NAME) { setContentType(value); } } //"HTTP/1.1 ${StatusCode} ${StatusName}\r\n" + // "Content-Type: ${ContentType}\r\n" + // "Server: minit\r\n" + // "Date: ${ZonedDateTime}\r\n" + public void sendHeaders() throws IOException { PrintWriter outputWriter = getWriter(); //下面这一端是输出状态行 outputWriter.print(this.getProtocol()); outputWriter.print(" "); outputWriter.print(status); if (message != null) { outputWriter.print(" "); outputWriter.print(message); } outputWriter.print("\r\n"); if (getContentType() != null) { outputWriter.print("Content-Type: " + getContentType() + "\r\n"); if (getContentLength() >= 0) { outputWriter.print("Content-Length: " + getContentLength() + "\r\n"); } //输出头信息 Iterator names = headers.keySet().iterator(); while (names.hasNext()) { String name = names.next(); String value = headers.get(name); outputWriter.print(name); outputWriter.print(": "); outputWriter.print(value); outputWriter.print("\r\n"); } //最后输出空行 outputWriter.print("\r\n"); outputWriter.flush(); } } /** * 获取状态码返回信息 * * @param status * @return */ protected String getStatusMessage(int status) { switch (status) { case SC_OK: return ("OK"); case SC_ACCEPTED: return ("Accepted"); case SC_BAD_GATEWAY: return ("Bad Gateway"); case SC_BAD_REQUEST: return ("Bad Request"); case SC_CONTINUE: return ("Continue"); case SC_FORBIDDEN: return ("Forbidden"); case SC_INTERNAL_SERVER_ERROR: return ("Internal Server Error"); case SC_METHOD_NOT_ALLOWED: return ("Method Not Allowed"); case SC_NOT_FOUND: return ("Not Found"); case SC_NOT_IMPLEMENTED: return ("Not Implemented"); case SC_REQUEST_URI_TOO_LONG: return ("Request URI Too Long"); case SC_SERVICE_UNAVAILABLE: return ("Service Unavailable"); case SC_UNAUTHORIZED: return ("Unauthorized"); default: return ("HTTP Response Status " + status); } } /** * 这个方法是静态方法演示 * * @throws IOException */ public void sendStaticResource() throws IOException { byte[] bytes = new byte[BUFFER_SIZE]; FileInputStream fis = null; try { File file = new File(JxdHttpServer.FILE_ROOT, request.getUri()); if (file.exists()) { fis = new FileInputStream(file); int ch = fis.read(bytes, 0, BUFFER_SIZE); while (ch != -1) { output.write(bytes, 0, ch); ch = fis.read(bytes, 0, BUFFER_SIZE); } output.flush(); } else { String errorMessage = "HTTP/1.1 404 FIle Not Found\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 23\r\n" + "\r\n" + " error未知
"; output.write(errorMessage.getBytes()); } } catch (Exception e) { System.out.println(e.toString()); } finally { if (fis != null) { fis.close(); } } } public long getContentLength() { return this.contentLength; } public void setContentLength(long contentLength) { this.contentLength = contentLength; } public String getProtocol() { return protocol; } public void setProtocol(String protocol) { this.protocol = protocol; } @Override public String getContentType() { return this.contentType; } @Override public PrintWriter getWriter() throws IOException { writer = new PrintWriter(new OutputStreamWriter(output, getCharacterEncoding()), true); return writer; } @Override public String getCharacterEncoding() { return characterEncoding; } @Override public void setCharacterEncoding(String characterEncoding) { this.characterEncoding = characterEncoding; } }
我们整理了一下,返回引入一个getStatusMessage 方法和 sendHeaders 方法 这样不用再拼接字符串了。
在看一下我们的 JxdServletProcessor
public void process(JxdRequest request, JxdResponse response) { //首先根据uri最后一个/号来定位,后面的字符串认为是servlet名字 String uri = request.getUri(); String servletName = uri.substring(uri.lastIndexOf("/") + 1); URLClassLoader loader = null; try { // create a URLClassLoader URL[] urls = new URL[1]; URLStreamHandler streamHandler = null; File classPath = new File(JxdHttpServer.WEB_ROOT); String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString(); urls[0] = new URL(null, repository, streamHandler); loader = new URLClassLoader(urls); } catch (IOException e) { System.out.println(e.toString()); } //由上面的URLClassLoader加载这个servlet Class> servletClass = null; Servlet servlet = null; try { HttpRequestFacade requestFacade = new HttpRequestFacade(request); HttpResponseFacade responseFacade = new HttpResponseFacade(response); servletClass = loader.loadClass(servletName); response.setCharacterEncoding("UTF-8"); response.addHeader(DefaultHeaders.CONTENT_TYPE_NAME,"text/html;charset=UTF-8"); response.sendHeaders(); servlet = (Servlet) servletClass.newInstance(); servlet.service(requestFacade, responseFacade); } catch (ClassNotFoundException | IOException e) { System.out.println(e.toString()); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (ServletException e) { e.printStackTrace(); } } }
之前的 OKMessage 拼接 响应字符串方法就不需要了。
同时引入两个门面HttpRequestFacade,HttpResponseFacade
看下 我们的两个类的代码:
public class HttpRequestFacade implements HttpServletRequest { private HttpServletRequest request; public HttpRequestFacade(JxdRequest request) { this.request = request; } public Object getAttribute(String name) { return request.getAttribute(name); } public Enumeration getAttributeNames() { return request.getAttributeNames(); } public String getCharacterEncoding() { return request.getCharacterEncoding(); } @Override public void setCharacterEncoding(String s) throws UnsupportedEncodingException { request.setCharacterEncoding(s); } public int getContentLength() { return request.getContentLength(); } @Override public long getContentLengthLong() { return 0; } public String getContentType() { return request.getContentType(); } @Override public String getAuthType() { return null; } public Cookie[] getCookies() { return request.getCookies(); } @Override public long getDateHeader(String s) { return 0; } @Override public String getHeader(String s) { return null; } public Enumeration getHeaderNames() { return request.getHeaderNames(); } public Enumeration getHeaders(String name) { return request.getHeaders(name); } public ServletInputStream getInputStream() throws IOException { return request.getInputStream(); } public int getIntHeader(String name) { return request.getIntHeader(name); } public String getMethod() { return request.getMethod(); } @Override public String getPathInfo() { return null; } @Override public String getPathTranslated() { return null; } @Override public String getContextPath() { return null; } public String getParameter(String name) { return request.getParameter(name); } public Map getParameterMap() { return request.getParameterMap(); } @Override public String getProtocol() { return null; } @Override public String getScheme() { return null; } @Override public String getServerName() { return null; } @Override public int getServerPort() { return 0; } public Enumeration getParameterNames() { return request.getParameterNames(); } public String[] getParameterValues(String name) { return request.getParameterValues(name); } public String getQueryString() { return request.getQueryString(); } @Override public String getRemoteUser() { return null; } @Override public boolean isUserInRole(String s) { return false; } @Override public Principal getUserPrincipal() { return null; } @Override public String getRequestedSessionId() { return null; } public BufferedReader getReader() throws IOException { return request.getReader(); } @Override public String getRemoteAddr() { return null; } @Override public String getRemoteHost() { return null; } public String getRequestURI() { return request.getRequestURI(); } public StringBuffer getRequestURL() { return request.getRequestURL(); } @Override public String getServletPath() { return null; } public HttpSession getSession() { return request.getSession(); } @Override public String changeSessionId() { return null; } @Override public boolean isRequestedSessionIdValid() { return false; } @Override public boolean isRequestedSessionIdFromCookie() { return false; } @Override public boolean isRequestedSessionIdFromURL() { return false; } @Override public boolean isRequestedSessionIdFromUrl() { return false; } @Override public boolean authenticate(HttpServletResponse httpServletResponse) throws IOException, ServletException { return false; } @Override public void login(String s, String s1) throws ServletException { } @Override public void logout() throws ServletException { } @Override public CollectiongetParts() throws IOException, ServletException { return null; } @Override public Part getPart(String s) throws IOException, ServletException { return null; } @Override public T upgrade(Class aClass) throws IOException, ServletException { return null; } public HttpSession getSession(boolean create) { return request.getSession(create); } public void removeAttribute(String attribute) { request.removeAttribute(attribute); } @Override public Locale getLocale() { return null; } @Override public Enumeration getLocales() { return null; } @Override public boolean isSecure() { return false; } @Override public RequestDispatcher getRequestDispatcher(String s) { return null; } @Override public String getRealPath(String s) { return null; } @Override public int getRemotePort() { return 0; } @Override public String getLocalName() { return null; } @Override public String getLocalAddr() { return null; } @Override public int getLocalPort() { return 0; } @Override public ServletContext getServletContext() { return null; } @Override public AsyncContext startAsync() throws IllegalStateException { return null; } @Override public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException { return null; } @Override public boolean isAsyncStarted() { return false; } @Override public boolean isAsyncSupported() { return false; } @Override public AsyncContext getAsyncContext() { return null; } @Override public DispatcherType getDispatcherType() { return null; } public void setAttribute(String key, Object value) { request.setAttribute(key, value); } }
public class HttpResponseFacade implements HttpServletResponse { private HttpServletResponse response; public HttpResponseFacade(JxdResponse response) { this.response = response; } @Override public void addCookie(Cookie cookie) { response.addCookie(cookie); } @Override public boolean containsHeader(String s) { return response.containsHeader(s); } @Override public String encodeURL(String s) { return response.encodeURL(s); } @Override public String encodeRedirectURL(String s) { return response.encodeRedirectURL(s); } @Override public String encodeUrl(String s) { return response.encodeUrl(s); } @Override public String encodeRedirectUrl(String s) { return response.encodeRedirectUrl(s); } @Override public void sendError(int i, String s) throws IOException { response.sendError(i, s); } @Override public void sendError(int i) throws IOException { response.sendError(i); } @Override public void sendRedirect(String s) throws IOException { response.sendRedirect(s); } @Override public void setDateHeader(String s, long l) { response.setDateHeader(s, l); } @Override public void addDateHeader(String s, long l) { response.addDateHeader(s, l); } @Override public void setHeader(String s, String s1) { response.setHeader(s, s1); } @Override public void addHeader(String s, String s1) { response.addHeader(s, s1); } @Override public void setIntHeader(String s, int i) { response.setIntHeader(s, i); } @Override public void addIntHeader(String s, int i) { response.addIntHeader(s, i); } @Override public void setStatus(int i) { response.setStatus(i); } @Override public void setStatus(int i, String s) { response.setStatus(i, s); } @Override public int getStatus() { return response.getStatus(); } @Override public String getHeader(String s) { return response.getHeader(s); } @Override public CollectiongetHeaders(String s) { return response.getHeaders(s); } @Override public Collection getHeaderNames() { return response.getHeaderNames(); } @Override public String getCharacterEncoding() { return response.getCharacterEncoding(); } @Override public String getContentType() { return response.getContentType(); } @Override public ServletOutputStream getOutputStream() throws IOException { return response.getOutputStream(); } @Override public PrintWriter getWriter() throws IOException { return response.getWriter(); } @Override public void setCharacterEncoding(String s) { response.setCharacterEncoding(s); } @Override public void setContentLength(int i) { response.setContentLength(i); } @Override public void setContentLengthLong(long l) { response.setContentLengthLong(l); } @Override public void setContentType(String s) { response.setContentType(s); } @Override public void setBufferSize(int i) { response.setBufferSize(i); } @Override public int getBufferSize() { return response.getBufferSize(); } @Override public void flushBuffer() throws IOException { response.flushBuffer(); } @Override public void resetBuffer() { response.resetBuffer(); } @Override public boolean isCommitted() { return response.isCommitted(); } @Override public void reset() { response.reset(); } @Override public void setLocale(Locale locale) { response.setLocale(locale); } @Override public Locale getLocale() { return response.getLocale(); } }
没什么难点,主要就是引入门面模式进行整理,之前都暴露着各种方法,用户在使用的时候会看到,同时 也避免 被更改 和强转的风险。