Servlet的request与response对象追踪
HttpServletRequest和HttpServletResponse是Servlet规范中规定的两个接口,HttpServlet中并没有实现这两个接口的成员变量,它们只是HttpServlet的service和doXXX等方法的参数
要是问传入到HttpServlet中的service和doXXX方法中的,实现了HttpServletRequest和HttpServletResponse接口的类的对象是从哪来的,那自然是某段代码中实例化来的。
那么实例化这两个对象的代码在哪呢?答案是在Servlet标准的实现者 - Servlet容器中
以使用BIO模型的Tomcat 7.0.72为例:
- ThreadPool将待处理的Socket连接丢给SocketProcessor处理
- SocketProcessor调用AbstractConnectionHandler的process方法
- AbstractConnectionHandler确认应使用Http11Processor来处理此请求,于是实例化一个(或者拿一个现成的)Http11Processor,调用其process方法来处理请求
- 在Http11Processor被实例化时,org.apache.coyote.Request和org.apache.coyote.Response对象同时被实例化:
public AbstractProcessor(AbstractEndpoint<S> endpoint) {
this.endpoint = endpoint;
asyncStateMachine = new AsyncStateMachine<S>(this);
request = new Request();
response = new Response();
response.setHook(this);
request.setResponse(response);
}
这里的Request和Response并没有实现Servlet标准中javax.servlet.http.HttpServletRequest和javax.servlet.http.HttpServletResponse接口
- 接下来,request和response对象被交给CoyoteAdapter的service方法处理,CoyoteAdapter将这两个对象解析并转化为org.apache.catalina.connector.Request和org.apache.catalina.connector.Response:
public void service(org.apache.coyote.Request req,
org.apache.coyote.Response res)
throws Exception {
Request request = (Request) req.getNote(ADAPTER_NOTES);
Response response = (Response) res.getNote(ADAPTER_NOTES);
if (request == null) {
// Create objects
request = connector.createRequest();
request.setCoyoteRequest(req);
response = connector.createResponse();
response.setCoyoteResponse(res);
// Link objects
request.setResponse(response);
response.setRequest(request);
// Set as notes
req.setNote(ADAPTER_NOTES, request);
res.setNote(ADAPTER_NOTES, response);
// Set query string encoding
req.getParameters().setQueryStringEncoding
(connector.getURIEncoding());
}
//...
}
- org.apache.catalina.connector.Request和org.apache.catalina.connector.Response这两个类则实现了Servlet标准的接口:
package org.apache.catalina.connector;
/**
* Wrapper object for the Coyote request.
*
* @author Remy Maucherat
* @author Craig R. McClanahan
*/
public class Request implements HttpServletRequest {
//...
}
- 此时的Request和Response对象,就已经符合题主所描述的“Servlet中的request和response”了。接下来,在Tomcat中还要进行7层的invoke调用和3层的filter,最终终于到达了Servlet(这还是没有自定义Filter的情况)
杂记-复习笔记
Servlet
-
概念
:server applet 运行在服务器端的小程序 -
Tomcat部署的方式
war:压缩打包后部署,修改文件都会重启Tomcat
war-exploded:热部署,将web工作文件原样部署到Tomcat,修改不需要重启
常见的是热部署在conf\Catalina\localhost创建任意名称的xml文件。在文件中编写虚拟目录是xml文件名
Servlet就是一个接口,定义了Java类被浏览器访问到tomcat识别的规定
将来我们定义一个类,实现了Servlet接口,复写方法
老版本配置
*创建javaEE项目
*定义一个类实现Servlet接口
*实现接口中的抽象方法
*配置Servlet
web.xml
<-- servlet3.0出现注解配置 -->
<servlet>
<servlet-name>自定义名字<servlet-name>
<servlet-class>java的全类名<servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>自定义名字</servlet-name>
<url-pattern>自定义servlet访问地址</url-pattern>
</servlet-mapping>
1.当服务器接受到客户端浏览器的请求后,会解析请求URl的路径,获取访问的Servlet的资源路径
2.查找web.xml文件,是否有对应的<url-pattern>标签体内容
3.如果有,则会找到对应的<servlet-class>全类名
4.tomcat
webservlet的注解配置
public @interface WebServlet {
String name() default "";
String[] value() default {};
String[] urlPatterns() default {};//可以配置多个虚拟路径
int loadOnStartup() default -1;
WebInitParam[] initParams() default {};
boolean asyncSupported() default false;
String smallIcon() default "";
String largeIcon() default "";
String description() default "";
String displayName() default "";
}
-
生命周期方法
实现Servlet接口:
1.被创建:执行init方法,只会执行一次 🌵只会执行一次说明只有一个对象,容易出现线程安全的问题,尽量不要定义修改成员变量,🌵
servlet什么时候被创建:默认第一次被访问的时候被创建
也可以配置执行Servlet的创建时机
2.提供服务:执行service方法,每次访问执行
3.被销毁执行destory方法
-
Servlet体系结构
||||||》对除了service之外的方法做了空实现
GenericServlet----抽象类
|||||》对http协议的一种封装,对请求方式等等一些判断简化
HttpServlet --抽象类
ps:当子类继承httpservlet时候没重写service时,调用会访问HttpServlet的service的方法,然后再根据请求方式分发调用对应的方法
1.复写了doGet和doPost方法
-
ServletContext对象:
概念:代表整个web应用,可以和程序的容器(服务器如tomcat)来通信,一个web应用只有一个
获取:1.通过域对象(request,)获取
作用:1.获取MIME类型
🌰因为所有的规定的MiME都在tomcat里面存着的,所以与服务器通信可以知道指定文件该是哪种mime类型
2.域对象,共享数据
3.获取文件的真实(服务器)路径
getRealPath()
, 所有项目都是部署到服务器的,所以本地那个路径不是真实路径
-
HTTP协议
//常见的请求头:
user-Agent:浏览器告诉服务器,我访问你使用的浏览器的版本信息
Referer:地址 :当前请求来的地址
1.可以防止别人链接到你网站的资源
2.统计工作
//常见的响应头:
Content-Type:服务器告诉浏览器本次响应体的数据格式以及编码格式
Content-disposition:服务器告诉客户端以什么格式打开响应体数据
*in-line:默认值,在当前页面
*attachment;filename=xxx;以附加形式打开响应体,文件下载
1.可以防止别人链接到你网站的资源
2.统计工作
request与response对象主要应用方法:
-----请求行
获取请求方式
//String getMethod()
获取项目虚拟目录
//String getContextPath()
获取Servlet虚拟目录
//String getServletPath()
获取get方式请求体参数(get请求)
//String getQueryString()
获取请求URL和uri
获取客户机的ip地址:
//String getRemoteAddr()
-------请求头 --------响应头
获取请求头 设置响应头
//String getHeader() //setHeader()
--------请求体 --------------响应体
1.获取流对象 1.获取输出流
2.再从流对象中拿数据 2.使用输出流,将数据输出到客户端浏览器
`通用方法`
//通过name获取请求参数值
getParameter(name:参数名称) |多个值对一个参数键:getParameterValues
//获取请求参数名称
getParameterNames()所有
//获取请求参数Map集合
getParameterMaps()
---------------------------------------------------------------
request的请求转发
getRequestDispatcher(string path)
特点:1.浏览器地址不发生变化,只请求一次,只能转发到服务器内部资源
ps:post请求参数还是在流中获取,注意post乱码问题
response重定向
步骤1.设置状态码:response.setStatus(302);设置响应:response.setHeader("location","重定向路径")
简化Api:response.sendRedirect("重定向路径")
特点:1.重定向地址栏发生变化,是两次请求不能共享数据,可以访问其他站点的资源
---------------
下载指定文件 ps:在maven里面会报错,原因是路径与正常部署是路径不同
String filename = req.getParameter("filename");
ServletContext servletContext = req.getServletContext();
String mimeType = servletContext.getMimeType(filename);
System.out.println(filename+""+mimeType);
String realPath = servletContext.getRealPath("a.properties");
resp.setHeader("content-type",mimeType);
resp.setHeader("Content-disposition","attachment;filename=xxx");
ServletOutputStream outputStream = resp.getOutputStream();
FileInputStream fileInputStream = new FileInputStream(realPath);
int a;
while ((a = fileInputStream.read())!=-1){
outputStream.write(a);
}
String realPath = request.getServletContext().getRealPath("/");
System.out.println(realPath);
URL resource = Thread.currentThread().getContextClassLoader().getResource("");
System.out.println(resource);
InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("user.properties");
System.out.println(resourceAsStream);
输出结果D:\a.java---!testJavaPlace\Maventest\src\main\webapp\
file:/D:/a.java---!testJavaPlace/Maventest/target/classes/
java.io.BufferedInputStream@55939162------模式maven的tomcat run
----------------------------------
输出结果D:\a.java---!testJavaPlace\Maventest\target\Maventest-1.0-SNAPSHOT\
file:/D:/a.java---!testJavaPlace/Maventest/target/Maventest-1.0-SNAPSHOT/WEB-INF/classes/
java.io.BufferedInputStream@2ca18815-----模式maven的tomcat run war