**正文开始 **
学习目标
- 理解WEB相关概念和WEB服务器概念
- 会安装、卸载、启动和关闭tomcat
- 掌握使用tomcat部署项目
- 了解Servlet概念
- 掌握Servlet的执行原理和生命周期
- 掌握Servlet的体系结构,了解其他Servlet配置
- 掌握Servlet3.0注解配置
一 、Web相关概念
1.1 软件架构
WEB:在英语中web即表示网页的意思,它用于表示Internet主机上供外界访问的资源。
JavaWeb:使用Java语言开发基于互联网的项目
1.1.1 软件架构:
1.1.2 软件架构详解:
-
C/S: Client/Server 客户端/服务器端
-
在用户本地有一个客户端程序,在远程有一个服务器端程序
- 如:QQ,迅雷…
-
特点:
- 充分发挥客户端PC的处理能力,很多数据可以通过客户端的处理后再发给服务器,降低了服务器的负荷,提高了速度。但维护和升级比较复杂,维护和升级是针对成千上万的客户机的。
- 必须安装专用的客户端软件。客户端是成千上万的,要安装专用软件,是多么大的工作量,如果一台客户机出现了问题,如:感染病毒、计算机故障等等原因,都需要进行安装或维护。系统软件需要升级的时候,每一台客户机都需要重新安装系统软件,维护和升级成本相当的高。
- 对客户机的操作系统有限制,对一些操作系统和新开发的操作系统不兼容。目前产品更新换代十分的快,要针对不同的操作系统系统版本开发不同的客户机软件,对成本而言是相当大。
-
-
B/S: Browser/Server 浏览器/服务器端
-
只需要一个浏览器,用户通过不同的网址(URL),客户访问不同的服务器端程序
- 如:淘宝,京东…
-
特点:
- 维护和升级简单,我们只要对服务器端进行维护和升级即可,不需要对成千上万的客服端进行维护和升级,减少了人力资源成本。
- 随时随地都可以访问,只要有一台连接互联网和安装了浏览器的计算机就可以访问。
- 减轻了客户端电脑载荷,客户端电脑只要运行少部分程序就能实现。因此对客服端电脑要求不高,对服务器端负荷较重,由于主要的功能都集中到了服务器端,因此对服务器要求高,但总体而言,还是大大降低了成本。
-
-
总结:B/S对C/S而言,B/S具有的优势。
- 分布性:可以随时随地进行查询和浏览等业务;
- 功能业务扩展比较方便:增加服务器的功能,就能增加浏览器端的功能;
- 维护简单方便:改变服务器端数据即可以实现所有用户同步更新;
- 开发简单,共享性强,成本低,数据可以持久存储在服务器端而不必担心数据的丢失。
1.2 Web资源分类
-
静态资源:
-
使用静态网页开发技术发布的资源
-
特点:
-
所有用户访问,得到的结果是一样的
- 如:文本,图片,音频、视频,
HTML,CSS,JavaScript
- 如:文本,图片,音频、视频,
-
如果用户请求的是静态资源,那么服务器会直接将静态资源发送给浏览器。浏览器中内置了静态资源的解析引擎,可以展示静态资源
-
-
-
动态资源:
-
使用动态网页技术发布的资源
-
特点:
-
所有用户访问,得到的结果可能不一样
- 如:
jsp/servlet,php,asp...
- 如:
-
如果用户请求的是动态资源,那么服务器会执行动态资源,转换为静态资源,再发送给浏览器
-
-
1.3 网络通信三要素
IP:电子设备(计算机)在网络中的唯一标识
端口:应用程序在计算机中的唯一标识。 0~65536
传输协议:规定了数据传输的规则
-
基础协议:
- tcp:安全协议,三次握手。 速度稍慢
- udp:不安全协议。 速度快
-
高级协议
-
http协议
- 基于TCP/IP的高级协议
- 基于请求/响应模型的:一次请求对应一次响应
-
1.4 Web资源请求响应过程
二、Web服务器软件
2.1 web服务器软件概念
服务器:安装了服务器软件的计算机。
服务器软件:接收用户的请求,处理请求,做出响应。
web服务器软件:接收用户的请求,处理请求,做出响应。
在web服务器软件中,可以部署web项目,让用户通过浏览器来访问这些项目。
疑问:学习web开发,为什么必须要先装一个WEB服务器 ?
2.2 常见的web服务器软件:
- webLogic:oracle公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
- webSphere:IBM公司, 大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
- JBOSS:JBOSS公司的,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
- Tomcat:Apache基金组织,中小型的JavaEE服务器,仅仅支持少量的JavaEE规范servlet/jsp。开源的,免费的。
2.3 Tomcat:web服务器软件
Tomcat免费的Web服务器,该服务器支持全部JSP以及Servlet规范,也是我们学习javaweb所使用的服务器,所以我们有必要深入了解;
2.3.1 下载
可以直接在官网下载:tomcat.apache.org/
2.3.2 安装
解压压缩包即可。
注意:安装目录建议不要有中文和空格,解压的目录结构如下图
2.3.3 卸载
删除目录就行了
2.3.4 启动
bin/startup.bat ,双击运行该文件即可
访问:浏览器输入:http://localhost:8080 回车访问自己
http://别人的ip:8080 访问别人
显示如下界面表示成功
启动时可能遇到的问题:
-
黑窗口一闪而过:
- 原因: 没有正确配置JAVA_HOME环境变量
- 解决方案:正确配置JAVA_HOME环境变量
-
端口号被占用:
-
暴力解决:找到占用的端口号,并且找到对应的进程,杀死该进程
- 使用命令
netstat –ano|findstr [指定端口号]找到占用端口的进程 - 打开任务管理器->查看->选择列->然后勾选PID选项,回到任务管理器上可以查看到对应的pid,然后结束进程
- 使用命令
-
-
温柔解决:修改自身的端口号
在conf/server.xml 配置文件中修改
<Connector port="8888" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8445" />
一般会将tomcat的默认端口号修改为80。80端口号是http协议的默认端口号。
好处:在访问时,就不用输入端口号
2.3.5 关闭
-
正常关闭:
bin/shutdown.batctrl+c
-
强制关闭:
- 点击启动窗口的
×
- 点击启动窗口的
2.3.6 Tomcat项目部署 (虚拟目录映射)
Web应用开发好后,若想供外界访问,需要把web应用所在目录交给web服务器管理,这个过程称之为项目部署(虚拟目录的映射)。
-
配置
conf/server.xml文件, 在<Host>标签体中加入子标签配置<!--<Context path="虚拟路径" docBase ="物理路径" />--> <Context docBase="D:\hello" path="/xixi" />docBase:项目存放的路径path:虚拟目录
-
直接将项目放到webapps目录下即可
/hello:项目的访问路径–>虚拟目录- 简化部署:将项目打成一个war包,再将war包放置到webapps目录下。 war包会自动解压缩。
三、使用IDEA开发Web应用程序
3.1 创建Web项目
File -----> New -----> Project ----->
开始创建Web项目
**右键添加Web框架依赖 **
3.2 IDEA配置Tomcat
tomcat详细配置
3.3 JavaWeb应用目录结构
开发web应用时,不同类型的文件有严格的存放规则,否则不仅可能会使web应用无法访问,还会导致web服务器启动报错
web应用中,web.xml文件是其中最重要的一个文件,它用于对web应用中的web资源进行配置。
但是在servlet3.0以后支持使用@Webservlet编程,进一步简化了JavaWeb开发。
四、Servlet
4.1 什么是Servlet?
Servlet是一门用于开发动态web资源的技术,它是运行在服务器端的小程序。
Servlet就是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则。
作用:Servlet主要用于处理客户端传来的HTTP请求,并返回一个响应,它能够处理的请求有doGet()和doPost()等方法。
用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
- 编写一个Java类,实现Servlet接口。
- 把开发好的Java类部署到web服务器中。
4.2什么是Servlet对象的生命周期
- Servlet对象什么时候被创建。
- Servlet对象什么时候被销毁。
- Servlet对象创建了几个?
- Servlet对象的生命周期表示:一个Servlet对象从出生在最后的死亡,整个过程是怎样的。
我们不需要在程序创建Servlet的对象,也没有去调用对象上的方法。Servlet对象的生命周期由web服务器负责
Servlet对象是由谁来维护的?
- Servlet对象的创建,对象上方法的调用,对象最终的销毁,Javaweb程序员是无权干预的。
- Servlet对象的生命周期是由Tomcat服务器(WEB Server)全权负责的。
- Tomcat服务器通常我们又称为:WEB容器。(这个叫法你要知道【WEB Container】)
- WEB容器来管理Servlet对象的死活。
思考:我们自己new的Servlet对象受WEB容器的管理吗?
- 我们自己new的Servlet对象是不受WEB容器管理的。
- WEB容器创建的Servlet对象,这些Servlet对象都会被放到一个集合当中(HashMap),只有放到这个HashMap集合中的Servlet才能够被WEB容器管理,自己new的Servlet对象不会被WEB容器管理。(自己new的Servlet对象不在容器当中)
- web容器底层应该有一个HashMap这样的集合,在这个集合当中存储了Servlet对象和请求路径之间的关系
key对应请求路径,value对应我们写的servlet程序
研究:服务器在启动的Servlet对象有没有被创建出来(默认情况下)?
- 在Servlet中提供一个无参数的构造方法,启动服务器的时候看看构造方法是否执行。
- 经过测试得出结论:默认情况下,服务器在启动的时候Servlet对象并不会被实例化。
- 这个设计是合理的。用户没有发送请求之前,如果提前创建出来所有的Servlet对象,必然是耗费内存的,并且创建出来的Servlet如果一直没有用户访问,显然这个Servlet对象是一个废物,没必要先创建。
- 怎么让服务器启动的时候创建Servlet对象呢?
- 在servlet标签中添加子标签,在该子标签中填写整数,越小的整数优先级越高。我写负数时,测试出来也不会创建对象
<servlet>
<servlet-name>aservlet</servlet-name>
<servlet-class>com.bjpowernode.javaweb.servlet.AServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>aservlet</servlet-name>
<url-pattern>/a</url-pattern>
</servlet-mapping>
Servlet对象生命周期
- 默认情况下服务器启动的时候AServlet对象并没有被实例化
- 下面这个是我用来测试Servlet生命周期写的
public class AServlet implements Servlet {
public AServlet() {
System.out.println("AServlet无参数构造方法执行了");
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("AServlet's init method execute!");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("AServlet's service method execute!");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
System.out.println("AServlet's destroy method execute!");
}
- 用户发送第一次请求的时候,控制台输出了以下内容:
AServlet无参数构造方法执行了
AServlet's init method execute!
AServlet's service method execute!
-
根据以上输出内容得出结论:
- 用户在发送第一次请求的时候Servlet对象被实例化(AServlet的构造方法被执行了。并且执行的是无参数构造方法。)
- AServlet对象被创建出来之后,Tomcat服务器马上调用了AServlet对象的init方法。(init方法在执行的时候,AServlet对象已经存在了。已经被创建出来了。) - 用户发送第一次请求的时候,init方法执行之后,Tomcat服务器马上调用AServlet对象的service方法。
- 用户在发送第一次请求的时候Servlet对象被实例化(AServlet的构造方法被执行了。并且执行的是无参数构造方法。)
-
用户继续发送第二次请求,控制台输出了以下内容:
AServlet's service method execute!
-
根据以上输出结果得知,用户在发送第二次,或者第三次,或者第四次请求的时候,Servlet对象并没有新建,还是使用之前创建好的Servlet对象,直接调用该Servlet对象的service方法,这说明:
- 第一:Servlet对象是单例的(单实例的。)(但是要注意:Servlet对象是单实例的,但是Servlet类并不符合单例模式。我们称之为假单例。之所以单例是因为Servlet对象的创建我们javaweb程序员管不着,这个对象的创建只能是Tomcat来说了算,Tomcat只创建了一个,所以导致了单例,但是属于假单例。真单例模式,构造方法是私有化的。)
- 第二:无参数构造方法、init方法只在第一次用户发送请求的时候执行。也就是说无参数构造方法只执行一次。init方法也只被Tomcat服务器调用一次。
- 第三:只要用户发送一次请求:service方法必然会被Tomcat服务器调用一次。发送100次请求,service方法会被调用100次。
-
关闭服务器的时候,控制台输出了以下内容:
AServlet's destroy method execute
-
通过以上输出内容,可以得出以下结论:
-
Servlet的destroy方法只被Tomcat服务器调用一次。
-
destroy方法是在什么时候被调用的?
- 在服务器关闭的时候。
- 因为服务器关闭的时候要销毁AServlet对象的内存。
- 服务器在销毁AServlet对象内存之前,Tomcat服务器会自动调用AServlet对象的destroy方法。
-
-
请问:destroy方法调用的时候,对象销毁了还是没有销毁呢?
- destroy方法执行的时候AServlet对象还在,没有被销毁。destroy方法执行结束之后,AServlet对象的内存才会被Tomcat释放。因为destroy方法不是静态方法,它是实例方法,需要有对象才能调用。
-
Servlet对象更像一个人的一生:
- Servlet的无参数构造方法执行:标志着你出生了。
- Servlet对象的init方法的执行:标志着你正在接受教育。
- Servlet对象的service方法的执行:标志着你已经开始工作了,已经开始为人类提供服务了。
- Servlet对象的destroy方法的执行:标志着临终。有什么遗言,抓紧的。要不然,来不及了。
-
关于Servlet类中方法的调用次数?
- 构造方法只执行一次。
- init方法只执行一次。
- service方法:用户发送一次请求则执行一次,发送N次请求则执行N次。
- destroy方法只执行一次。
-
当我们Servlet类中编写一个有参数的构造方法,如果没有手动编写无参数构造方法会出现什么问题?
- 报错了:500错误。
- 注意:500是一个HTTP协议的错误状态码。
- 500一般情况下是因为服务器端的Java程序出现了异常。(服务器端的错误都是500错误:服务器内部错误。)
- 如果没有无参数的构造方法,会导致出现500错误,无法实例化Servlet对象。
- 所以,一定要注意:在Servlet开发当中,不建议程序员来定义构造方法,因为定义不当,一不小心就会导致无法实例化Servlet对象。
-
思考:Servlet的无参数构造方法是在对象第一次创建的时候执行,并且只执行一次。init方法也是在对象第一次创建的时候执行,并且只执行一次。那么这个无参数构造方法可以代替掉init方法吗?
- 不能。
- Servlet规范中有要求,作为javaweb程序员,编写Servlet类的时候,不建议手动编写构造方法,因为编写构造方法,很容易让无参数构造方法消失,这个操作可能会导致Servlet对象无法实例化。所以init方法是有存在的必要的。
-
init、service、destroy方法中使用最多的是哪个方法?
- 使用最多就是service方法,service方法是一定要实现的,因为service方法是处理用户请求的核心方法。
什么时候使用init方法呢?
-
init方法很少用。
-
通常在init方法当中做初始化操作,并且这个初始化操作只需要执行一次。例如:初始化数据库连接池,初始化线程池… 我们就想想什么样的代码只执行一次,并且在对象创建后执行
-
什么时候使用destroy方法呢?
- destroy方法也很少用。
- 通常在destroy方法当中,进行资源的关闭。马上对象要被销毁了,还有什么没有关闭的,抓紧时间关闭资源。还有什么资源没保存的,抓紧时间保存一下。
看完后,再来复习一下
4.2 Servlet快速入门
案例2:
快速入门,用Servlet向浏览器输出“hello servlet”。
-
创建JavaEE项目
-
定义一个类,实现Servlet接口
- public class Demo1Servlet implements Servlet
-
实现接口中的抽象方法
package com.bailiban.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; /* * Servlet快速入门 * 定义一个类实现Servlet接口 */ public class Demo1Servlet implements Servlet{ @Override public void destroy() { // TODO Auto-generated method stub } @Override public ServletConfig getServletConfig() { // TODO Auto-generated method stub return null; } @Override public String getServletInfo() { // TODO Auto-generated method stub return null; } @Override public void init(ServletConfig config) throws ServletException { // TODO Auto-generated method stub } //提供服务的方法 @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { //向控制台输出一句话 System.out.println("Hello Servlet"); //得到输出对象 PrintWriter out = res.getWriter(); //向浏览器输出信息 out.write("Hello Servlet"); } } -
在web.xml中配置Servlet
<!--配置Servlet --> <servlet> <servlet-name>demo1</servlet-name> <servlet-class>cn.hp.servlet.Demo1Servlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>demo1</servlet-name> <url-pattern>/demo1</url-pattern> </servlet-mapping> -
运行效果
6.Servlet执行原理
4.3 Servlet3.0 注解配置
Servlet3.0开始支持注解配置,通过WebServlet注解来实现映射,web.xml不再是必需的组件。
步骤:
-
创建JavaEE项目,选择Servlet的版本3.0以上,可以不创建web.xml
-
定义一个类,实现Servlet接口
-
复写方法
-
在类上使用
@WebServlet注解,进行配置@WebServlet("资源路径")
下面是@WebServlet的源码实现
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebServlet {
String name() default "";//相当于<Servlet-name>
String[] value() default {};//代表urlPatterns()属性配置
String[] urlPatterns() default {};//相当于<url-pattern>
int loadOnStartup() default -1;//相当于<load-on-startup>
WebInitParam[] initParams() default {};
boolean asyncSupported() default false;
String smallIcon() default "";
String largeIcon() default "";
String description() default "";
String displayName() default "";
}
4.3 Servlet体系结构
Servlet– 接口
|
GenericServlet – 抽象类
|
HttpServlet – 抽象类
-
GenericServlet:将Servlet接口中其他的方法做了默认空实现,只将service()方法作为抽象
- 定义Servlet类时,可以继承GenericServlet,实现service()方法即可
package com.bailiban.servlet; import java.io.IOException; import javax.servlet.GenericServlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebServlet; /* * 继承 GenericServlet 方式 创建Servlet */ @WebServlet("/demo1") public class Demo1Servlet extends GenericServlet { @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { System.out.println("继承 GenericServlet 方式 创建Servlet"); } } -
HttpServlet:对http协议的一种封装,简化操作 (我们一般使用这个)
- 定义类继承HttpServlet
- 复写doGet/doPost方法
package com.bailiban.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 继承 HttpServlet方式创建servlet */ @WebServlet("/demo2") public class Demo2Servlet extends HttpServlet { private static final long serialVersionUID = 1L; //如果请求方式为get执行该方法 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("get方式~~~~~"); } //如果请求方式为post执行该方法 @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("post方式~~~~~"); } }
案例4:
分别以继承GenericServlet和HttpServlet方式 创建Servlet。