Servlet知识上篇
来源:互联网 发布:mac系统windows虚拟机 编辑:程序博客网 时间:2024/06/06 19:09
1.Servlet的时序图
2.Servlet的生命周期的三个阶段
(1) Servlet容器加载servlet类,把servlet类的.class文件中的数据读到内存中。
(2) 然后Servlet容器创建一个ServletConfig对象。ServletConfig对象包含了Servlet的初始化配置信息。
(3)Servlet容器创建一个servlet对象。
(4) Servlet容器调用servlet对象的init方法进行初始化。init方法有一个带形参的方法,如下图。说明ServletConfig对象是在调用init方法之前
创建的。
(1)当servlet容器接收到一个请求时,servlet容器会针对这个请求创建servletRequest和servletResponse对象。
(2)然后调用service方法。并把这两个参数传递给service方法。Service方法通过servletRequest对象获得请求的信息。并处理该请求。再通过 servletResponse对象生成这个请求的响应结果。
(3)Servlet接口中定义了一个service方法,HttpServlet对该方法进行了实现,实现方式就是将ServletRequest与ServletResponse转换为HttpServletRequest与HttpServletResponse,转换完毕后,会调用HttpServlet类中自己定义的service方法,在该service方法中,首先获得到请求的方法名,然后根据方法名调用对应的doXXX方法,比如说请求方法为GET,那么就去调用doGet方法;请求方法为POST,那么就去调用doPost方法。下面代码是httpServlet的service方法的源代码。
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 / 1000 * 1000)) { // 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); } }由上述代码可以看出,在运行阶段,HttpServlet会先调用service方法,然后通过解析请求时get还是post,然后再调用对应的doXxx()方法。所以顺序是先service,然后才是doXxx方法。所以,一般来说不再重写HttpServlet的service方法,只重写doGet和doPost方法。GenericServlet 是不存在doXxx方法的。如下图:
3).销毁阶段
当Web应用被终止时,servlet容器会先调用servlet对象的destrory方法,然后再销毁servlet对象,同时也会销毁与servlet对象相关联的servletConfig对象。我们可以在destroy方法的实现中,释放servlet所占用的资源,如关闭数据库连接,关闭文件输入输出流等。
在这里该注意的地方:
在servlet生命周期中,servlet的初始化(第一个客户端访问)和和销毁阶段(如关闭服务器)只会发生一次,而service方法执行的次数则取决于servlet被客户端访问的次数
3.Servlet、GenericServlet、HttpServlet
Servlet是一个接口,而GenericServlet实现了servlet这个接口,并且也实现了ServletConfig, java.io.Serializable这两个接口。而HttpServlet继承了GenericServlet这个抽象类。这是三者之间的关系。HttpServlet比GenericServlet多了一些方法:如doXXX()方法
区别是:
(1)HttpServlet是基于http协议的,而其余两者没有特别针对哪个协议。
(2)Servlet和GenerticServlet在执行阶段创建的是ServletRequest和ServletResponse对象,而HttpServlet创建的是 HttpServletRequest和HttpServletResponse对象。如下源代码:
<span style="font-weight: normal;"><span style="font-size:14px;"> public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; try { request = (HttpServletRequest) req; response = (HttpServletResponse) res; } catch (ClassCastException e) { throw new ServletException("non-HTTP request or response"); } service(request, response); }}</span></span>
HttpServletRequest、 HttpServletResponse分别是ServletRequest和ServletResponse的子类 。它们比父类多了一些针对http协议的方法。如:getHeader(String name), getMethod() , getSession() 。
4.ServletContext和ServletConfig
getRequestURI方法返回请求行中的资源名部分。
getQueryString 方法返回请求行中的参数部分。
getPathInfo方法返回请求URL中的额外路径信息。额外路径信息是请求URL中的位于Servlet的路径之后和查询参数之前的内容,它以“/”开头。
getRemoteAddr方法返回发出请求的客户机的IP地址。
getRemoteHost方法返回发出请求的客户机的完整主机名。
getRemotePort方法返回客户机所使用的网络端口号。
getLocalAddr方法返回WEB服务器的IP地址。
getLocalName方法返回WEB服务器的主机名。
获得客户机请求头
getHeader(string name)方法:String ; getHeaders(String name)方法:Enumeration
getParameter()客户端与服务器端交互:获取客户端的表单或者url返回的是一个string对象
getAttribute(string name,string value)服务器端交互先通过setAttribute()设置属性,在通过getAttribute()获取属性返回的是一个object对象
HttpServletResponse对象
//浏览器不缓存的三种方法
response.setDateHeader("Expires", 0);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("pragma","no-cache");
Response.getOutputStream() 字节输出流对象
Response.getWriter() 字符的输出流对象
4.Servlet的多线程问题
Servlet默认是单实例多线程运行方式,的模式,如果servlet中定义的全局变量是可写的,就会发生同步问题所以Servlet的全局变量最好是只读的,局部变量可以可读可写的。单实例是指Servlet对象是在servlet初始化阶段才创建的,而初始化init()方法只进行一次,所以Servlet对象是单实例的。当有客户端请求Servlet时,Servlet容器为这个客户端创建一个线程,去执行service方法。所以针对一个单实例多线程的程序,数据是不安全的。
5.forward和redirect
request.getRequestDispatcher(/test4.jsp).forward(request,response);请求转发
response.sendRedirect("www.baidu.com");重定向
forward和redirect的区别
1.从地址栏显示来说
forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址.redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.所以redirect等于客户端向服务器端发出两次request,同时也接受两次response。
2.从数据共享来说
forward:转发页面和转发到的页面可以共享request里面的数据.假如从a页面 到 b页面 在到c页面 如果用在a页面中:
request.setAttribute("a","aa");
<jsp:forward page="b.jsp"></jsp:forward>
在b页面中:<jsp:forward page="c.jsp"></jsp:forward>跳转 在c页面用request.getAttribute("a")
就可以得到a页面的值,或者用request.getParameter("name")也可以得到。
但是要用response.sendRedirect("b.jsp");跳转的话就得不到a 页面的值和内容。
redirect:不能共享数据.
redirect不仅可以重定向到当前应用程序的其他资源,还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源.forward,方法只能在同一个Web应用程序内的资源之间转发请求.forward 是服务器内部的一种操作.redirect 是服务器通知客户端,让客户端重新发起请求.所以,你可以说 redirect 是一种间接的请求, 但是你不能说"一个请求是属于forward还是redirect "
3.从运用地方来说
forward:一般用于用户登陆的时候,根据角色转发到相应的模块.redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等.
4.从效率来说
forward:高.
redirect:低.
6.解决servlet的乱码问题
request请求分为post和get,对于不同的请求方式有不同的解决乱码的方案;
1.post请求乱码
错误原因:
解决方案:
2.get请求乱码
Response乱码
在网上很有效的解决方法是添加:
response.setCharacterEncoding("UTF-8");
解决不了,后来又搜到一条解决方法是:
respnse.setHeader("content-type","text/html;charset=UTF-8");
两句都填上,后来终于解决了这个问题;
其实我们应该思考一下本质;
问题1:
我们这里先来说明一下错误的原因,下图是显示乱码的流程图:
response.setContentType("text/html;charset=UTF-8"); 目的是为了控制浏览器的行为,即控制浏览器用UTF-8进行解码;
response.setCharacterEncoding("UTF-8"); 的目的是用于response.getWriter()输出的字符流的乱码问题,如果是response.getOutputStream()是不需要此种解决方案的;因为这句话的意思是为了将response对象中的数据以UTF-8解码后发向浏览器;
解决方案流程图:
问题2
问题代码如下:
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- PrintWriter out = response.getWriter();
- String data = "博客";
- out.println(data);
- }
浏览器输出: ??
原因:"博客"首先被封装在response对象中,因为IE和WEB服务器之间不能传输文本,然后就通过ISO-8859-1进行编码,但是ISO-8859-1中没有“博客”的编码,因此输出“??”表示没有编码;
错误代码流程图:
而解决方案是:response.setCharacterEncoding("GB2312"); 设置response使用的码表
解决方案流程图:
补充:通过<meta>标签模拟response头;
<meta http-equiv="content-type" content="text/html"/> 等价于 response.setContentType("text/html");
- Servlet知识上篇
- Remoting编程知识上篇
- Remoting编程知识上篇
- ASP.Net 知识汇总 (上篇)
- Servlet知识
- Servlet知识
- servlet知识
- Servlet知识
- Servlet知识
- servlet知识
- servlet知识
- Servlet知识
- Servlet知识
- C/C++知识总结——上篇
- Java Servlet 入门知识
- servlet知识收集
- servlet方面知识
- JSP+Servlet小知识
- java SE基础(UDP通信)
- CSS,Jquery精美进度条和滑动条(滑块)插件
- shell之文本编辑
- EditText的功能与用法
- 车道线检测-模式识别综合实验
- Servlet知识上篇
- Android 2.2 API ---------ImageButton
- 《Thinking in Java》第一篇笔记 对多态的一点小琢磨
- android程序内存泄漏的原因和解决办法
- Bootstrap 按钮 图片
- ACM组合数学题目列表
- code vs 方格取数3
- iOS 学习资料整理
- PythonChallenge Mission 12