Servlet(Ⅰ):概述以及基础

HTTP协议

概述

HTTP协议(HyperText Transfer Protocol,超文本传输协议)详细的规定了浏览器和服务器之间进行通信的规则,通过网络传输HTML文档数据的协议 。
HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果。
HTTP协议是一个应用层的协议,由请求和响应构成,一次请求一次响应。

HTTP1.0之前使用的是种短连接的方式,即限制每次连接只处理一个请求,服务器处理完成并收到浏览器的应答之后,就会断开连接。
优点:可以节省传输时间
缺点:如果客户端连接频繁,会在会话的建立和关闭上浪费时间。
HTTP1.1使用的是长连接,即当一个网页打开完成后,客户端和服务端之间传输数据时,连接不会关闭。如果客户端再次访问这个服务器上的网页,会继续使用这一条连接
优点:长连接可以省去较多的会话建立/关闭的操作,减少浪费,节省时间
缺点:随着客户的越来越多,client和server如果长时间不关闭的话,服务器迟早会无法承受,可能会损害服务器的整体性能

HTTP协议是一种无状态协议,即HTTP不会为了下一次连接,而维护本次连接所传输的数据,如果在一个网站中的多个页面间需要共享数据,可以通过Cookie和Session来实现。

Request 请求

请求是指浏览器向服务器发送的数据

请求的组成

  • 请求行:请求信息的第一行
  • 请求头:从请求信息的第二行开始到请求空行结束 。请求头包含许多有关的客户端环境和请求正文的有用信息。
  • 请求体(请求正文):请求头和请求体之间有一个空行(请求空行),它表示请求头已经结束,接下来的是请求体

常见的请求头
Accept: text/html,image/*   客户端可以接收的文档的类型
Accept-Charset: ISO-8859-1  客户端提交的表单可能使用的编码类型
Accept-Encoding: gzip    浏览器支持的编码类型
Accept-Language:zh-cn     语言环境
Host: localhost:8080     访问主机及端口号
Referer: http://www.baidu.com/index.jsp 来自哪个页面,可用于防盗链
Connection:Keep-Alive       链接状态,长链接

GET请求
请求行:
GET /HTTPTest/login?username=zhangsan&password=123456 HTTP/1.1
格式: 请求方式 /请求的URI?请求参数 协议/版本
GET请求的参数会拼接请求路径(URI)的后面,请求数据的大小有限制,无请求体
POS请求
请求行:
POST /login/login HTTP/1.1
格式: 请求方式 /请求的URI 协议/版本
POST有请求体,请求参数在请求体中,请求数据的大小无限制
请求体:
username=zhangsan&password=123456

Response 响应

响应是指在请求过后服务器向浏览器发送的数据
响应的组成:

  • 响应行:响应信息第一行
    HTTP/1.1 200 OK
    格式: 协议/版本 响应状态码 响应的描述
  • 响应头:响应信息第二行到响应空行
  • 响应体:响应空行以下

常见的响应状态码:
200 成功响应
404 请求的资源没有找到
302 重定向
500 服务器内部错误

Servlet

Servlet接口定义所有Servlet都必须实现的方法
Servlet是运行在Web服务器中的小型Java程序。Servlet通常通过 HTTP(超文本传输协议)接收和响应来自Web客户端的请求。

创建Servlet项目的步骤

定义一个类实现Servlet接口并重写其中的抽象方法

import javax.servlet.*;
import java.io.IOException;

public class MyServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("请求来了......");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

在项目的web目录下的WEB-INF目录下的web.xml文件中配置Servlet,配置如下:

<servlet>
   <!--<servlet-name>中的名称没有要求-->
    <servlet-name>myServlet</servlet-name>
    <!--<servlet-class>中需要定义的Servlet子类的全路径-->
    <servlet-class>myServletDemo1.MyServlet</servlet-class>
</servlet>
<!--配置Servlet的映射路径-->
<servlet-mapping>
    <servlet-name>myServlet</servlet-name>
    <!--Servlet的映射路径(以'/'开头),浏览器通过映射路径,可以访问到我们的Servlet-->
    <url-pattern>/demo</url-pattern>
</servlet-mapping>

在配置文件中可以配置多个Servlet子类,但是映射路径不能相同

运行项目后,会打开网页,默认打开web目录下的index.jsp这个html文件
在地址栏输入demo,就可以在网页访问我们的Servlet项目,执行service方法中的代码

原理:
当请求服务器时,服务器就会读取web.xml文件中的配置内容。通过浏览器请求的映射路径找到servlet-class中的全路径,通过反射(Class.forname方法)创建该Servlet(MyServlet)的对象,调用service方法

Servlet生命周期方法

Servlet接口定义了初始化Servlet的方法、为请求提供服务的方法和从服务器移除Servlet的方法。这些方法称为生命周期方法,它们是按以下顺序调用的:

  1. 构造Servlet,然后使用init方法将其初始化。
  2. 处理来自客户端的对service方法的所有调用。
  3. 从服务中取出Servlet,然后使用destroy方法销毁它,最后进行垃圾回收并终止它。

除了生命周期方法之外,此接口还提供了getServletConfig方法和getServletInfo方法,Servlet可使用前一种方法获得任何启动信息,而后一种方法允许Servlet返回有关其自身的基本信息,比如作者、版本和版权。

//由Servlet容器调用,指示将该Servlet放入服务。 
public void init(ServletConfig config) throws ServletException
//由Servlet容器调用,以允许Servlet响应某个请求。 
public void service(ServletRequest req, ServletResponse res) throws ServletException, java.io.IOException
//由Servlet容器调用,指示将从服务中取出该Servlet。
public void destroy()
//返回有关Servlet的信息,比如作者、版本和版权。 
public String getServletInfo()
//返回ServletConfig对象,该对象包含此Servlet的初始化和启动参数。
public ServletConfig getServletConfig()

import javax.servlet.*;
import java.io.IOException;

public class MyServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        //在init方法中进行初始化的准备工作
        //init方法只会在浏览器第一次请求实例化该Servlet对象后执行一次,当浏览器再次请求时,不会再执行
        System.out.println("init() run...");
    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        //对外提供服务的方法,每次请求都会调用该方法。在该方法中处理请求,作出响应
        System.out.println("service() run...");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {
        //Servlet销毁前,调用destroy方法,在该方法中做一些关闭资源的收尾工作
        System.out.println("destroy() run...");
    }
}

可以在配置文件中,设置init方法调用的时间

<servlet>
	<servlet-name>myServlet</servlet-name>
	<servlet-class>myServletDemo1.MyServlet</servlet-class>
	<!--设置init方法调用的时间
	    默认值为-1,代表实例化Servlet后调用
	    非负数代表在服务器开启过程中调用,数字越小,越早调用
	    如果两个配置的load-on-startup值相同,在下面的配置的Servlet的init方法先调用-->
	<load-on-startup>1</load-on-startup>
</servlet>

Servlet是单例多线程的
尽量在Servlet中定义成员变量,可能会出现线程安全问题

创建Servlet的3种方式

第一种方法:定义一个类实现Servlet接口并重写其中抽象方法,即以上的方法

第二种方法:定义一个类继承GenericServlet类,并重写抽象方法service方法。GenericServlet类实现了Servlet类,并重写了除service方法外的所有抽象方法,而我们只需要在自定义类中重写service方法

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;

public class MyServlet extends GenericServlet {
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

    }
}

第三种方法:定义一个类继承HttpServlet类。
HttpServlet类继承了GenericServlet类,在该类重写的service方法中,会获取请求方法,根据请求方法进行不同的处理,调用不同的方法,而我们只需要重写不同请求方法的处理的方法即可

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/*使用注解@WebServlet配置Servlet
name相当于<servlet-name>
value和urlPatterns相当于<url-pattern>
在注解中可以进行大部分配置*/
@WebServlet(name = "MyServlet",value = "/demo")
public class MyServlet extends HttpServlet {
    //重写doGet方法和doPost方法,分别处理Get请求和Post请求
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    	//在处理GET和POST请求时,如果处理代码相同,可以在某一个方法中只写一遍代码,在另一个方法中调用该方法
		this.doPost(request, response);
    }
}
/*value和urlPatterns是一个String类型的数组
所以一个Servlet可以由多个映射路径,用"{}"包裹,但是一个映射路径只能对应一个Servlet*/
@WebServlet(name = "MyServlet",value = {"/demo1","/demo2","/demo3"})

ServletContext

ServletContext接口定义一组方法,Servlet使用这些方法与其Servlet容器进行通信,例如,获取文件的MIME类型、分发请求或写入日志文件。
每个Java虚拟机的每个“Web 应用程序”都有一个上下文,即ServletContext对象,一个Web应用对应一个ServletContext对象,同时该对象也是一个域对象。该对象全局唯一,工程内部的所有Servlet都共享这个对象
服务器启动后,该对象被创建,服务器关闭,该对象被销毁,该对象是单例的

共享数据

作为一个全局域对象,可以在整个Web应用中共享数据

//获取ServletContext对象
ServletContext servletContext = this.getServletContext();
//getServletContext方法在底层是通过ServletConfig对象获取ServletContext对象的
public ServletContext getServletContext() {
   return this.getServletConfig().getServletContext();
}
//对于域对象,都可以使用这3个方法,用于存储、取出、删除数据
//将对象绑定到此Servlet上下文中的给定属性名称
//如果已将指定名称用于某个属性,则此方法将使用新属性替换具有该名称的属性。 
public void setAttribute(String name, Object object)
//返回具有给定名称的Servlet容器属性,如果不具有该名称的属性,则返回null
public Object getAttribute(String name)
从Servlet上下文中移除具有给定名称的属性。
public void removeAttribute(String name)
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "MyServlet1",value = "/demo1")
public class ServletDemo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext();
        //将该数据共享到MyServlet2中
        String name="abc";
        servletContext.setAttribute("name",name);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

@WebServlet(name = "MyServlet2",value = "/demo2")
public class ServletDemo2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext();
        String name = (String) servletContext.getAttribute("name");
        System.out.println(name);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

JavaWeb中有四个域对象(作用范围从大到小),之后会详细讲解,我们需要在不同情况下选择不同的域对象。
ServletContext全局域对象,作用于整个Web应用
Session会话域,作用于一次会话中
Request请求域,作用于一次请求和响应
PageContext页面域,作用于整个JSP页面

获取服务器真实路径

在Web项目的web目录下存在文件a.txt,在WEB-INF目录下存在文件b.txt,在src目录下存在文件c.txt,我们要访问这三个文件

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

@WebServlet(name = "MyServlet",value = "/demo")
public class MyServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        File file = new File("src/c.txt");
        //报异常FileNotFoundException,提示系统找不到指定的路径
        //Web项目不是本地项目,需要部署到服务器上,路径会发生改变
        FileInputStream in = new FileInputStream(file);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

@WebServlet(name = "MyServlet",value = "/demo")
public class MyServlet3 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /*项目编译过后,web目录变为项目的根目录,a.txt文件在项目根目录下
        b.txt在项目根目录的WEB-INF目录下
        src目录变为WEB-INF目录下的classes目录,c.txt在classes目录下*/ 
        ServletContext servletContext = this.getServletContext();
        /*为给定虚拟路径返回包含实际路径的 String
        public String getRealPath(String path)*/
        //动态获取当前项目的真实路径,"/"代表当前项目的根目录的虚拟路径        				
        String realPath = servletContext.getRealPath("/");
        //E:\MyProject\servletdemo\out\artifacts\servletdemo_war_exploded\
        System.out.println(realPath);
        //通过拼串的方式访问这些文件
        FileInputStream in1 = new FileInputStream(new File(realPath+"a.txt"));
        FileInputStream in2 = new FileInputStream( new File(realPath+"WEB-INF/b.txt"));
        FileInputStream in3 = new FileInputStream( new File(realPath+"WEB-INF/classes/c.txt"));     
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

Web项目发布后,项目可以放到到tomcat文件下的webapps目录下
也可以放在任意目录下,但是要在tomcat文件下的conf/server.xml下的Host标签下配置
或者在tomcat/conf/Catalina(引擎目录)/localhost(主机目录)下新建一个xml文件配置
配置语句如下:

<Context path="/项目名" docBase="项目的磁盘目录"/>

所以在访问项目中的文件时,要通过getRealPath方法动态获取真实路径。

在Web项目中普通类读取src下的文件

//返回该类的类加载器
public ClassLoader getClassLoader()
//返回读取指定资源的输入流
public InputStream getResourceAsStream(String name)
import java.io.InputStream;

public class Demo {
    public static void main(String[] args) {
    //直接输入资源名称"c.txt",获取src目录下的文件
        InputStream in = Demo.class.getClassLoader().getResourceAsStream("c.txt");
    }
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值