ServletRequest
简述
其实就是对于请求报文的封装,一般就是HttpServletRequest。
常用方法
package com.simon.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("/request1")
public class RequestServlet1 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();
// /app/request1
String requestURI = request.getRequestURI();
// http://localhost/app/request1 requestURL = 协议 + 主机端口号 + requestURI
String requestURL = request.getRequestURL().toString();
String protocol = request.getProtocol();
System.out.println(method + " " + requestURI + " " + protocol);
System.out.println(method + " " + requestURL + " " + protocol);
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()){
String key = headerNames.nextElement();
String value = request.getHeader(key);
System.out.println(key + ":" + value);
}
//请求体
//request.getInputStream();
}
}
除此之外还可以获取到客户端和服务器主机的一些信息:
package com.simon.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("/request2")
public class RequestServlet2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//request还可以获取客户机和服务器主机的一些信息
String localAddr = request.getLocalAddr();
int localPort = request.getLocalPort();
String remoteAddr = request.getRemoteAddr();
int remotePort = request.getRemotePort();
System.out.println("客户机:" + remoteAddr + "使用端口号:" + remotePort +
"访问了服务器主机:" + localAddr + " 服务器端口号:" + localPort);
}
}
Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象、和代表响应的response对象。
那么,频繁地去刷新同一个链接,会创建多个request对象还是一个request对象呢?多个request对象.
使用场景
最常用的使用场景就是获取请求参数,比如登录一个网站,需要用户输入用户名密码。点击登录,会发送一个HTTP请求,HTTP请求报文、用户名、密码会随着HTTP请求报文携带到服务器上面去;
用户名、密码在请求报文中,接下来,我们需要做的就是从请求报文中取出用户名、密码,做校验。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/servlet/login" method="post">
用户名:<input type="text" name="username"/><br>
密码:<input type="password" name="password"/><br>
<input type="checkbox" name="hobby" value="Java">Java<br>
<input type="checkbox" name="hobby" value="PHP">PHP<br>
<input type="submit"/>
</form>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
what happen
</body>
</html>
package com.simon.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.Arrays;
import java.util.Enumeration;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
//getParameter()方法不仅可以获取请求体里面的请求参数,还可以获取在请求行的请求参数
//但是该方法也有限定条件,它只能获取key=value&key=value型的数据
String username = req.getParameter("username");
String password = req.getParameter("password");
if ("zs".equals(username)&&"abc".equals(password)){
Enumeration<String> parameterNames = req.getParameterNames();
while (parameterNames.hasMoreElements()){
String parameterName = parameterNames.nextElement();
String[] parameterValues = req.getParameterValues(parameterName);
if (1 == parameterValues.length ){
System.out.println(parameterName + ":" + parameterValues[0]);
}else {
System.out.println(parameterName + ":" + Arrays.toString(parameterValues));
}
}
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().println("恭喜,登陆成功即将跳转....");
RequestDispatcher dispatcher = req.getRequestDispatcher("/success.html");
dispatcher.forward(req,resp);
}
}
}
Request域
共享空间。Request对象中存在一个map,如果能够拿到同一个request对象,那么就能够共享这个map
但是,哪些组件可以拿到同一个request对象
刷新同一个页面的多个请求可以共享request域吗?
不可以
转发的两个组件之间 共享request域。
如果某个servlet需要将数据和另外一个servlet进行共享,不仅仅可以通过context域进行共享,还可以利用request域来共享
比如某个servlet运行时获取到了商品的数据,接下来需要在另外一个servlet中去做一些格式化,Wed 2020-
context域:范围很大。所有的servlet均可以共享
request域:很小,只有这两个组件之间可以共享。假设你的场景需求就是在这个请求内需要共享,出了这个请求,就不需要共享,那么完全可以使用request域,而不需要使用context域,有点浪费
ServletResponse
常规API
package com.simon.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("/response1")
public class ServletResponseDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(404);
resp.setHeader("Content-Type","text/html");
resp.getWriter().println("<h1 style='color:red'>File Not Found</h1>");
//服务器接收参数和发送参数,都可设置编码格式;
//接收时,我设置请求报文的编码格式供我解析
//发送时,指定utf-8,但要告知给客户端,放在响应头/体,让客户端也以这个格式解析我
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().println("你好");
}
}
缺省Servlet
要求:在当前应用中实现缺省Servlet的功能,url-pattern必须是/,把这些文件正常显示出来;如果文件不存在,显示404。
package com.simon.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.File;
import java.io.FileInputStream;
import java.io.IOException;
@WebServlet("/")
public class ServletResponseDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//显示处缺省servlet的某一个文件,比如2.html
//ServletOutputStream:只需要将文件写入到response的缓冲区即可,tomcat会读取这个response里面
//的内容,然后生成响应报文
ServletOutputStream outputStream = resp.getOutputStream();
String realPath = getServletContext().getRealPath("WEB-INF/2.html");
FileInputStream inputStream = new FileInputStream(new File(realPath));
int length = 0;
byte[] bytes = new byte[1024];
while ((length = inputStream.read(bytes)) != -1){
outputStream.write(bytes,0,length);
}
inputStream.close();
////输出流可以关闭也可以不关闭,如果不关闭,tomcat会帮你关闭
outputStream.close();
}
}
重定向、刷新和转发
package com.simon.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("/redirect")
public class ServletResponseDemo4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.sendRedirect("url="+req.getContextPath()+"/1.html");
}
}
package com.simon.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.text.SimpleDateFormat;
import java.util.Date;
@WebServlet("/refresh")
public class ServletResponseDemo3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//refresh有2个作用:①定时刷新 ②页面跳转
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateFormat = simpleDateFormat.format(new Date());
//每2秒刷新一次
resp.getWriter().println(dateFormat);
resp.setHeader("refresh","2");
// resp.setHeader("refresh","3;url=https://www.baidu.com");
resp.setHeader("refresh","3;url="+req.getContextPath()+"/login.html");
}
}
package com.simon.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.Arrays;
import java.util.Enumeration;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
if ("zs".equals(username)&&"abc".equals(password)){
Enumeration<String> parameterNames = req.getParameterNames();
while (parameterNames.hasMoreElements()){
String parameterName = parameterNames.nextElement();
String[] parameterValues = req.getParameterValues(parameterName);
if (1 == parameterValues.length ){
System.out.println(parameterName + ":" + parameterValues[0]);
}else {
System.out.println(parameterName + ":" + Arrays.toString(parameterValues));
}
}
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().println("恭喜,登陆成功即将跳转....");
RequestDispatcher dispatcher = req.getRequestDispatcher("/success.html");
dispatcher.forward(req,resp);
}
}
}
三个页面跳转之间的区别
联系:都可以进行页面的跳转
区别:
1.状态码不同。重定向是302,转发、刷新都是200
2.能否共享request域。转发可以共享request域,其他两种是不可以的
3.响应头不一致。转发没有响应头;刷新是refresh响应头;重定向是Location响应头
4.请求次数不同。转发只发了一次请求,刷新、重定向都是多次
5.介导对象不同。转发是request介导的;刷新、重定向是response介导的
6.请求方法不同。转发前后请求方法不变(转发前是post请求,转发后还是post请求),但是对于刷新、重定向,后面会变成get请求。
7.跳转的范围不同。转发只可以在当前应用下调转,刷新、重定向是没有限制的
文件下载
package com.simon.download;
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 {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//将WEB-INF目录下的1.txt文件下载到本地硬盘上面,而不是直接打开该文件
String realPath = getServletContext().getRealPath("WEB-INF/1.txt");
FileInputStream inputStream = new FileInputStream(realPath);
//key code line
resp.setHeader("Content-Disposition","attachment;filename=1.txt");
ServletOutputStream outputStream = resp.getOutputStream();
int length = 0;
byte[] bytes = new byte[1024];
while ((length=inputStream.read(bytes)) != -1){
outputStream.write(bytes,0,length);
}
}
}
使用场景:做后台管理系统,会有导出的功能。
三种查看图片文件的方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/app/threeGirls.jpg">点我直接查看图片</a>
<a href="/app/pic/view">点我通过servlet查看图片</a>
<a href="/app/pic/download">点我下载图片</a>
<a href="/app/pic2?op=view2">点我通过servlet查看图片,改进版</a>
<a href="/app/pic2?op=download2">点我下载图片,改进版</a>
</body>
</html>
初级版
package com.simon.download;
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.FileNotFoundException;
import java.io.IOException;
@WebServlet("/pic/*")
public class ShowServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String requestURI = req.getRequestURI();
String action = requestURI.replace(req.getContextPath() + "/pic/", "");
if ("view".equals(action)){
show(req,resp);
}
if ("download".equals(action)){
resp.setHeader("Content-Disposition","attachment;filename=threeGirls.jpg");
show(req,resp);
}
}
private void show(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
String realPath = getServletContext().getRealPath("/threeGirls.jpg");
FileInputStream inputStream = new FileInputStream(realPath);
ServletOutputStream outputStream = resp.getOutputStream();
int length = 0;
byte[] bytes = new byte[1024];
while ((length = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, length);
}
}
}
改进版
package com.simon.download;
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("/pic2")
public class ShowServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// String requestURI = req.getRequestURI();
// String action = requestURI.replace(req.getContextPath() + "/pic/", "");
String action = req.getParameter("op");
if ("view2".equals(action)){
show(req,resp);
}
if ("download2".equals(action)){
resp.setHeader("Content-Disposition","attachment;filename=threeGirls.jpg");
show(req,resp);
}
}
private void show(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
String realPath = getServletContext().getRealPath("/threeGirls.jpg");
FileInputStream inputStream = new FileInputStream(realPath);
ServletOutputStream outputStream = resp.getOutputStream();
int length = 0;
byte[] bytes = new byte[1024];
while ((length = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, length);
}
}
}
文件上传
需求:将一个图片文件上传到web目录下的image目录的threeGirls.jpg文件去。
失败版
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/app/upload1" enctype="multipart/form-data" method="post">
<input type="file" name="image"><br>
<input type="submit">
</form>
</body>
</html>
package com.simon.upload;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@WebServlet("/upload1")
public class UploadServlet1 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//先拿到请求报文的输入流
ServletInputStream inputStream = req.getInputStream();
//放到服务器的某个地方,比如部署根目录的image/threeGirls.jpg
String realPath = getServletContext().getRealPath("/image/threeGirls.jpg");
File file = new File(realPath);
if (!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
FileOutputStream outputStream = new FileOutputStream(file);
byte[] bytes = new byte[1024];
int length = 0;
while ((length=inputStream.read(bytes)) != -1){
outputStream.write(bytes,0,length);
}
outputStream.close();
}
}
解决办法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/app/upload2" enctype="multipart/form-data" method="post">
<input type="file" name="image"><br>
<input type="text" name="username"><br>
<input type="password" name="password"><br>
<input type="submit">
</form>
</body>
</html>
package com.simon.upload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
//提交含文件的表单,上传到服务器
@WebServlet("/upload2")
public class UploadServlet2 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
List<FileItem> fileItems = null;
DiskFileItemFactory itemFactory = null;
FileItem item = null;
//确保request对象包含上传的文件
boolean isMultipart = ServletFileUpload.isMultipartContent(req);
if (!isMultipart) return;
//创建对应form表单key-value工厂,用以缓存临时文件
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletContext servletContext = getServletContext();
File repository = (File) servletContext
.getAttribute("javax.servlet.context.tempdir");
factory.setRepository(repository);
//将缓存区的文件提交给request以供后续对象来解析
ServletFileUpload upload = new ServletFileUpload(factory);
try {
fileItems = upload.parseRequest(req);
Iterator<FileItem> iterator = fileItems.iterator();
while (iterator.hasNext()){
item = iterator.next();
if (item.isFormField()){
processUploadedFile(item);
}else {
processFormField(item);
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
//根据form表单里key值是否为文件类型,分类解析
//最终将文件写入到硬盘的某个位置
String realPath = getServletContext().getRealPath("/image/OIP.jpg");
File file = new File(realPath);
}
private void processFormField(FileItem item) {
String name = item.getFieldName();
String value = item.getString();
System.out.println("name:" + name);
System.out.println("value:" + value);
}
private void processUploadedFile(FileItem item) {
String fieldName = item.getFieldName();
String fileName = item.getName();
String contentType = item.getContentType();
boolean isInMemory = item.isInMemory();
long sizeInBytes = item.getSize();
System.out.println("fieldName:" + fieldName);
System.out.println("fileName:" + fileName);
System.out.println("contentType:" + contentType);
System.out.println("isInMemory:" + isInMemory);
System.out.println("sizeBytes:" + sizeInBytes);
String image = getServletContext().getRealPath("image");
String realPath = image + "/" + fileName;
File file = new File(realPath);
try {
item.write(file);
} catch (Exception e) {
e.printStackTrace();
}
}
}
又失败了,嘤嘤嘤~~~~