Servlet基础

99 阅读26分钟

JavaWeb

JavaWeb是指,所有通过Java语言编些并且通过浏览器访问的程序总称就成为JavaWeb

JavaWeb是基于请求与响应的应用开发

什么是请求?

请求是指客户端(浏览器)给服务器发送数据就叫做请求(Request)

什么是响应?

响应是指服务器给客户端(浏览器)回传数据就叫做响应(Response)

2021-09-06_083733.png

web资源的分类

web资源按照实现的技术可以分为不同种类:

静态资源: html、css、js、txt、音频、视频、图片等等

动态资源: JSP页面 、servlet 程序(JavaWeb所说的请求与响应载体)

HTTP协议

什么是HTTP协议?

协议(Protocol)是指双方或多方法,相互约定好,大家都需要遵守规则,叫做协议

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

HTTP:现在有两种 一种是http 另外一种是https

在以前https 只有 金融机构使用

http和https是web的传输协议知 ,http是明文传送,数据没加密的。也就是说,局域道网里面谁都能看到你在网页上发送的数据(使用嗅探器),比如说版邮箱密码。权但是https是加密传送,别人就算能看到数据,也是加密的。

而现在基本上都在开始使用了,http现在协议有 HTTP1.0 、1.1(两者是共存关系)和最新的2.0(还没有普及,而且非常庞大复杂)

基于请求与响应模式: 一个请求有一个相应

无状态的: 登录页面的时候都会进行状态保存,主要是为了下一次方便登录,但是这个保存在本地而非服务器端

无状态指的是每一次请求响应都是一次全新的请求和响应,而不是上一次的效果延续

当浏览器发送请求给服务器的时候,服务器响应,但是同一个浏览器再发送请求给服务器的时候,他会响应,但是他不知道你就是刚才那个浏览器,简单地说,就是服务器不会去记得你,所以是无状态协议。

既然无法得知是哪个浏览器那数据怎么办?就需要使用到cookie和session了

网络七层协议.gif

网络四层协议.png

HTTP协议的主要特点如下: 1.支持客户端(浏览器)/服务器模式。B/S

2.简单快速:客户向服务器请求服务时,只需传送请求方法(请求方式)和路径(服务器的资源定位URL)。请求方法常用的有GET、POST。每种方法规定了客户端与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。

3.灵活:HTTP允许传输任意类型的数据对象。传输的类型由Content-Type加以标记。

4.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

5.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

HTTP协议能在一次连接之间多次请求,多次响应,响应完之后在关闭连接,在一个TCP连接上可以传送多个HTTP请求和响应,所谓HTTP协议就是指,客户端与服务器之间通信时,发送数据的需要遵守规则,就叫做HTTP协议,借助这个HTTP协议所提供的请求与响应完成JavaWeb程序开发

HTTP协议到底约束了什么

1.约束了浏览器以何种形式向服务器发送数据

2.约束了服务器以何种形式来接收客户端发送的数据

3.约束了服务器以何种形式来反馈数据给浏览器

4.约束了浏览器以何种形式来接收服务器的反馈数据

请求的HTTP协议格式(Request)

客户端给服务器发送数据叫做请求,客户端向服务器请求资源也是请求

请求又分为GET请求和POST请求

GET请求和POST请求
1.GET请求一般用于去请求数据,POST请求一般用于发送数据
2.GET请求也可以发送数据到后台程序,但是使用GET请求发送数据到后台,会在浏览器地址栏的URL中现实出请求的发送的数据,所以隐私安全性不高,且参数长度也收到限制

例如浏览器地址栏中URL  :https://www.baidu.com/s?ie=utf-8&wd=500万韩元可以在韩国玩多久
  http://localhost:8080/bookstores/login.html?username=zhangsan&password=123456
  
PS: 允许在地址栏中URL路径上进行参数拼接的上面的login.html页面使用参数片接方式
  http://ip地址:端口号/工程名字/资源名称?key1=value1&key2=value2...
  第一个参数拼接的位置使用?相连,后续的参数片接使用&相连, 赋值方式是kv兼职对形式使用=作为数据连接符号
  
Post请求参数是方式Request body(请求体)中,不会在浏览器地址栏中URL路径中显式,比GET更加安全,且参数长度无限制
例如浏览器地址栏中URL :   http://localhost:8080/bookstores/login.html
在URL路径是看不到数拼接参数的

PS:对于我们而言(后端程序)都是一样的,URL路径是否显式是给用户或爬虫提供,无论是GET还POST,后端都要获取出数据,所以可以看到数据

3.GET请求刷新浏览器或回退的时候没有影响,POST请求会回退或刷新是会出现数据的二次提交
4.GET请求可以被缓存,POST请求不允许缓存
5.GET请求保留在浏览器历史记录中,POST请求不会保留在浏览历史记录中
6.GET请求可以被收藏为书签,POST请求不被收藏为书签
7.GET请求只能进行URL编码(application/x-www-form-urlencoded)
  POST请求支持多种URL编码(application/x-www-form-urlencoded 或 multipart/form-data)
8.GET请求是最为常见请求方式,POST请求多使用在form表单或文件上传或下载操作
*/
GET请求和POST请求

每个浏览器中都有一个web开发者模式,这个模式中是可以看到浏览器是以和何种形式向服务器发送请求的,web开发者模式下,可以查看网络,网络中就会提供以请求方式所提供的信息,只要找到我们请URL路径就可以查看详细的请求信息

2021-09-06_093640.png

2021-09-06_093652.png 上图说明:这个就是请求体携带的数据发送到服务器端

Accept: 告诉服务器,客户端可以接受的数据类型

Accept-Encoding: 告诉服务器,科技端可以接受的数据编码(压缩)格式

Accept-Language: 告诉服务器客户端可以接受的语言类型 畅常用的参数(zh-CN[中文],en_US[英文])

Connection: 告诉浏览器以何种方式处理连接

keep-alive 告诉服务器回传数据不要马上关闭,保持一段时间

closed 马上关闭

Host: 表示请求服务器的IP地址与端口号

Referer: 表示请求发起时,浏览器地址栏中地址(从哪来)

cookie: cookie是由服务器端生成的,发送给User-Agent,cookie会在浏览器中进行一些数据的记录,并且会存在浏览器本地,请求网站时,会发送记录这个网站cookie

User-Agent: 浏览器信息

2021-09-06_094041.png火狐浏览自带的,可点击方便查看当前发送数据是什么意思,解释的是请求头中key位置例如:Accept

响应的HTTP协议格式(Response)

服务器给客户端回传数据方式叫做响应,回传数据可以是web资源或具体数据

2021-09-06_095102.png

上图说明:是服务器向客户端响应数据时回传的信息

content-length: 响应体的长度(大小)

date: 表示的响应的时间(格林尼治时间,需要在这个时间的基础上+8,才是我们标准时间)

content-type:通过设置content-type决定对客户端响应数据类型和编码集

server: 表示服务器的信息

Transfer-Encoding: 用来该表HTTP报文形式

cache-control : 是否有缓存,方式是什么

需要注意HTTP响应的状态

状态码:是由协议版本,数字形式的状态代码及响应的状态描述组成

状态码:由3位数字组成,表示请求是否被理解或满足(是否给出合理响应)

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

状态码由5个数字来做第一位定义:

1XX:指示信息-请求已接收,继续处理

2XX:成功-表示请求已经被成功接收处理

3XX:重定向-要求请求必须在进一步处理

4XX:客户端错误-请求语法错误或请求无法实现

5xx:服务器端错误 - 服务器端未能实现合法请求处理

列举常见状态码:

200 客户端请求与响应都是成功

404 请求的资源不存在,最常见的就是请求URL资源路径写错了

500 服务器端程序发生错误,一般就是程序抛出异常

302 请求重定向,请求的原始网址不在提供服务,会跳转到新的网址继续提供服务

剩余装填码查看HTTP状态码全

B/C和C/S架构

2021-09-06_104641.png

JavaWeb服务器程序开发

JavawWeb程序开发为我们提供三个核心组件用于对JavaWeb程序进行开发 :"Servlet程序、Filter过滤器、Listenter监听器" ,现在主要学习就是Servlet技术开发服务器端应用程序以完成HTTP协议提供请求与响应操作

Servlet程序开发无非就是在完成:接收客户端发送请求、动态生成网页(网页数据可以改变)、将包含结果的动态网页发送给客户端

创建第一个Servlet程序

1.需要在IDEA中创建一个JavaWeb工程

2.在工程内部的src文件夹下创建一个普通类,实现Servlet接口就可以完成一个Servlet程序了


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

//第一个Servlet程序 让类实现Servlet接口,这个接口是Servlet程序的根接口
public class FirstServletDemo implements Servlet {
    //init方法是Servlet的初始化方法
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("初始化Servlet");
    }
    //获取Servlet配置
    @Override
    public ServletConfig getServletConfig() {
        System.out.println("获取Servlet的配置信息");
        return null;
    }
    //核心方法service(处理请求与响应)
    //观察方法可以返现,这个方法参数是servletRequest(请求对象)和ServletResponse(响应对象)
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("servlet核心方法处理请求和影响操作");
    }
    //获取servlet的基本信息
    @Override
    public String getServletInfo() {
        System.out.println("获取servlet基本信息");
        return null;
    }
    //servlet销毁
    @Override
    public void destroy() {
        System.out.println("servlet销毁了");

    }
}

3.编写好的Servlet程序代码是不能执行的,如果需要让Servlet程序代码执行需要配置web.xml文件了

这个web.xml文件在工程中web目录下的WEB-INF目录中

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
		  http://java.sun.com/xml/ns/javaee/web-app_4_0.xsd"
           version="4.0">
<!--    这个xml文件是配置文件,它有自己的标签  -->
<!--    servlet标签是给tomcat服务器配置servlet应用程序使用的-->
      <servlet>
<!--          servlet-name标签 配置servlet程序的别名(一般使用的是servlet类名)-->
          <servlet-name>FirstServlet</servlet-name>
<!--          servlet-class标签 配置servlet程序从什位置可以加载(就是反射)
              配置信息就是要执行servlet的类权限定名称(包名+类名)-->
          <servlet-class>com.qfedu.FirstServlet.FirstServletDemo</servlet-class>
      </servlet>
<!--    servlet-mapping和servlet标签是成对出现 mapping是为servlet标签中提供Servlet程序提供
外界的访问地址-->
      <servlet-mapping>
<!--          mapping中servlet-name标签需要和servlet中servlet-name标签是一致
     这样mapping才可以找到是那个servlet执行-->
          <servlet-name>FirstServlet</servlet-name>
<!--          url-pattern标签 这个标签就是配置servlet程序在外界访问的URL地址
              地址配置是以 [/] 开始  后面跟上名字
              这里 / 在服务器解析路径的时候,表示的是 http://ip地址:端口号/工程名称
              即外界要访问servlet 全路径就是: http://ip地址:顿口号/工程名称/fds-->
          <url-pattern>/fsd</url-pattern>
      </servlet-mapping>
<!--    外界是如何访问servlet的,首先会在浏览器地址栏中输入 http://ip地址:顿口号/工程名称/fds
定位到tomcat中对应工程的web.xml文件中配置信息,先查找servlet-mapping中那个url-pattern匹配访问路径
找到之后在获取servlet-name的值去servlet标签中寻找匹配的servlet-name标签值,然后再通过servlet-class
标签反射访问当前servlet程序并执行-->


</web-app>

外界访问servlet的时候会执行servlet程序的初始化,并执行servlet中提供服务方法用于处理前端页面所提供请求与访问操作,当Tomcat服务器关闭的时候,就会销毁servlet程序

2021-06-15_134107.png

只需要在service方法调用servletResponse对象就可以响应数据到页面上

    //观察方法可以返现,这个方法参数是servletRequest(请求对象)和ServletResponse(响应对象)
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("servlet核心方法处理请求和影响操作");
        servletResponse.setContentType("text/html;charset=UTF-8");
        servletResponse.getWriter().println("服务器响应客户端信息");
    }

HttpServlet类

如果在开发中需要开发servlet类现有的做法就是实现Servlet接口,但是这个接口中一共提供5个方法,对于开发而言,核心方法方法只有一个service方法处理请求与响应,剩余方法对于开发而言没有太大作用,为了精简开发,不太建议实现Servlet接口,替代方案是什么?

查看JavaEEAPI文档,通过文档可以发现

servlet 是运行在 Web 服务器中的小型 Java 程序。servlet 通常通过 HTTP(超文本传输协议)接收和响应来自 Web 客户端的请求。

要实现此接口,可以编写一个扩展 javax.servlet.GenericServlet 的一般 servlet,或者编写一个扩展 javax.servlet.http.HttpServlet 的 HTTP servlet

GenericServlet类

首先这个类是一个抽象类,实现Servlet接口,但是在API说明中 "定义一般的、与协议无关的 servlet。要编写用于 Web 上的 HTTP servlet,请改为扩展 javax.servlet.http.HttpServlet" .文档这个说明就间接奠定了这类是不适合编写servlet的一个类,servlet是需要有HTTP协议,但是这个类是一个无协议,推荐了这个类子类HttpServlet.

HttpServlet类

通过观察API文档可以发现HttpServlet也是一个抽象类,但是文档说明很明确

提供将要被子类化以创建适用于 Web 站点的 HTTP servlet 的抽象类。HttpServlet 的子类至少必须重写一个方法,该方法通常是以下这些方法之一:

  • doGet,如果 servlet 支持 HTTP GET 请求
  • doPost,用于 HTTP POST 请求
  • doPut,用于 HTTP PUT 请求
  • doDelete,用于 HTTP DELETE 请求
  • initdestroy,用于管理 servlet 的生命周期内保存的资源
  • getServletInfo,servlet 使用它提供有关其自身的信息

几乎没有理由重写 service 方法。service 通过将标准 HTTP 请求分发给每个 HTTP 请求类型的处理程序方法(上面列出的 doXXX 方法)来处理它们。

httpServlet抽象类是一个适合作为开发web Servlet程序的一个父类,并且是遵守了HTTP协议,而且将Servlet接口中原来service方法进行细分,我们需要提供service方法的重写,而是使用httpServlet中提供doXXX方法来出来请求和响应操作,Java Web应用程序是基于HTTP的请求与响应,HTTP的请求方式GET和POST,所以我们创建Servlet程序只需要继承与HttpServlet就可以成为Java Web的应用程序,并且只需要实现doGet或doPost方法就可以完成请求与响应

HttpServlet类的层级关系

2020-10-09_144957.png

HttpServlet类创建自定义Servlet


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

//当前这个Servlet类是继承与HttpServlet
public class SecondServlet extends HttpServlet {
    //根据外部的请求方式提供对应方法
    /*
    观察doGet和doPost方法的参数和实现Servlet接口中service方法的参数是不一样
    Servlet接口中service方法的参数是ServletRequest和ServletResponse
    而doGet和doPost方法的参数是HttpServletRequest 和 HttpServletResponse
    带有Http开头的是和原有ServletRequest和ServletResponse是继承关系
    HttpServletRequest 和 HttpServletResponse 是子类,更加利于http协议的开发
    方法更加多用,不影响request和response开发,反而更加利于开发
     */

    //处理的就是get请求
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");
        resp.getWriter().println("我是HttpServlet实现的自定义Servlet");
    }
    //处理的就是post请求
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    }
}

PS:通过观察HTTP实现的原码可以发现这个类提供很多方法,包括doGet和doPost方法,并且这个类中提供两个service方法的重写,一个是实现方法的分发不同请求方式分发给HttpServlet这个类实现的方法,还有一个方法service方法,但是这个方法的实现

这个是HttpServlet类中service方法的实现,但是问题在于方法内部实现调用
this.service(request, response); 这里就触发 Java中"递归调用"
什么是递归?
递归是一个中自身方法调用自身的一种实现方式,类似于"死循环",执行效果极高
如果编写递归方法必须给递归方法本身提供一个出口,类似于"停止死循环"的方式
否则化会出现"栈溢出错误",直接让JVM栈区爆满,程序崩溃(StackOverflowError)
   
思考作业:为什么HttpServlet中当前这个service方法没出现"栈溢出问题"而是正常执行
*/
 public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        HttpServletRequest request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)res;
        } catch (ClassCastException var6) {
            throw new ServletException(lStrings.getString("http.non_http"));
        }
		//为什么没有出现死递归问题
        this.service(request, response);
    }

如果一个普通Servlet类实现了Servlet接口必须提供5个抽象方法的重写,但是继承与HttpServlet这个类之后只提供了doGet或doPost方法的重写,那么剩余没有重写方法为什么不用在提供实现重写,在HttpServlet类的原码中并没有看到这个4个方法的实现,原因是父类GenericServlet已经实现了这些方法,所以无需在重复实现,好处在于如果开发要用到这4个方法某一个,因为继承关系的存在,所以只要再次提供重写皆可

如何设置IDEA中的Tomcat操作

IDEA创建每个JavaWeb项目的时候都需要进行一些Tomcat的设置操作,这个操作自在什么位置修改

image-20200412142810390.png

image-20200412144004693.png

image-20200412145558394.png

Servlet注解

现在如果要开发一个Servlet程序,开发完之后需要在web.xml文件中进行配置,如果Servlet比较多,那么web.xml文件的配置操作就会非常的多,这样一来就不太利于管理和编写,配置servlet操作太繁琐,在Servlet3.0开始Servlet对开发人员进行Servlet的配置提供的极大的简化操作,Servlet3.0开始提供注解配置Servlet程序的操作,无需在web.xml文件中繁琐的配置Servlet,只需要在Servlet开发类上使用注解就可以简易的完成Servlet的配置操作

PS:现在开发都是基于注解,除注解无法配置使用web.xml文件之外,Servlet一律都是用注解

什么是注解

注解是JavaSE中的一个概念,注解和注释不要搞混,他们是不同的概念

注释是给程序猿看的,给程序添加说明让程序猿明确当前代码的含义和使用方式

注解是程序中一个特殊标记,程序通过这个特殊标记的读取,进行数据的获取或加载配置,现在注解多用于文件的配置操作

注解的使用:

1.servlet的配置就可使用注解

2.SSM框架会大量使用注解简便开发

3.提示代码是否有错误或提供数据操作

自定义注解

//自定义注解  --> 使用关键字 是 @interface
public @interface MyAnnotation {
    /*
    注解中可以使用数据类型有[基本数据类型,String类型,Class类型,枚举类型,注解类型,一维数组]
    注解中只能定义"属性",剩余任何类型操作都不允许
     */
    String name(); // ---> 这个就是注解中"属性"
    int age();
}

注解的原理是什么?

通过反编译工具可以发现,所创建注解其实就是接口,这个接口继承Annotation,才被称之为 "注解"

在定义注解属性时候就是在变相定义接口中抽象方法


public interface MyAnnotation extends Annotation{

	public abstract String name();

	public abstract int age();
}

注解的使用

PS:现在创建注解并没有使用任何"元注解"操作,所以现在注解可以使用在任意类中位置


//@MyAnnotation(name="zhangsan",age=18)
public class Person {
    //@符号就是注解的标识,因为在定义注解属性时候并没有值
    //所以在使用注解时需要对,注解中属性进行赋值操作
    @MyAnnotation(name="zhangsan",age=18)
    public void show(){

    }
 
     
}

注解属性赋值
/*
    是否可以在创建注解属性的同时给属性进行赋值操作
    只需要在创建注解属性时候使用 default
    就可以给注解的属性记性 默认值赋值
    */
    String name() default "王五";
此时注解属性已经有默认值,外界就可以无需赋值,在号私用时候就是默认值,你也可以进行二次赋值,使用就新赋值的值

使用反射读取注解中的值


import java.lang.reflect.Method;

public class Test {
    public static void main(String[] args) throws Exception {
        //使用反射将Person2类中show方法上的注解数据获取,并赋值给show方法执行操作
        //1.通过反射获取类的对象
        Class aClass = Class.forName("com.qfedu.Annotation.Person2");
        //2.通过有类的对象获取方法对象
        Method show = aClass.getMethod("show",String.class,int.class,String.class);
        //3.通过方法对象获取方法上的注解
        MyAnnotation2 annotation = show.getAnnotation(MyAnnotation2.class);
        //4.执行show方法将注解对象中数据传递到show方法
        Object o = aClass.newInstance();
        //运行程序时,出现了NullPointerException异常,为什么会出现这个异常?
        System.out.println("Object对象:"+o);
        System.out.println("Method对象:"+show);
        System.out.println("Annotation对象"+annotation);
        show.invoke(o,annotation.name(),annotation.age(),annotation.sex());
    }
}

为什么注解会出现null?

我们所创建的自定义注解是有声明周期,在没有明确注解声明周期的前提下,注解声明周期仅限于字节码加载JVM这个阶段就消亡了,编译时注解事就消亡了,运行时可定是拿不到注解的,所以出现null

元注解

用于描述注解的注解,就是元注解,它可以决定注解的一些基础信息 [注解生命周期和注解使用位置]

@Retention 可以声明在自定义注解的上方,表示注解可以保存在哪一个代码时期,保存的时间【注解生命周期】


/*有三种表示形式被封装在RetentionPolicy枚举中 

CLASS(默认值):注解可以存储在源文件和字节码文件中,但是一旦JVM加载,会在JVM中消失 

RUNTIME:注解 可以存在于源文件和字节码文件和JVM中 

SOURCE:注解只能存储在于源文件中,一旦编译,在字节码中就消失 */

@Target表示注解可以贴在哪些位置,内部使用ElementType枚举定义位置 【注解可以使用在什么位置】


TYPE:只能修饰类,接口和枚举 

FIELD:只能修饰属性,包括常量(枚举常量) 

METHOD:只能修饰方法 

PARAMETER:只能修饰参数

CONSTRUCTOR:只能修饰构造方法 

LOCAL_VARIABLE:只能修饰局部不变量 

ANNOTATION_TYPE 只能修饰注解 

PACKAGE:修饰包

ps:在创建包的时候可以创建出一个package-info.java文件,这个文件的主要作用就是给包使用注解 

因为包需要放到整段代码的第一张,那么无法在包上添加注解,所以写到文件中就是给包添加注解了 

@Document 表示是一个文档注解,会保存在文档中 

@Inherited 表示当前注解可以被继承

PS:在没有使用这个注解的前提下可以使用使用在任何位置
只需使用元注解提高注解生命周期就可以解决问题
*/

import org.omg.SendingContext.RunTime;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//提供一个注解
//这里添加元注解
@Retention(RetentionPolicy.RUNTIME) //JVM,原码和字节码文件中都存活
@Target(ElementType.METHOD)
public @interface MyAnnotation2 {
    //提供三个属性
    String name();
    int age();
    String sex();
}

介绍Servlet3.0中提供注解操作

现在Servlet的配置操作,无需在web.xml文件完成,只需要在开发的Servlet程序上使用 @WebServlet这个注解就可以完成对Servlet的配置操作, @WebServlet注解可以使用那些属性

属性名类型描述
nameString指定Servlet 的 name 属性,等价于 。如果没有显式指定,则该 Servlet 的取值即为类的全限定名。
valueString[]该属性等价于 urlPatterns 属性。两个属性不能同时使用。
urlPatternsString[]指定一组 Servlet 的 URL 匹配模式。等价于标签。
loadOnStartupint指定 Servlet 的加载顺序,等价于 标签。
initParamsWebInitParam[]指定一组 Servlet 初始化参数,等价于标签。
asyncSupportedboolean声明 Servlet 是否支持异步操作模式,等价于 标签。
descriptionString该 Servlet 的描述信息,等价于 标签。
displayNameString该 Servlet 的显示名,通常配合工具使用,等价于 标签。

说明:

1.value和urlPatterns是狠心属性主要是配置Servlet的外部访问地址使用

2.name和initParams这个两个不是必要属性,可能会被用上一些,name是Servlet的一个名字,initParams初始化的属性

3.name这个属性在注解中可以是省略不写,initParams也是一样的,但是value或urlPatterns必须写一个

两者不能共存(只能二选一)

如果做的是Servlet精确匹配(就是一个访问地址可以访问到一个Servlet) ---> 建议使用value

如果做的是Servlet模糊匹配(多个地址都可以访问到Servlet) ---> 建议使用urlPatterns

使用Servlet注解完成Servlet程序开发与配置


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;
//这里使用注解进行Servlet配置操作
/*
标准配置 提供name和value属性 --> 提供servlet名字和servlet地址
配置路径的时候千万不要忘记 [/] ,如果不添加程序会报错
在注解中路径 / 代表什么 --> http://ip地址:端口号/工程名字
value和urlPatterns都是 String数组所以可以单独赋值,也可以多个赋值
 */
//@WebServlet(name="ThreeServlet",value="/ts")
//省略配置 不提供name属性
//@WebServlet(value="/ts1")
//如果Servlet配置访问地址是唯一的,value都可以省略
@WebServlet("/ts2")
//如果给Servlet配置多个访问路径(只要是以下三个路径中任何一个都可以访问到当前servlet)
//@WebServlet(urlPatterns = {"/ts3","/ts4","/ssss"})
//每个Servlet地址都是唯一的
public class ThreeServlet extends HttpServlet {

    //重写的方法
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //在doGet请求中处理响应操作
          resp.setContentType("text/html;charset=UTF-8");
          resp.getWriter().println("doGet请求做的响应操作");
    }

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


    }
}

Get请求和Post请求的处理

1.在项目中web目录下提供一个HTML文件--> login.html

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录界面</title>
</head>
<body>
<!--
Java Web开发都要遵守HTTP协议,所有数据请求方式GET和POST
在HTML中form表单的作用就是收集前端用户输入的数据传递到后台服务器的应用程序
即 前端页面发送请求到后台服务器程序 --- 请求(request)
form表单三大核心属性,现在就要用到其中两个了
action 通过form表单中submit按钮将表单中数据提交到action所提供地址
action 地址可以是一个HTML页面 也可是一个JSP页面 还是可以是Servlet程序
       如果是一个Servlet程序或JSP页面 就相当于将页面数据发送到服务器端的程序
       就是可以在servlet程序或JSP页面 来处理请求而来数据了并提供响应
       而如果是HTML页面只是简单的条件
使用action属性提交数据到servlet程序中,如何编写地址?
servlet属于一个服务器端的程序,你要访问的需要提供访问到服务器端程序的地址,服务器才会帮助你访问
提交地址也要以[/]开头,但是需要注意--- 这里的[/]代表的是 --- http://ip地址:端口号
需要在action中提供  工程名字+servlet的地址       

method 通过form表单以何种方式提表单 -- get/post
       在默认不提供前提下就是get请求

-->
<form action="/Servlet_01/login" method="get">
    <label>用户名:</label><input type="text" name="username">
    <label>密码:</label><input type="password" name="password">
    <input type="submit" value="登录">
</form>

</body>
</html>

如何正确处理前端用户请求

在实际开中前后端是分离开发的,前端开发前端,后端开发后端,只会定义写数据传输接口,前端那么多页面,请求方式是不会全告诉后端的,所以我们就面临一个问题,就是如何处理是doGet请求还是doPost请求

第一种:手动分发处理(不推荐)

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
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("/login")
public class LoginServlet extends HttpServlet {
     //1.需要重写service方法明确请求方式进行方法分发
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
       //1.需要将ServletRequest 和 ServletResponse 向下转型为子类类型
        HttpServletRequest request = (HttpServletRequest)req; //请求对象
        HttpServletResponse response = (HttpServletResponse)res;//响应对象
        //2.使用request对象中提供getMethod方法获取请求方式
        String method = request.getMethod();
        //3.判断method的请求方式调用不同的实现
        if(method.equals("GET")){
            doGet(request, response);
        }else if(method.equals("POST")){
            doPost(request,response);
        }

    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /*
        因为form表单在提交的时候会将数据通过请求方式传递到后台servlet中
         如果将请求中数据获取出来 使用到request(HttpServletRequest) 即参数中req 请求对象
         getParameter("name属性值") --> 获取请求参数数据 -->返回值只有String
         这个方法有一个参数,这个参数决定着获取数据的值,可就是标签中的name属性值
         */
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println("用户名:"+username+" 密码:"+password);


    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         /*
        因为form表单在提交的时候会将数据通过请求方式传递到后台servlet中
         如果将请求中数据获取出来 使用到request(HttpServletRequest) 即参数中req 请求对象
         getParameter("name属性值") --> 获取请求参数数据 -->返回值只有String
         这个方法有一个参数,这个参数决定着获取数据的值,可就是标签中的name属性值
         */
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println("用户名:"+username+" 密码:"+password);
    }
}

这就是Get请求时浏览器地址栏中URL路径:http://localhost:8080/Servlet_01/login?username=zhangsan&password=123456

我们是不推荐使用这种方式进行操作,违背了HttpServlet中不重写service方法的原则,就是为了保证每个请求都可以处理数据操作,需要在doGet和doPost中都需要实现相同的代码,违反了DRY原则(不要写重复代码),如果出现修改就需要修改两次

第二种方式get即post,post即get(推荐)

对于用户而言它请求是区分get和post请求,原因在于需要避免地址栏中URL出现敏感数据,但是对于后端开发人员而言,无论是get还是post请求,最终都要获取出数据,数据的是是否被隐藏对于我们而言没有效果的,所以无论你get还是post请求,处理一次就可以的,无论以什么方式请求而来的数据我们后端开发人员统一当做一种请求处理,要么是get或post


import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
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("/login2")
public class LoginServlet2 extends HttpServlet {

   //你选择一个请求方式提供处理逻辑(doGet或doPost都可以)
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /*
        因为form表单在提交的时候会将数据通过请求方式传递到后台servlet中
         如果将请求中数据获取出来 使用到request(HttpServletRequest) 即参数中req 请求对象
         getParameter("name属性值") --> 获取请求参数数据 -->返回值只有String
         这个方法有一个参数,这个参数决定着获取数据的值,可就是标签中的name属性值
         */
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println("用户名:"+username+" 密码:"+password);


    }
    //只要调用doGet方法就可以了
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
    }
}