Servlet

标签 : Java与Web


HTTP协议

HTTP(hypertext transport protocol),即超文本传输协议.这个协议详细规定了浏览器(Browser)和万维网服务器(WebServer)之间互相通信的规则.其主要特点可简单概括如下:

1) 简单快速: 客户端向服务器请求服务时,只需传送请求方法和路径, 因此使得HTTP服务器的程序规模小,通信速度快;

2) 灵活: HTTP允许传输任意类型的数据对象(传输类型由Content-Type控制);

3) 无连接: 无连接的含义是限制每次连接只处理一个请求;

4) 无状态: 无状态是指协议对于事务处理没有记忆能力(如果后续处理需要前面的信息,则必须重传.这样可能导致每次连接传送的数据量增大.但如果在服务器不需要先前信息时它的应答就会非常快快).


HTTP请求

一个HTTP请求通常包含三部分(中间已空行隔开):

请求行:        (方法 /统一资源标识符URI/协议/版本)
请求头:        (Accept/Accept-Language等)
空行:     (CRLF)
请求体:        (携带的数据信息, GET请求没有)

HTTP请求可以使用HTTP标准中定义的所有请求类型, HTTP1.1支持7种请求类型, 但在互联网应用中最为常用的只有GETPOST.


HTTP-GET

GET /WeChat/cc3200/get_status.do HTTP/1.1
Host: aliyun
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
  • 请求头解析
请求头 描述
User-Agent 浏览器与操作系统信息
Accept 当前浏览器可以接收的文档类型
Accept-Language 当前浏览器支持的语言
Accept-Encoding 当前浏览器支持的压缩格式:服务器会把数据压缩后再发送到网络中传输
Accept-Charset 当前浏览器支持的编码
Connection 当前浏览器支持的连接方式(keep-alive即保持一段时间的连接,默认为3000ms)
Cookie 如果不是第一次访问该网址,可能会在请求中把上次服务器响应的Cookie数据一并发送过去

HTTP-POST

POST /WeChat/cc3200/get_status.do HTTP/1.1
Content-Length: 36
Cache-Control: max-age=0
Origin: http://localhost:8080
Content-Type: application/x-www-form-urlencoded
Referer: http://localhost:8080/test/
...

user_name=feiqing&user_password=pass
  • 请求头解析
请求头 描述
Referer 表明请求来自哪个页面
Content-Type application/x-www-form-urlencoded:表单数据类型,说明会使用URL编码来格式化数据
Content-Length 请求体长度
user_name=feiqing&user_password=pass 请求体: 请求携带的数据

HTTP响应

一个HTTP响应通常也包含三部分(中间已空行隔开):

响应行:        (协议/状态码/描述)
响应头:        (Server/Content-Length/Set-Cookie等)
空行:     (CRLF)
响应体:        (携带的数据)

HTTP响应是由服务器发送给浏览器的数据,浏览器会根据HTTP响应来解析并显示内容:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Length: 8
Date: Sun, 17 Apr 2016 12:39:11 GMT

<html>
    ...
</html>
  • 响应头解析
响应头 描述
Server 服务器信息
Content-Length 响应实体长度
Set-Cookie 响应给客户端的Cookie
Expires: -1; / Cache-Control: no-cache; / Pragma: no-cache; 设置浏览器不要缓存数据
Refresh 自动刷新页面

在HTML文件中可用<meta/>标签来设置响应头信息:

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

响应状态码

状态码说明了响应的真正含义:

状态 描述
200 请求成功
404 请求资源没找到
500 服务器内部错误
302 重定向: 表示服务器要求浏览器重新再发一个请求到服务器指定的一个Location
304 缓存未过期(服务器资源未曾修改), 详细可参考理解HTTP/304响应

Tomcat

Tomcat是一个免费开源的Serlvet容器,它是Apache基金会的Jakarta项目中的一个核心项目,由Apache,Sun和其它一些公司及个人共同开发而成. 由于有了Sun的参与和支持, 因此最新的Servlet和Jsp规范总能在Tomcat中得到体现.主页:http://tomcat.apache.org/.


Tomcat目录结构

  • bin: 存放可执行脚本文件(如startup.bat/startup.sh等)
  • conf: 存放Tomcat相关配置文件:
    • server.xml: 整个Tomcat运行环境配置(如端口号/虚拟主机等)
    • web.xml: 部署描述符文件(定义了默认JSP/Servlet处理规则,是所有web项目中WEB-INF/web.xml的父文件)
    • context.xml: 对所有应用的统一配置.
  • lib:Tomcat类库, 该目录中的jar包所有项目共享.
  • logs : Tomcat日志目录.
  • webapps:存放WEB应用,其每个子目录都是一个项目;
  • work:运行时生成的文件.

server.xml

<Server port="8005" shutdown="SHUTDOWN">
  <Service name="Catalina">
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

    <Engine name="Catalina" defaultHost="localhost">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>

      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log." suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
      </Host>
    </Engine>
  </Service>
</Server>
  • 元素解析
元素 描述
<Server/> 根元素,整个Tomcat的配置信息
<Service/> 服务(在<Server/>中只能有一个<Service/>)
<Connector/> 连接
<Engine/> 引擎,是<Service/>组件核心
<Host/> 每个<Host/>元素表示一台虚拟主机.每台虚拟主机都有自己的主机名和项目目录
<Context/> 每个<Context/>元素表示一个应用.如果应用在<Host/>的appBase指定的目录下,那么可以不配置<Context/>元素,如果是外部应用,那么就必须配置<Context/>

Tomcat配置

1. 配置端口号

编辑%CATALANA_HOME%\conf\server.xml文件中的<Connector/>元素

<!-- A "Connector" represents an endpoint by which requests are received
     and responses are returned. Documentation at :
     Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)
     Java AJP  Connector: /docs/config/ajp.html
     APR (HTTP/AJP) Connector: /docs/apr.html
     Define a non-SSL HTTP/1.1 Connector on port 8080
-->
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />

2. 配置外部应用

配置外部应用之后, 项目就可以不用拷贝到webapps目录下,自定义项目存放位置,其配置方式有两种:

  • 1: 修改server.xml

    <Host/>元素中添加<Context/>元素
  <Host name="localhost"  appBase="webapps"
        unpackWARs="true" autoDeploy="true">
    <Context path="/test/" docBase="/home/www/test"/>

    <!-- Access log processes all example.
         Documentation at: /docs/config/valve.html
         Note: The pattern used is equivalent to using pattern="common" -->
    <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
           prefix="localhost_access_log." suffix=".txt"
           pattern="%h %l %u %t &quot;%r&quot; %s %b" />

  </Host>

如果指定path为空(path=”“), 则默认访问的项目就是/home/www/test, 而不再是webapps下的ROOT.

  • 2: 编辑conf/catalana/localhost目录:

    新增test.xml文件
<Context docBase="/home/www/test"/>

存放到%CATALANA_HOME%/conf/catalana/localhost目录下, 文件名即为应用名.


Servlet

Servlet技术核心就是Servlet接口,所有Servlet实现类都必须实现Servlet接口,Servlet容器(如Tomcat)会把Servlet类加载到内存并生成唯一实例,当有请求到来时调用其方法.

  • 实现Servlet方式有三种:

    1. 实现javax.servlet.Servlet接口
    2. 继承javax.servlet.GenericServlet
    3. 继承javax.servlet.http.HttpServlet

Servlet

Servlet接口定义如下

public interface Servlet {

    public void init(ServletConfig config) throws ServletException;

    public ServletConfig getServletConfig();

    public void service(ServletRequest req, ServletResponse res)
    throws ServletException, IOException;

    public String getServletInfo();

    public void destroy();
}
方法 描述
init 在第一次请求该Servlet(默认)或容器启动时, Servlet容器就会调用init(), 且只调用一次
service 每次请求Servlet都会调用该方法
destroy 销毁Servlet时(卸载应用/关闭容器时), 调用该方法
  • HelloServlet
/**
 * @author jifang.
 * @since 2016/4/17 8:32.
 */
public class HelloServlet implements Servlet {

    private ServletConfig config;

    public void init(ServletConfig config) throws ServletException {
        System.out.println("init()...");
        this.config = config;
        System.out.println("config: <" + config + ">");
    }

    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        System.out.println("service()...");
        System.out.println("req: <" + req + ">, res: <" + res + ">");
        res.getWriter().print("<h1>HelloServlet</h1>");
    }

    public void destroy() {
        System.out.println("destroy()...");
    }

    public ServletConfig getServletConfig() {
        return this.config;
    }

    public String getServletInfo() {
        return null;
    }
}
  • web.xml
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0"
         metadata-complete="true">
    <display-name>JavaWeb</display-name>
    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.fq.web.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello_servlet.do</url-pattern>
    </servlet-mapping>
</web-app>
  1. url-pattern

    <url-pattern/>用来指定Servlet的访问路径,必须以/开头.

    • 可以在<servlet-mapping/>配置多个<url-pattern/>, 此时一个Servlet实例就绑定多个URL.
    • 可以在<url-pattern/>中使用通配符*,可以使一个Servlet绑定一组URL, 但*不能出现在中间位置,也不能只有*通配符, 另外, 通配符只是一种模糊匹配URL的方式,如果存在更具体的<url-pattern/>,那么会优先选择精确匹配.
  2. 配置在容器启动时创建Servlet实例

<servlet>
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>com.fq.web.servlet.HelloServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<load-on-startup/>元素可以让容器在启动时就创建该Servlet实例(调用init()方法),注意<load-on-startup/>元素的值必须是>=0的整数,它代表容器启动时创建Servlet实例的顺序.


GenericService

GenericService抽象类实现了Servlet接口并完成以下工作:

1. 将init()方法中的ServletConfig赋给一个实例变量, 使他可以通过getServletConfig()来获取.

2. 为Servlet接口的所有方法提供默认实现.

3. 提供方法来包装ServletConfig.

  • Generic部分代码
public abstract class GenericServlet
    implements Servlet, ServletConfig, java.io.Serializable
{
    private transient ServletConfig config;

    public GenericServlet() { }

    public void destroy() {
    }

    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);
    }

    public Enumeration<String> getInitParameterNames() {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getInitParameterNames();
    }   

    public ServletConfig getServletConfig() {
    return config;
    }

    public ServletContext getServletContext() {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getServletContext();
    }

    public String getServletInfo() {
    return "";
    }

    public void init(ServletConfig config) throws ServletException {
    this.config = config;
    this.init();
    }

    public void init() throws ServletException {

    }

    public abstract void service(ServletRequest req, ServletResponse res)
    throws ServletException, IOException;

    public String getServletName() {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getServletName();
    }
}

HttpServlet

HttpServletGenericServlet的子类,它提供了对HTTP协议的支持.覆盖了GenericServletservice()方法,并新增了接受HttpServletRequest/HttpServletResponse参数的service()方法:

@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);
}

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);
    }
}
  • 原始的service()将请求/响应向下转型为HttpServletRequest/HttpServletResponse, 并调用新的service(). 由于HttpServlet在新的service()方法中已经做了很多工作, 因此在继承HttpServlet实现自动以Servlet时, 则只需覆盖doGet()/doPost()等即可, 而没有必要覆盖service()(极少数情况需要覆盖doHead()等)

注意: Request/Response向下转型总会成功:因为在调用service()方法时,Servlet容器总会预计使用HTTP,从而直接创建并传递HttpServletRequest/HttpServletResponse实例.

  • HelloHttpServlet
/**
 * @author jifang.
 * @since 2016/4/20 19:48.
 */
@WebServlet(name = "HelloHttpServlet", urlPatterns = "/hello_http_servlet.do")
public class HelloHttpServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("doPost() ...");
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("doGet() ...");
    }
}

HttpServletRequest

对于每一个HTTP请求, Servlet容器会在调用service()方法时创建Request实例并传递给service形参, HttpServletRequest是Request在HTTP环境下的实例,其封装了有关请求的信息:

  • 封装请求头信息;
  • 封装请求正文数据(GET没有正文);
  • 提供请求转发/包含功能;
  • 作为域对象, 可以传递数据.

获取请求头

方法 描述
String getHeader(String name) Returns the value of the specified request header as a String.
Enumeration<String> getHeaderNames() Returns an enumeration of all the header names this request contains.
long getDateHeader(String name) Returns the value of the specified request header as a long value that represents a Date object.
Enumeration<String> getHeaders(String name) Returns all the values of the specified request header as an Enumeration of String objects.
int getIntHeader(String name) Returns the value of the specified request header as an int.
String getRemoteAddr() Returns the Internet Protocol (IP) address of the client or last proxy that sent the request.
String getMethod() Returns the name of the HTTP method with which this request was made, for example, GET, POST, or PUT.
String getContextPath() Returns the portion of the request URI that indicates the context of the request.
  • 获取请求来源
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String referer = request.getHeader("Referer");
    String userAgent = request.getHeader("User-Agent");
    composeResponse(referer, userAgent, response);
}

private void composeResponse(String referer, String userAgent, HttpServletResponse response) throws IOException {
    response.setHeader("Content-Type", "text/html;charset=utf-8");
    PrintWriter writer = response.getWriter();
    if (!Strings.isNullOrEmpty(referer)) {
        writer.print("<h1>来源地址: " + referer + "</h1>");
    } else {
        writer.print("<h1>来自浏览器地址栏</h1>");
    }

    writer.print("<hr>");
    writer.print("<h1>来源信息: " + userAgent + "</h1>");
}

获取请求参数

方法 描述
String getParameter(String name) Returns the value of a request parameter as a String, or null if the parameter does not exist.
Map<String,String[]> getParameterMap() Returns a java.util.Map of the parameters of this request.
Enumeration<String> getParameterNames() Returns an Enumeration of String objects containing the names of the parameters contained in this request.
String[] getParameterValues(String name) Returns an array of String objects containing all of the values the given request parameter has, or null if the parameter does not exist.
  • 获取微信请求消息
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    Element root;
    String xml = request.getParameter("xml");
    try {
        if (!Strings.isNullOrEmpty(xml)) {
            root = new SAXReader().read(new StringReader(xml)).getRootElement();
        } else {
            String data = CharStreams.toString(new InputStreamReader(request.getInputStream()));
            root = new SAXReader().read(new StringReader(data)).getRootElement();
        }
    } catch (DocumentException | IOException e) {
        LOGGER.error("parse wx xml error", e);
        throw new RuntimeException();
    }

    // ...
}

请求转发/包含

Request提供了getRequestDispatcher()来获取一个RequestDispatcher, 并由其提供请求转发/请求包含功能.

Request方法 描述
RequestDispatcher getRequestDispatcher(String path) Returns a RequestDispatcher object that acts as a wrapper for the resource located at the given path.

请求转发/请求包含都是由多个Servlet协作完成一个请求, 因此需要从一个Servlet中跳到另一个Servlet中:

RequestDispatcher方法 描述
void include(ServletRequest request, ServletResponse response) Includes the content of a resource (servlet, JSP page, HTML file) in the response.
void forward(ServletRequest request, ServletResponse response) Forwards a request from a servlet to another resource (servlet, JSP file, or HTML file) on the server.
  • 请求转发: 原Servlet只会保留设置的响应头信息.
  • 请求包含: 原Servlet既会保留响应头, 还会保留响应体内容.

注意: 请求转发时, 可能会因为原Servlet设置了过多的响应体内容导致抛出异常java.lang.IllegalStateException: Cannot forward after response has been committed


域对象传递数据

由于请求转发/请求包含都只是一次请求, 因此在多个Servlet之间都是共用一个Reqeust, 因此可以利用Request的在多个Servlet之间共享数据:

方法 描述
Object getAttribute(String name) Returns the value of the named attribute as an Object, or null if no attribute of the given name exists.
Enumeration<String> getAttributeNames() Returns an Enumeration containing the names of the attributes available to this request.
void setAttribute(String name, Object o) Stores an attribute in this request.
void removeAttribute(String name) Removes an attribute from this request.

HttpServletResponse

同Request, Servlet容器会在每次调用service()方法时创建Response实例并传递给service()形参, HttpServletResponse是Response绑定在HTTP环境下的实例, 其隐藏了将响应发送给浏览器的复杂性:

  • 设置响应状态码;
  • 设置响应头信息;
  • 设置响应正文;

设置响应状态码

方法 描述
void setStatus(int sc) Sets the status code for this response.
void sendError(int sc) Sends an error response to the client using the specified status code and clears the buffer.
void sendError(int sc, String msg) Sends an error response to the client using the specified status and clears the buffer.

关于状态码的描述, 详见HTTP协议部分介绍, 在此就不再赘述.

  • 响应404
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // response.sendError(404, "nothing!!");
    response.setStatus(404);
}

设置响应头信息

方法 描述
void setHeader(String name, String value) Sets a response header with the given name and value.
void addHeader(String name, String value) Adds a response header with the given name and value.
void setIntHeader(String name, int value) Sets a response header with the given name and integer value.
void addIntHeader(String name, int value) Adds a response header with the given name and integer value.
void addDateHeader(String name, long date) Adds a response header with the given name and date-value.
void setDateHeader(String name, long date) Sets a response header with the given name and date-value.
void sendRedirect(String location) Sends a temporary redirect response to the client using the specified redirect location URL and clears the buffer.

关于HTTP响应头的描述, 详见HTTP协议部分介绍, 在此就不再赘述.

  • 设置禁用浏览器缓存(Cache-Control, pragma, expires)
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    response.setHeader("Cache-Control", "no-cache");
    response.setHeader("pragma", "no-cache");
    response.setDateHeader("expires", -1);
}
  • 设置重定向(302, Location)
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
    response.setHeader("Location", "http://www.baidu.com");
}

HttpServletResponse还提供了另外一种重定向的方式, 直接使用sendRedirect()方法, 避免了以上的步骤:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    response.sendRedirect("http://www.baidu.com");
}

设置响应正文

Response提供了如下两个方法来获取输出流对象以响应HTTP正文内容

方法 描述
ServletOutputStream getOutputStream() Returns a ServletOutputStream suitable for writing binary data in the response.
PrintWriter getWriter() Returns a PrintWriter object that can send character text to the client.

OutputStream传输二进制数据流(字节数据), 常用作文件下载; Writer传输字符数据, 常用作响应HTTP正文内容(如HTML/XML等).

注意: 在一个请求中,不能同时使用这两个流, 否则会抛出IllegalStateException.

字符响应流
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    PrintWriter writer = response.getWriter();
    writer.print("<html>");
    writer.print("<h1>content</h1>");
    writer.print("</html>");
}
  • 缓冲区

    PrintWriter的默认缓冲区大小为8K, 因此当响应数据大小<8K时, 数据存放在缓冲区, 而不会立刻发送到浏览器, 直到Servlet执行结束,因此如果希望马上发送给浏览器, 需要调用Response的flushBuffer()方法手动刷新缓冲区.

ServletConfig

在容器初始化Servlet时, 会将一个ServletConfig实例传给init()方法,其封装了@WebServlet/部署描述符传递给Servlet的配置信息:

方法 描述
String getInitParameter(String name) Gets the value of the initialization parameter with the given name.
Enumeration<String> getInitParameterNames() Returns the names of the servlet’s initialization parameters as an Enumeration of String objects.
ServletContext getServletContext() Returns a reference to the ServletContext in which the caller is executing.
  • java
public void init(ServletConfig config) throws ServletException {
    this.config = config;

    Enumeration<String> names = config.getInitParameterNames();
    while (names.hasMoreElements()) {
        String name = names.nextElement();
        String value = config.getInitParameter(name);

        System.out.println(name + " -> " + value);
    }
}
  • web.xml
    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.fq.web.servlet.HelloServlet</servlet-class>
        <init-param>
            <param-name>admin</param-name>
            <param-value>com.fq</param-value>
        </init-param>
        <init-param>
            <param-name>e-mail</param-name>
            <param-value>zhujifang666@163.com</param-value>
        </init-param>
    </servlet>

ServletContext

ServletConfig中提供了获取ServletContext的方法getServletContext(), ServletContext代表Servlet应用程序,且每个应用程序仅有一个ServletContext实例,其在容器启动时创建, 在容器关闭时销毁, 因此可以利用其在多个Servlet中传递数据.

所有域对象都有存取数据的功能,因为域对象内部有一个Map,用来存储数据,下面是ServletContext对象用来操作数据的方法:

方法 描述
void setAttribute(String name, Object object) Binds an object to a given attribute name in this ServletContext.
Object getAttribute(String name) Returns the servlet container attribute with the given name, or null if there is no attribute by that name.
Enumeration<String> getAttributeNames() Returns an Enumeration containing the attribute names available within this ServletContext.
void removeAttribute(String name) Removes the attribute with the given name from this ServletContext.

应用初始化参数

前面看到ServletConfig可以获取针对本Servlet的初始化参数,而利用ServletContext可以获取针对本应用程序的公共初始化参数:

方法 描述
String getInitParameter(String name) Returns a String containing the value of the named context-wide initialization parameter, or null if the parameter does not exist.
Enumeration<String> getInitParameterNames() Returns the names of the context’s initialization parameters as an Enumeration of String objects, or an empty Enumeration if the context has no initialization parameters.
  • web.xml
<context-param>
    <param-name>admin</param-name>
    <param-value>feiqing</param-value>
</context-param>
<context-param>
    <param-name>e-mail</param-name>
    <param-value>zhujifang666@163.com</param-value>
</context-param>
  • java
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    ServletContext context = getServletContext();
    String admin = context.getInitParameter("admin");
    String email = context.getInitParameter("e-mail");
    System.out.printf("admin: %s%n", admin);
    System.out.printf("e-mail: %s%n", email);
}

获取资源

可以使用ServletContext来获取Web应用下的资源路径/资源流等内容:

方法 描述
String getRealPath(String path) Gets the real path corresponding to the given virtual path.
URL getResource(String path) Returns a URL to the resource that is mapped to the given path.
InputStream getResourceAsStream(String path)` Returns the resource located at the named path as an InputStream object.
Set<String> getResourcePaths(String path) Returns a directory-like listing of all the paths to resources within the web application whose longest sub-path matches the supplied path argument.

Servlet - 基础的更多相关文章

  1. JSP数据交互(二)和Servlet基础

    01.Application原理与应用 01.application对象的作用域范围是整个应用服务,而它在应用中所承担的责任就类似于一个全局变量.只要服务启动,则application对象就会存在. ...

  2. Servlet基础(三) Servlet的多线程同步问题

    Servlet基础(三) Servlet的多线程同步问题 Servlet/JSP技术和ASP.PHP等相比,由于其多线程运行而具有很高的执行效率. 由于Servlet/JSP默认是以多线程模式执行的, ...

  3. Servlet基础(二) Servlet的生命周期

    Servlet基础(二) Servlet的生命周期 Servlet的生命周期可以分为三个阶段: 1.初始化阶段 2.响应客户请求阶段 3.终止阶段 Servlet的初始化阶段 在下列时刻Servlet ...

  4. Servlet基础(一) Servlet简介 关键API介绍及结合源码讲解

    Servlet基础(一) Servlet基础和关键的API介绍 Servlet简介 Java Servlet是和平台无关的服务器端组件,它运行在Servlet容器中. Servlet容器负责Servl ...

  5. JSP/Servlet基础语法

    相关学习资料 http://my.oschina.net/chape/blog/170247 http://docs.oracle.com/cd/E13222_01/wls/docs81/webapp ...

  6. Servlet基础简单总结(上)

    Servlet基础一些简单总结(上): 1.Java Servlet是运行在Web服务器上的Java程序2.Java平台给Servlet开发者提供了强大的API/面向对象编程平台无关/强类型/垃圾回收 ...

  7. servlet总结:Servlet基础

    Servlet基础 1.手工编写第一个Servlet ⑴继承HttpServlet ⑵重写doGet()或者doPost()方法 ⑶在web.xml中注册Servlet 2.使用eclipse编写第一 ...

  8. servlet基础(组成与生命周期)

    servlet基础作用:servlet是运行在Web服务器或应用服务器上的程序:担当web浏览器或其他HTTP客户程序发出的请求与HTTP服务器上的数据库或应用程序之间的中间层.1.读取客户程序发送的 ...

  9. Unit01: Servlet基础 、 HTTP协议

    Unit01: Servlet基础 . HTTP协议 在页面上输出当前时间 package web; import java.io.IOException; import java.io.PrintW ...

  10. Servlet基础教程:tutorialspoint-servlet

    来自turorialspoint的Servlet基础教程(英文),官网:https://www.tutorialspoint.com/servlets/index.htm 这个教程在国内已经被翻译成中 ...

随机推荐

  1. 再谈angularJS数据绑定机制及背后原理—angularJS常见问题总结

    这篇是对angularJS的一些疑点回顾,是对目前angularJS开发的各种常见问题的整理汇总.如果对文中的题目全部了然于胸,觉得对整个angular框架应该掌握的七七八八了.希望志同道合的通知补充 ...

  2. [LeetCode] Minimum Factorization 最小因数分解

    Given a positive integer a, find the smallest positive integer b whose multiplication of each digit ...

  3. 使用redis,zookeeper实现分布式锁

    1.分布式锁 分布式锁一般用在分布式系统或者多个应用中,用来控制同一任务是否执行或者任务的执行顺序.在项目中,部署了多个tomcat应用,在执行定时任务时就会遇到同一任务可能执行多次的情况,我们可以借 ...

  4. Python super使用

    一 基础使用 在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能,这时,我们就需要调用父类的方法了,可通过使用 super 来实现,比如: #!/usr ...

  5. 【BZOJ1059】【ZJOI2007】矩阵游戏

    Description 小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏――矩阵游戏.矩阵游戏在一个N*N黑白方阵进行(如同国际象棋一般,只是颜色是随意的).每次可以对该矩阵进行两 ...

  6. ●洛谷P3168 [CQOI2015]任务查询系统

    题链: https://www.luogu.org/problemnew/show/P3168题解: 主席树 强制在线? 那就直接对每一个前缀时间建一个线段树(可持久化线段树),线段树维护优先度权值. ...

  7. Unix系统的文件目录项的内容是什么,这样处理的好处是什么?

    (Unix系统采用树型目录结构,而且目录中带有交叉勾链.每个目录表称为一个目录文件.一个目录文件是由目录项组成的.) 每个目录项包含16个字节,一个辅存磁盘块(512B)包含32个目录项.在目录项中, ...

  8. Hash算法入门指南(聊点不一样的算法人生)

    前言 很多人到现在为止都总是问我算法该怎么学啊,数据结构好难啊怎么的,学习难度被莫名的夸大了,其实不然.对于一个学计算机相关专业的人都知道,数据结构是大学的一门必修课,数据结构与算法是基础,却常常容易 ...

  9. avalon,xmp

  10. python实现编写windows服务

    使用python编写windows服务 最近测试服务器上经常发生磁盘空间不足,每次手动清除比较麻烦,所以写个windows服务定时清理下.中间也遇到过几个坑,一起记录下来. 1.python实现win ...