Servlet基础详解)

一、Servlet技术

1. 了解Servlet

  1. Servlet 是 Javaee 规范之一,规范就是 api
  2. Servlet 是 JavaWeb 三大组件之一,三大组件:Servlet程序、Filter过滤器、Listener监听器
  3. Servlet 是运行在服务器上的 java 程序,用于接收客户端发送的请求,并响应数据给客户端

2. 手动实现Servlet程序

相关步骤:

        1)编写一个类实现 Servlet 接口

        2)实现接口中的 service 方法,用来处理请求,并响应数据

        3)到 web.xml 中,配置 servlet 程序的访问地址  

web.xml中的配置信息:

  1. <servlet>标签用来给Tomcat配置Servlet程序
            <servlet-name>标签给Servlet程序起别名
            <servlet-class>标签是Servlet程序的全类名
  2. <servlet-mapping>标签给Servlet程序配置访问地址
            <servlet-name>标签告诉浏览器,当前配置的地址是个哪个Servlet程序使用的(通常和<servlet>标签中<servlet-name>标签内容一样)
            <url-pattern>标签配置访问地址(格式:/ + 访问地址)

3. Servlet程序的生命周期

        1)执行构造器方法

        2)执行 init 初始化方法

        3)执行 service 方法

        4)执行 destroy 销毁方法

程序演示:启动服务器后,访问配置的servlet程序地址,执行的顺序如控制台所示

public class HelloServlet implements Servlet {
    public HelloServlet() {
        System.out.println("1. 构造器方法");
    }

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("2. init初始化方法");
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("3. service方法 === 访问:Hello Servlet!");
    }

    @Override
    public void destroy() {
        System.out.println("4. 销毁方法");
    }
}

注意:在执行顺序中,

        1)2)在第一次访问的时候,创建servlet程序会调用

        3)每次访问都会调用

        4)在web工程停止的时候,才会执行

4. Get/Post请求的分发处理

        1)通过 form 标签的 method 属性,表单的请求方式

<!-- 请求方法为POST -->
<form action="http://localhost:8080/06_Servlet/hello" method="post">
</form>

        2)在Servlet程序的service方法中,获取请求类型

 @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {        
        // 类型转换为HttpServletRequest,因为HttpServletRequest中有获取请求类型的方法
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        // 获取请求方法
        String method = httpServletRequest.getMethod();
}

        3)判断请求类型类别,执行不同的程序

        // 判断请求类型,执行不同操作
        if ("GET".equals(method)) {
            doGet();
        } else if ("POST".equals(method)) {
            doPost();
        }

        4)doGet方法、doPost方法,减少service方法中的代码量

    // 请求方法为Get时,执行的操作
    public void doGet() {
        System.out.println("Get方法");
    }
    // 请求方法为Post时,执行的操作
    public void doPost() {
        System.out.println("Post方法");
    }

5. 继承HttpServlet实现Servlet程序

在实际开发中,其实很少通过以上实现Servlet接口的方式去实现Servlet程序,而是使用继承HttpServlet类的方式去实现Servlet程序 。

        1)编写一个类继承HttpServlet

public class HelloServlet2 extends HttpServlet {
}

        2)根据业务需要,重写doGet或doPost方法,HttpServlet类中已经分发好了get和post请求,会自动调用相对应的方法

public class HelloServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("HelloServlet2的doGet方法");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("HelloServlet2的doPost方法");
    }
}

        3)到web.xml中配置Servlet程序的访问地址

    <servlet>
        <servlet-name>HelloServlet2</servlet-name>
        <servlet-class>com.ldyr.HelloServlet2</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloServlet2</servlet-name>
        <url-pattern>/hello2</url-pattern>
    </servlet-mapping>

6. Servlet类的继承体系


二、ServletConfig类 

1. 说明

        1)ServletConfig 类 ,用来给Servlet 程序配置初始化信息

        2)Servlet 程序和 ServletConfig 对象都是由 Tomcat 负责创建,我们负责使用

        3)Servlet 程序默认在第一次访问配置的地址的时候创建,ServletConfig 对象是每个 Servlet 程序创建时,就会创建一个对应的 ServletConfig 对象

        4)重写 init 初始化方法时,要在重写的方法中加上 super.init(ServletConfig实例对象),用来重新调用父类中的 init 方法,否则父类中的保存操作就会丢失,随之ServletConfig类 获取初始信息会出现问题

2. ServletConfig类三大作用

        1).getServletName(),可以获取Servlet程序的别名,也就是 servlet-name 标签的值

 @Override
    public void init(ServletConfig servletConfig) throws ServletException {

        //1)可以获取Servlet程序的别名,也就是 servlet-name 标签的值
        System.out.println("HelloServlet程序的别名是:" + servletConfig.getServletName());
}

        2).getInitParameter(),可以获取初始化参数 init-param,需要在web.xml中配置初始化参数 init-param(键值对的形式)

 @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        //2)可以获取初始化参数 init-param
        System.out.println("HelloServlet程序的初始化参数是:" + servletConfig.getInitParameter("username"));
        System.out.println("HelloServlet程序的初始化参数是:" + servletConfig.getInitParameter("password"));
        System.out.println("HelloServlet程序的初始化参数是:" + servletConfig.getInitParameter("url"));

}
<servlet>
    <!--        配置HelloServlet程序的初始化参数-->
        <init-param>
            <param-name>username</param-name>
            <param-value>root</param-value>
        </init-param>
        <init-param>
            <param-name>password</param-name>
            <param-value>123456</param-value>
        </init-param>
        <init-param>
            <param-name>url</param-name>
            <param-value>jdbc:mysql://localhost:3306/test</param-value>
        </init-param>
</servlet>

        3).getServletContext(),可以获取 ServletContext 对象

 @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        //3)可以获取 ServletContext 对象
        System.out.println("HelloServlet程序的ServletContext对象是:" + servletConfig.getServletContext());
}


三、ServletContext类

1. 说明

        1)ServletContext 类是一个接口,它表示 Servlet 上下文对象

        2)一个 web 工程只有一个 ServletContext 对象

        3)ServletContext 对象是域对象:

                i)域对象是可以向 Map 一样存取数据的对象        

                ii))这里的域指的是存取数据的范围,这个范围是整个 web 工程

        4)Map 和域对象区别

                                存数据                取数据                删除数据

                Map           put()                   get()                  remove()

            域对象        setAttribute()     getAttribute()     removeAttribute()       

        5)ServletContext 在 web 工程部署启动的时候创建,在 web 工程停止的时候销毁

2. ServletContext类的四个作用

        1).getInitParameter(),获取 web.xml 中配置的上下文参数 context-param,需要在 web.xml 中配置上下文参数context-param(键值对形式,属于整个 web 工程)

public class ServletContext extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws {
        // 1)获取 web.xml 中配置的上下文参数 context-param
        System.out.println("获取上下文参数username:" + servletContext.getInitParameter("username"));
    }
}
<!--    配置ServletContext程序的上下文参数-->
    <context-param>
        <param-name>username</param-name>
        <param-value>context</param-value>
    </context-param>
    <context-param>
        <param-name>password</param-name>
        <param-value>123456</param-value>
    </context-param>

  2).getContextPath(),获取当前的工程路径

public class ServletContext extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws {
        // 2)获取当前的工程路径
        System.out.println("当前的工程路径是:" + servletContext.getContextPath());
    }
}

        3).getRealPath(),获取工程部署后在服务器磁盘上的绝对路径

public class ServletContext extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws {
        // 3)获取工程部署后在服务器磁盘上的绝对路径
        // "/" 被浏览器解析为:http://ip:port/工程名/,相当于映射到IDEA代码的web目录
        System.out.println("工程部署的绝对路径是:" + servletContext.getRealPath("/"));
        System.out.println("WEB-INF的绝对路径是:" + servletContext.getRealPath("/WEB-INF"));
    }
}

        4)像Map一样存取数据

public class ServletContext extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws {
        // 4)像Map一样存取数据
        System.out.println("数据储存前的key1:" + servletContext.getAttribute("key1"));
        // key1 = value1
        servletContext.setAttribute("key1","value1");
        System.out.println("数据储存后的key1:" + servletContext.getAttribute("key1"));
    }
}

        5)注意:只要有 ServletContext 对象,同个工程下,不管在哪个 Servlet 程序中,都可以取到 ServletContext 对象中保存过的数据,不存在或没保存这个数据的话会返回null

public class ServletContext extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws {
        ServletContext servletContext = getServletContext();
        // 获取 ServletContext 对象中保存过的数据key1的值
        System.out.println("ServletContext对象的key1的值是:" + servletContext.getAttribute("key1"));
    }
}

四、Http 协议

 1. 什么是 Http 协议

        1)所谓 Http 协议,就是指,客户端和服务器之间通信时,发送的数据,需要遵守的规则,叫Http协议

        2)Http 协议中的数据,又称为报文

2. 请求的 Http 协议格式

        1)客户端给服务器发送的数据叫请求

        2)服务器给客户端回传的数据叫响应

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

                i)GET 请求

                        1.请求行

                                1)请求的方式                        GET

                                2)请求的资源路径                 [+?+请求参数]

                                3)请求的协议和版本号          HTTP/1.1

                        2.请求头

                                key:value 组成,不同的键值对,表示不同的意义

                        3.以下为 GET 请求的 HTTP 协议内容:

                ii)POST请求

                        1.请求行

                                1)请求的方式                        POST

                                2)请求的资源路径                 [+?+请求参数]

                                3)请求的协议和版本号          HTTP/1.1

                        2.请求头

                                1)key:value 组成,不同的键值对,表示不同的意义

                                2)请求头和请求体之间,有一个空行

                        3.请求体 ===>>> 发送给服务器的内容(用户输入的或选择的)

                        4.以下是POST请求的HTTP协议内容:

        4)常用请求头说明

                1. Accept:客户端可以接受的信息

                2. Accept-Language:客户端可以接受的语言类型

                3. User-Agent:浏览器的信息

                4. Host:请求时服务器 ip 和端口号

        5)区分 GET 请求和 POST 请求

                GET 请求有哪些?

                        1. form标签 method=get

                        2. a标签引入链接

                        3. img标签引入图片

                        4. iframe标签引入 html 页面窗口

                        5. link标签引入 css 文件

                        6. script标签引入 js 文件

                        7. 浏览器地址栏敲入地址后回车

        POST 请求有哪些?

                        8. form标签 method=POST

        

3. 响应的 Http 协议格式

        1)响应行

                1. 响应的协议和版本号

                2. 响应的状态码

                3. 响应的状态描述

        2)响应头

                1. key:value,不同的响应头,有不同的含义

                2. 响应头和响应体之间,有一个空行

        3)响应体 ===>>> 回传给客户端的数据

        4)以下为响应的 Http 协议内容:

4. 常用响应码说明

        1)200:表示请求成功

        2)302:表示请求重定向

        3)404:表示请求服务器已经收到,但是需要的数据不存在(通常是请求地址错误)

        4)500:表示服务器已经收到请求,但是服务器内部(代码)错误

5. MIME 类型说明

        1)MIME 是 Http 协议中的数据类型

        2)常见的 MIME 类型:


五、HttpServletRequest 类

1. HttpServletRequest 类的作用

       每次只要有请求进入 Tomcat 服务器,Tomcat 服务器就会把请求过来的 Http 协议信息解析好封装到 Request 对象中,然后传递到 service 方法(doGet/doPost)中给我们使用。我们可以通过 HttpServletRequest 对象,获取到所有请求的信息。

2. HttpServletRequest类的常用 API

        1)getRequestURI():获取请求的资源路径

        2)getRequestURL():获取请求的资源的绝对路径

        3)getRemoteHost():获取客户端的 IP 地址

        4)getHeader():获取请求头

        5)getParameter():获取请求的参数

        6)getParameterValues():获取请求的参数(多个值的时候使用)

        7)getMethod():获取请求的方式 Get/Post

        8)setAttribute(key,value):设置域数据

        9)getAttribute(key):获取域数据

        10)getRequestDispatcher():获取请求转发对象

代码演示:

public class RequestAPIServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//        1)getRequestURI():获取请求的资源路径
        System.out.println("URI:" + request.getRequestURI());

//        2)getRequestURL():获取请求的资源的绝对路径
        System.out.println("URL:" + request.getRequestURL());

//        3)getRemoteHost():获取客户端的 IP 地址
        System.out.println("客户端IP地址:" + request.getRemoteHost());

//        4)getHeader():获取请求头
        System.out.println("请求头Accept:" + request.getHeader("Accept"));

//        7)getMethod():获取请求的方式 Get/Post
        System.out.println("Method:" + request.getMethod());
    }
}

3. 获取客户端请求的参数:getParameter()

         1)新建一个表单页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form method="get" action="http://localhost:8080/06_Servlet/paramter">
        <label>用户名:</label><input type="text" name="username"><br>
        <label>密码:</label><input type="password" name="password"><br>
        <label>用户名</label><input type="checkbox" name="hobby" value="C">C
        <input type="checkbox" name="hobby" value="Java">Java
        <input type="checkbox" name="hobby" value="Python">Python<br>
        <input type="submit">
    </form>
</body>
</html>

        2)获取表单中的信息

public class ParameterServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//        5)getParameter():获取请求的参数
//        6)getParameterValues():获取请求的参数(多个值的时候使用)
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String[] hobby = request.getParameterValues("hobby");
        System.out.println("用户名:" + username);
        System.out.println("密码:" + password);
        System.out.println("爱好:" + Arrays.asList(hobby));
    }
}

               

         3)Post请求中文乱问题

public class ParameterServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        5)getParameter():获取请求的参数
//        6)getParameterValues():获取请求的参数(多个值的时候使用)
        System.out.println("-------------doGet--------------");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String[] hobby = req.getParameterValues("hobby");
        System.out.println("用户名:" + username);
        System.out.println("密码:" + password);
        System.out.println("爱好:" + Arrays.asList(hobby));
    }
}

        4)解决中文乱码的方法:可以通过设置请求体的字符集为 UTF-8,解决此问题,在上述 doPost 方法中加入以下代码。注意,.setCharacterEncoding()这个API需要在所有的获取请求参数前调用才有效。

// 设置请求体的字符集为UTF-8,解决Post请求的中文乱码问题
// .setCharacterEncoding()这个API需要在所有的获取请求参数前调用才有效
req.setCharacterEncoding("UTF-8");

4. 请求转发:getRequestDispatcher()

  • 请求的转发,是指服务器收到请求后,从一个资源跳转到另一个资源的操作叫请求转发

        1)资源1:Servlet1执行操作,并转发请求:getRequestDispatcher(path)

public class Servlet1 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("===========Servlet1业务=============");
        // 获取请求的参数
        String username = request.getParameter("username");
        System.out.println("获取的请求参数用户名是:" + username);

        // 设置域数据
        request.setAttribute("key1","Servlet1_pass");

        // 设置请求转发到??地址
        RequestDispatcher requestDispatcher = request.getRequestDispatcher("/servlet2");
        // 设置跳转到 /servlet2
        requestDispatcher.forward(request,response);
    }
}

        2)资源2:Servlet2执行业务

public class Servlet2 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("===========Servlet2业务=============");
        // 获取请求的参数
        String username = request.getParameter("username");
        System.out.println("获取的请求参数用户名是:" + username);

        // 查看请求转发前的域数据
        Object key1 = request.getAttribute("key1");
        System.out.println("请求转发前的数据key1:" + key1);

        // 处理业务
        System.out.println("Servlet2_pass");
    }
}

        3)请求转发的特点

                        1. 浏览器地址栏没有变化

                        2. 请求转发只有一次请求

                        3. 请求共享 Request 域中的数据 

                        4. 请求可以转发到 WEB-INF 目录下

                        5. 不可以访问本工程以外的资源

5. Base标签

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

代码演示:通过请求转发实现从 index.html 跳转到 /a/b/c.html 页面

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
    首页<br/>
    <a href="a/b/c.html">跳转到a/b/c.html</a><br>
    <a href="http://localhost:8080/06_Servlet/forwordC">请求转发:/a/b/c.html</a>
</body>
</html>

c.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>c.html</title>
    <!--base标签设置本页所有相对路径工作时,
    参照href属性中的路径进行跳转-->
    <base href="http://localhost:8080/06_Servlet/a/b/c.html">
</head>
<body>
    a下的b下的c.html<br/>
    <a href="../../index.html">跳转到首页</a>
</body>
</html>

实现请求转发的Servlet程序: 

public class ForwordC extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("请求转发到a/b/c.html");
        // 请求转发到a/b/c.html页面
        request.getRequestDispatcher("a/b/c.html").forward(request,response);
    }
}

六、HttpServletResponse 类

1. HttpServletResponse 类的作用

        HttpServletResponse 类和 HttpServletRequest 类一样。每次请求进来,Tomcat 服务器都会创建一个 Response 对象传递给 Servlet 程序使用。HttpServletRequest 表示请求过来的信息,HttpServletResponse 表示所有响应的信息,我们如果需要设置返回给客户端的信息,都可以通过 HttpServletResponse 对象来进行设置。

2. 两个响应流说明

        1)字节流:getOutputStream();        常用于下载(传递二进制数据)

        2)字符流:getWriter();        常用于回传字符串(常用)

        3)特点:字节流和字符流同时只能使用一个,否则就会报错

3. 回传给客户端数据 

        1)getWriter.writer(),往客户端回传 字符串 数据

public class ResponseIOServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 往客户端回传 字符串 数据
        PrintWriter writer = response.getWriter();
        writer.write("Response content");
    }
}

        2)若回传字符串为中文,则会出现乱码问题

public class ResponseIOServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 往客户端回传 字符串 数据
        PrintWriter writer = response.getWriter();
        writer.println("Response content");
        // 若回传为中文,则会出现中文乱码的问题
        writer.println("回传字符串数据");
    }
}

        3)解决中文乱码的两种方法

                i. 可以通过设置请求体的字符集为 UTF-8,解决此问题,但是浏览器的字符集为 GBK,所有还要通过设置响应头,来设置浏览器字符集为 UTF-8。

// 解决中文乱码的方法一:设置请求体的字符集为UTF-8,解决回传数据的中文乱码问题
// .setCharacterEncoding()这个API需要在所有的获取请求参数前调用才有效
response.setCharacterEncoding("UTF-8");
// 但是浏览器的字符集为 GBK,所以需要设置浏览器的响应字符集为U8
response.setHeader("Content-type","text/html; charset=UTF-8");

                 ii. setContentType(),同时设置服务器和浏览器的字符集为 UTF-8。注意:此方法一定要在获取流对象之前使用才有效。

// 解决中文乱码的方法二:同时设置服务器和浏览器的字符集为u8
response.setContentType("tetx/html; charset=UTF-8");

4. 请求重定向

        1)说明:请求重定向,是指客户端发请求给服务器,服务器告诉客户端一个新地址去访问,叫做请求重定向(重定向的原因:可能之前的地址已经被废弃)。

       

        2)重定向步骤:

                1. 在被弃用的 Servlet 程序中,

                        i. setStatus(),设置状态响应码 302 --- 表示重定向 

public class Response1 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Response1 已被弃用,重定向至 Response2");
        // 设置状态响应码:302,表示重定向
        response.setStatus(302);
    }
}

                        ii. setHeader(),设置响应头中心的地址 (Location,path),说明新的地址在哪里

public class Response1 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 设置响应头中心的地址 (Location,path),说明新的地址在哪里
        response.setHeader("Location","http://localhost:8080/06_Servlet/response2");
    }
}

               

                2. 在新的 Servlet 程序中,执行新的业务

public class Response2 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("已经重定向至 Response2");
        // 响应请求
        response.getWriter().write("response2 content");
    }
}

        3)请求重定向的特点

                1. 浏览器地址会发生变化

                2. 两次请求

                3. 不共享Request域中的数据,因为每次请求就会把请求过来的数据解析好封装成一个Request对象,两次请求不是一个Request对象

                4. 不能访问 WEB-INF 下的资源

                5. 可以访问本工程以外的资源

5. 请求重定向的方法二(推荐使用)

  • sendRedirect(),直接告诉重定向地址,由于 响应状态时固定的302,所有不需要设置
public class Response1 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        
        // 请求重定向的方法二:推荐使用
        response.sendRedirect("http://localhost:8080/06_Servlet/response2");
    }
}

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值