Servlet细节问题:
1.一个<servlet>可以对应多个<servlet-mapping>,从而一个Servlet可以有多个访问路径;
2.url-partten中的路径可以使用*匹配符进行匹配,但只能以/开头/*结尾或*.后缀,优先级判断的标准是:①选最像的;②*.后缀的匹配级别最低。
3.<servlet>可以配置<load-on-startup>标签来指定Servlet的启动次序,当不配置或配置参数为负数时,表示只有在该Servlet首次被访问时才回去创建此Servlet,配置为0或正数时,表示在web应用被加载时,该Servlet即Servlet容器所创建,值越小越先被加载创建。
4.缺省的Servlet:一个Servlet的<url-pattern>被配置为正斜杠(/),这个Servlet就成了缺省的Servlet,其他Servlet都不处理的请求,有缺省的Servlet处理;
静态资源的访问就是由缺省的Servlet来执行的,而此缺省的Servlet是由tomcat提供的,在web.xml中可以看到它的配置信息,此处的web.xml是指Servlet容器中的conf/web.xml,Servlet容器中的所有的web应用的WEB-INF/web.xml都继承了conf/web.xml的配置信息。
设置404页面500页面也是有缺省的Servlet来执行的;通常我们不会去配置缺省的Servlet。
5.线程安全问题
由于默认情况下Servlet在内存中只有一个对象,当多个浏览器访问Servlet时就有可能产生线程安全问题,目前解决的办法有以下:
①加锁(效率较低)
②实现SingleThreadMode接口(不能真正的解决线程安全问题,已经废弃使用)
③在Servlet中尽量少用类变量,将会造成造成线程安全问题的代码加锁,尽量的使被锁住的内容少,减少客户端等待的时间,提高Servlet的响应速度。
ServletConfig(代表当前的Servlet的配置对象)
String getServletName() 获得当前Servlet在web.xml中配置的名字,<servlet-name>的值;
String getInitParameter(String name) 根据name,获取当前Servlet在web.xml中的初始化参数值,name是初始化参数的<param-name>;
Enumeration getInitParameterNames() 获取当前Servlet在web.xml中的所有初始化参数的名称;
ServletContext getServletContext() 获取代表当前web应用的ServletContext对象
ServletContext(代表当前web应用)
Web应用被创建时会创建唯一一个ServletContext对象。
ServletContext对象的主要作用:
1.作为域对象可以在整个web应用范围内共享数据。
作用范围:整个web应用范围内;
生命周期:当服务器加载web应用时就会创建ServletContext对象,当web应用被移除时ServletContext对象被销毁;
void setAttribute(String key, Object obj) 设置一个域属性
Object getAttribute(String key) 根据key值查找到对应的域属性
void removeAttribute(String key) 删除key对应的域属性
2.获取web应用的初始化参数
String getInitParameter(String name) 根据name,获取当前web应用在web.xml中的初始化参数值;
Enumeration getInitParameterNames() 获取当前web应用在web.xml中的所有初始化参数的名称
3.实现Servlet的重定向和转发
重定向: 302 + Location,两次请求两次响应
请求转发:一次请求一次响应
①请求重定向
方法一:(HttpServletResponse response)
response.setStatus(302);
response.setHeader(“Location”, “/HelloWorld/index.html”);
方法二:
response.sendRedirect(“/HelloWorld/index.html”);
②请求转发
RequestDispatcher dispatcher
= this.getServletContext().getRequestDispatcher(“/HelloWorld/registerServlet”);
dispatcher.forward(request, response);
【说明】从上面请求转发的过程中看到,请求转发并没有创建新的HttpServletRequest和HttpServletResponse对象,而是将之前接收到的request和response转发给其他Servlet。
4.Servlet容器的相关信息(ServletContext context)
context.getMajorVersion() 获得容器支持的Java Servlet API的主版本号
context.getMinorVersion() 获得容器支持的Java Servlet API的次版本号
context.getServletInfo() 获得Servlet容器名称和版本号
5.访问Servlet中的文件系统
getRealPath(String name) 获得在/WEB-INFO下,名称为name的文件的绝对路径。
getMimeType(String file) 获得指定文件的MIME类型(e.g. Text/html)
getContextPath() 获得web应用的URL入口
ServletRequest(从对象中获得来自客户端的请求信息)
常用接口:
getContentLength() 获得请求正文的长度,未知则返回-1
getContentType() 获得请求正文的编码方式
getInputStream() 读取请求中的输入流
getLocalAddr() 获得服务器的IP地址
getLocalName() 获得主机(Host)名
getLocalPort() 获得服务器FPT端口
getParameter(String name) 根据参数名获得请求URL中的请求参数值
getProtocol() 获得通信协议及版本号(e.g. HTTP 1.1)
getReader() BufferReader
getRemoteAddr() 获得客户端的IP地址
getRemoteHost() 获得客户端主机名
getRemotePort() 获得客户端FTP端口号
HttpServletRequest(继承自ServletRequest)
常用接口:
getContentPath() 获得客户端访问服务器web应用的入口,
(e.g. Url=http://localhost:8080/HelloWorld/infoServlet时,URL入口为/HelloWorld)
getCookies()
getHeader(String key) 从request中获得key的请求头信息
getHeaderNames() 获得请求头中所有的的key,返回一个Enumeration对象
getMethod() 获得请求的方式(GET,POST等)
getRequestURI() 获取请求url中的URI
getQueryString() 获取请求URL中的请求参数部分
ServletResponse
常用接口:
setCharacterEncoding(String charset) 设置服务器的编码方式,默认为IOS8859-1
setContentLength() 设置响应正文的长度
getCharacterEncoding() 获得服务器的编码格式
getContentType() 获得服务器的MIME类型
setBufferSize(int size) 设置存放响应的缓存的大小
getBufferSize() 获得服务器存放响应的缓存的大小
reset() 清空缓存区正文、响应内容(全部清空)
resetBuffer() 只清空缓存区正文内容
flushBuffer() 强制性的将缓存区的内容发给浏览器
isCommitted() 若为true表示缓存区数据已经发给了浏览器,若返回false表示缓存区数据未发送
getOutputStream() 从response中获得字节流,用于向响应缓存区写入数据
getWriter() 从response中获得字符流,用于向响应缓存区写入数据
【说明】一下几种情况,缓存数据会被提交给浏览器:
①缓存区数据已经满;
②调用response的flushBuffer()方法
③调用ServletOutputStream()/PrintWriter对象的flush()或close()方法。
【注意】
Servlet在调用完service()之后,会自动关闭ServletOutputStream/PrintWriter,从而保证数据发送给浏览器。
HttpServletResponse(通过该对象生成响应)
常用接口:
setHeader(String key, String value) 设置响应头信息
Servlet相关问题:
1.控制服务器和浏览器的编码
①方法一
response.getOutputStream().write(“中国”.getBytes(“utf-8”)); // 服务器端指定编码格式通过设置HTTP响应头设置浏览器的解码方式为utf-8
response.setHeader(“Content-Type” , “text/html;charset=utf-8”);
//上面设置HTTP响应头信息的过程也可以通过下面的方式
response.setContentType(“utf-8”);
②方法二
// 设置服务器的编码方式
response.setCharacterEncoding(“utf-8”);
response.getWriter().write(“中国”);
// 设置完服务器的编码格式,与方法一一样,需要通过HTTP响应头设置浏览器的解码方式
response.setHeader(“Content-Type”, “text/html;charset=utf-8”);
// 或者response.setContentType(“utf-8”);
【注意】
a).ISO8859-1中没有对中文进行编码,使用ISO8859-1编码中文,则会全部编译为?号;
b).为了保证浏览器不出现中文乱码的情况,需要保证服务器的编码使用的码表和浏览器的解码的码表相同;
c)response.getOutputStream()将保存Http响应的缓存区设置为字节流型,缓存的内容是以字节流的形式保存的,response.getWriter()是将缓存设置为字符流型,将缓存内容以字符流的形式保存下来,因此对于同一个response,上面两种方法不能同时出现;
需要说明的是,在请求转发的时候,由于转发的是同一个response,所以同样需要保证转发response和接受response的Servlet使用相同的方法写缓存。
2.图片显示和下载文件
InputStream in = new FileInputStream(“iMxd.png”);
OutputStream out = response.getOutputStream();
byte[] b = new byte[1024];
int i = 0;
while((i = in.read(b)) != -1)
{
out.write(b,0,i);
}
in.close();
【说明】
①上面的程序中无需关闭OutputStream,Servlet会自动关闭;
②通过上面的程序会在响应缓存区存储一张图片,通过字符流发送到浏览器,浏览器在接收到图片流之后会将图片显示在网页上,不会是下载图片的操作;若要改成下载图片而不是现实图片,可以通过设置响应头信息来实现:
response.setHeader(“Content-Disposition”,“attachment;filename=iMxd.png”);
通过设置响应头中的Content-Disposition来指定浏览器下载图片,当图片名称为中文时,下载之后的文件名称会出现乱码等问题,可以通过下面的方式来解决这个问题:
response.setHeader(“Content-Disposition”,”attachment;filename=” + URLEncoder.encode(“中国.png”));
URLEncoder的encode实现URL编码
URLDecoder的decode实现URL解码
3.Response控制定是刷新页面
response.setHeader(“Refresh”,”1”);
// 上面给响应头添加了刷新页面的信息,浏览器介绍到信息之后,会每隔一秒重新请求一次服务器,并同时刷新页面
response.setHeader(“Refresh”,”3;url=/HelloWorld/index.html”);
// 上面的程序将在三面之后跳转到/HelloWorld/index.html
在Html中模拟”Refresh”响应头:
<head>
<meta http-equiv=”Refresh”
content=”3;url=/HelloWorld/index.html” >
</head>
4.Response控制浏览器不进行缓存
若浏览器对访问资源页面进行了缓存,当浏览器再次访问相同资源时,浏览器会显示本地中已经缓存的信息,而不会在服务器中重新请求信息的数据,这样就造成了访问资源数据不是实时的。
因此对于实时信息不应该做缓存。
response.setIntHeader(“Expires”, -1);
response.setHeader(“Cache-Control”, “no-cache”);
response.setHeader(“Pragma”, “no-cache”);
// 由于历史原因,不同的浏览器支持的响应头信息太完全一致,上面的三行头信息的设置可以保证所有浏览器不缓存内容
// 若要进行资源的缓存,则:
response.setDateHeader(“Expires”, System.currentTimeMillis() + 1000 * 60*60 * 24 * 30);
【说明】
通过响应头通知浏览器进行缓存,需要设置缓存的时间,上面的代码设置保存1个月,此时间是从1970年1月1日0时0分0秒开始计算,一直到未来的某个时间点,设置在这段时间内缓存资源,不在此段时间内则删除资源,System.currentTimeMillis()是得到了从上面起点时间(1970年1月1日0时0分0秒)到当前的毫秒数,再加上一个月的毫秒数。
【注意】
需要注意的是1000*60*60*24*30已经超出了int类型的范围,会起到减的效果,因此一般是转化为Long型,1000l*60*60*24*30(在1000后面加l)。
5.请求重定向
请求重定向会进行两次访问两次响应,当浏览器访问服务器某一Servlet时,若此Servlet无对应的资源,会响应浏览器,通过302通知浏览器去访问其他url,浏览器拿到新的url之后,无需用户操作浏览器,自动重定向新的url,访问服务器,产生了新的访问和响应。
重定向有两种方法:
方法一:
response.setStatus(302);
response.setHeader(“Location”, “/HelloWorld/index.html”);
方法二:
response.setRedirect(“/HelloWorld/index.html”);