day01 javaweb:servelt

1 servlet

1.1使用注解的配置Servlet

用注解配置 Servlet

@WebServlet(name="Servlet01",value="/ser01")
@WebServlet(name="Servlet01",urlPatterns = "/ser01")

也可以配置多个访问路径

@WebServlet(name="Servlet01",value={"/ser01",'/ser001'})
@WebServlet(name="Servlet01",urlPatterns={"/ser01",'/ser001'})

路径中的斜杠一定不要忘记

1.2 Servlet的生命周期

​ Servlet没有 main()方法,不能独立运行,它的运行完全由 Servlet 引擎来控制和调度。 所谓生命周期,指的是 servlet 容器何时创建 servlet 实例、何时调用其方法进行请求的处理、 何时并销毁其实例的整个过程。

  • 实例和初始化时

    当请求到达容器时,容器查找该 servlet 对象是否存在,如果不存在,则会创建实例并进行初始化。

  • 就绪/调用**/服务**阶段

    有请求到达容器,容器调用 servlet 对象的 service()方法,处理请求的方法在整个生命周期中可以被多次调用; HttpServlet 的 service()方法,会依据请求方式来调用 doGet()或者 doPost()方法。但是, 这两个 do 方法默认情况下,会抛出异常,需要子类去 override。

  • 销毁时机

    当容器关闭时(应用程序停止时),会将程序中的 Servlet 实例进行销毁。

    上述的生命周期可以通过 Servlet 中的生命周期方法来观察。在 Servlet 中有三个生命周 期方法,不由用户手动调用,而是在特定的时机有容器自动调用,观察这三个生命周期方法 即可观察到 Servlet 的生命周期。

    init 方法,在 Servlet 实例创建之后执行(证明该 Servlet 有实例创建了)

    public void init(ServletConfig config) throws ServletException {
        System.out.println("实例创建了...");
    }
    

    service 方法,每次有请求到达某个 Servlet 方法时执行,用来处理请求(证明该Servlet 进行服务了)

    protected void service(HttpServletRequest req, HttpServletResponse resp) 
        throws ServletException, IOException {
        System.out.println("服务调用了...");
    }
    

    destroy 方法,Servlet 实例销毁时执行(证明该 Servlet 的实例被销毁了)

    public void destroy() {
    	System.out.println("实例销毁了...");
    }
    

    Servlet 的生命周期,简单的概括这就分为四步:servlet 类加载–>实例化–>服务–>销毁。

2.1 HttpServletRequest对象

​ HttpServletRequest 对象:主要作用是用来接收客户端发送过来的请求信息,例如:请求的参数,发送的头信息等都属于客户端发来的信息,service()方法中形参接收的是 HttpServletRequest 接口的实例化对象,表示该对象主要应用在 HTTP 协议上,该对象是由 Tomcat 封装好传递过来。

​ HttpServletRequest 是 ServletRequest 的子接口,ServletRequest 只有一个子接口,就是 HttpServletRequest。既然只有一个子接口为什么不将两个接口合并为一个?

​ 从长远上讲:现在主要用的协议是 HTTP 协议,但以后可能出现更多新的协议。若以后想要支持这种新协议,只需要直接继承 ServletRequest 接口就行了。

​ 在 HttpServletRequest 接口中,定义的方法很多,但都是围绕接收客户端参数的。但是怎么拿到该对象呢?不需要,直接在 Service 方法中由容器传入过来,而我们需要做的就是取出对象中的数据,进行分析、处理。

2.2 接收请求

常用方法

在这里插入图片描述

  1. 示例

    // 获取客户端请求的完整URL (从http开始,到?前面结束)
    String url = request.getRequestURL().toString();
    System.out.println("获取客户端请求的完整URL:" + url);
    //  获取客户端请求的部分URL (从站点名开始,到?前面结束)
    String uri = request.getRequestURI();
    System.out.println("获取客户端请求的部分URL:" + uri);
    // 获取请求行中的参数部分
    String queryString = request.getQueryString();
    System.out.println("获取请求行中的参数部分:" + queryString);
    // 获取客户端的请求方式
    String method = request.getMethod();
    System.out.println("获取客户端的请求方式:" + method);
    // 获取HTTP版本号
    String protocol = request.getProtocol();
    System.out.println("获取HTTP版本号:" + protocol);
    // 获取webapp名字 (站点名)
    String webapp = request.getContextPath();
    System.out.println("获取webapp名字:" + webapp);
    
2.3 获取请求参数
  1. 方法

    diyieg[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FoRmLNSw-1647697834745)(/Servlet-12.png)]

  2. 示例:第一个方法最重要

    // 获取指定名称的参数,返回字符串
    String uname = request.getParameter("uname");
    System.out.println("uname的参数值:" + uname);
    // 获取指定名称参数的所有参数值,返回数组
    String[] hobbys = request.getParameterValues("hobby");
    System.out.println("获取指定名称参数的所有参数值:" + Arrays.toString(hobbys));
    

2.4 请求乱码问题

​ 由于现在的 request 属于接收客户端的参数,所以必然有其默认的语言编码,主要是由于在解析过程中默认使用的编码方式为 ISO-8859-1(此编码不支持中文),所以解析时一定会出现乱码。要想解决这种乱码问题,需要设置 request 中的编码方式,告诉服务器以何种方式来解析数据。或者在接收到乱码数据以后,再通过相应的编码格式还原。

方式一:

request.setCharacterEncoding("UTF-8");

这种方式只针对 POST 有效(必须在接收所有的数据之前设定)

方式二:

new String(request.getParameter(name).getBytes("ISO-8859-1"),"UTF-8");

借助了String 对象的方法,该种方式对任何请求有效,是通用的

Tomcat8起,以后的GET方式请求是不会出现乱码的。

2.5 请求转发

​ 请求转发,是一种服务器端的行为,当客户端请求到达后,服务器进行转发,此时会将请求对象进行保存,地址栏中的 URL 地址不会改变,得到响应后,服务器端再将响应发送给客户端,从始至终只有一个请求发出

实现方式如下,达到多个资源协同响应的效果。

request.getRequestDispatcher(url).forward(request,response);

特点:

  • 地址栏不发生改变。
  • 从始至终只有一个请求
  • 数据可以共享

2.6 request作用域

​ 通过该对象可以在一个请求中传递数据,作用范围:在一次请求中有效,即服务器跳转有效。

// 设置域对象内容
request.setAttribute(String name, String value);
// 获取域对象内容
request.getAttribute(String name); 
// 删除域对象内容
request.removeAttribute(String name);

​ request 域对象中的数据在一次请求中有效,则经过请求转发,request 域中的数据依然存在,则在请求转发的过程中可以通过 request 来传输/共享数据。

3.1 HttpServletResponse对象

​ Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的 request 对象和代表响应的 response 对象。

​ request 和 response 对象代表请求和响应:获取客户端数据,需要通过 request 对象;向客户端输出数据,需要通过 response 对象

​ HttpServletResponse 的主要功能用于服务器对客户端的请求进行响应,将 Web 服务器处理后的结果返回给客户端。service()方法中形参接收的是 HttpServletResponse 接口的实例化对象,这个对象中封装了向客户端发送数据、发送响应头,发送响应状态码的方法。

3.2 响应数据

​ 接收到客户端请求后,可以通过 HttpServletResponse 对象直接进行响应,响应时需要获取输出流。

​ 有两种形式:

getWriter() 获取字符流(只能响应回字符)

getOutputStream() 获取字节流(能响应一切数据)

​ 响应回的数据到客户端被浏览器解析。

注意:两者不能同时使用。

// 字符输出流
PrintWriter writer = response.getWriter();
writer.write("Hello");
writer.write("<h2>Hello</h2>");
// 字节输出流
ServletOutputStream out = response.getOutputStream();
out.write("Hello".getBytes());
out.write("<h2>Hello</h2>".getBytes());

​ 设置响应类型,默认是字符串

// 设置响应MIME类型
response.setHeader("content-type","text/html"); // html

3.3响应乱码问题

​ 在响应中,如果我们响应的内容中含有中文,则有可能出现乱码。这是因为服务器响应的数据也会经过网络传输,服务器端有一种编码方式,在客户端也存在一种编码方式,当两端使用的编码方式不同时则出现乱码。

getWriter()的字符乱码

​ 对于 getWriter()获取到的字符流,响应中文必定出乱码,由于服务器端在进行编码时默认会使用 ISO-8859-1 格式的编码,该编码方式并不支持中文。

​ 要解决该种乱码只能在服务器端告知服务器使用一种能够支持中文的编码格式,比如我们通常用的"UTF-8"。

response.setCharacterEncoding("UTF-8");

​ 此时还只完成了一半的工作,要保证数据正确显示,还需要指定客户端的解码方式。

response.setHeader("content-type", "text/html;charset=UTF-8");

​ 两端指定编码后,乱码就解决了。一句话:保证发送端和接收端的编码一致

// 设置服务端的编码
response.setCharacterEncoding("UTF-8");
// 设置客户端的响应类型及编码
response.setHeader("content-type","text/html;charset=UTF-8");
// 得到字符输出流
PrintWriter writer = response.getWriter();
writer.write("<h2>你好</h2>");

以上两端编码的指定也可以使用一句替代,同时指定服务器和客户端

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

getOutputStream()字节乱码

​ 对于 getOutputStream()方式获取到的字节流,响应中文时,由于本身就是传输的字节, 所以此时可能出现乱码,也可能正确显示。当服务器端给的字节恰好和客户端使用的编码方式一致时则文本正确显示,否则出现乱码。无论如何我们都应该准确掌握服务器和客户端使用的是那种编码格式,以确保数据正确显示。

指定客户端和服务器使用的编码方式一致。

response.setHeader("content-type","text/html;charset=UTF-8");
// 设置客户端的编码及响应类型
ServletOutputStream out = response.getOutputStream();
response.setHeader("content-type","text/html;charset=UTF-8");
out.write("<h2>你好</h2>".getBytes("UTF-8"));

​ 同样也可以使用一句替代

// 设置客户端与服务端的编码
response.setContentType("text/html;charset=UTF-8");

总结:要想解决响应的乱码,只需要保证使用支持中文的编码格式。并且保证服务器端 和客户端使用相同的编码方式即可

3.4 重定向

​ 重定向是一种服务器指导,客户端的行为。客户端发出第一个请求,被服务器接收处理后,服务器会进行响应,在响应的同时,服务器会给客户端一个新的地址(下次请求的地址 response.sendRedirect(url);),当客户端接收到响应后,会立刻、马上、自动根据服务器给的新地址发起第二个请求,服务器接收请求并作出响应,重定向完成。

​ 从描述中可以看出重定向当中有两个请求存在,并且属于客户端行为。

// 重定向跳转到index.jsp
response.sendRedirect("index.jsp");

​ 通过观察浏览器我们发现第一次请求获得的响应码为 302,并且含有一个 location 头信息。并且地址栏最终看到的地址是和第一次请求地址不同的,地址栏已经发生了变化。

3.5 请求转发与重定向的区别

​ 请求转发和重定向比较:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j4uWL0YF-1647697834751)(/Servlet-14.png)]

​ 两者都可进行跳转,根据实际需求选取即可。

4 Cookie对象

​ Cookie是浏览器提供的一种技术,通过服务器的程序能将一些只须保存在客户端,或者在客户端进行处理的数据,放在本地的计算机上,不需要通过网络传输,因而提高网页处理的效率,并且能够减少服务器的负载,但是由于 Cookie 是服务器端保存在客户端的信息, 所以其安全性也是很差的。例如常见的记住密码则可以通过 Cookie 来实现。

​ 有一个专门操作Cookie的类 javax.servlet.http.Cookie。随着服务器端的响应发送给客户端,保存在浏览器。当下次再访问服务器时把Cookie再带回服务器。

​ Cookie 的格式:键值对用“=”链接,多个键值对间通过“;”隔开。

4.1 Cookie的创建和发送

​ 通过 new Cookie(“key”,“value”);来创建一个 Cookie 对象,要想将 Cookie 随响应发送到客户端,需要先添加到 response 对象中,response.addCookie(cookie);此时该 cookie 对象则随着响应发送至了客户端。在浏览器上可以看见。

// 创建Cookie对象
Cookie cookie = new Cookie("uname","zhangsan");
// 发送Cookie对象
response.addCookie(cookie);

F12 查看

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HYtGrmTn-1647697834753)(/Servlet-15.png)]

4.2 Cookie的获取

​ 在服务器端只提供了一个 getCookies()的方法用来获取客户端回传的所有 cookie 组成的一个数组,如果需要获取单个 cookie 则需要通过遍历,getName()获取 Cookie 的名称,getValue()获取 Cookie 的值。

// 获取Cookie数组
Cookie[] cookies = request.getCookies();
// 判断数组是否为空
if (cookies != null && cookies.length > 0) {
    // 遍历Cookie数组
    for (Cookie cookie : cookies){
        System.out.println(cookie.getName());
        System.out.println(cookie.getValue());
    }
}

4.3 Cookie设置到期时间

​ 除了 Cookie 的名称和内容外,我们还需要关心一个信息,到期时间,到期时间用来指定该 cookie 何时失效。默认为当前浏览器关闭即失效。我们可以手动设定 cookie 的有效时间(通过到期时间计算),通过 setMaxAge(int time);方法设定 cookie 的最大有效时间,以秒为单位。

到期时间的取值

  • 负整

    若为负数,表示不存储该 cookie。

    cookie 的 maxAge 属性的默认值就是-1,表示只在浏览器内存中存活,一旦关闭浏览器窗口,那么 cookie 就会消失。

  • 正整

    若大于 0 的整数,表示存储的秒数。

    表示 cookie 对象可存活指定的秒数。当生命大于 0 时,浏览器会把 Cookie 保存到硬盘上,就算关闭浏览器,就算重启客户端电脑,cookie 也会存活相应的时间。

  • 若为 0,表示删除该 cookie。

    cookie 生命等于 0 是一个特殊的值,它表示 cookie 被作废!也就是说,如果原来浏览器已经保存了这个 Cookie,那么可以通过 Cookie 的 setMaxAge(0)来删除这个 Cookie。 无论是在浏览器内存中,还是在客户端硬盘上都会删除这个 Cookie。

设置Cookie对象指定时间后失效

// 创建Cookie对象
Cookie cookie = new Cookie("uname","zhangsan");
// 设置Cookie 3天后失效
cookie.setMaxAge(3 * 24 * 60 * 60);
// 发送Cookie对象
response.addCookie(cookie);

4.4 Cookie的注意点

  1. Cookie保存在当前浏览器中。

    在一般的站点中常常有记住用户名这样一个操作,该操作只是将信息保存在本机上,换电脑以后这些信息就无效了。而且 cookie 还不能跨浏览器。

  2. Cookie存中文问题

    Cookie 中不能出现中文,如果有中文则通过 URLEncoder.encode()来进行编码,获取时通过 URLDecoder.decode()来进行解码。

    String name = "姓名";
    String value = "张三";
    // 通过 URLEncoder.encode()来进行编码
    name = URLEncoder.encode(name);
    value = URLEncoder.encode(value);
    // 创建Cookie对象
    Cookie cookie = new Cookie(name,value);
    // 发送Cookie对象
    response.addCookie(cookie);
    
    // 获取时通过 URLDecoder.decode()来进行解码
    URLDecoder.decode(cookie.getName());
    URLDecoder.decode(cookie.getValue());
    
  3. 同名Cookie问题

    如果服务器端发送重复的Cookie那么会覆盖原有的Cookie。

  4. 浏览器存放Cookie的数量

    不同的浏览器对Cookie也有限定,Cookie的存储有是上限的。Cookie是存储在客户端(浏览器)的,而且一般是由服务器端创建和设定。后期结合Session来实现回话跟踪。

4.5 Cookie的路径

​ Cookie的setPath设置cookie的路径,这个路径直接决定服务器的请求是否会从浏览器中加载某些cookie。

**情景一:**当前服务器下任何项目的任意资源都可获取Cookie对象

/* 当前项目路径为:s01 */
Cookie cookie = new Cookie("xxx","XXX");
// 设置路径为"/",表示在当前服务器下任何项目都可访问到Cookie对象
cookie.setPath("/");
response.addCookie(cookie);

**情景二:**当前项目下的资源可获取Cookie对象 (默认不设置Cookie的path)

/* 当前项目路径为:s01 */
Cookie cookie = new Cookie("xxx","XXX");
// 设置路径为"/s01",表示在当前项目下任何项目都可访问到Cookie对象
cookie.setPath("/s01"); // 默认情况,可不设置path的值
response.addCookie(cookie);

**情景三:**指定项目下的资源可获取Cookie对象

/* 当前项目路径为:s01 */
Cookie cookie = new Cookie("xxx","XXX");
// 设置路径为"/s02",表示在s02项目下才可访问到Cookie对象
cookie.setPath("/s02"); // 只能在s02项目下获取Cookie,就算cookie是s01产生的,s01也不能获取它
response.addCookie(cookie);

**情景四:**指定目录下的资源可获取Cookie对象

/* 当前项目路径为:s01 */
Cookie cookie = new Cookie("xxx","XXX");
// 设置路径为"/s01/cook",表示在s02/cook目录下才可访问到Cookie对象
cookie.setPath("/s01/cook"); 
response.addCookie(cookie);

​ 如果我们设置path,如果当前访问的路径包含了cookie的路径(当前访问路径在cookie路径基础上要比cookie的范围小)cookie就会加载到request对象之中。

​ cookie的路径指的是可以访问该cookie的顶层目录,该路径的子路径也可以访问该cookie。

总结:当访问的路径包含了cookie的路径时,则该请求将带上该cookie;如果访问路径不包含cookie路径,则该请求不会携带该cookie。

5 HttpSession对象

HttpSession对象是 javax.servlet.http.HttpSession 的实例,该接口并不像 HttpServletRequest 或 HttpServletResponse 还存在一个父接口,该接口只是一个纯粹的接口。这因为 session 本身就属于 HTTP 协议的范畴。

​ 对于服务器而言,每一个连接到它的客户端都是一个 session,servlet 容器使用此接口创建 HTTP 客户端和 HTTP 服务器之间的会话。会话将保留指定的时间段,跨多个连接或来自用户的页面请求。一个会话通常对应于一个用户,该用户可能多次访问一个站点。可以通过此接口查看和操作有关某个会话的信息,比如会话标识符、创建时间和最后一次访问时间。在整个 session 中,最重要的就是属性的操作。

​ session 无论客户端还是服务器端都可以感知到,若重新打开一个新的浏览器,则无法取得之前设置的 session,因为每一个 session 只保存在当前的浏览器当中,(是属于服务端的)并在相关的页面取得。

​ Session 的作用就是为了标识一次会话,或者说确认一个用户;并且在一次会话(一个用户的多次请求)期间共享数据。我们可以通过 request.getSession()方法,来获取当前会话的 session 对象。

// 如果session对象存在,则获取;如果session对象不存在,则创建
HttpSession session = request.getSession();

5.1 标识符 JSESSIONID

​ Session 既然是为了标识一次会话,那么此次会话就应该有一个唯一的标志,这个标志就是 sessionId。

​ 每当一次请求到达服务器,如果开启了会话(访问了 session),服务器第一步会查看是否从客户端回传一个名为 JSESSIONID 的 cookie,
    如果没有则认为这是一次新的会话,会创建 一个新的 session 对象,并用唯一的 sessionId 为此次会话做一个标志。如果有 JESSIONID 这 个cookie回传,服务器则会根据 JSESSIONID 这个值去查看是否含有id为JSESSION值的session 对象,如果没有则认为是一个新的会话,重新创建一个新的 session 对象,并标志此次会话; 如果找到了相应的 session 对象,则认为是之前标志过的一次会话,返回该 session 对象,数据达到共享。

​ 这里提到一个叫做 JSESSIONID 的 cookie,这是一个比较特殊的 cookie,当用户请求服务器时,如果访问了 session,则服务器会创建一个名为 JSESSIONID,值为获取到的 session(无论是获取到的还是新创建的)的 sessionId 的 cookie 对象,并添加到 response 对象中,响应给客户端,有效时间为关闭浏览器。

​ 所以 Session 的底层依赖 Cookie 来实现。

5.2 session域对象

​ Session 用来表示一次会话,在一次会话中数据是可以共享的,这时 session 作为域对象存在,可以通过 setAttribute(name,value) 方法向域对象中添加数据,通过 getAttribute(name) 从域对象中获取数据,通过 removeAttribute(name) 从域对象中移除数据。

// 获取session对象 
HttpSession session = request.getSession();
// 设置session域对象
session.setAttribute("uname","admin");
// 获取指定名称的session域对象
String uname = (String) request.getAttribute("uname");
// 移除指定名称的session域对象
session.removeAttribute("uname");

​ 数据存储在 session 域对象中,当 session 对象不存在了,或者是两个不同的 session 对象时,数据也就不能共享了。这就不得不谈到 session 的生命周期。
在这里插入图片描述

5.3 session对象的销毁

默认时间到期

​ 当客户端第一次请求 servlet 并且操作 session 时,session 对象生成,Tomcat 中 session 默认的存活时间为 30min,即你不操作界面的时间,一旦有操作,session 会重新计时。

​ 那么 session 的默认时间可以改么?答案是肯定的。

​ 可以在 Tomcat 中的 conf 目录下的 web.xml 文件中进行修改。

<!-- session 默认的最大不活动时间。单位:分钟。 -->
<session-config>
	<session-timeout>30</session-timeout>
</session-config>
自己设定到期时间

​ 当然除了以上的修改方式外,我们也可以在程序中自己设定 session 的生命周期,通过session.setMaxInactiveInterval(int) 来设定 session 的最大不活动时间,单位为秒。

// 获取session对象 
HttpSession session = request.getSession();
// 设置session的最大不活动时间
session.setMaxInactiveInterval(15); // 15秒

​ 当然我们也可以通过 getMaxInactiveInterval() 方法来查看当前 Session 对象的最大不活动时间。

// 获取session的最大不活动时间
int time = session.getMaxInactiveInterval();
立刻失效

​ 或者我们也可以通过 session.invalidate() 方法让 session 立刻失效

// 销毁session对象
session.invalidate();
关闭浏览器

​ 从前面的 JESSIONID 可知道,session 的底层依赖 cookie 实现,并且该 cookie 的有效时间为关闭浏览器,从而 session 在浏览器关闭时也相当于失效了(因为没有 JSESSION 再与之对应)。

关闭服务器

​ 当关闭服务器时,session 销毁。

​ Session 失效则意味着此次会话结束,数据共享结束。

6 ServletContext对象

​ 每一个 web 应用都有且仅有一个ServletContext 对象,又称 Application 对象,从名称中可知,该对象是与应用程序相关的。在 WEB 容器启动的时候,会为每一个 WEB 应用程序创建一个对应的 ServletContext 对象。(应用对象)

​ 该对象有两大作用,第一、作为域对象用来共享数据,此时数据在整个应用程序中共享; 第二、该对象中保存了当前应用程序相关信息。例如可以通过 getServerInfo() 方法获取当前服务器信息 ,getRealPath(String path) 获取资源的真实路径等。

6.1 ServletContext对象的获取

​ 获取 ServletContext 对象的途径有很多。比如:

  1. 通过 request 对象获取

    ServletContext servletContext = request.getServletContext();
    
  2. 通过 session 对象获取

    ServletContext servletContext = request.getSession().getServletContext();      
    
  3. 通过 servletConfig 对象获取,在 Servlet 标准中提供了 ServletConfig 方法

    ServletConfig servletConfig = getServletConfig();
    ServletContext servletContext = servletConfig.getServletContext();
    
  4. 直接获取,Servlet 类中提供了直接获取 ServletContext 对象的方法

    ServletContext servletContext = getServletContext();
    

常用方法

// 获取项目存放的真实路径
String realPath = request.getServletContext().getRealPath("/");
// 获取当前服务器的版本信息
String serverInfo = request.getServletContext().getServerInfo();

6.2 ServletContext域对象

​ ServletContext 也可当做域对象来使用,通过向 ServletContext 中存取数据,可以使得整个应用程序共享某些数据。当然不建议存放过多数据,因为 ServletContext 中的数据一旦存储进去没有手动移除将会一直保存。

// 获取ServletContext对象
ServletContext servletContext = request.getServletContext();
// 设置域对象
servletContext.setAttribute("name","zhangsan");
// 获取域对象
String name = (String) servletContext.getAttribute("name");
// 移除域对象
servletContext.removeAttribute("name");

Servlet的三大域对象

  1. request域对象

    在一次请求中有效。请求转发有效,重定向失效。

  2. session域对象

    在一次会话中有效。请求转发和重定向都有效,session销毁后失效。

  3. servletContext域对象

    在整个应用程序中有效。服务器关闭后失效。

7 文件上传和下载

​ 在上网的时候我们常常遇到文件上传的情况,例如上传头像、上传资料等;当然除了上传,遇见下载的情况也很多,接下来看看我们 servlet 中怎么实现文件的上传和下载。

文件上传

​ 文件上传涉及到前台页面的编写和后台服务器端代码的编写,前台发送文件,后台接收并保存文件,这才是一个完整的文件上传。

7.1前台页面

​ 在做文件上传的时候,会有一个上传文件的界面,首先我们需要一个表单,并且表单的请求方式为 POST;其次我们的 form 表单的 enctype 必须设为"multipart/form-data",即 enctype=“multipart/form-data”,意思是设置表单的类型为文件上传表单。默认情况下这个表单类型是 “application/x-www-form-urlencoded”, 不能用于文件上传。只有使用了multipart/form-data 才能完整地传递文件数据。

<!--
    文件上传表单
        1. 表单提交类型 method="post"
        2. 表单类型 enctype="multipart/form-data"
        3. 表单元素类型  文件域设置name属性值
-->
<form method="post" action="uploadServlet" enctype="multipart/form-data">
    姓名:<input type="text" name="uname" > <br>
    文件:<input type="file" name="myfile" > <br>
    <button type="submit">提交</button>
</form>
7.2后台实现

​ 使用注解 @MultipartConfig 将一个 Servlet 标识为支持文件上传。 Servlet 将 multipart/form-data 的 POST 请求封装成 Part,通过 Part 对上传的文件进行操作。

package com.xxxx.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;

@WebServlet("/uploadServlet")
@MultipartConfig // 如果是文件上传表单,一定要加这个注解
public class UploadServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 设置请求的编码格式
        request.setCharacterEncoding("UTF-8");
        // 获取普通表单项 (文本框)
        String uname = request.getParameter("uname"); // "uname"代表的是文本框的name属性值
        // 通过 getPart(name) 方法获取Part对象 (name代表的是页面中file文件域的name属性值)
        Part part = request.getPart("myfile");
        // 通过Part对象,获取上传的文件名
        String fileName = part.getSubmittedFileName();
        // 获取上传文件需要存放的路径 (得到项目存放的真实路径)
        String realPath = request.getServletContext().getRealPath("/");
        // 将文件上传到指定位置
        part.write(realPath + fileName);
    }
}

7.3 文件下载

​ 文件下载,即将服务器上的资源下载(拷贝)到本地,我们可以通过两种方式下载。第一种是通过超链接本身的特性来下载;第二种是通过代码下载。

7.4 超链接下载

​ 当我们在 HTML 或 JSP 页面中使用a标签时,原意是希望能够进行跳转,但当超链接遇到浏览器不识别的资源时会自动下载;当遇见浏览器能够直接显示的资源,浏览器就会默认显示出来,比如 txt、png、jpg 等。当然我们也可以通过 download 属性规定浏览器进行下载。但有些浏览器并不支持。

默认下载

<!-- 当超链接遇到浏览器不识别的资源时,会自动下载 -->
<a href="test.zip">超链接下载</a>

指定 download 属性下载

<!-- 当超链接遇到浏览器识别的资源时,默认不会下载。通过download属性可进行下载 -->
<a href="test.txt" download>超链接下载</a>

​ download 属性可以不写任何信息,会自动使用默认文件名。如果设置了download属性的值,则使用设置的值做为文件名。当用户打开浏览器点击链接的时候就会直接下载文件。

后台实现下载

实现步骤

  1. 需要通过 response.setContentType 方法设置 Content-type 头字段的值, 为浏览器无法使用某种方式或激活某个程序来处理的 MIME 类型,例 如 “application/octet-stream” 或 “application/x-msdownload” 等。

  2. 需要通过 response.setHeader 方法设置 Content-Disposition 头的值 为 “attachment;filename=文件名”

  3. 读取下载文件,调用 response.getOutputStream 方法向客户端写入附件内容。

package com.xxxx.servlet;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class DownloadServlet extends HttpServlet {
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 设置请求的编码
        request.setCharacterEncoding("UTF-8");
        // 获取文件下载路径
        String path = getServletContext().getRealPath("/");
        // 获取要下载的文件名
        String name = request.getParameter("fileName");
        // 通过路径得到file对象
        File file = new File(path + name);
        // 判断file对象是否存在,且是否是一个标准文件
        if (file.exists() && file.isFile()) {
            // 设置响应类型 (浏览器无法使用某种方式或激活某个程序来处理的类型)
            response.setContentType("application/x-msdownload");
            // 设置头信息
            response.setHeader("Content-Disposition", "attachment;filename=" + name);
            // 得到输入流
            InputStream is = new FileInputStream(file);
            // 得到输出流
            ServletOutputStream os = response.getOutputStream();
            // 定义byte数组
            byte[] car = new byte[1024];
            // 定义长度
            int len = 0;
            // 循环 输出
            while ((len = is.read(car)) != -1) {
                os.write(car, 0, len);
            }
            // 关闭流 释放资源
            os.close();
            is.close();
        } else {
            System.out.println("文件不存在,下载失败!");
        }
    }
}

8课后题

8.1案例需求:

1_用户首次访问系统登录界面显示如下效果

在这里插入图片描述

2_用户录入账户,密码而且选中记住用户名,点击登录按钮
在这里插入图片描述

3_登录失败显示如下效果
在这里插入图片描述

4_登录成功显示如下效果:

在这里插入图片描述在这里插入图片描述

5_此时用户再次访问登录界面,显示如下效果:

8.2:说出session的概念,作用以及实现方式

  1. 会话:一次会话中包含多次请求和响应。
    1. 一次会话:浏览器第一次给服务器资源发送请求,会话建立,知道一方断开为止
  2. 功能:再一次护花的范围内多次请求间,共享数据
  3. 方式
    1. 客户端会话技术:Cookie
    2. 服务端:会话技术:Seeion
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值