HttpServletRequest
public interface HttpServletRequest extends ServletRequest {
String BASIC_AUTH = "BASIC";
String FORM_AUTH = "FORM";
String CLIENT_CERT_AUTH = "CLIENT_CERT";
String DIGEST_AUTH = "DIGEST";
String getAuthType();
Cookie[] getCookies();
long getDateHeader(String var1);
String getHeader(String var1);
Enumeration<String> getHeaders(String var1);
Enumeration<String> getHeaderNames();
int getIntHeader(String var1);
String getMethod();
String getPathInfo();
String getPathTranslated();
String getContextPath();
String getQueryString();
String getRemoteUser();
boolean isUserInRole(String var1);
Principal getUserPrincipal();
String getRequestedSessionId();
String getRequestURI();
StringBuffer getRequestURL();
String getServletPath();
HttpSession getSession(boolean var1);
HttpSession getSession();
String changeSessionId();
boolean isRequestedSessionIdValid();
boolean isRequestedSessionIdFromCookie();
boolean isRequestedSessionIdFromURL();
/** @deprecated */
boolean isRequestedSessionIdFromUrl();
boolean authenticate(HttpServletResponse var1) throws IOException, ServletException;
void login(String var1, String var2) throws ServletException;
void logout() throws ServletException;
Collection<Part> getParts() throws IOException, ServletException;
Part getPart(String var1) throws IOException, ServletException;
<T extends HttpUpgradeHandler> T upgrade(Class<T> var1) throws IOException, ServletException;
}
当HTTP请求由Web容器处理时,Web容器会对其进行数据采集并封装在HttpServletRequest对象中,所以我们可以通过HttpServletRequest来获取HTTP中的信息,示例代码如下:
/**
* 该Serlvet主要是为了获取Http请求中的数据
*/
public class HttpRequestContextServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// URL:http://localhost:8080/learnServlet/getHttpRequestContext?name=niezhic&age=23
// 获取特定的请求参数值
System.out.println(request.getParameter("name"));// niezhic
// 这个方法原来是为了获取,像复选框checkbox这类同一个请求参数名对应多个值的情况,这样就是一个数组了
request.getParameterValues("");
// 获取所有请求参数名称
Enumeration<String> params = request.getParameterNames();// name、age
while (params.hasMoreElements()){
String param = params.nextElement();
System.out.println(param);
}
// 获取请求头中的信息
Enumeration<String> headers = request.getHeaderNames();// accept、accept-language、user-agent、accept-encoding、host、connection、cookie
while (headers.hasMoreElements()){
String head = headers.nextElement();
System.out.println(head + ":" + request.getHeader(head));// 获取请求头名称和请求头值
}
}
}
如果请求头的值是个整数或日期则可以用getIntHeader()或getDateHeader()分别转换为int和Date
请求编码的处理
/**
* 对于请求参数处理的Servlet,GET和POST处理的方式不同
*/
public class EncodeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 该方法只对请求体中的请求参数有效,所以只用于POST,不过要在获取请求之前声明
request.setCharacterEncoding("utf-8");
String name = request.getParameter("username");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getParameter("username");
// GET中采用这种方法来处理请求参数的编码
String name = new String(request.getParameter("username").getBytes("iso-8859-1"), "utf-8");
}
}
当然,在实际的项目中比如SpringMVC项目,只需要在web.xml配置一个过滤器就搞定请求编码的处理
读取请求体的中内容
先看提交的form表单:
<form action="/learnServlet/requestBodyServlet" method="post">
用户名:<input name="username" value="聂置纯"/>
<br/>
密码:<input type="password" name="password" value="niezhicisgod"/>
<br/>
<input type="submit" />
</form>
再看处理的Servlet:
/**
* 获取请求体中内容的Servlet
*/
public class RequestBodyServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// getReader()获取请求体中的内容
BufferedReader read = request.getReader();
String in = "";
String requestBody = "";
while ((in = read.readLine()) != null) {
requestBody += in + "<br/>";
}
PrintWriter out = response.getWriter();
out.print(requestBody);// username=%E8%81%82%E7%BD%AE%E7%BA%AF&password=niezhicisgod
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
当上传文件的时候,先处理form表单如下:
<form action="/learnServlet/uploadServlet" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="filename" />
<input type="submit" name="upload" />
</form>
此时的Servlet如下:
/**
* 用于上传文件的Servlet
*/
public class UpLoadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1、获取请求体
byte[] body = readBody(request);
// 2、将请求体内容以字符串表示
String txtBody = new String(body, "utf-8");
// 3、取得上传文件的名称
String fileName = getFileName(txtBody);
// 4、取得文件开始与结束位置
Position position = getFilePosition(request, txtBody);
// 5、输出至文件
writeTo(fileName, body, position);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
/**
* 定义文件开始与结束的位置的内部类
*/
class Position {
int begin;
int end;
public Position(int begin, int end) {
this.begin = begin;
this.end = end;
}
}
private void writeTo(String fileName, byte[] body, Position position) throws IOException {
FileOutputStream out = new FileOutputStream("d:" + fileName);
out.write(body, position.begin, (position.end - position.begin));
out.flush();
out.close();
}
private Position getFilePosition(HttpServletRequest request, String txtBody) throws UnsupportedEncodingException {
String contentType = request.getContentType();
String boundaryTxt = contentType.substring(contentType.lastIndexOf("=") + 1, contentType.length());
int pos = txtBody.indexOf("fileName=\"");
pos = txtBody.indexOf("\n", pos) + 1;
pos = txtBody.indexOf("\n", pos) + 1;
pos = txtBody.indexOf("\n", pos) + 1;
int boundaryLoc = txtBody.indexOf(boundaryTxt, pos) - 4;
int begin = ((txtBody.substring(0, pos)).getBytes("utf-8")).length;
int end = ((txtBody.substring(0, boundaryLoc)).getBytes("utf-8")).length;
return new Position(begin, end);
}
private String getFileName(String txtBody) {
String fileName = txtBody.substring(txtBody.indexOf("filename=\"") + 10);
fileName = fileName.substring(0, fileName.indexOf("\n"));
fileName = fileName.substring(fileName.lastIndexOf("\\") + 1, fileName.indexOf("\""));
return fileName;
}
private byte[] readBody(HttpServletRequest request) throws IOException {
int fileSize = request.getContentLength();
DataInputStream in = new DataInputStream(request.getInputStream());// 上传文件时,文件是以流的形式存在request中的
byte[] body = new byte[fileSize];
int totalByte = 0;
while (totalByte < fileSize) {
int bytes = in.read(body, totalByte, fileSize);
totalByte += bytes;
}
return body;
}
}
Servlet3.0中上传文件
在Servlet3.0中,新增了Part接口,可以方便的对文件进行上传操作,进行上传操作时,可以使用request.getPart()取得上传文件数据
public interface Part {
InputStream getInputStream() throws IOException;
String getContentType();
String getName();
String getSubmittedFileName();
long getSize();
void write(String var1) throws IOException;
void delete() throws IOException;
String getHeader(String var1);
Collection<String> getHeaders(String var1);
Collection<String> getHeaderNames();
}
此时的上传文件Servlet示例代码如下:
/**
* Servlet3.0中用于上传文件的Servlet
*/
@MultipartConfig // 必须设置该注解才能使用getPart()等相关方法,该注解还有一些非常好用的属性
public class UpLoadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 0、上传的文件名称可能包含中文
request.setCharacterEncoding("utf-8");
// 1、获取Part对象
Part part = request.getPart("upFile");
// 2、取得上传文件的名称
String fileName = getFileName(part);
// 5、输出至文件
writeTo(fileName, part);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
/**
* 当在 @MultipartConfig 注解中设置了location 输出文件目录,
* 就可以直接使用part.write(filename)方法,无需自定义writeTo()方法了
*/
private void writeTo(String fileName, Part part) throws IOException {
InputStream in = part.getInputStream();
OutputStream out = new FileOutputStream(fileName + "TEMP");
byte[] buffer = new byte[1024];
int length = -1;
while((length = in.read(buffer)) != -1) {
out.write(buffer, 0, length);
}
in.close();
out.close();
}
private String getFileName(Part part) {
String head = part.getHeader("Content-Disposition");
String fileName = head.substring(head.indexOf("filename=\"") + 10, head.lastIndexOf("\""));
return fileName;
}
}
@MultipartConfig注解,有一些属性如下:
1. location:设置写入文件时的目录,默认为空字符串;当设置了该属性,就可以使用Part中默认的write()方法输出文件了
2. maxFileSize:限制上传文件的大小,默认值为-1L,表示不限制大小
3. maxRequestSize:限制multipart/form-data请求个数,默认值为-1L,表示不限制个数
4. ....
同时上传多个文件时,此时的form表单:
<form action="/learnServlet/upLoadServlet" method="post" enctype="multipart/form-data">
选择文件1:<input type="file" name="upFile1" />
选择文件2:<input type="file" name="upFile2" />
选择文件3:<input type="file" name="upFile3" />
<input type="submit" name="upload" />
</form>
可以使用request.getParts()方法,此时的Servlet:
/**
* Servlet3.0中用于上传多个文件的Servlet
*/
@MultipartConfig // 必须设置该注解才能使用getPart()等相关方法,该注解还有一些非常好用的属性
public class UpLoadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 0、上传的文件名称可能包含中文
request.setCharacterEncoding("utf-8");
// 1、多个上传文件时,使用request.getParts方法
for (Part part:request.getParts()) {
String fileName = getFileName(part);
if(StringUtils.isNotBlank(fileName)) {
writeTo(fileName, part);
}
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
/**
* 当在 @MultipartConfig 注解中设置了location 输出文件目录,
* 就可以直接使用part.write(filename)方法,无需自定义writeTo()方法了
*/
private void writeTo(String fileName, Part part) throws IOException {
InputStream in = part.getInputStream();
OutputStream out = new FileOutputStream(fileName + "TEMP");
byte[] buffer = new byte[1024];
int length = -1;
while((length = in.read(buffer)) != -1) {
out.write(buffer, 0, length);
}
in.close();
out.close();
}
private String getFileName(Part part) {
String head = part.getHeader("Content-Disposition");
String fileName = head.substring(head.indexOf("filename=\"") + 10, head.lastIndexOf("\""));
return fileName;
}
}
@MultipartConfig注解当然也可以在web.xml中进行配置
<servlet>
<servlet-name>UpLoadServlet</servlet-name>
<servlet-class>isgod.niezhic.servlet.UpLoadServlet</servlet-class>
<multipart-config>
进行相关属性配置,如location
</multipart-config>
</servlet>
<servlet-mapping>
<servlet-name>UpLoadServlet</servlet-name>
<url-pattern>/upLoadServlet</url-pattern>
</servlet-mapping>
使用RequestDispatcher调派请求
在web应用中,经常需要多个Servlet来完成请求。例如,将另一个Servlet的请求处理使用include()包含进来,或将请求通过forward()转发给别的Servlet处理。这两个方法都在RequestDispathcer接口中,可以通过request.getRequestDispatcher()方法来获取到这个接口的实例。
public interface RequestDispatcher {
String FORWARD_REQUEST_URI = "javax.servlet.forward.request_uri";
String FORWARD_CONTEXT_PATH = "javax.servlet.forward.context_path";
String FORWARD_PATH_INFO = "javax.servlet.forward.path_info";
String FORWARD_SERVLET_PATH = "javax.servlet.forward.servlet_path";
String FORWARD_QUERY_STRING = "javax.servlet.forward.query_string";
String INCLUDE_REQUEST_URI = "javax.servlet.include.request_uri";
String INCLUDE_CONTEXT_PATH = "javax.servlet.include.context_path";
String INCLUDE_PATH_INFO = "javax.servlet.include.path_info";
String INCLUDE_SERVLET_PATH = "javax.servlet.include.servlet_path";
String INCLUDE_QUERY_STRING = "javax.servlet.include.query_string";
String ERROR_EXCEPTION = "javax.servlet.error.exception";
String ERROR_EXCEPTION_TYPE = "javax.servlet.error.exception_type";
String ERROR_MESSAGE = "javax.servlet.error.message";
String ERROR_REQUEST_URI = "javax.servlet.error.request_uri";
String ERROR_SERVLET_NAME = "javax.servlet.error.servlet_name";
String ERROR_STATUS_CODE = "javax.servlet.error.status_code";
void forward(ServletRequest req, ServletResponse resp) throws ServletException, IOException;
void include(ServletRequest req, ServletResponse resp) throws ServletException, IOException;
}
使用include()方法示例代码,如下:
public class OutServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 解决中文字符以 锛氱幇鍦 的乱码格式
response.setHeader("Content-type", "text/html;charset=UTF-8");
// 解决中文字符以 ???? 的乱码格式
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
out.print("outServlet:现在将要演示包含其他请求处理的方法include(),当然我还会给他一个惊喜");
// 当要传递对象给inServlet时,可以使用request.setAttribute()方法,通过setAttribute()方法设置的属性被称为请求范围属性,因为只适用于当前请求,当要删除每个属性时,可以通过removeAttribute()方法删除指定属性 request.setAttribute("user",new User("我是一个妹纸", 23));
// 将inServlet的请求处理流程包含进来,
// 还可以包含inServlet请求参数,如request.getRequestDispatcher("inServlet?username=niezhicisgod")
RequestDispatcher disp = request.getRequestDispatcher("inServlet");
disp.include(request,response);
out.close();
}
}
public class InServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 解决中文字符以 锛氱幇鍦 的乱码格式
response.setHeader("Content-type", "text/html;charset=UTF-8");
// 解决中文字符以 ???? 的乱码格式
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
out.print("inServlet:咦...大家好,没想到以这种方式和大家见面了。额,没想到outServlet还送了妹纸给我,我好喜欢");
// 获取同一个请求对象生命周期中的设置的对象
User user = (User) request.getAttribute("user");
out.print(user);
// RequestDispatcher该接口中还定义了和include()相关的常量:
// INCLUDE_REQUEST_URI = "javax.servlet.include.request_uri"; 表示上一个Servlet的请求URL,不过在include中没有上一个Servlet这种说法
// INCLUDE_CONTEXT_PATH = "javax.servlet.include.context_path"; 表示上一个Servlet的上下文路径,不过在include中没有上一个Servlet这种说法
// INCLUDE_PATH_INFO = "javax.servlet.include.path_info"; 表示上一个Servlet的路径信息,不过在include中没有上一个Servlet这种说法
// INCLUDE_SERVLET_PATH = "javax.servlet.include.servlet_path"; 表示上一个Servlet的路径,不过在include中没有上一个Servlet这种说法
// INCLUDE_QUERY_STRING = "javax.servlet.include.query_string"; 表示上一个Servlet的请求参数,不过在include中没有上一个Servlet这种说法
String url = (String) request.getAttribute("javax.servlet.include.request_uri");
out.print(url);
out.close();
}
}
使用forward()方法示例代码,如下:
public class FrontServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 解决中文字符以 锛氱幇鍦 的乱码格式
response.setHeader("Content-type", "text/html;charset=UTF-8");
// 解决中文字符以 ???? 的乱码格式
response.setCharacterEncoding("utf-8");
request.setAttribute("user",new User("一个妹纸", 23));
// 请求转发操作时,当前Servlet不能进行响应确认否则报错
RequestDispatcher disp = request.getRequestDispatcher("backServlet");
disp.forward(request,response);
}
}
public class BackServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.print("backServlet:frontServlet说要介绍一个妹纸给我,他自己也还是单身,却为我着想,我好感动");
// 获取同一个请求对象生命周期中的设置的对象
User user = (User) request.getAttribute("user");
out.print(user);
// RequestDispatcher该接口中还定义了和forward()相关的常量:
// FORWARD_REQUEST_URI = "javax.servlet.forward.request_uri"; 表示上一个Servlet的请求URL
// FORWARD_CONTEXT_PATH = "javax.servlet.forward.context_path";
// FORWARD_PATH_INFO = "javax.servlet.forward.path_info";
// FORWARD_SERVLET_PATH = "javax.servlet.forward.servlet_path";
// FORWARD_QUERY_STRING = "javax.servlet.forward.query_string";
// url = (String) request.getAttribute("javax.servlet.include.request_uri");
String url = (String) request.getAttribute("javax.servlet.forward.request_uri");
out.print(url);// learnServlet/frontServlet
}
}
在使用转发请求操作时,当前的Servlet不能有任何响应确认,否则会抛出IllegalStateException;这里的响应确认是指客户端接收到响应的内容了