JavaWeb系列七: 动态WEB开发核心(Servlet) 下

在这里插入图片描述

ServletConfig

ServletConfig基本介绍
1.ServletConfig 类是为Servlet程序配置信息的类
2.Servlet程序和ServletConfig对象都是由Tomcat负责创建的
3.Servlet程序默认是第1次访问的时候创建.ServletConfigServlet程序创建时, 就创建一个对应的ServletConfig对象

ServletConfig类能干什么
1.获取Servlet程序的servlet-name的值
2.获取初始化参数init-param
3.获取ServletContext对象

ServletConfig应用实例
需求: 编写DBServlet.java, 实现如下功能
1.在web.xml中编写连接mysql的用户名和密码
2.在DBServlet执行doGet() / doPost()方法时, 均可以获取到web.xml配置的用户名和密码
3.示意图(思路分析)
在这里插入图片描述

1.web.xml配置DBServlet

<servlet>
    <servlet-name>DBServlet</servlet-name>
    <servlet-class>com.zzw.servlet.DBServlet</servlet-class>
    <!--配置信息, 而不是硬编码到程序-->
    <init-param>
        <param-name>username</param-name>
        <param-value>zzw</param-value>
    </init-param>
    <init-param>
        <param-name>pwd</param-name>
        <param-value>123456</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>DBServlet</servlet-name>
    <url-pattern>/dbServlet</url-pattern>
</servlet-mapping>

2.在com.zzw.servlet下新建DBServlet

public class DBServlet extends HttpServlet {

    /**
     * 老师梳理ServletConfig config 使用流程
     * 1.当DBServlet对象初始化时, tomcat会同时创建一个 ServletConfig对象
     * 2.这时如果DBServlet init() 方法中你调用super.init(config)
     * 3.调用 父类 GenericServlet
     *     public void init(ServletConfig config) throws ServletException {
     *         this.config = config;
     *         this.init();
     *     }
     * 4.这时就会把 Tomcat创建的 ServletConfig对象赋给 GenericServlet的属性 config
     * 5.如果注销super.init(config), 那么在doGet,doPost和其它方法中将无法通过 getServletConfig() 方法获取ServletConfig
     * 6.因此如果你要重写init()方法, 还想在其它方法通过 getServletConfig() 方法获取ServletConfig
     *   , 则一定要记住 在init()方法中 调用 super.init(config)
     * @param config
     * @throws ServletException
     */
    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("init() config=" + config);
        super.init(config);

    }

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //在DBServlet执行doGet() / doPost()方法时, 均可以获取到web.xml配置的用户名和密码
        //OOP程序员->现有的方法或对象来实现
        //DBServlet的父类有GenericServlet有getServletConfig()
        /**
         * 解读
         * 1. getServletConfig() 方法是 GenericServlet
         * 2. 返回的 servletConfig对象是 GenericServlet private transient ServletConfig config;
         * 3. 当一个属性被transient修饰, 表示该属性不会被串行化(有些重要信息, 不希望保存到文件)
         */
        ServletConfig servletConfig = this.getServletConfig();
        System.out.println("doPost() servletConfig=" + servletConfig);
        String username = servletConfig.getInitParameter("username");
        String pwd = servletConfig.getInitParameter("pwd");
        System.out.println("初始化参数username=" + username);
        System.out.println("初始化参数pwd=" + pwd);
    }
}

ServletContext

为什么需要ServletContext
1.先看一个需求: 如果我们希望统计某个web应用所有的Servlet被访问的次数, 怎么办?
2.方案1-DB

在这里插入图片描述

2.方案2-ServletContext

在这里插入图片描述

ServletContext基本介绍

  1. ServletContext是一个接口, 他表示Servlet上下文对象
  2. 一个web工程, 只有一个ServletContext对象实例
  3. ServletContext对象在web工程启动的时候创建, 在web工程停止的时候销毁
  4. ServletContext对象可以通过this.getServletConfig().getServletContext()方法获得ServletContext对象的引用, 也可以通过this.getServletContext()来获得其对象的引用
  5. 由于一个WEB应用中的所有Servlet共享同一个ServletContext对象, 因此Servlet对象之间可以通过ServletContext对象来实现通信. ServletContext对象通常也称之为域对象.

ServletContext可以做什么
1.获取web.xml 中配置的上下文参数context-param[这个信息和整个web应用相关, 而不是属于某个Servlet]
2.获取当前的工程路径, 格式: /工程路径 ⇒ 比如 /servlet
3.获取工程部署后在服务器硬盘上的绝对路径 (比如: D:\idea_project\zzw_javaweb\servlet\out\artifacts\servlet_war_exploded)
4.像Map一样存取数据, 多个Servlet共享数据
在这里插入图片描述

应用实例1-获取工程相关信息
●需求如下
1.获取web.xml中配置的上下文参数 context-param
2.获取当前的工程路径, 格式: /工程路径
3.获取工程部署后在服务器硬盘上的绝对路径

●代码实现
1.修改web.xml, 增加相关配置

<!--配置整个网站的信息-->
<context-param>
    <param-name>website</param-name>
    <param-value>http://www.baidu.com</param-value>
</context-param>
<context-param>
    <param-name>company</param-name>
    <param-value>百度</param-value>
</context-param>

2.web.xml配置ServletContext_

<!--配置ServletContext_-->
<servlet>
    <servlet-name>ServletContext_</servlet-name>
    <servlet-class>com.zzw.servlet.servletcontext.ServletContext_</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ServletContext_</servlet-name>
    <url-pattern>/servletContext_</url-pattern>
</servlet-mapping>

3.com.zzw.servlet.servletcontext下新建ServletContext_

public class ServletContext_ extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取web.xml的context-parameter

        //1.获取ServletContext对象
        ServletContext servletContext =
                this.getServletConfig().getServletContext();
        //2.获取website
        String website = servletContext.getInitParameter("website");
        String company = servletContext.getInitParameter("company");
        //3.获取项目的工程路径
        String contextPath = servletContext.getContextPath();
        //4.获取项目发布后, 真正的工作路径
        //  / 表示我们的项目(发布后)的 根路径
        //  D:\idea_project\zzw_javaweb\servlet3\out\artifacts\servlet3_war_exploded
        String realPath = servletContext.getRealPath("/");
        System.out.println("项目发布后的绝对路径 realPath=" + realPath);
        System.out.println("contextPath=" + contextPath);
        System.out.println("website=" + website);
        System.out.println("company=" + company);
    }
}

网站计数器

需求分析/图解
1.需求: 完成一个简单的网站访问次数计数器
2.使用Chrome访问Servlet01, 每访问一次, 就增加1访问次数, 在后台输出, 并将结果返回给浏览器显示.
3.使用火狐访问Servlet02, 每访问一次, 就增加1访问次数, 在后台输出, 并将结果返回给浏览器显示.
在这里插入图片描述

●代码实现
1.在web.xml配置OrderServlet, PayServlet

<servlet>
    <servlet-name>OrderServlet</servlet-name>
    <servlet-class>com.zzw.servlet.servletcontext.OrderServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>OrderServlet</servlet-name>
    <url-pattern>/orderServlet</url-pattern>
</servlet-mapping>
<servlet>
    <servlet-name>PayServlet</servlet-name>
    <servlet-class>com.zzw.servlet.servletcontext.PayServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>PayServlet</servlet-name>
    <url-pattern>/payServlet</url-pattern>
</servlet-mapping>

2.com.zzw.servlet.servletcontext创建OrderServlet

public class OrderServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取到ServletContext对象
        ServletContext servletContext =
                this.getServletConfig().getServletContext();

        //System.out.println("OrderServlet servletContext=" + servletContext + " 运行类型=" + servletContext.getClass());

        从servletContext获取 visit_count 属性
        //Object visit_count = servletContext.getAttribute("visit_count");
        判断visit_count是否为null
        //if (visit_count == null) {//说明是第1次访问
        //    servletContext.setAttribute("visit_count", 1);
        //    visit_count = 1;
        //} else {//是第二次或以后
        //    //取出visit_count属性的值+1
        //    visit_count = Integer.parseInt(visit_count + "") + 1;
        //    //放回到servletContext
        //    servletContext.setAttribute("visit_count", visit_count);
        //}

        Integer visit_count = WebUtils.visitCount(servletContext);
        //输出显示
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write("<h1>新网站被访问的次数是</h1>" + visit_count + "次</h1>");
    }
}

3.com.zzw.servlet.servletcontext创建PayServlet

public class PayServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取到ServletContext对象
        ServletContext servletContext =
                this.getServletConfig().getServletContext();

        //System.out.println("PayServlet servletContext=" + servletContext + " 运行类型=" + servletContext.getClass());

        从servletContext获取 visit_count 属性
        //Object visit_count = servletContext.getAttribute("visit_count");
        判断visit_count是否为null
        //if (visit_count == null) {//说明是第1次访问
        //    servletContext.setAttribute("visit_count", 1);
        //    visit_count = 1;
        //} else {//是第二次或以后
        //    //取出visit_count属性的值+1
        //    visit_count = Integer.parseInt(visit_count + "") + 1;
        //    //放回到servletContext
        //    servletContext.setAttribute("visit_count", visit_count);
        //}

        Integer visit_count = WebUtils.visitCount(servletContext);
        //输出显示
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write("<h1>新网站被访问的次数是</h1>" + visit_count + "次</h1>");
    }
}

4.在com.zzw.servlet.servletcontext新建WebUtils

public class WebUtils {

    //这个方法就是对访问的次数累积, 同时返回次数
    public static Integer visitCount(ServletContext servletContext) {
        //从servletContext获取 visit_count 属性
        Object visit_count = servletContext.getAttribute("visit_count");
        //判断visit_count是否为null
        if (visit_count == null) {//说明是第1次访问
            servletContext.setAttribute("visit_count", 1);
            visit_count = 1;
        } else {//是第二次或以后
            //取出visit_count属性的值+1
            visit_count = Integer.parseInt(visit_count + "") + 1;
            //放回到servletContext
            servletContext.setAttribute("visit_count", visit_count);
        }
        return Integer.parseInt(visit_count + "");
    }
}

5.测试
在这里插入图片描述

HttpServletRequest

1.HttpServletRequest对象代表客户端的请求

2.当客户端/浏览器通过HTTP协议访问服务器时, HTTP请求头中所有的信息都封装在这个对象中

3.通过这个对象的方法, 可以获取客户端信息

HttpServletRequest类图

在这里插入图片描述

HttpServletRequest常用方法

getServletPath()…

1.getRequestURI() 获取请求的资源路径 http://localhost:8080/servlet/login.html

2.getRequestURL() 获取请求的统一资源定位符(绝对路径) http://localhost:8080/servlet/login.html

3.getHeader() 获取请求头

4.getParameter() 获取请求的参数

5.getParameterValues() 获取请求的参数(多个值时使用) 比如checkbox, 或返回的数组

6.getRemoteHost() 获取客户端的主机

7.getRemoteAddr() 获取客户端的ip

8.getMethod() 获取请求的方式(GET或POST)

9.setAttribute(key, value) 设置域数据

10.getAttribute(key) 获取域数据

11.getRequestDispatcher() 获取请求转发对象 (请求转发的核心对象)

HttpServletRequest应用实例

1.需求: 在一个表单提交数据给 Servlet, 然后在 Servlet 通过 HttpServletRequest 对象获取相关数据.

2.创建E:\idea_project\zzw_javaweb\servlet\web\register_request.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册</title>
</head>
<body>
<h1>注册用户</h1>
<form action="http://localhost:8888/servlet/requestMethods" method="post">
    u: <input type="text" name="username"/><br/>
    p: <input type="password" name="password"><br/>
    选择你喜欢的老师<br/>
    <input type="checkbox" name="favorite" value="秋香老师"/>秋香老师
    <input type="checkbox" name="favorite" value="雅蝶老师">雅蝶老师
    <input type="checkbox" name="favorite" value="美女老师">美女老师<br/><!--不选后端接收null-->
    你的年龄<br/>
    <input type="radio" name="age" value="21">21岁
    <input type="radio" name="age" value="22">22岁
    <input type="radio" name="age" value="23">23岁<br/><!--不选后端接收null-->
    你的生日和邮箱<br/>
    <input type="date" name="date">
    <input type="email" name="email"><br/> <!--不填后端接收空字符串""-->
    你的所在城市
    <select name="city">
        <option value="">请选择城市</option>
        <option value="beijing">北京</option>
        <option value="shanghai">上海</option>
        <option value="nanjing">南京</option>
    </select><br/>
    你的自我介绍<br/>
    <textarea name="introduction"></textarea><br/>
    你要上传的文件<br/>
    <input type="file" name="file"/><br/><!--暂不处理文件提交-->
    <input type="submit" value="注册用户"/>
    <input type="reset" value="重置"/>
</form>
</body>
</html>

3.创建src/com/zzw/servlet/request/HttpServletRequestMethods.java

public class HttpServletRequestMethods extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /********************************
         *      获取http请求头相关信息      *
         ********************************/
        System.out.println("请求头信息");
        System.out.println("资源路径URI(请求中的)=" + request.getRequestURI());// /servlet/requestMethods
        System.out.println("统一资源定位符(绝对路径)URL=" + request.getRequestURL());// http://localhost:8888/servlet/requestMethods
        System.out.println("客户端ip地址=" + request.getRemoteAddr());// 0:0:0:0:0:0:0:1
        // 获取http请求头的信息: 可以使用request.getHeader("请求头字段")
        // 可以指定 Accept, Accept-Encoding, Accept-Language, Connection, Cookie, Host, Referer
        System.out.println("http请求头中的Accept信息=" + request.getHeader("Accept"));// text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
        System.out.println("http请求头中的Host=" + request.getHeader("Host"));// localhost:8888
        System.out.println("http请求方式(GET/POST)=" + request.getMethod());// POST
        String cookie = request.getHeader("Cookie");
        String[] split = cookie.split("=");
        System.out.println("cookie=" + split[1]);// cookie=10B3ED94B98A25B414E4EA1B3E131A19; rememberMe
        /********************************
         *        获取表单提交的数据        *
         ********************************/
        //1.获取单个表单数据
        // 解决接收参数的中文乱码问题, 不能写在request.getParameter()后面
        request.setCharacterEncoding("utf-8");//浏览器按照urlEncode编码方式提交数据, 后端要用utf-8来接收
        String username = request.getParameter("username");//zhaozhiwei
        String password = request.getParameter("password");//123456
        String date = request.getParameter("date");//2024-06-28
        String age = request.getParameter("age");//21
        String email = request.getParameter("email");//978964140@qq.com
        System.out.println("username=" + username);
        System.out.println("password=" + password);//前端不填text输入框, 后端接收后是一个空字符串"", 不是null
        System.out.println("date=" + date);
        System.out.println("age=" + age); //单选框前端不选则后端返回的是null
        System.out.println("\"\".equals(age) -> " + "".equals(age));// false
        System.out.println("age == null -> " + (age == null));// true
        System.out.println("email=" + email);
        System.out.println("\"\".equals(email) -> " + "".equals(email));// true
        System.out.println("email == null -> " + (email == null));// false


        //2.获取一组表单数据 复选框, 下拉框
        String[] favorites = request.getParameterValues("favorite");
        if (favorites != null) {//复选框前端不选则后端返回的是null
            System.out.println("favorites=" + Arrays.asList(favorites));// favorites=[秋香老师, 雅蝶老师, 美女老师]
            for (String favorite : favorites) {
                System.out.print(favorite + " ");
            }
        }

        String city = request.getParameter("city");
        /*
         1. 前端下拉框value选定空字符串时, 后端接收后是一个空字符串"", 不是null
         2. 前端下拉框value不选时, 后端接收后是文本值"请选择城市"
         */
        System.out.println("city=" + city);
        System.out.println("\"\".equals(city) -> " + "".equals(city));// true
        System.out.println("city == null -> " + (city == null));// false
        
        String introduction = request.getParameter("introduction");
        System.out.println("introduction=" + introduction);//前端不填textarea输入框, 后端接收后是一个空字符串"", 不是null
        System.out.println("\"\".equals(introduction) -> " + "".equals(introduction));// true
        System.out.println("introduction == null -> " + (introduction == null));// false

        /*
         1.返回接收到的信息, 给浏览器回显
         2.本质实在http响应头加上Content-Type: text/html;charset=utf-8
           (1)text/html 表示返回的数据,请浏览器使用html方式解析
           (2)text/plain 表示返回的数据,请浏览器使用文本方式解析
           (3)application/x-tar 表示返回的是一个文件,浏览器就会以下载文件的方式处理
         */
        response.setContentType("text/html; charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("<h1>提交的用户名=" + username + "</h1>");
        writer.flush();
        writer.close();
    }
}

4.配置web.xml

<servlet>
    <servlet-name>HttpServletRequestMethods</servlet-name>
    <servlet-class>com.zzw.servlet.request.HttpServletRequestMethods</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>HttpServletRequestMethods</servlet-name>
    <url-pattern>/requestMethods</url-pattern>
</servlet-mapping>

注意事项和细节

1.text, date, password, email类型的输入框如果不填值会将空字符串传给后端. username=&password=&date=&email=, 后端用request.getParameter()接收这些值便是空字符串.

2.单选框, 复选框如果不选(不包括下拉框), 则不向后台传值, 即username=&password=&date=&email=&city=这里根本就没有单选框和复选框的参数, 后台通过request.getParameter()request.getParameterValues()获取实际上是获取了一个不存在的参数, 后端接收后是一个null.

3用request.getParameter()获取前端传来的数组, 实际上获取的是数组的第一个值.

4.获取 doPost 参数中文乱码问题: 注意 request.setCharacterEncoding("utf-8"); 要写在request.getParameter()前面.

request.setCharacterEncoding("utf-8");//浏览器按照urlEncode编码方式提交数据, 后端要用utf-8来接收
String username = request.getParameter("username");//赵志伟
String password = request.getParameter("password");//123456

5.注意:如果通过 PrintWriter writer, 有返回数据给浏览器,建议将获取参数代码写在 writer.print() 之前,否则可能获取不到参数值(doPost)

6.处理 http 响应数据中文乱码问题.

//解决返回数据乱码问题, 要放在 response.getWriter() 之前
response.setContentType("text/html; charset=utf-8");
PrintWriter writer = response.getWriter();
writer.print("<h1>提交的用户名=" + username + "</h1>");
writer.flush();
writer.close();

7.再次理解 Http 协议响应 Content-Type 的含义, 比如 text/plain application/x-tar, 浏览器会根据这个类型来解析数据

    //本质实在http响应头加上Content-Type: text/html;charset=utf-8
    // text/plain 表示返回的数据,请浏览器使用文本方式解析
    // application/x-tar 表示返回的是一个文件,浏览器就会以下载文件的方式处理
    response.setContentType("application/x-tar; charset=utf-8");
    PrintWriter writer = response.getWriter();
    writer.print("<h1>提交的用户名=" + username + "</h1>");
    writer.flush();
    writer.close();

课堂练习

1.请通过 HttpServletRequest 对象获取到, 是什么浏览器访问过服务器.
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36

// 获取是什么浏览器访问了服务器
String header = request.getHeader("User-Agent");
System.out.println("http请求头中的User-Agent信息=" + header);
String broswer = header.substring(header.lastIndexOf(" ") + 1, header.lastIndexOf("/"));
System.out.println("是什么浏览器访问了服务器 -> " + broswer);

2.想办法获取到 JSESSIONID 的值.

// 获取JESSIONID的值
String cookieValue = request.getHeader("Cookie");
if (cookieValue != null) {
    String[] split = cookieValue.split(";");
    String[] jessionId = split[0].split("=");
    System.out.println(jessionId[0] + " = " + jessionId[1]);
}

请求转发

为什么需要请求转发

在这里插入图片描述

请求转发说明

1.实现请求转发: 请求转发指一个web资源收到客户端请求后, 通知服务器(比如Tomcat)去调用另外一个web资源进行处理.

2.HttpServletRequest对象(也叫Request对象)提供了一个getRequestDispather方法, 该方法返回一个RequestDispacher对象, 调用这个对象的forward方法可以实现请求转发.

3.request对象同时也是一个域对象, 开发人员通过request对象在实现转发时, 把数据通过request对象带给其它web资源.

setAttribute方法
getAttribute方法
removeAttribute方法
getAttributeNames方法

实现请求转发

需求: 如果是tom, 提示为管理员, 其它是普通用户.

在这里插入图片描述

在这里插入图片描述

请求转发原理示意图

在这里插入图片描述

请求转发应用实例

1.新建web/login.html

<form action="http://localhost:8888/servlet/loginServlet" method="post">
   user: <input type="text" name="username"/><br/>
  <input type="submit" value="登录"/>
  <input type="reset" value="重置"/>
</form>

2.新建src/com/zzw/servlet/request/CheckServlet.java

public class CheckServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("CheckServlet doPost()被调用...");

        //设置请求体的编码
        request.setCharacterEncoding("utf-8");
        //根据用户名来确定该用户是什么身份
        String username = request.getParameter("username");

        //在请求转发中, request对象是同一个, 那么可以在不同的servlet中,获取同一个请求参数
        if ("tom".equals(username)) {
            request.setAttribute("role", "管理员");
        } else {
            request.setAttribute("role", "普通用户");
        }

        //获取分发器
        //1. /manageServlet 表示要请求转发的 servlet的url
        //2. / 会被解析成 /web工程路径
        //3. forward(request, response) 方法会把当前servlet的request对象和response对象
        //, 传递给下一个servlet使用.
        request.getRequestDispatcher("/manageServlet").forward(request, response);
    }
}

3.新建src/com/zzw/servlet/request/ManageServlet.java

public class ManagerServlet extends HttpServlet {
    private int count;
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        String username = request.getParameter("username");
        String role = (String) request.getAttribute("role");

        //输出信息
        response.setContentType("text/html; charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println("<h1>用户名 " + username + "</h1>");
        writer.print("<h1>角色=" + role + "</h1>");
        writer.flush();
        writer.close();
    }
}

3.配置web.xml

<servlet>
    <servlet-name>CheckServlet</servlet-name>
    <servlet-class>com.zzw.servlet.request.CheckServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>CheckServlet</servlet-name>
    <url-pattern>/checkServlet</url-pattern>
</servlet-mapping>
<servlet>
    <servlet-name>ManageServlet</servlet-name>
    <servlet-class>com.zzw.servlet.request.ManageServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ManageServlet</servlet-name>
    <url-pattern>/manageServlet</url-pattern>
</servlet-mapping>

注意事项和细节

1.浏览器地址栏不会发生变化(地址会停留在第1servleturl)

2.在同一次HTTP请求中, 进行多次转发, 仍然是一次HTTP请求

3.在同一次HTTP请求中, 进行多次转发, 多个Servlet可以共享request域/对象的数据(因为始终是同一个request对象)

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

5.不能访问当前WEB工程外的资源

6.如果最初的请求是 GET 请求,那么在转发后仍然是 GET 请求;如果最初的请求是 POST 请求,那么在转发后仍然是 POST 请求

7.转发和重定向的后续代码会被执行, 根据情况可添加return 👉参考

8.因为浏览器地址栏会止在第一个servlet ,如果你刷新页面,会再次发出请求(并且会带数据), 所以在支付页面情况下,不要使用请求转发,否则会造成重复支付[演示]

在这里插入图片描述

课堂练习

1.编写一个 RegisterServlet , 能够接收到提交的各种数据, 并把接收到的数据返回给浏览器, 并显示(回显). 注意处理中文乱码问题, 暂不处理文件提交

在这里插入图片描述
在这里插入图片描述
1)新建web/register.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册用户</title>
</head>
<body>
<h2>用户注册</h2>
<form action="http://localhost:8888/servlet/registerServlet" method="post">
    用户名: <input type="text" name="username"/><br/>
    密码: <input type="password" name="password"/><br/><br/>
    选择你喜欢的老师:<br/>
    <input type="checkbox" name="teacher" value="秋香老师"/>秋香老师
    <input type="checkbox" name="teacher" value="雅蝶老师"/>雅蝶老师
    <input type="checkbox" name="teacher" value="美女老师"/>美女老师<br/><br/>
    你的年龄<br/>
    <input type="radio" name="age" value="23岁"/>23岁
    <input type="radio" name="age" value="24岁">24岁
    <input type="radio" name="age" value="25岁">25岁<br/><br/>
    你的生日<br/>
    <input type="date" name="birthday"/><br/><br/>
    你的邮箱<br/>
    <input type="email" name="email"/><br/><br/>
    你的所在城市<br/>
    <select name="city">
        <option value="">请选择城市</option>
        <option value="北京">北京</option>
        <option value="上海">上海</option>
        <option value="南京">南京</option>
    </select><br/><br/>
    你的自我介绍<br/>
    <textarea name="introduction"></textarea><br/><br/>
    你要上传的文件<br/>
    <input type="file" name="file"/><br/><br/>
    <input type="submit" value="注册用户"/>
    <input type="reset" value="重置"/>
</form>
</body>
</html>

2)新建src/com/zzw/servlet/request/RegisterServlet.java

public class RegisterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("RegisterServlet doPost()被调用...");

        request.setCharacterEncoding("utf-8");

        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String[] teachers = request.getParameterValues("teacher");
        //会取数组的第一个值
        String teacher = request.getParameter("teacher");
        String age = request.getParameter("age");
        String birthday = request.getParameter("birthday");
        String email = request.getParameter("email");
        String city = request.getParameter("city");
        String introduction = request.getParameter("introduction");


        response.setHeader("Content-Type", "text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("<p>用户名: " + username + "</p>");
        writer.print("<p>密码: " + password + "</p>");
        writer.print("<p>喜欢的老师: " + Arrays.asList(teachers) + "</p>");
        writer.print("<p>年龄: " + age + "</p>");
        writer.print("<p>生日: " + birthday + "</p>");
        writer.print("<p>邮箱: " + email + "</p>");
        writer.print("<p>所在城市: " + city + "</p>");
        writer.print("<p>自我介绍: " + introduction + "</p>");
        writer.flush();
        writer.close();
    }
}

3)配置web.xml

<servlet>
    <servlet-name>RegisterServlet</servlet-name>
    <servlet-class>com.zzw.servlet.request.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>RegisterServlet</servlet-name>
    <url-pattern>/registerServlet</url-pattern>
</servlet-mapping>

2.编写一个Servlet, 可以获取到浏览器所在电脑的操作系统版本(Windows NT 10.0)和位数(32 还是 64 ) Win64, 显示在页面.

public class ComputerServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //谷歌浏览器:
        // User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
        //Edge浏览器:
        // User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0
        
        String content = request.getHeader("User-Agent");
        String regStr = "\\((?<computerInfo>[\\w\\ \\.\\;]+)\\)";

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        
        matcher.find();
        
        String computerInfo = matcher.group("computerInfo");
        String[] split = computerInfo.split("\\; ");
        
        System.out.println("操作系统: " + split[0]);
        System.out.println("系统操作位数: " + split[1]);
    }
}
<servlet>
    <servlet-name>ComputerServlet</servlet-name>
    <servlet-class>com.zzw.servlet.ComputerServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ComputerServlet</servlet-name>
    <url-pattern>/computerServlet</url-pattern>
</servlet-mapping>

HttpServletResponse

基本介绍

1.每次 HTTP 请求, Tomcat 会创建一个 HttpServletResponse 对象传递给 Servlet 使用.

2.HttpServletRequest 表示请求过来的信息, HttpServletResponse 表示所有相应的信息. 如果需要设置返回给客户端的信息, 通过 HttpServletResponse 对象进行设置即可.

在这里插入图片描述

HttpServletResponse 类图

在这里插入图片描述

向客户端返回数据方法

在这里插入图片描述

1.字节流: getOutputStream(), 常用于下载 (处理二进制数据)

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

3.细节: 两个流同时只能使用一个. 使用了字节流, 就不能再使用字符流, 反之亦然, 否则就会报错.

应用实例

1.需求: 浏览器请求, 返回 hello, world

2.代码实现

  • 乱码问题
  1. 处理乱码问题方案1
    在这里插入图片描述
  2. 处理乱码问题方案2
    在这里插入图片描述

请求重定向

  1. 请求重定向是指: 一个web资源收到客户端请求后, 通知客户端去访问另外一个web资源, 这称之为重定向
  2. 请求重定向分析图
    在这里插入图片描述
    测试代码
public class DownServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("DownServlet 自己的业务");
        //1.sendRedirect 本质会返回一个 302状态码 和 Location: /servlet/downServletNew
        //2.因此 302状态码 和 /servlet/downServletNew是浏览器解析的
        //3.浏览器会将 /servlet/downServletNew 解析成http://localhost:8080/servlet/downServletNew
        response.sendRedirect("/servlet/downServletNew");
    }
}

public class DownServletNew extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("DownServletNew doPost");
        response.setContentType("application/x-tar; charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println("<h1>下载完成</h1>");
        writer.flush();
        writer.close();
    }
}
<body>
<h2>下载文件</h2>
<a href="http://localhost:8888/servlet/downServlet">下载&lt;&lt;三体&gt;&gt;小说</a>
</body>

测试结果
在这里插入图片描述
在这里插入图片描述

请求重定向注意事项

  1. 最佳应用场景: 网站迁移, 比如原域名是 www.zzw.com 迁移到 www.world.cn, 但是百度抓取的还是原来的网址
  2. 浏览器地址会发生变化, 本质是两次Http请求
  3. 不能共享Request域中的数据, 本质是两次Http请求, 会生成两个HttpServletRequest对象
  4. 不能重定向到WEB-INF下的资源
  5. 可以重定向到Web工程以外的资源, 比如到http://www.baidu.com
  6. 重定向有两种方式, 推荐使用第1种
//第一种重定向使用
response.sendRedirect("/servlet/downServletNew");
//第二种重定向使用
response.setStatus(302);//设置http响应的状态码
//设置http响应的Location: /servlet/downServletNew
response.setHeader("Location", "/servlet/downServletNew");

动态获取到application context

在这里插入图片描述

//动态获取 application context
String contextPath = getServletContext().getContextPath();
System.out.println(contextPath);// /servlet
response.sendRedirect(contextPath + "/downServletNew");

在这里插入图片描述

练习题

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>支付页面</title>
</head>
<body>
<h1>支付页面</h1>
<!--这里action的第1个/ 会被浏览器解析成浏览器地址栏的主机名-->
<form action="/servlet/myPayServlet">
    用户编号:<input type="text" name="userId"/>
    支付金额:<input type="text" name="money"/>
    <input type="submit" value="点击支付">
</form>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>支付成功</title>
</head>
<body>
<h1>恭喜你支付成功</h1>
</body>
</html>
public class MyPayServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        String userId = request.getParameter("userId");
        String money = request.getParameter("money");
        String contextPath = getServletContext().getContextPath();
        if (WebUtils.parseString(money) > 100) {
            response.sendRedirect(contextPath + "/pay_ok.html");
        } else {
            response.sendRedirect(contextPath + "/pay.html");
        }
    }
}
public class WebUtils {
    public static int parseString(String str) {
        int num = 0;
        try {
            //shortcuts: ctrl+alt+t
            num = Integer.parseInt(str);
        } catch (NumberFormatException e) {
            System.out.println("输入的str格式不正确");
        }
        return num;
    }
}
<servlet>
        <servlet-name>MyPayServlet</servlet-name>
        <servlet-class>com.zzw.servlet.response.MyPayServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyPayServlet</servlet-name>
        <url-pattern>/myPayServlet</url-pattern>
    </servlet-mapping>
  • 16
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~ 小团子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值