一:Servlet细节
01.Servlet的映射细节
1):一个Servlet程序(WEB组件),可以配置多个<utl-patternt>,表示一个Servlet有多个资源名称
2):一个Servlet程序,可以配置多个<servlet-mapping>.
3):<rul-patternt>必须保证唯一性,而且必须使用/打头.
4):Servlet的映射支持通配符映射( * :表示任意字符);
第一种: /*,任意的资源都可以访问该Servlet. /system/*:请求的资源必须以/system/打头才可以访问,Servlet中,权限控制:
第二种: *.拓展名.比如: *.do,请求的资源必须以.do作为结尾才可以访问该Servlet.
5):在映射Servlet的时候,<servlet-name>元素的文本内容不能是default.
因为的tomcat中存在一个叫做default的Servlet,专门用于处理请求静态资源(html,css,js,图片等).在Tomcat根/conf/web.xml文件:
6):localhost会默认访问URL为localhost/index.html的静态页面,所以只需要设置web.xml文件中的文件即可:
<welcome-file-list>
<welcome-file>hello.html</welcome-file>
</welcome-file-list>*/
02.Servlet3.0新特性–注解配置
问题:如果Servlet有N个,就得配置10*N行代码,web.xml文件,臃肿,不利于维护,开发效率低,从Tomcat7开始,可以使用注解(WebServlet)来取代XML配置.
使用注意:在Web.xml文件的根元素中,存在属性,表示是否忽略扫描WEB组件注解:
metadata-complete="true" : 要忽略
metadata-complete="false" 不忽略
不要改属性: 缺省情况等价于metadata-complete="false"
Servlet代码:
@WebServlet(value="/m1",loadOnStartup=1,
initParams=
{@WebInitParam(name="encoding",value="UTF-8"),
@WebInitParam(name="name",value="miao")
}
)
使用配置,可以使用XML文件也可以使用注解:问题XML和注解各自的优缺点是什么,怎么选择?
XML:优点:XML配置很清晰,很直观,因为和JAVA代码相分离,维护性较高.
缺点:XML配置导致配置文件臃肿,开发效率较低.
注解:优点:开发效率高,配置文件不臃肿,也方便快速定位.
缺点:和java代码耦在一起,维护性较低.
抉择:一般的在企业中,现在注解使用的非常之多,而我们做开发,XML文件用于做通用配置.个别配置使用注解来.
学习阶段:先学XML配置,再讲注解配置.
03.服务器启动就初始化Servlet
回顾Servlet生命周期方法的执行流程:
在启动Tomcat服务器的时候,没有Servlet创建和初始化操作.
在第一次服务端请求的时候:
1):创建Servelt对象.
2):调用init方法做初始化.
3):调用servlet方法,处理请求.
如果某一天,某一个Servlet(核心Servlet:初始化全局信息)需要在启动服务器的时候就创建出来,怎么办
web.xml中的<servlet></servlet>的配置信息添加:
//在启动服务器的时候就加载,值越小越优先加载//
<load-on-startup>1</load-on-startup>
此时该Servlet,会在服务器启动的时候,创建好对象,并做好初始化操作.
使用注解:上面的注解有说到.
比如:在Strutst中的核心Action其本质就是Servlet,既然核心的Action是用来处理所有请求的,
就应该在服务器启动的时候,就初始化,而不是第一个请求过来,才初始化
04.Servlet线程不安全问题
造成的根本原因是:Servlet是单例的,Servlet中的非static的成员变量只有一份,多个客户端好比是多个线程,都访问的是同一个空间.
解决方案:
1:让当前的Servlet实现javax.servlet.SingleThreadMode接口.
包装只有一个线程放Servelt,如果有多个线程就排队,如此的话,性能超低(已过时).
2:在Servlet中不要使用成员变量,使用局部变量.
每一个用户,每一个请求都会调用service方法.而局部变量在service方法中,每一次都是新的空间.
Struts1,Spring MVC都是线程不安全的,都是单例的和Servelt类似.
Struts2是线程安全的,每一个线程(请求),都是一个新的Action对象.
二:Http协议无状态带来的问题
05.HTTP协议的无状态连接
一次会话:可以简单的理解:打开浏览器,访问某一个站点,在该网址内部查看信息,点击超链接等相关的操作,最后关闭浏览器的整个过程,称为一次会话.
HTTP协议:
有一个特点:无状态连接,服务端不知道上一次是哪一个客户端请求了自己.
无状态连接带来的问题:
再一次会话中,我们可以查看多个资源,每一个资源都会先发送请求,再响应,每次的请求都是客户端
发出的,但是,HTTP是无状态的,它不知道上次是谁请求了自己
也就是说,再一次会话中,多个请求之间无共享数据.
邮箱的会话跟踪图示
06.使用参数传递机制解决用户会话跟踪
解决方案:
1)使用参数传递机制,在每一个请求之间使用参数来传递需要共享的数据.
http://localhost/param/list?username=lucy
可以解决问题,但是请求需要共享的数据全部都暴露在浏览器的地址栏中,不安全.
如何解决共享数据不暴露在浏览器的地址栏:为什么会在浏览器的地址栏显示.
因为:请求的请求行数据:GET/param/list?username=lucy Http/1.1
如何解决:共享的数据不会在请求头中出现.
把共享数据存放到请求头中,此时就不会在浏览器地址栏出现了.--->(Cookie)
2):Cookie
Cookie是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器,当用户使用
浏览器再去访问服务器中的web资源时,就会带着各自的资源去,这样,web资源处理的就是用户各自
的数据了.
3):Session
三:Cookie
07.Cookie的简单运用
Cookie的操作:
1:创建Cookie对象.
Cookie cookie = new Cookie(String name,String value);
参数:
name: 该当前Cookie取一个唯一的名字.
value:存储在Cookie的共享数据,只能是String类型.
Cookie cookie = new Cookie("currentName","will");
2:把Cookie放入响应中,响应给浏览器,把共享的数据存储到浏览器中.
resp.addCookie(cookie);
3:获取Cookie以及获取Cookie中的数据.因为Cookie存在请求头中,所以应该通过request去获取.
Cookie[] cs = req.getCookies();
4:Cookie的中文问题.
在Cookie中属性名和属性值都不能使用中文.
//编码
String name = URLEncoder.encode(msg,"UTF-8");
System.out.println(name);
//解码
String str = URLDecoder.decode(name,"UTF-8");
System.err.println(str);
5:修改Cookie中指定属性名的属性值.
需求:修改Cookie cookie = new Cookie("currentName","will");
方式1:创建一个同名的新的Cookie.
Cookie c = new Cookie("currentName","lucy");
方式2:获取该Cookie对象,通过setValue方法,重新设置新的value值.
Cookie对象.setValue("新的值");
注意:别忘了,重新把该Cookie放入响应中:resp.addCookie(c);
6:Cookie的分类(会话Cookie和持久化Cookie):
会 话Cookie:关闭浏览器之后,Cookie就销毁了. 缺省情况.
持久化Cookie:Cookie可以保存指定的时间段(3天,一周,一个月).
设置Cookie的最大存活时间:cookie对象.setMaxAge(int seconds);
seconds == 0; 删除Cookie.
seconds < 0; 会话Cookie.
seconds > 0; 存储指定的秒数
7:删除Cookie: cookie对象.setMaxAge(0);
8.Cookie的路径和Cookie的缺陷
Cookie的domain:
1):设置Cookie的path为"/". 列如:cookie.setPath("/");
2):设置Cookie的domain. 列如:cookie.setDomain(".baidu.com").其中domain中没有指定域名前缀!
Cookie的缺陷:
1):多个人使用同一台电脑的时候,可以查看浏览器的Cookie,不安全.
2):Cookie存储中文比较麻烦(得编码再解码).
3):Cookie的value是String类型,一个Cookie就只能存储一个数据,如果需要存储多个数据,就得使用N个Cookie
4):一个站点对Cookie有限制:
Cookie大小限制在4KB之内:
一台服务器在一个客户端最多保存20个Cookie;
一个浏览器最多可以保存300个Cookie;
5):在设计上就有问题,考虑生活中问题.
Cookie是浏览器和服务器之间数据交互的凭证.
在生活中,我们是把识别数据存储到服务端.
四:Session
9.Session的原理
Session其本质就是一个会话Cookie(浏览器关闭之后,Session就失效了).
Session的原理图
10.Session的简单运用
1:创建和获取Session对象.
HttpSession session = req.getSession(true);
如果当前请求中存在一个Session对象,就直接返回,如果不存在Session对象,就先创建一个再返回.
HttpSession session = req.getSession(false);
如果当前请求中存在一个Session对象,就直接返回,如果不存在Session对象,就返回null.
HttpSession session = req.getSession(); 等价于: HttpSession session = req.getSession(true);
2:往Session中存储数据
Session对象.setAttribute(String name,Object value);
3:从Session中取出数据.
Object value = session对象.getAttribute(String key);
4:删除Session.(用户注销登录)
1):删除Session中指定属性名的值.
session对象.removeAttrbute("currentName");
2):销毁Session对象(Session中所有的属性都不存在).
session对象.invalidate();
5:Session的超时管理
在超时时间之内,如果客户端和服务端没有交互(用户的两次操作不能超过该时间),则自动销毁Session.
session对象.setMaxInactiveInterval(60*10);//超过10分钟,则销毁Session
Tomcat服务器的默认时间为:30分钟 可以修web.xml文件中的代码
<service-config>
<session-timeout>15</session-timeout>
</session-config>
6:URL重写.
Session是一种特殊的Cookie,而浏览器可以禁用Cookie.
此时,需要在每一个资源之后,手动的携带session的ID.
/session/list;jsessionid=3FB3D48B84806A040F03B070F7DAE56A
String url = response.encodeURL("/session/list");自动在资源之后拼接;jsessionid=3FB3D48B84806A040F03B070F7DAE56A
注意:开发中都不会取消接受Cookie的.
11.Session的规范和细节
Session的细节:
1:一般的,我们存储到Session中的属性名称,要唯一,我们习惯XXX_IN_SESSION;
session对象.setAttribute("user_in_session","will");
2:若需要把多个数据存放到Session中,就得调用setAttribute方法N次,可以的.
一般的我们把需要存储的数据,封装成一个对象,然后存储到Session中.
3:如果多台服务器之间需要共享Session,此时Session中的对象必须实现java.io.Serializable(才能在网络上传输).
序 列 化: 把对象信息存储为二进制.
反序列化:把二进制信息恢复成对象.