用户通过浏览器访问服务器时,Tomcat将HTTP请求中所有的信息封装在Request对象中 作用:开发人员可以通过request对象方法,来获取浏览器发送的所有信息 Request体系结构:
ServletRequest | HttpServletRequest | org.apache.catalina.connector.RequestFacade(由tomcat厂商提供实现类)在JavaEE中我们是面向接口编程:
例如:GET /day09_request/requestDemo1 HTTP/1.1 相关API
获取请求方式:GET String getMethod()获取项目虚拟路径(项目名):/day09_request String getContextPath()获取URI:/day09_request/requestDemo1 统一资源定位符(确定某一个地址) StringBuffer getRequestURI()获取URL http://localhost:8080/day09_request/requestDemo1 统一资源定位符(确定某一个地址) 中华人民共和国 StringBuffer getRequestURL()获取协议和版本号 HTTP/1.1 String getProtocol()获取客户端ip String getRemoteAddr()例如: Host: localhost:8080
相关API:
获取知道请求头名称对应的值,注:名称不区分大小写 String getHeader(String name)
获取所有请求头的名称 Enumeration getHeaderNames() 注:是Iterator前身
referer:请求来源
/* 视频防盗链 */ @WebServlet("/refererRequest") public class RefererRequest extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); // 1.获取请求来源(如果是浏览器地址直接访问的话,referer就是null) String referer = req.getHeader("referer"); // 2.判断是不是自家网站发起的请求 if (referer != null && referer.startsWith("http://localhost:8080")) { resp.getWriter().write("正常播放视频..."); }else{ resp.getWriter().write("想看吗?来优酷吧...."); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } }现在后端处理兼容性问题的需求越来越少,基本都是前端工程师完成的 user-agen:浏览器版本信息
/* 浏览器兼容性 */ @WebServlet("/userAgentReqeust") public class UserAgentReqeust extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=utf-8"); // 1.获取浏览器版本信息 String userAgent = req.getHeader("user-agent"); // 2.判断浏览器版本 if (userAgent.contains("Chrome")) { resp.getWriter().write("浏览器:谷歌"); } else if (userAgent.contains("Firefox")) { resp.getWriter().write("浏览器:火狐"); } else { resp.getWriter().write("浏览器:其他"); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } }参数 username=jack&password=123&hobby=drink&hobby=perm
API
获取指定参数名的值 username=jack String getParameter(String name)
获取指定参数名的值数组 hobby=drink&hobby=perm String[] getParameterValues(String name)
获取所有参数名和对应值数组,参数名 name(key),值数组 value,封装map集合 Map<String,String[]> getParameterMap()
中文乱码【重点】 get:在tomcat8及以上版本,内部URL编码(UTF-8) post:编码解码不一致,造成乱码现象 客户端(浏览器)编码:UTF-8 服务器默认 解码:ISO-8859-1 拉丁文 指定解码:void setCharacterEncoding(String env) 注:这哥们必须在方法内,行首
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>form</title> </head> <body> <h3>get方式:</h3> <form action="/day09_request/requestDemo3" method="get"> 用户:<input type="text" name="username"> <br> 密码:<input type="password" name="password"> <br> 爱好: <input type="checkbox" name="hobby" value="somke"/>抽烟 <input type="checkbox" name="hobby" value="drink"/>喝酒 <input type="checkbox" name="hobby" value="perm"/>烫头 <input type="submit" value="get提交..."> </form> <h3>post方式:</h3> <form action="/day09_request/requestDemo3" method="post"> 用户:<input type="text" name="username"> <br> 密码:<input type="password" name="password"> <br> 爱好: <input type="checkbox" name="hobby" value="somke"/>抽烟 <input type="checkbox" name="hobby" value="drink"/>喝酒 <input type="checkbox" name="hobby" value="perm"/>烫头 <input type="submit" value="post提交..."> </form> </body> </html> @WebServlet("/requestDemo3") public class RequestDemo3 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("手动获取---------"); String username = req.getParameter("username"); System.out.println("用户:" + username); String password = req.getParameter("password"); System.out.println("密码:" + password); String[] hobby = req.getParameterValues("hobby"); System.out.println("爱好:" + Arrays.toString(hobby)); System.out.println("自动获取---------"); Map<String, String[]> parameterMap = req.getParameterMap(); parameterMap.forEach((k, v) -> { System.out.println(k + " = " + Arrays.toString(v)); }); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 指定post的解码方式.... req.setCharacterEncoding("UTF-8"); System.out.println("post提交方法,再去调用get...."); this.doGet(req, resp); // 让get小老弟干活... } }一种在服务器内部的资源跳转方式
API
通过reqeust对象,获得转发器对象 RequestDispatcher getRequestDispatcher(String path)
通过转发器对象,实现转发功能 void forward(ServletRequest request, ServletResponse response)
请求转发特点 浏览器:发了一次请求 地址栏:没有发生改变 只能转发到服务器内部资源…
链式编程 request.getRequestDispatcher("/bServlet").forward(reqeust,response)
API
设置数据 void setAttribute(String name, Object o)
获取数据 Object getAttribute(String name)
删除数据 void removeAttribute(String name)
生命周期
何时创建? 用户发送请求时,创建request
何时销毁 服务器返回响应是,销毁request
作用范围? 一次请求,包含多次转发
@WebServlet("/aServlet") public class AServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("aServlet处理功能上...."); // 转发到BServlet /* // 1.获得转发器对象 path = @WebServlet("/bServlet") RequestDispatcher requestDispatcher = request.getRequestDispatcher("/bServlet"); // 2.实现转发功能 requestDispatcher.forward(request, response);*/ // 存一个数据 request.setAttribute("hanbao", "香辣鸡腿堡"); // 链式编程横 request.getRequestDispatcher("bServlet").forward(request, response); } } @WebServlet("/bServlet") public class BServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("bServlet处理功能下...."); // 获取数据 String hanbao = (String) request.getAttribute("hanbao"); System.out.println("hanbao:" + hanbao); } }中文直译:应用上下文对象,表示一个web项目 通过reuqest,可以获得ServletContext对象
public ServletContext getServletContext();需求 实现用户的登录功能 登录成功跳转到SuccessServlet展示:登录成功!xxx,欢迎您 登录失败跳转到FailServlet展示:登录失败,用户名或密码错误 需求分析
创建web项目 导入BeanUtils工具类 编写index.html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>index</title> </head> <body> <h4>用户登录</h4> <form action="/day09_login/loginServlet" method="post"> 用户:<input type="text" name="username"> <br> 密码:<input type="password" name="password"> <br> <input type="submit" value="登录"> </form> </body> </html> User实体类 // 用户对象 public class User { private String username;// 用户名 private String password;// 密码 public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } LoginServlet @WebServlet("/loginServlet") public class LoginServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1.设置request解码方式 request.setCharacterEncoding("UTF-8"); // 2.获取浏览器请求参数,map集合 Map<String, String[]> parameterMap = request.getParameterMap(); // 3.使用BeanUtils工具类,封装user对象中 User user = new User(); try { BeanUtils.populate(user, parameterMap); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } // 4.判断(课下作业,你们写一个file文件,存储真实用户名和密码 判断) if("jack".equals(user.getUsername())&&"123".equals(user.getPassword())){ // 正确 request.setAttribute("user", user); request.getRequestDispatcher("/successServlet").forward(request,response); }else{ // 错误 request.getRequestDispatcher("/failServlet").forward(request,response); } } } SuccessServlet @WebServlet("/successServlet") public class SuccessServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1.从request域获取user对象 User user = (User) request.getAttribute("user"); // 2.友情提示 response.setContentType("text/html;charset=utf-8"); response.getWriter().write(user.getUsername() + ",登录成功"); } } FailServlet @WebServlet("/failServlet") public class FailServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1.友情提示 response.setContentType("text/html;charset=utf-8"); response.getWriter().write("用户名或密码错误.."); } }Web容器(tomcat)在启动时,他会为每个web项目承建一个对应的ServletContext对象 它代表当前Web项目 主要作用:
域对象(共享数据)获取资源在服务器的真实地址获取全局的配置参数获取文件MIME类型在当前项目范围中,共享数据(多个servlet都可以获取)
存储数据: void setAttribute(String name,Object value)获取数据: Object getAttribute(String name)删除数据: void removeAttribute(String name)OneServlet
@WebServlet("/OneServlet") public class OneServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 向servletContext域存数据.... ServletContext sc1 = request.getServletContext(); ServletContext sc2 = getServletContext(); sc1.setAttribute("user", "jack"); System.out.println("OneServlet存了数据。。。"); } }TwoServlet
@WebServlet("/TwoServlet") public class TwoServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 从servletContext域获取数据 String user = (String) request.getServletContext().getAttribute("user"); System.out.println("TwoServlet获取数据:"+user); } }可以实现web项目的移植性,动态获取文件真实路径 API: String getRealPath(String path);
@WebServlet("/RealpathServlet") public class RealpathServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取car.jpg 文件真实路径 String carPath = request.getServletContext().getRealPath("/img/car.jpg"); System.out.println(carPath); // 获取web.xml 文件真实路径 String webPath = request.getServletContext().getRealPath("/WEB-INF/web.xml"); System.out.println(webPath); } }读取web.xml配置文件中标签信息,实现参数和代码的解耦(多个servlet都可以获取) web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <!--全局配置参数:所有的servlet都可以读取...--> <context-param> <param-name>encode</param-name> <param-value>UTF-8</param-value> </context-param> </web-app>ContextPathServlet
@WebServlet("/ContextPathServlet") public class ContextPathServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取全局参数 String value = request.getServletContext().getInitParameter("encode"); System.out.println("全局配置参数:"+value); } }在互联网通信过程中定义的一种文件数据类型 格式:大类型/小类型例如:text/html image/jpeg`
<a href="/day10_servletContext/MimeServlet?filename=luola.avi">获取文件的mime类型</a><br> @WebServlet("/MimeServlet") public class MimeServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取指定文件的mime类型 // 获取请求参数 String filename = request.getParameter("filename"); // 获取文件的mime类型 String mimeType = request.getServletContext().getMimeType(filename); response.getWriter().write(filename + "---" + mimeType); } }需求: 一般个人博客的首页,都会显示你是第几位访问此网站…
@WebServlet(value = "/CountServlet", loadOnStartup = 4) // 服务器启动时,创建此servlet对象 public class CountServlet extends HttpServlet { @Override public void init() throws ServletException { getServletContext().setAttribute("count", 0); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置response响应编码 response.setContentType("text/html;charset=utf-8"); response.getWriter().write("<h1>itcast博客网站</h1>"); // 用户每次访问,从域中取出,加1,再存进去 ServletContext servletContext = request.getServletContext(); // 从域中取出 Integer count = (Integer) servletContext.getAttribute("count"); // 加1 count++; // 再存进去 servletContext.setAttribute("count", count); response.getWriter().write("<div>你是,第" + count + "位访问此网站...</div>"); } }response对象表示web服务器给浏览器返回的响应信息 作用:开发人员可以使用response对象的方法,设置要返回给浏览器的响应信息
需求: 用户访问AServlet后,服务器告诉浏览器重定向到BServlet
哪个对象 转发(request对象的方法) request.getRequestDispatcher("/bServlet").forward(request,response); 重定向(response对象的方法) response.sendRedirect("/day10_response/bServlet");
几次请求 转发 地址栏: 没有改变 浏览器: 发了一次请求 服务器: 只有一对请求和响应对象 发生的位置: 服务器 重定向 地址栏: 发生了改变 浏览器: 发了两次请求 服务器: 有两对请求和响应对象 发生的位置: 浏览器
小结 写法 转发("/servlet资源路径") 服务器内部行为 重定向 ("/虚拟路径(项目名)/servlet资源路径") 浏览器外部行为 使用场景(重点掌握) 如果需要传递数据(request域),使用转发 如果不需要传递数据(request域),使用重定向
需求:在当前页面停留3秒钟之后,跳转到传智播客首页
需求:向页面输出中文数据没有乱码
需求:在页面展示登录验证码,点击辞严证码可以更换新的验证码 作用:防止表单的恶意提交 本质上:就是一张随机图片 如何通过java代码制作一个验证码
/* 跟我一起了解一下验证码的制作代码.... */ @WebServlet("/CheckcodeServlet") public class CheckcodeServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 创建画布 int width = 120; int height = 40; BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // 获得画笔 Graphics g = bufferedImage.getGraphics(); // 填充背景颜色 g.setColor(Color.white); g.fillRect(0, 0, width, height); // 绘制边框 g.setColor(Color.red); g.drawRect(0, 0, width - 1, height - 1); // 生成随机字符 // 准备数据 String data = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"; // 准备随机对象 Random r = new Random(); // 声明一个变量 保存验证码 String code = ""; // 书写4个随机字符 for (int i = 0; i < 4; i++) { // 设置字体 g.setFont(new Font("宋体", Font.BOLD, 28)); // 设置随机颜色 g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255))); String str = data.charAt(r.nextInt(data.length())) + ""; g.drawString(str, 10 + i * 28, 30); // 将新的字符 保存到验证码中 code = code + str; } // 绘制干扰线 for (int i = 0; i < 6; i++) { // 设置随机颜色 g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255))); g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height)); } // 将验证码 打印到控制台 System.out.println(code); // 将验证码放到session中 request.getSession().setAttribute("code_session", code); // 将画布显示在浏览器中 ImageIO.write(bufferedImage, "jpg", response.getOutputStream()); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } <img src="/day10_response/CheckcodeServlet" alt="servlet随机验证码" id="img1"> <br> <script> // 给图片绑定一个点击事件 document.getElementById('img1').onclick=function () { // 重置src路径,重写发送请求 this.src='/day10_response/CheckcodeServlet?'+new Date().getTime(); // 后面加一个毫秒值的时间戳,欺骗浏览器 } </script>需求:用户点击页面的链接,浏览器开始下载文件。
将需要下载的素材复制到web项目中 编写下载页面 <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>donload.html</title> </head> <body> <h3>文件下载</h3> <h5>超链接下载</h5> <a href="/day10_response/download/demo.docx">word文档</a><br> <a href="/day10_response/download/car.jpg">图片下载</a><br> <a href="/day10_response/download/test.zip">压缩包下载</a><br> <h5>servlet下载</h5> </body> </html>缺点:
浏览器可识别的媒体类型,是直接打开而不是下载不能判断用户是否登录,进行限制使用Servlet下载文件 两个响应头两个字节流
被下载文件的字节输入流 FileInputStreamresponse字节输出流 ServletOutputStream告知客户端下载文件的MIME类型(最新的浏览器此步骤可以省略…) Content-Type:MIME类型告知浏览器以附件的方式保存 Content-Disposition:attachment;filename=文件名 attachment 附件 filename=文件名 .download.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>donload.html</title> </head> <body> <h3>文件下载</h3> <h5>超链接下载</h5> <a href="/day10_response/download/demo.docx">word文档</a><br> <a href="/day10_response/download/car.jpg">图片下载</a><br> <a href="/day10_response/download/test.zip">压缩包下载</a><br> <h5>servlet下载</h5> <a href="/day10_response/DownLoadServlet?filename=demo.docx">word文档</a><br> <a href="/day10_response/DownLoadServlet?filename=girl.jpg">靓女</a><br> <a href="/day10_response/DownLoadServlet?filename=禽兽.jpg">禽兽</a><br> </body> </html> DownLoadServlet @WebServlet("/DownLoadServlet") public class DownLoadServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1.获取请求文件名 String filename = request.getParameter("filename"); // 2.获取文件真实路径,封装到字节输入流 ServletContext servletContext = request.getServletContext(); String realPath = servletContext.getRealPath("/download/" + filename); FileInputStream in = new FileInputStream(realPath); // 3.告诉浏览器mime类型 String mimeType = servletContext.getMimeType(filename); response.setContentType(mimeType); // 4.告诉浏览器以附件方式保存 // 解决中文乱码和浏览器兼容性 String userAgent = request.getHeader("user-agent"); // 调用工具类处理 filename = DownLoadUtils.getName(userAgent, filename); response.setHeader("content-disposition", "attachment;filename=" + filename); // 5.获取字节输出流 ServletOutputStream out = response.getOutputStream(); // 6.io流的拷贝 byte[] b = new byte[4096];// 4kb int len = -1; while((len = in.read(b))!=-1){ out.write(b, 0, len); } // 7.释放资源 out.close(); // out流对象,可以交给tomcat关闭 in.close(); } } 中文乱码如果该下载文件名是中文的话,会出现乱码… 谷歌和绝大多数的浏览器是通过 url编码 URLEncode() 编码 URLDecode() 解码 火狐浏览器 base64编码
我们就需要考虑浏览器兼容性问题… 今天帅哥提供了判断浏览器不同编码的工具类直接使用即可…
hutool工具包 这哥们封装了se阶段的很多基础操作…官网:https://www.hutool.cn/