您的位置:首页 > Web前端 > JavaScript

JSP&Servlet学习笔记(3): 请求与响应

2018-02-28 22:19 295 查看

从容器到HttpServlet

有关HTTP请求的相关信息,是如何变成相对应的Java对象的呢?

当请求来到HTTP服务器,服务器将请求转交给Web容器的时候,Web容器会创建一个代表当次请求的HttpServletRequest对象,并给这个对象设置请求的相关信息。同时,容器也会创建一个作为稍后对客户端进行响应的HttpServletResponse对象。

接着,容器会根据读取的@WebServlet标注或web.xml的设置,找出处理该请求的Servlet,调用它的service()方法,将创建的HttpServletRequest对象和HttpServletResponse对象传入作为参数,service()方法中会根据HTTP请求的方式,调用对应的doxxx()方法。

例如,若为GET,调用doGet()方法,那么在该方法中就可以使用两个传入的对象了。可以使用getParameter()取得请求参数,使用getWriter()取得输出用的PrintWriter()对象,并进行各项响应处理。对PrintWriter做的输出操作,最后由容器转换为HTTP响应,再由HTTP服务器对浏览器进行响应。之后容器将做对象销毁回收,该次请求响应结束。

在GET与POST都需要相同处理的情境下,通常可以在继承HttpServlet之后,在doGet()、doPost()中都调用一个自定义的processRequest()。

protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
processRequest(req, resp);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
processRequest(req, resp);
}
protected void processRequest(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//处理请求...
}


关于HttpServletRequest

处理请求参数与标头

HttpServletRequest定义了取得一些通用请求信息的方法:

1. getParameter():指定请求参数名称来取得对应的值。
String username = request.getParameter("name");

2. getParameterValues():可复选,多值。
String[] values = request.getParameterValues("param");
取得所有请求参数名称:
Enumeration<String> e = req.getParameterNames();
while(e.hasMoreElements()) {
String param = e.nextElement();
...
}

3.getParameterMap():键是请求参数名称,值是请求参数值。


对于HTTP的标头(描述客户端或者服务器的属性、被传输的资源以及应该实现的连接 ),可以用以下方法取得:

getHeader()
getHeaders()
getHeaderName()
*转换:getIntHeader()或getDateHeader()


另外,getContextPath()可以取得Web应用程序环境路径。

请求参数编码处理

POST

如果浏览器以UTF-8来发送请求,那么接收时也要使用UTF-8编码字符串,所以在取得任何参数前调用执行该语句:

req.setCharacterEncoding("UTF-8");


GET

Tomcat在GET时,使用setCharacterEncoding()方法设置编码就不会有作用。所以是通过String的getBytes()指定编码来取得该字符串的字节数组,然后再重新构造为正确编码的字符串:

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


getReader()读取Body内容

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

...
String body = readBody(request);
...
}

private String readBody(HttpServletRequest request) throws IOException {
BufferedReader reader = request.getReader();
String input = null;
String requestBody = "";
while((input = reader.readLine()) != null) {
requestBody = requestBody = input + "<BR>";
}
return requestBody;
}
}


在同一个请求期间,getReader()与getIntputStream()只能择一调用,若两者都有调用,会抛出IllegalStatExcption异常。

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

编写一个Servlet来进行文件上传的处理,使用getPart()来处理上传的文件:

package cc.openhome;

import com.sun.xml.internal.fastinfoset.tools.FI_DOM_Or_XML_DOM_SAX_SAXEvent;

import java.io.*;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

@MultipartConfig   //Tomcat中必须设置此标注才能使用getPart()相关API
@WebServlet("/upload.do")
public class UploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
Part part = req.getPart("photo"); //使用getPart()取得Part对象
String filename = getFilename(part);
writeTo(filename, part);
}

private String getFilename(Part part) {  //取得上传文件名
String header = part.getHeader("Content-Disposit
4000
ion");
String filename = header.substring(header.indexOf("filename=\"") + 10, header.lastIndexOf("\""));
return filename;
}

private void writeTo(String filename, Part part) throws IOException, FileNotFoundException {  //储存文件
InputStream in = part.getInputStream();
OutputStream out = new FileOutputStream("/home/hxll/桌面/" + filename);
byte[] buffer = new byte[1024];
int length = -1;
while ((length = in.read(buffer)) != -1) {
out.write(buffer, 0, length);
}
in.close();
out.close();
}
}


其实,Part有个方便的write()方法,可以直接将上传文件指定文件名写入磁盘中:

part.write(filename);


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

for(Part part : req.getParts()) {  //迭代Collection中所有Part对象
if(part.getName().startsWith("file")) {
//只处理上传文件区段(因为"上传"按钮也会是其中一个Part对象,所以用if判断名称是不是以file开头)
String filename = getFilename(part);
part.write(filename);
}
}


使用RequestDispatcher调派请求

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

...
@WebServlet("/some.view")
...
PrintWriter out = resp.getWriter();
out.println("Some do one...");
RequestDispatcher dispatcher = req.getRequestDispatcher("other.view");
dispatcher.include(req, resp);
out.println("Some do two...");
out.close();
}
}
--------------------------------------------------------------------------
...
@WebServlet("other.view")
...
PrintWriter out = resp.getWriter();
out.println("Other do one...");
}
}


则网页上见到的响应顺序是Some do one…Other do one…Some do two…

使用forward()方法,将请求处理转发给别的Servlet

若要调用forward()方法,目前的Servlet不能有任何响应确认

@WebServlet("/hello.do")
public class HelloController extends HttpServlet {
private HelloModel model = new HelloModel();
@Override
protected void doGet(........ {
String name = request.getParameter("user"); //收集请求参数
String message = model.doHello(name); //委托HelloModel对象处理
request.setAttribute("message", message); //将结果信息设置请求对象成为属性
request.getRequestDispatcher("/hello.view").forward(request, response); //转发给hello.view进行响应


HelloController会收集请求参数并委托一个HelloModel对象处理。HelloModel对象处理的结果,会设置为请求对象中的属性。

请求属性范围

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

setAttribute()  指定名称与对象设置属性
getAttribute()  指定名称取得属性
getAttributeNames()  取得所有属性名称
removeAttribute()    指定名称移除属性


关于HttpServletResponse

设置响应标头、缓冲区

所有的标头设置,必须在响应确认之前,否则会被容器忽略

容器可以对响应进行缓冲:

getBufferSize()
setBufferSize()
isCommitted()  查看响应是否已确认
reset()   重置所有响应信息,连同已设置的标头一并清除
resetBuffer()  重置响应内容,但不清除标头
flushBuffer()  清除所有缓冲区中已设置的响应信息至客户端


setBufferSize()必须在调用getWriter()之前使用

reset()、resetBuffer()必须在响应未确认前调用

使用getWriter()输出字符

设置Locale

resp.setLocale(Locale.xxxx);


使用setCharacterEncoding()或setContentType()

resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=UTF-8");


如果指定了charset,则setLocale()就会被忽略。

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

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

...
response.setContentType("application/pdf");
InputStream in = getServletContext().getResourceAsStream("/WEB-INF/xxx.pdf");
OutputStream out = response.getOutputStream(); //取得输出串流
writeBytes(in, out);
}
private void writeBytes(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int length = -1;
while ((length = in.read(buffer)) != -1) {
out.write(buffer, 0, length);
}
in.close();
out.close();
}
}


使用sendRedirect()、sendError()

可以使用HttpServletResponse的sendRedirect()要求浏览器重新请求另一个URL,又称为重定向:

response.sendRedirect("http://openhome.cc");


在响应未确认输出前执行。

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

response.sendError(HttpServletResponse.SC_NOT_FOUND);


在响应未确认输出前执行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: