java web Request和Response快速入门笔记

一、Request

request 与 response原理
我们知道tomcat会在第一次请求url来创建对应路径映射的servlet对象(如果设置servlet启动时自动创建,则请求url不会重复创建servlet对象)
同时,每一次请求,tomcat会先创建response和request对象,其中request对象中会封装请求消息数据
然后tomcat会将这两个对象传递给servlet实现类中的service方法,并调用
我们可以在service方法中,通过response对象来设置响应消息,最后用户通过浏览器可以获取到这些响应数据(这是省略前端的情况下,一般前端工程师会对响应拦截处理)
当然tomcat在响应数据前,会先获取response里面的数据,然后再响应给前端
HttpServletRequest

在这里插入图片描述在这里插入图片描述
如果你观察Tomcat的源码就会发现,tomcat有一个HttpServletRequest的实现类org.apache.catalina.connector包下的RequestFacade,同时此包下还有一个ResponseFacade是HttpServletResponse接口的实现类
在这里插入图片描述在这里插入图片描述

1、获取请求消息数据

1、获取请求行数据

请求行格式
举例:GET /day1/demo1?name=zhangsan HTTP/1.1
GET这个位置:请求方法,可以是POST,DELETE,PUT等等,可通过String getMethod()方法获取
/day1:虚拟目录,是在Tomcat设置的,可通过String getContextPath()方法获取
/demo1:servlet路径,可通过String getServletPath()方法获取
?name=zhangsan:请求参数,可通过String getQueryString()方法获取
/day1/demo1:这两个合起来是请求URI,可通过String getRequestURI()方法获取
StringBuffer getRequestURL():和上面差不多,只不过它获取的路径会带http://ip地址/day1/demo1
HTTP/1.1:协议及版本,可通过String getProtocol()方法获取
获取客户机ip地址,可通过String getRemoteAddr()方法获取

在这里插入图片描述

package com.yzpnb.servlet;

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

/**
 * Request快速入门
 */
@WebServlet("/dome1")
public class Dome1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取请求方法
        String method = req.getMethod();
        System.out.println("请求方法:"+method);
        //获取虚拟目录
        String contextPath = req.getContextPath();
        System.out.println("虚拟目录:"+contextPath);
        //获取servlet路径
        String servletPath = req.getServletPath();
        System.out.println("servlet路径:"+servletPath);
        //获取get请求参数
        String queryString = req.getQueryString();
        System.out.println("请求参数:"+queryString);
        //获取请求URL
        String requestURI = req.getRequestURI();
        StringBuffer requestURL = req.getRequestURL();
        System.out.println("请求路径:"+requestURI+"========"+requestURL);
        //获取协议及版本
        String protocol = req.getProtocol();
        System.out.println("协议及版本:"+protocol);
        //获取客户机ip
        String remoteAddr = req.getRemoteAddr();
        System.out.println("客户机ip:"+remoteAddr);
    }
}

2、获取请求头数据

方法
String getHeader(String name):通过请求头名称获取请求头(就是键值对的形式)
Enumeration< String > getHeaderNames():获取所有请求头名称,返回值比较特殊,可以当Enumeration类型为迭代器

在这里插入图片描述

package com.yzpnb.servlet;

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

/**
 * Request快速入门
 */
@WebServlet("/dome1")
public class Dome1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取所有请求头名称
        Enumeration<String> headerNames = req.getHeaderNames();
        System.out.println("所有请求头");
        //遍历请求头名称
        while(headerNames.hasMoreElements()){//如果没有下一个值则退出循环
            String s = headerNames.nextElement();//获取下一个元素

            String header = req.getHeader(s);//根据请求头获取请求头值
            System.out.println(s+"   "+header);
        }

        /*根据user-agent请求头获取用户所用浏览器版本*/
        String userAgent = req.getHeader("user-agent");
        if(userAgent.contains("Chrome")){//判断是否包含关键字Chrome
            //是谷歌浏览器
            System.out.println("很好,这是我们推荐的Chrome浏览器");
        }else{
            //不是谷歌浏览器
            System.out.println("推荐使用谷歌Chrome浏览器");
        }
        /*根据referer获取用户从哪里点超链接跳转到这里的*/
        String referer = req.getHeader("referer");
        System.out.println("用户从:"+referer+"来");//注意如果你直接浏览器输入地址进来,会输出null
        if(referer != null){//防盗链
            if(referer.contains("dome1")){
                System.out.println("正常进入链接");
            }else{
                System.out.println("非正常进入");
            }
        }else{
            System.out.println("直接输入网址进入");
        }
    }
}

3、请求体数据

post请求才有请求体
1、先获取输入流对象:BufferReader getReader():获取字符输入流ServletInputStream getInputStream():获取字节输入流

发送post请求,需要用到表单,或者用某些模拟浏览器,如果你不会,应该先去补习,而不是学这个
在这里插入图片描述

@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取字符流
        BufferedReader reader = req.getReader();
        //读取数据
        String line = null;
        while((line = reader.readLine()) != null){
            System.out.println(line);
        }
    }

2、获取数据通用方法

1、获取请求参数通用方法

String getParameter(String name):根据参数名称获取参数值,比如username=zhangsan&age=14,那么我们通过参数名username可以获取对应值zhangsan
String[] getParameterValues(String name):根据参数名称获取参数值数组,比如hobby=basketball&hobby=game,通过hobby可以获取数组[basketball,game]
Enumeration< String > getParameterNames():获取所有请求参数名称
Map< String,String[] > getParameterMap():获取所有参数的map集合

在这里插入图片描述

<%--
  Created by IntelliJ IDEA.
  User: dell
  Date: 2020/10/4
  Time: 16:42
  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>
    <form action="/dome1" method="post">
        <input type="text" name="username" placeholder="请输入用户名"/><br/>
        <input type="text" name="password" placeholder="请输入密码"/><br/>

        <input type="checkbox" name="hobby" value="game"/>游戏
        <input type="checkbox" name="hobby" value="basketball"/>篮球<br/>

        <input type="submit" value="提交"/>
    </form>
</body>
</html>

在这里插入图片描述

package com.yzpnb.servlet;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;

/**
 * Request快速入门
 */
@WebServlet("/dome1")
public class Dome1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //get获取请求参数

        //根据参数名称获取值
//        String username = req.getParameter("username");
        this.doPost(req, resp);//因为代码逻辑相同,我们可以调用doPost方法来简化代码


    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //post获取请求参数
        //根据参数名称获取值
        String username = req.getParameter("username");
        System.out.println("username="+username);
        System.out.println("==============================");

        //根据参数名获取参数数组
        String[] hobbies = req.getParameterValues("hobby");
        if(hobbies!=null){
            System.out.print("hobby=[");
            for(String hobby:hobbies){
                System.out.print(hobby+",");
            }
            System.out.println("]");
            System.out.println("==============================");
        }

        //获取所有参数名
        Enumeration<String> parameterNames = req.getParameterNames();
        while(parameterNames.hasMoreElements()){
            String s = parameterNames.nextElement();
            System.out.print(s+"=");
            String parameter = req.getParameter(s);//无法获取数组
            System.out.println(parameter);
        }
        System.out.println("==============================");

        //获取所有参数map集合(解决上面无法获取数组问题)
        Map<String, String[]> parameterMap = req.getParameterMap();//获取所有map
        Set<String> keySet = parameterMap.keySet();//获取key
        for(String key:keySet){//遍历key
            String[] values = parameterMap.get(key);//根据key获取value
            if(hobbies!=null){//如果有值
                System.out.print(key+"=");
                for(String value:values){//遍历值
                    System.out.print(value+" ");
                }
                System.out.println();
            }
        }
    }
}

在这里插入图片描述

解决中文乱码
//解决中文乱码,设置流的字符集编码
req.setCharacterEncoding("utf-8");

在这里插入图片描述
这时你可能要问,如果用tomcat8以下版本怎么解决中文乱码,放心,就像人们现在都用智能手机,你还会专门回去用小诺基亚么?还会有人专门回去诺基亚研制触屏,上网么?

2、请求转发

请求转发
一种服务器跳转方式,通常我们一个servlet是完不成一项功能的,一般都是几个servlet配合完成,那么如何在servlet1处理完后跳转到servlet2继续处理呢?就需要请求转发
1、RequestDispatcher requestDispatcher = req.getRequestDispatcher(String path);:通过request对象获取请求转发器对象RequestDispatcher
2、requestDispatcher.forward(ServletRequest servletRequest,ServletResponse servletResponse);:使用请求转发器对象RequestDispatcher的forward方法转发

在这里插入图片描述

package com.yzpnb.servlet;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;

/**
 * Request快速入门
 */
@WebServlet("/dome1")
public class Dome1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("我是dome1Get");
//        RequestDispatcher requestDispatcher = req.getRequestDispatcher("/dome2");
//        requestDispatcher.forward(req,resp);
        req.getRequestDispatcher("/dome2").forward(req,resp);//上面那么写太麻烦,一行搞定转发
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //解决中文乱码,设置流的字符集编码
        req.setCharacterEncoding("utf-8");
        System.out.println("我是dome1Post");
//        RequestDispatcher requestDispatcher = req.getRequestDispatcher("/dome2");
//        requestDispatcher.forward(req,resp);
        req.getRequestDispatcher("/dome2").forward(req,resp);//上面那么写太麻烦,一行搞定转发
    }
}

在这里插入图片描述

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

@WebServlet("/dome2")
public class Dome2 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("我是dome2Post");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("我是dome2Get");
    }
}

在这里插入图片描述
在这里插入图片描述

需要注意的点(面试可能问)
1、浏览器地址栏并不会发生改变
2、只能请求转发到服务器内部资源,而不能转发到外部,比如www.baidu.com
3、转发是一次请求,而不是多次,如果细心你会发现我们forward跳转时,都是将request和response对象传入的,也就是说,无论转发多少次,都是同一此请求

3、共享数据

域对象
一个有作用范围的对象,可以在范围内共享数据,不同域对象作用范围不同
request域
范围是一次请求,通常用于在多个转发资源中共享数据,比如servlet1转发到2,2转发到3,而就算转发10000次,也都在一次请求中,这就是request域
void setAttribute(String name,Object obj):存储一个数据到request域中,name是键,obj是数据,在同一个域中,可通过name获取obj
Object getAttribute(String name):通过键获取值
void removeAttribute(String name):移除指定键值对

在这里插入图片描述

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //解决中文乱码,设置流的字符集编码
        req.setCharacterEncoding("utf-8");
        System.out.println("我是dome1Post");

        //在域中设置值,需要在转发之前
        req.setAttribute("name","我是字符串");
        req.setAttribute("age",15);
        req.setAttribute("array",new String[] {"1","2","3"});

        req.getRequestDispatcher("/dome2").forward(req,resp);//上面那么写太麻烦,一行搞定转发

    }

在这里插入图片描述

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("我是dome2Post");

        String name = (String)req.getAttribute("name");

        Integer age = (Integer)req.getAttribute("age");

        String[] array = (String[])req.getAttribute("array");
        System.out.println(name);
        System.out.println(age);
        System.out.println(array);
    }

移除就不演示了,直接request.removeAttribute("name")这样的就可以将值移除出域

4、获取ServletContext

ServletContext
一个非常重要的对象,这里只讲怎么获取,后面会专门讲解此对象
ServletContext getServletContext():通过Request对象调用方法获取即可

在这里插入图片描述

二、HTTP响应协议

响应消息
前面我们学过请求消息,就是客户端发送给服务端的数据,由请求行,请求头,请求空行,请求体组成
响应消息:服务端发送给客户端的数据
响应消息由,响应行,响应头,响应空行,响应体组成

在这里插入图片描述

响应行组成:协议及版本 响应状态码 状态码描述
状态码:服务器告诉客户端浏览器本次请求与响应的状态,一般由3位数字组成,比如404,502,可以百度HTTP状态码来详细了解分类,下面简单介绍一下状态码分类
状态码分类(XX代表随机数字):1XX(表示服务端接收消息,接收了一半,没接收完,等了一段时间只能发送状态码1XX),2XX(表示成功),3XX(302代表重定向,比如我们平常登陆完成后出现5秒后跳转页面,这时跳转去的页面就是重定向页面。304代表访问缓存,比如你的头像,第一次访问后服务器反馈给你,下次你又来请求相同的内容,这时就没必要重复响应,服务器会告诉浏览器你本地有,去访问缓存就行了),4XX(表示客户端错误,404表示你请求的资源不存在,一般路径写错就会报这个错,405表示请求方法不对,比如你发Post请求,而后端只有处理Get请求的方法),5XX(表示服务器错误,一般后端代码出错会报这个错)
响应头
Content-Type:表示响应体数据格式以及编码格式
Content-disposition:表示以何种格式打开响应体,没有指定就使用默认值in-line,表示在当前页面打开,一般我们需要指定时使用attachment;filename=XXX,表示以附件形式打开响应体,比如下载时指定使用,filename指定文件名

三、Response

设置响应信息和设置请求信息差不多,就不多赘述了

设置响应行、响应头
setStatus(int sc):设置;响应行状态码
setHeader(String name,String value):设置响应头

在这里插入图片描述

设置响应头
1、获取输出流(字符输出流PrintWriter getWriter(),字节输出流ServletOutputStream getOutputStream()。)
2、使用输出流将数据响应给客户端浏览器

1、response重定向

服务器端重定向
就是用户发送请求到一个servlet,服务器告诉用户这个servlet办不了,你去找X某某办
1、重定向需要给浏览器设置状态码302
2、需要告诉浏览器重定向路径,需设置location

在这里插入图片描述在这里插入图片描述

@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("我是dome1Get");
        this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //解决中文乱码,设置流的字符集编码
        req.setCharacterEncoding("utf-8");
        System.out.println("我是dome1Post");

        /*dome1重定向到dome2*/
        //设置状态码为302
//        resp.setStatus(302);
        //设置响应头location
//        resp.setHeader("location","dome2");

        //上面两行代码,302和location都是固定的,能变得只有dome2这个路径,所以有一个更简单的方法
        resp.sendRedirect("dome2");
    }

在这里插入图片描述

重定向特点(与请求转发完全相反)
地址栏会随着重定向而改变
重定向几次就发送几次请求,也就是不能用request域来传递数据了,因为都不是同一次请求
重定向可以访问到其它站点,而不局限与本服务器资源

2、response相对/绝对路径

因为这个是初学者非常容易犯的错,所有特地挑出来讲解
绝对地址:http://ip地址/资源路径
相对地址:/资源路径
以/开头的是相对路径,不以/开头的是绝对路径
相对路径会相对于当前路径范围下,寻找指定资源
绝对路径会根据路径直接寻找资源
建议给客户端使用的重定向,加上虚拟目录,虚拟目录最好不要写死,以后改一下,要改很多地方,推荐使用request.getContextPath()动态获取虚拟目录

3、response输出数据

在这里插入图片描述

最大的问题
就是服务器响应与浏览器编码不一样,会乱码
那么响应头中Content-Type参数可以设置编码格式
通过设置响应头来规定编码

在这里插入图片描述

@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("我是dome1Get");
        this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //解决中文乱码,设置流的字符集编码
        req.setCharacterEncoding("utf-8");

//        resp.setCharacterEncoding("utf-8");//响应时也需要设置编码,默认流编码为ISO-8859-1

//        resp.setHeader("content-type","text/html;charset=utf-8");//这一行的功能将上一行也包括了

        //同样的,和重定向一样,这个设置编码也提供了简单形式
        resp.setContentType("text/html;charset=utf-8");

        System.out.println("我是dome1Post");

        //获取字符输出流
//        PrintWriter writer = resp.getWriter();
//        writer.write("<h1>字符输出流<h1/>");


        //获取字节输出流,注意,同一次响应,只能使用一种输出流,如果想测试字符输出,先将下面这两句注释,然后放开上面两句测试
        ServletOutputStream outputStream = resp.getOutputStream();
        outputStream.write("alksdjflkasjfl案例可使肌肤鲁大师".getBytes("utf-8"));//只要确保内容转换为字节即可输出
    }

4、response验证码

简单的验证码例子,可不要把这种验证码放在项目中用

在这里插入图片描述

@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("我是dome1Get");
        this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //解决中文乱码,设置流的字符集编码
        req.setCharacterEncoding("utf-8");

//        resp.setCharacterEncoding("utf-8");//响应时也需要设置编码,默认流编码为ISO-8859-1

//        resp.setHeader("content-type","text/html;charset=utf-8");//这一行的功能将上一行也包括了

        //同样的,和重定向一样,这个设置编码也提供了简单形式
//        resp.setContentType("text/html;charset=utf-8");

        int width = 100;//生成图片的宽
        int height = 50;//生成图片的高

        //1、创建一个对象,在内存中代表一个图片
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);//创建图片对象

        /*2、美化图片*/

        //2.1填充背景色
        Graphics graphics = bufferedImage.getGraphics();//创建绘画对象
        graphics.setColor(Color.PINK);//设置画笔颜色
        graphics.fillRect(0,0,width,height);//填充一个矩形区域,从(0,0)开始

        //2.2画边框
        graphics.setColor(Color.BLUE);//重新设置画笔颜色
        graphics.drawRect(0,0,width-1,height-1);//画一个框框,-1是因为这个对象只有100*50,而边框有1像素,会跑到对象外面而看不见

        //2.3生成验证码
        String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        for(int i = 1;i < 5;i++){
            int index = random.nextInt(str.length());//获取随机下标

            char ch = str.charAt(index);//拿到随机字符

            graphics.drawString(ch+"",width/5*i,height/2);//画字符
        }
        //3、将图片输出到页面上
        ImageIO.write(bufferedImage, "jpg", resp.getOutputStream());
    }

在这里插入图片描述

四、ServletContext对象

ServletContext
代表整个web应用,可以和整个程序的容器(比如servlet,Tomcat等等)通信
可以获取MIME类型
可以作为域对象,共享数据
获取文件的真实路径(服务器路径)
获取
1、通过request对象获取:request.getServletContext();
2、直接通过HttpServlet获取(因为HttpServlet继承Servlet接口):this.getServletContext();

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("我是dome1Get");
        this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //解决中文乱码,设置流的字符集编码
        req.setCharacterEncoding("utf-8");

//        resp.setCharacterEncoding("utf-8");//响应时也需要设置编码,默认流编码为ISO-8859-1

//        resp.setHeader("content-type","text/html;charset=utf-8");//这一行的功能将上一行也包括了

        //同样的,和重定向一样,这个设置编码也提供了简单形式
//        resp.setContentType("text/html;charset=utf-8");

        //1、通过request对象获取ServletContext对象
        ServletContext servletContext1 = req.getServletContext();

        //2、通过HttpServlet直接获取
        ServletContext servletContext2 = this.getServletContext();

        //结果为true,无论何处获取,同一工程下只有一个ServletContext对象
        System.out.println("两种方式获取的ServletContext是否是同一个对象:"+(servletContext1 == servletContext2));

        /*
            获取MIME类型
        *   在互联网通信过程中定义的一种文件数据类型

            格式:大类型/小类型   比如text/html     text表示纯文本      html表示html文档       再比如 image/jpeg

            作用,再给客户端响应数据时,先要了解类型格式,响应时响应头中的Content-Type要指定对应的格式,这样浏览器才能正确接收

            获取方法
                String getMimeType(String file) 通过文件后缀名获取MIME类型
        * */

        //定义文件名称
        String fileName = "a.jpg";
        //获取MIME文件类型
        String MimeType = servletContext1.getMimeType(fileName);

        System.out.println("文件a.jpg对应的MIME类型为:"+MimeType);

        /*
            ServletContext对象作为域对象的作用域是最大的
            因为它的作用范围是整个web程序

            设置值,获取值的方法和请求域相同,getAttribute这些方法,是所有域对象通用的
         */

        //设置一个值到ServletContext域,那么整个web程序任何地方,只要这条语句执行过,就可以获取到
        servletContext1.setAttribute("name","zhangsan");

        /*
         * 获取文件真实路径
         *
         * String getRealPath("")
         */

        String realPath = servletContext1.getRealPath("/index.jsp");// 一个/ 后面跟资源名称,就是我们web或webapp目录下的资源
        //如果你要获取WEB-INF下面资源,需要些/WEB-INF/XXX.xxx
        
        System.out.println(realPath);
        //创建文件对象时,经常需要文件绝对路径,那么通过这个获取非常高效
        File file = new File(realPath);


    }

五、文件下载

步骤
1、设置响应头,告诉浏览器文件打开方式为附件打开,Content-disposition:attachment;filename=XXX,表示以附件形式打开响应体
2、用输入流读取文件,转到输出流输出

在这里插入图片描述

@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("我是dome1Get");
        this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //解决中文乱码,设置流的字符集编码
        req.setCharacterEncoding("utf-8");

        ServletContext servletContext = req.getServletContext();//获取ServletContext

        //1、获取文件的真实路径
        String realPath = servletContext.getRealPath("/index.jsp");

        //2、用字节流关联
        FileInputStream fileInputStream = new FileInputStream(realPath);

        //3、设置响应头,让浏览器以附件打开响应体
        //3.1获取文件MIME类型并设置
        String mimeType = servletContext.getMimeType("index.jsp");

        resp.setHeader("content-type",mimeType);

        //3.2设置以附件方式打开
        resp.setHeader("content-disposition","attachment;filename=index.jsp");

        //4、将输入流数据写出,标准的输入流数据转到输出流写法
        ServletOutputStream outputStream = resp.getOutputStream();
        byte[] bytes = new byte[1024 * 8];
        int len = 0;
        while((len = fileInputStream.read(bytes)) != -1){
            outputStream.write(bytes,0,len);
        }
        fileInputStream.close();
    }

1、中文文件名乱码问题

中文文件名问题,中文文件名无法正常获取显示
1、获取客户端浏览器版本信息
2、根据不同版本信息,响应不同的数据(设置filename文件名的编码方式)

在这里插入图片描述

package com.yzpnb.utils;

import sun.misc.BASE64Encoder;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

public class DownloadUtils {
    public static String getFileName(String agent,String filename) throws UnsupportedEncodingException {
        if(agent.contains("MSIE")){
            //IE浏览器
            filename = URLEncoder.encode(filename,"utf-8");
            filename = filename.replace("+"," ");
        } else if(agent.contains("Firefox")){
            //火狐浏览器
            BASE64Encoder base64Encoder = new BASE64Encoder();
            filename = "=?utf-8?B?"+base64Encoder.encode(filename.getBytes("utf-8"))+"?=";
        } else{
            //其它浏览器
            filename = URLEncoder.encode(filename,"utf-8");
        }
        return filename;
    }
}

在这里插入图片描述

@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //解决中文乱码,设置流的字符集编码
        req.setCharacterEncoding("utf-8");

        ServletContext servletContext = req.getServletContext();//获取ServletContext

        String fileName = "你好.txt";

        //1、获取文件的真实路径
        String realPath = servletContext.getRealPath("/"+fileName);

        //2、用字节流关联
        FileInputStream fileInputStream = new FileInputStream(realPath);

        //3、设置响应头,让浏览器以附件打开响应体
        //3.1获取文件MIME类型并设置
        String mimeType = servletContext.getMimeType(fileName);

        resp.setHeader("content-type",mimeType);

        /**解决中文文件名*/
        //1、获取user-agent请求头,拿到浏览器版本
        String userAgent = req.getHeader("user-agent");
        fileName = DownloadUtils.getFileName(userAgent, fileName);

        //3.2设置以附件方式打开
        resp.setHeader("content-disposition","attachment;filename="+fileName);

        //4、将输入流数据写出,标准的输入流数据转到输出流写法
        ServletOutputStream outputStream = resp.getOutputStream();
        byte[] bytes = new byte[1024 * 8];
        int len = 0;
        while((len = fileInputStream.read(bytes)) != -1){
            outputStream.write(bytes,0,len);
        }
        fileInputStream.close();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

殷丿grd_志鹏

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

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

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

打赏作者

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

抵扣说明:

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

余额充值