继续我们这次的优化,上次是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
Map<String, String> headers = 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<String> 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" +
"<h1>error未知</h1>";
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 Collection<Part> getParts() throws IOException, ServletException {
return null;
}
@Override
public Part getPart(String s) throws IOException, ServletException {
return null;
}
@Override
public <T extends HttpUpgradeHandler> T upgrade(Class<T> 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<Locale> 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 Collection<String> getHeaders(String s) {
return response.getHeaders(s);
}
@Override
public Collection<String> 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();
}
}
没什么难点,主要就是引入门面模式进行整理,之前都暴露着各种方法,用户在使用的时候会看到,同时 也避免 被更改 和强转的风险。