Servlet:Java服务器端小应用的一些总结

1.Servlet的继承结构

1. 概述

  • tomcat服务器提供了Servlet规范的实现。我们写的代码要想被服务器调用,也必须遵守Servlet规范。

  • 自定义的Servlet类并没有去直接实现Servlet接口,是因为该接口中方法较多,Servlet接口有它的一系列实现类,我们继承实现类即间接的实现了Servlet接口。

2. 继承结构体系

2.1 Servlet接口
  1. init(),创建Servlet对象后立即调用该方法完成一些初始化工作。

  2. service(),处理客户端请求,执行业务操作,可以利用响应对象响应客户端请求。

  3. destroy(),在销毁Servlet对象之前调用该方法。

  4. getServletConfig(),ServletConfig是容器向servlet传递参数的载体。

  5. getServletInfo(),获取servlet相关信息。

2.2 ServletConfig接口
  1. String getServletName(),返回 Servlet 的名字,即 web.xml 中 <servlet-name>元素的值。

  2. ServletContext getServletContext(),返回一个代表当前 Web 应用的 ServletContext 对象。

  3. String getInitParameter(String name),根据初始化参数名返回对应的初始化参数值。

  4. Enumeration getInitParameterNames(),返回一个 Enumeration 对象,其中包含了所有的初始化参数名。

2.3 GenericServle抽象类

GenericServlet是实现了Servlet接口的抽象类。在GenericServlet中进一步的定义了Servlet接口的具体实现,其设计的目的是为了和应用层协议解耦,在GenericServlet中包含一个Service抽象方法。

2.4 HttpServlet类

继承自 GenericServlet,针对于处理 HTTP 协议的请求所定制。在 HttpServlet的service() 方法中已经把 ServletReuqest 和 ServletResponse 转为 HttpServletRequest 和 HttpServletResponse。 直接使用 HttpServletRequest 和 HttpServletResponse, 不再需要强转。实际开发中, 直接继承 HttpServlet, 并根据请求方式复写 doXxx() 方法即可。

2.5 总结

2.6. 注意事项

tomcat服务器在接收到浏览器的请求后,会调用Servlet的service方法处理器请求,如果当前自定义的Servlet类没有service方法会调用父类的service方法进行处理。

2.Servlet的生命周期

1. 执行过程

Servlet的生命周期是由容器管理的,分别经历三各阶段:

反射:实例化对象

init():初始化

service():服务

destroy():销毁

2. 问题

2.1 问题1:Servlet对象创建、初始化并使用完后会销毁吗?

Servlet对象在创建、初始化并使用后不应该销毁。如果使用完(请求处理完)就销毁,那么下次过来请求又得去创建Servlet对象,这样效率并不高!!

我们自始至终都使用同一个Servlet对象去处理请求,如果同时有10个请求过来访问Tomcat服务器,服务器会创建10个线程来处理请求,避免使用全局变量, 多个线程操作全局变量存在线程安全的问题, service()方法中的局部变量不存在线程安全问题。

2.2 问题2:Servlet对象会被创建及初始化几次?

由问题1,我们可以了解到,Servlet对象只会被创建及初始化一次。之后会驻留在内存当中。

2.3 问题3:Servlet对象是在什么时候创建及初始化的?

Servlet的创建与初始化的时机有两个:

  1. Servlet在第一次被浏览器访问的时候创建与初始化的(目前我们的代码用的就是这种方式,默认就是这种)。

  2. Servlet在启动服务器的时候被创建与初始化的(该方式需要做一些配置,告诉Tomcat服务器在启动的时候就创建Servlet对象)。load-on-startup

2.4 问题4:Servlet对象什么时候销毁?

Servlet对象是由Tomcat服务器创建的,之后就一直驻留在内存中处理请求。直到服务器停止后,Servlet才会被销毁。

3. 总结

  1. 当客户端浏览器第一次请求Servlet时,容器会实例化这个Servlet,如果配置了load-on-startup启动容器时就会完成servlet的创建,然后调用一次init方法,并在新的线程中执行service方法处理请求。service方法执行完毕后容器不会销毁这个Servlet而是做缓存处理,当客户端浏览器再次请求这个Servlet时,容器会从缓存中直接找到这个Servlet对象,并再一次在新的线程中执行Service方法。当容器在销毁Servlet之前对调用一次destroy方法。

  2. 没有配置load-on-startup的情况:

  3. 配置了load-on-startup的情况:

服务器启动的时候就会执行:构造方法,然后执行初始化方法。

之后有请求过来,就直接走service方法进行处理。

服务器停止的时候,执行销毁方法。

3.Servlet在Tomcat中运行的原理

启动Tomcat服务器(以下动作只在服务器启动的时候执行):

  1. 解析web项目的web.xml文件。

    1. 默认的servlet

      解析web.xml,解析出url-partten(访问路径)和servlet-class(包名+类名)。

    2. 配置了load-on-startup

      解析web.xml,解析出的url-partten(访问路径)作为key,servlet-class中的包名和类名,通过反射创建Servlet对象(Class clazz=Class.forName(“包名+类名”); Servlet servlet= clazz.newInstance();)将实例化的Servlet对象作为value存储在map集合中。

  2. Tomcat服务器接收请求,例如:请求地址: http://localhost:8080/servlet_day02/aa

  3. Tomcat服务器解析请求,查找请求的资源。

    1. 默认的servlet

      根据url中解析结果,找到web.xml中匹配的url-partten,获取包名和类名,利用反射完成方法的调用。

      Class clazz= Class.forName("包名+类名");

      Servlet servlet = aClass.getConstructor().newInstance();

      servlet.service();

    2. 配置了load-on-startup

      根据url中解析结果,在map集合中根据key(url-partten)获取对应的实例化对象。

      Class clazz= Class.forName("包名+类名");

      Servlet servlet = aClass.getConstructor().newInstance();

      map.set("url-partten中解析的值", servlet );

      Servlet servlet = map.get(key);

      servlet.service();

  4. 注意: 该流程由Tomcat底层接收请求后自动执行,我们是看不到的,我们需要做的是将实现了Servlet接口的代码提前放到Tomcat服务器中。

5. Servlet使用流程总结

5.1 代码编写流程

  1. 打开IDEA

  2. 在IDEA中创建一个Java Enterprise项目

    1. 配置本机的Tomcat服务器,第一次需要配置,后续不需要再配置。

    2. 勾选Web Application,创建web引用程序,自动创建web.xml。

  3. 在项目的src目录下创建一个com.bjsxt.servlet包,在包中创建自己的类继承HttpServlet。

  4. 重写service方法,doGet方法,doPost方法,在方法中写的就是处理请求的业务逻辑代码。

  5. 在web.xml中配置映射关系

    配置servlet的访问路径。

  6. 启动tomcat服务器

    tomcat服务器会解析web.xml。

  7. 在浏览器输入路径访问Servlet

    tomcat接收到客户端的请求后,会创建请求与响应对象,调用请求的serlvet执行service方法,

    将创建的请求与响应对象以参数的形式传递到service方法中。

5.2 代码执行流程(看不到)

  1. tomcat服务器启动时,会加载解析我们项目的web.xml文件。

  2. tomcat服务器根据解析的结果,创建所有在web.xml中配置的Servlet对象(假设都配置了load-on-startup)。

  3. tomcat服务器将所有创建好的Servlet对象以键值对的形式放在内存中,键是你配置的url-pattern,值是Servlet对象。

  4. 在浏览器地址栏输入url地址,比如:http://localhost:8080/demo/Hello

  5. tomcat服务器接收到浏览器发送的http请求,然后进行解析,得到本次请求的两个对象,HttpServletRequest和HttpServletResponse。

  6. tomcat服务器解析url地址中要访问的资源,根据资源路径找到提前创建好的Servlet对象。

  7. tomcat服务器根据反射调用Servlet对象的service方法,并将此次请求解析出的request和response对象传递给service执行。

  8. service方法执行完后,tomcat会按照http响应的格式将数据响应给浏览器。

  9. 浏览器接收到tomcat的响应结果后,对其进行解析,以网页的形式展示给用户看。

3.请求转发和请求重定向

1. 请求转发

问题:

Servlet就是用来处理浏览器发送的请求的,在一个项目中我们可以写多个Servlet去处理不同的请求。由于业务需求,可能会出现多个Servlet配合完成某一项功能。

例如:访问AServlet处理请求,AServlet处理完成后,还需要BServlet处理请求,由BServlet向浏览器响应。此时就需要多个Servlet配合完成某一项功能.

解决方案:

我们可以在A Servlet的service方法中调用B Servlet的service方法接着进行业务的处理。 ​但是Servlet对象是由服务器创建的,service方法也是由服务器进行调用的。所以,我们不能自己去调用。 ​应该在A Servlet的service方法中写一行特殊的代码,告诉tomcat服务器,让服务器去调用B Servlet的service方法接着进行请求的处理。

解决: ​使用请求转发的方式。(forward)

请求转发的特点
  1. 请求转发是一次请求,地址栏地址不变,还是访问第一个Servlet的地址。

  2. 请求转发是一次请求(共享请求和响应对象),所以转发内的各个Servlet共享一个request对象。

  3. 请求转发是Tomcat服务器内部的行为,用户是看不到的。

  4. 可以使用req.setAttribute(key,value)和getAttribute(key)实现请求转发内的Servlet的数据的流转。

  5. 注意:在学习的请求转发后,每个Servlet的访问方式就会有两种:

    1. 浏览器直接发起请求访问。

    2. 其他Servlet通过请求转发访问。

  1. 总结:请求转发可以实现在后端Servlet之间的相互调用,一个请求由一个Servlet处理,转变为了多个Servlet的协同处理

2.请求重定向

请求重定向的特点
  1. 重定向是两次请求,地址栏信息改变,地址会变成第二次请求的地址。

  2. 重定向的地址是浏览器收到第一次请求响应回来的地址,自动跳转的,用户不参与。

  3. 重定向的两次请求,request对象是不同的。

请求转发与请求重定向的比较

请求转发:

  1. 请求转发是一次请求,是Tomcat服务器内部的行为,共享同一个request对象。浏览器只需要发一次请求即可将业务处理完毕。

  2. 一般浏览器发起的查询功能会使用请求转发来完成请求的处理及结果的响应。

  3. 浏览器发起的是增删改的请求,如果使用请求转发来处理的话,因为转发后的地址栏信息是不变的,容易造成用户刷新页面后表单重复提交。

重定向:

  1. 重定向是两次请求,地址栏信息会改变,不共享同一个请求和响应对象。

  2. 一般用户的增删改请求会使用重定向的方式来处理请求。目的是保护第一次请求,避免用户因刷新页面造成表单重复提交。

请求转发与请求重定向的总结

区别转发重定向
浏览器地址栏发生是否改变
请求与响应的次数1次请求,1次响应2次请求,2次响应
是否共享Request和Response对象
是否可以通过Request对象传递数据
速度相对较快相对较慢
行为类型服务器内部行为非服务器内部行为

总结:

不论是请求转发还是请求重定向,都会涉及到多个Servlet。其实,什么时候该用请求转发什么时候该用请求重定向也很容易判断。

如果你需要将A Servlet的处理结果通过请求对象带到B Servlet中去使用,那就使用请求转发。

如果A Servlet的处理结果不需要带到B Servlet中去使用,那就使用重定向。

4.Cookie对象

1. Cookie的引入

问题:

http协议为无状态的,浏览器发起请求(请求中一般是需要携带数据的),服务器接收到请求后调用相关的后端代码去处理该请求,处理完后会响应浏览器。 本次请求与响应结束后,相关的请求与响应数据就会销毁。

如果浏览器又发送了请求,而且本次请求需要用到上次请求传递过的数据,那么本次请求又要重新带上上次请求传递的数据。这样效率不高,而且用户体验度也差!

比如:用户在访问京东的时候,在登录界面输入用户名密码登录了。然后用户在结算的时候,因为http协议的无状态性,导致用户又得重新传递一次登录的信息才行!

解决:

浏览器在发起请求的时候,请求达到服务器,服务器认为本次请求携带的数据比较常用,以后的请求也会用得上,那么服务器就会在响应的时候告诉浏览器,把本次请求的数据给保存起来。然后浏览器以后每次发送请求访问服务器的时候都给带上。

总结:

  1. 客户端存储数据的技术。

  2. 服务器决定哪些数据是以后的请求也会用到的。

  3. 服务器以响应的方式告诉浏览器将常用的这些数据存储起来,存储在浏览器端。

  4. 浏览器以后每次发送请求的时候需要带上这些存储起来的数据。

2. 实现

Cookie技术。

3. 特点

  1. Cookie是浏览器端的数据存储技术。

  2. Cookie使用字符串存储数据。

  3. Cookie使用Key与Value结构存储数据。

  4. 不安全,不适合存储重要的数据到浏览器端。

  5. 单个Cookie存储数据大小限制在4097个字节(4kb左右)。

  6. Cookie存储的数据中不支持中文,Servlet4.0中支持。

  7. Cookie分为持久化Cooke与状态Cookie。

  8. Cookie对象保存在客户端浏览器内存或系统磁盘中。

  9. 浏览器在保存同一域名所返回Cookie的数量是有限的。不同浏览器支持的数量不同,Chrome浏览器为50个

  10. 浏览器每次请求时都会把与当前访问的域名相关的Cookie在请求中提交到服务端。

  11. Cookie是与域名绑定所以不支持跨一级域名访问。

4. Cookie的使用

4.1 Cookie的创建及响应
//创建Cookie,Cookie中保存的数据是键值对的方式
Cookie cookie = new Cookie("username", "root");
​
//将创建好的Cookie添加到响应中,这样浏览器就会将Cookie中的信息保存起来了
resp.addCookie(cookie);

说明:Cookie中存放的是键值对的数据,而且要求值只能是字符串的!

4.2 Cookie数据的获取
Cookie[] cookies = req.getCookies();
if(cookies != null){
    for (Cookie cookie : cookies) {
        String name = cookie.getName();
        String value = cookie.getValue();
        System.out.println(name + ":" + value);
    }
}
4.3 Cookie的存活设置

Cookie是可以设置在浏览器的存活时间的。

使用setMaxAge()方法可以设置存活时间:

  • 正数:表示在指定的秒数后过期

  • 负数:表示浏览器一关,Cookie就会被删除(默认是-1)

  • 零:表示马上删除Cookie

Cookie cookie = new Cookie("life60", "life60");
cookie.setMaxAge(60);
resp.addCookie(cookie);
4.4 Cookie的path属性

Cookie的path属性可以有效的过滤哪些Cookie可以发送给服务器,哪些不发。

path属性是通过请求的地址来进行有效的过滤。

如果不设置path属性,那Cookie的有效路径是当前项目。

比如:

CookieA path=/工程路径

CookieB path=/工程路径/abc

请求地址如下:

http://ip:port/工程路径/a.html 则CookieA发送,CookieB不发送

http://ip:port/工程路径/abc/a.html 则CookieA发送,CookieB发送

案例:

Cookie cookie = new Cookie("path1","path1");
cookie.setPath(req.getContextPath() + "/abc");// 路径是  /工程路径/abc
resp.addCookie(cookie);

需要注意的是:你要想看到/工程路径/abc这个路径的Cookie,那你的地址栏中请求地址必须包含/工程路径/abc才行。

4.5 Cookie的domain属性

域名对应的就是咱们的ip地址。比如:www.baidu.com是百度的域名,那这个域名对应的ip地址是:182.61.200.7。

域名一般是以www开头,以com结尾。

域名分为:顶级(一级)域名、二级域名。

比如: www.baidu.com是顶级域名、.baidu.com是二级域名

Cookie是不支持顶级域名的跨域,支持二级域名的跨域。

比如:在www.baidu.com这个一级域名中存储的Cookie值,在www.jd.com这个一级域名中是拿不到的!但是在news.baidu.com这个二级域名中是可以拿到的。

Cookie有domain属性,可以通过domain属性设置访问该Cookie的域名。如果设置为“www.itbz.com”,则只能是 "www.itbz.com" 可以访问。 如果设置为 ".itbz.com",则以 ".itbz.com" 结尾的域名都可以访问到该Cookie。

5.HttpSession对象

1. 概述

服务端存储数据的技术解决Http无状态。

2. 特点

  • Session将数据保存在服务器端。

  • HttpSession使用Key与Value结构存储数据。

  • HttpSession的Key是字符串类型,Value则是Object类型。

  • HttpSession存储数据大小无限制。

  • HttpSession存储数据安全。

3. 介绍

  1. 一个浏览器在服务器中只会创建一个Session对象。不同用户(浏览器)的Session对象之间是互相独立的。

  2. 服务器中创建Session对象,创建完成后会将Session对象的Id(JSESSIONID)以Cookie的形式保存在客户端(浏览器)。用户再次发请求时,会携带该Cookie,也就是JSESSIONID到服务器,服务器会根据该Id找到用户的Session对象。

  3. 用户JSESSIONID的Cookie丢失或者服务器中存储的Session对象被销毁,服务器接收到用户的请求后,如果找不到对应的Session对象,会重新创建,并将新的JSESSIONID以Cookie的形式保存到浏览器中。

  4. 存储JSESSIONID的Cookie不需要手动创建,Session对象创建完成,Tomcat服务器会自动创建Cookie, 将JESSIONID存储在Cookie中响应回浏览器。

  5. Cookie默认的有效期为一次会话(浏览器不能关闭),浏览器关闭,Cookie即失效。

  6. Session对象在Tomcat服务器的默认有效期为30分钟。

4. 使用

HttpSession对象的创建是通过request.getSession()方法来创建的。客户端浏览器在请求服务端资源时,如果在请求中没有jsessionid,getSession()方法将会为这个客户端浏览器创建一个新的HttpSession对象,并为这个HttpSession对象生成一个jsessionid,在响应中通过状态Cookie写回给客户端浏览器、如果在请求中包含了jsessionid,getSession()方法则根据这个ID返回与这个客户端浏览器对应的HttpSession对象。

getSession()方法还有一个重载方法getSession(true|false)。当参数为true时与getSession()方法作用相同。当参数为false时则只去根据jsessionid查找是否有与这个客户端浏览器对应的HttpSession,如果有则返回,如果没有jsessionid则不会创建新的HttpSession对象。

4.1 HttpSession的创建
HttpSession session = req.getSession();

注意:

  1. 如果请求的Cookie中携带了JSESSIONID,则根据JSESSIONID找对应的Session对象

    1. 找到, 返回该Session。

    2. 没有找到, 创建新的Session对象, 会将JSESSIONID存储在Cookie中响应回浏览器。

  2. 如果请求中没有携带JSESSIONID,则会创建一个Session对象, 会将JSESSIONID存储在Cookie中响应回浏览器

  3. 总结:服务器中能找到对应的Session对象,那就使用该Session对象,如果找不到,就会新创建。

4.2 HttpSession存储数据
session.setAttribute("user", user);
4.3 HttpSession获取数据
session.getAttribute("user");
4.4 HttpSession的销毁方式

HttpSession的销毁方式有两种:

  1. 达到超时时间后会销毁,默认30分钟,时间的计算方式是根据最后一次请求时间作为起始时间开始计算。

    1. Tomcat服务器的conf/web.xml文件中配置HttpSession的超时时间,这个文件是所有项目web.xml的父文件,不建议修改。

    2. 可以修改项目的web.xml中的HttpSession的超时时间。该时间对整个web项目中的所有HttpSession对象有效。

      <session-config>   
          <!--设置Session的超时时间,单位是分钟-->    
          <session-timeout>10</session-timeout>
      </session-config>

  2. 调用HttpSession对象中的invalidate()方法销毁。

  3. 注意:客户端关闭浏览器后,再次打开浏览器并发起请求,由于存储JSESSIONID的Cookie会销毁,服务器会重新创建Session对象。服务器端的旧的Session对象还在,存储的数据也在,过了超时时间后,就销毁了。

4.5 Session相关方法
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  HttpSession session = req.getSession();
  String id = session.getId();//获取JSESSIONID
  System.out.println(id);
  long creationTime = session.getCreationTime();//获取创建时间
  Date date = new Date(creationTime);
  System.out.println(date.toLocaleString());
  long lastAccessedTime = session.getLastAccessedTime();//获取最后一次访问时间
  System.out.println(new Date(lastAccessedTime).toLocaleString());
  session.setMaxInactiveInterval(10);//设置最大非活动时间
  int maxInactiveInterval = session.getMaxInactiveInterval();//获取最大非活动时间
  System.out.println(maxInactiveInterval);
  //session.invalidate();//销毁session对象
}
4.6 HttpSession对象总结

Session和Cookie的区别:

  1. Cookie数据存储在客户端,而HttpSession中的数据存储在服务器。

  2. Cookie不安全,而HttpSession是安全的。

  3. 单个cookie保存的数据不能超过约4KB,很多浏览器都限制一个域名保存cookie的数量。

    HttpSession没有容量以及数量的限制, 随着Session中存储的内容增多,会比较占用服务器内存,Session不存放业务数据。

  4. Cookie的数据都以字符串的形式保存。Session中可以保存对象。

  5. Cookie实现,如:记住我 最近浏览商品 网页皮肤 等。

  6. Session实现,如:登录信息 错误信息 购物车 等。

Session和Cookie的关系:Session依赖于Cookie。

六、基于注解式开发Servlet

在Servlet3.0以及之后的版本中支持注解式开发Servlet。对于Servlet的配置不在依赖于web.xml配置文件,而是使用@WebServlet注解完成Servlet的配置。

1. @WebServlet

属性名类型作用
initParamsWebInitParam[]Servlet的init参数
nameStringServlet的名称
urlPatternsString[]Servlet的访问URL,支持多个
valueString[]Servlet的访问URL,支持多个
loadOnStartupint自启动Servlet
descriptionStringServlet的描述
@WebServlet(name = "first", value = "/first", loadOnStartup = 1, 
initParams = {@WebInitParam(name = "test", value = "aaa")}, 
description = "测试servlet")

6.ServletContext对象

1. 问题

项目中可以使用Session对象在服务器端存储数据,它解决了一个用户不同请求的数据共享问题。

但是在实际功能中,不同的用户也可能会用到相同的数据,如果使用Session来进行存储,会造成同一份数据在服务器中被存储多份,浪费空间。

2. 解决

ServletContext对象, 在一个web项目中只创建一次,所有用户都可以获取及使用,可以实现不同用户请求的数据共享。

3. 实现

获取ServletContext对象,在JSP中也叫Application对象。

4. 特点

  1. ServletContext对象由Tomcat服务器在启动加载项目的时候完成创建。

  2. ServletContext对象一个项目中只有一个,以任意方式获取到的都是同一个。

  3. ServletContext对象中保存的数据是所有用户共享的。

5. 使用

5.1 获取ServletContext对象
//方式一:
ServletContext servletContext = this.getServletContext();
​
//方式二:
ServletContext servletContext1 = req.getSession().getServletContext();
​
//方式三:
ServletContext servletContext2 = req.getServletContext();
5.2 使用ServletContext对象存取数据
//往ServletContext对象中存数据,键值对的方式
servletContext.setAttribute("name", "root");
​
//从ServletContext对象中获取数据
String name = (String)servletContext.getAttribute("name");
5.3 ServletContext对象获取web.xml中配置的上下文参数

可以在web.xml中配置一些参数,可以通过ServletContext对象获取。经常出现在框架的底层。

<!--配置上下文参数-->
<context-param>
    <param-name>name</param-name>
    <param-value>admin</param-value>
</context-param>
​
<context-param>
    <param-name>age</param-name>
    <param-value>18</param-value>
</context-param>
String name1 = servletContext.getInitParameter("name");
String age = servletContext.getInitParameter("age");
​
System.out.println("name:" + name1 + ", age:" + age);
5.6 ServletContext对象的生命周期

当服务器启动时会创建ServletContext对象。服务器关闭后该对象销毁。

ServletContext对象的生命周期很长,仅存放所有用户共享的数据。

7.域对象

1. 认识域对象

1.1 什么是域对象

域对象类似于之前学习的map集合,可以存放键值对的数据。不同的是域对象中数据的使用有一定的区域范围限制。 三大域对象

对象名称
request域HttpServeltRequest对象请求域
session域HttpSession对象会话域
application域ServletContext对象应用域
1.2 常用API
方法作用
setAttribute(key, value)向域中添加|修改数据,无则添加,有则修改
getAttribute(key)获取域中的数据
removeAttribute(key)从域中移除指定key的数据

2. request域

有效范围 一次请求有效

作用

流转业务数据

生命周期 创建:浏览器每次请求,服务器都会重新创建 使用:在请求的Servlet中或者请求转发后的Servlet中使用 销毁:请求响应结束后,该请求对象就会被销毁

3. Session域

有效范围

单次会话内有效,多次请求 作用

一般用来存储用户状态数据,比如:用户的登录信息等

生命周期

创建:从第一次发出请求,会话开始

使用:一次会话内,浏览器和服务器之间发生多次请求都有效

销毁:会话结束,比如:达到最大不活动时间、手动销毁

4. Application域

有效范围

当前web项目内都有效,可以跨请求,跨会话访问 ​作用

一般放一些全局的和项目本身相关所有用户共享的数据,如在线人数,不建议存放业务数据

生命周期

创建:服务器启动

使用:服务器运行期间都有效

销毁:服务器关闭

8.文件上传

1. 介绍

在Servlet3.0之前的版本中如果实现文件上传需要依赖apache的Fileupload组件,在Servlet3.0以及之后的版本中提供了Part对象处理文件上传,所以不在需要额外的添加Fileupload组件。

2. 配置

在Servlet3.0以及之后的版本中实现文件上传时必须要在Servlet中开启多参数配置:

2.1 方式一:

web.xml 配置

<multipart-config>
    <file-size-threshold></file-size-threshold>
    <location></location>
    <max-file-size></max-file-size>
    <max-request-size></max-request-size>
</multipart-config>
元素名类型描述
<file-size-threshold>int当数据量大于该值时,内容将被写入临时文件。
<location>String存放生成的临时文件地址
<max-file-size>long允许上传的文件最大值(byte)。默认值为 -1,表示没有限制
<max-request-size>long一个 multipart/form-data请求能携带的最大字节数(byte),默认值为 -1,表示没有限制。
2.2 方式二:

@MultipartConfig 配置

属性名类型描述
fileSizeThresholdint当数据量大于该值时,内容将被写入临时文件。
locationString存放生临时成的文件地址
maxFileSizelong允许上传的文件最大值(byte)。默认值为 -1,表示没有限制
maxRequestSizelong一个 multipart/form-data请求能携带的最大字节数(byte),默认值为 -1,表示没有限制。

3. Part对象中常用的方法

方法说明
long getSize()上传文件的大小
String getSubmittedFileName()上传文件的原始文件名
String getName()获取<input name="upload" ...>标签中name属性值
InputStream getInputStream()获取上传文件的输入流
void write(String path)保存文件至指定位置

4. 实现

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--
    method="post":必须为post
    enctype="multipart/form-data":必须为multipart/form-data
-->
<form action="uploadServlet" enctype="multipart/form-data" method="post">
    头像:<input type="file" name="photo"> <br>
    <input type="submit">
</form>
</body>
</html>

Servlet

@MultipartConfig
@WebServlet("/uploadServlet")
public class UploadServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Part photo = req.getPart("photo");
        String name = photo.getSubmittedFileName();
        String upload = getServletContext().getRealPath("upload");
        File file = new File(upload);
        if (!file.exists()) {
            file.mkdirs();
        }
        photo.write(upload + "/" + name);
    }
}

9.文件下载

获取文件的输入流,通过输出流响应到浏览器。

@WebServlet("/download")
public class DownLoad extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setHeader("Content-Disposition", "attachment; filename=" + new String("aa.png"));
        //中文需要指定编码
        //resp.setHeader("Content-Disposition", "attachment; filename=" + new String("你好.png".getBytes(),"ISO8859_1"));//下载
        //resp.setHeader("Content-Disposition", "inline; filename=" + new String("你好.png".getBytes(),"ISO8859_1"));//在线浏览
        String upload = getServletContext().getRealPath("upload");
        FileInputStream fis = new FileInputStream(upload + "/aa.png");
        BufferedInputStream bis = new BufferedInputStream(fis);
        ServletOutputStream sos = resp.getOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(sos);
        byte[] bys = new byte[1024];
        while (bis.read(bys) != -1) {
            bos.write(bys, 0, bys.length);
        }
        bos.close();
        bis.close();
    }
}

10.监听器(Listener)

1. 监听器的需求

目前我们在web项目中,可以使用三大域对象request、session、application作为数据流转的载体。而这三个域对象都不是我们创建的,也不是我们销毁的。

但是我们想要像Servlet一样,Servlet虽然不是我们创建的,但是在Servlet中我们可以使用init和destroy方法在Servlet被创建及销毁的时候完成一系列其他的操作,怎么办?

我们可以给三大域对象添加监听,监听三大域对象的创建及销毁,监听到他们有动态的时候,执行对应的方法。这就是监听器。

2. 监听器的介绍

作用:

监听三大域对象的创建、销毁及数据的变更。

特点:

  1. 监听方法由tomcat根据监听结果来调用执行。

  2. 监听方法中的逻辑代码由我们根据需要编写。

3. 监听器的使用

监听器的使用步骤:

  1. 创建一个类,实现监听器接口(Listener)。

  2. 实现里面的方法。

  3. 在web.xml中配置监听器。

监听器接口:

  1. ServletRequestListenter 监听request对象的创建销毁

  2. ServletRequestAttributeListener 监听request域中数据的变更

  3. HttpSessionListener 监听Session对象的创建销毁

  4. HttpSessionAttributeListener 监听Session对象中数据的变更

  5. ServletContextListener 监听ServletContext对象的创建销毁

  6. ServletContextAttributeListener 监听ServletContext对象中数据的变更

public class MyListener implements ServletRequestListener, ServletRequestAttributeListener,
        HttpSessionListener, HttpSessionAttributeListener, ServletContextListener, ServletContextAttributeListener {
    //监听ServletContext对象中数据的添加
    @Override
    public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
​
    }
    //监听ServletContext对象中数据的删除
    @Override
    public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
​
    }
    //监听ServletContext对象中数据的修改
    @Override
    public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
​
    }
    //监听ServletContext对象的初始化
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
​
    }
    //监听ServletContext对象的销毁
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
​
    }
    //监听ServletRequest对象中数据的添加
    @Override
    public void attributeAdded(ServletRequestAttributeEvent servletRequestAttributeEvent) {
        System.out.println("request对象中添加的数据!");
    }
    //监听ServletRequest对象中数据的删除
    @Override
    public void attributeRemoved(ServletRequestAttributeEvent servletRequestAttributeEvent) {
        System.out.println("request对象中删除了数据!");
    }
    //监听ServletRequest对象中数据的修改
    @Override
    public void attributeReplaced(ServletRequestAttributeEvent servletRequestAttributeEvent) {
        System.out.println("request对象中修改了数据!");
    }
    //监听ServletRequest对象中数据的销毁
    @Override
    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
        System.out.println("request对象被销毁!");
    }
    //监听ServletRequest对象的初始化
    @Override
    public void requestInitialized(ServletRequestEvent servletRequestEvent) {
        System.out.println("request对象被初始化!");
    }
    //监听HttpSession对象中数据的添加
    @Override
    public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
​
    }
    //监听HttpSession对象中数据的删除
    @Override
    public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
​
    }
    //监听HttpSession对象中数据的修改
    @Override
    public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
​
    }
    //监听HttpSession对象的创建
    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
​
    }
    //监听HttpSession对象的销毁
    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
​
    }
}
<!--
    配置监听器,在服务器启动的时候就会创建监听器对象,监听器生效,一旦符合监听要求,
    tomcat底层会通过反射调用监听器中的方法完成处理
-->
<listener>
    <listener-class>com.bjsxt.listener.MyListener</listener-class>
</listener>

11.过滤器(Filter)

1. 过滤器的介绍

1.1 目前请求处理中存在的安全问题

通过前面的Servlet学习,我们了解到Tomcat服务器一直是在被动的接收请求,而且Tomcat服务器收到请求后需要调用Servlet的service方法进行处理。

目前,只要在浏览器中输入正确的url地址,不管此次请求是否合理,Tomcat服务器在接收到请求后就会直接调用对应的资源完成请求的处理。有些场景, 需要对请求进行相关处理, 处理完成后, 在访问请求的资源。

比如:

我们写的登录案例,大家发现,如果用户没有登录也可以直接输入主界面的地址访问到主界面。登录其实就像个摆设一样。

1.2 解决方案

在浏览器发起请求,Tomcat服务器收到后,调用资源处理请求之前添加拦截。

拦截后发现请求不合理,可以拒绝访问;如果合理,可以进行相关的设置, 然后放行,继续访问请求的资源。

这个其实就是过滤器(Filter)。

1.3 过滤器的作用

Tomcat收到客户端请求后, 调用资源前会对请求进行拦截, 完成相关的处理。

1.4 过滤器的编写步骤
  1. 创建一个类,实现过滤器接口(Filter)。

  2. 实现接口中的方法,编写自己的代码。

  3. 在web.xml中配置过滤器或通过注解配置。

2. 过滤器的使用

public class CharacterFilter implements Filter {
​
    public CharacterFilter() {
        System.out.println("过滤器被创建!");
    }
​
    /**
     * 处理化方法,执行一些初始化的操作,一般不用
     * @param filterConfig
     * @throws ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器被初始化!");
    }
​
    /**
     * 过滤器的核心方法,过滤器拦截到请求后,就是在该方法中对请求进行判断,看是否让其继续访问我们的资源
     * @param servletRequest    封装的请求信息
     * @param servletResponse   封装的响应对象
     * @param filterChain       过滤器链,用来放行的
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("开始对请求进行判断处理!");
        filterChain.doFilter(servletRequest, servletResponse);//放行
    }
​
    /**
     * 销毁方法,用来做一些释放资源的操作,一般不用
     */
    @Override
    public void destroy() {
        System.out.println("过滤器被销毁!");
    }
}
<!--配置过滤器-->
<filter>
    <filter-name>CharacterFilter</filter-name>
    <!--
        配置过滤器所在的全路径,由Tomcat在启动的时候,通过放射创建该过滤器对象
    -->
    <filter-class>com.bjsxt.filter.CharacterFilter</filter-class>
</filter>
​
<!--配置过滤器的拦截路径,也就是对哪些请求进行拦截-->
<filter-mapping>
    <filter-name>CharacterFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

3. 过滤器链

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值