• 手写一个民用Tomcat (05)


    继续我们这次的优化,上次是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 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 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 Collection getParts() 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 Collection getHeaders(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();
        }
    }

    没什么难点,主要就是引入门面模式进行整理,之前都暴露着各种方法,用户在使用的时候会看到,同时 也避免 被更改 和强转的风险。

  • 相关阅读:
    【数据挖掘 & 机器学习 | 时间序列】时间序列必学模型: ARIMA超详细讲解
    (Open Shortest Path First,OSPF)实验4
    已解决ModuleNotFoundError: No module named ‘requests‘
    美创科技获浙江省网络空间安全协会多项荣誉认可
    windows10/11子系统安装ubuntu22.04
    kali/debain/linux包管理
    【动态库】Ubuntu 添加动态库的搜索路径
    Priority queue(优先队列的常见用法)和算法题(数据流中的中位数)
    java——Junit单元测试
    洛谷题单 Part 2.3 二分答案
  • 原文地址:https://blog.csdn.net/weixin_39831786/article/details/137831007