Servlet线程安全,请求的转发和重定向:

Servlet线程安全:
Servlet的service方法,每次被请求时,调用.
这个调用很特殊,是在新的子线程中调用的,当service方法执行完毕,子线程死亡了.
可以简单理解为: service方法每次执行都是一个新的线程

代码锁:

synchronized(o){
    //代码线程锁
}

多个代码块 尽量不要用同一个锁!!!

请求的转发:

概念: 一个web组件 将未处理完毕的请求,通过tomcat转交给另一个web组件处理

步骤:

  1. 获取请求转发器
RequestDispatcher rd = request.getRequestDispatcher("转发的地址");
  1. 通过转发器发起转发
rd.forward(request,response);

简写步骤:

request.getRequestDispatcher("转发的地址").forward(request,response);

转发流程:
步骤1. 当浏览器访问服务器中tomcat时
步骤2. tomcat将请求信息,与响应工具进行封装,传递给我们的Servlet的service方法进行处理
步骤3. 我们在service方法中 得到请求转发器, 通过请求转发器 告知tomcat,请求转发的地址
步骤4. tomcat接收到请求转发需求,会重新封装请求信息,将请求对象 与 响应对象传递给转发地址的Servlet的service方法进行处理

特点:

  1. 转发过程中,多个Servlet之间共享一份请求信息,共享一个响应对象.
  2. 转发只能发生在同一个服务器中.(转发无法实现跨域)
  3. 无论转发发生多少次,对于浏览器来说,只能发起过一次请求,并且只接到了一次响应.
  4. 相对于重定向来说,效率更高

请求的重定向:
概念: 响应时,告知浏览器的新的请求地址,浏览器接受到 自动请求显得地址!

步骤:

response.sendRedirect("重定向地址");

重定向流程:
步骤1. 当浏览器访问服务时,服务器对浏览器响应一个302的状态码,以及一个location的地址
步骤2. HTTP协议约定,当浏览器接收到302状态码时,会自动寻找location地址,并发起新的请求.(相当于 控制用户浏览器 自动完成页面的跳转操作.)

特点:

  1. 重定向会产生新的请求 和 新的响应.
  2. 使用重定向,可以多个服务器之间发生(可以实现跨域操作)
  3. 浏览器地址栏的内容,会发生改变
  4. 相对于请求转发而言,效率较低

注意:
在一次用户的操作中,可以无限制的进行转发和重定向,但是记住: 一定要存在出口

HttpServletRequest 类常用操作:

  1. 获取访问的客户端ip地址
    String ip = request.getRemoteAddr();
    
  2. 获取客户端访问的地址(有可能因为服务器映射了多个域名,多个用户的访问地址 不同)
    request.getRequestURI();
    
  3. 获取服务器的名称 (通常获取的是ip)
    request.getServerName();
    
  4. 获取端口号
    request.getServerPort();
    
  5. 获取请求的方式
    String method = request.getMethod();
    
  6. 获取get请求的参数(网址中 ? 后面的部分)
    String params = request.getQueryString();
    

三个将请求对象 作为数据容器特殊的方式:

  1. 存储数据
    request.setAttribute(String key,Object value);
    
  2. 获取数据
    Object value = request.getAttribute(String key);
    
  3. 删除数据
    request.removeAttribute(String key);
    

ServletContext 上下文:

每一个Servlet都是一个独立的用于处理请求的对象
为了便于多个Servlet之间的数据交流,JavaWeb提供了一个上下文对象ServletContext
我们在任何的Servlet代码中,都可以获得这个ServletContext对象,且每一个Servlet获取的都是同一份ServletContext对象.
上下文对象,类似于我们SE所学习的MAP集合,是一个键值对的容器.

作用: ServletContext是Servlet之间通信的桥梁,用于多个Servlet之间信息的共享.

从Servlet中得到上下文对象:

格式:

    ServletContext context = getServletContext();  

ServletContext的常用方法:

  1. 存储数据
    context.setAttribute(String key,Object value);
    
  2. 获取数据
    Object value = context.getAttribute(String key);
    
  3. 删除数据
    context.removeAttribute(String key);
    
  4. 获取项目运行时的 文件夹绝对路径

//因为一个项目,只有一个ServletContext对象,且在项目启动时创建了,项目销毁时销毁.
//所以我们再一次项目启动的过程中,一个Servlet存储的数据,任何Servlet都可以获取到

会话跟踪(状态管理):
HTTP协议是无状态的, 我们的服务器在与客户端进行交互时,没有记忆.
两种方式来实现状态管理:

  1. Cookie技术: 将状态, 存储到客户端中
  2. Session技术: 将id存储在客户端中, 将状态存储在服务器中

Cookie技术:
技术实现步骤以及原理:

  1. 当服务器向客户端响应时 ,可以响应头部加入Cookie, 每一个Cookie表示一个键值对.
  2. 浏览器在接收到响应后,如果存在Cookie,则会将Cookie存储在文本文件中(.txt)
    存储时,会存储的信息有: 服务器的域,路径,Cookie键,Cookie的值,存储时长...
  3. 当浏览器向客户端请求时,会遍历Cookie的文本文件,将匹配新请求地址的Cookie携带上,放在请求头部,发送给服务器.
    Cookie匹配的规则:
    当cookie存储的域相同时,路径匹配时,才会将Cookie发送给服务器.

如何创建Cookie:
Cookie在Java中的体现,就是一个表示键值对的Java类,类名为:Cookie.
格式:

Cookie cookie = new Cookie(String name,String value);

如何将Cookie添加到响应头部:
通过响应对象,将Cookie添加到响应头部
格式:

response.addCookie(Cookie cookie);

一次响应,可以添加n个cookie
如果浏览器中已经存储过与某个Cookie的那么相同的Cookie, 再次存储时会覆盖value
如何从请求头部 得到之前存储的所有Cookie:
因为一个域 和路径下,可能存在多个Cookie,所以获取的不是单个Cookie,而是数组:

Cookie[] cookies = request.getCookies();
//如果从未存储过,则返回的数组值是null

得到Cookie后,如何取出其中的键和值:
获取Cookie的键:

String name = cookie.getName();

获取Cookie的值:

String value  cookie.getValue();

如何调整Cookie存储时长:
cookie.getMaxAge(int 秒):
传入值:

  • 负数 : 默认 -1 ,表示浏览会话结束时删除
  • 正数 : 存活的秒数, 例如60*60*24*365*10表示十年
  • 0 : 经常用于覆盖一个cookie时使用, 作用为0秒后删除(立即删除)

Cookie存储时,路径问题的解决:

路径匹配的规则:

  • Cookie的替换: 只能由相同域,相同路径的完成替换.
  • Cookie的获取: 只能由相同域,相同路径或子路径获取

例如:
A地址: localhost/x/a.do
B地址: localhost/x/b.do
C地址: localhost/c.do

A存储数据时: a/b可以获取, a/b可以替换 . c不能获取也不能替换
C存储数据时: a/b/c可以获取 , c可以替换

Cookie的路径问题,经常影响我们的开发

JavaWeb给我们提供了一个cookie方法,用于设置Cookie的路径
通常我们会将cookie的路径设置为/(根目录)
格式:

cookie.setPath("/"); 

Cookie的优缺点:
缺点:

  1. Cookie存储的数据类型,只能是字符串
  2. 数据存储的大小,有限制,最大为4kb
  3. 数据存储在用户的计算机上, 不安全
  4. 受限于用户的浏览器设置,当浏览器禁止使用Cookie时,cookie就无法再存储了

优点:
数据存储在客户端, 分散了服务器的压力