web服务器收到客户端的Servlet访问请求后,若是服务器装载并创建了Servlet的实列对象
1) Tomcat将http请求文本进行解析,然后封装称为HttpServletRequest类型的Requset对象
2) Tomcat将要响应的信息封装为HttpServletResponse类型的response对象进行返回
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { request; HttpServletResponse response; try { request = (HttpServletRequest)req; response = (HttpServletResponse)res; } catch (ClassCastException var6) { throw new ServletException("non-HTTP request or response"); } this.service(request, response); }
三 创建一个Servlet
3.1 Servlet的执行流程
首先,如果浏览器由这样一个输入:http://localhost:8080/demo/MyServlet
http:http协议
统一资源定位符URL。
格式:<协议>://<主机>:<端口>/<路径>
localhost:域名
8080:Tomcat端口号
demo: web应用的名称,在webapps下找是否存在demo的目录。
MyServlet:web资源,在demoweb的应用的应用下查找是否存在此资源。
/MyServlet资源就是我们的一个Servlet
-> 得到/MyServlet字符串
-> 使用/MyServlet到web.xml文件中查找每一个<servlet-mapping>下的<url-pattern>标签里的内容,然后得到sevlet-name
-> 使用sevlet-name去servlet标签中找到对应的相同名称的servlet配置。
-> 得到servlet配置中的servlet-class内容。
<servlet> <servlet-name>MyServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
3.2 DIEA开发Servlet
1 新建JAVA EE Web Appication工程。
2 新建一个Servlet类。
3 导入需要依赖的tomcat目录下的servlet-api.jar包
4 编写FirstServlet的代码.
package javademo; import java.io.IOException; import java.io.PrintWriter; public class FirstrServlet extends javax.servlet.http.HttpServlet { protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { } protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { response.setContentType("text/html"); PrintWriter pw = response.getWriter(); pw.write("<h1> hello first servlet!</h1>"); } }
5 编写web,xml配置文件 dom4j才能正确解析
<servlet> <servlet-name>FirstrServlet</servlet-name> <servlet-class>javademo.FirstrServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>FirstrServlet</servlet-name> <!-- 响应所有请求--> <url-pattern>/FirstrServlet</url-pattern> </servlet-mapping>
3.3 详解Servlet实现原理
3.3.1 servlet的生命周期是什么?
服务器启动时(web.xml中配置load-on-startup=1,默认为0)或者第一次请求该servlet时,就会初始化一个Servlet对象,也就是会执行初始化方法init(ServletConfig conf)
该servlet对象去处理所有客户端请求,在service(ServletRequest req,ServletResponse res)方法中执行
最后服务器关闭时,才会销毁这个servlet对象,执行destroy()方法。
3.3.2 为什么创建的servlet是继承自httpServlet,而不是直接实现Servlet接口?
Servlet是一个接口,如果实现了这个接口,那么就必须实现接口里面定义的所有方法。
我们来看HttpServlet源码:
继承了HttpServlet实际上也就实现了Servlet接口,没有必要再去实现Servlet中的方法。HttpServlet在实现servlet接口时,已经实现了Servlet里面的所有方法,所以不用再去覆写对应的生命周期等方法。
Servlet接口:
public interface Servlet { //由Servlet容器调用,以指示将servlet放入服务器的servlet void init(ServletConfig var1) throws ServletException; //返回一个servlet对象,其中包含这个servlet初始化和启动参数。 ServletConfig getServletConfig(); //由servive调用,以允许servlet对请求做出响应 void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException; //返回有关servlet的信息,如作者,版本和版权 String getServletInfo(); //由servlet容器调用,以只是servlet将排除在服务器之外 void destroy(); }
ServletConfig接口:
interface ServletConfig { String getServletName(); ServletContext getServletContext(); String getInitParameter(String var1); Enumeration<String> getInitParameterNames(); }
其中servletContext接口是Servlet中最大的一个接口,呈现了web应用的Servlet视图。获得ServletContext对象也就能得到我们需要的大部分信息。
GenericServlet中有两个Init函数,一个有参数一个无参 。这样做是为什么呢?
博主 一杯凉茶解释的很好:通过这几个方法一起来讲解,首先看init(ServletConfig config)方法,因为只有init(ServletConfig config)中带有ServletConfig对象,为了方便能够在其他地方也能直接使用ServletConfig对象,而不仅仅局限在init(ServletConfig config)方法中,所以创建一个私有的成员变量config,在init(ServletConfig config)方法中就将其赋值给config,然后通过getServletConfig()方法就能够获取ServletConfig对象了,这个可以理解,但是在init(ServletConfig config)中,158行,还调用了一个init()方法,并且这个init()方法是空的,什么读没有,这是为什么呢?这个原因是为了防止一件事情,当我们需要在init方法中做一点别的事情,我们想到的方法就是继承GenericServlet并且重写了init(ServletConfig config)方法,这样依赖,就破坏了原本在GenericServlet类中init(ServletConfig config)写的代码了,也就是在GenericServlet类中的成员变量config会一直是null,无法得到赋值,因为被重写了,就不会在执行GenericServlet中init(ServletConfig config)方法中的代码。要想赋值,就必须在重写的init(ServletConfig config)方法中调用父类的init(ServletConfig config)方法,也就是super.init(ServletConfig config),这样一来,就很不方便,怕有时候会忘了写这句代码,所以在GenericServlet类中增加一个init()方法,以后需要在init方法中需要初始化别的数据,只需要重写init()这个方法,而不需要去覆盖init(ServletConfig config)这个方法,这样设计,就好很多,不用在管 init(ServletConfig config)这个其中的内容了。也不用出现其他的问题。
四 关于ServletConfig对象,ServletContext对象、request对象,response对象的学习。
ServletConfig对象
1)通过getServletConfig()获得。
2)通过继承父类(GenericServlet)的方法得到一个ServletConfig对象
功能:获取servletname context parameter initparameternames
public interface ServletConfig { //获取web.xml中配置的Servlet-name String getServletName(); //获取ServletContext对象 其中内容非常多 ServletContext getServletContext(); //获取在servlet中初始化参数的值。 String getInitParameter(String var1); //返回类型是枚举型,获取在Servlet中所有初始化参数的名字。相当于有多个<init-param> Enumeration<String> getInitParameterNames(); }
Web.xml配置如下:
运行结果如下:
ServletContext对象
获取:
1)getServletContext()
2)getServletConfig().getServletContext();
功能:tomcat为每个web项目都创建一个ServletContext实列,主要是为了方便数据共享,让每个Servlet都可以访问到它。
4.1 web项目中共享数据
在一定范围内(当前应用),使多个Servlet共享数据
setAttribute(String name, Object obj) 在web项目范围内存放内容,放入对应的key和value,以便让在web项目中所有的servlet读能访问到
getAttribute(String name) 通过指定名称获得内容
removeAttribute(String name) 通过指定名称移除内容
实例如下:
getServletContext().setAttribute("name1","value1");
4.2 获取全局配置信息
整个web项目初始化参数 (这个就是全局初始化参数,每个Servlet中都能获取到该初始化值)
getInitPatameter(String name) //通过指定名称获取初始化值
getInitParameterNames() //获得枚举类型 上面说过的,多个servlet-name
4.3 获取web项目资源
4.3.1 获取web项目下指定资源的路径:getServletContext().getRealPath("/WEB-INF/web.xml")
String getRealPath(String path);//根据资源名称得到资源的绝对路径
4.3.2 获取web项目下指定资源的内容,返回的是字节输入流。InputStream getResourceAsStream(java.lang.String path)
public void test()throws IOException{ InputStream in = getServletContext().getResourceAsStream("/WEB-INF/web.xml"); //统一编码才能正确进行输出 InputStreamReader is = new InputStreamReader(in,"UTF-8"); BufferedReader br = new BufferedReader(is); String s = null; while ((s = br.readLine())!=null) { System.out.println(s); } }
结果如下,正是web.xml里面的配置内容
4.3.4 实现Servlet的转发
ServletContext sc = this.getServletContext(); RequestDispacher rd = sc.getRequestDispacher("/转发页面"); rd.forward(request,response);
4.4 Request、Response
4.4.1 request和response是什么?
request就是将请求文本封装而成的对象,所以通过request能获得请求文本中的所有内容,请求头、请求体、请求行 。
response是服务器根据请求进行的响应
request
包含:请求头,请求行,请求体。
下面是一个实际的请求报文:
②为请求对应的URL地址,它和报文头的Host属性组成完整的请求URL
③是协议名称及版本号。
④是HTTP的报文头,报文头包含若干个属性,格式为“属性名:属性值”,服务端据此获取客户端的信息。
⑤是报文体,它将一个页面表单中的组件值通过param1=value1¶m2=value2的键值对形式编码成一个格式化串,它承载多个请求参数的数据。不但报文体可以传递请求参数,请求URL也可以通过类似于“/chapter15/user.html? param1=value1¶m2=value2”的方式传递请求参数。
Accept:告诉服务器,客户机支持的数据类型
Accept-Encoding:告诉服务器,客户机支持的数据压缩格式
Cache-Control:缓存控制,服务器通过控制浏览器要不要缓存数据
Connection:处理完这次请求,是断开连接还是保持连接
Cookie:客户机通过这个可以向服务器带数据
Host:访问的主机名
Upgrade-Insecure-Requests:参考http://www.cnblogs.com/hustskyking/p/upgrade-insecure-requests.html
User-Agent:告诉服务器,客户机的软件环境
response也有与之对应的响应报文
Response Headers响应头
Connection:处理完这次请求后,是断开连接还是继续保持连接
Content-Encoding:服务器通过这个头告诉浏览器数据的压缩格式
Content-Length:服务器通过这个头告诉浏览器回送数据的长度
Content-Type:服务器通过这个头告诉浏览器回送数据的类型
Date:当前时间值
Server:服务器通过这个头告诉浏览器服务器的类型
Vary:Accept-Encoding ——明确告知缓存服务器按照 Accept-Encoding 字段的内容,分别缓存不同的版本;参考:https://imququ.com/post/vary-header-in-http.html
X-Powered-By:服务器告知客户机网站是用何种语言或框架编写的。
总结:搞懂基础性的东西才能让未来的路走的更远!