Java Web篇_05 Request&Response

Request

请求对象

请求,顾名思议,就是使用者希望从服务器端索取一些资源,向服务器发出询问。在B/S架构中,就是客户浏览器向服务器发出询问。在我们的JavaEE工程中,客户浏览器发出询问,要遵循HTTP协议所规定的。

请求对象,就是在JavaEE工程中,用于发送请求的对象。我们常用的对象就是ServletRequest和HttpServletRequest,它们的区别就是是否和HTTP协议有关。

获取各种路径的方法

在这里插入图片描述
实操演示,先创建一个项目,我这里起名request_demo,
创建一个继承HttpServlet 的类

package com.symc.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;

/**
 * @Author: 凤文  沈阳医学院2019级医学信息工程 0213
 * @CreateTime: 2021/10/12 19:24
 * @Description:
 */
@WebServlet("/requestDemo1")
public class RequestDemo1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取虚拟目录的名称
        String contextPath = req.getContextPath();
        System.out.println(contextPath);
        //获取servlet映射路径
        String servletPath = req.getServletPath();
        System.out.println(servletPath);
        //获取访问者IP
        String remoteAddr = req.getRemoteAddr();
        System.out.println(remoteAddr);
        //获取请求消息的数据
        String queryString = req.getQueryString();
        System.out.println(queryString);
        //获取统一资源标识符
        String requestURI = req.getRequestURI();
        System.out.println(requestURI);
        //获取统一资源定位符
        StringBuffer requestURL = req.getRequestURL();
        System.out.println(requestURL);
    }

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

配置
在这里插入图片描述
启动tomcat,浏览器访问,控制台显示如下
在这里插入图片描述
由输出可知,虚拟目录和映射路径是什么东西;
获取的访问者iP,这里是本机地址,采用的是IPv6;
而请求消息的数据,这里并没有,所以是空的;
对于URI和URL需要知道的是URI包含URL。

现在我们在地址栏加入请求内容
在这里插入图片描述
在观察控制台
在这里插入图片描述
这就是获取到的请求消息的数据。

获取请求头信息

在这里插入图片描述
还是使用刚才的例子,我们在网页按F12打开开发者工具
在这里插入图片描述
现在我们要在控制台获取请求头的这些信息。

package com.symc.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;
import java.util.Enumeration;

/**
 * @Author: 凤文  沈阳医学院2019级医学信息工程 0213
 * @CreateTime: 2021/10/12 19:24
 * @Description: 获取请求头信息
 */
@WebServlet("/requestDemo2")
public class RequestDemo2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //根据请求头名称获取一个值,比如这里获取的是Connection的信息,不区分大小写
        String value = req.getHeader("connection");
        System.out.println(value);
        System.out.println("-----------------------------------");//分割线
        //根据请求头名称获取多个值
        Enumeration<String> values = req.getHeaders("Accept-Encoding");
        while (values.hasMoreElements()) {
            String val = values.nextElement();
            System.out.print(val + " ");
        }
        System.out.println("-----------------------------------");//分割线
        //获取所有请求头名称
        Enumeration<String> names = req.getHeaderNames();
        while (names.hasMoreElements()) {
            String name = names.nextElement();
            String s = req.getHeader(name);
            System.out.println(s);
        }
    }

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

观察控制台
在这里插入图片描述

获取请求参数信息

在这里插入图片描述

首先写一个html,用于用户访问

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>注册页面</title>
</head>
<body>
    <div>
        <form action="/request/requestDemo3" method="get" autocomplete="off">
            用户名:<input type="text" name="username"><br>
            密码:<input type="password" name="password"><br>
            爱好:<input type="checkbox" name="hobby" value="study">学习
            <input type="checkbox" name="hobby" value="game">游戏
            <input type="checkbox" name="hobby" value="sport">运动<br>
            <button type="submit">注册</button><br>
        </form>
    </div>
</body>
</html>

创建一个类来测试上面的这些方法

package com.symc.servlet;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sound.midi.Soundbank;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;

/**
 * @Author: 凤文  沈阳医学院2019级医学信息工程 0213
 * @CreateTime: 2021/10/13 10:26
 * @Description:
 */
@WebServlet("/requestDemo3")
public class RequestDemo3 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);
        System.out.println(password);
        System.out.println("---------------------------------------");
        //根据名称获取所有数据
        String[] hobbies = req.getParameterValues("hobby");
        for (String hobby : hobbies) {
            System.out.println(hobby);
        }
        System.out.println("---------------------------------------");
        //获取所有名称
        Enumeration<String> names = req.getParameterNames();
        while (names.hasMoreElements()) {
            String name = names.nextElement();
            System.out.println(name);
        }
        System.out.println("---------------------------------------");
        //获取所有参数的键值对
        Map<String, String[]> map = req.getParameterMap();
        for (String key : map.keySet()) {
            String[] values = map.get(key);
            System.out.print(key + ":");
            for (String value : values) {
                System.out.println(value);
            }
        }

    }

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

开启服务器,访问并填写内容提交,观察控制台。
在这里插入图片描述
在这里插入图片描述

获取参数手动封装对象

首先说一下为什么要封装对象,刚才的案例属性比较少,通过打印到控制台还是比较容易的,但是当数据非常多的时候,输出起来就非常复杂。那么我们将每一次用户访问的数据封装到一个对象中,我们只需要通过获取对象的信息就能获取到这些数据。

首先创建一个实体类,并且其中的成员变量一定要与我们要获得的信息一致。

package com.symc.bean;

import java.util.Arrays;

/**
 * @Author: 凤文  沈阳医学院2019级医学信息工程 0213
 * @CreateTime: 2021/10/13 17:46
 * @Description:
 */
public class User {
    private String username;
    private String password;
    private String[] hobbies;

    public User() {
    }

    public User(String username, String password, String[] hobbies) {
        this.username = username;
        this.password = password;
        this.hobbies = hobbies;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", hobbies=" + Arrays.toString(hobbies) +
                '}';
    }
}

这样我们在写servlet时只需要将获取的参数放到对象中即可。

package com.symc.servlet;

import com.symc.bean.User;

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;

/**
 * @Author: 凤文  沈阳医学院2019级医学信息工程 0213
 * @CreateTime: 2021/10/13 17:42
 * @Description:
 */
@WebServlet("/requestDemo4")
public class RequestDemo4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String[] hobbies = req.getParameterValues("hobby");

        User user1 = new User(username, password, hobbies);

        System.out.println(user1);
    }

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

别忘记html的提交位置也要改变

 <form action="/request/requestDemo4" method="get" autocomplete="off">

访问,观察控制台
在这里插入图片描述

获取参数反射封装对象

刚才将输出部分封装起来,可是当数据项足够多的时候,我们还是得写入大量的req.getParameter()方法,有没有一劳永逸的方法呢?

package com.symc.servlet;

import com.symc.bean.User;

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.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * @Author: 凤文  沈阳医学院2019级医学信息工程 0213
 * @CreateTime: 2021/10/13 19:38
 * @Description: 获取参数反射封装对象
 */
@WebServlet("/requestDemo5")
public class RequestDemo5 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取所有数据
        Map<String, String[]> parameterMap = req.getParameterMap();
        //封装对象
        User user = new User();
        //遍历集合
        for (String name : parameterMap.keySet()) {
            String[] value = parameterMap.get(name);
            try {
                //获取封装对象的属性描述器
                PropertyDescriptor pd = new PropertyDescriptor(name, user.getClass());
                //获取对应的setXxx方法
                Method writeMethod = pd.getWriteMethod();
                //执行方法
                if (value.length>1) {
                    writeMethod.invoke(user, (Object) value);
                }else {
                    writeMethod.invoke(user,value);
                }
            } catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        System.out.println(user);

    }

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

我做这个的时候遇到个异常:
java.beans.IntrospectionException: Method not found: isHobby

获取参数工具类封装对象

上面我们写起来还是很复杂,我们可以导入已经写好的jar包。
所以这里关键是如何导入jar包。

首先,将我们的本地的jar包复制下来,这两个jar包都是由apache提供的。
在这里插入图片描述
在web目录下创建一个lib目录,专门用来放置jar包,粘贴进去。
在这里插入图片描述
粘贴进来后还需要将他们添加到引用类库中
全选右键找到add as library,确定即可。
在这里插入图片描述在这里插入图片描述
这个时候我们就可以使用了。

这里我已经把需要的jar包上传到网盘了。
百度网盘资源链接
链接:https://pan.baidu.com/s/1Qev4FerXAFGAPhfXepZSJA
提取码:xxxx

导入jar包后我们就要写代码了

package com.symc.servlet;

import com.symc.bean.User;
import org.apache.commons.beanutils.BeanUtils;

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;
import java.util.Map;

/**
 * @Author: 凤文  沈阳医学院2019级医学信息工程 0213
 * @CreateTime: 2021/10/14 15:31
 * @Description: 使用工具类封装对象
 */
@WebServlet("/requestDemo6")
public class RequestDemo6 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Map<String, String[]> parameterMap = req.getParameterMap();
        User user = new User();
        try {
            BeanUtils.populate(user,parameterMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(user);
    }

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

可见,我们只需要将map集合获取,调用BeanUtils的populate类传入对象和map集合就可以了。
调整好html的提交位置,现在我们来启动服务器运行一下
结果。。。
在这里插入图片描述
网页提示找不到这个类,造成这个问题的原因是这个jar包虽然导入到类库中,但并没有导入到项目的war包中,解决方法如下:

在file——projectStructure中,最下面选项的problem,出现有一个问题,点击fix,选图中的第一个,然后问题就解决了。
在这里插入图片描述

通过流对象获取请求信息

在这里插入图片描述

@WebServlet("/requestDemo7")
public class RequestDemo7 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //字符流(必须是post请求方式)
        BufferedReader br = req.getReader();
        String line;
        while ((line = br.readLine()) != null){
            System.out.println(line);
        }
        br.close();
    }

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

需要注意,通过字符流的这种方式只有post是有效的。

  <form action="/request/requestDemo7" method="post" autocomplete="off">

由于编码的限制,我这里用一个英文名字,并且会发现post方式地址栏不显示请求信息。
在这里插入图片描述
控制台是这样的
在这里插入图片描述
这个是字节流

        //字节流
        ServletInputStream is = req.getInputStream();
        byte[] bytes = new byte[1024];
        int len;
        while ((len = is.read(bytes)) !=-1){
            System.out.println(new String(bytes,0,len));
        }

中文乱码问题

Get方式没有乱码问题,已经在Tomcat8版本后解决了。
Post方式有乱码问题,可以通过setCharacterEncoding()方法来解决。

之前的例子都是用get方式来做的,或者用对象的方式,我这个9.0的tomcat没有发现乱码问题!
我们来看一下Post方式的乱码:

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        System.out.println(username);
    }

输出这样的:
在这里插入图片描述
我们只需要在方法里面添加上setCharacterEncoding方法就可以解决。

        req.setCharacterEncoding("UTF-8");
        String username = req.getParameter("username");
        System.out.println(username);

这里的编码要与Html中的编码一致才可以,当然我们大多数情况下开发用的都是UTF-8。

<html lang="en">
<head>
    <meta charset="UTF-8">

这样问题就解决了。

请求域、请求转发、请求包含

请求域也叫request域,可以在一次请求范围内进行共享数据。它一般用于请求转发的多个资源中共享数据。

请求对象操作共享数据方法。
在这里插入图片描述

请求转发:客户端的一次请求到达后,发现需要借助其他Servlet来实现功能。
当客户端访问到ServletA时,想要通过ServletA完成功能,但是发送给它时发现ServletA并不能满足想要的功能,同时有一个ServletB却可以实现这个功能,那么ServletA将请求发送给ServletB,有ServletB完成目标,这个过程就叫请求转发。
在这里插入图片描述
请求转发的特点:
浏览器地址栏不变,域对象中的数据不丢失,负责转发的Servlet转发前后的响应正文会丢失,由转发的目的地来响应客户端。
请求转发的API:
在这里插入图片描述
这里的形参列表是请求转发到的路径,获取到的就是请求调度对象RequestDispatcher,获取到这个对象后,通过forward方法来实现转发,
在这里插入图片描述
forword方法调用时还需要将请求和响应对象传递。

package com.symc.servlet;

import javax.servlet.RequestDispatcher;
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;

/**
 * @Author: 凤文  沈阳医学院2019级医学信息工程 0213
 * @CreateTime: 2021/10/16 17:31
 * @Description: 请求转发实现
 */
@WebServlet("/requestDemo9")
public class RequestDemo9 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置共享数据
        req.setAttribute("data","随意的测试数据");
        //获取请求调度对象
        RequestDispatcher rd = req.getRequestDispatcher("/requestDemo10");
        rd.forward(req,resp);
        //实现转发
    }
}

package com.symc.servlet;

import javax.servlet.RequestDispatcher;
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;

/**
 * @Author: 凤文  沈阳医学院2019级医学信息工程 0213
 * @CreateTime: 2021/10/16 17:31
 * @Description: 请求转发实现
 */
@WebServlet("/requestDemo9")
public class RequestDemo9 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置共享数据
        req.setAttribute("data","随意的测试数据");
        //获取请求调度对象
        RequestDispatcher rd = req.getRequestDispatcher("/requestDemo10");
        rd.forward(req,resp);
        //实现转发
    }
}

这两个类完成后我们直接访问requestDemo9,发现控制台的信息便是成功转发给了requestDemo10
在这里插入图片描述

请求包含:可以合并其他Servlet的功能一起响应给客户端。

请求包含和请求转发类似。客户端发送请求给ServletA,ServletA能够完成一部分,而剩下的部分A不能完成,这时发现ServletB能够完成剩下的部分,于是A就把B包含。
在这里插入图片描述
请求包含的特点:
浏览器地址栏不变,域对象的数据不丢失,被包含的Servlet响应头会丢失。
实现方法与请求转发类似:
在这里插入图片描述
在这里插入图片描述
代码实现方式与请求转发基本一致

requestDemo11

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("requestDemo11执行了。。");
        //获取请求调度对象
        RequestDispatcher rd = req.getRequestDispatcher("/requestDemo12");
        //实现请求包含
        rd.include(req,resp);
    }

requestDemo12

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("requestDemo12执行了。。。");
    }

在这里插入图片描述

Response

响应对象

响应:回馈结果。在BS架构中,就是服务器给客户端浏览器反馈结果。
对于这个回馈结果,要么是成功,要么是失败。
响应对象:就是项目中用于发送响应的对象。
响应对象有ServletResponse、HttpServletResponse

常见状态码

状态码说明
200成功
302重定向
304请求资源未改变
400请求错误
404请求资源未找到
405请求方式不支持
500服务器错误
刚才提到响应的结果,要么成功,要么失败,这个结果浏览器会返回一些状态码,表明是否响应成功,又表明问题可以出现的原因。
对于200,说明响应成功了;
对于3开头的3xx,说明访问成功,但是还需要进行进一步的细化操作,比如302,重定向,需要继续访问,再如304,请求资源未改变,使用的是缓存的资源,这个时候客户端应重新刷新;
对于4xx开头的,属于客户端访问出错,尤其经常出现的404,找不到文件,很可能是因为地址栏输入错误,而对于开发者,也可能是因为后端的某些脚本存放的路径错误;
然后500这样的,都属于服务器错误,比如,服务器宕机。对于开发者,那还可以从后端代码错误上找原因,浏览器页面会抛出异常。

字节流响应消息和解决乱码问题

在这里插入图片描述
我这里又创建了一个块。

package com.symc.servlet;

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

/**
 * @Author: 凤文  沈阳医学院2019级医学信息工程 0213
 * @CreateTime: 2021/10/17 16:06
 * @Description: 字节流响应消息
 */
@WebServlet("/responseDemo1")
public class ResponseDemo1 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");//设置编码
        //创建输出流对象
        ServletOutputStream os = resp.getOutputStream();
        //创建消息
        String message = "你好!";
        //响应给浏览器
        //getBytes默认的编码是GBK,浏览器的编码也是GBK
        //但是项目的编码需要统一为utf-8,于是需要解决乱码问题
        os.write(message.getBytes("utf-8"));

    }

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

字符流响应消息和解决乱码问题

在这里插入图片描述
写法与上面字节流差不多

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter pw = resp.getWriter();
        String message = "你好!";
        pw.write(message);
    }

响应图片

之前都是返回给页面文字,那现在我想返回一张图片。
首先需要有一张图片,把图片粘贴到web目录下,我这里还新建了一个img目录;
在这里插入图片描述
同样是使用流的方式,不过这次使用的是效率更高的buffered,然后代码如下:

package com.symc.servlet;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * @Author: 凤文  沈阳医学院2019级医学信息工程 0213
 * @CreateTime: 2021/10/18 13:10
 * @Description: 响应图片
 */
@WebServlet("/responseDemo3")
public class ResponseDemo3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //通过文件的相对路径获取绝对路径
        String realPath = getServletContext().getRealPath("/img/resp.png");
        System.out.println(realPath);
        //创建字节输入流对象,关联图片路径
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(realPath));
        //通过响应对象获取字节输出流对象
        ServletOutputStream os = resp.getOutputStream();
        //循环读写
        int len;
        byte[] bytes = new byte[1024];
        while ((len = bis.read(bytes)) != -1) {
            os.write(bytes,0,len);
        }
        //os由服务器自动关闭
        bis.close();
    }
}

这个代码就是将图片文件转成流。
看一下访问的效果
在这里插入图片描述
这里有个问题值得说一下:
这里为什么要获取绝对路径,难道直接用相对路径不可以吗?
其实正常读取文件使用相对路径是可以的,但是我们现在是要发布到网页上,发布的路径是经过war包的路径的,所以必须使用绝对路径才可以,通过servlet的获取绝对路径的方法就可以实现。下面是控制台打印的绝对路径
在这里插入图片描述
这里有个response_demo_war_exploded的war包路径,使用相对路径是找不到文件的。
当然,我把使用相对路径的访问情况也发一下
在这里插入图片描述

设置缓存

缓存:对于不经常变化的数据,我们可以设置合理的缓存时间,以避免浏览器频繁请求服务器,依此来提高效率。
在这里插入图片描述
通过设置缓存,我们期望,当用户访问我们的资源时,只有第一次才会访问我们的服务器端,比如设置1小时的缓存时间,在客户访问服务器后的这一小时内,如果客户再次来请求的话,是不会来请求我们的服务器端,而是直接从缓存中查询数据。
而这个方法setDateHeader有两个参数,在代码中会解释。

package com.symc.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;

/**
 * @Author: 凤文  沈阳医学院2019级医学信息工程 0213
 * @CreateTime: 2021/10/18 15:31
 * @Description: 设置缓存
 */
@WebServlet("/responseDemo4")
public class RequestDemo4 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置数据
        String message = "这条消息设置了缓存,1小时内都可以查看";
        //设置缓存
        //这个方法中有两个参数,第一个要填写消息头,这里其实就是Expires,过期的意思,也就是说,
        //给这些缓存设置失效的时间,而第二个参数就是具体的时间,单位是毫秒数,
        // 这里使用的是获取当前时间再加上1小时,即设置1小时的缓存,也即在1小时后这个缓存会失效
        resp.setDateHeader("Expires",
                System.currentTimeMillis() + 1 * 60 * 60 * 1000);
        //设置编码格式
        resp.setContentType("text/html;charset=utf-8");
        //写出数据
        resp.getWriter().write(message);

        //用来测试的
        System.out.println("用户访问了服务器。。");
    }
}

定时刷新

相信同学们在使用浏览器访问时,也常常遇到说“3秒后自动跳转到另一个页面”,当然这个页面是我们可以指定。
定时刷新就是,过了指定的时间,页面自动进行跳转。
在这里插入图片描述

package com.symc.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;

/**
 * @Author: 凤文  沈阳医学院2019级医学信息工程 0213
 * @CreateTime: 2021/10/18 16:14
 * @Description: 定时刷新
 */
@WebServlet("/responseDemo5")
public class ResponseDemo5 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String message = "登录成功!3秒后自动返回登录页面";
        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().write(message);
        //设置定时刷新
        //定时刷新有两个参数,第一个消息头写“Refresh”,是刷新的意思,第二个参数中的3是代表
        //3秒后刷新,URL是跳转的目标
        resp.setHeader("Refresh","3;URL=/response/html/login.html");
    }
}

这里面的login.html就写个简单的登录界面能用来测试就行。

    <div>
        <form action="/response/responseDemo5" method="get" autocomplete="off">
            用户名:<input type="text" name="username"><br>
            密码:<input type="password" name="password"><br>
            <button type="submit">登录</button><br>
        </form>
    </div>

请求重定向

请求重定向:客户端的一次请求到达后,发现需要借助其他Servlet来实现功能。
特点:浏览器地址栏会发生改变,两次请求、请求域对象中不能共享数据,可以重定向到其他的服务器。
重定向的实现原理:
1. 设置状态码为302:resp.setStatus(302);
2. 设置资源的响应路径(响应到哪里去,通过响应消息头location来指定)
resp.setHeader(“location”,“/response/responseDemo7”)
以上两个方法就是实现原理,不过已经有了封装好的方法直接使用。
响应对象重定向方法:
在这里插入图片描述
下面我们来创建两个类来感受一下重定向的特点:

@WebServlet("/responseDemo6")
public class ResponseDemo6 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("responseDemo6执行了");
        //设置共享数据
        req.setAttribute("username","张三");
        //设置重定向
        resp.sendRedirect(req.getContextPath()+"/responseDemo7");
    }
}
@WebServlet("/responseDemo7")
public class ResponseDemo7 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("responseDemo7执行了");
        //获取共享数据
        Object username = req.getAttribute("username");
        System.out.println(username);
    }
}

当我们访问Demo6的时候,它立即跳转到Demo7
在这里插入图片描述
而控制台的情况如下
在这里插入图片描述
这说明这两个servlet都访问到了,但是Demo6中设置的共享数据Demo7中并不能访问到,证明不能共享数据。

我们打开开发者工具,找到网络的选项
在这里插入图片描述
发现Demo6的响应状态是302,重定向的位置就是Demo7
在这里插入图片描述
Demo7的状态是200,说明响应成功,所以是两次请求。

下载文件

1.创建字节输入流,关联读取的文件。
2.设置响应消息头支持的类型。
3.设置响应消息头以下载方式打开资源。
4.通过响应对象获取字节输出流对象。
5.循环读写。
6.释放资源。

package com.symc.servlet;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * @Author: 凤文  沈阳医学院2019级医学信息工程 0213
 * @CreateTime: 2021/10/18 20:30
 * @Description: 下载文件
 */
@WebServlet("/responseDemo8")
public class ResponseDemo8 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        1.创建字节输入流,关联读取的文件。
        String realPath = getServletContext().getRealPath("/img/resp.png");
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(realPath));
//        2.设置响应消息头支持的类型。
        //Content-Type 消息头名称 支持的类型
        //application/octet-stream 消息头参数 应用的类型为字节流
        resp.setHeader("Content-Type", "application/octet-stream");
//        3.设置响应消息头以下载方式打开资源。
        //Content-Disposition 消息头名称 处理的形式
        //attachment;filename=resp.png 消息头参数 附件形式进行处理 指定下载文件的名称
        resp.setHeader("Context-Disposition", "attachment;filename=resp.png");
//        4.通过响应对象获取字节输出流对象。
        ServletOutputStream os = resp.getOutputStream();
//        5.循环读写。
        byte[] b = new byte[1024];
        int len;
        while ((len = bis.read(b)) != -1) {
            os.write(b);
        }
//        6.释放资源。
        bis.close();
    }
}

我们访问后,可以发现就有下载文件的提示。
在这里插入图片描述

案例

先来看一下要做个什么样的页面:
首页是一个学生管理功能的页面,有添加和查看的功能
在这里插入图片描述
添加功能如下
在这里插入图片描述
项目目录是这样的:
这里的index.html是首页
addStudent.html是添加学生的功能页面
info.txt是用来存放学生信息的本地文件,当然可以使用mysql实现,我这里用个记事本代替一下。
在这里插入图片描述
接下来开始实现:
创建项目并配置,我这里虚拟目录为stu
首先,先创建一个主页

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>学生管理系统首页</title>
</head>
<body>
    <a href="/stu/addStudent.html">添加学生</a>
    <a href="/stu/listStudentServlet">查看学生</a>
</body>
</html>

然后打开web.xml文件,将它设置为默认主页

<?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">
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

再写一个添加功能的页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>保存学生信息</title>
</head>
<body>
    <div>
        <form action="/stu/addStudentServlet" method="get" autocomplete="off">
            学生姓名:<input type="text" name="name"><br>
            学生班级:<input type="number" name="aClass"><br>
            学生成绩:<input type="number" name="score"><br>
            <button type="submit">保存</button>
        </form>
    </div>
</body>
</html>

接下来写后端功能,在bean目录下创建Student学生实体,并添加构造方法和get、set方法:

package com.symc.test.bean;

/**
 * @Author: 凤文  沈阳医学院2019级医学信息工程 0213
 * @CreateTime: 2021/10/21 20:47
 * @Description:
 */
public class Student {
    private String name;
    private int aClass;
    private double score;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAClass() {
        return aClass;
    }

    public void setAClass(int aClass) {
        this.aClass = aClass;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    public Student() {
    }

    public Student(String name, int aClass, double score) {
        this.name = name;
        this.aClass = aClass;
        this.score = score;
    }
}

添加功能的实现:

package com.symc.test.servlet;

import com.symc.test.bean.Student;
import javafx.scene.text.FontPosture;
import sun.font.TrueTypeFont;

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.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

/**
 * @Author: 凤文  沈阳医学院2019级医学信息工程 0213
 * @CreateTime: 2021/10/21 20:53
 * @Description: 1.创建类AddStudentServlet,继承HttpServlet
 * 2.重写doGet和doPost方法
 * 3.获取表单中的数据。
 * 4.将获取到的数据封装成Student对象
 * 5.将Student的中数据保存到文件中
 * 6.通过定时刷新功能完成对浏览器的响应。
 */
@WebServlet("/addStudentServlet")
public class AddStudentServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        String aClass = req.getParameter("aClass");
        String score = req.getParameter("score");

        Student stu = new Student(name, Integer.parseInt(aClass),
                Double.parseDouble(score));

        BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\Documents" +
                "\\Documents\\ProgramProjects\\javaee\\reqresp_test\\file" +
                "\\info.txt",true));
        bw.write(stu.getName() + "," + stu.getAClass() + "," + stu.getScore());
        bw.newLine();
        bw.close();

        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().write("添加成功!3秒后自动跳转到首页。。。");
        resp.setHeader("Refresh", "3,URL=index.html");
    }
}


查看功能的实现:

package com.symc.test.servlet;

import com.symc.test.bean.Student;
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.awt.dnd.DragGestureEvent;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;

/**
 * @Author: 凤文  沈阳医学院2019级医学信息工程 0213
 * @CreateTime: 2021/10/22 8:32
 * @Description:
 * 1.创建一个ListStudentServlet类,继承HttpServlet
 * 2.重写doGet和doPost方法
 * 3.通过字符输入流读取文件中的数据。
 * 4.将读取到的数据封装到Student对象中。
 * 5.将多个Student对象保存到集合中。
 * 6.遍历集合,响应到浏览器中
 */
@WebServlet("/listStudentServlet")
public class ListStudentServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        BufferedReader br = new BufferedReader(new FileReader("D:\\Documents\\Documents" +
                "\\ProgramProjects\\javaee\\reqresp_test\\file\\info.txt"));
        String line;
        ArrayList<Student> students = new ArrayList<>();
        while ((line = br.readLine()) != null){
            String[] arr = line.split(",");
            Student stu = new Student();
            stu.setName(arr[0]);
            stu.setAClass(Integer.parseInt(arr[1]));
            stu.setScore(Double.parseDouble(arr[2]));
            students.add(stu);
        }
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter pw = resp.getWriter();
        for (Student stu : students) {
            pw.write(stu.getName()+","+stu.getAClass()+","+stu.getScore());
            pw.write("<br>");
        }
    }
}

最后到浏览器测试。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值