一、Servlet的生命周期
容器最终要调用service方法为客户进行服务
1、Servlet接口中的常用方法:
public void init(ServletConfig config):初始化。Servlet类被实例化后就执行,且执行一次。由容器进行调用
public void destroy():销毁Servlet对象。由容器进行调用
2、Servlet实例对象和初始化方法,默认情况下,只有第一次访问时才执行,且只执行一次。在内存中一个Servlet只有一个实例。针对不同的用户请求,容器采用多线程的机制调用service方法的。
希望在应用被Tomcat加载完毕后(此时还没有任何人访问),就实例化并完成初始化Servlet的工作?
<servlet>
<servlet-name>FirstServlet</servlet-name>
<servlet-class>cn.itcast.servlet.FirstServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
3、如果设计与HTTP协议有关的Servlet,一般选择集成javax.servlet.http.HttpServlet.
HttpServlet覆盖了其父类GenericServlet的public abstract void service(ServletRequest req, ServletResponse res)方法,
然后在覆盖的service方法中调用了自己的protected void service(HttpServletRequest req, HttpServletResponse resp)方法,
在自己的service方法中调用了自己的doXXX方法。
故自己写的Servlet不应该覆盖HttpServlet的service方法,而应该去覆盖掉它的doXXX方法。
4、Servlet实例化对象和初始化方法,默认情况下,只有第一次访问时才执行,且只执行一次。
二、Servlet的线程安全问题
在内存中一个Servlet只有一个实例。针对不同的用户请求,容器采用多线程的机制调用service方法的。
在Servlet中定义变量,除非特殊要求,尽量使用局部变量。
如果有需要实例变量时,应做同步处理,且同步代码块尽量包围少的代码。
三、Servlet的配置
Servlet的配置对象ServletConfig:(容器来创建)
作用:代表了Servlet配置中的参数信息。
比如在web.xml中的参数配置如下:
<servlet>
<servlet-name>ServletDemo2</servlet-name>
<servlet-class>cn.jxn.servlet.ServletDemo2</servlet-class>
<!-- aaa=bbb -->
<init-param>
<param-name>aaa</param-name>
<param-value>bbb</param-value>
</init-param>
<init-param>
<param-name>xxx</param-name>
<param-value>yyy</param-value>
</init-param>
</servlet>
Servlet配置
1、一个Servlet可以被映射到多个URL地址上
2、URL地址映射还支持通配符*
方式一:以*开头,以扩展名结尾。比如 <url-pattern>*.do</url-pattern>
方式二:以/前缀开头,以*结尾。 比如<url-pattern>/action/*</url-pattern>
3、多个Servlet使用通配符时,有可能有多
以"/"开头(方式二)要比"*"开头(方式一)优先级高
都以"/"开头,还是有多个匹配,找最匹配的
4、如果一个Servlet的映射为一个"/",就称之为默认的Servlet,它负责处理没有映射路径的URL请求的响应。
四、ServletContext
1、在应用被服务器加载时就创建ServletContext对象的实例。每一个JavaWeb应用都有唯一的一个ServletContext对象。它就代表着当前的应用。
2、如何得到ServletContext对象:ServletConfig.getServletContext();
3、作用:
3.1ServletContext对象是一个域对象(域对象就是说其内部维护了一个Map<String,Object>)
Object getAttribute(String name):根据名称获取绑定的对象
Enumeration getAttributeNames() :获取ServletContext域中所有的值对应的名称
void removeAttribute(String name):根据名称移除对象
void setAttribute(String name,Object value):添加或修改对象。
3.2实现多个Servlet之间的数据共享
3.3获取WEB应用的初始化参数(应用的全局参数)
在web.xml下配置以下信息:
<context-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</context-param>
这些参数就属于整个应用的全局参数,使用ServletContext来读取。
3.4读取资源文件的三种方式:
利用ServletContext.getRealPath():
特点:读取应用中任何文件。只能在Web环境下用
利用ResourceBundle读取配置文件
特点:可以用在非web环境下。但是只能读取类路径中的properties文件
利用类加载器读取配置文件(专业)
特点:可以用在非web环境下。可以读取类路径下的任何文件。
五、HttpServletResponse详解
5.1输出中文数据:
字节流:
注:String.getBytes()方法:使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
String.getBytes("UTF-8")方法:使用UTF-8将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
ServletOutputStream out = response.getOutputStream();
out.write("中文".getBytes());无乱码
无乱码的原因:平台默认的字符集和浏览器默认的字符集一样(在中国一般为GBK)
ServletOutputStream out = response.getOutputStream();
out.write("中文".getBytes("UTF-8"));有乱码
解决办法:
通知浏览器,使用的码表
方式一:response.setHeader("Content-Type", "text/html;charset=UTF-8");
方式二:response.getOutputStream().write("<meta http-equiv='Content-Type' content='text/html;charset=UTF-8'>".getBytes("UTF-8"));
*方式三:response.setContentType("text/html;charset=UTF-8");//方式一、二、三都是一样的
字符流:
注:Servlet中的字符流默认查ISO-8859-1(SUN的Servlet规范要求的)
PrintWriter out = response.getWriter();
out.write(s);//字符输出流out默认查的是ISO-8859-1码表,即默认以ISO-8859-1编码的形式输出到浏览器
解决办法:
方式一:
第一步:更改默认的编码: response.setCharacterEncoding("UTF-8");
第二步:通知浏览器的编码: response.setHeader("Content-Type", "text/html;charset=UTF-8");
方式二:
response.setContentType("text/html;charset=UTF-8");
在字符流输出中文数据时:response.setContentType("text/html;charset=UTF-8");有两个作用:
(1)通知字符流以UTF-8编码输出
(2)通知客户端以UTF-8解码显示
5.2控制不要缓存
response.setHeader("Pragma","no-cache"); // HTTP1.0
response.setHeader("Cache-Control","no-cache"); // HTTP1.1
response.setDateHeader("Expires", 0);
5.3HttpServletResponse细节:
字节流和字符流不能同时使用,互斥的。
通过字符流或字节流输出的数据并不是直接打给浏览器的。而是把数据写到response对象的缓存中的。服务器从缓存中取出数据,按照HTTP协议的响应格式输出给浏览器。
如果你调用的response的输出流没有主动关闭,服务器会替你关的。
六、HttpServletRequest详解
HttpServletRequest代表着客户端的请求。要客户的信息只要找这个对象即可,该对象由容器创建。
ServletRequest是一个域对象(内部维护了一个Map<String,Object>)
Object getAttribute(Stirng name):
void setAttribute(String name,Object value):
void removeAttribute(String name):
请求参数的编码:
浏览器当前使用什么编码,就以什么编码提交请求参数。<meta http-equiv="content-type" content="text/html; charset=UTF-8">
request.setCharacterEncoding(编码):通知程序,客户端提交的数据使用的编码。但是只对POST请求方式有效
如果是get请求提交数据,编码就是ISO-8859-1
请求转发、包含、重定向
1、请求转发:(当前应用内转)
请求转发借助于RequestDispatcher: RequestDispatcher.forward(request,response)
如何得到RequestDispatcher对象:
方式一:ServletContext.getRequestDispatcher(目标资源的URI);
方式二:ServletRequest.getRequestDispatcher(目标资源的URI);
区别:
方式一中的目标资源的URI必须以"/"开头,否则报错,此"/"就表示的是当前应用(绝对路径表示法)
方式二中的目标资源的URI如果以"/"开头,就表示的是当前应用(绝对路径表示法)。如果不以"/"开头,就表示相对路径。
转发的细节:AServlet(源组件)--->BServlet(目标组件)
注:Response对象是有缓存的。转发前,容器会清空response的缓存
1>转发前会清空response的正文。容器会清空源组件输出的数据。因此,用户只会看到目标组件输出的页面结果。但是,源组件的响应头信息是不清空的。
2>转发页面上只会输出目标组件的输出,源组件的任何页面输出都无效。
原则:转发前,不要刷新或关闭response的输出流。
2、包含:借助于RequestDispatcher: RequestDispatcher.include(request,response)
AServlet(源组件)--->BServlet(目标组件):AServlet包含BServlet的输出内容
包含的细节:
由源组件包含到目标组件时,容器会清空目标组件的头。因此,只有源组件设置的头才有效。但是,目标组件的响应体信息是不清空的。
编码原则:不要在目标组件中设置响应头。(做无用功)
3、重定向:response.sendRedirect(String location)
各种URL地址的写法
相对路径:不是以"/"开头
绝对路径:(建议的)
原则:地址是不是给服务器用的,如果是,"/"就代表着当前应用。如果是给客户端用的绝对路径要加上应用名称。
<link href=path/> 要加/day07
<script src=path/> 要加/day07
<img src=path/> 要加/day07
<a href=path/> 要加/day07
<form action="path"/> 要加/day07
HttpServletResponse.sendRedirect(path) 要加/day07
getRequestDispatcher(String path): 不要加应用名称,"/"就代表着当前应用
ServletContext.getRealPath(path) 不要加,"/"就代表着当前应用
响应消息头:Refresh=2;URL=path 要加/day06
七、会话概述
(一)Cookie 是客户端技术
1、Cookie详细介绍
javax.servlet.http.Cookie
1)Cookie是什么?
Cookie是一段小信息。Servlet把这些小信息写到客户端的缓存中(Set-Cookie),客户端还能带着小信息给服务器(Cookie)。
2)Cookie的属性:
name:必须的
value:必须的
comment:(可选的)注释
path:(可选的)
写Cookie的程序的访问路径是:http://localhost:8080/day07/servlet/CookieDemo1
其中:localhost就是域名;/day07/servlet就是当前Cookie的path
若访问的地址的URI是以cookie的路径(path)开头的,那么发出的请求就会带上这个Cookie
eg:
1、cookie的路径是/day07
现在访问的地址是:http://localhost:8080/day07/servlet/CookieDemo1 带Cookie
现在访问的地址是:http://localhost:8080/day07/CookieDemo1 带Cookie
2、cookie的路径是/day07/servlet/
现在访问的地址是:http://localhost:8080/day07/servlet/CookieDemo1 带Cookie
现在访问的地址是:http://localhost:8080/day07/CookieDemo1 不带Cookie
domain:(可选的)默认值是写Cookie的那个网站。如果domain取值为localhost,那么只有访问localhost这个网站时才会带过去。
maximum age:
(可选的)设置Cookie的最大存活时间。默认值是浏览器进程(一次会话)。单位是秒。
可选的。不设置就是会话过程(存在浏览器的内存中)。单位是秒
若设置为0,则会删除Cookie。
version:可选的。
3)向客户端写Cookie:HttpServletResponse.addCookie(Cookie)(就是写了一个响应消息头:Set-Cookie:cookie的信息)
特点:一个浏览器针对一个网站最多存20个Cookie;一共最多存300个Cookie,每个Cookie的长度不能超过4KB。
4)服务器得到客户端传来的Cookie:HttpServletRequest.getCookies()
5)区分Cookie:domian+path+name:唯一定位一个Cookie eg:localhost:8080/day07/servlet/CookieDemo1
2、Cookie案例:
1记住用户最后一次的访问时间
2记住用户登录时的用户名
3电商网站:记住用户商品的历史浏览记录
(二)HttpSession是服务器端技术
1、HttpSession 是一个域对象。
2、HttpSession实际上用的是cookie技术。服务器向客户端写了一个特殊的cookie,名字为"JSESSIONID",值为当前session对象的id(由服务器生成、唯一),path是当前应用。
3、HttpSession中常用的方法
a、得到HttpSession对象:HttpServletRequest.getSession():根据客户端cookie(JSESSIONID=HttpSession对象的id)的值查找session对象,若没有,创建一个session对象。
b、HttpServletReqeust.getSession(boolean create):如果为true,与a没有区别。如果为false,只会查找。
c、HttpSession.getId():唯一的session对象标识。
HttpSession对象的状态及转换(序列化)
4、更改内存中HttpSession对象的超时时间。
修改web.xml
<session-config>
<session-timeout>1</session-timeout><!--自然整数,单位是分钟-->
</session-config>
原文:http://blog.csdn.net/wodewutai17quiet/article/details/44005183