Servlet总结
在Java Web程序中,Servlet主要负责接收用户请求HttpServletRequest,在doGet(),doPost()中做相应的处理,并将回应HttpServletResponse反馈给用户。Servlet可以设置初始化参数,供Servlet内部使用。一个Servlet类只会有一个实例,在它初始化时调用init()方法,销毁时调用destroy()方法。Servlet需要在web.xml中配置(MyEclipse中创建Servlet会自动配置),一个Servlet可以设置多个URL访问。Servlet不是线程安全,因此要谨慎使用类变量。
Servlet接口中有哪些方法及Servlet生命周期
Servlet接口定义了5个方法,其中前三个方法与Servlet生命周期相关:
- void init(ServletConfig config) throws ServletException
- void service(ServletRequest req, ServletResponse resp) throws ServletException, java.io.IOException
- void destory()
- java.lang.String getServletInfo()
- ServletConfig getServletConfig()
生命周期
Web容器加载Servlet并将其实例化后,Servlet生命周期开始,容器运行其init()方法进行Servlet的初始化;请求到达时调用Servlet的service()方法,service()方法会根据需要调用与请求对应的doGet或doPost等方法;当服务器关闭或项目被卸载时服务器会将Servlet实例销毁,此时会调用Servlet的destroy()方法。init方法和destroy方法只会执行一次,service方法客户端每次请求Servlet都会执行。Servlet中有时会用到一些需要初始化与销毁的资源,因此可以把初始化资源的代码放入init方法中,销毁资源的代码放入destroy方法中,这样就不需要每次处理客户端的请求都要初始化与销毁资源
容器如何执行请求
- 用户发出servlet请求
- 服务器解析请求,发现请求对象为servlet之后,创建HTTP请求对象和HTTP响应对象
- 容器根据请求中的URL找到Servlet,并为其创建或分配一个线程,并把请求对象和响应对象传递给servlet线程
- 容器调用setvlet的service(),根据请求方式的不同,GET或者是POST,执行doGet()或者doPost()
- 执行方法结束,线程结束。容器把响应对象转换为一个HTTP响应,把它发给客户,然后删除请求对象和响应对象
get和post请求的区别
- get请求用来从服务器上获得资源,而post是用来向服务器提交数据(Restful开发中确定资源,通过请求类型的不同,比如get,put,delete,update来执行不同的控制器处理方法)
- get将表单中数据按照name=value的形式,添加到action 所指向的URL 后面,并且两者使用"?“连接,而各个变量之间使用”&"连接;post是将表单中的数据放在HTTP协议的请求头或消息体中,传递到action所指向URL
- get传输的数据要受到URL长度限制(最大长度是 2048 个字符);而post可以传输大量的数据,上传文件通常要使用post方式
- 使用get时参数会显示在地址栏上,如果这些数据不是敏感数据,那么可以使用get;对于敏感数据还是应用使用post
转发(Forward)和重定向(Redirect)的区别
转发和重定向的区别
转发是服务器行为,重定向是客户端行为
转发
转发(Forword) 通过RequestDispatcher对象的forward(HttpServletRequest request,HttpServletResponse response)方法实现的。RequestDispatcher可以通过HttpServletRequest 的getRequestDispatcher()方法获得。例如下面的代码就是跳转到login_success.jsp页面
request.getRequestDispatcher("login_success.jsp").forward(request, response);
重定向
重定向(Redirect) 是利用服务器返回的状态码来实现的。客户端浏览器请求服务器的时候,服务器会返回一个状态码。服务器通过 HttpServletResponse 的 setStatus(int status) 方法设置状态码。如果服务器返回301或者302,则浏览器会到新的网址重新请求该资源
区别
- 从地址栏显示来说:forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址. redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL
- 从数据共享来说:forward:转发页面和转发到的页面可以共享request里面的数据. redirect:不能共享数据
- 从运用地方来说:forward:一般用于用户登陆的时候,根据角色转发到相应的模块. redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等
- 从效率来说:forward:高. redirect:低.
自动刷新(Refresh)
自动刷新不仅可以实现一段时间之后自动跳转到另一个页面,还可以实现一段时间之后自动刷新本页面。Servlet中通过HttpServletResponse对象设置Header属性实现自动刷新例如:
Response.setHeader("Refresh","5;URL=http://localhost:8080/servlet/example.htm");
其中5为时间,单位为秒。URL指定就是要跳转的页面(如果设置自己的路径,就会实现每过5秒自动刷新本页面一次)
Servlet与线程安全
Servlet不是线程安全的,多线程并发的读写会导致数据不同步的问题。 解决的办法是尽量不要定义name属性,而是要把name变量分别定义在doGet()和doPost()方法内。虽然使用synchronized(name){}语句块可以解决问题,但是会造成线程的等待,不是很科学的办法。 注意:多线程的并发的读写Servlet类属性会导致数据不同步。但是如果只是并发地读取属性而不写入,则不存在数据不同步的问题。因此Servlet里的只读属性最好定义为final类型的
JSP和Servlet是什么关系
Servlet是一个特殊的Java程序,它运行于服务器的JVM中,能够依靠服务器的支持向浏览器提供显示内容。JSP本质上是Servlet的一种简易形式,JSP会被服务器处理成一个类似于Servlet的Java程序,可以简化页面内容的生成。Servlet和JSP最主要的不同点在于,Servlet的应用逻辑是在Java文件中,并且完全从表示层中的HTML分离开来。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件。有人说,Servlet就是在Java中写HTML,而JSP就是在HTML中写Java代码,当然这个说法是很片面且不够准确的。JSP侧重于视图,Servlet更侧重于控制逻辑,在MVC架构模式中,JSP适合充当视图(view)而Servlet适合充当控制器(controller)
JSP工作原理
JSP是一种Servlet,但是与HttpServlet的工作方式不太一样。HttpServlet是先由源代码编译为class文件后部署到服务器下,为先编译后部署。而JSP则是先部署后编译。JSP会在客户端第一次请求JSP文件时被编译为HttpJspPage类(接口Servlet的一个子类)。该类会被服务器临时存放在服务器工作目录里面。下面通过实例给大家介绍。 工程JspLoginDemo下有一个名为login.jsp的Jsp文件,把工程第一次部署到服务器上后访问这个Jsp文件,我们发现这个目录下多了下图这两个东东。 .class文件便是JSP对应的Servlet。编译完毕后再运行class文件来响应客户端请求。以后客户端访问login.jsp的时候,Tomcat将不再重新编译JSP文件,而是直接调用class文件来响应客户端请求。
请求的时候才被编译 ,因此第一次请求JSP时会感觉比较慢,之后就会感觉快很多。如果把服务器保存的class文件删除,服务器也会重新编译JSP。
开发Web程序时经常需要修改JSP。Tomcat能够自动检测到JSP程序的改动。如果检测到JSP源代码发生了改动。Tomcat会在下次客户端请求JSP时重新编译JSP,而不需要重启Tomcat。这种自动检测功能是默认开启的,检测改动会消耗少量的时间,在部署Web应用的时候可以在web.xml中将它关掉
JSP内置对象
JSP的9个内置对象
- request:封装客户端的请求,其中包含来自GET或POST请求的参数
- response:封装服务器对客户端的响应
- session:封装用户会话的对象
- application:封装服务器运行环境的对象
- pageContext:通过该对象可以获取其他对象
- out:输出服务器响应的输出流对象
- config:Web应用的配置对象
- page:JSP页面本身(相当于Java程序中的this)
- exception:封装页面抛出异常的对象
Request对象的主要方法
- setAttribute(String name,Object):设置名字为name的request 的参数值
- getAttribute(String name):返回由name指定的属性值
- getAttributeNames():返回request 对象所有属性的名字集合,结果是一个枚举的实例
- getCookies():返回客户端的所有 Cookie 对象,结果是一个Cookie 数组
- getCharacterEncoding() :返回请求中的字符编码方式 = getContentLength() :返回请求的 Body的长度
- getHeader(String name) :获得HTTP协议定义的文件头信息
- getHeaders(String name) :返回指定名字的request Header 的所有值,结果是一个枚举的实例
- getInputStream() :返回请求的输入流,用于获得请求中的数据
- getParameter(String name) :获得客户端传送给服务器端的有 name指定的参数值
- …
request.getAttribute()和 request.getParameter()有何区别
- 从获取方向来看:getParameter()是获取 POST/GET 传递的参数值;getAttribute()是获取对象容器中的数据值
- 从用途来看:getParameter用于客户端重定向时,即点击了链接或提交按扭时传值用,即用于在用表单或url重定向传值时接收数据用;getAttribute 只能收到程序用 setAttribute 传过来的值
- 可以用 setAttribute,getAttribute 发送接收对象.而 getParameter 显然只能传字符串。setAttribute 是应用服务器把这个对象放在该页面所对应的一块内存中去,当你的页面服务器重定向到另一个页面时,应用服务器会把这块内存拷贝另一个页面所对应的内存中。这样getAttribute就能取得你所设下的值,当然这种方法可以传对象。session也一样,只是对象在内存中的生命周期不一样而已;getParameter只是应用服务器在分析你送上来的 request页面的文本时,取得你设在表单或 url 重定向时的值。
include指令include的行为的区别
include指令-静态: JSP可以通过include指令来包含其他文件。被包含的文件可以是JSP文件、HTML文件或文本文件。包含的文件就好像是该JSP文件的一部分,会被同时编译执行。 语法格式如下: <%@ include file=“文件相对 url 地址” %>
include动作-动态:jsp:include动作元素用来包含静态和动态的文件。该动作把指定文件插入正在生成的页面。语法格式如下: <jsp:include page=“相对 URL 地址” flush=“true” />
JSP九大内置对象,七大动作,三大指令
JSP的四种作用域
JSP中的四种作用域包括page、request、session和application,具体来说:
- page代表与一个页面相关的对象和属性
- request代表与Web客户机发出的一个请求相关的对象和属性。一个请求可能跨越多个页面,涉及多个Web组件;需要在页面显示的临时数据可以置于此作用域
- session代表与某个用户与服务器建立的一次会话相关的对象和属性。跟某个用户相关的数据应该放在用户自己的session中
- application代表与整个Web应用程序相关的对象和属性,它实质上是跨越整个Web应用程序,包括多个页面、请求和会话的一个全局作用域
如何实现JSP或Servlet的单线程模式
对于JSP页面,可以通过page指令进行设置。 <%@page isThreadSafe=”false”%>
对于Servlet,可以让自定义的Servlet实现SingleThreadModel标识接口
说明:如果将JSP或Servlet设置成单线程工作模式,会导致每个请求创建一个Servlet实例。Servlet和Jsp默认为单例多线程工作
会话跟踪技术实现
使用Cookie
向客户端发送Cookie
Cookie c =new Cookie("name","value"); //创建Cookie
c.setMaxAge(60*60*24); //设置最大时效,此处设置的最大时效为一天
response.addCookie(c); //把Cookie放入到HTTP响应中
从客户端读取Cookie
String name ="name";
Cookie[]cookies =request.getCookies();
if(cookies !=null){
for(int i= 0;i<cookies.length;i++){
Cookie cookie =cookies[i];
if(name.equals(cookis.getName()))
//something is here.
//you can get the value
cookie.getValue();
}
}
优点:数据可以持久保存,不需要服务器资源,简单,基于文本的Key-Value
缺点:大小受到限制,用户可以禁用Cookie功能,由于保存在本地,有一定的安全风险
URL重写
在URL中添加用户会话的信息作为请求的参数,或者将唯一的会话ID添加到URL结尾以标识一个会话
优点:在Cookie被禁用的时候依然可以使用
缺点:必须对网站的URL进行编码,所有页面必须动态生成,不能用预先记录下来的URL进行访问
隐藏的表单域
<input type="hidden" name ="session" value="..."/>
优点:在Cookie被禁用的时候依然可以使用
缺点:所有页面必须是表单提交之后的结果
HttpSession
在所有会话跟踪技术中,HttpSession对象是最强大也是功能最多的。当一个用户第一次访问某个网站时会自动创建 HttpSession,每个用户可以访问他自己的HttpSession。可以通过HttpServletRequest对象的getSession方 法获得HttpSession,通过HttpSession的setAttribute方法可以将一个值放在HttpSession中,通过调用 HttpSession对象的getAttribute方法,同时传入属性名就可以获取保存在HttpSession中的对象。与上面三种方式不同的 是,HttpSession放在服务器的内存中,因此不要将过大的对象放在里面,即使目前的Servlet容器可以在内存将满时将HttpSession 中的对象移到其他存储设备中,但是这样势必影响性能。添加到HttpSession中的值可以是任意Java对象,这个对象最好实现了 Serializable接口,这样Servlet容器在必要的时候可以将其序列化到文件中,否则在序列化时就会出现异常
Tomcat+Nginx负载均衡集群环境下如何实现会话跟踪
方案一:植入Spring Session框架实现集群下Session
方案二:手动设置Cookie作为自定义"SessionId",通过Redis进行存储
Cookie和Session的的区别
Cookie是Session的一种实现
关于HTTP信息,可以阅读读者本人关于HTTP的博客。