HttpServletResponse详解

day4 - Servlet&JSP

HttpServletResponse详解

​ Http协议是一种请求响应协议,同时也是一种无状态协议(每一次请求与前后请求都无直接的关联,是相对独立的);所谓请求响应即;

​ 客户端发送请求到服务端,服务端(Servlet)通过HttpServletRequest来接收并处理请求(获取表单数,获取请求头信息),服务端处理完请求之后需要给客户端响应,因此,servlet中通过HttpServletReponse对客户端进行响应。

​ HttpServletResponse是一个接口从ServletResponse继承过来,里面包含的方法主要用于响应客户端信息,常见方法:

  • sendRedirect() 重定向(即通过客户端发送到指定目标的请求)
  • getWriter() 获取基于response对象的输出流,用于向客户端输出信息
  • setContentType() 设置响应的内容类型,常见设置:text/html;charset=utf-8
  • setResponseCharacterEncoding() 设置响应数据的编码模式

会话跟踪技术总结

会话(Session)跟踪,http协议是一个无状态协议,通过http发送的各个请求之间没有关联,如果需要设计到各个请求之间的数据传递?针对以上的需求,在servlet包含四种会话跟踪技术:

  1. URL重写

    http://localhost/pro/query?key=查询关键字&page=1&temp=0.932345987981273
    
  2. 隐藏域传值

     <input type="hidden" name="id" value="1">
    
  3. session

    session是用于存储客户端和服务端一次会话信息一个缓存空间;session是服务端的一段缓存空间,session在servlet中是有HttpSession所表示,session的获取需要通过HttpServletRequest对象:

    HttpSession session = request.getSession();
    session.setAttribute("user",user);
    

    session的默认有效期是30分钟,可以通过在web.xml中手动设置超时时间:

    
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
       version="4.0">
    
    
    <session-config>
      <session-timeout>20session-timeout>
    session-config>
    
    web-app>
    

    关于数据传递:

    session.setAttribute和request.setAttribute区别?

    session能够保存一次会话的信息,只要浏览器不关闭,或者不到达session有效时长,存储在session中的数据会一直存在;request仅限于一次跳转(请求转发),跳转之后在下一个页面中可以获取传递的数据,但是如果后续的跳转未继续传递,则request范围的数据会被清理

    session由于是存储在服务端的缓存空间,因此处于效率考虑,不应该向session中存储大量数据,session适用于存储少量的信息,并且对安全性要求较高的数据,比如说用户身份信息。

  4. cookie

    cookie是一个用于在客户端浏览器中缓存数据的客户端文件,适用于稍大量的数据信息,比如:购物车信息,网站历史浏览器记录;cookie也是由服务端向客户端响应的数据构成:

    //将java对象转换为json字符串
    String json = JSON.toJSONString(user);
    //将字符串使用utf-8编码为http编码
    json = URLEncoder.encode(json,"utf-8");
    //构建一个cookie对象
    Cookie c1 = new Cookie("user", json);
    //将cookie加入到response对象中
    response.addCookie(c1);
    

    注意事项:

    1. cookie的生命周期可以自由设置,单位分钟
    2. 如果未指定有效时长,则默认与session一致
    3. cookie不允许存储中文信息(会出现乱码)
    4. cookie的键值都是String
    5. cookie存储数据一般在4kb左右
    6. cookie在客户端以文件形式存储数据

day5 - JSP快速入门

请求转发与重定向

servlet的跳转分为两种方式:

  1. 请求转发
  2. 重定向

请求转发(forward)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YCqvVrio-1598793028836)(assets\1598319106975.png)]

​ 请求转发是由HttpServletReqeust发起的跳转,跳转的同时可以将请求范围之内的信息传递到下一个Servlet中,请求转发是服务端跳转,请求转发对于客户端来说只发送了一次请求,并且地址栏只会显示第一次请求的地址。

request.setAttribute(key,value);
request.getRequestDispartcher("目标资源").forward(request,response);

注意:

对于请求转发来说,目标资源一般为servlet或jsp;不会使用静态页面

重定向(redirect)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vVxwvEMT-1598793028840)(assets\1598319245748.png)]

​ 重定向是由HttpServletResponse发起的跳转,重定向属于客户端条跳转,因此存储在request范围之类数据无法传递到下一个servlet中,重定向发送了多次请求,并且请求均为客户端发起,地址栏中显示是最后一次请求的地址

response.sendRedirect("目标资源")

关于请求转发和重定向的使用场景:

如果跳转到下一个servlet时需要传递数据则优先考虑使用请求转发(forward),反之则使用重定向(redirect)

请求转发是服务端跳转,重定向是客户端跳转

JSP

Java->Applet->Servlet->JSP

JSP概述

​ JSP(Java Server Pages),java服务页面,允许开发者在html页面中嵌入Java代码,从而快速构建的动态网页,因此jsp也称之为动态网页技术,目前JSP主要作为视图层模板技术,在JavaEE的生态体系中类似的模板技术还有以下:

  1. freemark
  2. velocty
  3. thymleaf

基本语法

一个常规的jsp页面必须包含以下页面声明:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

另外文件的后缀必须是以*.jsp结尾

java代码块

jsp中一段可执行的Java代码必须包含在一对<% 这个里面编写Java代码 %>

<%
    for (int i = 1; i < 10 ; i++) {
        for (int j = 1; j <= i ; j++) {
            System.out.print(j+"*"+i+"="+(i*j)+" ");
        }
        System.out.println();
    }
%>

输出

jsp中对于需要在输出到网页中的内容使用<%=输入的内容 %>

<%
	String s = "hello jsp";
%>
<%=s %>

输出的变量之后不需要添加“;”结尾

通过输出的内容为一个变量

JSP运行原理

  1. 服务器启动后,当前请求第一次到达指定的jsp
  2. 服务会使用jsp引擎对jsp进行编译操作,将jsp页面编译为一个Java类(Servlet)
  3. 通过Java编译器对servlet编译
  4. 然后运行编译之后的字节码文件,将需要传输到客户端的数据以流的形式输出到客户端

JSP运行的时候web容器会将其转换为一个Servlet,因此JSP本质就是一个Servlet;通过到web容器(服务器)的工作目录(work)中即可找到原理。

内置对象

内置对象,也称之为内建对象,即无需创建可直接使用的对象,在jsp中主要包含九大内置对象:

  1. request 即 HttpServletRequest
  2. response 即 HttpServletResponse
  3. session 即 HttpSession
  4. application 即 ServletContext
  5. page 即 this
  6. pageContext servlet中不存在该对象,仅仅在jsp才存在,就是PageContext对象
  7. config 即 ServletConfig
  8. out 即 PrintWriter
  9. exception

四大作用域

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LPCvBYLf-1598793028847)(D:\带班资料\2020\j2003\线下\part5-javaweb\20200825\笔记\assets\1598338927122.png)]

servlet(jsp)中,缓存数据的对象主要包含以下4个,并且这四个对象对于数据的存储作用域存在区别:

  1. PageContext pageContext

    存储在pageContext范围的数据只针对当前页面生效

  2. HttpServletRequest request

    存储在request范围内的数据针对一次请求生效(请求转发)

  3. HttpSession session

    存储在session范围内的数据针对整个会话生效(浏览器不关闭,session未到有效期)

  4. ServletContext application

    存储在application范围的数据,针对所有访问的客户端都生效,只要服务器不关闭

以上四个对象都包含以下方法:

  • setAttribute 向当前作用域存储数据,数据以键值对结构存储(类似Map)
  • getAttribute 根据键名获取存储的值,值是Object类型

三大指令

jsp中包含三大基本指令

  • <%@ page %>

    page指令用于声明当前页面是jsp页面,并且可以进行基础配置,比如编码,el表达式开启或关闭等

  • <%@ include %>

    静态包含,可以将其他的jsp页面包含到当前页面中:

    <%@ include file="reg.jsp" %>
    
  • <%@ taglib %>

    标签库指令,用于导入JSTL标签库相关的信息

    <%@ taglib prefix="c" url="" %>
    

EL表达式与JSTL

基于Servlet3.0 的文件上传和下载
前言

在Servlet2.5中,我们要实现文件上传功能时,一般都需要借助第三方开源组件,例如Apache的commons-fileupload组件,在Servlet3.0中提供了对文件上传的原生支持,我们不需要借助任何第三方上传组件,直接使用Servlet3.0提供的API就能够实现文件上传功能了。

文件域和表单的enctype属性

一、关于HTML 标签的 enctype 属性

application/x-www-form-urlencoded:在发送前编码所有字符(默认)

multipart/form-data: 不对字符编码,或在使用包含文件上传控件的表单时,必须使用该值。

text/plain:空格转换为 “+” 加号,但不对特殊字符编码。

二、enctype:规定了form表单在发送到服务器时候编码方式,有如下的三个值。

1、application/x-www-form-urlencoded。默认的编码方式。但是在用文本的传输和MP3等大型文件的时候,使用这种编码就显得 效率低下。

2、multipart/form-data 。 指定传输数据为二进制类型,比如图片、mp3、文件。

3、text/plain。纯文体的传输。空格转换为 “+” 加号,但不对特殊字符编码。

简单的说,在我们要进行文件上传时应该设置表单组件的enctype属性为multipart/form-data,已二进制的方式提交表单,从而可以提交上传各种类型的文件

    <fieldset>
      <legend>上传单个文件legend>
      <form action="upload" method="post" enctype="multipart/form-data">
        上传文件: <input type="file" name="myFile"><br>
        <input type="submit" value="上传">
      form>
    fieldset>
  <fieldset>
      <legend>上传多个文件legend>
    <form action="upload" method="post" enctype="multipart/form-data">
      上传文件: <input type="file" name="myFile"><br>
      上传文件: <input type="file" name="myFile"><br>
      <input type="submit" value="上传">
    form>
  fieldset>
@MultipartConfig注解和Part对象

Servlet3.0 提供了@MultipartConfig注解,让我们的servlet能够接受来自客户端提交的二进制数据,通过request对象的getPart/getParts方法即可从请求中提取上传的文件信息

@WebServlet("/upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {
        @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Collection<Part> partList = req.getParts(); //获取当前表单中提交的所有文件,返回一个集合
        Part part = req.getPart("name"); //根据文件域所对应的name提取单个文件
    }
}

当获取了part对象后,可以利用part提供的api进一步获取文件的相关信息

        	Part part = req.getPart("myFile");
            String header = part.getHeader("content-disposition");//获取mime头信息
            String fileName = part.getSubmittedFileName(); //获取文件名
            long size = part.getSize(); //获取文件大小
            String type = part.getContentType(); //获取文件类型
            System.out.println(fileName);
            System.out.println(size);
            System.out.println(type);

针对之前的HTML案例,我们可以编写一个用于接收一个或多个文件的上传的servlet

package com.softeem.upload;

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.File;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.UUID;

@WebServlet("/upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Collection<Part> partList = req.getParts();
        req.setCharacterEncoding("utf-8");
        if(partList.size()==1){
            Part part = req.getPart("myFile");
            String header = part.getHeader("content-disposition");
            String fileName = part.getSubmittedFileName(); //获取文件名
            long size = part.getSize(); //获取文件大小
            String type = part.getContentType(); //获取文件类型
            System.out.println(fileName);
            System.out.println(size);
            System.out.println(type);
            String path = req.getServletContext().getRealPath("/upload")+File.separator+UUID.randomUUID()+fileName;
            part.write(path);
        }else{
            for (Part part : partList) {
                String fileName = part.getSubmittedFileName();
                String path = req.getServletContext().getRealPath("/upload") + File.separator + UUID.randomUUID() + fileName;
                part.write(path);
                req.getRequestDispatcher("/getFiles").forward(req,resp);
            }
        }
    }
}

知识点:

request.getServletContext(): 获取当前上下文/容器对象

ServletContext.getRealPath(“path”): 返回上下文目录中某个文件/文件夹的完整路径

UUID.randomUUID(): 根据UUID获取一个32位随机字符

文件下载

要实现下载非常简单,只需要向浏览器声明content-disposition标明attachment即可,如果不标识这个信息,浏览器会直接打开该文件(如果浏览器可以打开,如图片,文档等),如果打不开也会激活下载

大致思路就是,我们通过一个输入流,读取想要让客户端下载的文件字节,然后通过输出流写到客户端即可,基本的IO操作

package com.softeem.upload;


import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
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;

@WebServlet("/down")
public class DownLoadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
//        String fileName = new String(req.getParameter("fileName").getBytes("iso-8859-1"),"utf-8");
        String fileName =req.getParameter("fileName");
        System.out.println(fileName);
        String path = req.getServletContext().getRealPath("/upload");
        File f= new File(path+File.separator+fileName);
        resp.setCharacterEncoding("utf-8");
        resp.setHeader("Content-Disposition", "attachment;fileName=" + fileName);
        System.out.println(f);
        try{
            InputStream input = new FileInputStream(f);
            ServletOutputStream out = resp.getOutputStream();
            byte[] buffer = new byte[1024];
            int len =0;
            while((len=input.read(buffer))!=-1){
                out.write(buffer);
            }
            input.close();
            out.close();
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }
}

基于Servlet3.0 的文件上传和下载
前言

在Servlet2.5中,我们要实现文件上传功能时,一般都需要借助第三方开源组件,例如Apache的commons-fileupload组件,在Servlet3.0中提供了对文件上传的原生支持,我们不需要借助任何第三方上传组件,直接使用Servlet3.0提供的API就能够实现文件上传功能了。

文件域和表单的enctype属性

一、关于HTML 标签的 enctype 属性

application/x-www-form-urlencoded:在发送前编码所有字符(默认)

multipart/form-data: 不对字符编码,或在使用包含文件上传控件的表单时,必须使用该值。

text/plain:空格转换为 “+” 加号,但不对特殊字符编码。

二、enctype:规定了form表单在发送到服务器时候编码方式,有如下的三个值。

1、application/x-www-form-urlencoded。默认的编码方式。但是在用文本的传输和MP3等大型文件的时候,使用这种编码就显得 效率低下。

2、multipart/form-data 。 指定传输数据为二进制类型,比如图片、mp3、文件。

3、text/plain。纯文体的传输。空格转换为 “+” 加号,但不对特殊字符编码。

简单的说,在我们要进行文件上传时应该设置表单组件的enctype属性为multipart/form-data,已二进制的方式提交表单,从而可以提交上传各种类型的文件

    <fieldset>
      <legend>上传单个文件legend>
      <form action="upload" method="post" enctype="multipart/form-data">
        上传文件: <input type="file" name="myFile"><br>
        <input type="submit" value="上传">
      form>
    fieldset>
  <fieldset>
      <legend>上传多个文件legend>
    <form action="upload" method="post" enctype="multipart/form-data">
      上传文件: <input type="file" name="myFile"><br>
      上传文件: <input type="file" name="myFile"><br>
      <input type="submit" value="上传">
    form>
  fieldset>
@MultipartConfig注解和Part对象

Servlet3.0 提供了@MultipartConfig注解,让我们的servlet能够接受来自客户端提交的二进制数据,通过request对象的getPart/getParts方法即可从请求中提取上传的文件信息

@WebServlet("/upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {
        @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Collection<Part> partList = req.getParts(); //获取当前表单中提交的所有文件,返回一个集合
        Part part = req.getPart("name"); //根据文件域所对应的name提取单个文件
    }
}

当获取了part对象后,可以利用part提供的api进一步获取文件的相关信息

        	Part part = req.getPart("myFile");
            String header = part.getHeader("content-disposition");//获取mime头信息
            String fileName = part.getSubmittedFileName(); //获取文件名
            long size = part.getSize(); //获取文件大小
            String type = part.getContentType(); //获取文件类型
            System.out.println(fileName);
            System.out.println(size);
            System.out.println(type);

针对之前的HTML案例,我们可以编写一个用于接收一个或多个文件的上传的servlet

package com.softeem.upload;

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.File;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.UUID;

@WebServlet("/upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Collection<Part> partList = req.getParts();
        req.setCharacterEncoding("utf-8");
        if(partList.size()==1){
            Part part = req.getPart("myFile");
            String header = part.getHeader("content-disposition");
            String fileName = part.getSubmittedFileName(); //获取文件名
            long size = part.getSize(); //获取文件大小
            String type = part.getContentType(); //获取文件类型
            System.out.println(fileName);
            System.out.println(size);
            System.out.println(type);
            String path = req.getServletContext().getRealPath("/upload")+File.separator+UUID.randomUUID()+fileName;
            part.write(path);
        }else{
            for (Part part : partList) {
                String fileName = part.getSubmittedFileName();
                String path = req.getServletContext().getRealPath("/upload") + File.separator + UUID.randomUUID() + fileName;
                part.write(path);
                req.getRequestDispatcher("/getFiles").forward(req,resp);
            }
        }
    }
}

知识点:

request.getServletContext(): 获取当前上下文/容器对象

ServletContext.getRealPath(“path”): 返回上下文目录中某个文件/文件夹的完整路径

UUID.randomUUID(): 根据UUID获取一个32位随机字符

文件下载

要实现下载非常简单,只需要向浏览器声明content-disposition标明attachment即可,如果不标识这个信息,浏览器会直接打开该文件(如果浏览器可以打开,如图片,文档等),如果打不开也会激活下载

大致思路就是,我们通过一个输入流,读取想要让客户端下载的文件字节,然后通过输出流写到客户端即可,基本的IO操作

package com.softeem.upload;


import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
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;

@WebServlet("/down")
public class DownLoadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
//        String fileName = new String(req.getParameter("fileName").getBytes("iso-8859-1"),"utf-8");
        String fileName =req.getParameter("fileName");
        System.out.println(fileName);
        String path = req.getServletContext().getRealPath("/upload");
        File f= new File(path+File.separator+fileName);
        resp.setCharacterEncoding("utf-8");
        resp.setHeader("Content-Disposition", "attachment;fileName=" + fileName);
        System.out.println(f);
        try{
            InputStream input = new FileInputStream(f);
            ServletOutputStream out = resp.getOutputStream();
            byte[] buffer = new byte[1024];
            int len =0;
            while((len=input.read(buffer))!=-1){
                out.write(buffer);
            }
            input.close();
            out.close();
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }
}

你可能感兴趣的:(java,servlet,session)