Java Web
1、Servlet总结
在Java Web程序中,Servlet主要负责接收用户请求 HttpServletRequest
,在doGet()
,doPost()
中做相应的处理,并将回应HttpServletResponse
反馈给用户。Servlet 可以设置初始化参数,供Servlet内部使用。一个Servlet类只会有一个实例,在它初始化时调用init()
方法,销毁时调用destroy()
方法。Servlet需要在web.xml中配置,一个Servlet可以设置多个URL访问。Servlet不是线程安全的,因此要谨慎使用成员变量。
2、Servlet的生命周期方法
Servlet接口定义了5个方法,其中前三个方法与Servlet生命周期相关:
void init(ServletConfig config) throws ServletException
void service(ServletRequest req, ServletResponse resp) throws ServletException, java.io.IOException
void destroy()
生命周期: Web容器加载Servlet并将其实例化后,Servlet生命周期开始,容器运行其init()方法进行Servlet的初始化;请求到达时调用Servlet的service()方法,service()方法会根据需要调用与请求对应的doGet或doPost等方法;当服务器关闭或项目被卸载时服务器会将Servlet实例销毁,此时会调用Servlet的destroy()方法。init方法和destroy方法只会执行一次,service方法客户端每次请求Servlet都会执行。Servlet中有时会用到一些需要初始化与销毁的资源,因此可以把初始化资源的代码放入init方法中,销毁资源的代码放入destroy方法中,这样就不需要每次处理客户端的请求都要初始化与销毁资源。
3、get、post请求的区别
get和post底层都是http,使用的都是tcp协议。
-
GET在浏览器回退时是无害的,而POST会再次提交请求。
-
GET产生的URL地址可以被Bookmark,而POST不可以。
-
GET请求会被浏览器主动cache,而POST不会,除非手动设置。
-
GET请求只能进行url编码,而POST支持多种编码方式。
-
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
-
GET请求在URL中传送的参数是有长度限制的,而POST没有。
-
对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
-
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
-
GET参数通过URL传递,POST放在Request body中。
GET和POST还有一个重大区别:GET产生一个TCP数据包;POST产生两个TCP数据包。
对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);
对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。
并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。
4、什么情况下调用doGet()和doPost()
Form标签里的method的属性为get时调用doGet(),为post时调用doPost()。
处理get请求时调用doGet,处理post请求时调用doPost()
5、转发(Forward)和重定向(Redirect)的区别
转发是服务器内部转发,重定向是服务器通知客户端请求一个新的地址
转发(Forward) 通过RequestDispatcher对象的forward(HttpServletRequest request,HttpServletResponse response)方法实现的。RequestDispatcher对象可以通过HttpServletRequest 的getRequestDispatcher()方法获得。
eg.登录成功,转发到login_success.jsp页面:
request.getRequestDispatcher("login_success.jsp").forward(request, response);
重定向(Redirect) 是利用服务器返回的状态码来实现的。客户端浏览器请求服务器的时候,服务器会返回一个状态码。服务器通过 HttpServletResponse
的 setStatus(int status)
方法设置状态码。如果服务器返回301或者302,则浏览器会到新的网址重新请求该资源。
- 从地址栏显示来看
forward:地址栏的url还是原来的那个,不变;redirect:地址栏的url会变为重定向的url
- 从数据共享来看
forward:转发到的页面可以共享request里面的数据. redirect:不能共享数据.
- 从使用场景来看
forward:一般用于用户登陆的时候,登录成功时根据角色转发到相应的模块. redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等
- 从效率来说
forward:高,因为是1次http请求,服务器本地转发到本地,速度快;redirect:低,因为是2次http请求,在客户端、服务器之间来回跑花时间。
6、自动刷新(Refresh)
自动刷新不仅可以实现一段时间后自动跳转到另一个页面,还可以实现一段时间后自动刷新本页面。Servlet中通过HttpServletResponse对象设置Header属性实现自动刷新例如:
Response.setHeader("Refresh","5;URL=http://localhost:8080/servlet/example.html");
其中5为时间,单位为秒。URL指定就是要跳转的页面,如果设置为本页面,每隔5s就会自动刷新本页面。因为5秒之后再次请求本页面,本页面的响应头依然是5秒后刷新,一直循环往复。
7、Servlet与线程安全
Servlet不是线程安全的,因为运行时一个servlet只有一个实例,多个客户端同时访问这个servelt的映射地址,tomcat会为每一个请求都创建一个线程来处理,这些线程同时调用同一个servlet实例来处理请求(访问同一个servlet的成员变量),多线程并发的读写会导致数据不同步的问题,如果并发访问都是只读servlet中的变量、不写入(修改),那倒是没有问题。尽量把只读的变量设置为final。
可以给成员变量加同步锁,但执行效率很低,会有大批请求等待。
解决的办法是servlet中尽量不要定义成员变量,使用的变量尽量放到成员方法doGet、doPost中作为局部变量。
8、JSP和Servlet是什么关系
Servlet是一个特殊的Java程序,它运行于服务器的JVM中,能够依靠服务器的支持向浏览器提供显示内容。
JSP本质上是Servlet,运行时JSP会先被服务器转换为Servlet。
Servlet和JSP最主要的不同点在于,Servlet的应用逻辑是在.java文件中,完全同表现层的html分开;而JSP是Java和HTML杂糅在一起组合.jsp文件。
JSP侧重于视图,Servlet更侧重于逻辑控制,在MVC架构模式中,JSP适合充当视图(view)而Servlet适合充当控制器(controller)。
9、JSP工作原理
JSP是一种Servlet,但是与Servlet的工作方式不太一样。Servlet是先由源代码编译为class文件后部署到服务器下,先编译后部署。而JSP则是先部署后编译。tomcat会在客户端第一次请求JSP文件时把.jsp转换为.java文件(servlet),使用的是HttpJspPage类(Servlet接口的一个子类),再编译为.class文件。.java、.class这2个文件会被临时存放在服务器工作目录里。编译完毕后再运行class文件来响应客户端请求。以后客户端访问login.jsp的时候,Tomcat将不再重新编译JSP文件,而是直接调用class文件来响应客户端请求。第一次访问jsp要转换、编译,速度慢,后续访问此jsp就快了。
10、JSP有哪些内置对象、作用分别是什么
JSP有9个内置对象:
- request:封装客户端的请求,其中包含来自GET或POST请求的参数;
- response:封装服务器对客户端的响应;
- pageContext:通过该对象可以获取其他对象;
- session:封装用户会话;
- application:封装服务器运行环境;
- out:服务器响应的输出流对象;
- config:Web应用的配置对象;
- page:JSP页面本身(相当于Java程序中的this);
- exception:封装页面抛出异常。
11、JSP的三大指令
1、page指令 设置jsp页面的相关信息
实例:<%@ page language=”java” import=”java.util.*” pageEncoding=”UTF-8”%>
- import:等同与import语句,导入多个类
在一个JSP页面中可以给出多个page指令,而且import是可以重复出现的
- pageEncoding:指定当前页面的编码
如果pageEncoding没有指定,那么默认为contentType的值;
如果pageEncoding和contentType都没有指定,那么默认值为iso-8859-1
- contentType:等同与调用response.setContentType(“text/html;charset=xxx”);
如果没有指定contentType属性,那么默认为pageEncoding的值;
如果contentType和pageEncoding都没有指定,那么默认值为iso-8859-1
- errorPage:如果当前页面出现异常,那么跳转到errorPage指定的错误页面。
例如:<%@ page errorPage=”b.jsp” %>
- isErrorPage:上面示例中指定b.jsp为错误页面,需要在b.jsp中使用<%@page isErrorPage=”true”%>指定本页面为错误页面,指定后才能在b.jsp中使用内置对象exception。
- 其它属性
buffer:指定out流的缓冲区大小,默认为8KB
autoFlush:当autoFlush为true时,表示out流缓冲区满时会自动刷新。默认为true
language:当前JSP使用的语言,默认为java,也只能选择java
info:当前JSP的说明信息
isThreadSafe:当前JSP是否是线程安全的(是否只支持单线程访问),默认为false,表示支持并发访问
2、include指令 包含其他文件
被包含的文件可以是JSP文件、HTML文件或文本文件。包含的文件就好像是该JSP文件的一部分,会被同时编译执行。
实例:<%@ include file=”文件相对 url 地址” %>
3、taglib指令 在当前jsp页面中导入第三方的标签库
实例:<%@ taglib uri=”http://java.sun.com/jsp/jstl/core” % prefix=”c” >
需要先添加第三方标签库所需的jar包。
12、JSP的七大动作元素
jsp:include:引入一个文件。
jsp:useBean:寻找或者实例化一个 JavaBean。
jsp:setProperty:设置 JavaBean 的属性。
jsp:getProperty:输出某个 JavaBean 的属性。
jsp:forward:把请求转到一个新的页面。
jsp:plugin:根据浏览器类型为 Java 插件生成 OBJECT 或 EMBED 标记
13、JSP中的四种作用域
- page 当前页面
- request 一个http请求,一个请求可能跨越多个页面(转发)
- session 某个用户与服务器建立的一次会话
- application 包含整个Web应用程序相关的对象和属性,整个web app中都可用
14、Request对象的主要方法有哪些
- setAttribute(String name,Object):设置名字为name的request 的参数值
- getAttribute(String name):返回由name指定的属性值
- getAttributeNames():返回request 对象所有属性的名字集合,结果是一个枚举的实例
- removeAttribute(String name):删除请求中的一个属性
- getCookies():返回客户端的所有 Cookie 对象,结果是一个Cookie 数组
- getCharacterEncoding() :返回请求中的字符编码方式 = getContentLength() :返回请求的 Body的长度
- getHeader(String name) :获得HTTP协议定义的文件头信息
- getHeaders(String name) :返回指定名字的request Header 的所有值,结果是一个枚举的实例
- getHeaderNames() :返回所以request Header 的名字,结果是一个枚举的实例
- getInputStream() :返回请求的输入流,用于获得请求中的数据
- getMethod() :获得客户端向服务器端传送数据的方法
- getParameter(String name) :获得客户端传送给服务器端的有 name指定的参数值
- getParameterNames() :获得客户端传送给服务器端的所有参数的名字,结果是一个枚举的实例
- getParameterValues(String name):获得有name指定的参数的所有值
- getProtocol():获取客户端向服务器端传送数据所依据的协议名称
- getQueryString() :获得查询字符串
- getRequestURI() :获取发出请求字符串的客户端地址
- getRemoteAddr():获取客户端的 IP 地址
- getRemoteHost() :获取客户端的主机名
- getSession([Boolean create]) :返回和请求相关 Session
- getServerName() :获取服务器的名字
- getServletPath():获取客户端所请求的脚本文件的路径
- getServerPort():获取服务器的端口号
15、request.getAttribute()和 request.getParameter()有何区别
1、获取的数据:getParameter()
是获取 POST/GET 传递的参数值(比如表单提交的数据);getAttribute()
是获取setAttribute()放到域中的数据。
2、返回值:getParameter()
返回的是String,需要转换为自己需要的相应类型;getAttribute()
返回的是Object,也需要转换为自己需要的相应类型
3、使用场景:request.getParameter()常用于直接获取http请求中携带的请求参数,比如获取表单表单提交的数据,request.getAttribute()常用于转发时获取前一个页面setAttribute传递的数据。
16、include指令、include动作元素的区别
include指令: JSP可以通过include指令来包含其他文件。被包含的文件可以是JSP文件、HTML文件或文本文件。包含的文件就好像是该JSP文件的一部分,会被同时编译执行。 语法格式如下: <%@ include file="文件相对 url 地址" %>
include动作元素: <jsp:include>
动作元素用来包含静态和动态的文件。该动作把指定文件插入正在生成的页面。语法格式如下: <jsp:include page="相对 URL 地址" flush="true" />
17、如何实现JSP、Servlet的单线程模式
servlet默认是单实例、支持多线程访问的(并发访问),jsp本质是servlet,也一样。
设置为单线程访问:JSP可以通过page指令进行设置, <%@page isThreadSafe="false"%>;
Servlet可以让Servlet实现SingleThreadModel标识接口。
说明:如果将JSP或Servlet设置成单线程工作模式,会导致每个请求创建一个Servlet实例,这种实践将导致严重的性能问题(服务器的内存压力很大,还会导致频繁的垃圾回收),所以通常情况下并不会这么做。
18、实现会话跟踪的技术有哪些
1、使用Cookie
优点: 数据可以持久保存,不占用服务器存储,基于文本的Key-Value,使用简单
缺点: 大小受到限制(每次请求该网站时都会将该网站的cookie放在请求头中),用户可以禁用Cookie功能,由于保存在客户端,有一定的安全风险。
2、session
在所有会话跟踪技术中,session对象是最强大也是功能最多的。当一个用户第一次访问某个网站时会自动创建 HttpSession,每个用户可以访问他自己的HttpSession。可以通过HttpServletRequest对象的getSession方 法获得HttpSession,通过HttpSession的setAttribute方法可以将一个值放在HttpSession中,通过调用 HttpSession对象的getAttribute方法,同时传入属性名就可以获取保存在HttpSession中的对象。与上面三种方式不同的 是,HttpSession放在服务器的内存中,因此不要将过大的对象放在里面,即使目前的Servlet容器可以在内存将满时将HttpSession 中的对象移到其他存储设备中,但是这样势必影响性能。添加到HttpSession中的值可以是任意Java对象,这个对象最好实现了 Serializable接口,这样Servlet容器在必要的时候可以将其序列化到文件中,否则在序列化时就会出现异常。
3、URL 重写
在URL中添加用户会话的信息作为请求的参数,或者将唯一的会话ID添加到URL结尾以标识一个会话。
优点: 在Cookie被禁用的时候依然可以使用
缺点: 必须对网站的URL进行编码,所有页面必须动态生成,不能用预置的URL进行访问。
4、隐藏的表单域
<input type="hidden" name ="session" value="..."/>
优点: Cookie被禁时可以使用
缺点:需要提交表单才能向服务器传递数据,且只能是单向传递(客户端=>服务器)
19、Cookie和Session的区别
Cookie 和 Session都是用来跟踪用户会话的,区别:
1、存储位置:Cookie 数据保存在客户端(浏览器端),Session 数据保存在服务器端。
2、安全性:session存储在服务器上,相对来说安全性更高。 尽量不要把敏感信息存储在 Cookie 中,就算要在cookie中存储敏感信息,也应该存储加密后的信息。服务器拿到加密后的信息后先解密再使用。
3、跟踪用户会话的实现方式
cookie:服务器把cookie(会话信息)存储在客户端(浏览器),每次向该网站发送http请求时,都会在请求头中附带该网站的cookie,请求头的大小有限,所以cookie能存储信息大小是有限的。
session:session(会话信息)存储在服务器上,使用一个唯一的sessionid来唯一标识此session对象,sessionid以cookie的方式保存在客户端,客户端发起http请求时,服务器会自动从cookie中获取sessionid,找到对应的session对象。
4、用户信息的保存时间
cookie:在cookie有效期内,cookie中的用户信息都有效,可以长期保存用户信息。
session:只是在本次会话期间保存会话信息,session超时时会自动删除服务器上的对应的session对象,默认超时时间是30min,即用户30min内没有再次访问服务器,session对象就会被删除。
有时候需要在删除session对象时做一些处理,比如把session中的一些数据以后还要用,需要保存至数据库。那就需要我们写一个监听器来监听session,session销毁时做一些处理:
@WebListener() public class MyListener implements HttpSessionListener { public void sessionCreated(HttpSessionEvent se) { } public void sessionDestroyed(HttpSessionEvent se) { HttpSession session = se.getSession(); //从session中获取数据,存储到数据库中 //...... } }
5、使用场景
Cookie 一般用来保存用户信息 ,比如:
(1)在 Cookie 中保存已经登录过的用户信息,下次访问网站的时候自动登录或自动填写一些字段;
(2)一般的网站都会保持登录,就是说下次你再访问网站的时候不需要重新登录,这是因为用户登录时存放了一个 Token 在 Cookie 中,下次登录的时候只需要根据 Token 值来查找用户即可(为了安全考虑,重新登录一般要将 Token 重写);
session存储的信息大小没有限制,可存储本次会话期间的信息,基于这2个特点,常见的应用有
(1)session常用来存储一次性验证码,将用户提交的验证码与session中正确的验证码比较,验证码30分钟内有效是设置sessionid这个cookie的有效期是30min。
(2)购物车
原文出处:
https://snailclimb.gitee.io/javaguide/#/docs/java/J2EE%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86
在原文基础上进行了部分修改