Servlet二:Servlet的一些其它相关问题
一、设置编码
-
get请求方式 基于tomcat8,不需要设置转码 在tomcat8之前发送中文数据,需要进行如下转码操作 String fname = req.getParameter("fname");
byte[] bytes = fname.getBytes("ISO-8859-1");
fname = new String(bytes,"UTF-8");
-
post请求方式 req.serCharacterEncoding("UTF-8");
注意:该代码必须在所有的获取参数动作之前
二、Servlet的继承关系
-
继承关系 javax.servlet.Servlet 接口
javax.servlet.GenericServlet 抽象类
javax.servlet.http.HttpServlet 抽象子类
-
相关方法 重点查看的是服务方法 ① javax.servlet.Servlet 接口 void init(config) 初始化方法
void service(ServletRequest var1, ServletResponse var2) 服务方法
void destory() 销毁方法
② javax.servlet.GenericServlet 抽象类 public abstract void service(ServletRequest var1, ServletResponse var2) 仍然是抽象方法
③ javax.servlet.http.HttpServlet 抽象子类 protected void service(HttpServletRequest req, HttpServletResponse resp){
String method = req.getMethod();
if (method.equals("GET")) {
this.doGet(req, resp);
} else if (method.equals("HEAD")) {
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_post_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
}
-
小结 ① 继承关系:HttpServlet -> GenericServlet -> Servlet ② Servlet中的核心方法:init( ) , service( ) , destroy( ) ③ 服务方法service( ) :当有请求过来时,service方法会自动响应(其实是tomcat容器调用的)。在HttpServlet中,会自动分析请求的方式,从而决定调用哪个do开头的方法。 ④ 这些do方法默认都是405的实现风格,因此我们在新建Servlet时,会考虑请求类型,从而决定重写对应的do方法
三、Servlet的生命周期
-
定义 从出现到消亡的整个过程,与其对应的是上面的三个核心方法,由tomcat维护 -
默认情况 第一次接收请求时,这个Servlet会进行实例化(调用构造方法)、初始化(调用init方法)、然后是服务(调用service方法) 从第二次请求开始,每一次都是服务 当容器关闭时,其中的所有servlet实例会被销毁 2.1 测试生命周期的service方法 package com.atguigu.servlets;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import java.io.IOException;
public class Web_Cycle extends HttpServlet {
public Web_Cycle() {
System.out.println("构造器");
}
@Override
public void init() throws ServletException {
System.out.println("初始方法");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("服务方法");
}
@Override
public void destroy() {
System.out.println("销毁方法");
}
}
2.2 配置web.xml文件 <?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>Web_Cycle</servlet-name>
<servlet-class>com.atguigu.servlets.Web_Cycle</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Web_Cycle</servlet-name>
<url-pattern>/demo1</url-pattern>
</servlet-mapping>
</web-app>
2.3 配置tomcat -
情况说明 在tomcat中,Servlet实例只会被创建一个,所有的请求都是这个实例去响应 在默认情况下,第一次请求,tomcat会实例化和初始化,为了提高系统的启动速度,我们应设置Servlet的初始化时机 -
Servlet的初始化时机
<servlet>
<load-on-startup>1</load-on-startup>
</servlet>
-
Servlet在容器中:单例、线程不安全 单例:所有的请求都是同一个实例去响应 线程不安全:一个线程需要根据这个实例中的某个成员变量去做逻辑判断。但是在中间的某个时刻,另一个线程改变了该成员变量 **故:**尽量不要在servlet中定义成员变量。如果必须定义成员变量,那么不要修改该成员变量的值或根据该成员变量的值去做逻辑判断
四、Http协议
-
HTTP:HyperText Transfer Protocol,超文本传输协议 -
Http是无状态的 -
Http请求 请求行 包含三个信息:请求的方式;请求的URL;请求的协议(一般是HTTP1.1,2015年退出HTTP2.0) 请求消息头 包含客户端告知服务器的消息。例如:浏览器的型号、版本、我能接收的内容类型、我给你发的内容类型 请求体 get方式:没有请求体,但是有一个queryString post方式:有请求体,form data json方式:有请求体:payload -
Http响应 响应行 包含三个消息:1.协议;2.响应状态码(200);3.响应状态(ok) 响应头 包含服务器的信息;服务器发给浏览器的信息(内容的媒体类型、编码、内容长度等) 响应体 响应的实际内容
五、会话(session)
-
Http是无状态的 概念:服务器无法判断两次的请求是同一个客户端发过来的,还是不同的客户端发过来的 现实举例:第一次请求是添加商品到购物车,第二次请求是结账。如果服务器无法区分两次请求是否为同一用户发来的,那么就会产生混乱,可能你给别人的购物车结账了 解决方法:会话跟踪技术 -
会话跟踪技术 2.1 客户端第一次发请求给服务器,服务器获取session,如果获取不到,则创建新的,然后相应给客户端 2.2 下次客户端给服务器发请求时,会把sessionId带给服务器,那么服务器在获取到的同时会判断这次请求和上次的哪个客户端的请求是相同的,从而区分不同的客户端
request.getSession();
request.getSession(true);
request.getSession(false);
session.getId();
session.isNew();
sesseion.getMaxInactiveInterval();
sesseion.setMaxInactiveInterval();
session.invalidate();
...
六、服务器内部转发以及客户端重定向
-
服务器内部转发 过程:一次请求响应的过程,对于客户端而言,内部经过了多少次转发,客户端都不知道 结果:地址栏没有变化 代码: public class Demo6Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo6");
req.getRequestDispatcher("demo7").forward(req,resp);
}
}
public class Demo7Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo7");
}
}
流程图: -
客户端重定向 过程:两次请求响应的过程。客户端知道请求的URL有变化 结果:地址栏有变化 代码: public class Demo6Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo6");
resp.sendRedirect("demo7");
}
}
public class Demo7Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo7");
}
}
流程图:
|