Servlet&JSP 第三章 请求与响应

时间:2023-01-02 21:03:21

一、doXXX()方法

1、HTTP定义了GET、POST、PUT、DELETE、HEAD、OPTIONS、TRACE等请求方式,HttpServlet中对应的方法有:

(1)doGet():处理HTTP GET请求

(2)doPost():处理HTTP POST请求

(3)doPut():处理HTTP PUT请求

(4)doDelete():处理HTTP DELETE请求

(5)doHead():处理HTTP HEAD请求

(6)doOptions():处理HTTP OPTIONS请求

(7)doTrace():处理HTTP TRACE请求

例1、如果在继承HttpServlet之后,没有重新定义doGet()方法,而客户端对Servlet发出了GET请求,则会收到错误信息。

2、对于GET请求,service()方法可以实现getLastModified()方法(默认返回-1,也就是默认不支持if-modified-since标头),来决定是否调用doGet()方法,getLastModified()方法返回自1970年1月1日凌晨至资源最后一次更新期间所经过的毫秒数,返回的这个时间如果晚于浏览器发出的if-modified-since标头,才会调用doGet()方法。

二、关于HttpServletRequest

  当HTTP转发给Web容器处理时,Web容器会收集相关的信息,并产生HttpServletRequest对象,可以通过这个对象取得HTTP请求中的信息,可以在Servlet中进行请求的处理,或是将请求转发(或包含)另一个Servlet/JSP进行处理,各个Servlet/JSP在同一请求周期中所需共享的资料,则可以设置在请求对象中成为属性。

1、处理请求参数与标头

请求来到服务器时,Web容器会创建HttpServletRequest实例来包装请求中的相关信息,HttpServletRequest定义了取得一些通用请求信息的方法。

可以使用以下方法来取得请求参数:

(1)getParameter():指定请求参数名称来取得对应的值,返回的是String对象,若传来的是像“123”这样的字符串值,而需要的是基本数据类型,则必须使用Integer.parseInt()这类的方法将它剖析为基本类型,若请求中没有所指定的请求参数名称,则会返回null。

例2、String username=request.getParameter(“name”);
(2)getParameterValues():如果窗体上有可复选的元件,如复选框、列表等,则同一个请求参数名称会有多个值(此时的HTTP查询字符串其实就是像param=10&param=20&param=30),此时可以用getParameterValues()方法取得一个String数组,数组元素代表所有被选取选项的值。

例3、String[] values=request.getParameterValues("param");
如果想要知道请求中有多少请求参数,则可以使用getParameterNames()方法,这时就会返回一个Enumeration对象,其中包括所有的请求参数名称。

例4、Enumeration<String> enum=request.getParameterNames();
(3)getParameterMap():将请求参数以Map对象返回,Map中的键(key)是请求参数名称,值(Value)的部分就是请求参数值,以字符串数组类型String[]返回(因考虑有同意请求参数有多个值的情况)。

(4)对于HTTP的标头(Header)信息,可以使用以下方法取得:

getHeader():使用方式与getParameter()类似,指定标头名称后可返回字符串值,代表浏览器所送出的标头信息。

getHeaders():使用方式与getParameterValues()类似,指定标头名称后可返回Enumeration,元素为字符串。

getHeaderNames():使用方式与getParameterNames()类似,取得所有标头名称,以Enumeration返回,内含所有标头字符串名称。如果标头值本身是个整数或日期的字符串表示法,则可以使用getIntHeader()方法或getDateHeader()方法分别取得转换为int或Date的值。如果getIntHeader()无法转换为int,则会抛出NumberFormatException;如果getDateHeader()无法转换为Date,则会抛出IllegalArgumentException。

2、请求参数编码处理

(1)POST请求参数编码处理

  如果客户端没有在Content-Type标头中设置字符编码信息,此时使用HttpServletRequest的getCharacterEncoding()返回值会是null,在这个情况下,容器若使用的默认编码处理是ISO-8859-1(大部分浏览器默认的字符集),而客户端使用UTF-8发送非ASCII字符的请求参数,Servlet直接使用getParameter()等方法取得该请求参数值,就会是不正确的结果也就是的到乱码。

  可以使用HttpServletRequest的setCharacterEncoding()方法指定取得POST请求参数时使用的编码,一定要在取得任何请求参数之前执行setCharacterEncoding()方法才有作用,在取得请求参数之后,再调用setCharacterEncoding()是没有任何作用的。
(2)GET请求参数编码处理

  通过String的getBytes()指定编码来取得该字符串的字节数组,然后再重新构造为正确编码的字符串。
例5、若浏览器使用UTF-8处理字符,Web容器默认使用ISO-8859-1编码,则正确处理编码的方式为:

String name=request.getParameter("name");
String name=new String(name.getBytes("ISO-8859-1),"UTF-8");

3、getReader()、getInputStream()读取body内容

(1)HttpServletRequest上定义有getReader()方法,可以取得一个BufferedReader通过该对象,可以读取请求的body数据。

例6、取得BufferedReader对象:BufferedReader buff=request.getReader();
(2)窗体发送时,如果<form>标签没有设置enctype属性,则默认值是application/x-www-form-urlencoded,如果要上传文件,则enctype属性要设为multipart/form-data。
(3)要取得上传的文件,基本方式是判断文件的开始与结束区段,然后使用HttpServletRequest的getInputStream()取得ServletInputStream,它是InputStream的子类,代表请求body的串流对象,可以利用它来处理上传的文件区段。

(4)在同一个请求期间,getReader()与getInputStream()只能择一调用,若同一期间两者都有调用,则会抛出I了legalStateException。

4、getPart()、getParts()取得上传文件

  可以通过HttpServletRequest的getPart()方法取得Part实例对象进行文件上传处理。

(1)要在Servlet上设置@MultipartConfig才能取得Part对象,否则getPart()会得到null结果,调用getPart()时要指定名称取得对应的Part对象。

(2)如果要取得标头信息,可以使用Part对象的getHeader()方法指定标头名称来取得对应的值,想要取得上传文件的名称,就是取得Content-Disposition标头的值,然后取得filename属性的值,最后再利用Java I/O API写入文件中。

(3)Part的write()方法可以直接将上传文件指定文件名写入磁盘中,write()可指定文件名,写入的路径是相对于@MultipartConfig的location设置的路径。

(4)如果有多个文件要上传,可以使用getParts()方法,这会返回一个Collection<Part>,其中是每个上传文件的Part对象。

5、@MultipartConfig标注

可用来设置Servlet处理上传文件的相关信息,@MultipartConfig可用的属性如下:

fileSizeThreshold:整数值设置,若上传文件大小超过设置门槛,会先写入缓存文件,默认值为0;

location:字符串设置,设置写入文件时的目录,如果设置这个属性,则缓存文件就是写到指定的目录,也可搭配Part的write()方法使用,默认为空字符串;

maxFileSize:限制上传文件的大小,默认值为-1L,表示不限制大小;

maxRequestSize:限制Mulitipart/form-data请求个数,默认值为-1L,表示不限个数;

6、使用RequestDispatcher调派请求

(1)在Web应用程序中,经常需要多个Servlet来完成请求,如果需要将另一个Servlet的请求处理流程包含进来,或将请求转发给别的Servlet来处理,可以使用HttpServletRequest的getRequestDispatcher()方法取得RequestDispatcher接口的实现对象实例,调用时指定转发或包含的相对URL网址。

例7、RequestDispatcher rd=request.getRequestDispatcher(“some.do”);
(2)取得RequestDispatcher还有两个方式,通过ServletContext的getRequestDispatcher()或getNamedDispatcher()方法。

(3)使用include()方法:RequestDispatcher的include()方法可以将另一个Servlet操作流程包括至目前Servlet操作流程之中。

调用include()方法时,必须分别传入实现ServletRequest、ServletResponse接口的对象,可以是service()方法传入对象,或者是自定义的对象或封装器。

在被包含(或转发,如果使用的是forward())的Servlet中可以使用getParameter(“data”)取得请求参数值。

使用include()时,被包含的Servlet中任何对请求标头的设置都会被忽略,被包含的Servlet中可以使用getSession()方法取得HttpSession对象。

(4)请求范围属性:在include()或forward()时包含请求参数的做法,仅适用于传递字符串值给另一个Servlet,在调派请求的过程中,

如果有必须共享的“对象”,可以设置给请求对象称为属性,称为请求范围属性。

与请求范围属性有关的几个方法如下:

setAttribute():指定名称与对象设置属性,通过它设置的属性才称为请求范围属性。

getAttribute():指定名称取得属性。

getAttributeNames():取得所有属性名称。

removeAttribute():指定名称移除属性。

在设置请求范围属性时,需注意属性名称由java.或javax.开头的名称通常保留给规格书中某些特定意义的属性。

如果被包含的Servlet还包括其他的Servlet,则这些属性名称的对应值也会被代换。

(5)使用forward()方法:调用时传入请求与响应对象,将请求处理转发给别的Servlet,“对客户端的响应同时也转发给另一个Servlet”,若要调用forward()方法,目前的Servlet不能有任何响应确认(Commit),如果在目前的Servlet中通过响应对象设置了一些响应但未确认(响应缓冲区未满或未调用任何清除方法),则所有响应设置会被忽略,如果已经有响应确认且调用了forward()方法,则会抛出IllegalStateException。

三、关于HttpResponse

  可以使用HttpResponse来对浏览器进行响应,大部分情况下,会使用setContentType()设置响应类型,使用getWriter()取得PrintWriter对象,而后使用PrintWriter的println()等方法输出HTML内容。

1、设置响应标头、缓冲区

(1)可以使用HttpServletResponse对象上的setHeader()、addHeader()来设置响应标头。setHeader()设置标头名称和值,addHeader()则可以在同一个标头名称上附加值,如果标头的值是整数,则可以使用setIntHeader()、addIntHeader()方法,如果标头的值是个日期,则可以使用setDataHeader()、addDataHeader()方法。

(2)所有的标头设置,必须在响应确认之前,在响应确认之后设置的标头会被容器忽略。

(3)容器可以(但非必要)对响应进行缓冲,通常容器默认都会对响应进行缓冲,可以操作HttpServletResponse有关的几个方法:

getBufferSize()

setBufferSize():必须在调用HttpServletResponse的getWrite()或getOutputStream()方法之前调用,所取得的Writter或ServletOutputStream才会套用这个设置。

isCommited():看是否响应已确认。

reset():重置所有响应,会连同已设置的标头一并清除,必须在响应为确认前调用。

resetBuffer():重置响应内容,但不会清除已设置的标头内容,必须在响应为确认前调用。

flushBuffer():清除所有缓冲区中已设置的响应信息至客户端。

(4)HttpServletResponse对象若被容器关闭,则必须清除所有的响应内容,响应对象被关闭的时机点有以下几种:

Servlet的service()方法已结束,响应的内容长度超过HttpServletResponse的setContentLength()所设置的长度;

调用了sendRedirect()方法;

调用了sendError()方法;

调用了AsyncContext的complete()方法;

2、使用getWriter()输出字符

(1)设置Locale:浏览器如果有发送Accept-Language标头,则可以使用HttpServletRequest的getLocale()来取得一个Locale对象,代表客户端可接受的语系,可以使用HttpServletResponse的setLocale()来设置地区(Locale)信息,地区信息就包括了语系与编码信息,而setLocale()也会设置HTTP响应的Content-Language标头。

例8、response.setLocale(Locale.*);
在使用HttpServletResponse的setContentType()时,指定charset,charset的值会自动用来调用setCharacterEncoding()方法。

例9、response.setContentType(“text/html;charset=UTF-8”);//设置内容类型为text/html,设置编码为UTF-8
如果使用setCharacterEncoding()或setContentType()时指定了charset,则setLocale()就会被忽略。

如果要收集中文请求参数并在响应时通过浏览器正确显示中文,必须同时设置HttpServletRequest的setCharacterEncoding()以及HttpServletResponse的setCharacterEncoding()或setContentType()为正确的编码。

(2)使用getOutputStream()输出二进制字符

  入股哦需要直接对浏览器进行字节输出,可使用HttpServletResponse的getOutputStream()方法取得ServletOutputStream实例,它是OutputStream的子类。

(3)使用sendRedirect()、sendError()

可使用HttpServletResponse的sengRedirect()方法要求浏览器重新请求另一个URL,又称为重定向,使用时可指定绝对URL或相对URL。

例10、response.sendRedirect("http://openhome.cc");
这个方法会在响应中设置状态码301以及Location标头,浏览器接收到这个标头,会重新指定GET方法请求指定的URL,因此地址栏上会出现URL的变更,这个方法必须在响应未确认输出前执行,否则会抛出IllegalStateException。

如果在处理请求的过程中发现一些错误,想要传送服务器默认的状态与错误信息,可以使用sendError()方法。

例11、如果根据请求参数必须返回的资源根本不存在,则可以送出错误信息:

response.sendError(HttpServletResponse.SC_NOT_FOUND);
“SC_NOT_FOUND”会令服务器响应404状态码,这些常数是定义在HttpServletResponse接口上的。如果想要使用自定义的信息来取代默认的信息文字,则可以使用sendError()的另一个版本:
response.sendError(HttpServletResponse.SC_NOT_FOUND,“笔记文件”);