java web Request和Response快速入门笔记

    科技2024-08-19  20

    文章目录

    一、Request1、获取请求消息数据1、获取请求行数据2、获取请求头数据3、请求体数据 2、获取数据通用方法1、获取请求参数通用方法2、请求转发3、共享数据4、获取ServletContext 二、HTTP响应协议三、Response1、response重定向2、response相对/绝对路径3、response输出数据4、response验证码 四、ServletContext对象五、文件下载1、中文文件名乱码问题

    一、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.1GET这个位置:请求方法,可以是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/demo1HTTP/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可以获取对应值zhangsanString[] 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对象获取请求转发器对象RequestDispatcher2、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.com3、转发是一次请求,而不是多次,如果细心你会发现我们forward跳转时,都是将request和response对象传入的,也就是说,无论转发多少次,都是同一此请求

    3、共享数据

    域对象一个有作用范围的对象,可以在范围内共享数据,不同域对象作用范围不同 request域范围是一次请求,通常用于在多个转发资源中共享数据,比如servlet1转发到2,2转发到3,而就算转发10000次,也都在一次请求中,这就是request域void setAttribute(String name,Object obj):存储一个数据到request域中,name是键,obj是数据,在同一个域中,可通过name获取objObject 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、重定向需要给浏览器设置状态码3022、需要告诉浏览器重定向路径,需设置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(); }
    Processed: 0.009, SQL: 8