【JavaWeb】第八章 Servlet

文章目录

  • 1、初识Servlet
  • 2、Servlet的HelloWorld
  • 3、Servlet的生命周期
  • 4、Servlet-请求的分发处理
  • 5、通过集成HttpServlet类来实现Servlet程序
  • 6、ServletConfig类
  • 7、ServletContext类
  • 8、HTTP协议
  • 9、HttpServletRequest类
  • 10、请求的转发
  • 11、base标签
  • 12、相对路径、绝对路径和斜杠\
  • 13、HttpServletResponse类
  • 14、请求重定向

1、初识Servlet

Servlet是JavaEE规范之一。规范就是接口。

Servlet是JavaWeb三大组件之一,三大组件分别是Servlet程序、Filter过滤器、Listener监听器

【JavaWeb】第八章 Servlet_第1张图片

Servlet是运行在服务器上的一个Java小程序,它可以接受客户端发送过来的请求,并响应数据给客户端。

2、Servlet的HelloWorld

流程:

  • 编写一个类实现Servlet接口
  • 实现service方法,处理请求,并响应数据
  • 到web.xml中去配置servlet程序的访问地址

实现代码:
【JavaWeb】第八章 Servlet_第2张图片

重写service方法后,编辑web.xml配置文件。内容:


<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_4_0.xsd"
         version="4.0">
    
    <servlet>
        
        <servlet-name>HelloServletservlet-name>
        
        <servlet-class>com.code.servlet.HelloServletservlet-class>
    servlet>
    
    <servlet-mapping>
        
        <servlet-name>HelloServletservlet-name>
        
        
        
        <url-pattern>/hellourl-pattern>
    servlet-mapping>
web-app>

启动Tomcat实例后,在url后加/hello即可在控制台看到Sevlet程序的输出。

url地址如何定位到的Servlet程序并访问

【JavaWeb】第八章 Servlet_第3张图片

Tip
无法实现Servlet接口或者import javax.servlet.*报错时,在lib目录中导入jsp和servlet的jar包
【JavaWeb】第八章 Servlet_第4张图片

3、Servlet的生命周期

  • 执行实现Servlet接口类的构造方法
  • 执行init初始化方法
  • 执行service方法
  • 执行destory方法

其中,前两步在第一次访问Servler程序的时候调用。第三步是每次访问都会调用。第四步是在web工程停止的时候会去调用

【JavaWeb】第八章 Servlet_第5张图片

4、Servlet-请求的分发处理

 /**
     * service方法是用来处理请求和响应的
     * @param servletRequest
     * @param servletResponse
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("Hello Servlet被访问了!");
        //类型转换,因为getMethod是子类特有的方法
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        
        String method = httpServletRequest.getMethod();
        
        if("GET".equals(method)){
            //System.out.println("这里写收到GET请求的code");
            doGet();
        }else if("POST".equals(method)){
            System.out.println("这里写收到POST请求的code");
        }
    }

    /**
     * 把收到GET请求要做的事定义成一个方法
     * 从而避免service方法中代码臃肿
     */
    public void doGet(){

    }

写个HTML文档表单提交到servlet

<body>
    <form action="http://localhost:8080/web/hello" method="get">
        <input type="submit" value="提交"/>
    form>

body>

点击提交,在控制台就可看到不同请求被分发给不同的IF分支了。

5、通过集成HttpServlet类来实现Servlet程序

实际的开发中,很少通过实现Servlet接口去实现Servlet程序,而是直接继承Servlert接口的子类,如HttpServlet:

  • 编写一个类去继承HttpServlet类
  • 根据业务需要重写doGet和doPost方法
  • 到web.xml中的配置Servlet程序的访问地址
public class ServletHello extends HttpServlet{

...
Alt+Insert
}

【JavaWeb】第八章 Servlet_第6张图片
以上是原理,在IDEA中可以直接生成Servlet程序:
【JavaWeb】第八章 Servlet_第7张图片

【JavaWeb】第八章 Servlet_第8张图片

这样可以直接生成xx.java和修改好web.xml文件。

整理Servlet类的继承体系:
.
.

【JavaWeb】第八章 Servlet_第9张图片

6、ServletConfig类

顾名思义即Servlet程序的配置信息类。有大三作用:

  • 可以获取Servlet程序的别名,即servlet-name的值
  • 获取初始化参数init-param
  • 获取ServletContext对象

☀代码实现:

关于初始化参数:
【JavaWeb】第八章 Servlet_第10张图片

System.out.println("Servlet别名"+servletConfig.getServletName());

System.out.println("Servlet程序初始化参数username的值是" + servletConfig.getInitParameter("username");

System.out.println(servletConfig.getServletContext());

【JavaWeb】第八章 Servlet_第11张图片

另外:

Servlet程序和ServletConfig对象都是由Tomcat服务器负责创建,我们负责使用。Servlet程序默认第一次访问的时候创建,ServletConfig是每个Servlet程序创建时,就创建一个对应的Servletconfig对象。


因此,每个servletConfig对象只能获取它自己对应的那个servlet程序的信息,获取不了其他servlet程序

【JavaWeb】第八章 Servlet_第12张图片

在其他方法中,可以这样获取servletConfig对象:

//也可以这样获取servletConfig对象
ServlerConfig servletConfig = getServletConfig();


常见错误–servletConfig对象空指针异常

重写init方法后,出现servletConfig对象空指针异常,加这一句:

@Override
public void init(ServletConfig config) throws ServletException{
	super.init(config);
	...
}

调用父类的init方法:
【JavaWeb】第八章 Servlet_第13张图片

7、ServletContext类

☀介绍

  • ServletContext是一个接口,它表示Servlet上下文对象
  • 一个web工程,只有一个ServletContext对象
  • ServletContext是在Web工程部署启动的时候创建,在web工程停止的时候销毁
  • ServletContext是一个域对象

域对象是指可以像Map一样存取数据的对象,这里的域是指存取数据的操作范围,即整个Web工程

存数据 取数据 删数据
Map put() get() remove()
域对象 setAttribute() getAttribute() removeAttribute()

☀作用

  • 获取web.xml中配置的上下文参数
  • 获取当前的工程路径
  • 获取工程部署后在服务器硬盘上的绝对路径
  • 像Map一样存取数据

代码实现:
【JavaWeb】第八章 Servlet_第14张图片

public void doSome(){
        ServletContext context = getServletConfig().getServletContext();
        //获取context上下文参数
        String username = context.getInitParameter("username");
        //获取当前的工程路径
        String path = context.getContextPath();
        /**
         * 获取工程在服务器硬盘上的绝对路径
         * 斜杠/即会被服务器解析地址为http://ip:port/工程名
         */
        String realPath = context.getRealPath("/"); //工程部署路径
        String realImgPath = context.getRealPath("/img"); //img目录的绝对路径
        
        context.setAttribute("key1","value1");
        System.out.println("context中获取域数据key1的值是:"+context.getAttribute("key1"));
}

另外,获取ServletContext对象也可直接调用getServletContext()方法,看底层源码:
【JavaWeb】第八章 Servlet_第15张图片

8、HTTP协议

协议

协议,即双方或多方相互约定好的、大家都需要遵守的规则。

HTTP协议,指客户端和服务端之间通信时,发送的数据要遵守的规则,就是HTTP协议。HTTP协议中的数据又叫报文。

请求

客户端给服务端发送数据叫请求,服务端给客户端回传数据叫响应。请求有GET和POST两种:

  • GET请求

请求行:

  • 请求的方式 GET
  • 请求的资源路径 [+?+请求参数]
  • 请求的协议版本号 HTTP/1.1
如:

GET /web/submit.html HTTP/1.1

请求头:

一组组的key:value格式
【JavaWeb】第八章 Servlet_第16张图片

  • POST请求

请求行:

  • 请求的方式 POST
  • 请求的资源路径 [+?+请求参数]
  • 请求的协议版本号 HTTP/1.1
如:

POST /web/submit HTTP:1.1

请求头:

一组组key:value。空行后接着是请求体
【JavaWeb】第八章 Servlet_第17张图片
Cache-Control表示如何控制缓存,no-cache即不缓存

请求体:

即发送给服务器的数据
请求体

场景区分

GET请求常包括:

  • form标签中 method=get
  • a标签
  • link标签引入css
  • Script标签引入js文件
  • img标签引入图片
  • iframe引入HTML页面
  • 在浏览器的地址栏中输入地址后敲回车

请求常包括:

  • form标签中method=post

响应

响应行:

  • 响应的协议和版本号
  • 响应的状态码
  • 响应状态描述符
如:

HTTP/1.1 200 OK

常见的响应码有:

  • 200:请求成功
  • 302:表示请求重定向
  • 404:表示服务器已经收到了,但你要的数据不存在(请求地址错误)
  • 500:服务器已经收到请求,但服务器内部错误

响应头:

一组组的key:value形式,最后一个空行后就是响应体
【JavaWeb】第八章 Servlet_第18张图片

响应体:

回传给客户端的数据,这里请求的是这个html页面:
【JavaWeb】第八章 Servlet_第19张图片

MIME类型

MIME即HTTP协议中的数据类型,起全称Multipurpose Internet Mail Extensions,多功能Internet邮件扩充给服务。MIME类型的格式是“大类型/小类型”,并与某一种文件的扩展名相对应。

【JavaWeb】第八章 Servlet_第20张图片

9、HttpServletRequest类

每次只要有请求进入Tomcat服务器,Tomcat服务器就会把请求过来的HTTP协议信息解析好封装到Request对象中,然后传递到service方法(doGet、doPost)中

HttpServletRequest类的常用方法

  • getRequestURI() 获取请求的资源路径
  • getRequestURL() 获取请求的统一资源定位符
  • getRemoteHost() 获取客户端的IP地址
  • getHeader() 获取请求头
  • getParameter() 获取请求的参数
  • getParameterValues() 获取请求的参数(多个值的时候)
  • getMethod() 获取请求的方式GET、POST
  • setAttribute(key,value) 设置域数据
  • getAttribute(key)获取域数据
  • getRequestDispatcher() 获取请求转发对象

示例代码:

package com.llg.web;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.Arrays;

public class HttpServlet1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String[] hobby = request.getParameterValues("hobby");
        System.out.println("username:" + username);
        System.out.println("password:" + password);
        System.out.println("hobby:" + Arrays.asList(hobby));
        System.out.println("URI:" + request.getRequestURI());
        System.out.println("URL:" + request.getRequestURL());
        System.out.println("Client_IP:"+request.getRemoteHost());
        System.out.println("User-Agent:" + request.getHeader("User-Agent"));
        System.out.println("Request-Method:" + request.getMethod());

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /**
         * setCharacterEncoding方法设置请求的字符集为UTF-8,解决post请求的中文乱码问题
         * 注意要在获取请求参数之前调用
         */
        request.setCharacterEncoding("UTF-8");
        System.out.println("-----POST-----");
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String[] hobby = request.getParameterValues("hobby");
        System.out.println("username:" + username);
        System.out.println("password:" + password);
        System.out.println("hobby:" + Arrays.asList(hobby));
    }
}

写个form用来提交信息:

<body>
    <form action="http://localhost:8080/web1/s1" method="post">
        用户名:<input type="text" name="username">br>
        密码:<input type="text" name="password">br>
        兴趣爱好:<input type="checkbox" name="hobby" value="c">C
        <input type="checkbox" name="hobby" value="java">Java
        <input type="checkbox" name="hobby" value="js">JavaScript
        <input type="submit">
    form>

body>

运行效果:
【JavaWeb】第八章 Servlet_第21张图片
【JavaWeb】第八章 Servlet_第22张图片

10、请求的转发

图解转发的过程:
【JavaWeb】第八章 Servlet_第23张图片
代码实现:

Servlet1的代码:

package com.llg.web;

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

@WebServlet(name = "Servlet1", value = "/Servlet1")
public class Servlet1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /**
         * 获取请求参数(办事的材料)
         */
        String username = request.getParameter("username");
        System.out.println("在Servlet1(柜台1)中查看参数(材料):" + username);
        /**
         * 给材料盖一个章,并传递到Servlet2(柜台2)取查看
         */
        request.setAttribute("key1","柜台1的章");
        /**
         * 问路Servlet2(柜台2)怎么走
         * 请求的转发必须要以斜杠打头,斜杠表示地址为:http://ip:port/工程名,映射到IDEA的web目录
         */
        RequestDispatcher requestDispatcher = request.getRequestDispatcher("/servlet2");
        /**
         * 走向Servlet2(柜台2)
         */
        requestDispatcher.forward(request,response);

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

Servlet2的代码:

package com.llg.web;

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

@WebServlet(name = "Servlet2", value = "/Servlet2")
public class Servlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /**
         * 获取请求参数(办事的材料)
         */
        String username = request.getParameter("username");
        System.out.println("在Servlet2(柜台2)中查看参数(材料):" + username);
        /**
         * 查看柜台1是否有盖章
         */
        Object key1 = request.getAttribute("key1");
        System.out.println("柜台1是否有章:" + key1);
        /**
         * 处理自己的业务
         */
        System.out.println("Servlet2在这里干它的业务");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

配置web.xml

【JavaWeb】第八章 Servlet_第24张图片

访问:
【JavaWeb】第八章 Servlet_第25张图片
控制台输出:
【JavaWeb】第八章 Servlet_第26张图片

请求转发的特点:

  • 浏览器地址栏没有变化
  • 他们是一次请求,因此共享Request域中的数据
  • 可以将请求转发到WEB-INF目录下,但不能访问工程以外的资源

11、base标签

实验前期准备:

先在web项目下建立这样一个目录结构,以便后续实验:
【JavaWeb】第八章 Servlet_第27张图片
c.html和index.html的内容:
【JavaWeb】第八章 Servlet_第28张图片
【JavaWeb】第八章 Servlet_第29张图片
启动项目,就先单单利用a标签实现了跳转的效果:
【JavaWeb】第八章 Servlet_第30张图片
【JavaWeb】第八章 Servlet_第31张图片

使用Servlet转发:

编写ForWardC类,重写doGet方法:

【JavaWeb】第八章 Servlet_第32张图片
【JavaWeb】第八章 Servlet_第33张图片
到此,访问:

http://localhost:8080/web1/forwardC

即会转发到a/b/c.html。在首页html中加入上面的链接,和之前做比较:

【JavaWeb】第八章 Servlet_第34张图片
重新部署后:
【JavaWeb】第八章 Servlet_第35张图片
跳转成功:
【JavaWeb】第八章 Servlet_第36张图片
再点击跳回首页,报错404,注意这时的路径:
【JavaWeb】第八章 Servlet_第37张图片

原因分析:

【JavaWeb】第八章 Servlet_第38张图片
跳回首页时a标签的路径是…/…/index.html,是一个相对路径。而 所有相对路径在工作的时候都会参照当前浏览器地址栏中的地址来跳转

用a标签的时候成功原因的分析:

【JavaWeb】第八章 Servlet_第39张图片
而用转发来跳转的时候:
【JavaWeb】第八章 Servlet_第40张图片

base标签

base标签可以设置当前页面中所有相对路径工作时,参照哪个路径来进行跳转

【JavaWeb】第八章 Servlet_第41张图片

加入base后,每次相对路径跳转时参考的就不再是浏览器中的地址栏url,而是base的href,进而转发后的页面也能跳成功

【JavaWeb】第八章 Servlet_第42张图片

12、相对路径、绝对路径和斜杠\

在JavaWeb中,关于相对路径和绝对路径,相对路径有:

  • . 表示当前目录
  • .. 表示上一级目录
  • 只有一个资源名,即当前目录/资源名

绝对路径是:

http://ip:port/工程路径/资源路径

而在web中,斜杠/是一种绝对路径:

  • 斜杠 / 如果被浏览器解析,则得到的是http://ip:port/
    【JavaWeb】第八章 Servlet_第43张图片
    【JavaWeb】第八章 Servlet_第44张图片
  • 斜杠/如果被服务器解析,得到的地址是:http://ip:port/工程路径
常见的地方有:

- xml中的<url-pattern>/servlet1<url-pattern>
- servletContext.getRealPath("/");
- request.getRequestDispatcher("/");
  • 特殊的是:response.sendRediect("/");是把斜杠发送给浏览器解析,得到http://ip:port/

13、HttpServletResponse类

输出流

HttpServletResponse和HttpServletRequest类一样,每次请求进来,Tomcat服务器都会创建一个Response对象传给Servlet程序使用。

HttpServletRequest表示请求过来的信息,HttpServletResponse表示所有响应的信息,如果需要设置返回给客户端的信息,则可通过HttpServletResponse对象来设置。

关于两个输出流:

  • 字节流 getOutputStream()方法,常用于下载(传递二进制数据)
  • 字符流 getWriter()方法,常用于回传字符串(用的多)

两个流不能同时使用。

【JavaWeb】第八章 Servlet_第45张图片
运行Tomcat实例:

【JavaWeb】第八章 Servlet_第46张图片

给客户端回传字符串

  • 代码:
    【JavaWeb】第八章 Servlet_第47张图片
  • 运行:
    【JavaWeb】第八章 Servlet_第48张图片
  • 当我们往客户端回传一个中文字符串的时候,会发现有乱码出现:
    【JavaWeb】第八章 Servlet_第49张图片
  • 查看默认的字符集,并设置服务器的字符集为UTF-8,以解决乱码:
    【JavaWeb】第八章 Servlet_第50张图片
    【JavaWeb】第八章 Servlet_第51张图片
  • 通过响应头,设置浏览器也使用UTF-8
    【JavaWeb】第八章 Servlet_第52张图片
    【JavaWeb】第八章 Servlet_第53张图片
response.setHeader("Content-Type","text/html; charset=UTF-8");
  • 最高效的是同时设置服务器和客户端都使用UTF-8字符集,还设置了响应头
    【JavaWeb】第八章 Servlet_第54张图片
    注意setContentType()方法虽然高效,但必须在获取流对象之前使用

14、请求重定向

请求重定向,是指客户端给服务器发请求,然后服务器告诉客户端说:我给你一个新地址,你去新地址访问。这就是请求的重定向(因为之前的地址可能已经废弃)。这就像生活中某旺铺搬迁,会在门口贴告示:新店已搬迁至南京路300弄

【JavaWeb】第八章 Servlet_第55张图片
注意和之前的转发做区分!

代码实现:

Response1:

package com.llg.web;

import ...

public class Response1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("曾到Response1一游");
        /**
         * 设置响应状态码302,表示重定向(已搬迁)
         */
        resp.setStatus(302);
        /**
         * 设置响应头,说明新的地址在哪儿
         */
        resp.setHeader("Location","http://localhost:8080/web1/response2");
        //resp.sendRedirect("http://localhost:8080/web1/response2");
    }
}

Response2:

package com.llg.web;

import ...

public class Response2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("this is Response2's result!!");
    }
}

配置web.xml文件:
【JavaWeb】第八章 Servlet_第56张图片

访问已废弃的localhost:8080/web1/response1:
【JavaWeb】第八章 Servlet_第57张图片
请求重定向的特点:(注意和之前的转发做区分)

  • 浏览器的地址栏会发生变化
  • 实际是两次请求,且不共享Request域中的数据
  • 不能访问WEB-INF下的资源,但可以转向访问工程外的资源,如www.baidu.com。
请求重定向,除了以上的:
resp.setStatus(302);
resp.setHeader("Location","http//localhost:8080/web1/response2");


还可直接调用方法sendRedirect()
resp.sendRedirect("http//localhost:8080/web1/response2");

两种重定向方式的效果都一样:

【JavaWeb】第八章 Servlet_第58张图片

你可能感兴趣的:(JavaWeb,servlet,java,tomcat)