记录在JavaWeb开发中学习的Servlet相关知识!💯💤
¶Servlet:运行在服务器端的小程序
🕶Servlet是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。
¶配置Servlet
¶1. 在web.xml中配置
<!--配置Servlet -->
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>cn.sucre.servlet.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/MyServlet</url-pattern> 虚拟路径,用于浏览器中访问
</servlet-mapping>
¶⭐️2. Servlet3.0支持注解配置。
在类上使用@WebServlet注解,进行配置:@WebServlet({"资源路径"})
¶3. 执行原理
-
当服务器接受到客户端浏览器的请求后,会解析请求的URL路径,获取要访问的Servlet的资源路径。
-
查找web.xml文件,查找对应的
<url-pattern>
内容,与资源路径匹配。 -
如果匹配成功,则获取对应的
<servlet-class>
的类名。 -
服务器端tomcat通过类名反射class.forName()将字节码文件加载进内存,并使用class.newInstance()创建Servlet对象。
-
执行该Servlet子类中的方法实现业务功能,如service()。
¶Servlet的生命周期:
- 默认情况下,第一次被访问时,执行
init()
方法,Servlet被创建,该方法只执行一次。- Servlet的
init()
方法只执行一次,说明Servlet在内存中只存在一个对象,即Servlet是单例的,当多个用户同时访问时,可能存在线程安全问题。- 解决:尽量不要在Servlet类中定义成员变量。即使定义了成员变量,也不要对修改值,可以在函数中定义局部变量。
- Servlet的
- Servlet通过调用
destroy()
方法终止,一般用于释放资源,只执行一次。Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
¶Servlet-GenericServlet-HttpServlet
-
体系结构
Servlet – 接口
|
GenericServlet – 抽象类
|
HttpServlet – 抽象类 -
GenericServlet:实现了 Servlet 接口,并且对其中的 init() 和 destroy() 和 service() 提供了默认实现。如果继承这个类的话,必须重写 service() 方法来对处理请求。
-
HttpServlet:进一步继承并封装了 GenericServlet,使得使用更加简单方便,使用 HttpServletRequest 和 HttpServletResponse扩展了 Http 的内容,这两个类分别是 ServletRequest 和 ServletResponse 的子类。HttpServlet 中对原始的 Servlet 中的方法都进行了默认的操作,不需要显式的销毁初始化以及 service(),在 HttpServlet 中,自定义了一个新的 service() 方法,其中通过
getMethod()
方法判断请求的类型,从而调用 doGet() 或者 doPost() 处理 get,post 请求。使用该类时只要继承 HttpServlet,然后重写 doPost() 或者 doGet() 方法处理请求即可。
¶浏览器的请求消息格式-Request对象
¶1. 请求消息格式
-
浏览器请求网页时将向服务器发送请求消息,消息格式包括:
-
请求行: 请求方式 请求url 请求协议/版本 如: GET /login.html HTTP/1.1
-
请求头:包含浏览器告诉服务器的相关信息,常用的有User-Agent和Referer
-
请求空行:用于POST方法中隔离请求头和请求体,GET方法中不存在请求体
-
请求体:用于POST请求中封装请求消息的请求参数
-
示例:
POST /login.html HTTP/1.1 //请求行 //请求头 Host: localhost User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Referer: http://localhost/login.html Connection: keep-alive Upgrade-Insecure-Requests: 1 //请求空行 username=zhangsan //请求体
-
¶2. HttpServletRequest对象:用来获取请求消息
-
获取请求行数据:
浏览器输入:http://localhost:8080/MyProject/sucre/main/MyRequest
getContextPath()
获取站点的根路径,也就是项目名MyProject。getRequstURI()
获取请求的统一资源标志符:MyProject/sucre/main/MyRequest。getRequestURL()
获取请求的统一资源定位符,http://localhost:8080/MyProject/sucre/main/MyRequest。
-
获取请求体数据
getHeader(String name)
:通过请求头的名称获取对应的值
-
获取请求体数据
只有POST方式有请求体,在POST的方式中将请求体封装成流对象。首先要获取流对象,其次从流对象中获取数据getReader()
:获取字符输入流,只能操作字符数据getInputStream()
:获取字节输入流,可以操作所有类型数据
-
通用获取参数,不论GET和POST都可用
String getParameter(String name)
:根据参数名称获取参数值String[] getParameterValues(String name)
:根据参数名称获取参数值的数组Enumeration<String> getParameterNames()
:获取所有请求的参数名称Map<String,String[]> getParameterMap()
:获取所有参数的map集合
¶服务器的响应消息格式-Response对象
¶1. 响应消息格式
-
服务器向客户端浏览器发送响应消息,消息格式主要包括:
-
响应行: 协议/版本 响应状态码 状态码描述
- ⭐️状态码:
- 1xx:服务器接受了客户端消息,但没有接受完成,等待一段时间后,发送该类状态码。
- 2xx:成功。代表:200。
- 3xx:重定向。代表:302(重定向),304(访问缓存)。
- 4xx:客户端错误。404(请求路径没有对应的资源), 405:请求方式没有对应的doXxx方法。
- 5xx:服务器端错误。代表:500(服务器内部出现异常)
- ⭐️状态码:
-
响应头:
-
格式:头名称: 值
-
常见的响应头:Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
-
-
响应空行
-
响应体:传输的数据
-
¶2. HttpServletResponse对象:用来设置响应消息
-
设置响应行的状态码:
setStatus(int sc)
-
设置响应头数据:
setHeader(String name, String value)
-
设置响应体:
- 步骤:
1. 获取输出流
+ 设置编码防止中文乱码:response.setContentType("text/html;charset=utf-8");
+ 字符输出流:PrintWriter getWriter()
+ 字节输出流:ServletOutputStream getOutputStream()
2. 使用输出流将数据输出到浏览器
- 步骤:
¶ServletContext对象
- 代表整个web应用,可以和程序的容器(服务器)来通信
- 使用
request.getServletContext()
或者this.getServletContext();
获取该对象 - 功能:
- 获取MIME类型:
String getMimeType(String file)
- 域对象:共享数据
setAttribute(String name,Object value),getAttribute(String name),removeAttribute(String name)
- 获取文件的真实(服务器)路径:
String getRealPath(String path)
- 获取MIME类型:
¶⭐️会话技术
☁️一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。会话跟踪技术是Web程序中用于跟踪用户整个会话的技术。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接,这就意味着服务器无法从连接上跟踪会话。因此引入Cookie和Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。
¶📰Cookie
识别返回用户包括三个步骤:
- 服务器脚本向浏览器发送一组 Cookie。例如:姓名、年龄或识别号码等。
- 浏览器将这些信息存储在本地计算机上,以备将来使用。
- 当下一次浏览器向 Web 服务器发送任何请求时,浏览器会把这些 Cookie 信息发送到服务器,服务器将使用这些信息来识别用户。
- 实现原理:基于响应头中的set-cookie字段以及请求头中的cookie字段实现。
- set-cookie字段信息例如:
Set-Cookie: name=xyz; expires=Friday, 04-Feb-07 22:03:38 GMT; path=/; domain=sucre.com
其中,expires 字段是一个指令,告诉浏览器在给定的时间和日期之后"忘记"该 Cookie; - 对应请求头中的cookie字段为:
Cookie: name=xyz等
。
- set-cookie字段信息例如:
- cookie的使用
- 在服务器端创建Cookie对象
new Cookie(String name, String value)
- 在服务器端设置生存周期
cookie.setMaxAge(60*60*24);
- 在服务器端通过response发送Cookie
response.addCookie(Cookie cookie)
- 在客户端获取Cookie
Cookie[] request.getCookies()
- 在服务器端创建Cookie对象
- 在默认情况下,浏览器关闭后,Cookie将会销毁,使用
setMaxAge(int second)
可以设置Cookie保存时间。- second为正数,表示Cookie存储在本地硬盘中的时间;
- second为负数为默认情况;
- second为0表示删除Cookie信息。
setPath(String path)
用于设置Cookie的获取范围。- 默认情况下,设置为当前的虚拟目录;
- 如果要共享,则可以将path设置为"/",表示根目录下所有项目共享该Cookie。
setDomain(String path)
如果设置一级域名相同,那么多个服务器之间Cookie可以共享。- 例如,setDomain(".baidu.com"),那么tieba.baidu.com和news.baidu.com中Cookie可以共享。
- Cookie的作用和特点
- Cookie存储数据在客户端浏览器。
- 浏览器对于单个Cookie的大小有限制(4kb)以及对同一个域名下的总cookie数量也有限制(20个)。
- Cookie一般用于存储少量的不太敏感的数据。
- 在不登录的情况下,Cookie用于完成服务器对客户端的身份识别。
¶📃Session
-
Session在一次会话的多次请求间共享数据
-
实现依赖于Cookie
- 在第一次访问服务器时,服务器内存中没有Session对象,创建该Session对象。
- 向客户端发送相应数据时,set-cookie字段中包含
JSESSIONID
,即为服务器内存中该Session对象的id。 - 客户端将Cookie信息存储到浏览器内部,下次访问服务器时,Cookie中将包含该
JSESSIONID
值,保证了多次请求中共享相同的Session对象。
-
客户端浏览器关闭后,服务器不关闭,则会话已经结束,再次打开浏览器后两次获取的Session将不相同。
- 可以创建Cookie,设置键JSESSIONID的存活时间
(setMaxAge)
,使其持久化就可保证两次相同。
- 可以创建Cookie,设置键JSESSIONID的存活时间
-
Session的销毁
- 服务器关闭
- Session对象调用
invalidate()
- 默认失效时间为 30分钟,在tomcat设置中可以配置
-
⭐️如果客户端禁用了Cookie,通常有两种方法实现session而不依赖cookie。
-
URL重写。就是把sessionId直接附加在URL路径的后面。
-
表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。
-
-
⭐️session与Cookie区别
- session存储在服务器端,cookie存储在客户端。
- session没有数据大小限制,cookie有限制,单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
- session相对安全,cookie相对不安全,可以分析存放在本地的COOKIE并进行COOKIE欺骗。
- session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用cookie。
- 生存周期不同。,session是IE启动到IE关闭,浏览器页面一关 ,Session就消失。Cookie是预先设置的生存周期,或永久的保存于本地的文件。
¶💊常见问题
-
重定向方式
response.setStatus(302);
response.setHeader("location", url);
response.sendRedirect("url");
-
⭐️重定向redirect与转发forward的比较
-
重定向的特点:redirect
- 地址栏发生变化
- 重定向可以访问其他站点(服务器)的资源
- 重定向是两次请求。不能使用request对象来共享数据
-
转发的特点:forward
- 转发地址栏路径不变,问当前服务器下的资源
- 转发是一次请求,可以使用request对象来共享数据
-
关于路径是否要加虚拟目录
规则:
- 给客户端浏览器使用:需要加虚拟目录 /
- 给服务器使用:不需要加虚拟目录,如转发路径
- 建议使用
request.getContextPath()
动态获取虚拟目录