关于 Servlet 你需要知道哪些?

目录

Servlet

ServletConfig

ServletContext

ServletRequest

ServletResponse        

总结

GenericServlet

HttpServlet

HttpServletRequest

HttpServletResponse

关于请求和响应的乱码问题


Servlet

        Servlet 是 java 编写的服务端程序,用户可以自己写一些逻辑代码,用于处理客户端发送来的请求及返回响应的结果。Java 语言编写了 Servlet 的接口用于定义 Servlet 的一些规范,但是我们平常会讲任何实现了该接口的类都成为 Servlet。

        Servlet 只有依赖 Servlet 容器才能真正发挥作用,而 Servlet 容器只有具备了各式各样的 Servlet 才能拥有丰富多彩的业务功能实现能力。可以比喻 Servlet 容器为计算机, Servlet 为各式各样的软件,如果计算机没有操作系统以及各式各样的软件,那么它就只是一个冷冷的没有感情的机器,但是各式各样的软件就给其注入的灵魂,相反,没有计算机作为载体,那么这么多花里胡哨的软件也是没法发挥它的价值的。

        俗话说无规矩不成方圆,既然 Servlet 容器需要跟 Servlet 协作共事,就需要定一些规矩,Servlet 的作用主要就是为了写一些业务逻辑,因为业务是无法确定的,每个公司甚至每个功能都有其特有的业务,这是没办法抽象出来的,那么业务方法交由程序员针对自己公司的情况去编写。但是 Servlet 容器是可以抽象出来一些功能出来的,比如说怎么管理 Servlet,什么时候调用 Servlet 编写的业务方法,不同的 Servlet 是可以才用同样的处理策略的,Java 提供的 Servlet 接口就是这么一个 Servlet 规范。

public interface Servlet {

    // 当客户端判断出客户的请求需要某个 Servlet 来处理时,就需要创建出一个 Servlet 实例,然后就会调用 init 初始化方法,但是每个 Servlet 只会调用一次该方法。其实它跟 Spring 中InitializingBean.afterPropertiesSet 很像。
    public void init(ServletConfig config) throws ServletException;
    
    // 返回 Servlet 的配置信息
    public ServletConfig getServletConfig();
    
    // 程序员可以在该方法编写业务逻辑,当 Servlet 容器识别到客户的请求时,就会调用对应 Servlet 的 service 方法来处理客户的请求,当然每次请求都会响应调用一次该方法
    public void service(ServletRequest req, ServletResponse res)
	throws ServletException, IOException;
	
	// 获取 Servlet 的信息
    public String getServletInfo();
    
    // 容器或者web程序关闭时,会调用 Servlet 的 destory 方法销毁 Servlet
    public void destroy();
}

        每个 Servlet 在 Servlet 容器中都只有一个实例,所以每个 init 方法都只会被调用一次,初始化的时候传入了 ServletConfig 参数,以便在初始化 Servlet 的时候可以使用配置信息做一些初始化操作。

        当发生用户请求的时候,Servlet 容器会调用对应 Servlet 的 service 方法,同时 Servlet 容器会把客户端请求封装成 ServletRequest 对象以及创建一个 ServletResponse 对象传递给 Servlet,然后 Servlet 就可以专心写自己业务部分的代码,最终将结果写入 ServletResponse 对象中,最终 Servlet 容器再将结果返回给客户端。

        当卸载应用程序或者直接关闭 Servlet 容器的时候就会调用 destroy 方法,用于销毁 Servlet。

        可以看到对于我们一般程序员来说,只需要在 service 方法中写一下业务逻辑,然后将结果写入 Servlet 容器生成的 ServletResponse 中就好了,其他的都是 Servlet 容器来做的。

ServletConfig

public interface ServletConfig {
    
    // 返回 Servlet 的名称,在 web.xml 中配置
    public String getServletName();

    // 返回 ServletContext 的引用,可以认为它是 web 程序的全局变量,各个 Servlet 可以共享该变量的值
    public ServletContext getServletContext();

    // 获取初始化参数的值
    public String getInitParameter(String name);

    // 获取初始化参数的名称
    public Enumeration<String> getInitParameterNames();

}

ServletContext

public interface ServletContext {

    // 返回该应用的上下文路径信息,如果什么都没有配置默认为 /,假如 Servlet 路径为 /test, 如果没有配置上下文路径,那么访问的时候可能直接 localhost:8080/test 就可以,但是如果上下文路径配置了 cison,那么必须访问 localhost:8080/cison/test, 且该配置对所有的 Servlet 都生效。
    public String getContextPath();

    // 获取上下文对象
    public ServletContext getContext(String uripath);

    // 获取指定文件的 MIME 类型,由 Servlet 容器配置,常见的类型有 text/html, image/gif 等
    public String getMimeType(String file);

    // 返回 Servlet 容器的名称和版本信息
    public String getServerInfo();

    // 获取初始化参数的值
    public String getInitParameter(String name);

    // 获取所有初始化参数的名称
    public Enumeration<String> getInitParameterNames();

    // 设置全局初始化参数属性名和属性值
    public boolean setInitParameter(String name, String value);

    // 获取容器的属性对象信息
    public Object getAttribute(String name);

    // 获取 Servlet 容器可用的属性名列表
    public Enumeration<String> getAttributeNames();

    // 设置属性信息
    public void setAttribute(String name, Object object);

    // 移除属性信息
    public void removeAttribute(String name);

    // 获取 web 应用名称
    public String getServletContextName();

    // 通过 servletName 和 Servlet 的 className 添加 Servlet, 此外还能通过操作返回结果进一步修改该 Servlet 的一些信息。
    public ServletRegistration.Dynamic addServlet(
        String servletName, String className);

    // 通过 Servlet 名字和 Servlet 实例来添加 Servlet
    public ServletRegistration.Dynamic addServlet(
        String servletName, Servlet servlet);

    // 通过 Servlet 和 Servlet 的类类型添加 Servlet 
    public ServletRegistration.Dynamic addServlet(String servletName,
        Class <? extends Servlet> servletClass);

    // 通过 Servlet 类信息实例化一个 Servlet 
    public <T extends Servlet> T createServlet(Class<T> clazz)
        throws ServletException;

    // 根据 Servlet 名称获取 Servlet 注册器
    public ServletRegistration getServletRegistration(String servletName);

    // 获取所有的 Servlet 注册器, key:Servlet 名称; value:ServletRegistration
    public Map<String, ? extends ServletRegistration> getServletRegistrations();

    // 根据过滤器名称和过滤器类名添加一个过滤器
    public FilterRegistration.Dynamic addFilter(
        String filterName, String className);

    // 根据过滤器名称和过滤器实例添加一个过滤器
    public FilterRegistration.Dynamic addFilter(
        String filterName, Filter filter);

    // 还是添加过滤器
    public FilterRegistration.Dynamic addFilter(String filterName,
        Class <? extends Filter> filterClass);

    // 创建一个过滤器实例
    public <T extends Filter> T createFilter(Class<T> clazz)
        throws ServletException;

    // 根据过滤器名称获取过滤器注册器
    public FilterRegistration getFilterRegistration(String filterName);

    // 获取所有的过滤器注册器
    public Map<String, ? extends FilterRegistration> getFilterRegistrations();

    // 获取 SessionCookie 配置
    public SessionCookieConfig getSessionCookieConfig();

    // 以下几个方法为添加监听器
    public void addListener(String className);

    public <T extends EventListener> void addListener(T t);

    public void addListener(Class <? extends EventListener> listenerClass);
    
    // 创建一个监听器实例
    public <T extends EventListener> T createListener(Class<T> clazz)
        throws ServletException;

    // 获取类加载器
    public ClassLoader getClassLoader();

    // 获取 session 的超时时间
    public int getSessionTimeout();

    // 设置 session 的超时时间
    public void setSessionTimeout(int sessionTimeout);

    // 获取请求字符编码类型
    public String getRequestCharacterEncoding();

    // 设置请求字符编码类型
    public void setRequestCharacterEncoding(String encoding);

    // 获取返回结果的编码类型
    public String getResponseCharacterEncoding();

    //设置返回结果的编码类型
    public void setResponseCharacterEncoding(String encoding);
}

        上面接口信息只列出了我认为比较重要的一部分,从上也可以看出 ServletContext 可以用来操作一些属性信息,且这些属性信息是整个 web 应用共享。还能添加创建 Servlet, 过滤器,监听器等。此外还能设置请求和返回结果的编码格式。

        由上面的分析也可以知道可以通过 ServletConfig 获取到 ServletContext 对象,而 ServletConfig 会在调用 Servlet.init 方法的时候传递给 Servlet,这样所有的 Servlet 都可以使用这个全局对象了。

ServletRequest

public interface ServletRequest {

    // 根据属性名获取属性对象
    public Object getAttribute(String name);
    
    // 获取请求参数中包含哪些属性名称
    public Enumeration<String> getAttributeNames();
    
    // 获取请求参数的字符编码类型
    public String getCharacterEncoding();

    // 设置请求参数的字符编码类型
    public void setCharacterEncoding(String env) throws UnsupportedEncodingException;

    // 获取请求体的长度,如果长度不知道或者大于 Integer.MAX_VALUE 则会返回 -1
    public int getContentLength();
    
    // 获取请求体的长度,如果是未知长度则会返回 -1
    public long getContentLengthLong();
    
    // 获取请求体的类型
    public String getContentType();
    
    // 获取请求体的输入流对象
    public ServletInputStream getInputStream() throws IOException; 
     
    // 获取请求参数值
    public String getParameter(String name);
    
    // 获取请求参数名称
    public Enumeration<String> getParameterNames();
        
    // 获取所有的参数值
    public String[] getParameterValues(String name);
 
    // 获取映射关系的请求参数信息
    public Map<String, String[]> getParameterMap();
    
    // 获取协议名称和版本
    public String getProtocol();
    
    // 获取请求的主机地址
    public String getServerName();
    
    // 获取请求哪一个端口
    public int getServerPort();
    
    // 获取请求的 Reader 对象
    public BufferedReader getReader() throws IOException;
    
    // 获取客户端地址
    public String getRemoteAddr();
    
    // 获取客户端主机名称
    public String getRemoteHost();
    
    // 设置请求属性
    public void setAttribute(String name, Object o);
    
    // 移除请求的属性
    public void removeAttribute(String name);
    
    // 获取客户端地区信息
    public Locale getLocale();
    
    // RequestDispatcher是一个Web资源的包装器,可以用来把当前request传递到该资源,或者把新的资源包括到当前响应中。RequestDispatcher接口中定义了两个方法:include/forward
    public RequestDispatcher getRequestDispatcher(String path);
    
    // 客户端端口 
    public int getRemotePort();

    // 服务器主机名称
    public String getLocalName();

    // 服务器地址   
    public String getLocalAddr();

    //服务器端口
    public int getLocalPort();

    // 获取 ServletContext 对象
    public ServletContext getServletContext();
}

ServletResponse        

public interface ServletResponse {
    
    // 响应字符编码类型
    public String getCharacterEncoding();
    
    // 获取响应内容的编码类型
    public String getContentType();

    // 响应输出流(主要用于操作二进制)
    public ServletOutputStream getOutputStream() throws IOException;
    
    // 响应输出流 (能操作二进制数据还能直接操作文件等)
    public PrintWriter getWriter() throws IOException;
    
    // 设置响应字符编码类型
    public void setCharacterEncoding(String charset);
    
    // 设置响应体长度
    public void setContentLength(int len);
    public void setContentLengthLong(long len);

    // 设置响应内容编码类型
    public void setContentType(String type);
    
    // 设置响应缓冲区大小
    public void setBufferSize(int size);
   
    // 获取相应缓冲区大小
    public int getBufferSize();
    
    // 刷新缓冲区,将缓冲区内内容刷新到客户端,也可以理解为手动提交
    public void flushBuffer() throws IOException;
    
    
    // 清空该 response 在缓冲区内的内容,但是响应头或者状态码会保留
    public void resetBuffer();
    
    // 判断该响应是否已经被提交
    public boolean isCommitted();
    
    // 清空响应缓冲区中的所有内容,包括响应头和状态码, 且不会提交到客户端
    public void reset();

}

        ServletResponse 通过输出流对象来控制响应消息的回写,且增加了缓冲区的概念,可以使用缓冲区保存数据,待响应数据达到一定量之后再响应给客户端。

总结

        上面这几个对象其实就已经定好了 Servlet 与 Servlet 容器合作时所依据的规范,Servlet 容器会构造出 ServletConfig 对象,它包括应用上下文信息以及初始化参数信息等,会在调用 Servlet.init 的方法时传给 Servlet。Servlet 容器还会根据客户端的请求构造请求对象,其中就包含了请求的所有信息,包括请求头,请求行,请求体等。还实例化了一个响应对象 ServletResponse 对象,Servlet 可以直接使用该对象的接口响应客户端的请求。ServletRequest 和 ServletResponse 对象会在调用 Servlet.service 方法的时候传递给 Servlet。由此可见,整个请求响应过程大部分都是由 Servlet 容器来处理的,而在实现业务功能的时候只需要重写 Servlet.service 方法并将处理后的最终结果通过 ServletResponse 来返回给客户端。

GenericServlet

        前面说的内容一起强调是规范,因为上面讲的都是接口层的内容,它并没有任何实现逻辑,只是规定了一些属性或者方法,但是真正运行程序的时候是需要具体实现逻辑的,如果自己写 Servlet 的时候还要将各个方法都重新实现一遍,那样既麻烦又不规范,GenericServlet 就是来解决这个问题的,它实现了 Servlet 和 ServletConfig 接口,并且帮我们实现了一些逻辑,我们再进行开发的时候直接继承该抽象类什么都不干就已经具备了一些基本功能了。简便了我们的开发流程。

public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable
{   
    // 维护 ServletConfig 变量,用于接收保存 Servlet 容器传过来的 ServletConfig 对象
    private transient ServletConfig config;

    // 无参构造方法
    public GenericServlet() { }
    
    // 销毁 Servlet 方法,没有实现逻辑
    public void destroy() {
    }
    
    // 添加 getInitParameter 逻辑,即从 ServletConfig 对象中获取
    public String getInitParameter(String name) {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getInitParameter(name);
    }
    
    // 添加初始化参数的信息,也是从 ServletConfig 中获取
    public Enumeration<String> getInitParameterNames() {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getInitParameterNames();
    }   
     
    // 获取 ServletConfig 对象
    public ServletConfig getServletConfig() {
	    return config;
    }
 
    // 获取 ServletContext 对象, 也是从 ServletConfig 中获取
    public ServletContext getServletContext() {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getServletContext();
    }

    // 获取 ServletInfo 信息,默认返回空字符串,可以重写该方法返回想返回的字符串信息
    public String getServletInfo() {
	    return "";
    }
    
    // GenericServlet 的初始化方法,Servlet 容器会调用该方法把 ServletConfig 对象传过来
    public void init(ServletConfig config) throws ServletException {
        // 保存容器传过来的 ServletConfig 对象
	    this.config = config;
        // 如果自己编写的 Servlet 继承了 GenericServlet, 那么在这里就会调用自己编写的 Servlet.init() 方法进行初始化操作。
	    this.init();
    }

    // 该方法主要是为了让子类,也就是我们自己写的 Servlet 覆写来实现一些自己的初始化逻辑,且不用再重新维护 ServletConfig 对象,因为上面的一个方法已经帮我们维护好了
    public void init() throws ServletException {

    }
    
    // 日志信息 
    public void log(String msg) {
	    getServletContext().log(getServletName() + ": "+ msg);
    }
   
    public void log(String message, Throwable t) {
	    getServletContext().log(getServletName() + ": " + message, t);
    }
    
    // service 还是有子类来实现
    public abstract void service(ServletRequest req, ServletResponse res)
	throws ServletException, IOException;
    
    // 获取 Servlet 的名称,也是从 ServletConfig 中获取
    public String getServletName() {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getServletName();
    }
}

HttpServlet

        如果是单机内网完成一些简单的逻辑,只需要继承 GenericServlet 来完成一些基本的功能在本机跑着就行了,可是目前基本所有的应用程序都要与 HTTP 结合起来使用,我们需要将 HTTP 与 Servlet 结合起来,这就引出了 HttpServlet。

        HttpServlet 继承 GenericServlet,在基本 Servlet 功能上再加上一些网络特性的功能,比如接受请求和响应结果。这也引出了 HttpServletRequest 和 HttpServletResponse 这两个分别是上面提到的 ServletRequest 和 ServletResponse 接口。通过这两个接口的实例来进行请求解析和响应结果的操作。首先看下 HttpServlet 接口

public abstract class HttpServlet extends GenericServlet
{
    private static final String METHOD_DELETE = "DELETE";
    private static final String METHOD_HEAD = "HEAD";
    private static final String METHOD_GET = "GET";
    private static final String METHOD_OPTIONS = "OPTIONS";
    private static final String METHOD_POST = "POST";
    private static final String METHOD_PUT = "PUT";
    private static final String METHOD_TRACE = "TRACE";

    private static final String HEADER_IFMODSINCE = "If-Modified-Since";
    private static final String HEADER_LASTMOD = "Last-Modified";
    
    private static final String LSTRING_FILE =
        "javax.servlet.http.LocalStrings";
    private static ResourceBundle lStrings =
        ResourceBundle.getBundle(LSTRING_FILE);
   
    // 这个构造方法没啥用,因为他是个抽象方法,不会被实例化的
    public HttpServlet() { }
    
    // 该方法用于处理 doGet 请求,需要字类重写该处理逻辑
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }
    
    // 获取 HttpServletRequest 上次被修改的时间,默认为 -1, 字类可以重写该逻辑
    protected long getLastModified(HttpServletRequest req) {
        return -1;
    }
    
    // 处理 Head 请求,需要字类重写该方法逻辑
    protected void doHead(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        NoBodyResponse response = new NoBodyResponse(resp);
        
        doGet(req, response);
        response.setContentLength();
    }

    // 处理 post 请求的方法
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_post_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }

    // 处理 put 请求的方法
    protected void doPut(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_put_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }

    // 处理 delete 方法
    protected void doDelete(HttpServletRequest req,
                            HttpServletResponse resp)
        throws ServletException, IOException
    {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_delete_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }
    
    // HttpServlet 的 service 方法,主要用于判断是哪种类型的 Http 请求,然后调用对应的处理方法。HttpServletRequest 为 ServletRequest 的字类,HttpServletResponse 为 ServletResponse 的字类
    protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String method = req.getMethod();

        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
            
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);
            
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
            
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);
            
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);
            
        } else {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //

            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);
            
            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }
    
    // 重写 Servlet 接口的 service 方法,因为容器传递过来的 ServletRequest 和 ServletResponse 对象分别就是 HttpServletRequest 和 HttpServletResponse 类型的,所以可以直接强制转换
    @Override
    public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException
    {
        HttpServletRequest  request;
        HttpServletResponse response;
        
        if (!(req instanceof HttpServletRequest &&
                res instanceof HttpServletResponse)) {
            throw new ServletException("non-HTTP request or response");
        }

        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;

        service(request, response);
    }
}

        HttpServlet 重写了 service 方法,根据 HTTP 请求类型抽象出来了多个方法,比如 doGet, doPost 等,但是也能看到各个方法都没有具体的业务实现逻辑,所以如果实现 HttpServlet 接口,只需要重写特定业务所需的请求类型的方法即可,比如一个 Servlet 只需要处理 GET 请求,那么只需要重写 doGet 方法就好,其他的就都不用管了。

HttpServletRequest

public interface HttpServletRequest extends ServletRequest {
    // 几种权限认证类型
    public static final String BASIC_AUTH = "BASIC";
    public static final String FORM_AUTH = "FORM";
    public static final String CLIENT_CERT_AUTH = "CLIENT_CERT";
    public static final String DIGEST_AUTH = "DIGEST";

    
    // 获取权限认证类型,所有的 Servlet 容器都支持 basic,form 和 client certificate 认证,有些也会支持 digest 认证
    public String getAuthType();

    // 获取 Cookie
    public Cookie[] getCookies();

    // 获取请求头的参数值
    public String getHeader(String name);

    // 有些请求头对应多个参数值
    public Enumeration<String> getHeaders(String name);

    // 获取请求头名称
    public Enumeration<String> getHeaderNames();

    // 获取 int 类型的参数值
    public int getIntHeader(String name);
    
    // 用于处理 Servlet 跟 Request 的映射逻辑
    default public HttpServletMapping getHttpServletMapping() {
        return new HttpServletMapping() {
            @Override
            public String getMatchValue() {
                return "";
            }

            @Override
            public String getPattern() {
                return "";
            }

            @Override
            public String getServletName() {
                return "";
            }

            @Override
            public MappingMatch getMappingMatch() {
               return null;
            }

            @Override
            public String toString() {
                return "MappingImpl{" + "matchValue=" + getMatchValue()
                        + ", pattern=" + getPattern() + ", servletName=" 
                        + getServletName() + ", mappingMatch=" + getMappingMatch() 
                        + "} HttpServletRequest {" + HttpServletRequest.this.toString()
                        + '}';
            }
            
            
            
        };
    }
    
    // 获取请求方法,如 GET, POST 等
    public String getMethod();

    // 返回 Servlet 的请求路径信息
    public String getPathInfo();

    // 本地文件路径信息
    public String getPathTranslated();

    // 应用上下文路径
    public String getContextPath();

    // 获取查询字符串信息, 如访问 http://localhost:8080/myHttpServlet?hehe=hehe,通过该方法获取到的值就为 "hehe=hehe"
    public String getQueryString();
    
    // 获取登陆的用户信息
    public String getRemoteUser();

    // 获取跟当前请求对应的 sessionId
    public String getRequestedSessionId();

    // Context-Path 后面的内容
    public String getRequestURI();

    // RequestURL 就是访问的全路径地址 ip:port/context-path/requestURI
    public StringBuffer getRequestURL();
    
    // 获取 session 对象,如果当前请求没有对应的 session 对象且 create = true, 则会新创建一个 session 对象出来
    public HttpSession getSession(boolean create);

    // 获取 session 对象,如果当前请求没有对应的 session 则会返回 null
    public HttpSession getSession();

    // 生成一个新的 sessionId 给当前 request 使用
    public String changeSessionId();

    // 判断当前请求的 sessionId 是否还有效
    public boolean isRequestedSessionIdValid();

    // 使用容器的功能来验证用户信息
    public void login(String username, String password)
	throws ServletException;

    // 用户退出登陆
    public void logout() throws ServletException;
}

         HttpServletRequest 实现了 ServletRequest 接口,在原有接口的功能上又进一步扩充,提供了权限校验,用户验证等功能。它通过 getRequestURL,getRequestURI,getQueryString 等方法获取请求行信息,通过 getHeader(String name), getHeaders(String name) 等方法获取请求头信息,通过父接口的 getParameter(String name),getParameterNames() 等方法定义了如何获取请求体信息。但是我们也发现了,无论是 HttpServletRequest 还是 ServletRequest 都是接口,都没有具体实现逻辑,所以目前为止还是约定规范的阶段。

HttpServletResponse

public interface HttpServletResponse extends ServletResponse {

    // 添加 Cookie
    public void addCookie(Cookie cookie);

    // 判读响应头是否已经添加了 name 信息
    public boolean containsHeader(String name);

    // 如果需要 session ID 的话,通过该方法进行编码,编码之后的 url 包含 session ID 
    public String encodeURL(String url);

    // 给客户端发送错误信息
    public void sendError(int sc, String msg) throws IOException;
    public void sendError(int sc) throws IOException;

    // 给客户端发送重定向地址,客户端根据 location 跳转到新的页面
    public void sendRedirect(String location) throws IOException;
    
    // 设置响应头信息
    public void setHeader(String name, String value);
    
    // 添加响应头信息
    public void addHeader(String name, String value);

    // 设置 int 类型的响应头信息
    public void setIntHeader(String name, int value);

    // 添加 int 类型的响应头信息
    public void addIntHeader(String name, int value);

    // 设置响应状态码
    public void setStatus(int sc);
  
    // 获取响应状态码
    public int getStatus();

    // 获取响应头的信息
    public String getHeader(String name); 
    public Collection<String> getHeaders(String name); 
    public Collection<String> getHeaderNames();

    // 定义一些服务状态码信息
    public static final int SC_CONTINUE = 100;
    public static final int SC_SWITCHING_PROTOCOLS = 101;
    public static final int SC_OK = 200;
    public static final int SC_CREATED = 201;
    public static final int SC_ACCEPTED = 202;
    public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203;
    public static final int SC_NO_CONTENT = 204;
    public static final int SC_RESET_CONTENT = 205;
    public static final int SC_PARTIAL_CONTENT = 206;
    public static final int SC_MULTIPLE_CHOICES = 300;
    public static final int SC_MOVED_PERMANENTLY = 301;
    public static final int SC_MOVED_TEMPORARILY = 302;
    public static final int SC_FOUND = 302;
    public static final int SC_SEE_OTHER = 303;
    public static final int SC_NOT_MODIFIED = 304;
    public static final int SC_USE_PROXY = 305;
    public static final int SC_TEMPORARY_REDIRECT = 307;
    public static final int SC_BAD_REQUEST = 400;
    public static final int SC_UNAUTHORIZED = 401;
    public static final int SC_PAYMENT_REQUIRED = 402;
    public static final int SC_FORBIDDEN = 403;
    public static final int SC_NOT_FOUND = 404;
    public static final int SC_METHOD_NOT_ALLOWED = 405;
    public static final int SC_NOT_ACCEPTABLE = 406;
    public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
    public static final int SC_REQUEST_TIMEOUT = 408;
    public static final int SC_CONFLICT = 409;
    public static final int SC_GONE = 410;
    public static final int SC_LENGTH_REQUIRED = 411;
    public static final int SC_PRECONDITION_FAILED = 412;
    public static final int SC_REQUEST_ENTITY_TOO_LARGE = 413;
    public static final int SC_REQUEST_URI_TOO_LONG = 414;
    public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415;
    public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
    public static final int SC_EXPECTATION_FAILED = 417;
    public static final int SC_INTERNAL_SERVER_ERROR = 500;
    public static final int SC_NOT_IMPLEMENTED = 501;
    public static final int SC_BAD_GATEWAY = 502;
    public static final int SC_SERVICE_UNAVAILABLE = 503;
    public static final int SC_GATEWAY_TIMEOUT = 504;
    public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
}

        同样的 HttpServletRequest 和 HttpServletResponse 这两个也是接口类型,我们暂时可以不用管这两个接口的实例是谁, Servlet 容器会帮我们生成这两个对象,我们目前知道它具体有什么功能就好,结合 HttpServlet 只需要重写 doGet,doPost 方法就可以处理 http 的请求和响应。

关于请求和响应的乱码问题

      看了下这篇文章写的还不错。doGet和doPost乱码解决方案_扶公瑾以苏的博客-CSDN博客先说一下乱码的原因:乱码是因为编码和解码的格式不一而引发的问题。 我们来看一下以下步骤:1.在前端页面传输数据时,会先将数据进行编码再进行传输(浏览器默认的编码格式是UTF-8)2.数据传输到Servlet时,tomcat会使用其默认编码进行解码。测试结果Tomcat从8.0开始转化为默认编码为utf-8的格式了,但是8.0以下的tomcat默认的编码还是ISO-8859-...https://blog.csdn.net/qq_36470686/article/details/83019872

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值