Servlet
在之前的笔记 中,我们已经初步了解了Servlet:
概念
步骤
执行原理
生命周期
Servlet3.0注解配置
接下来我们深入学习一下:
Servlet体系结构
Servlet相关配置
Servlet的体系结构
Servlet – 接口
|
GenericServlet – 抽象类
|
HttpServlet – 抽象类
GenericServlet
GenericServlet :将Servlet接口中其他的方法做了默认实现,只将service()
方法作为抽象方法
这样我们将来定义Servlet类时,可以继承GenericServlet ,只需要实现service()
方法即可
例子:我们定义一个Demo01类,继承GenericServlet 类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package web.Servlet;import javax.servlet.GenericServlet;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.annotation.WebServlet;import java.io.IOException;@WebServlet ("/demo01" )public class Demo01 extends GenericServlet { @Override public void service (ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("GenericServlet...Demo01" ); } }
HttpServlet
HttpServlet:对http协议的一种封装,简化操作。在操作时:
定义类时继承HttpServlet
复写doGet和doPost方法
例子,我们创建Demo02代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package web.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 ("/demo02" )public class Demo02 extends HttpServlet { @Override protected void doGet (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("doGet..." ); } @Override protected void doPost (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("doPost..." ); } }
Servlet相关配置
urlpartten:Servlet访问路径(即@WebServlet
注解中写的内容)
一个Servlet可以定义多个访问路径 :@WebServlet({"/demo01", "/demo011","/demo0111"})
例子,我们将Demo01代码修改如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package web.Servlet;import javax.servlet.GenericServlet;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.annotation.WebServlet;import java.io.IOException;@WebServlet ({"/demo01" , "/demo011" ,"/demo0111" })public class Demo01 extends GenericServlet { @Override public void service (ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("GenericServlet...Demo01" ); } }
这样访问路径就可以为多个:/demo01,/demo011,/demo0111
注意一下路径定义规则:
/xxx:路径匹配
/xxx/xxx:多层路径,目录结构
*.do:自定义扩展名匹配(扩展名可以修改)
例子,创建Demo04代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package web.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 ("*.do" ) public class Demo03 extends HttpServlet { @Override protected void doGet (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("doGet...Demo03" ); } }
HTTP
超文本传输协议(Hypertext Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII形式给出;而消息内容则具有一个类似MIME的格式。这个简单模型是早期Web成功的有功之臣,因为它使开发和部署非常地直截了当。
概念:Hyper Text Transfer Protocol 超文本传输协议
传输协议:定义了客户端和服务器端通信时,发送数据的格式
特点:
基于TCP/IP的高级协议
默认端口号:80
基于请求/响应模型的:一次请求对应一次响应
无状态的:每次请求之间相互独立,不能交互数据
历史版本:
1.0:每一次请求响应都会建立新的连接
1.1:复用连接
(视频讲解 )
请求消息数据格式
请求消息:客户端发送给服务器端的数据
响应格式:服务器端发送给客户端的数据
请求消息数据格式:
视频讲解
请求行
请求方式 请求url 请求协议/版本(如:GET /login.html HTTP/1.1
)
请求方式 :HTTP协议有9中请求方式(菜鸟教程 ,HTTP请求方式简单介绍 )。常用的两种:
GET:
请求参数在请求行中,在url后
请求的url长度是有限制的
不太安全
POST
请求参数在请求体中
请求的url长度是没有限制的
相对安全
请求头
请求头:客户端浏览器告诉服务器一些信息
常见请求头:请求头值
User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息
可以在服务器端获取该头的信息,解决浏览器的兼容性问题
Referer:http://localhost/login.html
请求空行
请求空行,就是用来分割POST请求的请求头和请求体
请求体
响应消息数据格式
请求消息:客户端发送给服务器端的数据
响应格式:服务器端发送给客户端的数据
响应消息数据格式:
视频讲解
响应行
组成:协议/版本 响应状态码 状态码描述(如:HTTP/1.1 200 OK
)
响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态。状态码都是3位数字。分类如下:
1xx:服务器就收客户端消息,但没有接受完成,等待一段时间后,发送1xx状态码
2xx:成功。代表:200
3xx:重定向。代表:302(重定向),304(访问缓存)
4xx:客户端错误。代表例子:
404(请求路径没有对应的资源)
405:请求方式没有对应的doXxx方法
5xx:服务器端错误。代表:500(服务器内部出现异常)
关于状态码详细文章有:HTTP 响应代码
响应头
格式:头名称: 值
常见的响应头:
Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式(取值有utf-8,gbk等)
Content-disposition:服务器告诉客户端以什么格式打开响应体数据。具体取值有:
in-line:默认值,在当前页面内打开
attachment;filename=xxx:以附件形式打开响应体。文件下载
响应空行
空行是用于分割请求数据的行,且是必须的
响应体
该响应消息的响应体是一个html文档。浏览器可以直接识别这个html文件。(而我们访问的是一个jsp文件,响应回去的是一个html文件。说明服务器将该jsp翻译成了一个html,然后再响应给浏览器)
Request
什么是request和response
request对象是服务器对浏览器请求的封装,而response是服务器对服务器响应的封装 。 request用来取出请求信息,而response则用来添加要返回给浏览器的信息 。
request和response对象
request对象和response对象的原理:
request和response对象是由服务器创建的。我们来使用它们
request对象是来获取请求消息,response对象是来设置响应消息
(视频讲解 )
Request继承体系
request对象继承体系结构:
ServletRequest – 接口
| 继承
HttpServletRequest – 接口
| 实现
org.apache.catalina.connector.RequestFacade 类(tomcat)
Request功能
视频讲解
获取请求消息数据
获取请求行数据
例如:GET /user/demo03?name=zhangsan HTTP/1.1
方法:
获取请求方式 :GET
获取虚拟目录 :/user
获取Servlet路径: /demo1
获取get方式请求参数:name=zhangsan
获取请求URI(或URL) :/user/demo03
String getRequestURI()
/user/demo03 (URI)
StringBuffer getRequestURL()
http://localhost/user/demo03
(URL)
获取协议及版本:HTTP/1.1
获取客户机的IP地址:
例子:我们先设置虚拟目录为:/user
然后创建RequestDemo01,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 package web.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 ("/requestDemo01" )public class RequestDemo01 extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String method = request.getMethod(); System.out.println("请求方式:" +method); String contextPath = request.getContextPath(); System.out.println("虚拟目录:" +contextPath); String servletPath = request.getServletPath(); System.out.println("Servlet路径:" +servletPath); String queryString = request.getQueryString(); System.out.println("get方式请求参数:" +queryString); String requestURI = request.getRequestURI(); StringBuffer requestURL = request.getRequestURL(); System.out.println("请求URI:" +requestURI); System.out.println("请求URL:" +requestURL); String protocol = request.getProtocol(); System.out.println("协议及版本:" +protocol); String remoteAddr = request.getRemoteAddr(); System.out.println("客户机的IP地址:" +remoteAddr); } }
在浏览器访问:http://localhost:8080/user/requestDemo01?name=zhangsan&age=18
结果为:
这里再简单提一下URL和URI的区别:
**URI:**Uniform Resource Identifier 统一资源标识符
**URL:**Uniform Resource Location 统一资源定位符
首先,URI,是统一资源标识符,用来唯一的标识一个资源。 而URL是统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。 也就是说,URI是以一种抽象的,高层次概念定义统一资源标识,而URL和URN则是具体的资源标识的方式。
URI和URL的区别
获取请求头数据
方法:
例子:
我们创建RequestDemo02,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package web.request;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;@WebServlet ("/requestDemo02" )public class RequestDemo02 extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Enumeration<String> headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()){ String name = headerNames.nextElement(); String header = request.getHeader(name); System.out.println("请求头名称:" +header); } String agent = request.getHeader("user-agent" ); System.out.println("user-agent:" +agent); if (agent.contains("Chrome" )){ System.out.println("Google" ); }else if (agent.contains("FirFox" )){ System.out.println("FirFox" ); } String referer = request.getHeader("Referer" ); System.out.println("Referer:" +referer); } }
通过浏览器访问:http://localhost:8080/user/requestDemo02
结果为:
关于获取Referer,从而防盗链的详细讲解:视频讲解
获取请求体数据
请求体:只有POST请求方式,才有请求体,在请求体中封装了POST请求的请求参数
步骤:
获取流对象
获取字符输入流,只能操作字符数据:BufferedReader getReader()
获取字节输入流,可以操作所有类型数据:ServletInputStream getInputStream()
(在后续上传文件案例中会具体讲到)
再从流对象中拿数据
例子:
我们先在web包下创建regist.html,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > 注册页面</title > </head > <body > <form action ="/user/requestDemo03" method ="post" > <input type ="text" name ="username" > <br > <input type ="password" name ="password" > <br > <input type ="submit" value ="注册" > <br > </form > </body > </html >
然后在request包下创建RequestDemo03,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package web.request;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.BufferedReader;import java.io.IOException;@WebServlet ("/requestDemo03" )public class RequestDemo03 extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { BufferedReader bufferedReader = request.getReader(); String line = null ; while ((line = bufferedReader.readLine())!=null ){ System.out.println(line); } } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } }
在浏览器输入:http://localhost:8080/user/regist.html
,然后输入用户名和密码,结果如下:
目录结构为:
request其他功能
获取请求参数(GET和POST通用)
请求转发
共享数据
获取ServletContext
获取请求参数(GET和POST通用)
获取请求参数通用方式。不论get还是post请求方式,都可以使用下列方法来获取请求参数 :
根据参数名称获取参数值 :username=zs&password=123
String getParameter(String name)
根据参数名称获取参数值的数组:hobby=xx&hobby=game
String[] getParameterValues(String name)
获取所有请求的参数名称:
Enumeration<String> getParameterNames()
获取所有参数的map集合 :
Map<String,String[]> getParameterMap()
解决中文乱码问题:
get方式:tomcat 8 已经将get方式乱码问题解决了
post方式:会乱码
解决:在获取参数前,设置request的编码request.setCharacterEncoding("utf-8");
例子:我们先在web包下创建regist1.html和regist2.html两个html页面,因为要验证GET和POST,所以这两个html文件除了method不同为其余均一样 ,这里给出regist.html的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > 注册页面</title > </head > <body > <form action ="/user/requestDemo04" method ="post" > <input type ="text" name ="username" > <br > <input type ="password" name ="password" > <br > <input type ="submit" value ="注册" > <br > </form > </body > </html >
创建RequestDemo04代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package web.request;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;import java.util.Set;@WebServlet ("/requestDemo04" )public class RequestDemo04 extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username" ); System.out.println("POST:" +username); Map<String, String[]> parameterMap = request.getParameterMap(); Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet(); for (Map.Entry<String, String[]> entry : entries) { System.out.println(entry.getKey()+entry.getValue()[0 ]); } } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username" ); System.out.println("GET:" +username); } }
在浏览器分别访问http://localhost:8080/user/regist1.html
和http://localhost:8080/user/regist2.html
(一个是GET一个是POST)
点击注册按钮后结果如下:
其余的方法这里就不展示了,这里有:视频讲解
请求转发
请求转发:一种在服务器内部的资源跳转方式
视频讲解
步骤:
通过request对象获取请求转发器对象 :RequestDispatcher getRequestDispatcher(String path)
使用RequestDispatcher对象来进行转发 :forward(ServletRequest request, ServletResponse response)
请求转发特点:
浏览器地址栏路径不发生变化
只能转发到当前服务器内部资源中
转发是一次请求(多个资源之间可以实现一次请求)
例子:我们分别创建RequestDemo05和RequestDemo06,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package web.request;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;import java.util.Map;import java.util.Set;@WebServlet ("/requestDemo05" )public class RequestDemo05 extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("RequestDemo05被访问" ); RequestDispatcher requestDispatcher = request.getRequestDispatcher("/requestDemo06" ); requestDispatcher.forward(request,response); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package web.request;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;import java.util.Set;@WebServlet ("/requestDemo06" )public class RequestDemo06 extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("RequestDemo06被访问" ); } }
在浏览器访问:http://localhost:8080/user/requestDemo05
结果如下:
共享数据
域对象:一个有作用范围的对象,可以在范围内共享数据
request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据
方法:
存储数据:void setAttribute(String name,Object obj)
通过键获取值:Object getAttitude(String name)
通过键移除键值对:void removeAttribute(String name)
例子,在上述RequestDemo05和RequestDemo06基础上,我们修改代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package web.request;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;import java.util.Map;import java.util.Set;@WebServlet ("/requestDemo05" )public class RequestDemo05 extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("RequestDemo05被访问" ); request.setAttribute("msg" ,"success" ); request.getRequestDispatcher("/requestDemo06" ).forward(request,response); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package web.request;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;import java.util.Set;@WebServlet ("/requestDemo06" )public class RequestDemo06 extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Object msg = request.getAttribute("msg" ); System.out.println("获取数据为:" +msg); System.out.println("RequestDemo06被访问" ); } }
在浏览器访问:http://localhost:8080/user/requestDemo05
结果如下:
获取ServletContext
方法:
获取ServletContext:ervletContext getServletContext()
例子:创建RequestDemo07代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package web.request;import javax.servlet.ServletContext;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 ("/requestDemo07" )public class RequestDemo07 extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext servletContext = request.getServletContext(); System.out.println("获取成功:" +servletContext); } }
在浏览器访问:http://localhost:8080/user/requestDemo07
结果如下:
Response
request对象和response对象的原理:
request和response对象是由服务器创建的。我们来使用它们
request对象是来获取请求消息,response对象是来设置响应消息
Response功能
设置响应行
方法:
设置响应头
方法:
设置响应头:setHeader(String name, String value)
简单的重定向方法:sendRedirect(String s)
设置响应体
步骤:
获取输出流。方法:
字符输出流:PrintWriter getWriter()
字节输出流:ServletOutputStream getOutputStream()
使用输出流,将数据输出到客户端浏览器
Response功能实现案例
这里通过几个案例来体现上述方法
完成重定向
服务器输出字符数据到浏览器
服务器输出字节数据到浏览器
验证码
完成重定向
重定向:资源跳转的方式
视频讲解
代码实现
我们分别创建ResponseDemo01和ResponseDemo02,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package response;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 ("/demo01" )public class ResponseDemo01 extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("demo01..." ); response.sendRedirect("/response01/demo02" ); } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this .doPost(request,response); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package response;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 ("/demo02" )public class ResponseDemo02 extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("demo02..." ); } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this .doPost(request,response); } }
在浏览器中访问:http://localhost:8080/response01/demo01
结果如下:
重定向的特点
视频讲解
重定向的特点(redirect)
地址栏路径发生变化
重定向可以访问其他站点(服务器)的资源
重定向是两次请求,不能使用request对象来共享数据
之前学习过的请求转发
转发的特点(forward)
地址栏路径不变
转发只能访问当前服务器下的资源
转发是一次请求,可以使用request对象来共享数据
路径的写法
视频讲解
路径分类:
相对路径:通过相对路径不可以确定唯一资源(如:./index.html)
以.开头的路径路径
规则:找到当前资源和目标资源之间的相对位置关系
绝对路径:通过绝对路径可以确定唯一资源(如:http://localhost:8080/response01/demo01
,简化书写为:/response01/demo01
)
以/开头的路径
规则:判断定义的路径是给谁用的?判断请求将来从哪儿发出
给客户端浏览器使用:需要加虚拟目录(项目的访问路径)。重定向就需要加虚拟目录
建议虚拟目录动态获取(使用方法获取):request.getContextPath()
给服务器使用:不需要加虚拟目录(比如说请求转发 时就没有加虚拟路径)
服务器输出字符数据到浏览器
步骤:
获取字符输出流
输出数据
注意,乱码问题:
PrintWriter pw = response.getWriter();获取的流的默认编码是ISO-8859-1
设置该流的默认编码
告诉浏览器响应体使用的编码
解决中文乱码(简单的形式,设置编码,是在获取流之前设置):
response.setContentType("text/html;charset=utf-8");
例子:创建ResponseDemo03代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package response;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.io.PrintWriter;@WebServlet ("/demo03" )public class ResponseDemo03 extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8" ); response.getWriter().write("ResponseDemo03,你好!" ); } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this .doPost(request,response); } }
在浏览器输入:http://localhost:8080/response01/demo03
结果如下:
服务器输出字节数据到浏览器
步骤:
获取字节输出流
输出数据
例子,创建ResponseDemo04,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package response;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;@WebServlet ("/demo04" )public class ResponseDemo04 extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8" ); ServletOutputStream servletOutputStream = response.getOutputStream(); servletOutputStream.write("ResponseDemo04:你好" .getBytes("utf-8" )); } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this .doPost(request,response); } }
在浏览器输入:http://localhost:8080/response01/demo04
结果如下:
验证码
视频讲解
例子:先创建CheckCodeServlet,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 package response;import javax.imageio.ImageIO;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.*;import java.awt.image.BufferedImage;import java.io.IOException;import java.util.Random;@WebServlet ("/check" )public class CheckCodeServlet extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { int width = 100 ; int height = 50 ; BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); Graphics g = image.getGraphics(); g.setColor(Color.PINK); g.fillRect(0 ,0 ,width,height); g.setColor(Color.BLUE); g.drawRect(0 ,0 ,width - 1 ,height - 1 ); String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789" ; Random ran = new Random(); for (int i = 1 ; i <= 4 ; i++) { int index = ran.nextInt(str.length()); char ch = str.charAt(index); g.drawString(ch+"" ,width/5 *i,height/2 ); } g.setColor(Color.GREEN); for (int i = 0 ; i < 10 ; i++) { int x1 = ran.nextInt(width); int x2 = ran.nextInt(width); int y1 = ran.nextInt(height); int y2 = ran.nextInt(height); g.drawLine(x1,y1,x2,y2); } ImageIO.write(image,"jpg" ,response.getOutputStream()); } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this .doPost(request,response); } }
然后在web包下创建register.html,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > 验证码</title > <script > /* 分析: 点击超链接或者图片,需要换一张 1.给超链接和图片绑定单击事件 2.重新设置图片的src属性值 */ window .onload = function ( ) { var img = document .getElementById("checkCode" ); img.onclick = function () { var date = new Date ().getTime(); img.src = "/response01/check?" +date; } } </script > </head > <body > <img id ="checkCode" src ="/response01/check" /> <a id ="change" href ="" > 看不清换一张?</a > </body > </html >
在浏览器输入:http://localhost:8080/response01/register.html
结果如下:
ServletContext对象
servletContext接口是Servlet中最大的一个接口,呈现了web应用的Servlet视图。ServletContext实例是通过 getServletContext()方法获得的,由于HttpServlet继承GenericServlet的关系,GenericServlet类和HttpServlet类同时具有该方法。
WEB容器在启动时,它会为每个Web应用程序都创建一个对应的ServletContext,它代表当前Web应用。并且它被所有客户端共享。
ServletContext对象可以通过ServletConfig.getServletContext()方法获得对ServletContext对象的引用,也可以通过this.getServletContext()方法获得其对象的引用。
由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。公共聊天室就会用到它。
当web应用关闭、Tomcat关闭或者Web应用reload的时候,ServletContext对象会被销毁
ServletContext 对象
概念:代表整个web应用,可以和程序的容器(服务器)来通信
获取ServletContext对象
获取ServletContext对象的方法:
通过request对象获取:request.getServletContext();
通过HttpServlet获取:this.getServletContext();
例子:创建ServletContextDemo01代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package servletcontext;import javax.servlet.ServletContext;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 ("/context01" )public class ServletContextDemo01 extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext servletContext1 = request.getServletContext(); ServletContext servletContext2 = this .getServletContext(); System.out.println(servletContext1); System.out.println(servletContext2); System.out.println(servletContext1 == servletContext2); } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this .doPost(request, response); } }
在浏览器中访问:http://localhost:8080/response01/context01
结果如下:
ServletContext对象功能
获取MIME类型
共享数据
获取文件的真实(服务器)路径
获取MIME类型
媒体类型(通常称为 Multipurpose Internet Mail Extensions 或 MIME 类型 )是一种标准,用来表示文档、文件或字节流的性质和格式。
浏览器通常使用MIME类型(而不是文件扩展名)来确定如何处理URL,因此Web服务器在响应头中添加正确的MIME类型非常重要。如果配置不正确,浏览器可能会曲解文件内容,网站将无法正常工作,并且下载的文件也会被错误处理。
MIME 类型
视频讲解
MIME类型:在互联网通信过程中定义的一种文件数据类型。
格式: 大类型/小类型。比如:text/html
,image/jpeg
获取MIME类型:
String getMimeType(String file)
例子:创建ServletContextDemo02代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package servletcontext;import javax.servlet.ServletContext;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 ("/context02" )public class ServletContextDemo02 extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext servletContext = this .getServletContext(); String fileName = "hello.jpg" ; String mimeType = servletContext.getMimeType(fileName); System.out.println(mimeType); } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this .doPost(request, response); } }
在浏览器中访问:http://localhost:8080/response01/context02
结果如下:
共享数据
(谨慎使用,一是不安全,二是内存占用时间过长,生命周期过长)
ServletContext是一个域对象(域对象:一个有作用范围的对象,可以在范围内共享数据)
注意,ServletContext对象范围:所有用户所有请求的数据 (上文的request域,代表一次请求的范围)
关于共享数据 ,上文也有详细说明
方法:
存储数据:void setAttribute(String name,Object obj)
通过键获取值:Object getAttitude(String name)
通过键移除键值对:void removeAttribute(String name)
例子:我们分别创建ServletContextDemo03和ServletContextDemo04,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package servletcontext;import javax.servlet.ServletContext;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 ("/context03" )public class ServletContextDemo03 extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext servletContext = this .getServletContext(); servletContext.setAttribute("msg" ,"hello" ); } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this .doPost(request, response); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package servletcontext;import javax.servlet.ServletContext;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 ("/context04" )public class ServletContextDemo04 extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext servletContext = this .getServletContext(); Object msg = servletContext.getAttribute("msg" ); System.out.println(msg); } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this .doPost(request, response); } }
在两个不同的浏览器 分别访问:http://localhost:8080/response01/context03
,http://localhost:8080/response01/context04
结果如下:
这说明ServletContext对象可以在不同用户之间共享数据
获取文件的真实(服务器)路径
视频讲解
获取文件的真实(服务器)路径方法:
String getRealPath(String path)
例子:我们要获取hello.txt
,world.txt
,abc.txt
这三个文件的路径。这三个文件位置如下:
创建ServletContextDemo05,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package servletcontext;import javax.servlet.ServletContext;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 ("/context05" )public class ServletContextDemo05 extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext servletContext = this .getServletContext(); String realPath_world = servletContext.getRealPath("/world.txt" ); System.out.println("world.txt路径:" +realPath_world); String realPath_hello = servletContext.getRealPath("/WEB-INF/hello.txt" ); System.out.println("hello.txt路径:" +realPath_hello); String realPath_abc = servletContext.getRealPath("/WEB-INF/classes/abc.txt" ); System.out.println("abc.txt路径:" +realPath_abc); } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this .doPost(request, response); } }
在浏览器中访问:http://localhost:8080/response01/context05
结果如下:
案例
登录案例
本案例仓库地址:https://gitee.com/qingyu1011/springboot_study/tree/master/J2EE/Demo_Login
知识点:Request+JDBC
用户登录案例需求:
编写login.html登录页面
username & password 两个输入框
使用Druid数据库连接池技术,操作mysql,jdbc_study数据库中user表
使用JdbcTemplate技术封装JDBC
登录成功跳转到SuccessServlet展示:登录成功!用户名,欢迎您
登录失败跳转到FailServlet展示:登录失败,用户名或密码错误
案例分析:视频讲解
实现步骤:
1.创建项目,导入html登录页面和druid配置文件,以及相关jar包
创建login.html,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Title</title > </head > <body > <form action ="/demo01/login" method ="post" > 用户名:<input type ="text" name ="username" > <br > 密码:<input type ="password" name ="password" > <br > <input type ="submit" value ="登录" > </form > </body > </html >
注意form表单中的action路径写法:虚拟路径+Servlet的资源路径
创建druid.properties配置文件放在src目录下,代码如下:
1 2 3 4 5 6 7 driverClassName =com.mysql.jdbc.Driver url =jdbc:mysql://localhost:3306/jdbc_study username =root password =123456 initialSize =5 maxActive =10 maxWait =3000
2.创建数据库环境
user表中数据如下:
3.在domain包下创建User类,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package edu.qing.domain;public class User { private Integer id; private String username; private String password; @Override public String toString () { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}' ; } }
4.在util包下,创建编写工具类JDBCUtils代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 package edu.qing.util;import com.alibaba.druid.pool.DruidDataSourceFactory;import javax.sql.DataSource;import java.io.IOException;import java.io.InputStream;import java.sql.Connection;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.Properties;public class JDBCUtils { private static DataSource dataSource; static { try { Properties properties = new Properties(); properties.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties")); dataSource = DruidDataSourceFactory.createDataSource(properties); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection () throws SQLException { return dataSource.getConnection(); } public static DataSource getDataSource () { return dataSource; } }
5.在dao包下,创建类UserDao,提供login方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package edu.qing.dao;import edu.qing.domain.User;import edu.qing.util.JDBCUtils;import org.springframework.dao.DataAccessException;import org.springframework.jdbc.core.BeanPropertyRowMapper;import org.springframework.jdbc.core.JdbcTemplate;import java.util.List;public class UserDao { private JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtils.getDataSource()); public User login (User loginUser) { try { String sql = "select * from user where username = ? and password = ?" ; User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class ), loginUser .getUsername (), loginUser .getPassword ()) ; return user; } catch (DataAccessException e) { e.printStackTrace(); return null ; } } }
6.接下来在servlet包下创建LoginServlet,FailServlet,SuccessServlet代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 package edu.qing.servlet;import edu.qing.dao.UserDao;import edu.qing.domain.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;@WebServlet ("/login" )public class LoginServlet extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8" ); String username = request.getParameter("username" ); String password = request.getParameter("password" ); User loginUser = new User(); loginUser.setUsername(username); loginUser.setPassword(password); UserDao userDao = new UserDao(); User user = userDao.login(loginUser); if (user == null ){ request.getRequestDispatcher("/fail" ).forward(request,response); } else { request.setAttribute("msg" ,user); request.getRequestDispatcher("/success" ).forward(request,response); } } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package edu.qing.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 ("/fail" )public class FailServlet extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8" ); response.getWriter().write("登录失败!请检查用户名或密码" ); } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this .doPost(request,response); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package edu.qing.servlet;import edu.qing.domain.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;@WebServlet ("/success" )public class SuccessServlet extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { User user = (User) request.getAttribute("msg" ); response.setContentType("text/html;charset=utf-8" ); if (user !=null ){ response.getWriter().write("登录成功!欢迎您:" + user.getUsername()); } } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this .doPost(request,response); } }
在浏览器访问:http://localhost:8080/demo01/login.html
结果如下:
BeanUtils工具类,简化数据封装
BeanUtils工具类,用于封装JavaBean的。
这里简单提一下JavaBean 。JavaBean:标准的Java类。
要求:
类必须被public修饰
必须提供空参的构造器
成员变量必须使用private修饰
提供公共setter和getter方法
功能:封装数据
了解一些概念:
成员变量,很好理解,比如说User类的id,就是成员变量
属性:setter和getter方法截取后的产物
例如:getUsername() --> Username–> username
关于属性的视频讲解
BeanUtils工具类的方法:
设置属性值:setProperty()
获取属性值:getProperty()
将map集合的键值对信息,封装到对应的JavaBean对象 :populate(Object obj, Map map)
在上述代码中,我们封装JavaBean是这样操作的:在LoginServlet中编写:
1 2 3 4 5 6 7 String username = request.getParameter("username" ); String password = request.getParameter("password" ); User loginUser = new User(); loginUser.setUsername(username); loginUser.setPassword(password);
这样的话如果需要封装的请求参数过多,就会导致代码很麻烦。这时就可以使用BeanUtils工具类,来简化数据封装
1.首先导入jar包:commons-beanutils-1.8.0.jar
2.在LoginServlet中修改上述封装代码,改为以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 Map<String, String[]> parameterMap = request.getParameterMap(); User loginUser = new User(); try { BeanUtils.populate(loginUser,parameterMap); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); }
文件下载案例
知识点:综合整个笔记
文件下载案例需求:
页面显示超链接
点击超链接后弹出下载提示框
完成图片文件下载
案例分析:(视频讲解 )
超链接指向的资源如果能够被浏览器解析,则在浏览器中展示,如果不能解析,则弹出下载提示框。不满足需求
任何资源都必须弹出下载提示框
使用响应头设置资源的打开方式:content-disposition:attachment;filename=xxx
步骤:
定义页面,编辑超链接href属性,指向Servlet,传递资源名称filename
定义Servlet,要实现以下功能:
获取文件名称
使用字节输入流加载文件进内存
指定response的响应头: content-disposition:attachment;filename=xxx
将数据写出到response输出流
代码实现:
首先创建download.html文件,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > 下载</title > </head > <body > <a > 从浏览器中查看</a > <hr /> <a href ="/response01/imgs/top1.jpg" > 图片1</a > <hr /> <a href ="/response01/imgs/top2.jpg" > 图片2</a > <hr /> <a > 点击下载</a > <hr /> <a href ="/response01/download?filename=top1.jpg" > 图片1</a > <hr /> <a href ="/response01/download?filename=top2.jpg" > 图片2</a > </body > </html >
然后在download包下创建DownloadServlet代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 package download;import javax.servlet.ServletContext;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.FileInputStream;import java.io.IOException;@WebServlet ("/download" )public class DownloadServlet extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String filename = request.getParameter("filename" ); ServletContext servletContext = this .getServletContext(); String realPath = servletContext.getRealPath("/imgs/" +filename); FileInputStream fileInputStream = new FileInputStream(realPath); String mimeType = servletContext.getMimeType(filename); response.setHeader("Content-Type" ,mimeType); response.setHeader("Content-disposition" ,"attachment;filename=" +filename); ServletOutputStream servletOutputStream = response.getOutputStream(); byte [] bytes = new byte [1024 * 8 ]; int length = 0 ; while ((length = fileInputStream.read(bytes)) != -1 ){ servletOutputStream.write(bytes,0 ,length); } fileInputStream.close(); } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this .doPost(request, response); } }
在浏览器输入:http://localhost:8080/response01/download.html
结果如下:
中文文件名问题
视频讲解
解决思路:
获取客户端使用的浏览器版本信息
根据不同的版本信息,设置filename的编码方式不同
具体例子:首先在utils包下创建DownLoadUtils工具类代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package 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" )) { 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; } }
然后在DownloadServlet中,补充相关代码(在// 3-2 设置响应头类型打开方式后补充):
1 2 3 4 5 6 7 8 9 String header = request.getHeader("user-agent" ); filename = DownLoadUtils.getFileName(header, filename); response.setHeader("Content-disposition" ,"attachment;filename=" +filename);