文章目录
下午处理了Tomcat的javaweb项目的配置报错,追踪分析了一下javax.servlet包中的 抽象类 HttpServlet、接口 HttpServletRespons、接口 ServletResponse、公共类 PrintWriter
,以及相关调用方法。虽然没有进行系统的理论学习,但零散看了一些资料,目前大脑有点像一片浆糊。
从目前来看,接下来今明两天的几篇文章应该聚焦如下内容,其中Servlet篇希望晚上能够完成一部分。
- 复习公共类、抽象类、接口的相关概念
- 【✅】较为全面地学习Java Servlet技术
- Java反射机制
- MVC模式和框架
Servlet详解
介绍
静态网页技术出生后,应用于动态网页技术的CGI应运而生,但是其过于"笨重"的设计,且限制过多,因此很难同时处理大量的客户端请求。
Java在探索动态网站技术的过程中,首先推出了applet(Java编写的插件,需要浏览器端安装)。其后,推出了Servlet,其命名可以理解为(Server + applet),将Java代码的执行都放在后端服务器执行,而不需要依赖浏览器端。
Servlet引擎采用多线程模式运行,它为并发的每个访问请求都使用一个独立的线程来进行响应。
Servlet的基本概念
Servlet是sun提供的一种动态web资源开发技术,本质上就是一段java小程序,可以将Servlet加入到Servlet容器中运行。
- Servlet容器:能够运行Servlet的环境就叫做Servlet容器. — tomcat
- web容器:能够运行web应用的环境就叫做web容器 — tomcat
Servlet的基本运行方式: Servlet没有main()方法。它们受控于另一个Java应用(例如Tomcat),这个Java应用称为Sevlet容器,Tomcat就是这样一个容器。通常我们把Tomcat也叫做Servlet容器。
Servlet默认是以多线程模式执行的。
注:JSP是为了方便写html代码和Java代码,它的本身其实还是Servlet。
Servlet的映射
由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序若想被外界访问,必须把servlet程序映射到一个URL地址上,这个工作在web.xml文件中使用 <servlet>
元素和 <servlet-mapping>
元素完成。
<servlet>元素用于注册Servlet,它包含有两个主要的子元素:<servlet-name>和<servlet-class>,分别用于设置Servlet的注册名称和Servlet的完整类名。
一个<servlet-mapping>元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个子元素:<servlet-name>和<url-pattern>,分别用于指定Servlet的注册名称和Servlet的对外访问路径。例如:
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.vae.servlet.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/servlet/MyServlet</url-pattern>
</servlet-mapping>
访问网页的工作过程
1、问题:访问URL:http://localhost:8080/servlet_test/FirstServlet
2、前提: tomcat服务器启动时,首先加载webapps中的每个web应用的web.xml配置文件。(补充webapps中存放的就是web项目中的WebRoot下的所有资源)
3、详解:
1)http://: http协议
2)localhost: 到本地的hosts文件中查找是否存在该域名对应的IP地址127.0.0.1
3)8080: 找到tomcat服务器
4)/servlet_test 在tomcat的webapps目录下找 servlet_test的目录
5)/FirstServlet 资源名称。
a)在day10的web.xml中查找是否有匹配的url-pattern的内容(/first)
b)如果找到匹配的url-pattern,则使用当前servlet-name的名称到web.xml文件中查询是否相同名称的servlet配置
c)如果找到,则取出对应的servlet配置信息中的servlet-class内容:字符串: gz.itcast.a_servlet.FirstServlet
d)通过反射:
Ⅰ)构造FirstServlet的对象。
Ⅱ)然后调用FirstServlet里面的方法。
Servlet的创建和生命周期
从前面的资料得知,Servlet是多线程的,在Web请求和后台代码之间扮演中间平台的角色。问题来了,我们如何创建一个Servlet程序?
Servlet容器(Tomcat,也是Web容器)负责接收请求并解析HTTP数据包,然后创建Servlet实例对象,并进入Servlet的生命周期:init()初始化、service()运行、destroy()销毁。
理解逐渐清晰,显而易见Servlet程序落地就是一个class,不同的class实例对象可以看作是不同的servlet线程。那么Java是如何创建servlet实例对象的?
Servlet包
为了支持Servlet的开发,或者说方便我们创建Servlet,jdk提供了一个jar包----servlet-api.jar。
查看Tomcat的欢迎文件HelloServlet.java,可以看到Servlet的路径映射代码,以及实例对象所继承的类 HttpServlet
。
(Servlet3.0以上版本,开发者只需添加@WebServlet注解即可修改Servlet的属性,无需在web.xml里配置)
之前有追踪过javax.servlet包的类和接口,见《【Java基础5】JavaWeb之简单追踪javax.servlet类库》,发现没有图解总是差点意思,有空找个作图软件,在实验之后做好图解总结。
package com.example.javawebdemo;
import java.io.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
@WebServlet(name = "helloServlet", value = "/hello-servlet")
public class HelloServlet extends HttpServlet {
private String message;
public void init() {
message = "Hello Java!";
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html");
// Hello
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("<h1>" + message + "</h1>");
out.println("</body></html>");
}
public void destroy() {
}
}
个人理解
浏览器访问指定路径,
Web服务器收到请求后开始寻找Servlet程序,
Servlet程序找到对应页面的代码、通过反射构造实例对象并执行方法,Servlet把代码执行结果动态返回给Web服务器,
Web服务器把数据封装成HTTP返回给浏览器。
Servlet实例对象的访问、创建和运行目前有了一定的理解,Servlet的访问流程见《Java代码审计 入门篇 4.3.2》。
动手创建Servlet
编写Servlet对象文件
本地环境:Java开发包 javax.servlet-api-4.0.1.jar。Web容器 Tomcat 8.5。开发工具包 java 14.0.2 2020-07-14。
创建HelloServlet2.java文件,初始代码如下。
package com.example.javawebdemo;
public class HelloServlet2 {
}
(1)继承Servlet类 HttpServlet
:extends HttpServlet,需要导入javax.servlet.http.HttpServlet类。
(2)为该代码文件设置URL路径:@WebServlet(name = “HelloServlet2”, value = “/Hello2”)。创建该实例对象,需要导入javax.servlet.annotation.WebServlet类。
(3)定义全局变量:public string message = “Hello2”;
(4)Servlet实例对象的初始化:public void init(){}
(5)Servlet实例对象的运行:service()方法、doGet()方法、doPost()方法等,此处涉及到3个以上的类及其调用方法。从前面的资料我们了解到,Servlet实例对象是用来处理HTTP请求的,这部分就是接下来要滚瓜烂熟的代码,此处先借鉴如下代码。
需要导入4个class: java.io.PrintWriter 用于输出信息、java.io.IOException 用于捕获IO异常。方法的形式参数分别时两个对象:HttpServletRequest 和 HttpServletResponse。
从此处我们可以看到,Servlet实例对象可以把前端代码也放在后端编写,JSP诞生后又产生了变化。(介绍JSP时会讲到)
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html");
// Hello
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("<h1>" + message + "</h1>");
out.println("</body></html>");
}
(6)Servlet对象的销毁阶段:public void destroy(){}
一个问题:目前可以通过@WebServlet注解修改Servlet对象的属性,那么还需要注册该Servlet对象吗?
测试:运行程序,访问刚才创建Servlet的路径/Hello2,访问成功。
结果:由此可见,Servlet 3.0以上版本中,的确不再需要在web.xml中注册Servlet对象信息,推断通过使用 javax.servlet.annotation.WebServlet
对象和注解,已经实现了对象的name、value注册。
参考
《JavaWeb学习之Servlet(一)----MyEclipse及Tomcat的配置》,对Servlet的基本概念描述得比较详细。
《JavaWeb学习之Servlet(三)----Servlet的映射匹配问题、线程安全问题》,对Servlet的映射进行了补充说明。
《Servlet的映射路径、Servlet缺省路径》,对Servlet的访问过程进行了说明。
《Java Web之Servlet入门》,生命周期图解比较奈斯。