文章目录
- 一、三个核心API
- 1.1 HttpServlet
- 【1】地位
- 【2】方法
- 1.2 HttpServletRequest
- 【1】地位
- 【2】方法
- 【3】关于构造请求
- 1.3 HttpServletResponse
- 【1】地位
- 【2】方法
- 四、涉及状态码的错误排查(404……)
- 五、关于自定义数据 ---- body或query String 里面的内容
- 5.1 地位
- 5.2 给服务器传递自定义数据
- 5.3 获取自定义数据
学习Servlet就是学习API以及如何进行web开发
一、三个核心API
1.1 HttpServlet
【1】地位
编写 Servlet 代码会用到的核心的类。我们通过继承这个类并重写其中的方法,把代码交给Tomcat,Tomcat负责在合适的时机去调用
【2】方法
-
init():
(1)使用时机:原则上 init() 是在Tomcat启动加载webapp的时候就执行了,但是Tomcat是可以配置webapp为“懒加载”状态的(让webapp在首次且真正被访问到的情况下才加载)(2)作用:进行一些初始化操作
-
destory():
(1)使用时机:webapp 被销毁的时候执行(2)作用:进行一些收尾工作
(3)该方法不一定会被调用到:因为destory()是webapp被销毁时被调用到,而Tomcat有两种方式结束。实际开发中,以第二种方式居多,所以我们不能太依赖destory()
- 一种是通过 8005 端口,给Tomcat发送特殊的请求(告诉Tomcat要关闭了),然后Tomcat调用destory()
- 直接杀死Tomcat进程,如任务管理器上直接结束进程,此时Tomcat没有机会执行destory()
-
service():
(1)使用时机:每次收到请求,都会处理service。实际开发中用得不多,多用下面的do三部曲。(2)作用:处理每个请求
-
doGet():
(1)使用时机:收到Get请求时(2)作用:处理Get请求的情景
-
doPost():
(1)使用时机:收到 Post 请求时(2)作用:处理 Post 请求的情景
-
doPut/doDelete……:使用时机同doGet、doPost,遇到对应的请求会被调用
1.2 HttpServletRequest
【1】地位
Tomcat 收到HTTP请求后,就会把请求解析成该对象
【2】方法
- getProtocol():返回请求协议的名称和版本
- getMethod():回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT
- getRequestURI():返回该请求的 URL
- 什么是URI:URL可以理解为是URI的一种实现方式,但是两者经常混用
- URI指的是唯一资源标识符,可以区分不同的资源
- URL则是唯一资源定位符,用来描述网络上一个资源,又因为资源是唯一的,所以可以定位资源
- 什么是URI:URL可以理解为是URI的一种实现方式,但是两者经常混用
- 获取请求中参数的值
- getParameterNames():拿到所有的key
- getParameter(String name):根据key拿到value
- getParameterValues(String name):涉及到一个key对应到多个value值的情况,并不经常使用
- 获取请求头中的内容:获取到请求头的键值对。Tomcat 在收到请求之后会把请求头解析成Map。
- getHeaderNames()
- getHeader(String name)
- 获取请求主体中的内容:
- getCharacterEncoding():获取到 contentText 里的字符集。字符集本质上是 contentType 的一部分,但是由于关于字符集的操作使用很频繁,所以被单独拉出来
- getContentType():获取到 body 里的类型
- getContentLength():获取到 body 的长度
- getInputStream():获取到能读取到body内容的流对象
【3】关于构造请求
- 服务器只能比较方便地构造出Get请求,至于其他类型的请求,我们需要使用ajax或者postman构造
- 实际开发中,常用的请求是 Get或Post
1.3 HttpServletResponse
【1】地位
与 HTTP响应数据匹配
【2】方法
- 给 header 赋值:
- setHeader(String name, String value):如果存在,新覆盖旧
- addHeader(String name, String value):如果存在,新旧并存
- 一般来说,约定键值对的key是要唯一的,但是实践中,可能会出现一个key对应多个value的情况,但这个是由浏览器/HTTP客户端来控制的
- Map无法允许key重复矛盾:注意,【Tomcat会将header解析成Map形式】只是一种粗略说法,实际上Tomcat内部不一定是把header解析成Java标准库的Map。Java标准库的Map并不允许key重复,但有第三方库是允许的
- 示例:通过 refresh 属性,设置浏览器自动刷新
- resp.setHeader(“Refresh”, 2): 浏览器每隔2s自动刷新一次。
实际上并非是精确的2000ms,一般会大一些。因为从 “浏览器发起请求” 到 “服务器响应”再到“页面被解析出来”都是需要消耗一定的时间的
- resp.setHeader(“Refresh”, 2): 浏览器每隔2s自动刷新一次。
- 设置状态码:
- setStatus(int sc)
- 关于个性化错误页面:Tomcat 是可以在返回状态码的时候,给body写入数据的,此时就可以得到一个“个性化的错误页面”。Tomcat有自己内置的错误页面,比如【resp.sendError(404)】,但由于太丑,日常开发中我们往往还是会选择自定义
四、涉及状态码的错误排查(404……)
- 404:浏览器要访问的资源,服务器上并不存在
- 检查请求路径和服务器配置是否一致
- 确认webapp是否被正确加载:我们的程序是通过
- 405:方法不允许
- 请求发起的方法与对应的doXX方法不匹配。如在浏览器中输入一个url地址,就是发起Get请求。
- 没有删除父类的方法。如父类的doGet方法会先获取一个版本号,根据版本号发送不同的错误,并会指定一个错误页面
- 500:服务器内部错误,代码出现了异常
- 空白页面:服务器没有给浏览器返回任何的body数值
- 无法访问此网站:Tomcat 服务器未正确运行/IP/端口号编写不对
五、关于自定义数据 ---- body或query String 里面的内容
5.1 地位
实际开发中,利用header的部分较少,更多的时候,我们是希望获取到 query string 或 body 的内容,因为这些内容是自定义的,可以供我们完成服务。
5.2 给服务器传递自定义数据
- 方式:HttpServletResponse有获取参数的方法,获取的参数就是我们传过去的这些数据。我们共有四种方式传递数据:a=x传递、Postman传递form表单、Postman传递JSON数据、ajax传递。
- a=x传递:
- 这个是把数据传到query string里
- query string本身是键值对结构的数据,Tomcat 在收到这个请求后,就会把这个query string解析成Map这样的键值对,使用getparameter就可以根据key获取到value。
- Postman传递form表单:使用form表单的形式提交,此时的body也是键值对格式
- 这个是把数据传到 body 里
- 如果是通过post form表单的形式提交的请求,body此时就也是和query string一样的键值对格式
- 如何发送数据
- Postman传递JSON数据:
- 注意:JSON格式下,key一定是字符串格式,原则上key是不需要加“”,但是有些库/程序检查比较严格,是需要给key加上“”的.
- Postman 构造的JSON数据需要给key加上“”,Ajax 构造的则不需要加上“”
- 类里面的属性为什么不使用private:本身,Jackson 会通过反射的方式,把User类里包含的public属性都获取到,此时就可以根据反射这里得到的“属性名字”,去JSON解析出来的键值对中进行匹配,如果匹配到了,就把value设置到刚才得到的属性中。而Jackson并不会直接针对private属性进行扫描,所以如果要使用private,需要提供getter和setter方法
class User{
public String username;
public String password;
}
@WebServlet("/JSON")
public class JSONServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ObjectMapper objectMapper = new ObjectMapper();
User user = objectMapper.readValue(req.getInputStream(), User.class);
resp.getWriter().write(user.username);
resp.getWriter().write("<br>");
resp.getWriter().write(user.password);
}
}
- ajax传递:
- 既可以传到 query string,也可以传递body中
- 如果是传递到 query string 中,依旧可以使用 getParameter 来获取
- 如果是使用 ajax Post 提交【不是 from表单的格式】,就需要使用 getInputStream 来获取
5.3 获取自定义数据
- 获取query string 里的值:
- 约定数据:约定前端传过来一个怎样的数据
- 形如 【password = 】这样的请求(只说明 key,不说明 value),password的值将是“”,即一个空字符串。
- 如果不传password(忽略key),password的值是null
- 选择调用的方法:调用getParameterNames()、getParameter(String name)、getParameterValues(String name)方法
- 约定数据:约定前端传过来一个怎样的数据
- 获取body(只考虑form表单的格式):
- 约定数据:Post方法下,提交的数据才会在body里
- 和query string一样,使用 getParameter(String name)方法获取数据
- 获取body(考虑为JSON格式):
- 为什么要引入Jackson库:
Servlet 自身不能对JSON的数据进行解析,所以我们需要引入第三方库来解析body数据,把这里面的键值对还原成如Map一样【key-value】的形式。而能够实现解析操作的库很多,我们这里使用Jackson来解析。 - 引入 Jackson 库:通过Maven引入,选择【Jackson Databind】。版本选哪个都行,但最好不要选择新版本,因为新版本往往没有经过时间充分的验证,可能会有问题
- 如何使用Jackson库:一个类,两个方法
- ObjectMapper类:对象映射,可以实现JSON数据和对象间的转换
- JSON数据转类对象:readValue(InputStream src,JavaType valueType),该方法会先把JSON字符串解析成键值对,再放到Map中,然后根据参数填入的类对象,通过反射API知道这个类的属性名和类型,一次把这里的每个属性都取出来后,通过属性名字查询上述的Map,最后把得到的值赋值给这个类的属性。
- 类对象转JSON数据:writeValueAsString(Object value)
- 关于类和JSON格式的转换问题:因为是使用匹配来转换,所以构建类要求属性名和键值对相同
- 为什么要引入Jackson库: