前言
在之前我们已经学过Servlet初级入门的一部分内容了,今天我们继续来学习Servlet,但是你如果对Servlet还不了解的话那么建议你先去看一下我之前写过的入门的部分。
传送门:【Servlet入门】一篇文章让你快速入门
传送门:【JSP入门】只知道HTML却不知道JSP?
接下来我们就正式来学习今天的内容吧!
请求与响应
我们之前学过Servlet最主要的作用就是处理客户端的请求,并向客户端作出响应。那么这里的请求与响应到底是什么呢?
大家可能只知道请求就是请求,响应就是响应,其他的可能一无所知或者很乱。那么今天我们就一起来深入了解学习一下请求与响应吧。
Get与Post请求
(1)GET和POST是什么?
是HTTP协议中的两种发送请求的方式。
(2)请求方式是什么?
浏览器向服务器发送数据的方式。
(3)那 HTTP又是什么 ?
HTTP是关于数据如何在万维网中如何通信的协议。
(4)那么Get与Post都是请求方式,它们又有什么区别呢?
GET请求:
1.默认情况下所有的请求都是GET请求。
2.采用路径传参,即通过路径携带参数。
3.传参过程中参数可见,隐私性差。
4.因为路径大小有限制,所以能够传递的参数很小。
POST请求:
1.因为默认情况下都是GET请求,所以我们使用POST请求时候需要写上method = "post"。
2.采用实体内容传参,即:请求体。
3.在传参的过程中,路径上(URL)看不到参数,隐私性好。
4.实体内容专门用于传递数据,因此大小不受限制。
(5)那我们什么时候该选用GET,什么时候又该选用POST呢?
一般来说:
(1)浏览器向服务器索取(查询)数据用GET请求 。
(2)浏览器向服务器提交(保存)数据用POST请求。
请求的结构
HTTP请求结构主要包含三部分:请求行,请求头,请求体。
(1)请求行:标明了请求方法,请求URL,HTTP协议及版本。
(2)请求头:请求头基本都是一些辅助信息,为程序处理提供了一些额外的数据支持。
下面是一些常见的请求头字段及含义:
Accept:浏览器可接受的MIME类型,也就是代表着浏览器希望接收什么样的文件
Accept-Charset:浏览器可接受的字符集
Accept-Encoding:浏览器能够进行解码的数据编码方式
Accept-Language:浏览器所接受的语言
Authorization:授权信息
Content-Length:表示请求消息正文的长度
Host:客户机通过这个头告诉服务器,想访问的主机名
If-Modified-Since:客户机通过这个头告诉服务器,资源的缓存时间
Referer:表明客户机是从哪里来的
User-Agent:User-Agent头域的内容包含发出请求的用户信息,浏览器类型
Pragma:指定“no-cache”值表示服务器必须返回一个刷新后的文档,即使它是代理服务器而且已经有了页面的本地拷贝。
Connection:处理完这次请求后是否断开连接还是继续保持连接。
UA-Pixels,UA-Color,UA-OS,UA-CPU:由某些版本的IE浏览器所发送的非标准的请求头,表示屏幕大小、颜色深度、操作系统和CPU类型。
(3)请求体:请求体主要是保存请求的一些参数,又因为Get请求是把参数都放在URL中进行传递的,所以说Get请求没有请求体。只有Post请求才有请求体。
示例:
接下来我们就写一个简单的Servlet来测试观察一下它们的结构吧!
首先写一个简单的Servlst,来处理请求处理:
mport java.io.IOException; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse;
i
@WebServlet("/request")//映射地址 public class ResquestServlet extends HttpServlet { private static final long serialVersionUID = 1L; //处理Get请求 protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { response.getWriter().println("This is get method"); } //处理Post请求 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter().println("This is post method"); } }
在HTML中写一个表单来接受请求参数
Insert title here
这里没有写请求方式所以默认的应该是Get请求,我们进入浏览器看效果
输入URL进行访问
输入测试数据,并且按下F12进入开发者模式进行监控
点击提交
这个是Get请求我们换位Post请求试试,该请求方式只需要:
Insert title here
然后重新发布这个项目,重新输入测试数据
点击提交
经过上面的测试相信我们对请求的印象已经进一步加深了。
响应的结构
HTTP响应结构主要包含三部分:响应行,响应头,响应体
(1)响应行:报文协议及版本,状态码以及状态描述
(2)响应头:HTTP请求头提供了关于请求,响应或者其他的发送实体的信息。
常见的响应头字段含义:
Allow:服务器支持哪些请求方法(如GET、POST等)。
Content-Encoding:文档的编码(Encode)方法。
Content-Length:表示内容长度。只有当浏览器使用持久HTTP连接时才需要这个数据。
Content- Type:表示后面的文档属于什么MIME类型
Expires:告诉浏览器把回送的资源缓存多长时间,-1或0则是不缓存
Server:服务器通过这个头告诉浏览器服务器的类型
WWW-Authenticate:客户应该在Authorization头中提供什么类型的授权信息
(3)响应体:是服务器返回给客户端的文本信息(如HTML网页)。
示例:
我们继续使用之前请求结构中写的Servlet来做演示,对比一下响应体结构。
启动Servlet,在浏览器中输入样例并且按下F12进行监控
点击提交
查看响应体结构
ContentType的作用
ContentType:决定浏览器将以什么形式来对响应体进行处理
经常看到一些网页点击的结果是下载到的一个文件或一张图片,这就是ContentType不同而造成的结果。
常见的媒体格式类型如下:
请求转发与重定向
之前我们对Servlet的学习都是对单个的Servlet进行演示操作,但是我们在实际场景中更多用到的是多个Servlet的联合使用。
我们在多个Servlet(JSP)之间跳转有两种方式:请求转发,响应重定向。
接下来我们分别对这两种方式进行总结学习
请求转发
请求转发属于转发,也是服务器跳转,相当于方法调用,在执行当前文件的过程中转向执行目标文件,两个文件(当前文件和目标文件)属于同一次请求。
转发核心语句:
request.getRequestDispatcher(URL地址).forward(request, response)
请求转发特点:
转发前后页共用一个request,可以通过此来传递一些数据或者session信息,request.setAttribute()和request.getAttribute()。
在前后两次执行后,地址栏不变,仍是当前文件的地址。
不能转向到本web应用之外的页面和网站,所以转向的速度要快。
示例:
接下来我们使用Servlet对请求转发进行演示
首先写一个Servlet模拟登录页面
进入这个Servlet之后,首先应该会在控制台上打印“用户登陆成功”的字样,然后设置了"username"属性值,最后会转发请求到映射地址为"/direct/index"的Servlet。
import java.io.IOException; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; public class CheckLoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("用户登陆成功"); //设置自定义属性("属性名(字符串)","属性值(object对象)") request.setAttribute("username", "admin"); //实现请求转发的功能(相同的请求) request.getRequestDispatcher("/direct/index").forward(request, response); } 这个Servlet的映射地址为"/direct/index",就是刚才Servlet该跳转到的页面。 在这个Servlet中首先会对请求对象调用"username"属性,然后在页面上打印出来。 import java.io.IOException; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; public class IndexServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response) throws ServletException, IOException { String username = (String)request.getAttribute("username"); response.getWriter().println("This is index page! current username is " + username ); } }
上面都是预计的效果,我们来具体试验一下是不是如我们想象的那样。
如图我们可以看到这是两个不同的Servlrt
接下来我们在浏览器中输入第一个Servlet的URL进行验证转发请求能否成功
如图所示是成功的,最后在网页中url仍然是第一个Servlet的url但是展示出来的页面是第二个Servlet的页面,而且在控制台也成功输出了“用户登陆成功”的字样说明请求转发是成功了的。
又是因为请求转发虽然启动了两个Servlet但是我们用的是同一个请求,所以我们可以在第一个Servlet中设置自定义属性,在第二个Servlet中仍然还可以调用这个属性。
响应重定向
重定向是服务器通知浏览器去访问另一个地址,即再发出另一个请求。
当你访问时,你会发现浏览器地址栏中的URL会变,这就是重定向了。
实现重定向核心语句:
response.sendRedirect(URL地址);
处理流程:
客户端发送请求,Servlet做出业务逻辑处理。
Servlet调用response.sendReadirect()方法,把要访问的目标资源作为response响应头信息发给客户端浏览器。
客户端浏览器重新访问服务器资源xxx.jsp,服务器再次对客户端浏览器做出响应。
示例:
我们对刚才的Servlet进行微改,继续来演示一下响应重定向
进入这个Servlet之后,首先应该会在控制台上打印“用户登陆成功”的字样,然后设置了"username"属性值,最后会重定向到映射地址为"/direct/index"的Servlet。
import java.io.IOException; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; public class CheckLoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("用户登陆成功"); //设置自定义属性("属性名(字符串)","属性值(object对象)") request.setAttribute("username", "admin"); //响应重定向需要增加contextPath(/request-struct) response.sendRedirect("/request-struct/direct/index"); } }
这个Servlet的映射地址为"/direct/index",就是刚才Servlet重定向到的页面。
在这个Servlet中首先会对请求对象调用"username"属性,然后在页面上打印出来。
import java.io.IOException; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; public class IndexServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response) throws ServletException, IOException { String username = (String)request.getAttribute("username"); response.getWriter().println("This is index page! current username is " + username ); }
它们仍然是被放在两个Servlet中,接下来我们在浏览器中输入url进行演示
因为发生响应重定向的时候原来的请求会被销毁,来产生新的请求去访问新的url,所以原来请求里面的username属性在新的Servlet中不存在。
请求转发与响应重定向的原理
请求转发:
响应重定向:
Servlet的核心对象
除了要学习Servlet的一些基本操作之外,我们还得知道Servlet的一些核心对象。接下来就让我们一起来学习了解一下Servlet有哪些核心对象吧。
浏览器Cookie对象
cookie是唯一一个可以将键值对数据保存在浏览器硬盘中的一种数据。
那Cookie又有哪些特点呢?
(1)Cookie是浏览器保存在本地的文本内容
(2)Cookie常用于保存登陆状态,用户资料等小文本
(3)Cookie具有时效性,Cookie内容会伴随请求发送给Tomcat
(4)Cookie数据和浏览器绑定在一起,不能跨越浏览器
cookie的有效期默认是关闭浏览器为止,但是我们也可以在Servlet中对其进行设置。
示例:
接下来我们写一个Servlet模拟用户登录来对其进行演示。
在这个Cookie中我们手动增加cookie,并且设置这个cookie的有效期。
import java.io.IOException; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.Cookie; public class ImoocLoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response) throws ServletException, IOException { System.out.println("用户登陆成功"); Cookie cookie = new Cookie("user", "admin"); //手动设置cookie有效期为7天 cookie.setMaxAge(60 * 60 * 24 * 7); response.addCookie(cookie); response.getWriter().println("login success"); } }
我们再写一个Servlet来对刚才添加的cookie进行调用查看。
import java.io.IOException; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; /** * Servlet implementation class ImoocIndexServlet */ public class ImoocIndexServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //request.getCookies()用于获取所有的Cookie Cookie[] cs = request.getCookies(); for(Cookie c : cs) { //向控制台输出cookie的信息 System.out.println(c.getName() + ":" + c.getValue()); } } }
接下来在浏览器进行演示:
同时我们使用F12进行监控也可以在请求头中找到这个Cookie的自定义属性
Session会话对象
Session技术是将数据存储在服务器端的技术,会为每个客户端都创建一块内存空间存储客户的数据,但客户端需要每次都携带一个标识ID去服务器中寻找属于自己的内存空间。所以说Session的实现是基于Cookie,Session需要借助于Cookie存储客户的唯一性标识JSESSIONID。
那么Session又有哪些特征呢?
(1)Session(用户会话)用于保存与“浏览器窗口”对应的数据。
(2)Session的数据存储在Tomcat服务器的内存中,具有时效性。
(3)Session通过浏览器Cookie的Sessionid值提取用户数据。
Session的基本操作
获得Session对象:
HttpSession session = request.getSession();
Session也是存储数据的区域对象,所以Session对象也具有如下三个方法:
session.setAttribute(String name,Object obj); //存 session.getAttribute(String name); //取 session.removeAttribute(String name); //删除
Session对象的生命周期
创建:第一次执行request.getSession()时创建
销毁:
服务器(非正常)关闭时
session过期/失效(默认30分钟)自动过期
示例:
获取Session对象并且在其中添加自定义属性,然后请求转发到新的Servlet
public class SessionLoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("用户登陆成功"); //获取用户会话Session对象 HttpSession session = request.getSession(); String sessionId = request.getRequestedSessionId(); System.out.println(sessionId); session.setAttribute("name", "张三"); request.getRequestDispatcher("/session/index").forward(request, response); } }
请求转发到下面这个Servlet中去,获取属性。
public class SessionIndexServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); String sessionId = request.getRequestedSessionId(); System.out.println(sessionId); String name = (String)session.getAttribute("name"); response.setContentType("text/html; charset = utf-8"); response.getWriter().println("这是首页,当前用户为:" + name); } }
使用浏览器进行试验
我们对第一个Servlet进行修改,使用请求重定向
public class SessionLoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("用户登陆成功"); //获取用户会话Session对象 HttpSession session = request.getSession(); String sessionId = request.getRequestedSessionId(); System.out.println(sessionId); session.setAttribute("name", "张三"); response.sendRedirect("/request-struct/session/index"); //request.getRequestDispatcher("/session/index").forward(request, response); } }
这里特别在强调一下Session技术是将数据存储在服务器端的技术
Session原理:
Cookie 和Session的区别:
(1)Cookie数据存放在客户的浏览器上,Session数据放在服务器上。
(2)Cookie不是很安全,别人可以分析存放在本地的Cookie并进行Cookie欺骗,考虑到安全应当使用Session。
(3)Session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用Cookie。
(4)单个Cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个Cookie。
(5)所以一般来说:
将登陆信息等重要信息存放为Session;
其他信息如果需要保留,可以放在Cookie中;
servletContext对象
ServletContext用来存放全局变量,每个Java虚拟机每个Web项目只有一个ServletContext,这个ServletContext是由Web服务器创建的,来保证它的唯一性。由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象通讯。ServletContext对象通常也被称之为Context域对象。
servletContext对象:服务器启动时会自动创建该对象,服务器关闭时自动销毁该对象,服务器运行期间,有且仅有一个servletContext对象。在代码中可以通过方法获取该唯一对象。
总结一下servletContext对象有什么特点:
(1)ServletContent(Servlet上下文对象),是Web应用全局对象
(2)一个Web应用只会创建一个ServletContent对象
(3)ServletContent随着Web应用启动而自动创建
ServletContext 对象的具体使用范围:
不同的servlet之间
不同的页面之间
不同的servlet和页面之间
不同的浏览器之间
不同的计算机之间
总结:服务器不关闭,数据可以在任何位置使用
web.xml常用配置
web.xml是web项目的配置文件,一般的web工程都会用到web.xml来配置,方便大型开发。web.xml主要用来配置Filter,Listener,Servlet等。但是web.xml并不是必须的,一个web工程可以没有web.xml文件。
web容器的加载顺序ServletContext -> context-param -> listener -> filter -> servlet。并且这些元素可以配置在文件中的任意位置,不会因为filter在web.xml文件中写在listener前面就先加载filter。
加载过程顺序如下:
(1)启动一个WEB项目的时候,WEB容器会去读取它的配置文件web.xml,读取和两个结点。
(2)紧急着,会创建一个ServletContext(servlet上下文),这个web项目的所有部分都将共享这个上下文。
(3)容器将转换为键值对,并交给servletContext。
(4)容器创建中的类实例,创建监听器。
下面是web.xml中的常用标签:
1、web-app
xml文件的根标签,用于声明命名空间、schema约束等。
xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee version="3.0">
2、icon
当使用GUI(Graphic User Interface)工具时,用于指定web应用的图标,拥有两个子标签,只支持gif和jpg格式。
小图标为 16*16像素
大图标为 32*32像素
/images/xxx.jpg
/images/xxx.jpg
3、display-name
当使用GUI(Graphic User Interface)工具时,用于指定web应用的名称。
xxxxxxxxxxxxxxx
4、description
用于描述web应用的相关信息
xxxxxxxxxxxxxxx
5、distributable
如果在web.xml中指定该标签,则表示应用程序已经可以部署在分布式的servlet容器中了,即此应用程序可以在多个实例之间分发servlet及会话
只要看web.xml中是否出现该标签,就可以判断web项目是否具有分布式的功能
6、context-param
初始化参数,应用与整个web项目,有两个子标签:
可以理解为map中的key
可以理解为map中的value
在容器启动时,会创建一个 ServletContext(上下文对象,也可以理解为web应用环境对象),然后会去读取 context-param 标签,容器会将 param-name 和 param-value 的值以 key-value 的形式set进ServletContext中。
在servlet中,通过 this.getServletContext().getInitParameter("key") 来获取值value。
key
value
7、filter
过滤器,可以对目标资源的请求和响应进行过滤,主要用于过滤字符编码,当然你可以自定义过滤器,来处理自己的业务逻辑:
过滤器名称,与下文提到的 filter-mapping 标签的 filter-name 相对应
过滤器类的完整类名
filter类的初始化参数,有两个子标签
可以理解为map中的key
可以理解为map中的value
在filter中,通过 request.getServletContext().getInitParameter("key"); 来获取值value,注意:此处的request为 ServletRequest
8、filter-mapping
过滤器的映射,与 filter 标签搭配使用,且必须先配置 filter 再配置 filter-mapping,有两个子标签:
过滤器名称,与上文提到的 filter 标签的 filter-name 相对应
映射路径,所有符合该模式的URL都会应用于该过滤器,Spring提供的字符编码过滤器
encodingFilter org.springframework.web.filter.CharacterEncodingFilter encoding UTF-8 forceEncoding false encodingFilter *.do
9、listener
监听器,可以用来监听客户端的请求,服务端的操作等,常用的监听器有:
ServletContext 监听器:
ServletContextListener用于对整个Servlet上下文在 创建、销毁 时进行监听
ServletContextAttributeListener用于对Servlet上下文属性的 增删改 操作进行监听
Session 监听器:
HttpSessionListener用于对Session在 创建、销毁 时进行监听
HttpSessionAttributeListener用于对Session属性的 增删改 操作进行监听
Request 监听器:
ServletRequestListener用于对Request在 创建、销毁 时进行监听
ServletRequestAttributeListener用于对Request属性的 增删改 操作进行监听
10、servlet
用来声明一个servlet数据,常用的有以下几个子标签:
servlet名称,与下文提到的 servlet-mapping 标签的 servlet-name 相对应
servlet类的完整类名
servlet类的初始化参数,有两个子标签
可以理解为map中的key
可以理解为map中的value
当web应用启动时,用于指定加载servlet的顺序
当值大于等0 时,web容器会按照值大小, 从小到大顺序加载
当值为负或未定义时,web容器会在首次访问该servlet时加载它
在servlet中,通过 this.getInitParameter("key") 来获取值value
11、servlet-mapping
servlet的映射,与 servlet 标签搭配使用,且必须先配置 servlet 再配置 servlet-mapping,有两个子标签
servlet名称,与上文提到的 servlet 标签的 servlet-name 相对应
映射路径,使用该路径可以访问到想要访问的 servlet,可自行定义
myServlet com.lala.servlet.Login key value myServlet /servlet/abc
在页面上,通过简单的form表单就可以访问到对应的servlet
12、session-config
设置 session 超时时间,单位为分钟
13、welcome-file-list
设置欢迎页,若不设置则会默认访问 WEB-INF 下的 index.html 页面
index1.html
index2.html
index3.html
当访问项目时,容器会按顺序依次搜索页面,如果有对应的页面存在,则显示该页面,若都没匹配到,则会报404错误
14、error-page
设置错误页,当404或500或指定异常时可以跳转至指定页面,有三个子标签:
错误码,例如 404, 500等
异常类型,例如 java.lang.NullPointerException(空指针异常)
用来设置错误页
404 /error_404.html java.lang.NullPointerException /error_null.html
结语
到这里就是今天Servlet进阶的所有内容了,首先恭喜你能够看完真的特别长。看完之后如果不去练习的话是很快就忘记的,所以大家一定要记得自己动手去练习,去探索每一个知识点。