HttpServleResponse 接口

介绍

  1. HttpServletResponse接口来自于Servlet规范中,在Tomcat中存在 servlet-api.jar

  2. HttpServletResponse接口实现类由Http服务器负责提供

  3. HttpServletResponse接口主要负责 doGet/doPost 方法执行结果写入到【响应体】中交给浏览器

  4. 开发人员习惯将HttpServletResponse接口修饰的对象称为 响应对象

响应对象主要功能

  1. 将执行结果以二进制写入到【响应体】中

  2. 设置响应头中【content-type】属性值,控制浏览器使用对应的编译器,将响应体二进制数据编译为【文字、图片、视频、命令】

  3. 可以设置响应头的属性 【location】属性,将一个请求地址赋值给我们的location,从而控制浏览器向指定的服务器发送请求

通过doGet方法将响应结果写到响应体

问题1:

  1. String str = "Hello World"; //执行结果
  2. //将执行结果响应到浏览器当中, 响应对象将结果写到响应体
  3. // 通过响应对象(response)的getWrite()拿到输出流
  4. PrintWriter out = response.getWriter();
  5. //通过输出流的write() 把执行结果以二进制的形式写到响应体中
  6. out.write(str);
  7. out.write() // 在执行时,可以将 [字符] [字符串] [ascii] 写入到响应体中

综上所述说明了 如果 write() 收到一个数字 会把 数字转换成ascii写入到响应体中

解决方案 : 使用 out.print() 方法把数字写到响应体中(实际开发中常用)

问题2:

JAVA
MySQL
HTML? 问题描述 浏览器将响应的结果中的
也作为文字内容展示出来了 没有当作Html标签命令来执行

  • 问题原因:浏览器收到响应包之后,根据响应头的【content-type】属性的值,来采用对应的【编译器】 进行编译

  • 在默认的情况下。 content-type的值是“text” 【content-type = “text”】

  • 此时我们的浏览器会采用文本编译器对响应体中的二进制数据进行解析

解决方案
  • 一定要在得到输出流之前,通过响应对象对响应头的content-type 属性进行重新赋值,用于指定浏览器采用正确的编译器进行处理
  • response.setContentType(“text/html”); // 意思是告诉浏览器使用text 或者 html编译器

问题3:

“红烧排骨
梅菜肘子
糖醋里脊” 输出到浏览器中为 ??? ??? ???

原因是 :在浏览器解析中文的时候,要靠响应头中的 content-type中的charset值来解析

解决方案

response.setContentType(“text/html;charset=utf-8”);

或者response.setCharacterEncoding(“UTF-8”);

sendRedirect() 重定向

String str = “http://baidu.com“;

//通过响应对象将地址赋值给我们响应头中的location属性

response.sendRedirect(str);

// 现在的响应头里面 会出现一个location属性

//浏览器在接收到响应包之后,

// 如果发现响应头中存在location属性自动通过地址栏向location指定网站发送请求

使用sendRedirect() 方法可以远程控制浏览器的请求行为

http://baidu.com/?userName=mike (可以加上请求内容)


HttpServletRequest 接口

介绍

  1. HttpServletRequest接口,在Tomcat中存在 servlet-api.jar

  2. HttpServletRequest接口实现类由Http服务器提供

  3. HttpServletRequest接口负责在doGet/doPost() 在运行的时候读取Http请求协议包中的信息

  4. 开发人员习惯成他的对象为【请求对象】

作用:

  • 可以去读取http请求协议包中【请求行】信息

  • 可以读取保存在http请求协议包中【请求头】或者【请求体】中请求参数信息

  • 可以去代替浏览器向http服务器申请资源文件调用

request.getRequestURL() // 得到url

返回一个StringBuffer 所以toString()一下

String url = request.getRequestURL().toString();

request.getMethod() //得到Method

request.getRequestURI() // 得到URI

URI : 资源文件精准定位地址,在请求行并没有,实际上是从URL中截取的一个字符串

格式: /网站名/资源文件名

URI的作用: 让http服务器来对被访问的资源文件进行定位

通过请求对象 获取请求参数(请求头/请求体)

  1. Enumeration<String> s = request.getParameterNames(); // 蒋所有请求参数名称保存到一个枚举对象当中
  2. while(s.hasMoreElements()){
  3. //类似 迭代
  4. //1.得到参数名称 nextElement();
  5. String para = (String) s.nextElement();
  6. //2.通过请求对象的指定的参数的值获取到
  7. String result = request.getParameter(para); //把请求参数名放进去
  8. System.out.println("请求参数名称"+para+":"+result);
  9. }

post请求的内容在请求体里面,上面的方法仍然适用

请求体使用的是 iso-8859-1 编码 如果有中文 会乱码 所以先通知tomcat更换字符集 request.setCharsetEncoding(“utf-8”);

request.getParameter(“username”);

post请求乱码

问题:用get方式发送中文内容时得到正常结果,但是post得到的乱码 ?????????

原因:在tomcat9中get方法的使用utf-8进行解码 但是post使用的时ISO-8859-1进行解码(东欧语字符集)

解决方案
  • 在post请求下 在读取请求体之前,通知请求对象去使用utf-8字符集去给请求体中的内容进行重新的解码

  • post请求参数保存在请求体中,此时请求对象会对请求体解码【ISO-8859-1】所以会出现乱码

  • resquest.setCharacterEncoding(“utf-8”);

请求响应生命周期/辅助知识点

request和response生命周期(对象)

  1. 在http服务器接收到浏览器发送的请求协议包之后会自动为当前的请求协议包生成请求对象和响应对象

  2. 在http服务器调用doGet()/doPost()方法时,负责将【响应对象】和【请求对象】作为实参传递到方法中

  3. doGet()/doPost()方法执行结束表示本次请求处理完毕——>响应协议包里存在响应结果被推送到浏览器

  4. http服务器准备推送http相应协议包之前,tomcat负责销毁掉两个对象

  5. 【请求对象】【响应对象】生命周期贯穿一个请求的处理过程中

默认欢迎资源文件

  1. 用户可以记住网站名称,但是不会记住网站的资源文件名

  2. 这时就需要导航页面(欢迎页面)

  3. 当用户向http服务器发送请求,针对某个网站的【默认请求】时,此时由http服务器自动从当前网站返回的资源文件

对比

正常请求:http://localhost:8080/myWeb/index/html

默认请求: http://localhost:8080/myWeb/

tomcat对于默认欢迎资源文件定位规则

  1. Tomcat——>conf——>web.xml——>最下面
  2. <welcome-file-list>
  3. <welcome-file>index.html</welcome-file>
  4. <welcome-file>index.htm</welcome-file>
  5. <welcome-file>index.jsp</welcome-file>
  6. </welcome-file-list>

把想要当成默认的欢迎资源文件名 改成 index.html

或者 自行设置当前网站的默认欢迎资源文件

规则: 网站/web/WEB-INF/web.xml

在web.xml下面添加

  1. <welcome-file-list>
  2. <welcome-file>User_login.html</welcome-file>
  3. </welcome-file-list>

注意问题

  • 如果网站里面设置默认文件定位规则(欢迎界面),那么此时tomact默认的定位规则会失效
  • 也可以写动态资源文件,把class的别名复制过来。然后把开头的/ 去掉

多个Servlet之间调用规则

前提条件

  • 某些来自于浏览器发送的请求,往往需要服务端中多个Servlet协同处理。

  • 但是浏览器一次只能访问一个Servlet,导致用户需要多次发起请求,才能的到结果

  • 增加用户获取服务单独,导致用户放弃访问

提高用户使用感受规则

  • 无论本次请求设计到多个Servlet,用户只需要通知一次浏览器发起一次请求即可

多个Servlet之间调用规则

  • 重定向解决方案
  • 请求转发解决方案

重定向解决方案

工作原理

  1. 用户第一次通过手动的方式,通知浏览器访问 OneServlet,当OneServlet执行完毕后,将TwoServlet地址写道响应头中的 location属性中

  2. 导致tomcat将302的状态码,写入状态行中。

  3. 在浏览器接收到响应包之后,会读取到302状态。此时浏览器自动根据响应头的location属性地址发起第二次请求,访问TwoServlet去完成请求中的剩余任务

实现命令

response.sendRedirect(“请求地址”); // 将地址写入响应包中的响应头中location属性中

地址格式:/myWeb/two /网站名/资源文件名

特征

请求地址

请求次数

  • 浏览器至少发送两次请求,只有第一次请求是用户手动发送的,后续的都是浏览器自动发送的

请求方式

  • TwoServlet的请求方式是get

  • 重定向的解决方案中,通过地址栏通知浏览器发起下一次请求,所以是get

  • 通过重定向解决方案调用的资源文件接收的请求方式一定是get

缺点

  • 重定向结局方案需要在浏览器与服务器之间进行多次的往返,大量的时间消耗在往返的次数,增加用户等待服务时间

请求转发解决方案

工作原理

  1. 用户第一次通过手动方式请求浏览器访问OneServlet. OneServlet工作完毕后,通过当前的请求对象代替浏览器向Tomcat发送请求,申请调用TwoServlet
  2. Tomcat在接收这个请求之后,自动调用TwoServlet来完成剩余任务

实现命令

RequestDispatcher report = request.getRequestDispatcher(“/资源文件名称”); // 通过当前请求对象生成资源文件申请报告对象

一定要/ 开头

report.forward(当前请求对象,当前的响应对象) //将报告对象发送给Tomcat

优点

  • 无论本次请求涉及多少个servlet,用户只需要手动的发起一次请求
  • servlet之间的调用发生在服务端计算机中,节省了服务端和浏览器之间往返次数

特征

  • 请求次数

  • 在请求转发过程中,浏览器只发送了一次请求

  • 请求地址

  • 只能向tomcat服务器申请调用当前网络下资源文件地址(不要写网站名)

  • request.getRequestDispathcer(“/资源文件名”)

  • 请求方式

  • 与浏览器所发送的请求方式一致

数据共享

概述

OneServlet执行完毕后,将产生的数据交给TwoServlet使用

四种数据共享方案

  1. ServletContext 接口

  2. Cookie类

  3. HttpSession 接口

  4. HttpServletRequest接口

ServletContext接口

介绍

  • 来自于Servlet规范中的一个接口。在tomcat中存在 servlet-api.jar

  • 在tomcat中负责提供这个接口实现类

  • 如果两个Servlet来自同一个网站,那么他们彼此之间就可以通过ServletContext实例对象实现数据共享

  • 开发人员习惯叫他为【全局作用域对象】

工作原理

  • 每一个网站里面都存在一个全局作用域对象

  • 全局作用域对象 【相当于】 map集合【键值对】可看作为一个公共的留言板

  • 在这个网站中 ,OneServlet可以将一个数据存入到全局作用域对象,当前网站中其他的Servlet都可以从这个全局作用域对象中得到这个数据

生命周期

  • 在Http服务器启动的过程中,自动为当前网站在内存中创建一个全局作用域对象

自动创建 就单独一个

  • 在http服务器运行下 全局作用域对象存活状态 | http服务器关闭,全局作用域销毁。

【贯穿当前网站整个运行期间】

命令实现

同一个网站 OneServlet将数据共享给TwoServlet

  1. public class OneServlet extends HttpServlet {
  2. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  3. //1.通过请求对象向Tomcat索要当前网站中的【全局作用域对象】
  4. ServletContext application = request.getServletContext();
  5. //2.将数据添加到全局作用域当中 作为共享数据
  6. application.setAttribute("key1","Hello World");
  7. }
  8. }

在TwoServlet里面访问 已经保存好的key1对应的值

  1. public class TwoServlet extends HttpServlet {
  2. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  3. //得到全局作用域对象
  4. ServletContext application = request.getServletContext();
  5. //得到指定关键字的指定数据 返回一个Object类型的数据
  6. Object s = application.getAttribute("key1");
  7. //强转
  8. String ss = (String) s;
  9. //输出到控制台
  10. System.out.println(ss);
  11. }
  12. }

全局作用域对象的变量名 建议叫 application

application.removeAttribute(“key1”) // 通过key 删除对应key1的共享数据

Cookie

介绍

  • 来自Servlet规范的一个工具类。 存在tomcat提供的servlet-api.jar

  • 如果两个Servlet来自于同一个网站,并且为同一个浏览器/用户提供服务时,此时借助于Cookie对象进行数据共享

  • Cookie里面存放当前用户的私人数据,在共享数据过程中提高服务质量

  • Cookie 相当于会员卡

原理

  • 用户通过浏览器第一次向myWeb 网站发送请求申明OneServlet

  • OneServlet在运行期间创建了一个Cookie存储当前用户相关数据

  • OneServlet工作完毕后,【将Cookie写入到响应头】交还给当前浏览器

  • 浏览器收到响应包之后,将Cookie存储到浏览器的缓存中

  • 一段时间之后,用户通过【同一个浏览器】再次向【myWeb网站】发送请求申请TwoServlet时。

  • 【浏览器需要无条件的将myWeb网站之前推送过来的Cookie,写入到请求头中】发送过去

  • 此时TwoServlet在运行时,就可以通过读取请求头中的Cookie中的信息,得到OneServlet提供的共享数据

实现命令

同一个网站中 OneServlet和TwoServlet借助Cookie来实现数据的共享方案

在OnewServlet中创建一个Cookie

  1. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  2. //1.创建Cookie对象,保存共享数据(当前用户数据)
  3. Cookie cookie = new Cookie("key","HelloWorld");
  4. //cookie 实际上也是一个map
  5. //一个cookie对象只能放一个键值对
  6. //这个键值对的key和value只能是String(key不能是中文)
  7. //2.把卡交给用户【把cookie写入到响应头中,交给浏览器】
  8. response.addCookie(cookie);
  9. }

TwoServlet中访问Cookie

  1. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  2. //调用请求对象,从请求头中得到浏览器返回的Cookie
  3. //将请求头中的所有cookie封装成一个数组进行返回
  4. Cookie[] cookies = request.getCookies();
  5. //循环遍历数组,得到每一个key和value
  6. for (Cookie c : cookies){
  7. String key = c.getName(); // 读取的是key
  8. String value = c.getValue(); // 读取的是value
  9. System.out.println(key);
  10. System.out.println(value);
  11. }
  12. }

Cookie生命周期

Cookie销毁时机

  • 默认的情况下,Cookie存放在浏览器的缓存中

  • 只要浏览器关闭,缓存清除,Cookie被销毁

  • 在手动设置情况下,可以要求浏览器将接收的Cookie存放在客户端计算机上的硬盘上同时需要去指定Cookie在硬盘上的存活时间。在存活时间范围内,关闭服务器,关闭浏览器,都不会导致Cookie销毁。 存活时间到达Cookie被自动销毁

cookie.setMaxAge(60); //表示当前的cookie对象 在硬盘上存活1分钟【秒】

HttpSession接口

介绍

  • 来自于Servlet规范下一个接口,存在于Tomcat中servlet-api.jar

  • 其实现类又http服务器提供

  • 如果两个Servlet来自于同一个网站,并且为同一个浏览器/用户提供服务时,此时借助于HttpSession对象进行数据共享

  • 开发人员称被HttpSession接口修饰的对象为 【会话作用域对象】

HttpSession和Cookie的区别

  • 存储位置不同

  • Cookie:存放在客户端的计算机中【浏览器缓存或者硬盘】

  • HttpSession:存放在服务端计算机内存中

  • 数据类型不同:

  • Cookie:存储的共享数据只能是String

  • HttpSession对象可以存储任意类型的共享数据

  • 数据的数量

  • 一个Cookie 只能存储一个共享数据

  • HttpSession 使用map集合共享数据,可以存储任意数量的数据

  • 参照物不同

  • Cookie相当于服务端的会员卡

  • HttpSession 相当于客户在服务端的私人保险柜【大,多】

命令实现

同一个网站下,OneServlet将数据传递给TwoServlet

OneServlet中写入共享数据

  1. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  2. //1.调用请求对象向Tomcat索要当前用户在服务端的私人储物柜
  3. //返回一个HttpSession对象 程序员们习惯叫他为session
  4. HttpSession session = request.getSession();
  5. //2. 将数据 添加到用户私人储物柜中
  6. session.setAttribute("key1","Hello World");
  7. }

TwoServlet 中读取共享数据

  1. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  2. // 访问共享数据
  3. //1.通过请求对象向Tomcat索要用户的私人储物柜
  4. HttpSession session = request.getSession();
  5. //2.从会话作用域对象中,得到OneServlet提供的共享数据(通过key得到value)
  6. //返回一个Object类型的数据
  7. String value = (String)session.getAttribute("key1");
  8. System.out.println(value);
  9. }

Http服务器如何将用户和HttpSession关联起来的呢

  • 当用户点击了加入购物车后,服务端执行到OneServlet里面的代码了

  • 会看有没有Session 如果没有就会新建一个,并且创建一个Cookie并且返回给浏览器【JSESSIONID = 12452..】

  • 当用户第二次访问的时候 ,请求头里面有一个Cookie 服务端接收到之后,有了ID就开对了箱子 【类似于浴池的手牌】

getSession(); 和getSession(false); 的区别【有参无参】

首先都是索要全局对话作用域对象

getSession();

  • //如果当前用户在服务端中,已经拥有了私人储物柜

  • 那么则要求tomcat返回这个私人储物柜

  • 如果当前用户尚未拥有自己的私人储物柜,那么Tomcat就会创建一个全新的私人储物柜

  • 在哪些地方出现: 登陆验证(就这一个地方)【用户身份合法 创建一个Session】

  1. **getSession(false)**
  • //如果当前用户在服务端中,已经拥有了私人储物柜

  • 那么则要求tomcat返回这个私人储物柜

  • 如果当前用户端在服务端中没有自己的私人储物柜,

  • 那么tomcat就会返回一个null

  • 在哪里出现: 其余的资源文件中 都用有参 因为不知道是不是恶意登录

什么时候用有参/无参

  • 当前用户事合法登录的【通过登陆验证】 用无参
  • 当前用户身份尚未确认【翻墙】 用有参

生命周期

  • 用户和HttpSesion关联使用的Cookie只能存放在浏览器的缓存中

  • 在浏览器关闭的时候 意味着用户与HttpSession的关系被切断

  • 由于Tomcat无法去监测浏览器何时关闭,因此在浏览器关闭时并不会导致Tomcat将浏览器中的Cookie和HttpSession进行销毁

  • 为了解决问题,tomcat会为每一个HttpSession对象设置一个空闲时间【开始——现在】 默认30分钟, 当前Session对象达到30分钟,Tomcat认为用户放弃了自己的Session 此时就会销毁

HttpSession空闲时间的手动设置

当前网站下 / web / WEB-INF/web.xml

  1. <session-config>
  2. <!-- 表示当前网站中对大的空闲时间为5分钟,5分后自动销毁-->
  3. <session-timeout>5<session-timeout>
  4. </session-config>

HttpServletRequest接口实现数据共享

介绍

  • 如果在同一个网站中两个Servlet之间通过请求转发的方式来进行调用,此时彼此之间将共享同一个请求协议包。而一个请求协议包只对应一个请求对象/响应对象因此servlet之间共享同一个请求对象,此时就可以利用请求对象在两个Servelt之间实现数据共享

  • 请求对象可以存放数据【有存放数据的属性 Attribute属性】,响应对象不可以存放数据,所以就可以用请求对象来实现共享

  • 在请求对象实现Servlet之间数据共享的功能的时候,开发人员将请求对象叫【请求作用域对象】

实现命令

OneServlet通过请求转发申请调用TwoServelt的时候,需要给TwoServlet提供共享数据

在OneServlet中写入共享数据

  1. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  2. // 1.将数据添加到【请求作用域对象】中的Attribute属性
  3. // value的类型可以是任何类型【map集合 key value】
  4. request.setAttribute("key1","HelloWorld");
  5. //2.向Tomcat申请调用TwoServlet,并别发给tomcat【请求对象,响应对象】
  6. request.getRequestDispatcher("/two").forward(request,response);
  7. }

在TwoSerlet中读取共享数据

  1. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  2. //1.因为是请求转发,所以TwoServlet使用的请求对象/响应对象和OneServlet使用的是一个
  3. //从当前请求对象中得到OneServlet所写入的共享数据
  4. String s = (String) request.getAttribute("key1");
  5. System.out.println(s);
  6. }

监听器

介绍

  • 一组来自于Servlet规范中的接口【有8个接口】

  • 存在于Tomcat中Servlet-api.jar

  • 监听器的接口要求开发人员亲自实现,【jar包中并没有对应的实现类】

  • 监听器接口用于监控【作用域对象生命周期变化时刻】和【作用域对象共享数据变化时刻】

  • 一般网站中监听器接口实现类 都在 listener 包下

什么叫做作用域对象

  1. 在Servlet规范中,认为在服务端内存中可以在某些条件下为两个Servlet进行数据共享的对象,被称为作用域对象

  2. ServletContext 全局作用域对象

  3. HttpSession 会话作用域对象

  4. HttpServletRequest 请求作用域对象

监听器接口实现类开发规范

  1. 根据监听的实际情况,选择对应的监听器接口进行实现

  2. 重写监听器接口中声明的【监听事件处理方法】

  3. 在web.xml文件中将监听器接口实现类注册到Http服务器中

  1. <!--将监听器接口实现类注册到Tomcat-->
  2. <listener>
  3. <!--在里面写上接口实现类的路径-->
  4. <listener-class>com.yixuexi.listener.OneListener</listener-class>
  5. </listener>

ServletContextListener接口

作用:

通过这个接口可以合法的检测全局作用域对象被初始化时刻和被销毁时刻

两个方法

  1. public class listener implements ServletContextListener {
  2. @Override
  3. public void contextInitialized(ServletContextEvent sce) {
  4. //此方法在全局作用域对象被Http服务器创建的时候调用
  5. }
  6. @Override
  7. public void contextDestroyed(ServletContextEvent sce) {
  8. //此方法在全局作用域对象被Http服务器销毁的时候调用
  9. }
  10. }
  • 因为全局作用域对象是Tomcat服务器负责声明/销毁

  • 所以在服务器打开的时候同时也声明了全局作用域对象所以执行 init..

  • 服务器关闭的时候同时销毁全局作用域对象执行des..

ServletContext application = sce.getServletContext(); // 得到全局作用域对象

ServletContextAttributeListener接口

通过这个接口合法的检测全局作用域对象共享数据变化时刻

三个方法

  1. public class OneListener implements ServletContextAttributeListener {
  2. @Override
  3. public void attributeAdded(ServletContextAttributeEvent scae) {
  4. //在全局作用域对象添加共享数据的时候被触发
  5. }
  6. @Override
  7. public void attributeRemoved(ServletContextAttributeEvent scae) {
  8. //在全局作用域对象删除共享数据的时候被触发
  9. }
  10. @Override
  11. public void attributeReplaced(ServletContextAttributeEvent scae) {
  12. //在全局作用域对象更新共享数据的时候被触发
  13. }
  14. }

全局作用域对象的变化时刻

  • ServletContext application = request.getServletContext(); //得到全局作用域对象

  • application.setAttribute(“key1”,100); // 新增共享数据

  • application.setAttribute(“key1”,200); // 更新 key1从100变200

  • application.removeAttribute(“key1”) // 通过key 删除对应的共享数据

过滤器

介绍

  • 来自Servlet规范下的接口 在Tomcat存在 Servlet-api.jar包中

  • Filter接口实现类由开发人员负责提供,Http服务器不负责提供

  • Filter接口在Http服务器调用资源文件之前,对Http服务器进行拦截

  • 开发过滤器接口实现类放到filter包下

具体作用

  • 拦截Http服务器帮助Http服务器检测当前请求的合法性
  • 拦截Http服务器,对当前请求进行增强操作

Filter接口实现类开发步骤

  1. 创建一个Java类,实现Filter接口 (选择javax.servlet包下的Filter接口)

  2. 重写Filter接口中的doFilter方法

  3. 在web.xml中将过滤器接口实现类注册得到Http服务器上

  1. <!--将过滤器类文件的路径交给Tomcat-->
  2. <filter>
  3. <!--变量名 里面存储了Filter的文件路径-->
  4. <filter-name>oneFilter</filter-name>
  5. <!--里面填写Filter的文件路径-->
  6. <filter-class>com.yixuexi.Filter</filter-class>
  7. </filter>
  8. <!-- 通知tomcat在调用那个资源文件时,需要被当前的过滤器拦截-->
  9. <filter-mapping>
  10. <!--告诉这个oneFilter过滤器-->
  11. <filter-name>oneFilter</filter-name>
  12. <!--在调用mm.jpg 文件的时候 要进行过滤操作-->
  13. <url-pattern>/mm.jpg</url-pattern>
  14. </filter-mapping>

具体实现

  1. public class OneFilter implements Filter{
  2. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  3. //filterChain对象负责 在判断合法的情况下把请求对象 和响应对象交还给Tomcat 【称为放行】
  4. //1.通过拦截的请求对象,得到请求包中的请求信息,从而得到用户真事年龄【访问该网站需要>18】
  5. String age = servletRequest.getParameter("age");
  6. //2. 根据年龄,帮助Http服务器判断
  7. if (Integer.valueOf(age) < 18){
  8. //如果小于18岁,则代替服务器 拒绝本次访问,【响应对象的响应体中有数据的话(tomcat会认为这次[请求+响应结束])】
  9. servletResponse.setContentType("text/html;charset=utf-8");
  10. PrintWriter out = servletResponse.getWriter();
  11. out.print("<center><font style='color:red;font-size:0pt; color:#6a8759;">本次作业为满18岁禁止访问</font></center>");
  12. }else{
  13. // 如果大于等于18的话就可以访问了
  14. // 将拦截的请求对象和响应对象交换给tomcat filterChain.doFilter() 交还给Tomcat
  15. filterChain.doFilter(servletRequest,servletResponse);
  16. }
  17. }

以上是验证请求的合法性

  • 如果有100百个Servlet实现类 (post请求) 那么在这100个实现类都需要对其进行servletRequest.setCharacterEncoding(“utf-8”); 此时就可以通过过滤器为其进行增强操作
  • /*

filter过滤器拦截地址格式(web.xml)

命令格式

  1. <filter-mapping>
  2. <!--告诉这个oneFilter过滤器-->
  3. <filter-name>oneFilter</filter-name>
  4. <!--在调用拦截地址文件的时候 要进行过滤操作-->
  5. <url-pattern>/拦截地址</url-pattern>
  6. </filter-mapping>

命令作用

拦截地址通知Tomcat在调用何种文件的时候之前需要调用OneFilter过滤及进行拦截

拦截命令的几种写法

  • 要求Tomcat在调用某一个具体文件之前,来调用OneFilter拦截

/img/mm.jpg

  • 要求Tomcat在调用某一个文件夹下所有的资源文件之前,来调用OneFilter拦截

    /文件夹/*

  • 要求Tomcat在调用任意一个文件夹下的某种类型文件之前,都要用OneFilter过滤

**.jpg

不管是哪里的图片 访问时 都会被拦截

不加 /

  • 要求Tomcat在调用网站中任意文件时,都要调用OneFilter来拦截

/*

防止用户恶意登录

问题:用户避开登陆验证, 直接通过地址栏访问内部资源文件,被称为恶意登录

令牌机制

用户通过login.html登录成功后 会配发一块令牌,在调用后续的资源文件时,动态资源文件会首先判断有没有session

令牌 == 信物 (Session 私人储物柜)

在登录验证的时候给用户创建一个Session 使用无参创建

在用户调用动态资源文件的时候,使用 HttpSession session = request.getSession(false); 如果返回的是null 就说明用户没有使用登陆验证,属于恶意登录

缺点:

  1. 增加开发难度,一个每个Servlet都要写 HttpSession session = request.getSession(false);
  2. 不能对静态文件进行保护(只能保护动态文件【class文件】)

使用过滤器解决 令牌机制的缺点

通知Tomcat在调用任意文件之前都要先调用过滤器

/*

  1. doFilter()方法中 向拦截的请求索要他的HttpSession
  2. //父接口中没有 getSession()方法 向下转型 转成 HttpServletRequest
  3. HttpServletRequest request = (HttpServletRequest)servletRequest;
  4. HttpServletResponse response = (HttpServletResponse) servletResponse;
  5. HttpSession session = req.getSession(false);
  6. if(session == null){
  7. //拒绝服务 response.sendRedirect()
  8. }else{
  9. // 有令牌 放行
  10. filterChain.doFilter(req,resp);
  11. }

出现的问题

全部的文件都被过滤器拦截了

解决方案

放行登录页面 和登录验证

  1. //父接口中没有 getSession()方法 向下转型 转成 HttpServletRequest
  2. HttpServletRequest request = (HttpServletRequest)servletRequest;
  3. // 得到uri 判断里面包含不包含 login 如果包含就放行
  4. String uri = request.getRequestURI();
  5. // 返回当前字符串中 在该字符串中第一次出现的位置 如果没有出现 返回-1
  6. // 或者是默认访问 默认访问的uri为 /myWeb/ 也需要放行
  7. if(uri.indexOf("login") != -1 || "/myWeb/".equals(uri)){
  8. // 放行
  9. filterChain.doFilter(servletRequest,servletResponse);
  10. return;
  11. }
  12. //如果本次的请求访问的是其他的文件需要得到令牌
  13. HttpSession session = request.getSession(false);
  14. //如果session不是null 说明用户通过了登录验证
  15. if (session != null) {
  16. //放行
  17. filterChain.doFilter(servletRequest,servletResponse);
  18. return;
  19. }
  20. //程序能执行到这里说明没有柜子【令牌】 输于恶意登录 请求转发
  21. request.getRequestDispatcher("/User_login_error.html").forward(servletRequest,servletResponse);

JSP

为什么学习JSP?

  • 响应对象只适合将较少的数据量写入到响应体中,如果Html代码多,用jsp
  • 在servlet接口实现类中 写的HTML代码特别多【冗余】就可以用jsp代替响应对象将处理结果写入到响应体中

什么是JSP规范

  • JSP来自JAVAEE规范中的一种

  • JSP制定了如何开发jsp文件代替响应对象将输出结果写入响应体中的开发流程

  • JSP规范制定了Http服务器应该如何管理调用这些JSP文件

JSP特点

  • JSP文件在执行中,自动将文件所有内容写入到响应体中,从而节省了书写 out.print();
  • 只能将存在于 当前网站下的 web文件夹下

如果在jsp中书写java命令

在jsp文件中,只有书写在执行标记中内容才会被当作java命令

<%

int i = 10 ;

int j = 20;

……..

%>

  • 可以声明java变量

  • 运算表达式 【数学运算】【关系运算】【逻辑运算】

  • 控制语句

将java命令的运行结果输出到浏览器

输出执行标记 <%= 变量名 %>

可以写运算表达式

输出控制语句

<%

for (int i = 0; i <= 100; i++){

%>

i = <%= i %>
//
在三不管的地方写

<%

}

%>

JSP内置对象

request(请求对象)

1.读取请求包中的

信息 http://localhost:8080/myWeb/index2.jsp?username=zhangsan&password=123456

<%

String username = request.getParameter(“username”);

String password = request.getParameter(“password”);

//System.out.println(username + “:” + password);

%>

来访用户姓名:<%= username %>

来访用户密码:<%= password %>

session

不需要再进行 request.getSession() 自带的 直接用 即可 【session】

application

直接application.setAttribute(); 添加属性

Servlet和jsp实现分工操作

Servlet和JSP的分工

Servlet:处理业务,并得到处理结果

【饭店的大厨】

JSP:不负责业务的处理,主要任务将Servlet中处理的结果写入到响应体中

【饭店中的传菜员】

Servket和JSP之间的调用关系

在Servlet工作完毕后,一般是通过请求转发的方式,向tomcat申请调用JSP

Servlet和JSP之间如何实现数据共享

我们的Servlet将处理结果去添加到请求作用域对象中,jsp文件在运行的时候,从请求作用域对象中得到处理结果

面试题

Http服务器调用JSP文件步骤?

  1. Http服务器首先将JSP文件内容【编辑】为一个Servlet接口实现类 .java

  2. Http服务器将Servlet接口实现类【编译】为一个class文件 .class

  3. Http服务器负责创建这个class的实例对象,【Servlet对象】

  4. Http服务器通过Servlet实例对象调用一个_jspService方法来将jsp文件上的内容写入到响应体中

Http服务器【编辑】和【编译】JSP文件的位置

  • C:\Users\【登录windows系统的角色名称】.IntelliJIdea2019.2\system\tomcat\Tomcat_9_0_35_01Servlet_19\work\Catalina\localhost\myWeb\org\apache\jsp
  • 标准答案:我在work文件夹下看到了jsp文件被编译成了Servlet

EL表达式

概述

什么是EL工具包

  1. 由JAVA开发的一个jar包

  2. 作用是降低JSP文件开发时java命令的难度

  3. Tomcat服务器本身自带了EL工具包(lib/el-api.jar)

JSP的作用

  • 代替响应的对象,将doGet/doPost的执行结果写入到响应体中【输出】

传统JSP开发步骤

  • 从【全局/请求/会话】作用域中拿到key对应的value

  • 强转成自己需要的类型的数据

  • 输出到页面上 <%= %>

EL简化JSP的开发步骤

  • 值:${requestScope.key1}

  • 值:${applicationScope.key1}

  • 值:${sessionScope.key1}

命令格式

${ 作用域对象别名.key}

key不需要引起来

命令作用

  • EL表达式是EL工具包提供一种特殊命令格式【表达式命令格式】

  • EL表达式在JSP文件上来使用

  • 负责在JSP文件上面从作用域对象中读取指定的共享数据,并写到响应体中

EL表达式中作用域的别名

JSP文件可以使用的作用域对象

  1. ServletContext application : 全局作用域对象

  2. HttpSession session : 会话作用域对象

  3. HttpServletRequest request : 请求作用域对象

  4. 【只能在JSP出现的作用域对象】PageContext pageContext : 当前页作用域对象

JSP中独有的 Servlet中不存在。

在当前页作用域对象中存放的数据 仅能在当前jsp页面中使用

不能共享给其他Servlet和JSP文件

主要开发中主要用于 JSTL标签和JSP文件之间数据共享给

EL表达式提供作用域对象别名

  • ${applicationScope.共享数据名} 全局作用域对象别名

  • ${sessionScope.共享数据名} 会话作用域对象别名

  • ${requestScope.共享数据名} 请求作用域对象别名

  • ${pageScope.共享数据名} 当前页作用域对象别名

EL表达式将引用对象属性写入响应体

  • 格式:${作用域对象别名.key.属性名}

  • 作用:从作用域对象中读取指定共享数据所关联的引用对象的属性值

  • 并自动写入到响应体中

  • 属性名:一定要与引用类型属性名完全一致 包括大小写 【私有属性也可以直接调用。】

EL表达式中没有提供遍历集合的方法,因此无法从作用域中的集合中得到元素

JSTL技术有效的弥补EL不能遍历集合输出的问题

EL表达式简化版(常用)

命令格式

${共享数据名}

少了作用域对象别名

命令作用

EL表达式允许在开发的时候省略作用域对象别名

工作原理

  1. 由于EL简化版没有指定作用域对象,所以在执行的时候 用的【猜的算法】

  2. 首先到【pageContext】定位共享数据,如果存在那么就直接读取结束执行

  3. 如果没有就去下一个 【request】 ——>【session】 ———【application】

  4. 如果都没有 就返回一个null

存在隐患

  • 降低程序执行的速度【南辕北辙】
  • 容易导致数据定位错误

应用场景

  • 设计目的:简化从当前页作用域对象【pageContext】中读取共享数据并输出的难度
  • EL简化版尽管存在了很多隐患 但是在实际开发过程中,开发人员为了节省时间 都是用简化版,而不是用标准版

EL支持的运算表达式

前提

  • 在JSP文件有时需要将读取共享数据进行一番运算之后,将运算结果写入到响应体中
  • 允许将key对应的value做数学运算 【不用考虑类型转换,String自动转换成Integer 】

都支持那些运算

  • 数学运算 + - ……….

  • 关系运算 > < != …….

  • 三目运算符 ? :

  • 逻辑运算 && || !

  • EL表达式支持的内置对象

命令格式 : ${param.请求参数名}

  • 作用:通过请求对象读取当前请求包中的请求参数内容,并将请求参数的内容写入到响应体【通过key得到value 】(得到来访者的姓名/密码….)

命令格式:${paramValues.请求参数名称[下标]}

  • 如果浏览器发送的请求参数是一个请求参数是一个请求参数关联多个值

  • Http://localhost:8080/myWeb/index_2.jsp?pageNo=1&pageNo=2&pageNo=3

  • 就有一个值 在请求包中 以数组的形式存在 下标从0开始

  • 此时可以通过paramValues.* 来读取请求参数下指定位置的值,并且写入响应体

${initParam.value}

在web.xml中编写下面代码表示在tomcat启动的时候写到全局作用域对象中去
value

Hello World
用initParam.value就可以读取 到 hello world

EL表达式 常见异常

javax.el.PropertyNotFoundException // 在对象中没有找到指定的属性

EL表达式 缺陷问题

  1. 执行读取作用域对象数据,不能向作用域中写入数据和更改数据

  2. 不支持控制语句 if while …….

  3. 如果单独使用EL表达式,无法确保JSP文件中所有的JAVA命令都被替换

  4. 实际开发中 jsp文件中不能出现任何一条java命令【规矩】

相对路径和绝对路径的区别

  • 相对路径:以当前文件的位置为起点,定位其他的资源文件

    同一层

    上一层

  • 绝对路径:以网站的根目录为起点,定位其他的资源文件

[ JSTL标签工具类

介绍

JSTL = JSP Standrad(标准) tag(标签) lib jsp中标准的标签工具类库

出现的原因

  • 在JSP文件中不能出现java命令【以持续10多年(风气)】

  • 为了不出现java命令,就出现了JSTL 【披着html的java命令】

  • 由sun公司提供

组成

  • 核心标签【java在jsp基本功能进行封装 if while】

  • sql标签 【JDBC在jsp上使用功能】

  • xml标签【DOM4J在JSP使用功能】

  • Format标签【JSP文件格式转换】

配置

  • 导入依赖的jar:jstl.jar standrad.jar

  • 先把jar包赋值到WEB-INF 下面新建一个lib文件夹 放到里面

  • 在file ——->Project Structure ——->Modules——-> 选中需要导包的项目 ———>Dependencies ——-> 右边加号添加jar包

  • 在jsp文件引入JSTL中core包依赖约束

  • <%@ taglib uri=”http://java.sun.com/jsp/jstl/core“ prefix=”c” %>

标签的使用介绍

:

作用:在jsp文件上设置作用域对象的共享数据

使用:

代替:<%

session.setAttribute(“key”,”10”);

%>

其中的属性含义:

scope 范围 指定当前要操作的作用域对象

var 声明域对象中的关键字 也就是key

value 存入的共享数据

EL表达式和JSTL联合使用

${requestScope.age}

作用 在JSP文件上控制那些内容可以写入到响应体中

内容

作用:在jsp文件上实现多分支选择判断,决定哪一个内容写入响应体

内容

……..

内容

一个c:when 相当于一个else if

c:otherwise相当于else 都不执行 他执行

第一种使用方案

var 定义一个变量i 开始值为1 结束值为5[<=] step:以一递增[可省略]

会自动的把i 放到当前页作用域对象中 ${pageScope.i}

第二种使用方案

遍历list和set集合

${stu.age}

items表示遍历那个集合,用el表达式来得到

stu表示的是 Student stu

遍历Map集合

告诉要遍历那个集合,声明一个循环变量

循环变量里面保存了键值对 【key_Value.key得到key】【key_Value.value得到value】 【key_Value.value.id】 得到value中的id

](/myWeb/jsp/one.jsp)