EL 表达式、JSTL 标签库、文件上传与下载

EL 表达式 与 JSTL 标签库

EL 表达式

EL 表达式概述以及它的作用

EL 表达式的全称是:Expression Language,即 表达式语言。

EL 表达式的作用:主要是为了替代 jsp 页面中的表达式脚本在 jsp 页面中进行数据输出。因为 EL 表达式在输出数据的时候,要比 jsp 的表达式脚本要简洁很多。

EL 表达式的格式: ${ 表达式 }

EL 表达式在输出 null 值的时候,输出的是空串。 jsp 表达式脚本输出 null 值的时候,输出的是 null 字符串。

EL 表达式的搜索域的顺序

EL 表达式主要是在 jsp 页面中进行数据输出,而且主要是输出域中对象的数据。

当 jsp 四大域对象都有相同 key 属性时,EL 表达式会按照四个域的从小到大的排序去进行搜索,找到就进行输出。

1
2
3
4
5
6
7
8
9
<body>
<%
pageContext.setAttribute("key", "pageContext");
request.setAttribute("key", "request");
session.setAttribute("key", "session");
application.setAttribute("key", "application");
%>
${ key } <%-- 从域范围最小开始向上查找对应 key 值,若找到则直接返回 key 对应的 value 值 --%>
</body>

(用 EL 表达式输出 Bean 的普通属性、数组属性、List 集合属性、map 集合属性):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<body>
<%
String name = "Tom";
String[] phones = new String[]{"100", "110", "119"};
List<String> hobbys = new ArrayList<>();
hobbys.add("C++");
hobbys.add("Java");
hobbys.add("Python");
Map<String, String> cities = new HashMap<>();
cities.put("key1", "Bejing");
cities.put("key.1", "ChengDu");
cities.put("key3", "FuJian");
Person p = new Person(name, phones, hobbys, cities);
pageContext.setAttribute("p", p);
%>

输出 Person 对象:${ p } <br />
输出 Person 的 name 属性:${ p.name } <br />
输出 Person 的 Phones 数组属性:${ p.phones} <br />
输出 Person 的 Phones 数组的元素值:${ p.phones[2] } <br />
素材 Person 的 List 集合: ${ p.hobbys } <br />
输出 Person 的 List 集合中的个别元素值:${ p.hobbys[1] } <br />
输出 Person 的 Map 集合: ${ p.cities } <br />
输出 Person 的 Map 集合中某个 key 的值:${ p.cities.key3 }, ${ p.cities["key1"] }, ${p.cities["key.1"]} <br />
</body>

EL 表达式的运算

语法格式:${ 运算表达式 },EL表达式支持如下运算符:

  1. 关系运算符

    关系运算符 说 明 范 例 结果
    == 或 eq 等于 ${ 5 == 5 } 或 ${ 5 eq 5 } ture
    != 或 ne 不等于 ${ 5 !=5 } 或${ 5 ne 5 } false
    < 或 lt 小于 ${ 3 < 5 } 或${ 3 lt 5 } true
    &rt; 或 gt 大于 ${ 2 > 10 } 或${ 2 gt 10 } false
    ≤ 或 le 小于等于 ${ 5 <= 12 } 或${ 5 le 12 } true
    ≥ 或 ge 大于等于 ${ 3 >= 5 } 或${ 3 ge 5 } false
  2. 逻辑运算符

    关系运算符 说 明 范 例 结果
    && 或 and 与运算 ${ 12 == 12 && 12 < 11 } 或 ${ 12 == 12 and 12 < 11 } false
    || 或 or 或运算 ${ 12 == 12 || 12 < 11 } 或 ${ 12 == 12 or 12 < 11 } true
    ! 或 not 取反运算 ${ !true } 或 ${not true } false
  3. 算数运算符

    关系运算符 说 明 范 例 结果
    + 加法 ${ 12 + 18 } 30
    - 减法 ${ 18 - 8 } 10
    * 乘法 ${ 12 * 12 } 144
    / 或 div 除法 ${ 144 / 12 } 或 ${ 144 div 12 } 12
    % 或 mod 取模 ${ 144 % 10 } 或 ${ 144 mod 10 } 4
  4. empty 运算

    empty 运算可以判断是否未空,如果为空,则输出 ture,不为空则输出 false。

    以下几种情况为空:

    1. 值为 null 值时
    2. 值为 空串 时
    3. 值是 Object 类型数组,长度为 0 时
    4. list 集合、map 集合元素个数为 0 时
  5. 三元运算

    格式:表达式1 ? 表达式2 : 表达式3

    ​ 如果表达式 1 的值为真,返回表达式 2 的值,如果表达式 1 的值为假,返回表达式 3 的值。

    示例:${ 12 == 12 ? "Yes!" : "No!" }

  6. “.” 运算 和 “[]” 中括号运算

    “.” 运算,可以输出 Bean 对象中的某个属性的值。

    “[]” 运算,可以输出有序集合中某个元素的值。并且该运算符可以输出 map 中 key 含有特殊字符的 key 值。

EL 表达式中的 11 个隐含对象

EL 表达式中 11 个隐含对象,是 EL 表达式中自己定义的,可以直接使用。

变量名 类型 作用
pageContext PageContextImpl 它可以获取 jsp 中的九大内置对象
pageScope Map < String,Object > 它可以获取 pageContext 域中的数据
requestScope Map < String,Object > 它可以获取 Request 域中的数据
sessionScope Map < String,Object > 它可以获取 Session 域中的数据
aplicationScope Map < String,Object > 它可以获取 ServletContext 域中的数据
param Map < String,String > 它可以获取请求参数的值
paramValues Map < String,String[] > 它也可以获取请求参数的值,获取多个值的时候使用
header Map < String,String > 它可以获取请求头的信息
headerValues Map < String,String[] > 它可以获取请求头的信息,它可以获取多个值的情况
cookie Map < String,Cookie > 它可以获取当前请求的 Cookie 信息
initParam Map < String,String > 它可以获取在 web.xml 中配置的上下文参数
  1. 获取 jsp 四个域对象 pageScope、requestScope、sessionScope、aplicationScope 的属性方法:**域变量名.key**

  2. pageContext 对象获取以下属性示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <body>
    <%
    pageContext.setAttribute("req", request);
    %>
    协议:${req.scheme} <br />

    工程路径:${req.contextPath} <br />

    请求方法:${req.method} <br />

    客户端 IP:${req.remoteHost} <br />

    服务器 IP:${req.serverName} <br />

    服务器端口号:${req.serverPort} <br />

    会话的 ID 编号:${req.session.id} <br />
    </body>

JSTL 标签库

JSTL 标签库的作用以及组成

JSTL 标签库的全称是 JSP Standard Tag Library JSP 标准标签库,是一个不断完善的开放源代码的 JSP 标签库。

EL 表达式主要是为了替换 jsp 中的表达式脚本,而标签库是为了替换代码脚本。这样使得整个 jsp 页面变得更加简洁。

JSTL 由五组不同的标签库组成:

功能范围 URI 前缀
核心标签库(重点) http://java.sun.com/jsp/jstl/core c
格式化 http://java.sun.com/jsp/jstl/fmt fmt
函数 http://java.sun.com/jsp/jstl/functions fn
数据库(不使用) http://java.sun.com/jsp/jstl/sql sql
XML(不使用) http://java.sun.com/jsp/jstl/xml x

JSTL 标签库的使用

使用 JSTL 标签库需要导入 JSTL 标签库的 jar 包以及在 jsp 标签库中使用 taglib 指令引入标签库,如下对应标签库标签:

CORE 标签库

1
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

XML 标签库

1
<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>

FMT 标签库

1
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

SQL 标签库

1
<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>

FUNCTIONS 标签库

1
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

JSTL 常见标签的使用

  1. 设置四个域对象中的值:

    1
    <c:set scope="page|request|session|application" val="属性名" value="属性值" />
  2. if 判断标签:

    1
    <c:if test="判断的条件(EL表达式)"> 输出的内容 </c:if>`
  3. 多路判断标签(类似 switch … case … default …):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      <c:choose> 
    <c:when test="EL表达式判断条件1">
    条件1成立执行内容
    </c:when>
    <c:when test="EL表达式判断条件2">
    条件2成立执行内容
    </c:when>
    ...
    <c:otherwise>
    when 中条件都不成立执行 otherwise 中的语句
    </c:otherwise>
    </c:choose>
  4. forEach 遍历标签:

    普通数值的遍历:

    1
    2
    3
    <c:forEach begin="开始索引值" end="结束值" step="步长" var="循环的遍历变量" varStatus="表示当前遍历到的数据状态">
    循环内容
    </c:forEach>

    Object 数组对象、Map、List 集合的遍历:

    1
    2
    3
    <c:forEach items="EL表达式获取到的数组" var="循环的遍历变量名" varStatus="表示当前遍历到的数据状态">
    循环内容
    </c:forEach>

文件的上传与下载

1. 上传与下载常用 API

上传常用

可以使用第三方 jar 包,进行对上传到服务器的数据进行解析:

​commons-fileupload.jar (依赖 commons-io.jar )

在 commons-fileupload 和 commons-io 包中常用的类与其方法:

ServletFileUpload 类:用于解析上传的数据

​`boolean ServletFileUpload.isMultipartContext(HttpServletRequest request)`

​用于判断当前上传的数据格式是否是多段格式。true 表示为当前数据是多段数据,反之亦然。

​`public List<FileItem> parseRequest(HttpServletRequest request)`

​解析上传的数据

FileItem 类:表示每个表单项

​`boolean FileItem.isFormField()`

​判断当前这个表单项,是否是普通的表单项,还是上传文件的表单项。true 表示前者,false 表示后者

​`String FileItem.getFieldName()`

​获取表单项的 name 属性值

​`String FileItem.getString()`
​获取当前表单项的值

​`String FileItem.getName()`

​获取上传的文件名

​`void FileItem.write(file)`
​将上传的文件写到参数 file 所指向的硬盘位置

下载常用

servletContext.getMimeType()

​ 获取下载的文件类型

response.setContentType()

​ 告诉浏览器下载的文件数据类型

response.setHeader()

​ 将参数 “Content-Disposition” 与 “attachement; fileName=” + fileName 传入,告诉浏览器这是下载操作

response.getOutputStream()

​ 获取服务器响应的输出流

servletContext.getResourceAsStream()

​ 获取服务器上文件内容的文件输入流

2. 文件的上传

  1. 要有一个 form 标签,并且 method 属性值为 post 请求(get 请求有长度限制,所以一般使用 post 请求)

  2. form 标签的 encType 属性值必须为 multipart/form-data 值(表示提交的数据,以多段的数据进行拼接)

  3. 在 form 标签中使用 input type = file 添加上传的文件

  4. 编写服务器代码接收,处理上传的数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    // 这里设置浏览器页面和服务器的编码一致,保证传输数据不会出现乱码
    resp.setContentType("text/html; charset=UTF-8");

    // 判断上传的数据是否是多段数据
    if (ServletFileUpload.isMultipartContent(req)){

    // 创建 FileItemFactory 工厂实现类
    FileItemFactory fileItemFactory = new DiskFileItemFactory();

    // 创建用于解析上传数据的 ServletFileUpload 工具类
    ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);

    try {
    // 解析上传的数据得到每一个表单项
    List<FileItem> list = servletFileUpload.parseRequest(req);

    PrintWriter writer = resp.getWriter();
    // 判断表单项是否为普通表单项还是文件上传表单项
    for (FileItem item : list){
    if (item.isFormField()){
    String fieldName = item.getFieldName();
    String value = item.getString("UTF-8");
    writer.print(fieldName + " = " + value);
    } else {
    // 获取文件名,上传文件到 File 指向的位置
    String fileName = item.getName();
    item.write(new File("D://" + fileName));
    writer.print("上传成功!");
    }
    }
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

3. 文件的下载

  1. 获取要下载的文件名

  2. 读取要下载的文件内容

  3. 将文件类型告诉给浏览器

  4. 通过响应头告诉浏览器返回给浏览器的内容是用于下载使用的

  5. 将文件内容回传给浏览器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    String path = "/file/";
    // 1. 获取要下载的文件名
    String fileName = req.getParameter("fileName");

    // 2. 读取要下载的文件内容
    ServletContext servletContext = getServletContext();
    InputStream resourceAsStream = servletContext.getResourceAsStream(path + fileName);

    // 3. 将文件类型返回给浏览器
    String mimeType = servletContext.getMimeType(path + fileName);
    System.out.println("文件类型为:" + mimeType);
    resp.setContentType(mimeType);

    // 4. 通过响应头告诉浏览器,返回的内容是用于下载使用的
    resp.setHeader("Content-Disposition", "attachment;fileName="+ fileName);

    // 5. 将文件内容会传给浏览器
    ServletOutputStream outputStream = resp.getOutputStream();
    IOUtils.copy(resourceAsStream, outputStream); // 用 commons-io 包下的 IOUtils