标签:
之前已经详细讲解了Servlet/JSP的基础知识,包括Servlet和JSP的关系、Servlet基本的编写和配置,以及一个请求/响应过程中,HTTP服务器、web容器、Servlet是如何配合工作的。
对于一个web应用程序来说,请求/响应是其工作工程的基础,我们这里只考虑基于HTTP协议的请求/响应模型,HttpServletRequest代表请求及相关参数,HttpServletResponse代表响应及相关参数,这两个对象会随着一个请求的发起而建立,随着一个响应的结束而销毁被回收。当一个请求到来时,HttpServlet会执行service()方法,在其中判断当前HTTP的请求方式(包括GET、POST、PUT、DELETE、HEAD、OPTIONS、TRACE),并创建HttpSevletRequest和HttpServletResponse对象,传给请求方式对应的方法doXXX()。
关于HttpSevletRequest,相关的知识无非就是请求参数的获取、编码处理、文件上传接收、请求重定向等,下面把常用的知识点整理一下,并附上demo。
获取请求参数与标头
HttpSevletRequest里面封装了获取请求参数的方法,请求参数是以键值对的形式存储在其中的,下面是相关方法:
方法 |
说明 |
String getParameter(String key) |
通过请求参数名称获取参数值 |
String[] getParameterValues(String key) |
同上,有时候请求参数名称对应多个值 |
Enumeration<String> getParameterNames() |
获取所有参数名称 |
Map<String, String[]> getParameterMap() |
请求参数以Map对象返回 |
对于HTTP的标头(Header)信息,可以使用下面的方法来获得:
方法 |
说明 |
String getHeader(String key) |
类似getParamater() |
String[] getHeaders(String key) |
类似getParamaterValues() |
Enumeration<String> getHeaderNames() |
类似getParamaterNames() |
请求参数编码处理
获取请求参数,编码是一定要考虑的,否则容易出现乱码,好在现在的框架帮我们完成了大部分编码处理的操作。什么情况下容易出现乱码呢?当客户端设置的编码和web容器使用的编码不一致时,最容易出现乱码。客户端的编码是我们自己设置的,web容器的编码一般是在一个请求中,在Content-Type表头中设置的,例如“ContentType: text/html; charset=UTF-8”就是告诉web容器:“你web容器想要获取正确的参数,就得用UTF-8解码,否则出现了问题别怪我客户端没提醒你!”。我们可以在HttpServletRequest中通过getCharacterEncoding()方法获取当前请求的编码,若客户端没有在标头中设置编码信息,这个方法将返回null,然后web容器默认使用ISO-8859-1(这是大部分浏览器默认的字符集)解码。
下面我们只讨论POST和GET两种最常用的请求方式下的编码处理。
POST
客户端会将参数封装到请求中,假如客户端的编码方式是UTF-8,它在封装参数的时候,相当于执行下面这段代码:
String parameter = java.net.URLEncoder.encode(value, "UTF-8");
String parameter = java.net.URLEncoder.encode(value, "ISO-8859-1");
解决方式是在客户端发起请求的Content-Type标头中设置编码(charset=UTF-8),在Servlet中获取请求参数前,调用request.setCharacterEncoding():
request.setCharacterEncoding("GBK");
GET
为什么POST和GET不一样呢?因为POST和GET的传参方式不同,在HttpServletRequest的API中对serCharacterEncoding()有如下说明:
Overides the name of the character encoding userd in the body of this request意思就是这个方式只对请求Body中的字符编码才有用,也就是说这个方法基本上只对POST有用,因为GET传参是通过URL实现的,而URL的处理是HTTP服务器来完成的,并非Web容器,所以要使用GET方式传参,其编码处理方式就不同了。
还是上面的例子,客户端的编码方式是UTF-8,执行下面代码,通过GET方式请求:
String parameter = java.net.URLEncoder.encode(value, "UTF-8");因为使用GET方式,所以web容器设置啥编码都没用了,默认使用ISO-8859-1解码:
String parameter = java.net.URLEncoder.encode(value, "ISO-8859-1");然后我们得在Servlet中这样解码:
String parameter = new String(value.getBytes("ISO-8859-1"), "utf-8");
test-get.html
<!DOCTYPE html> <html> <head> <meta name="content-type" content="text/html; charset=GBK"> </head> <body> <form action="hello.view" method="get"> <input type="text" name="username" /> <button>发送GET请求</button> </form> </body> </html>test-post.html
<!DOCTYPE html> <html> <head> <meta name="content-type" content="text/html; charset=GBK"> </head> <body> <form action="hello.view" method="post"> <input type="text" name="username" /> <button>发送POST请求</button> </form> </body> </html>HelloServlet.java
@WebServlet("/hello.view") public class HelloServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("username"); name = new String(name.getBytes("ISO-8859-1"), "GBK"); System.out.println("GET:" + name); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("GBK"); String name = request.getParameter("username"); System.out.println("POST:" + name); } }
实际上,在Servlet中直接进行编码设置或转换,并不是最好的方法,以后学会了过滤器(Filter)时,我们就可以在过滤器中处理编码转换,将编码和逻辑解耦,这才是一种好的方式。
上传文件的接收
在HttpServletRequest中,有getReader()方法、getInputStream()方法,可以实现获取上传的文件,但这种方式实现起来很麻烦,需要自己判断文件的起始点、标签、key等,还容易出错。于是在Servlet 3.0中,新增了Part接口,可以让我们更方便地进行文件的上传处理,举个例子:
upload.html
<!DOCTYPE html> <html> <head> <meta name="content-type" content="text/html; charset=UTF-8"> </head> <body> <form action="hello.view" method="post" enctype="multipart/form-data"> 上传文件:<input type="file" name="uploadfile" /> <input type="submit" name="upload" value="上传"> </form> </body> </html>HelloServlet.java
@MultipartConfig @WebServlet("/hello.view") public class HelloServlet extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Part part = request.getPart("uploadfile"); String fileName = getFileName(part); save(fileName, part); } private String getFileName(Part part) { String header = part.getHeader("Content-Disposition"); String fileName = header.substring(header.indexOf("filename=\"") + 10, header.lastIndexOf("\"")); return fileName; } private void save(String fileName, Part part) throws IOException{ InputStream in = part.getInputStream(); File file = new File("D:/" + fileName); file.mkdirs(); OutputStream out = new FileOutputStream(file); byte[] buffer = new byte[1024]; int length = -1; while ((length = in.read(buffer)) != -1) { out.write(buffer, 0, length); } in.close(); out.close(); } }
属性 |
说明 |
fileSizeThreshold |
整数值,若上传文件大小超过这里设置的门槛,会先写入缓存文件,默认值为0 |
location |
字符串,设置写入文件时的目录,若设置该属性,则缓存文件就是写到指定的目录,可以搭配part的write()方法使用,默认为空字符串 |
maxFileSize |
限制上传文件大小,默认为-1L,即不限制大小 |
maxRequestSize |
显示multipart/form-data请求个数,默认同上 |
<span style="font-family:Microsoft YaHei;font-size:14px;">Content-Disposition: form-data; name="filename"; filename="xxxx.txt"</span>
@MultipartConfig(location="D:/") @WebServlet("/hello.view") public class HelloServlet extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Part part = request.getPart("uploadfile"); String fileName = getFileName(part); part.write(fileName); } private String getFileName(Part part) { String header = part.getHeader("Content-Disposition"); String fileName = header.substring(header.indexOf("filename=\"") + 10, header.lastIndexOf("\"")); return fileName; } }
<body> <form action="hello.view" method="post" enctype="multipart/form-data"> 文件1:<input type="file" name="file1" /> 文件2:<input type="file" name="file2" /> 文件3:<input type="file" name="file3" /> <input type="submit" name="upload" value="上传"> </form> </body>
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { for (Part part: request.getParts()) { //加个判断是因为form表单中的上传按钮,也会被算作part if(part.getName().startsWith("file")){ String fileName = getFileName(part); part.write(fileName); } } }
<servlet> <servlet-name>SimpleServlet</servlet-name> <servlet-class>com.web.SimpleServlet</servlet-class> <multipart-config> <location>D:/</location> </multipart-config> </servlet>
web应用程序中,一个请求经常需要多个servlet协作完成,这就需要考虑多个servlet如何传递/交接请求、如何传递参数等。HttpServletRequest提供了getRequestDispatcher()方法取得RequestDispatcher接口的实现对象实例,调用时需要传入被调用的servlet名称:
RequestDispatcher dispatcher = req.getRequestDispatcher("test.view");
RequestDispatcher接口包含两个方法:
下面是一个例子:
@WebServlet("/hello.view") public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter out = resp.getWriter(); out.println("这是第一段输出的内容"); RequestDispatcher dispatcher = req.getRequestDispatcher("test.view"); dispatcher.include(req, resp); out.println("这是第n+1段输出的内容(n >= 0)"); out.close(); } public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter out = resp.getWriter(); out.println("这段内容将不会被输出"); RequestDispatcher dispatcher = req.getRequestDispatcher("test.view"); dispatcher.forward(req, resp); out.println("这段内容将不会被输出"); // out.close(); 这段代码会抛出异常 } }
@WebServlet("/hello.view") public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter out = resp.getWriter(); RequestDispatcher dispatcher = req.getRequestDispatcher("test.view"); List<String> list = new ArrayList<String>(); req.setAttribute("userIds", list); dispatcher.include(req, resp); out.close(); } public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter out = resp.getWriter(); RequestDispatcher dispatcher = req.getRequestDispatcher("test.view"); List<String> list = new ArrayList<String>(); req.setAttribute("userIds", list); dispatcher.forward(req, resp); } }
Java Web基础(三)(HttpServletRequest-请求基础)
标签:
原文地址:http://blog.csdn.net/zhai56565/article/details/51337045