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/request1String requestURI = request.getRequestURI();// http://localhost/app/request1 requestURL = 协议 + 主机端口号 + requestURIString 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 {@Overrideprotected 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 {@Overrideprotected 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 {@Overrideprotected 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 {@Overrideprotected 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 {@Overrideprotected 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 {@Overrideprotected 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 {@Overrideprotected 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 lineresp.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 {@Overrideprotected 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 {@Overrideprotected 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 {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {//先拿到请求报文的输入流ServletInputStream inputStream = req.getInputStream();//放到服务器的某个地方,比如部署根目录的image/threeGirls.jpgString 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 {@Overrideprotected 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();}}}



又失败了,嘤嘤嘤~~~~
