JavaWeb-02-Servlet

6 ,Servlet

Servlet 接口在 sun 公司有两个默认的实现类: HttpServlet,GenericServlet

6.1 Servlet简介

  • servlet 就是 sun 公司开发动态 web 的一门技术
  • Sun 公司在这些 API 中提供了一个接口:Servlet:
    • 编写一个类,实现 Servlet 接口
    • 把开发好的 Java 类部署到 web 服务器中

把实现了 Servlet 接口的 Java程序 叫做 Servlet

6.2 Hello Servlet

  1. 构建一个普通的 maven 项目,删掉 src 目录,

  2. 关于 maven 父子工程的理解:

    父项目中会有:

    <modules>
        <module>servlet-01</module>
        <module>servlet-02</module>
        <module>response</module>
        <module>request</module>
    </modules>
    

    子项目中会有:

        
    
  3. maven 环境优化:

​ 修改 web.xml 为最新的

​ 将 maven 结构搭建完整

  1. 编写一个 servlet 程序

​ 编写一个普通类

​ 实现 Servlet 接口,这里直接继承 HttpServlet

​ 编写 Servlet 的映射

​ 为什么需要映射,Java 程序 需要浏览器访问,浏览器需要连接 web 服务器,所以需要在 web 服务中心注册写的 Servlet ,还需要给他一个浏览器能够访问的 路径

<!--注册 servlet-->
<servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>com.kuang.servlet.HelloServlet</servlet-class>
</servlet>
<!--Servlet 的请求路径-->
<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
  1. 配置 Tomcat

  2. 启动测试

6.3 Servlet 原理

Servlet 是由 Web 服务器调用,web服务器 在收到浏览器请求后,会:

在这里插入图片描述

6.4 Mapping 问题

  1. 一个servlet 可以指定一个映射路径
  2. 一个servlet 可以指定多个映射路径
  3. 一个servlet 可以指定通用映射路径

6.5 ServletContext

web 容器在启动的时候,他会为每个web程序都创建一个对应的 ServletContext 对象,他代表了当前的 web 应用

1 ,共享数据

在这个 servlet 中保存的数据,可以再另外一个 servlet 中拿到;

放置数据的类:

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // this.getInitParameter()  初始化参数
        // this.getServletConfig()  Servlet配置
        // this.getServletContext()  Servlet上下文

        ServletContext context = this.getServletContext();

        String username = "姚明";    // 数据
        context.setAttribute("username",username); // 将一个数据保存在了 ServletContext 中,名字为:username 值:username



        System.out.println("hello");
    }


}

读取数据的类:

public class GetServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();

        String username =(String) context.getAttribute("username");

        resp.setContentType("text/html");
        resp.setCharacterEncoding("utf-8");
        resp.getWriter().println("名字"+username);
    }

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

配置文件:

<?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_4_0.xsd"
         version="4.0"
         metadata-complete="true">
    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.kuang.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>getc</servlet-name>
        <servlet-class>com.kuang.servlet.GetServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>getc</servlet-name>
        <url-pattern>/getc</url-pattern>
    </servlet-mapping>



</web-app>

启动测试:

2 ,获取初始化参数

配置初始化参数

<!--配置 web 应用的初始化参数-->
<context-param>
    <param-name>url</param-name>
    <param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>

拿到参数:

package com.kuang.servlet;

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

public class ServletDemo03 extends HelloServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();

        String url = context.getInitParameter("url");
        resp.getWriter().println(url);
    }

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

注册:

<servlet>
    <servlet-name>url</servlet-name>
    <servlet-class>com.kuang.servlet.ServletDemo03</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>url</servlet-name>
    <url-pattern>/urls</url-pattern>
</servlet-mapping>

启动测试

3 ,请求转发

package com.kuang.servlet;


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

public class ServletDemo04 extends HelloServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        System.out.println("进入了ServletDemo04");
        // RequestDispatcher requestDispatcher = context.getRequestDispatcher("urls");// 转发的请求路径
        // requestDispatcher.forward(req,resp); // 调用 forward 方法 实现请求转发
        context.getRequestDispatcher("/urls").forward(req,resp);

    }

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

4 ,读取资源文件

Properties 类:

  • 在 java 目录下新建 properties
  • 在 resources 目录下新建 properties

都被打包在了 classes 路径下

思想:需要一个文件流

username=root
password=root
package com.kuang.servlet;

import javax.servlet.http.HttpServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class PropertiesServlet extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext(); 
        
        // 把资源变成一个流  返回一个 is 流   /WEB-INF 代表当前 web 项目
        InputStream is = context.getResourceAsStream("/WEB-INF/classes/com/kuang/servlet/aa.properties");

        Properties properties = new Properties();
        properties.load(is);  // 把流加载进去
        
        // 获取属性
        String user = properties.getProperty("username");
        String pwd = properties.getProperty("password");
        
        resp.getWriter().println(user+pwd);  // 输出到前端


    }

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

访问测试即可

6.6 HttpServletResponse

响应

web 服务器 接收到客户端的 http 请求,针对这个请求,分别创建一个代表请求的 HttpServletRequest 对象,代表响应的一个 HttpServletResponse 对象;

  • 如果要获取客户端请求过来的参数,找 HttpServletRequest
  • 如果要给客户端响应一些参数:找 HttpServletResponse

1 ,简单分类

负责向浏览器发送数据的方法

  • ServletOutputStream getOutputStream() throws IOException;
    PrintWriter getWriter() throws IOException;
    

负责向浏览器发送一些响应头的方法

void setCharacterEncoding(String var1);

void setContentLength(int var1);

void setContentLengthLong(long var1);

void setContentType(String var1);

void setDateHeader(String var1, long var2);

void addDateHeader(String var1, long var2);

void setHeader(String var1, String var2);

void addHeader(String var1, String var2);

void setIntHeader(String var1, int var2);

void addIntHeader(String var1, int var2);

响应状态码:

int SC_CONTINUE = 100;
int SC_SWITCHING_PROTOCOLS = 101;
int SC_OK = 200;
int SC_CREATED = 201;
int SC_ACCEPTED = 202;
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
int SC_NO_CONTENT = 204;
int SC_RESET_CONTENT = 205;
int SC_PARTIAL_CONTENT = 206;
int SC_MULTIPLE_CHOICES = 300;
int SC_MOVED_PERMANENTLY = 301;
int SC_MOVED_TEMPORARILY = 302;
int SC_FOUND = 302;
int SC_SEE_OTHER = 303;
int SC_NOT_MODIFIED = 304;
int SC_USE_PROXY = 305;
int SC_TEMPORARY_REDIRECT = 307;
int SC_BAD_REQUEST = 400;
int SC_UNAUTHORIZED = 401;
int SC_PAYMENT_REQUIRED = 402;
int SC_FORBIDDEN = 403;
int SC_NOT_FOUND = 404;
int SC_METHOD_NOT_ALLOWED = 405;
int SC_NOT_ACCEPTABLE = 406;
int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
int SC_REQUEST_TIMEOUT = 408;
int SC_CONFLICT = 409;
int SC_GONE = 410;
int SC_LENGTH_REQUIRED = 411;
int SC_PRECONDITION_FAILED = 412;
int SC_REQUEST_ENTITY_TOO_LARGE = 413;
int SC_REQUEST_URI_TOO_LONG = 414;
int SC_UNSUPPORTED_MEDIA_TYPE = 415;
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
int SC_EXPECTATION_FAILED = 417;
int SC_INTERNAL_SERVER_ERROR = 500;
int SC_NOT_IMPLEMENTED = 501;
int SC_BAD_GATEWAY = 502;
int SC_SERVICE_UNAVAILABLE = 503;
int SC_GATEWAY_TIMEOUT = 504;
int SC_HTTP_VERSION_NOT_SUPPORTED = 505;

2 ,常见应用:

1.向浏览器输送消息
2.下载文件
  1. 要获取文件下载的路径
  2. 下载的文件名是啥
  3. 设置想办法让浏览器支持下载我们需要的东西
  4. 获取下载文件的输入流
  5. 创建缓冲区
  6. 获得 OutputStream 对象
  7. 将 FileOutputStream 流写入到 buffer 缓冲区
  8. 使用 OutputStream 将缓冲区中的数据输出到客户端

3 ,验证码功能

验证怎么来?

  • 前端实现
  • 后端实现,需要用到 java 的图片类,生成一个图片

4 ,实现重定向

*提交路径:action="${pageContext.request.contextPath}/se"

<form action="${pageContext.request.contextPath}/se" method="get">
    用户名:<input type="text" name="username"></br>
    密码 :<input type="password" name="password"><br>
    <input type="submit">
</form>

B 一个 web 资源受到客户端 A 的请求后,B 会通知 A 客户端去访问另外一个 web 资源C,这个过程叫做重定向

常见场景:页面跳转

  • 用户登录

    void sendRedirect(String var1) throws IOException;
    

    测试:

    登录页面:

    <html>
    <body>
    <h2>Hello World!</h2>
    
    <form action="${pageContext.request.contextPath}/se" method="get">
        用户名:<input type="text" name="username"></br>
        密码 :<input type="password" name="password"><br>
        <input type="submit">
    </form>
    
    
    </from>
    
    </body>
    </html>
    

    跳转页面:

    <%--
      Created by IntelliJ IDEA.
      User: 小狂神
      Date: 2021/7/29
      Time: 9:31
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    
    <h1>success</h1>
    
    </body>
    </html>
    
    

    java 代码:

    package com.kuang.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    public class RedirectServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 获取前端参数
            String username = req.getParameter("username");
            String password = req.getParameter("password");
            // 将参数输出到后台
            System.out.println(username+":"+password);
            
            // 重定向
            resp.sendRedirect("/r/success.jsp");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    

    面试题:重定向和转发的区别?

    相同点:页面都会实现跳转

    不同点:请求转发的时候,URL 不会发生变化,重定向的时候,URl 地址栏会发生变化

6.7 HttpServletRequest

HttpServletRequest 代表客户端的请求,用户通过 http 协议访问服务器,http 请求中的所有信息会被封装到 HttpServletRequest,通过这个HttpServletRequest 的方法 获得客户端的所有信息

1 ,获取前端传递的参数,请求转发

前端的 index

<%--
  Created by IntelliJ IDEA.
  User: 小狂神
  Date: 2021/7/29
  Time: 11:12
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录</title>
</head>
<body>

<h1>登录页面</h1>
<div style="text-align: center">

    <%--这里表单表示的意思:以 post 方式提交表单,提交到我们的 login 请求--%>
    <form action="${pageContext.request.contextPath}/login" method="post">
        用户名:<input type="text"name="username"><br>
        密码 :<input type="password" name="password"><br>
        爱好 :
        <input type="checkbox" name="hobby" value="男">男
        <input type="checkbox" name="hobby" value="女">女
        <input type="checkbox" name="hobby" value="打球">打球
        <input type="checkbox" name="hobby" value="唱歌">唱歌

        <br>
        <input type="submit">
    </form>
</div>


</body>
</html>

前端的跳转页面 success

<%--
  Created by IntelliJ IDEA.
  User: 小狂神
  Date: 2021/7/29
  Time: 11:22
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<h1>登陆成功</h1>

</body>
</html>

java 代码:

package com.kuang.servlet;

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

public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 解决乱码问题
        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");

        // 获取参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        // req.getParameterValues()  获取多个参数值
        String[] hobbies = req.getParameterValues("hobby");

        System.out.println("===========================================");
        // 后台接收中文乱码问题
        System.out.println(username);
        System.out.println(password);
        System.out.println(Arrays.toString(hobbies)); // 打印数组元素
        System.out.println("===========================================");

        System.out.println(req.getContextPath());
        // 通过请求转发
        // 这里的 / 代表当前的 web 应用
        req.getRequestDispatcher("/success.jsp").forward(req,resp);




    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
  • 注册 servlet
  • 启动 Tomcat 测试

面试题:重定向和转发的区别?

相同点:页面都会实现跳转

不同点:请求转发的时候,URL 不会发生变化,307 重定向的时候,URl 地址栏会发生变化 302


版权声明:本文为Who_heard原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。