servlet
当在网页中点击一个链接,链接的 URL 指向一个 servlet , web 容器识别这个请求所指向的 servlet,所有容器创建两个对象:
- HttpServletResponse:响应对象
- HttpServletRequest:请求对象
容器根据请求中的 URL 找到正确的 servlet,并为这个请求创建或分配一个线程,并调用 servlet 的 service() 方法,把请求和响应对象作为参数传入。service() 方法根据请求中的 HTTP 方法(GET、POST 等),确定要调用哪个 servlet 方法。进入相关方法后,处理数据,将处理完成的数据返回或者通知浏览器操作成功了。servlet 将会使用响应对象将相关数据写入,并传给容器,容器传回浏览器。
响应结束,service() 方法也将结束,所以线程要么撤销,要么返回到容器管理的一个线程池。请求和响应对象引用已经出了作用域,所以这两个对象也没有意义,将会被垃圾回收。
servlet 类的运行过程:
- 首先被 Web 容器加载
- 实例化 servlet (构造函数运行)
- 容器调用 init() 方法(servlet 生命周期中只调用一次,而且在容器调用 service() 方法前必须完成。
- 处理请求使用 service() 方法(doGet、doPost 等)
- 容器调用 destroy() 方法(servlet 被杀死,servlet 生命周期中只调用一次)
那么为什么已经调用了 servlet 构造函数初始化了 servlet,还有一个 init() 方法来进行初始化呢?
因为构造方法只是将 servlet 的这个类初始化,得到 servlet 的实例,这时候的 servlet 并不能称为 servlet,它还只是一个普通的 Java 对象,要成 servlet 必须得servlet 该有的所有特权,譬如,能够使用 ServletContext 引用从容器中得到信息。servlet 要从普通对象变成 servlet 必须获得特权,但是如果在 servlet 的生命周期中太早的运行这些获得特权的初始化代码可能会失败。所有 init() 方法就出现。注意,不要在 servlet 的构造方法中放置任何的东西,但什么都可以放置在 init() 方法中。
- ServletConfig:配置信息,没个 servlet 都有一个 ServletConfig,用于向 servlet 传递部署时信息,访问 ServletContext,参数在部署描述文件(web.xml)中的位置。
- ServletContext:Servlet 上下文 ,每一个 web 应用只有一个 ServletContext,用于访问 web 应用参数(也在部署描述文件中配置),可以在这里放置属性,其他部分可以访问这些属性,用于得到服务器信息,包括容器的名字和版本,以及所支持的 api 等。
请求
Http 请求方法:
- GET:要求得到所请求URL上的一个东西(资源/文件)。
- POST:要求服务器接收附加请求的体信息,并提供所请求URL上的一个东西。
- HEAD:只要求得到 GET 返回结果的首部部分。有点像 GET ,但是响应中没有体。它能提供所请求URL的有关消息,但是不会真正返回实际的东西。
- TRACE:要求请求消息回送,这样客户能看到另一端上接收了什么,用于测试和排错。
- PUT:指出要把所包含的信息(体)放在请求的URL上。
- DELETE:指出删除所请求URL上的东西(资源/文件)。
- OPTIONS:要求得到一个 http 方法列表,所请求URL上的东西可以对这些 http 方法做出响应。
- CONNECT:要求连接以便建立隧道。
GET 和 POST 的区别,GET 和 POST 都能发送参数,但是利用 GET 的话,对参数数据有限制,只能放在请求行的内容。POST 请求比 GET请求多出一个消息体,也被称为有效负载,传送的资源或者文件都在消息体中。安全性,POST可以隐藏请求参数和内容,要比 GET 更安全。
GET、HEAD、PUT 是幂等的,POST 是非幂等的:
- 幂等:可以重复一遍又一遍地反复做执行同一件事。而不会对服务器产生负面作用。
- 非幂等:只会执行一次,不会重复执行。
如果在表单中没有注明这是一个 method=“POST” 方法,表单会默认这是一个 GET请求。
Request 请求的部分常用方法:
- String client = request.getHeader(“User-Agent”) :客户的平台和浏览器信息,请求头信息。
- Cookie[] cookies = request.getCookies():与请求相关的 cookie。
- HttpSession session = request.getSession():与客户相关的会话 session。
- String theMethod = request.getMethod() :请求的 http 方法。
- InputStream input = request.getInputStream():请求的输入流。
- String val = request.getParameter():获取请求参数。
- String[] vals = reques.getParameterValues():获取请求参数数组。
Http 请求中我们可能只会使用 getParameter() 方法来获取参数,但是如果这些值可能很大,就需要用到输入流。利用输入流,可以去除所有首部信息,处理请求负载体的原始数据,也可以将其写到服务器的文件中。
响应
响应有两种,返回一个字符流或者一个字节流:
- PrintWriter:返回一个字符流,把文本数据打印到字符流。
- ServeltOutputStream:写入字节流。
response.setContentType(“text/html”):设置返回数据类型方法。这里设置的是 html 类型的数据。
增加请求头或者设置请求头/首部:
- response.setHeader(“foo”,“bar”):如果响应中已经有了同名的首部,则用这个值替换替换原来的值。否则,向响应中增加一个新首部和值。
- response.addHeader(“foo”,“bar”):为响应增加一个新首部和值,或者向一个现有的首部增加另一个值。
- response.setIntHeader(“foo”,“bar”):用提供的整数值替换现有首部的值,或者向响应增加一个新首部和值。
响应重定向:
reponse.setRedirect():跳转到另一个链接中,工作原理是,servlet 使用了 reponse.setRedirect(URL) 重定向到了另一个链接,servlet 会向浏览器发送状态码 301,将重定向的 URL 放置在 Location 响应首部中,浏览器接收到响应,发现状态码是 301,然后就会找到 Location 首部,并且拿到 URL,跳转到这个 URL中。
重定向的 URL 可以是一个完整的链接,如 http://www.baidu.com/myapp/cool/bar.do
也可以使用相对 URL,相对 URL有两种类型:
前面有斜线和没有斜线的:
如果完整的请求名是 http://www.baidu.com/myapp/cool/bar.do
- 没有斜线的: sendRedirect(“foo/stuff.html”),这个命令,会将上方的请求URL重新建立,样式为:http://www.baidu.com/myapp/cool/foo/stuff.html
- 有斜线的:sendRedirect("/foo/stuff.html") 这个命令,会将上方的请求URL重新建立,样式为:http://www.baidu.com/foo/stuff.html
注意:
sendRedirect 命令如果在响应已经提交再调用这个方法,会抛出异常。提交的意思是值,响应已经发出,意味着数据已经刷新到流中。