Web环境搭建以及Servlet入门

129 阅读17分钟

在这里插入图片描述
**正文开始 **

学习目标

  • 理解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 访问别人

显示如下界面表示成功

启动时可能遇到的问题

  1. 黑窗口一闪而过:

    1. 原因: 没有正确配置JAVA_HOME环境变量
    2. 解决方案:正确配置JAVA_HOME环境变量
  2. 端口号被占用:

    1. 暴力解决:找到占用的端口号,并且找到对应的进程,杀死该进程

      1. 使用命令netstat –ano|findstr [指定端口号]找到占用端口的进程
      2. 打开任务管理器->查看->选择列->然后勾选PID选项,回到任务管理器上可以查看到对应的pid,然后结束进程
  3. 温柔解决:修改自身的端口号

在conf/server.xml 配置文件中修改

<Connector port="8888" protocol="HTTP/1.1"
	    connectionTimeout="20000"
   	    redirectPort="8445" />

一般会将tomcat的默认端口号修改为80。80端口号是http协议的默认端口号。

好处:在访问时,就不用输入端口号

2.3.5 关闭
  • 正常关闭:

    • bin/shutdown.bat
    • ctrl+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 ----->

image-20220819172013846

开始创建Web项目

image-20220819172350009

**右键添加Web框架依赖 **

image-20220819172544437 image-20220819172629012

3.2 IDEA配置Tomcat

tomcat详细配置

image-20220819220432972

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个步骤:

  1. 编写一个Java类,实现Servlet接口。
  2. 把开发好的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对象和请求路径之间的关系
  • image-20220819233802399 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>

image-20220819233342293

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方法。
  • 用户继续发送第二次请求,控制台输出了以下内容:

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”。

  1. 创建JavaEE项目

  2. 定义一个类,实现Servlet接口

    • public class Demo1Servlet implements Servlet
  3. 实现接口中的抽象方法

    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");
    	}	
    
    }
    
  4. 在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>
    
  5. 运行效果

    6.Servlet执行原理

4.3 Servlet3.0 注解配置

Servlet3.0开始支持注解配置,通过WebServlet注解来实现映射,web.xml不再是必需的组件。

步骤:

  1. 创建JavaEE项目,选择Servlet的版本3.0以上,可以不创建web.xml

  2. 定义一个类,实现Servlet接口

  3. 复写方法

  4. 在类上使用@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协议的一种封装,简化操作 (我们一般使用这个)

    1. 定义类继承HttpServlet
    2. 复写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。