Servlet的具体使用方式以及http协议

Servlet的具体使用方式以及http协议_第1张图片

一、Servlet概述

Servlet 是Java Server Applet的简称,称为小服务器程序,用Java编写的服务器端程序,主要功能交互式地浏览和修改数据,生成动态Web内容。

Servlet运行于支持Java的应用服务器中。从实现上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。

Servlet编程需要使用到javax.servlet 和 javax.servlet.http两个包下面的类和接口,在所有的类和接口中,javax.servlet.Servlet 接口最为重要。所有的servlet程序都必须实现该接口或者继承实现了该接口的类。javax.servlet.ServletConfig;
javax.servlet.ServletException;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
javax.servlet.http.HttpSession;
javax.servlet.http.Cookie

二、Servlet使用,两种方式

2.1 继承HttpServlet

GenericServlet抽象类,实现了 Servlet, ServletConfig, Serializable三个接口,使编写 servlet 变得更容易。它提供生命周期方法 init 和 destroy 的简单实现,要编写一般的 servlet,只需重写抽象service 方法即可。

HttpServlet类,是【继承GenericServlet的基础上进一步的扩展】,提供将要被子类化以创建适用于 Web 站点的 HTTP servlet 的抽象类。HttpServlet 的子类至少必须重写一个方法,该方法通常是以下这些方法之一:

doGet,如果 servlet 支持 HTTP GET 请求
doPost,用于 HTTP POST 请求
doPut,用于 HTTP PUT 请求
doDelete,用于 HTTP DELETE 请求
init 和 destroy,用于管理 servlet 的生命周期内保存的资源 ,当服务器关闭,执行destroy方法
getServletInfo,servlet 使用它提供有关其自身的信息

一般我们只需要重写doPost和doGet方法即可。

具体步骤

1. 新建servlet类,直接右键新建

Servlet的具体使用方式以及http协议_第2张图片

2. 在doGet方法里面调用doPost方法
@WebServlet(name = "MyServlet",value = "myservlet")
public class MyServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	//在doGet方法里面调用doPost方法
        doPost(request, response);
    }
}
3. 设置编码

web开发出现乱码的问题主要是两个地方:一个是从浏览器表单中接收的数据,一个是服务器向浏览器发送的数据。

接收数据

接收数据使用的是【getParameter】方法,要在doPost方法内书写。

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	String request.getParameter(String var1);	//var1是前端的变量名,或者表单的name, 返回的是value值
	String[] getParameterValues(String var1);	//返回的是数组,一般用于表单的多项选择,获取值
}

但是从前端获取的是utf-8编码的value,而服务器的request对象使用的是ISO8859-1(西欧编码集)这个字符编码来接收数据,浏览器和服务器沟通的编码不一致因此才会产生中文乱码的,所以使用【setCharacterEncoding】方法设置request编码

request.setCharacterEncoding("utf-8");

向浏览器响应数据
服务器向浏览器进行数据反馈响应,使用的是字节流和字符流的方法。
注意:字节流和字符流方法,只能二选一,不可同时用,一般传输音频、视频等需要字节流,文本使用字符流

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	PrintWriter writer = response.getWriter();//字符流
	ServletOutputStream os = response.getOutputStream();//字节流
}

这样输出的结果是乱码,浏览器识别不到返回的中文是什么编码格式,就会默认使用GB2312,如果返回的是UTF-8格式的那么在浏览器上就会显示乱码的问题,问题出在浏览器上。需要使用【setContentType】方法设置response编码

//设置响应内容类型及编码,在响应报文中添加一个响应头 content-type:text/html;charset=utf-8
response.setContentType("text/html;charset=utf-8");
4. 给servlet配置url【核心】

必须配置servlet的url,用于html表单里面的【action】属性。
配置方式主要有两种:一种是注解,一种是配置WEB-INF下的【web.xml】文件

注解配置

注解类 【@WebServlet】,放到Servlet类的上面,主要属性:

name:serlvet名字 (可选)
value: 配置url路径,必须配置,value是数组,可以匹配多个url
urlPatterns:配置url路径 ,数组,可以匹配多个url,和value作用一样,不能同时使用
loadOnStartup:配置Servlet的创建的时机, 如果是0或者正数 启动程序时创建,如果是负数,则浏览器访问时创建,数子越小优先级越高,主要用于【init】方法
initParams:配置Servlet的初始化参数,可以在【init】方法中调取

Servlet中的url路径,共有四种方式:

注意有精确匹配优先精确匹配,否则模糊匹配

  1. 精确匹配:只有url路径是具体的名称的时候才会触发Servlet。
//必须有斜杠
@WebServlet(name = "MyServlet5",value = "/myservlet5")
  1. 模糊匹配——后缀匹配,只要是以某一后缀结尾的都可以运行
@WebServlet(name = "MyServlet4",urlPatterns = "*.do")
  1. 模糊匹配——通配符匹配
/*匹配所有请求,包含服务器的所有资源,但会导致静态网页html和jsp无法访问*/
@WebServlet(name = "MyServlet4",urlPatterns = "/*")

/*匹配所有请求,包含服务器的所有资源,不包括.jsp,但会导致静态网页html无法访问*/
@WebServlet(name = "MyServlet4",urlPatterns = "/")

/*可以参考D:\TomCat\apache-tomcat-8.5.45\conf\web.xml下的官方web.xml文件*/
/*对于导致静态网页html无法访问的问题,可以通过配置web.xml文件来解决,*/
/*配置默认类,然后在映射中使用通配符【*.html】来给html文件放行,从而可以访问*/
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    /*添加servlet节点*/
    <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    </servlet>

    /*添加servlet-mapping节点*/
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>
</web-app>

在html静态网页文件的form表单中的url路径书写格式

<body>
    <h2>用户信息h2>
    
    
    
    <form action="myservlet5" method="post" enctype="application/x-www-form-urlencoded">
        姓名<input type="text" name="username"><br/>
        年龄<input type="text" name="age"><br/>
        地址<input type="text" name="address"><br/>
        <input type="submit" value="提交"><br/>
    form>
body>

关于【initParams】属性
可以在注解中设置参数,然后在init方法内调用,该属性是数组,可以传入多个参数,传参数需要再调用【@WebInitParam】注解

@WebServlet(value = "/myservlet",initParams = {@WebInitParam(name = "username", value = "张三"), @WebInitParam(name = "age", value = "20")})
public class MyServlet extends HttpServlet {
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        String username = config.getInitParameter("username");
        String age = config.getInitParameter("age");
        System.out.println("姓名:" + username + ",年龄:" + age);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("我的servlet......");
    }
}
web.xml文件配置

除了注解的方式,还有一种常用方式是通过配置【WEB-INF】下的【web.xml】文件,分为两个步骤,一个是添加servlet类节点,找到类位置,执行servlet类方法;一个是添加servlet-mapping映射节点,设置url路径,保证浏览器可以访问。
注意:1.两个步骤的【servlet-name】必须一致;2. 在【】标签【内】中添加配置


<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    
    <servlet>
        <servlet-name>myservlet3servlet-name>
        <servlet-class>com.servlet.MyServlet3servlet-class>
        
        <init-param>
            <param-name>nameparam-name>
            <param-value>李四param-value>
        init-param>
        <init-param>
            <param-name>addressparam-name>
            <param-value>北京param-value>
        init-param>
        
        <load-on-startup>1load-on-startup>
    servlet>

    
    <servlet-mapping>
        <servlet-name>myservlet3servlet-name>
        <url-pattern>/myservlet3url-pattern>
    servlet-mapping>
web-app>
5. 重新部署,启动

2.2 遵从Servlet接口,实现各方法

与继承的方法基本一致,但是需要实现多个方法,比较麻烦。

@WebServlet(name = "MyServlet2",urlPatterns = "/myservlet2",loadOnStartup = 0,
        initParams = {@WebInitParam(name = "username", value = "张三"),@WebInitParam(name = "age", value = "20")})
public class Myservlet2 implements Servlet {
    //注解:初始化servlet,loadOnStartup为-1,表示浏览器访问的时候初始化,0或正数表示创建的时候初始化
    //注解:initParams 初始化数组
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("初始化servlet:init");
        //获取注解中的initParams初始化数组中的参数
        String username = servletConfig.getInitParameter("username");
        String age = servletConfig.getInitParameter("age");
        System.out.println("姓名:" + username + ",年龄" + age);
    }

    //获取servlet配置
    @Override
    public ServletConfig getServletConfig() {
        System.out.println("获取servlet配置");
        return null;
    }

    //服务方法,处理请求的方法,相当于doPost和doGet
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("服务方法执行:service()");
    }

    //获取servlet基本信息
    @Override
    public String getServletInfo() {
        System.out.println("获取servlet基本信息:作者、版权等");
        return null;
    }

    //销毁
    @Override
    public void destroy() {
        System.out.println("servlet销毁,当服务器停止的时候调用");
    }
}

servlet可以获取浏览器表单数据,然后再利用数据库操作,可以将表单数据导入数据库,完成前后端的合并。

//激活码工具
public class ActiveCodeUtils {
	public static String createActiveCode() {
		Date date=new Date();
		SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmssSSS");
		String s1=sdf.format(date);
		String s2=Integer.toHexString(new Random().nextInt(900)+100);
		return s1+s2;
	}
}

三、Servlet使用常见问题

3.1 线程安全问题

因为每次请求都会创建一个线程,如果多人同时请求,那么就会存在多个线程操作同一个Servlet对象,那么如果在对应的方法中操作了成员变量,就有可能产生线程安全的问题。‘’

解决办法:

  1. synchronized:将存在线程安全问题的代码放到同步代码块中
  2. 尽可能只使用局部变量

3.2 常见错误解决方法

  1. 404问题
    一般是地址输入有误,检查静态页面和servlet类中地址是否有书写错误
  2. HTTP Status 404 资源找不到
    (1)查看Out目录下的WEB-INF下的classes内能否找到刚刚的class文件,如果有,重新启动Tomcat,如果没有,删除out文件,重新运行。
    (2)查看Tomcat的webapps目录下找到当前项目在WEB-INF下的classes内能否找到刚刚的class文件,如果有,重新启动Tomcat,如果没有,在Eclipse中选择Project–>clean让Eclipse清空缓存并重新构建项目,再次运行
  3. 报错只查看Caused by从下往上看
    (1)are both mapped to the url-pattern[/helloservlet]两个类同时映射,说明注解处地址重复
    (2)Invalid 说明注解处地址没有加斜杠
    (3)Both the urlPatterns and value attributes were set for the WebServlet 地址重复,value和urlPattern二选一

四、Servlet生命周期

阶段一、实例化(调用构造方法)

实例化阶段是Servlet生命周期中的第一步,由Servlet容器调用Servlet的构造器创建一个具体的Servlet对象的过程。而这个创建的时机可以是在容器收到针对这个组件的请求之后,即用了才创建;也可以在容器启动之后立刻创建实例,而不管此时Servlet是否使用的上。使用如下代码可以设置Servlet是否在服务器启动时就执行创建
1

阶段二、初始化(init方法)

Servlet在被加载实例化之后,必须要初始化它。在初始化阶段,init()方法会被调用。这个方法在javax.servlet.Servlet接口中定义。其中,方法以一个ServletConfig类型的对象作为参数。ServletConfig对象由Servlet引擎负责创建,从中可以读取到事先在web.xml文件中通过节点配置的多个name-value名值对。ServletConfig对象还可以让Servlet接受一个ServletContext对象。
一般情况下,init方法不需要编写,因GenericServlet已经提供了init方法的实现,并且提供了getServletConfig方法来获得ServletConfig对象。
注:init方法只被执行一次

阶段三、就绪/服务

Servlet被初始化以后就处于能够响应请求的就绪状态。每个对Servlet的请求由一个ServletRequest对象代表,Servlet给客户端的响应由一个ServletResponse对象代表。当客户端有一个请求时,容器就会将请求与响应对象转给Servlet,以参数的形式传给service方法。service方法由javax.servlet.Servlet定义,由具体的Servlet实现
HttpServlet将service方法拆分了。doGet和doPost

阶段四、销毁

Servlet容器在销毁Servlet对象时会调用destroy方法来释放资源。通常情况下Servlet容器停止或者重新启动都会引起销毁Servlet对象的动作,但除此之外,Servlet容器也有自身管理Servlet对象的准则,整个生命周期并不需要人为进行干预

五、关于http

5.1什么是HTTP协议

超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议,是一个基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式。

HTTP协议的主要特点如下
1.支持客户端/服务器模式。
2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
3.灵活:HTTP允许传输任意类型的数据对象。传输的类型由Content-Type加以标记。
4.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
5.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

Http协议的通信
HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤:
1、 建立TCP连接
在HTTP工作开始之前,Web浏览器首先要通过网络与Web服务器建立连接,该连接是通过TCP来完成的,该协议与IP协议共同构建Internet,即著名的TCP/IP协议族,因此Internet又被称作是TCP/IP网络。HTTP是比TCP更高层次的应用层协议,根据规则,只有低层协议建立之后才能进行更高层协议的连接。因此,首先要建立TCP连接,一般TCP连接的端口号是80
2、 浏览器向Web服务器发送请求命令
一旦建立了TCP连接,Web浏览器就会向Web服务器发送请求命令
例如:GET /sample/hello.html HTTP/1.1
3、 浏览器发送请求头信息
浏览器发送其请求命令之后,还要以头信息的形式向Web服务器发送一些别的信息,之后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送。
4、 Web服务器应答
客户机向服务器发出请求后,服务器会客户机回送应答,
HTTP/1.1 200 OK
应答的第一部分是协议的版本号和应答状态码
5、 Web服务器发送应答头信息
正如客户端会随同请求发送关于自身的信息一样,服务器也会随同应答向用户发送关于它自己的数据及被请求的文档。
6、 Web服务器向浏览器发送数据
Web服务器向浏览器发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据
7、 Web服务器关闭TCP连接
一般情况下,一旦Web服务器向浏览器发送了请求数据,它就要关闭TCP连接,然后如果浏览器或者服务器在其头信息加入了这行代码
Connection:keep-alive
TCP连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽

5.2 请求报文和响应报文

关于http协议问题,参考文章《HTTP请求报文和HTTP响应报文》——华山大师兄

HTTP请求报文和响应报文
HTTP请求报文 包括 请求行 请求头 空行 请求体
HTTP响应报文 包括 状态行、消息报头、空行、响应正文。

请求头
accept:浏览器通过这个头告诉服务器,它所支持的数据类型
Accept-Charset: 浏览器通过这个头告诉服务器,它支持哪种字符集
Accept-Encoding:浏览器通过这个头告诉服务器,支持的压缩格式
Accept-Language:浏览器通过这个头告诉服务器,它的语言环境
Host:浏览器通过这个头告诉服务器,想访问哪台主机
If-Modified-Since: 浏览器通过这个头告诉服务器,缓存数据的时间
Referer:浏览器通过这个头告诉服务器,客户机是哪个页面来的 防盗链
Connection:浏览器通过这个头告诉服务器,请求完后是断开链接还是保持链接

响应头
Location: 服务器通过这个头,来告诉浏览器跳到哪里 重定向
Server:服务器通过这个头,告诉浏览器服务器的型号
Content-Encoding:服务器通过这个头,告诉浏览器,数据的压缩格式
Content-Length: 服务器通过这个头,告诉浏览器回送数据的长度
Content-Language: 服务器通过这个头,告诉浏览器语言环境
Content-Type:服务器通过这个头,告诉浏览器回送数据的类型
Refresh:服务器通过这个头,告诉浏览器定时刷新
Content-Disposition: 服务器通过这个头,告诉浏览器以下载方式打数据
Transfer-Encoding:服务器通过这个头,告诉浏览器数据是以分块方式回送的
Expires: -1 控制浏览器不要缓存
Cache-Control: no-cache 控制浏览器不要缓存
Pragma: no-cache 控制浏览器不要缓存

状态行
状态代码由3位数字组成,表示请求是否被理解或被满足。

状态描述:

状态描述给出了关于状态代码的简短的文字描述。

状态代码的第一个数字定义了响应的类别,后面两位没有具体的分类。

第一个数字有五种可能的取值:

  • 1xx: 指示信息—表示请求已接收,继续处理。

  • 2xx: 成功—表示请求已经被成功接收、理解、接受。

  • 3xx: 重定向—要完成请求必须进行更进一步的操作。

  • 4xx: 客户端错误—请求有语法错误或请求无法实现。

  • 5xx: 服务器端错误—服务器未能实现合法的请求。

状态代码 状态描述 说明
200 OK 客户端请求成功
301 永久重定向
302 临时重定向
400 Bad Request 由于客户端请求有语法错误,不能被服务器所理解
401 Unauthonzed 请求未经授权。这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden 服务器收到请求,但是拒绝提供服务。服务器通常会在响应正文中给出不提供服务的原因
404 Not Found 请求的资源不存在,例如,输入了错误的URL
500 Internal Server Error 服务器发生不可预期的错误,导致无法完成客户端的请求
503 Service Unavailable 服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常

你可能感兴趣的:(JAVA,Basics,java,Servlet,http)