个人java学习路线-HttpServletRequest接口,乱码,线程安全问题,转发和重定向,Cookie和Session

HttpServletRequest接口

简单介绍

HttpServletRequest是Servlet规范中的重要接口之一
HttpServletRequest 继承了 ServletRequest()
HttpServletRequest接口的实现类是WEB容器负责实现的,Tomcat服务器有自己的实现。
我们无需关心具体的实现,我们只需要面向HttpServletRequest接口调用方法即可。

HttpServletRequest这个对象封装了哪些信息呢?

封装了HTTP请求协议的全部内容:
- 请求方式
- URI
- 协议版本号
- 表单提交的数据
....

HttpServletRequest一般变量名叫做:request,表示请求,HttpServletRequest对象代表一次请求,

	一次请求对应一个request对象,100个请求对应100个request对象,所以request对象的生命周期是短暂的,什么是一次请求:
	到目前为止我们可以这样理解一次请求:在网页上点击超链接,到网页停下来,这就是一次完整的请求。

HttpServletRequest中的方法

表单提交的数据,会自动被封装到request对象中,request对象中有Map集合存储这些数据:Map集合的key是name,value是一个一维字符串数组

- String getParameter(String name)	//通过key获取value这个一维数组中的首元素(这个用的多,但不能获取类似多选框的多个值)
- String[] getParameterValues(String name)	//通过Map集合的key获取value

- Map getParameterMap()		//获取整个map集合
- Enumeration getParameterNames()	//获取map集合的key

- String getContextPath()	//获取上下文路径,webapp路径
- String getMethod()		//获取浏览器的请求方式
- String getRequestURI()	//获取URI
- StringBuffer getRequestURL()	//获取URL
- String getServletPath()	//获取Servlet PATH url-pattern
- String getRemoteaddr()	//获取客户端IP地址

- void setAttribute(String name,Object o)	//向Request范围中添加数据
- Object getAttribute(String name)			//从Request范围中读取数据
- void removeAttribute(String name)			//移除Request范围中的数据

- RequestDispatcher getRequestDispatcher(String path) //获取请求转发器,让转发器对象指向某个资源

- void setCharacterEncoding(String env)

- Cookie[] getCookies()		//下面两个都是后面讲
- HttpSession getSession()

关于存数据范围对象的选择

ServletConetx 应用范围,可以跨用户传递数据
ServletRequest 请求范围,只能在同一个请求中传递数据【可以跨Servlet传递数据,但是这多个Servlet必须在同一个请求中】
优先选择request范围

乱码

1.乱码经常出现在什么位置上
	* 数据"传递"过程中的乱码
	* 数据"展示"过程中的乱码
	* 数据"保存"过程中的乱码
	
2.数据保存过程中的乱码
	- 最终保存到数据库中的术后,数据出现乱码、
	- 导致数据保存过程中的乱码包括以下两种情况
		第一种情况:在保存之前,数据本身就是乱码,保存到数据库中一定时乱码
		第二种情况:保存之前,数据不是乱码,但是由于本身数据库不支持简体中文,保存之后出现乱码
		
3.数据展示过程中的乱码?
	- 最终显示到网页上出现中文乱码
	- 经过执行java程序之后,java程序负责向浏览器响应的时候,中文出现乱码,怎么解决:
		* 设置响应的内容类型,以及对应的字符编码方式:
			response.setContentType=("text/html;charset=UTF-8");
		
	- 没有经过执行java程序,直接访问html页面,出现中文乱码,解决方法:
			 <meta content="text/html;charset=UTF-8"> 	
			 
4.数据传递过程中的乱码?
	-  将数据从浏览器发送给服务器的时候,服务器接受到的数据时乱码
	-  浏览器是这样发送数据给服务器的: dname=%E5%B8%82%E5%9C%BA%E9%83%A8
	这个是“市场部”对应的ISO-8859-1的编码
	- ISO-8859-1是国际标准码,不支持中文编码,兼容ASCII码,又被称为latin1编码
	- 不管是哪个国家的文字,在浏览器发送给服务器的时候都会采用ISO-8859-1编码的方式发送。
	- 发送给web服务器之后,web服务器不知道这些数据之前是什么类型的文字,所以web接受的数据时会乱码
	- 解决数据传递过程中的乱码:
		第一种方法:
			万能方法,既能解决POST请求乱码,又能解决GET请求乱码
			先将服务器中接受到的数据采用ISO-8859-1的方式解码,回到初始状态
			再给一种支持简体中文的编码方式重写编码组装我【组装的编码方式需和浏览器的编码方式相同】
			
		第二种解决方案:
			request.setCharacterEncoding("UTF-8");
			以上代码必须在从request中获取任何数据之前才能起效果
			
		第三种方案:专门解决GET请求的乱码问题,因为种方式只对请求行编码
			修改CATALINA_HOME/conf/server.xml文件
			<Connector port="9527" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           URIEncoding="UTF-8" />//最后一行是加的
           
           扩展:	上面的Connector标签中都可以编写哪些属性?
           port	端口
           maxThreads	Tomcat服务器最高能支持多少个线程并发执行,默认200
           URIEncoding	设置请求行上的编码方式,解决GET请求乱码

线程安全问题

1.Servlet是单实例多线程环境下运行的

2.什么时候程序存在线程安全问题?
	- 多线程并发
	- 有共享的数据
	- 共享数据有修改操作
	
3.在jvm中,哪些数据可能会存在线程安全问题?
	- 局部变量内存空间不共享,一个线程一个栈,局部变量在栈中储存,局部变量不会存在线程安全问题
	- 常量不会被修改,所以常量不会存在线程安全问题。
	- 所有线程共享一个堆:
		*堆内存中new出来的对象在其中储存,对象内部有“实例变量”,所以“实例变量”的内存是多线程共享的
		实例变量多线程共同访问,并且涉及到修改操作的时候就会存在线程安全问题
		
	- 所有线程共享一个方法区
		*方法区中有静态变量,静态变量的内存也是共享的,若涉及修改,静态变量也会出现线程安全问题。
		
4.数据库中也会出现线程安全问题,如多个线程共享同一章表,并且同时去修改表中的一些记录,那么这些记录就存在线程安全问题。
怎么解决?
	- 第一种方案是:在java程序中使用synchronized关键字,线程都排队执行,自然不会在数据库中年并发,解决线程安全问题。
	- 第二种方案是:行级锁【悲观锁】
	- 第三种方案是:事务隔离级别,例如:串行化
	- 第四种方案是:乐观锁......
	
5.怎么解决线程安全问题?
	5.1 不使用实例变量,尽量使用局部变量
	5.2 若必须使用实例变量,那么我们可以考虑把该对象变成多列对象,一个线程一个java对象,实例变量的内存也不会共享
	5.3 若必须使用单例,那么只能使用synchronized线程同步机制,线程一但排队执行,则吞吐量降低,降低用户体验。
	
6. Servlet怎么解决线程安全问题?
	6.1 不使用实例变量,尽量用局部变量
	6.2用synchronized

转发和重定向

1.跳转包括两种方式:
	- 转发- forward
	- 重定向- redirect
	
2.代码
	-转发:
		request.getRequestDispatcher("/b").forward(request, response);
	
	-重定向:
		response.sendRedirect(request.getContextPath()+"/b");
		
3.相同的和不同点:
	相同:都可以完成资源跳转
	
	不同:
		转发是request对象触发的
		重定向是response对象触发的
		转发是一次请求,浏览器地址栏不会变化【/a】
		重定向是两次请求,浏览器地址栏上的地址发生变化【/a,/b】
		重定向的路径需要加webapp的根路径
		转发是在本项目内完成的内部资源跳转
		重定向可以完成app跳转
		
4.跳转的下一个资源可以是web服务器中的任何一种资源:html servlet jsp...

5.若想完成app跳转,必须使用重定向
若想在下一个资源中调用上一个资源的request范围中的数据,用转发
重定向可以解决浏览器的刷新问题(表单页面转发刷新会重复提交表单)

6.重定向时,程序给了联络线一个新的路径,浏览器又自动给web服务器发送了一个新的请求

7.点击一个超链接,到网页最终停下来,可能时多次请求

Cookie

1.由曲奇饼干翻译过来的Cookie,可以保存会话状态到浏览器缓存上,或者客户端硬盘上。(保存数据)
 	
2.Cookie机制是Http协议规定的,所有基于Http协议的项目,就有Cookie的存在

3.Cookie可以实现的功能:
	- 保留购物车商品的状态到客户端
	- 十天之内免登录
	.......
	
4.java中Cookie被当作类来处理,
	Cookie cookie=new Cookie(String cookieName,String cookieValue);
	
5.服务器一次可以向浏览器发送多个Cookie,默认情况下Cookie会保存在浏览器缓存中,浏览器关闭Cookie被清除。

6.Cookie和请求路径绑定,不同的请求路径会让浏览器发送不同的Cookie给服务器

7.如何绑定:*****
	/prj-servlet-18/test/createAndSendCookieToBrowser 请求服务器,服务器生成Cookie,并将Cookie发送给浏览器客户端
	这个浏览器中的Cookie会默认和"test/"这个路径绑定在一起。
	也就是说只要发送"test/"请求,Cookie一定会提交给服务器。
	
	/prj-servlet-18/a请求服务器时
	浏览器中的Cookie会默认和"prj-servlet-18/"绑定在一起
	
	******注意有无"/"
	
8.路径可以指定:在java程序中
		cookie.setPath("/prj-servlet-18/king");
	那么Cookie将和"/prj-servlet-18/king"路径绑定
	
9.因为默认Cookie保存在浏览器缓存中,浏览器关闭,Cookie消失,所以我们可以设置Cookie有效时长,从而把Cookie保存在硬盘中:
 	cookie1.setMaxAge();
 	单位秒,必须大于0(等于零自动直接销毁)
 	cookie1.setMaxAge(60*60);//1小时

10.服务器接受浏览器发送的Cookie:
Cookie[] cookies=request.getCookies();
if(cookies!=null) {
    
    
	for (Cookie cookie : cookies) {
    
    
		String cookieName=cookie.getName();
		String cookieValue=cookie.getValue();
		System.out.println(cookieName+"="+cookieValue);
	}
}

添加的话直接用addCookie()方法就好
response.addCookie(cookie1);

Session

关于web编程中的Session:
	1.Session不是java特有的,是web开发的机制
	2.对应java中的类型:	javax.serlvet.http.HttpSession 简称session/会话
	3.Cookie可以将会话状态保存在客户端,HttpSession可以将会话状态保存在服务器端
	4.HttpSession对象是一个会话级别的对象,一次会话对应一个HttpSession对象
	5.什么是一次会话?
		目前可以简单的认为:用户打开浏览器并发送多个请求,最后关闭浏览器,表示一次完整的会话
	6.在会话过程中,web服务器一直为当前用户维护着一个会话对象/HttpSession
	7.在WEB容器中,WEB容器维护了大量的HttpSession对象,也就是说,WEB容器中应该有一个"session列表"
	
	为什么当前会话中的每一次请求可以获取到属于自己的会话对象?session的实现原理?
		- 打开浏览器,在浏览器上发送首次请求
		- 服务器会创建一个HttpSession对象,该对象代表一次会话
		- 同时生成HttpSession对象对应的Cookie对象,并且Cookie对象的name是JSESSIONID,Cookie的value是32位长度的字符串
		- 服务器将Cookie的value和HttpSession对象绑定到session列表中
		- 服务器将Cookie完整发送给浏览器客户端
		- 浏览器客户端将Cookie保存到缓存中
		- 只要浏览器不关闭,Cookie不会消失
		- 当再次发送请求的时候,会自动提交缓存当中的Cookie
		- 服务器接受到Cookie,验证该Cookie的name的确是:JSESSIONID,然后获取该Cookie的value
		- 通过Cookie的value去session列表中检索对应的HttpSession对象。
		
	8.和HttpSession对象关联的这个Cookie是比较特殊的,在java中就叫做:jsessionid
	
	9.浏览器禁用Cookie会出现什么问题?怎么解决?
		- 浏览器禁用Cookie,则浏览器缓存中不在保存Cookie
		- 导致在同一个会话中,无法获取到对应的会话对象
		- 禁用Cookie之后,每一次获取的会话对象都是新的
		
		浏览器禁用Cookie后,若还想拿到对应的Session对象,必须使用URL重写机制,怎么重写URL:
			http://localhost/prj-servlet-21/user/accessMySelfSession;jessionid=D3E9985SADAS331SAD..
			(手动添加Cookie)
			
	10.浏览器关闭之后,服务端对应的session对象会被销毁吗?为什么?
		- 浏览器关闭之后,服务器不会销毁session
		- 因为B/S架构的系统基于HTTP协议,而Http协议是一种无连接/无状态的协议
		- 什么是无连接/无状态?
			* 请求的瞬间浏览器和服务器之间的通道是打开的,请求响应结束之后,通道关闭
			* 这样做的目的是为了降低服务器的压力
			
	11.session对象什么时候会被销毁?
		- web系统中引入了session超时的概念
		- 当很长一段时间(可以自己设置)没有用户再访问该session对象,此时session对象超时,web服务器自动回收session对象
		- 可以配置:web.sml文件中,默认30分钟
			<session-config>
				<session-timeout>120</session-timeout>
			</session-config>
			
	12.什么是一次会话?
		- 本质上说是从session对象的创建到超时销毁是一次完整对话
		
	13.关于javax.servlet.http.HttpSession接口中常用方法:
		- void setAttribute(String name,Object value)
		- Object getAttribute(String name)
		- void removeAttribute(String name)
		- void invalidate()
		- 

补充HttpServletRequest中的方法:

	//获取session对象,若没有获取到,则创建session对象
	HttpSession session=request.getSession();
	
	//获取session对象,若没有获取到,则创建session对象
	HttpSession session=request.getSession(true);
	
	//获取session对象,若没有获取到,则返回null
	HttpSession session=request.getSession(false);

ServletContext,HttpSession,HttpServletRequest接口的对比:

		1。以上都是范围对象:
			ServletContext application; 是应用范围
			HttpSession session; 是会话对象
			HttpServletRequest request; 是请求范围
			
		2.三个范围的排序:
			application>session>request
			
		3.
			application完成跨会话共享数据,
			session完成跨请求共享数据,但是这些请求必须在用一个会话中
			request完成跨Servlet共享数据,但是这些Servlet必须在同一个请求中【转发】
			
		4.使用原则:由小到大尝试:
			例如:登录成功之后,已经登录的状态需要保存起来,可以将登录成功的这个状态保存到session对象中
			登录成功状态不能保存到request范围中,因为一次请求对应一个新的request对象
			登录成功状态也不能保存到application范围中,因为登录成功状态是属于回会话级别的,不能所有用户共享

猜你喜欢

转载自blog.csdn.net/youxizaixian123/article/details/119854511