Servlet学习笔记5——线程安全、转发与重定向

news/2024/5/18 12:26:46 标签: cookie, session

文章目录

  • 关于程序中出现的乱码问题以及解决方案
    • 1、乱码可能出现在哪里?
    • 2、数据“展示”过程中的乱码
    • 3、数据“保存”过程中的乱码
    • 4、数据“传递”过程中的乱码
    • 5、建议:
  • 关于Servlet的线程安全问题
    • 1、Servlet在什么环境下运行?
    • 2、什么情况下程序会存在线程安全问题?
    • 3、对于多线程来说,JVM内存中哪些内存空间是共享的,哪些内存空间是独立的?
    • 4、怎么解决线程安全问题呢?
    • Servlet线程安全问题及解决方案 (Servlet单实例多线程)
    • 小结
  • 转发与重定向的区别(资源跳转)
    • 什么是一次请求:
    • 1、web系统中资源跳转,怎么做?
    • 2、转发
    • 3、重定向
    • 4、转发和重定向的区别
    • 5、什么时候使用转发?什么时候使用重定向?

关于程序中出现的乱码问题以及解决方案

1、乱码可能出现在哪里?

	1) 数据“传递”过程中的乱码
	2) 数据“展示”过程中的乱码
	3) 数据“保存”过程中的乱码

2、数据“展示”过程中的乱码

	1) 在response获取标准输出流之后,使用标准输出流输出到浏览器上中文的时候,出现的乱码
	2) 怎么解决?

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

3、数据“保存”过程中的乱码

1) 数据最终保存到数据库的时候,表中存储的数据出现乱码问题
2) 数据库表中存储的数据出现乱码,为什么?

可能是在保存之前就已经出现乱码,保存到数据库表中的数据一定是乱码,保存之前数据没有出现乱码,但是数据库本身不支持简体中文,也可能出现乱码
3) 怎么解决?

  • 若保存之前就是乱码,和数据库没有关系,先解决保存之前的乱码问题
  • 让数据库本身支持简体中文

4、数据“传递”过程中的乱码

  1. 浏览器提交数据给服务器,在传送的过程中出现中文乱码问题
  2. 为什么在传递过程中会出现乱码呢?

浏览器在提交表单数据的时候,不管这个语言是哪个国家的语言,不管这个文字是哪个国家的文字,都是采用ISO-8859-1的这种编码方式提交数据的。

换句话说,在网络中传送的数据包中涉及到文字的话,该文字一定是ISO-8859-1的编码方式

发送给Tomcat服务器之后,Tomcat服务器接收到数据,只是接收到一堆ISO-8859-1编码方式的数据,不知道该数据以前是哪个国家的文字

浏览器是这样提交数据的:username=%E5%BC%A0%E4%B8%89

%E5%BC%A0%E4%B8%89是ISO-8859-1的编码方式编码之后的数据,以前是什么,不知道!!!
3) 解决方案:
第一种方案:万能方案,适合于所有的请求,包括GET请求和POST请求

将从request对象中获取到的数据,经过ISO-8859-1的编码方式进行解码还原,回归最原始的二进制码

再找一种编码方式,这种编码方式和浏览器页面的编码方式相同,进行重新编码
第二种方案:只能解决POST请求中的乱码问题

request.setCharacterEncoding(“UTF-8”);

以上代码在从request对象中获取任何数据之前设置有效果

以上的代码只对请求体中的数据进行编码,无法对请求行上的数据进行编码,所以只能解决POST,不能解决GET
第三种方案:只能解决GET请求中的乱码问题

修改CATALINA_HOME/conf/server.xml文件

<Connector port="80" protocol="HTTP/1.1"
    connectionTimeout="20000"
    redirectPort="8443"
   URIEncoding="UTF-8"/>

server.xml文件中的Connector标签中可以编写什么属性呢?

参考:C:\tomcat7\webapps\docs\config\http.html

port 设置端口号

URIEncoding 设置URI的编码方式

maxThreads 设置Tomcat服务器可支持的最大线程数量

5、建议:

为了避免乱码的出现,建议整个工程中凡是涉及到编码方式的,最好所有的编码方式统一。

数据库的编码方式、HTML页面的编码方式、java程序中使用的编码方式、myeclipse工作区的编码方式…都采用UTF-8

关于Servlet的线程安全问题

1、Servlet在什么环境下运行?

Servlet在“单实例”多线程的环境下运行。

某种类型的Servlet对象在容器中只有一个。

2、什么情况下程序会存在线程安全问题?

多线程环境

有共享数据

共享数据涉及到修改操作

3、对于多线程来说,JVM内存中哪些内存空间是共享的,哪些内存空间是独立的?

方法区和堆区内存共享

栈内存独立,一个线程一个栈

局部变量内存不共享,所以局部变量不存在线程安全问题

静态变量和实例变量,静态变量在方法区中,实例变量堆内存的java对象内部,静态变量和实例变量存在线程安全问题

4、怎么解决线程安全问题呢?

第一种方案:尽量使用局部变量代替实例变量
第二种方案:若必须使用实例变量,那么可以考虑,让对象变成多例,不再是单例。
第三种方案:若必须使用实例变量,必须是单例的,这个时候必须使用线程同步机制:synchronized

注意:使用线程同步机制,是不得以的时候再使用,因为这种方式会让程序的吞吐量降低,用户排队访问,用户体验差。

Servlet线程安全问题及解决方案 (Servlet单实例多线程)

Servlet体系结构是建立在Java多线程机制之上的,它的生命周期是由Web容器负责的。当客户端第一次请求某个Servlet时,Servlet容器将
会根据web.xml配置文件实例化这个Servlet类。当有新的客户端请求该Servlet时,一般不会再实例化该Servlet类,也就是有多个线程在使
用这个实例。这样的话,当两个或多个线程同时访问同一个Servlet时,可能会发生多个线程同时访问同一资源的情况,数据可能会变得不
一致,所以就很容易造成一系列的一些安全性问题。为了保证数据的安全性可以采用下列方式:
同步对共享数据的操作
使用synchronized 关键字能保证一次只有一个线程可以访问被保护的区段,同步后的代码如下:
public class XXXServlet extends HttpServlet {
…………
synchronized (this){XXXX}

}

避免使用实例变量、静态变量
线程安全问题还有些是由实例变量、静态变量造成的,只要在Servlet里面的任何方法里面都不使用实例变量、静态变量,那么该Servlet就是线程安全的。
对上面的两种种方法进行测试,可以表明用它们都能设计出线程安全的Servlet程序。但是在程序中使用同步来保护要使用的共享的数据,会使系统的性能大大下降。这是因为被同步的代码块在同一时刻只能有一个线程执行它,使得其同时处理客户请求的吞吐量降低,而且很多客户处于阻塞状态。另外为保证主存内容和线程的工作内存中的数据的一致性,要频繁地刷新缓存,这也会大大地影响系统的性能。所以在实际的开发中也应避免或最小化Servlet 中的同步代码;在Serlet中避免使用实例变量是保证Servlet线程安全的最佳选择。从Java 内存模型也可以知道,方法中的临时变量是在栈上分配空间,而且每个线程都有自己私有的栈空间,所以它们不会影响线程的安全。

小结

Servlet的线程安全问题只有在大量的并发访问时才会显现出来,并且很难发现,因此在编写Servlet程序时要特别注意。线程安全问题主要
是由实例变量造成的,因此在Servlet中应避免使用实例变量。如果应用程序设计无法避免使用实例变量,那么使用同步来保护要使用的实
例变量,但为保证系统的最佳性能,应该同步可用性最小的代码路径。

转发与重定向的区别(资源跳转)

在这里插入图片描述

代码上的实现:


转发:request.getRequestDispatcher(/servletPath”).forward(request,response); 

重定向:response.sendRedirect(/webcontextPath/servletPath”);

注意资源路径:

在转发中不需要编写web应用的根路径名称。
但是在重定向的时候需要编写web应用的根路径名称,假设web应用的根路径名称PrjStudyServlet,该web应用的根下有a资源,如果是转发则路径写 /a,如果是重定向则 /PrjStudyServlet/a
  • forward方法只能将请求转发给同一个WEB应用中的资源(这个资源可能是Servlet、JSP、HTML等),而HttpServletResponse.sendRedirect 方法不仅可以重定向到当前应用程序中的其他资源,还可以重定向到另一个WEB应用中的资源

  • 调用HttpServletResponse.sendRedirect方法重定向的访问过程结束后,浏览器地址栏中显示的URL会发生改变,由初始的URL地址变成重定向的目标URL;而调用RequestDispatcher.forward 方法的请求转发过程结束后,浏览器地址栏保持初始的URL地址不变。

  • HttpServletResponse.sendRedirect方法对浏览器的请求直接作出响应,响应的结果就是告诉浏览器去重新发出对另外一个URL的 访问请求,这个过程好比有个绰号叫“浏览器”的人写信找张三借钱,张三回信说没有钱,让“浏览器”去找李四借,并将李四现在的通信地址告诉给了“浏览器”。于是,“浏览器”又按张三提供通信地址给李四写信借钱,李四收到信后就把钱汇给了“浏览器”。可见,“浏览器”一共发出了两封信和收到了两次回复, “浏览器”也知道他借到的钱出自李四之手。

  • RequestDispatcher.forward方法在服务器端内部将请求转发给另外一个资源,浏览器只知道发出了请求并得到了响应结果,并不知道在服务器程序内部发生了转发行为。这个过程好比绰号叫“浏览器”的人写信找张三借钱,张三没有钱,于是张三找李四借了一些钱,甚至还可以加上自己的一些钱,然后再将这些钱汇给了“浏览器”。可见,“浏览器”只发 出了一封信和收到了一次回复,他只知道从张三那里借到了钱,并不知道有一部分钱出自李四之手。

  • RequestDispatcher.forward方法的调用者与被调用者之间共享相同的request对象和response对象,它们属于同一个访问请求和响应过程;

  • 而HttpServletResponse.sendRedirect方法调用者与被调用者使用各自的request对象和response对象,它们属于两个独立的访问请求和响应过程。对于同一个WEB应用程序的内部资源之间的跳转,特别是跳转之前要对请求进行一些前期预处理,并要使用HttpServletRequest.setAttribute方法传递预处理结果,那就应该使用RequestDispatcher.forward方法。不同WEB应用程序之间的重定向,特别是要重定向到另外一个WEB站点上的资源的情况,都应该使用HttpServletResponse.sendRedirect方法。

无论是转发还是重定向,转发和重定向后面不能再有转发和重定向相关的代码。
(转发和重定向在同一个Servlet中只能有一次。)

怎么选择是重定向还是转发呢?
通常情况下转发更快,而且能保持request内的对象,所以他是第一选择。但是由于在转发之后,浏览器中URL仍然指向开始页面,此时如果重载当前页面,开始页面将会被重新调用。

如果你不想看到这样的情况,则选择转发(页面刷新问题)。 不要仅仅为了把变量传到下一个页面而使用session作用域,那会无故增大变量的作用域,转发也许可以帮助你解决这个问题。

重定向:以前的request中存放的变量全部失效,并进入一个新的request作用域。  
转发:以前的request中存放的变量不会失效,就像把两个页面拼到了一起。

什么是一次请求:

浏览器向服务器发送请求到服务器响应结束为一次请求。
但是重定向发送了两次请求,服务器响应了两次。

1、	如果是web应用之间资源的跳转,必须使用重定向。
2、	为了解决页面的刷新问题,必须使用重定向。
3、	如果在Servlet中向request对象中存储了一个数据,希望在下一个Servlet/JSP页面中把request对象中的数据取出来,这个时候必须使用转发,因为重定向是两次请求,request不能跨请求传递数据。其它情况都可以是用重定向。

1、web系统中资源跳转,怎么做?

需要使用转发机制(forward)和重定向机制(redirect)完成资源跳转

注意:跳转的下一个资源不一定是一个Servlet,下一个资源可能是:JSP、Servlet、html…

2、转发

代码怎么写:
request.getRequestDispatcher("/b").forward(request,response);

  • 转发是一次请求
  • 转发是request对象触发的
  • 用户点击超链接:http://localhost/prj-servlet-16/a,浏览器地址栏上最终显示的地址也是:http://localhost/prj-servlet-16/a
  • 转发的资源路径中不需要添加contextPath
  • 转发只能完成项目内部资源的跳转

3、重定向

- 代码怎么写:
	response.sendRedirect("/prj-servlet-16/b");
- 重定向是两次请求
- 重定向是response对象触发的
- 用户点击超链接:http://localhost/prj-servlet-16/a,
浏览器地址栏上最终显示的地址是:http://localhost/prj-servlet-16/b
- 重定向的资源路径需要添加contextPath
- 重定向可以完成跨项目资源跳转

4、转发和重定向的区别

5、什么时候使用转发?什么时候使用重定向?

若跨项目跳转只能用重定向

大部分情况下,重定向使用较多

在上一个程序中向request范围中存储了数据,希望能从下一个程序中将request范围中的数据取出,必须使用转发

重定向可以解决页面刷新问题(F5)

6、这个描述不正确
在浏览器上用户点击超链接,到最终网页停下来,是一次请求。这个描述已经不正确了。
因为这个过程中可能发生重定向操作。


http://www.niftyadmin.cn/n/1617368.html

相关文章

远程服务器nohup后台训练网络,再也不用怕由于断网而间断训练

使用服务器进行远程训练 由于经常需要使用服务器进行训练&#xff0c;且有些模型训练起来需要很长的时间&#xff0c;故经常需要长期跑程序。 由于我使用的是ssh登录&#xff0c;因此断网或者退出账号时程序就会被kill。总结了以下常用的远程训练指令&#xff0c;帮你可以不间…

Servlet学习笔记6——cookie与session

文章目录Cookie概述Cookie是什么? Cookie作用? Cookie保存在哪里?Cookie只有在javaweb中有吗?Cookie实现的功能&#xff0c;常见的有哪些?在java中Cookie被当做类来处理&#xff0c;使用new运算符可以创建Cookie对象,而且Cookie由两部分组成&#xff0c;在java程序中怎么创…

Leetcode—— 20. 有效的括号

20. 最长公共前缀 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 ""。 示例 1: 输入: ["flower","flow","flight"] 输出: "fl" 示例 2: 输入: ["dog","…

Leetcode—— 26. 删除排序数组中的重复项

26. 删除排序数组中的重复项 给定一个排序数组&#xff0c;你需要在原地删除重复出现的元素&#xff0c;使得每个元素只出现一次&#xff0c;返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 示…

MyBatis常用方法学习笔记

文章目录如何使用Mapper.xml参数传递级联查询ORMapping: Object Relationship Mapping 对象关系映射对象指面向对象关系指关系型数据库Java 到 MySQL 的映射&#xff0c;开发者可以以⾯面向对象的思想来管理理数据库。如何使用 通过 Mapper 代理理实现自定义接口,定义相关业务…

Leetcode—— 27.移除元素

27.移除元素 给定一个数组 nums 和一个值 val&#xff0c;你需要原地移除所有数值等于 val 的元素&#xff0c;返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 元素的顺序可以改变。你不需要考…

Leetcode—— 35. 搜索插入位置

35. 搜索插入位置 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 你可以假设数组中无重复元素。 示例 1: 输入: [1,3,5,6], 5 输出: 2 示例 2: 输入: [1,3,…

Leetcode—— 28.实现strStr()

28.实现strStr&#xff08;&#xff09; 实现 strStr() 函数。 给定一个 haystack 字符串和一个 needle 字符串&#xff0c;在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在&#xff0c;则返回 -1。 示例 1: 输入: haystack "hello&…