个人主页:兜里有颗棉花糖
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创
收录于专栏【Servlet】
本专栏旨在分享学习Servlet的一点学习心得,欢迎大家在评论区交流讨论💌
目录
- 一、HttpServlet
- 二、HttpServletRequest
- 核心方法
- 代码示例1
- 如何获取query string和body(form格式)中的数据
- 获取body(json格式)中的数据
- jackon依赖的导入
- 三、HttpServletResponse
- setStatus
- setHeader
- 构造重定向响应
- 返回一个html界面
API就是一组类和方法,本文中我们学习Servlet API的三个类:HttpServlet
、HttpServletRequest
、HttpServletResponse
。
一、HttpServlet
HttpServlet
是我们编写Servlet代码用来的核心类,通过继承这个类并重写其中的方法,然后Tomcat去调用其中的代码逻辑。可以这样理解:我们这里写的代码(重写的方法)并不是我们自己手动调用手动执行的,而是将我们写地代码交给Tomcat,让Tomcat帮助我们执行调用这些代码。
核心方法如下:
Init方法
:在webapp被加载的时候会调用此方法,可以使用该方法进行初始化操作。destroy方法:
在webapp被销毁(或Tomcat结束)的时候执行destroy方法,可以使用该方法进行收尾工作。注意:该方法不能保证一定会被调用到。
这里分为两种情况。
第一种情况:通过8005端口给Tomcat发起一个特殊的请求,然后Tomcat就关闭了(这种情况可以调用到destroy方法)。
第二种情况:直接杀死Tomcat进程,比如说通过任务资源管理器直接结束Tomcat任务进程,此时就无法执行destroy方法。
实际开发中第二种情况占多数(尤其是在Linux中),这就提醒我们不能依赖destroy方法,因为该方法不一定被调用到。
service方法:
每次收到请求会执行service方法,处理每个请求。一般会使用doXXX方法
来替代service方法
。
对于上述方法,浏览器只能构造Get方法,对于其它的方法浏览器并不方便构造。如果想要构造其它的请求方法,我们可以使用ajax或者postman。
实际开发中用到的最多的是Get和Post。
二、HttpServletRequest
HttpServletRequest
是Java Servlet API
提供的接口之一,用于表示客户端的HTTP请求。
一个HTTP请求中都有哪些信息都会在HttpServletRequest类中进行体现。当Tomcat接收到Http请求时,它将解析请求并将相关的信息填充到HttpServletRequest对象中,从而使开发人员可以方便地获取和处理这些信息。
核心方法
下图是HttpServletRequest的方法:
URI和URL
:URI是唯一资源标识符,URL是唯一资源定位符;URI用来区分不同的资源,而URL就是用来区分不同资源的一种方式。我们可以这样理解,URL是URI的实现方式。实际开发中一般会混着用。
Enumeration getParameterNames()
和String getParameter(String name)
我们直到请求中可以通过一些方式把自定义数据传递到服务器中,有两种方式:
第一种方式:query string
,query string
是键值对结构的数据,Tomcat收到请求后就会把query string解析成Map这样的键值对。然后使用getParameter
就可以根据key获取到value;而getParameterNames
是拿到所有的key。
第二种方式:body
:如果是通过post form表单的形式提交表单的话,此时body中也是键值对的形式(和query string一样)。
getParameterValues方法
:即一个key涉及到多个value。
Enumeration getHeaderNames()
和String getHeader(String name)
:获取到请求头中的键值对,Tomcat收到请求后也会把请求头解析成Map。getHeader
是通过key拿到指定的value;而getHeaderNames
是拿到所有的key。
代码示例1
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
@WebServlet("/request")
public class RequestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 下行代码就是为了显示告诉浏览器,浏览器拿到的内容是html
resp.setContentType("text/html");
// 调用req的各个方法,把得到的结果汇总到一个字符串中,然后统一返回到桌面上
StringBuilder respBody = new StringBuilder();
// 由于下面的内容在浏览器是按照html展示的,\n在浏览器上并不是换行,所以使用<br>来表示换行
// 获得HTTP请求协议的版本号
respBody.append(req.getProtocol());
respBody.append("<br");
// 获取HTTP请求方法
respBody.append(req.getMethod());
respBody.append("<br>");
// 获取请求的URI
respBody.append(req.getRequestURI());
respBody.append("<br>");
// 将req.getContextPath()返回的上下文路径添加到respBody中
respBody.append(req.getContextPath());
respBody.append("<br>");
// 返回的查询字符串添加到respBody字符串中的代码
respBody.append(req.getQueryString());
respBody.append("<br>");
// 拼接header
Enumeration<String> headers = req.getHeaderNames();
while(headers.hasMoreElements()) {
String header = headers.nextElement();
respBody.append("<br>");
respBody.append(header + ": " + req.getHeader(header));
}
resp.getWriter().write(respBody.toString());
}
}
跑起来之后如下图:
如何获取query string和body(form格式)中的数据
如何获取query string中的数据
代码如下:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/parameter")
public class ParameterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println("username=" + username);
System.out.println("password=" + password);
resp.getWriter().write("OK");
}
}
运行结果如下:
如何获取中body的数据
由于body有很多种格式,所以这里就拿form表单格式(和query string格式一样是键值对的格式)来举例。这里我们让客户端发送一个Post请求,同时使用form格式的数据在body中把数据进行传递。
代码如下:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/parameter2")
public class Parameter2Servlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println("username=" + username);
System.out.println("password=" + password);
resp.getWriter().write("OK");
}
}
结果如下:
总结:使用
getParameter()
方法可以用于获取query string
中的value值以及form表单
中的value值。
所以我们完全可以使用一种代码来获取query string
中的value值以及form表单
中的value值(doPost()方法用于处理POST请求,获取表单中的参数值。doGet()方法用于处理GET请求,获取查询字符串中的参数值)。
注意:上述两份代码的servlet path是不能重复的,否则会出现404报错。
获取body(json格式)中的数据
再来回顾一下json格式:
{
username:lisi;
password:9521;
}
json格式虽然在开发中也是经常会用到的一种格式,但是Servlet自身不能够对json格式的数据进行解析。解决方式是引入第三方库来进行解析(将键值对还原成Map这种key value的形式)。
解析json格式的第三方库也是有很多的,我们这里使用jackon
来对json进行解析。
jackon依赖的导入
然后这里选择一个版本(建议选旧版本)
然后复制粘贴到pom.xml
文件中去。
注意是复制粘贴到<dependencies></dependencies>
标签中(一个dependencies标签
可以包含多个依赖)。
最后刷新
一下即可。
jackon依赖
引入的是一个类两个方法:类是ObjectMapper
,用于将Java对象转换为JSON格式的字符串,也可以将JSON字符串转换回相应的Java对象。
现在我们回归正题:获取body(json格式)中的数据(即客户端中的body按照json格式进行传输)。
readValue
方法选择上图中的版本。该方法的作用就是把json格式的字符串解析成Java对象。
第一个参数(InputStream src
)可以看到是一个流对象,表示json从哪里来。
第二个参数(JavaType valueType
)用于指定一个类型:即json格式的字符串需要解析成什么类型的Java对象(这是一个将json格式的字符串映射成java对象的过程)。
关于第二个参数:我们需要定义一个类,该类的属性名称与 JSON 字符串中的字段匹配(如下图)
完成代码如下:
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//{
// "username":"lisi",
// "password":"465"
//}
class User {
public String username;
public String password;
}
@WebServlet("/json")
public class JsonServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ObjectMapper objectMapper = new ObjectMapper();
User user = objectMapper.readValue(req.getInputStream(),User.class);
System.out.println("username=" + user.username + ", password=" + user.password);
resp.getWriter().write("OK");
}
}
运行结果如下:
总结:
readValue
方法将req请求中的body(json格式)中的字符串读取并解析,然后构造成了user对象,而user中的属性就是body(json格式)中所体现的内容。
jackon
还提供了一个方法可以将java对象转换成json格式
的字符串。该方法为writeValueAsString()
。
三、HttpServletResponse
HttpServletResponse
是用于构造HTTP响应的对象,提供了一系列方法用于操作响应的状态码、头部信息(header)和响应体数据(body)。它和HTTP响应数据相匹配,可以用于向客户端发送响应数据。然后针对状态码、header、body
这些属性就可以进行设置。
注意区分下面两个概念:
请求对象:拿到请求对象之后是为了获取
对象中的属性(读操作)。
响应对象:拿到响应对象之后是为了设置
对象中的属性(写操作)。
而对于
doXXX
这样的方法的作用就是根据请求计算响应。
再强调一下:请求对象是Tomcat收到后对Http协议解析得到的对象。
而响应对象是Tomcat创建空的对象,然后在代码中把响应对象的属性设置好。
下面来看HttpServletResponse
中的核心方法,如下:
addHeader()
:可能会出现key相同的两个键值对(一个key可以对应多个value)。另外,Java标准库的Map是不允许key重复的,Tomcat内部也不一定把header解析成Map。setHeader()
:一个key对应一个value。setCharacterEncoding
:告诉浏览器按照什么样的字符集来解析响应的body。sendRedirect
:用来设定重定向
响应。
setStatus
代码示例1如下:
运行结果如下:
代码示例2如下:
运行结果如下:
在返回状态码的同时,可以给body写入数据,这样就可以得到
比较个性化的错误页面
,比如:
上图就是搜狗的404错误页面。
上图就是百度的404错误页面。
上图是哔哩哔哩的404错误页面。
Tomcat同样有一个内置的404报错页面,虽然
setStatus
方法并没有页面,但是sendError
方法是有页面的。代码如下:
上图是Tomcat的404报错页面。
setHeader
我们通过使用setHeader方法来设置任意的响应报头。举例:通过refresh属性来设置浏览器自动刷新(比如refresh:2
,意思就是浏览器每隔两秒就会自动刷新)。
代码如下:
运行结果如下(下图中的时间每隔两秒就会改变):
构造重定向响应
让页面重定向到百度主页。
注意:使用重定向一定要带有Location属性,然后用这个属性来描述你要重定向到哪个地方
。
代码如下:
结果如下:
补充:
301:永久重定向
302:临时重定向
刚刚上述代码可以等价替换成下面代码:
即resp.sendRedirect("https://www.baidu.com");
等价于resp.setStatus(302);resp.setHeader("Location","https://www.baidu.com");
(浏览器看到302和https://www.baidu.com这两个字段就知道要跳转到百度)
返回一个html界面
结果如下:
为什么会出现乱码呢?
我们要知道,如果在IDEA中直接写一个中文字符串的话是按照utf-8
进行编码的。但是浏览器默认是使用操作系统的编码方式来解析和显示页面,而windows简体中文版的默认编码方式是gdk,此时浏览器按照gdk的方式来解析utf-8的话就会出现上图中的乱码。
所以我们要设置一下让浏览器按照utf-8的方式进行解析(如下)。
上述代码还存在一个问题,如下(将doGet方法中的两行代码进行互换):
可以看到又出现了乱码。在Servlet中,为resp设置属性的时候,需要注意顺序:要先设置header,然后再设置body;否则如果先设置body的话此时header、status就已经定性而来不及修改了
。
好了,以上就是本文的全部内容了。希望各位友友可以一键三连哈!!!