1、EL表达式简介
EL 全名为Expression Language。
EL表达式
不能嵌套${${}}
EL主要作用:
获取数据:
EL表达式主要用于替换JSP页面中的脚本表达式,以从各种类型的web域 中检索java对象、获取数据。(某个web域 中的对象,访问javabean的属性、访问list集合、访问map集合、访问数组)
执行运算:
利用EL表达式可以在JSP页面中执行一些基本的关系运算、逻辑运算和算术运算,以在JSP页面中完成一些简单的逻辑运算。${user==null}
获取web开发常用对象
EL 表达式定义了一些隐式对象,利用这些隐式对象,web开发人员可以很轻松获得对web常用对象的引用,从而获得这些对象中的数据。
调用Java方法
EL表达式允许用户开发自定义EL函数,以在JSP页面中通过EL表达式调用Java类的方法。
获取数据:
EL表达式主要用于替换JSP页面中的脚本表达式,以从各种类型的web域 中检索java对象、获取数据。(某个web域 中的对象,访问javabean的属性、访问list集合、访问map集合、访问数组)
执行运算:
利用EL表达式可以在JSP页面中执行一些基本的关系运算、逻辑运算和算术运算,以在JSP页面中完成一些简单的逻辑运算。${user==null}
获取web开发常用对象
EL 表达式定义了一些隐式对象,利用这些隐式对象,web开发人员可以很轻松获得对web常用对象的引用,从而获得这些对象中的数据。
调用Java方法
EL表达式允许用户开发自定义EL函数,以在JSP页面中通过EL表达式调用Java类的方法。
(1)、获取数据
使用EL表达式获取数据语法:
“${标识符}”
EL表达式语句在执行时,会调用 pageContext.findAttribute方法,用标识符为关键字,分别从 page、request、session、application四个域中查找相应的对象,找到则返回相应对象, 找不到则返回”” (注意,不是null,而是空字符串)。
示例:${user}
EL表达式语句在执行时,会调用 pageContext.findAttribute方法,用标识符为关键字,分别从 page、request、session、application四个域中查找相应的对象,找到则返回相应对象, 找不到则返回”” (注意,不是null,而是空字符串)。
示例:${user}
EL表达式也可以很轻松获取JavaBean的属性,或获取数组、Collection、Map类型集合的数据,例如:
- ${user.address.city}
- ${user.list[0]}:访问有序集合某个位置的元素
- ${map.key} : 获得map集合中指定key的值
- 迭代数组
- 迭代collection类型集合
- 迭代map类型集合
(2)、执行运算
语法:${运算表达式},EL表达式支持如下运算符:
数学运算与逻辑运算
empty运算符:检查对象是否为null或“空”,
很好用!!! 判断传送过来的map,list进行迭代:$"{!empty(list)}
二元表达式:${user!=null?user.name : “”} , 很好用!!! 判断如果登录就显示用户名,否则啥都不显示
[ ] (取动态变量的值)和 . 号运算符
二元表达式:${user!=null?user.name : “”} , 很好用!!! 判断如果登录就显示用户名,否则啥都不显示
[ ] (取动态变量的值)和 . 号运算符
<%
User user = new User();
user.setGender("male");
//数据回显
request.setAttribute("user",user);
%>
<input type="radio" name="gender" value="male" ${user.gender=='male'?'checked':'' }>男
<input type="radio" name="gender" value="female" ${user.gender=='female'?'checked':'' }>女
<br/>
(3)、获得web开发常用对象
EL表达式语言中定义了
11个隐含对象,使用这些隐含对象可以很方便地获取web开发中的一些常见对象,并读取这些对象的数据。
语法: ${隐式对象名称} :获得对象的引用
语法: ${隐式对象名称} :获得对象的引用
隐含对象 | 描述 |
pageContext | 对应于JSP页面中的pageContext对象(注意:取的是pageContext对象。) |
pageScope | 代表page域中用于保存属性的Map对象 |
requestScope | 代表request域中用于保存属性的Map对象 |
sessionScope | 代表session域中用于保存属性的Map对象 |
applicationScope | 代表application域中用于保存属性的Map对象 |
param | 表示一个保存了所有请求参数的Map对象 |
paramValues | 表示一个保存了所有请求参数的Map对象,它对于某个请求参数,返回 的是一个string[] |
header | 表示一个保存了所有http请求头字段的Map对象 |
headerValues | 同上,返回string[]数组。注意:如果头里面有“-” ,例Accept-Encoding, 则要headerValues[“Accept-Encoding”] |
cookie | 表示一个保存了所有cookie的Map对象 |
initParam | 表示一个保存了所有web应用初始化参数的map对象 |
注意事项
- 测试headerValues时,如果头里面有“-” ,例Accept-Encoding,则要headerValues[“Accept-Encoding”]
- 测试cookie时,例${cookie.key}取的是cookie对象,如访问cookie的名称和值,须${cookie.key.name}或${cookie.key.value}
示例:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>el隐式对象</title>
</head>
<body>
${pageContext } <!-- pageContext.findAttribute("name") -->
<br/>
<br/>---------------从指定的page域中查找数据------------------------<br/>
<%
pageContext.setAttribute("name","aaa"); //map
%>
${pageScope.name }
<br/>---------------从request域中获取数据------------------------<br/>
<%
request.setAttribute("name","bbb"); //map
%>
${requestScope.name }
<br/>---------------从session域中获取数据------------------------<br/>
${sessionScope.user }
<br/>--------------获得用于保存请求参数map,并从map中获取数据------------------------<br/>
<!-- http://localhost:8080/day12/3.jsp?name=aaa -->
${param.name }
<!-- 此表达式会经常用在数据回显上 -->
<form action="${pageContext.request.contextPath }/servlet/RegisterServlet" method="post">
<input type="text" name="username" value="${param.username }">
<input type="submit" value="注册">
</form>
<br/>--------------paramValues获得请求参数 //map{"",String[]}------------------------<br/>
<!-- http://localhost:8080/day12/3.jsp?like=aaa&like=bbb -->
${paramValues.like[0] }
${paramValues.like[1] }
<br/>--------------header获得请求头------------------------<br/>
${header.Accept }
${header["Accept-Encoding"] }
<br/>--------------获取客户机提交的cookie------------------------<br/>
<!-- 从cookie隐式对象中根据名称获取到的是cookie对象,要想获取值,还需要.value -->
${cookie.JSESSIONID.value } //保存所有cookie的map
<br/>--------------获取web应用初始化参数------------------------<br/>
${initParam.xxx } //servletContext中用于保存初始化参数的map
${initParam.root }
</body>
</html>
(4)、使用EL表达式调用Java方法
EL表达式语法允许开发人员开发 自定义函数,以调用Java类的方法。示例:${prefix:method(params)}
- 在EL表达式中调用的只能是Java类的静态方法。
- 这个Java类的静态方法需要在TLD文件中描述,才可以被EL表达式调用。
一般来说,
EL自定义函数开发与应用包括以下
三个步骤:
示例:开发对html标签进行转义的el function
- 编写一个Java类的静态方法
- 编写标签库描述符(tld)文件,在tld文件中描述自定义函数。
- 在JSP页面中导入和使用自定义函数
示例:开发对html标签进行转义的el function
实现类:
A、编写一个包含静态方法的类
package cn.itcast;
import java.util.List;
public class HtmlFilter {
public static String filter(String message,int arr[]) {
System.out.println(arr[0]);
if (message == null)
return (null);
char content[] = new char[message.length()];
message.getChars(0, message.length(), content, 0);
StringBuffer result = new StringBuffer(content.length + 50);
for (int i = 0; i < content.length; i++) {
switch (content[i]) {
case '<':
result.append("<");
break;
case '>':
result.append(">");
break;
case '&':
result.append("&");
break;
case '"':
result.append(""");
break;
default:
result.append(content[i]);
}
}
return (result.toString());
}
}
B、在web-inf\目录下新建一个tld文件,对想被jsp页面调用的函数进行描述
<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<description>A tag library exercising SimpleTag handlers.</description>
<tlib-version>1.0</tlib-version>
<short-name>SimpleTagLibrary</short-name>
<uri>/itcast</uri>
<function>
<name>filter</name>
<function-class>cn.itcast.HtmlFilter</function-class>
<function-signature>java.lang.String filter(java.lang.String,int[])</function-signature>
</function>
</taglib>
C、在jsp页面导入标签库,并调用el函数
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/WEB-INF/itcast.tld" prefix="fn" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP '4.jsp' starting page</title>
</head>
<body>
${fn:filter("<a href=''>点点</a>") }
</body>
</html>
2、JSTL中的常用EL函数
由于在JSP页面中显示数据时,经常需要对显示的字符串进行处理,SUN公司针对于一些常见处理定义了一套EL函数库供开发者使用。这些EL函数在JSTL开发包中进行描述,因此在JSP页面中使用SUN公司的EL函数库, 需要导入JSTL开发包,并在页面中导入EL函数库,如下所示:
在页面中使用JSTL定义的EL函数:
<%@taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
(1)、fn:toLowerCase
fn:toLowerCase函数将一个字符串中包含的所有字符转换为小写形式,并返回转换后的字符串,它接收一个字符串类型的参数,例如fn:toLowerCase("Www.IT315.org") 的返回值为字符串“www.it315.org”
fn:toLowerCase("")的返回值为空字符串
(2)、fn:toUpperCase
fn:toUpperCase函数将一个字符串中包含的所有字符转换为大写形式,并返回转换后的字符串,它接收一个字符串类型的参数。例如:
fn:toUpperCase("Www.IT315.org") 的返回值为字符串“WWW.IT315.ORG”
fn:toUpperCase("")的返回值为空字符串
fn:toUpperCase("Www.IT315.org") 的返回值为字符串“WWW.IT315.ORG”
fn:toUpperCase("")的返回值为空字符串
(3)、fn:trim
fn:trim函数删除一个字符串的首尾的空格,并返回删除空格后的结果字符串,它接收一个字符串类型的参数。需要注意的是,fn:trim函数不能删除字符串中间位置的空格。
例如,fn:trim(" www.it315.org ") 的返回值为字符串“www.it 315.org”。
例如,fn:trim(" www.it315.org ") 的返回值为字符串“www.it 315.org”。
(4)、fn:length
fn:length函数返回一个 集合或 数组大小,或返回 一个字符串中包含的字符的个数,返回值为 int类型。fn:length函数接收一个参数,这个参数可以是<c:forEach>标签的items属性支持的任何类型,包括任意类型的数组、java.util.Collection、java.util.Iterator、java.util.Enumeration、java.util.Map等类的实例对象和字符串。如果fn:length函数的参数为null或者是元素个数为0的集合或数组对象,则函数返回0;如果参数是空字符串,则函数返回0。
(5)、fn:split
fn:split函数以指定字符串作为分隔符,将一个字符串分割成字符串数组并 返回这个 字符串数组。fn:split函数接收两个字符串类型的参数,第一个参数表示要分割的字符串,第二个参数表示作为分隔符的字符串。
例如,fn:split("www.it315.org", ".")[1]的返回值为字符串“it315”。
(6)、fn:join
fn:join函数以一个字符串作为分隔符,将一个 字符串数组中的所有元素 合并为一个字符串并返回合并后的结果 字符串。
fn:join函数接收两个参数,第一个参数是要操作的字符串数组,第二个参数是作为分隔符的字符串。
如果fn:join函数的第二个参数是
空字符串,则fn:join函数的返回值直接将元素连接起来。例如:
假设stringArray是保存在Web域中的一个属性,它表示一个值为{"www","it315","org"}的字符串数组,则fn:join(stringArray, “.")返回字符串“www.it315.org”
fn:join(fn:split("www,it315,org", ","), ".") 的返回值为字符串“www.it315.org”
(7)、fn:indexOf
fn:indexOf函数返回指定字符串在一个字符串中 第一次出现的索引值, 返回值为int类型。
fn:indexOf函数接收两个字符串类型的参数,如果第一个参数字符串中包含第二个参数字符串,那么,不管第二个参数字符串在第一个参数字符串中出现几次,fn:indexOf函数总是返回第一次出现的索引值;如果第一个参数中不包含第二个参数,则fn:indexOf函数返回-1。如果第二个参数为空字符串,则fn:indexOf函数总是返回0。例如:
fn:indexOf("www.it315.org","t3") 的返回值为5
fn:indexOf("www.it315.org","t3") 的返回值为5
(8)、fn:contains
fn:contains函数检测一个字符串中是否包含指定的字符串, 返回值为布尔类型。fn:contains函数在比较两个字符串是否相等时是 大小写敏感的。fn:contains函数接收两个字符串类型的参数,如果第一个参数字符串中包含第二个参数字符串,则fn:contains函数返回true,否则返回false。如果第二个参数的值为空字符串,则fn:contains函数总是返回true。 实际上,fn:contains(string, substring)等价于fn:indexOf(string, substring) != -1。
忽略大小写的EL函数: fn:containsIgnoreCase
(9)、fn:startsWith
fn:startsWith函数用于检测一个字符串是否是以指定字符串开始的, 返回值为布尔类型。fn:startsWith函数接收两个字符串类型的参数,如果第一个参数字符串以第二个参数字符串开始,则函数返回true,否则函数返回false。如果第二个参数为空字符串,则fn:startsWith函数总是返回true。例如:
fn:startsWith("www.it315.org","it315")的返回值为false
与之对应的EL函数:fn:endsWith
(10)、fn:replace
fn:replace函数将一个字符串中包含的指定子字符串替换为其它的指定字符串,并返回替换后的结果字符串。
fn:replace方法接收三个字符串类型的参数,第一个参数表示要操作的源字符串,第二个参数表示源字符串中要被替换的子字符串,第三个参数表示要被替换成的字符串。例如:
fn:replace("www it315 org", " ", ".")的返回值为字符串“www.it315.org”
fn:replace("www it315 org", " ", ".")的返回值为字符串“www.it315.org”
(10)、fn:substring
fn:substring函数用于截取一个字符串的子字符串并 返回截取到的子字符串。
fn:substring函数接收三个参数,第一个参数是用于指定要操作的源字符串,第二个参数是用于指定截取子字符串开始的索引值,第三个参数是用于指定截取子字符串结束的索引值,第二个参数和第三个参数都是int类型,
其值都从0开始。例如:
fn:substring("www.it315.org", 4, 9) 的返回值为字符串“it315”
fn:substring("www.it315.org", 4, 9) 的返回值为字符串“it315”
(11)、fn:substringAfter
fn:substringAfter函数用于截取并返回一个字符串中的指定子字符串 第一次出现之后的子字符串。
fn:substringAfter函数接收两个字符串类型的参数,第一个参数表示要操作的源字符串,第二个参数表示指定的子字符串,例如:
fn:substringAfter(“www.it315.org”, “.”)的返回值为字符串“it315.org”。
与之对应的EL函数为:fn:substringBefore
fn:substringAfter(“www.it315.org”, “.”)的返回值为字符串“it315.org”。
与之对应的EL函数为:fn:substringBefore
(12)、escapeXml
转义函数。
常用例子:
<br/><br/>---------------使用el函数回显数据(重要!!!)---------------------------<br/>
<%
User user = new User();
String likes[] = {"sing","dance"};
user.setLikes(likes);
//数据回显
request.setAttribute("user",user);
%>
<input type="checkbox" name="like" vlaue="sing" ${fn:contains(fn:join(user.likes,","),"sing")?'checked':'' }>唱歌
<input type="checkbox" name="like" value="dance" ${fn:contains(fn:join(user.likes,","),"dance")?'checked':'' }>跳舞
<input type="checkbox" name="like" value="basketball" ${fn:contains(fn:join(user.likes,","),"basketball")?'checked':'' }>蓝球
<input type="checkbox" name="like" value="football" ${fn:contains(fn:join(user.likes,","),"football")?'checked':'' }>足球
${fn:escapeXml("<a href=''>点点点</a>")}
3、JSTL标签库
核心标签库:c.tld国际化标签:fmt.tld
数据库标签:sql.tld
XML标签:x.tld
JSTL函数(EL函数):fn.tld
(1)、核心标签库
A、<c:out>标签
<c:out> 标签用于输出一段文本内容到pageContext对象当前保存的“out”对象中。
属性名 | 是否支持EL | 属性类型 | 属性描述 |
Value | true | Object | 指定要输出的内容 |
escapeXml | true | Boolean | 指定是否将>、<、&、'、" 等特殊字符进行HTML编码 转换后再进行输出。默认值为true |
default | true | Object | 指定如果value属性的值为null时所输出的默认值 |
<br/>-----------------------c:out标签--------------------------------------<br/>
<%
request.setAttribute("data",null);
%>
<c:out value="${data}" escapeXml="true" default="对不起,您要的数据找不着哟!!!"></c:out>
B、<c:set>标签
<c:set>标签用于把某一个对象存在指定的域范围内,或者设置Web域中的java.util.Map类型的属性对象或JavaBean类型的属性对象的属性。
属性名 | 是否支持EL | 属性类型 | 属性描述 |
value | true | Object | 用于指定属性值 |
var | false | String | 用于指定要设置的web域属性的名称 |
scope | false | String | 用于指定属性所在的web域 |
target | true | Object | 用于指定要设置属性的对象,这个对象必须是JavaBean 对象或java.util.Map对象 |
property | true | String | 用于指定当前要为对象设置的属性名称 |
<br/>-----------------------c:set标签:向web存数据,向map或bean中存数据--------------------------------------<br/>
<c:set var="data" value="xxx" scope="page"/>
${pageScope.data }
<%
Map map = new HashMap();
request.setAttribute("map",map);
%>
<c:set property="data" value="yyyyy" target="${map}"/>
${map.data }
<%--<c:set property="name" value="flx" target="${person}"></c:set>--%>
C、<c:remove>标签
<c:remove>标签用于删除各种Web域中的属性。
其语法格式如下:
<c:remove var="varName"
[scope="{page|request|session|application}"] />
其语法格式如下:
<c:remove var="varName"
[scope="{page|request|session|application}"] />
D、<c:catch>标签
<c:catch>标签用于捕获嵌套在标签体中的内容抛出的异常,其语法格式如下:<c:catch [var="varName"]>nested actions</c:catch>
var属性用于标识<c:catch>标签捕获的异常对象,它将保存在page这个Web域中。
var属性用于标识<c:catch>标签捕获的异常对象,它将保存在page这个Web域中。
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=gb2312" %>
<c:catch var="myex“ scope=“page”>
<%
10/0;
%>
</c:catch>
异常:<c:out value="${myex}" /><br />
异常 myex.getMessage:<c:out value="${myex.message}" /><br />
异常 myex.getCause:<c:out value="${myex.cause}" /><br />
异常 myex.getStackTrace:<c:out value="${myex.stackTrace}" />
E、<c:if>标签
<c:if test=“”>标签可以构造简单的“if-then”结构的条件表达式
属性名 | 是否支持EL | 属性类型 | 属性描述 |
test | true | boolean | 决定是否处理标签体中的内容的条件表达式 |
var | false | String | 用于指定将test属性的执行结果保存到某个Web域中 的某个属性的名称 |
scope | false | String | 指定将test属性的执行结果保存到哪个Web域中 |
<br/>-----------------------c:if标签--------------------------------------<br/>
<c:if test="${user==null}" var="b" scope="page"></c:if>
${b }
F、<c:choose>标签
<c:choose>标签用于指定多个条件选择的组合边界,它必须与<c:when>和<c:otherwise>标签一起使用。使用<c:choose>,<c:when>和<c:otherwise>三个标签,可以构造类似 “if-else if-else” 的复杂条件判断结构。
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=gb2312" %>
<c:set value="${param.count}" var="count“ /> pageContext(count,2)
<c:choose>
<c:when test="${count == 0}">
对不起,没有符合您要求的记录。
</c:when>
<c:otherwise>
符合您要求的记录共有${count}条.
</c:otherwise>
</c:choose>
G、<c:forEach>标签
<c:forEach>标签用于对一个集合对象中的元素进行循环迭代操作,或者按指定的次数重复迭代执行标签体中的内容。
属性名 | 是否支持EL | 属性类型 | 属性描述 |
var | false | String | 指定将当前迭代到的元素保存到page这个Web域中的 属性名称 |
items | true | 任何支持的类型 | 将要迭代的集合对象 |
begin | true | int | 如果指定items属性,就从集合中的第begin个元素 开始进行迭代,begin的索引值从0开始编号;如果 没有指定items属性,就从begin指定的值开始迭代, 直到end值时结束迭代 |
end | true | int | 参看begin属性的描述 |
step | true | int | 指定迭代的步长,即迭代因子的迭代增量 |
<br/>-----------------------foreach标签--------------------------------------<br/>
<c:forEach var="num" begin="1" end="10" step="1">
${num }
</c:forEach>
<%
List list = Arrays.asList("1","2");
request.setAttribute("list",list);
%>
<c:forEach var="index" begin="0" end="${fn:length(list)}">
${list[index] }
</c:forEach>
H、<c:param>标签
- 在JSP页面进行URL的相关操作时,经常要在URL地址后面附加一些参数。<c:param>标签可以嵌套在<c:import>、<c:url>或<c:redirect>标签内,为这些标签所使用的URL地址附加参数。
- <c:param>标签在为一个URL地址附加参数时,将自动对参数值进行URL编码,例如,如果传递的参数值为“中国”,则将其转换为“%d6%d0%b9%fa”后再附加到URL地址后面,这也就是使用<c:param>标签的最大好处。
示例:<c:param name="name" value="value" />
I、<c:url>标签
<c:url>标签用于在JSP页面中构造一个URL地址,其主要目的是实现URL重写。URL重写就是将会话标识号以参数形式附加在URL地址后面
属性名 | 是否支持EL | 属性类型 | 属性描述 |
value | true | String | 指定要构造的URL |
var | false | String | 指定将构造出的URL结果保存到Web域中的属性名称 |
scope | false | String | 指定将构造出的URL结果保存到哪个Web域中 |
<br/>-----------------------c:url标签(重点)--------------------------------------<br/>
<c:url value="/servlet/ServletDemo1" var="servletdemo1">
<c:param name="name" value="中国"/>
<c:param name="password" value="我是一个"/>
</c:url>
<a href="${servletdemo1 }">点点</a>
J、<c:redirect>标签
<c:redirect>标签用于实现请求重定向
属性名 | 是否支持EL | 属性类型 | 属性描述 |
url | true | String | 指定要转发或重定向到的目标资源的URL地址 |
context | true | String | 当要使用相对路径重定向到同一个服务器下的其他WEB应用程 序中的资源时,context属性指定其他WEB应用程序的名称 |
(2)、WEB国际化
软件的国际化:软件开发时,要使它能同时应对世界不同地区和国家的访问,并针对不同地区和国家的访问,提供相应的、符合来访者阅读习惯的页面或数据。
国际化又称为 i18n:internationalization
国际化又称为 i18n:internationalization
软件实现国际化,需具备哪些特征:
- 对于程序中固定使用的文本元素,例如菜单栏、导航条等中使用的文本元素、或错误提示信息,状态信息等,需要根据来访者的地区和国家,选择不同语言的文本为之服务。
- 对于程序动态产生的数据,例如(日期,货币等),软件应能根据当前所在的国家或地区的文化习惯进行显示。
A、固定文本元素的国际化
对于软件中的菜单栏、导航条、错误提示信息,状态信息等这些固定不变的文本信息,可以把它们
写在一个properties文件中,并根据不同的国家编写不同的properties文件。这一组properties文件称之为一个资源包。
在JavaAPI中提供了一个 ResourceBundle 类用于描述一个资源包,并且 ResourceBundle类提供了相应的方法getBundle,这个方法可以根据来访者的国家地区自动获取与之对应的资源文件予以显示。
在JavaAPI中提供了一个 ResourceBundle 类用于描述一个资源包,并且 ResourceBundle类提供了相应的方法getBundle,这个方法可以根据来访者的国家地区自动获取与之对应的资源文件予以显示。
a、创建资源包和资源文件
一个资源包中的每个资源文件都必须拥有
共同的基名。除了基名,每个资源文件的名称中还必须有标识其本地信息的附加部分。例如:一个资源包的基名是“myproperties”,则与中文、英文环境相对应的资源文件名则为:
“myproperites_zh.properties” “myproperites_en.properties”
每个资源包都应有一个默认资源文件,这个文件不带有标识本地信息的附加部分。若ResourceBundle对象在资源包中找不到与用户匹配的资源文件,它将选择该资源包中与用户 最相近的资源文件,如果再找不到,则 使用默认资源文件。例如:
myproperites.properties
“myproperites_zh.properties” “myproperites_en.properties”
每个资源包都应有一个默认资源文件,这个文件不带有标识本地信息的附加部分。若ResourceBundle对象在资源包中找不到与用户匹配的资源文件,它将选择该资源包中与用户 最相近的资源文件,如果再找不到,则 使用默认资源文件。例如:
myproperites.properties
b、资源文件的书写格式
资源文件的内容通常采用“关键字=值”的形式,软件根据关键字检索值显示在页面上。一个资源包中的所有资源文件的关键字必须相同,值则为相应国家的文字。
并且资源文件中采用的是properties格式文件,所以文件中的所有字符都必须是ASCII字码,对于像中文这样的非ACSII字符,须先进行编码。(java提供了一个native2ascII命令用于编码)。例:
属性文件是不能保存中文的
并且资源文件中采用的是properties格式文件,所以文件中的所有字符都必须是ASCII字码,对于像中文这样的非ACSII字符,须先进行编码。(java提供了一个native2ascII命令用于编码)。例:
属性文件是不能保存中文的
c、编程实现固定文本的国际化
ResourceBundle类提供了一个静态方法getBundle,该方法用于装载资源文件,并创建ResourceBundle实例:
Locale currentLocale = Locale.getDefault(); //获取当前java虚拟机默认的语言环境
ResourceBundle myResources =ResourceBundle.getBundle(basename, currentLocale);
basename为资源包基名(且必须为完整路径)。
如果与该locale对象匹配的资源包子类找不到。一般情况下,则选用默认资源文件予以显示。
加载资源文件后, 程序就可以调用ResourceBundle 实例对象的 getString 方法获取指定的资源信息名称所对应的值。
String value = myResources.getString(“key");
在WEB应用中实现固定文本的国际化
Locale currentLocale = Locale.getDefault(); //获取当前java虚拟机默认的语言环境
ResourceBundle myResources =ResourceBundle.getBundle(basename, currentLocale);
basename为资源包基名(且必须为完整路径)。
如果与该locale对象匹配的资源包子类找不到。一般情况下,则选用默认资源文件予以显示。
加载资源文件后, 程序就可以调用ResourceBundle 实例对象的 getString 方法获取指定的资源信息名称所对应的值。
String value = myResources.getString(“key");
在WEB应用中实现固定文本的国际化
建立一个resource包,分别建立properties文件
demo1
public static void main(String[] args) {
Locale locale = Locale.getDefault();
ResourceBundle bundle = ResourceBundle.getBundle("cn.itcast.resource.myproperties",Locale.US);
String username = bundle.getString("username");
String password= bundle.getString("password");
System.out.println(username);
System.out.println(password);
}
JSP中实现静态文本国际化:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>login</title>
</head>
<body>
<fmt:setBundle var="bundle" basename="cn.itcast.resource.myproperties" scope="page"/>
<form action="">
<fmt:message key="username" bundle="${bundle}"/><input type="text" name="username"><br/>
<fmt:message key="password" bundle="${bundle}"/><input type="password" name="password"><br/>
<input type="submit" value="<fmt:message key="submit" bundle="${bundle}"/>">
</form>
</body>
</html>
B、动态数据的国际化
数值,货币,时间,日期等数据由于可能在程序运行时动态产生,所以无法像文字一样简单地将它们从应用程序中分离出来,而是需要特殊处理。Java 中提供了解决这些问题的 API 类(位于 java.util 包和 java.text 包中)
Locale 类(没有的利用构造函数构造)
Locale 实例对象代表一个特定的地理,政治、文化区域。
一个 Locale 对象本身不会验证它代表的语言和国家地区信息是否正确,只是向本地敏感的类提供国家地区信息,与国际化相关的格式化和解析任务由本地敏感的类去完成。(若JDK中的某个类在运行时需要根据 Locale 对象来调整其功能,这个类就称为本地敏感类)
Locale 实例对象代表一个特定的地理,政治、文化区域。
一个 Locale 对象本身不会验证它代表的语言和国家地区信息是否正确,只是向本地敏感的类提供国家地区信息,与国际化相关的格式化和解析任务由本地敏感的类去完成。(若JDK中的某个类在运行时需要根据 Locale 对象来调整其功能,这个类就称为本地敏感类)
a、时间日期国际化——DateFormat类
DateFormat 类可以将一个日期/时间对象格式化为表示某个国家地区的日期/时间字符串。
DateFormat 类除了可按国家地区格式化输出日期外,它还定义了一些用于描述日期/时间的显示模式的 int 型的常量,包括FULL, LONG, MEDIUM, DEFAULT, SHORT,实例化DateFormat对象时,可以使用这些常量,控制日期/时间的显示长度。
DateFormat 类除了可按国家地区格式化输出日期外,它还定义了一些用于描述日期/时间的显示模式的 int 型的常量,包括FULL, LONG, MEDIUM, DEFAULT, SHORT,实例化DateFormat对象时,可以使用这些常量,控制日期/时间的显示长度。
例子:
例如,对于日期/时间“2005年9月15日下午4时41分20秒”,如设置了DateFormat的显示模式,则日期/时间显示样式分别为:
SHORT模式完全是数字的,在中文环境下显示为“05-9-15 下午4:41”;在英文环境下为“9/15/05 4:41 PM”。
MEDIUM模式比SHORT模式长些,在中文环境显示为“2005-9-15 16:41:20”;在英文环境下显示为“Sep 15, 2005 4:41:20 PM”。
LONG模式比MEDIUM模式更长一些,在中文环境下显示为“2005年9月15日 下午04时41分20秒”;在英文环境下显示为“September 15, 2005 4:41:20 PM CST”。
FULL模式指定日期/时间的完整格式,在中文环境下显示为“2005年9月15日 星期四 下午04时41分20秒 CST”;在英文环境下,这个日期/时间显示为“Thursday, September 15, 2005 4:41:20 PM CST”。
SHORT模式完全是数字的,在中文环境下显示为“05-9-15 下午4:41”;在英文环境下为“9/15/05 4:41 PM”。
MEDIUM模式比SHORT模式长些,在中文环境显示为“2005-9-15 16:41:20”;在英文环境下显示为“Sep 15, 2005 4:41:20 PM”。
LONG模式比MEDIUM模式更长一些,在中文环境下显示为“2005年9月15日 下午04时41分20秒”;在英文环境下显示为“September 15, 2005 4:41:20 PM CST”。
FULL模式指定日期/时间的完整格式,在中文环境下显示为“2005年9月15日 星期四 下午04时41分20秒 CST”;在英文环境下,这个日期/时间显示为“Thursday, September 15, 2005 4:41:20 PM CST”。
实例化DateFormat类有九种方式,以下三种为带参形式,下面列出的三种方式也可以分别不带参,或只带显示样式的参数。
- getDateInstance(int style, Locale aLocale):以指定的日期显示模式和本地信息来获得DateFormat实例对象,该实例对象不处理时间值部分。
- getTimeInstance(int style, Locale aLocale):以指定的时间显示模式和本地信息来获得DateFormat实例对象,该实例对象不处理日期值部分。
- getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale):以单独指定的日期显示模式、时间显示模式和本地信息来获得DateFormat实例对象。
DateFormat 对象的方法:
format: 将date对象格式化为符合某个本地环境习惯的字符串。
parse:将字符串解析为日期/时间对象
注意:parse和format完全相反,一个是把date时间转化为相应地区和国家的显示样式,一个是把相应地区的时间日期转化成date对象,该方法在使用时,解析的时间或日期要符合指定的国家、地区格式,否则会抛异常。
DateFormat 对象通常不是线程安全的,每个线程都应该创建自己的 DateFormat 实例对象
format: 将date对象格式化为符合某个本地环境习惯的字符串。
parse:将字符串解析为日期/时间对象
注意:parse和format完全相反,一个是把date时间转化为相应地区和国家的显示样式,一个是把相应地区的时间日期转化成date对象,该方法在使用时,解析的时间或日期要符合指定的国家、地区格式,否则会抛异常。
DateFormat 对象通常不是线程安全的,每个线程都应该创建自己的 DateFormat 实例对象
public static void main(String[] args) throws ParseException {
Date date = new Date(); //当前这一刻的时间(日期、时间)
//输出日期部分
DateFormat df = DateFormat.getDateInstance(DateFormat.FULL, Locale.GERMAN);
String result = df.format(date);
System.out.println(result);
//输出时间部分
df = DateFormat.getTimeInstance(DateFormat.FULL, Locale.CHINA);
result = df.format(date);
System.out.println(result);
//输出日期和时间
df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, Locale.CHINA);
result = df.format(date);
System.out.println(result);
//把字符串反向解析成一个date对象
String s = "10-9-26 下午02时49分53秒";
df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, Locale.CHINA);
Date d = df.parse(s);
System.out.println(d);
}
b、数字货币国际化——NumberFormat类
NumberFormat 可以将一个数值格式化为符合某个国家地区习惯的数值字符串,也可以将符合某个国家地区习惯的数值字符串解析为对应的数值
NumberFormat 类的方法:
NumberFormat 类的方法:
- format 方法:将一个数值格式化为符合某个国家地区习惯的数值字符串
- parse 方法:将符合某个国家地区习惯的数值字符串解析为对应的数值。
实例化NumberFormat类时,可以使用locale对象作为参数,也可以不使用,下面列出的是使用参数的。
- getNumberInstance(Locale locale):以参数locale对象所标识的本地信息来获得具有多种用途的NumberFormat实例对象
- getIntegerInstance(Locale locale):以参数locale对象所标识的本地信息来获得处理整数的NumberFormat实例对象
- getCurrencyInstance(Locale locale):以参数locale对象所标识的本地信息来获得处理货币的NumberFormat实例对象
- getPercentInstance(Locale locale):以参数locale对象所标识的本地信息来获得处理百分比数值的NumberFormat实例对象
int price = 89;
NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.CHINA);
String result = nf.format(price);
System.out.println(result);
String s = "¥89.00";
nf = NumberFormat.getCurrencyInstance(Locale.CHINA);
Number n = nf.parse(s);
System.out.println(n.doubleValue()+1);
double num = 0.5;
nf = NumberFormat.getPercentInstance();
System.out.println(nf.format(num));
b、动态文本——MessageFormat
如果一个字符串中包含了多个与国际化相关的数据,可以使用MessageFormat类对这些数据进行批量处理。
例如:
At 12:30 pm on jul 3,1998, a hurricance destroyed 99 houses and caused $1000000 of damage
以上字符串中包含了时间、数字、货币等多个与国际化相关的数据,对于这种字符串,可以使用MessageFormat类对其国际化相关的数据进行批量处理。
MessageFormat 类如何进行批量处理呢?
例如:
At 12:30 pm on jul 3,1998, a hurricance destroyed 99 houses and caused $1000000 of damage
以上字符串中包含了时间、数字、货币等多个与国际化相关的数据,对于这种字符串,可以使用MessageFormat类对其国际化相关的数据进行批量处理。
MessageFormat 类如何进行批量处理呢?
- MessageFormat类允许开发人员用占位符替换掉字符串中的敏感数据(即国际化相关的数据)。
- MessageFormat类在格式化输出包含占位符的文本时,messageFormat类可以接收一个参数数组,以替换文本中的每一个占位符。
At 12:30 pm on jul 3,1998, a hurricance destroyed 99 houses and caused $1000000 of damage
模式字符串:
At {0} on {1},a destroyed {2} houses and caused {3} of damage
模式字符串:
At {0} on {1},a destroyed {2} houses and caused {3} of damage
模式字符串:
On {0}, a hurricance destroyed {1} houses and caused {2} of damage.
On {0}, a hurricance destroyed {1} houses and caused {2} of damage.
MessageFormat类
MessageFormat(String pattern)
实例化MessageFormat对象,并装载相应的模式字符串。
format(object obj[])
格式化输出模式字符串,参数数组中指定占位符相应的替换对象。
format(new Object[ ]{date, new Integer(99), new Double(1E7) })
String pattern = "On {0}, a hurricance destroyed {1} houses and caused "
+ "{2} of damage.";
MessageFormat msgFmt = new MessageFormat(pattern,Locale.US);
//准备参数数组
String datetime = "Jul 3, 1998 12:30 PM";
Date date = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
DateFormat.SHORT, Locale.US).parse(datetime);
Object [] msgArgs = {date, new Integer(99),new Double(1E7)};
//执行格式化操作
String result = msgFmt.format(msgArgs);
System.out.println(result);
占位符有三种方式书写方式:
- {argumentIndex}: 0-9 之间的数字,表示要格式化对象数据在参数数组中的索引号
- {argumentIndex,formatType}: 参数的格式化类型
- {argumentIndex,formatType,FormatStyle}: 格式化的样式,它的值必须是与格式化类型相匹配的合法模式、或表示合法模式的字符串。
String pattern = "At {0, time, short} on {0, date}, a destroyed'\n'"
+ "{1} houses and caused {2, number, currency} of damage.";
MessageFormat msgFmt = new MessageFormat(pattern,Locale.US);
String datetimeString = "Jul 3, 1998 12:30 PM";
Date date = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
DateFormat.SHORT,Locale.US).parse(datetimeString);
String event = "a hurricance";
Object []msgArgs = {date, event, new Integer(99), new Double(1E7)};
String result = msgFmt.format(msgArgs);
System.out.println(result);
C、国际化标签库
a、<fmt:setLocale>标签
<fmt:setLocale value="locale"
[variant="variant"]
[scope="{page|request|session|application}"]/>
<fmt:setLocale>
b、<fmt:setBundle>标签
<fmt:setBundle basename="basename"
[var="varName"]
[scope="{page|request|session|application}"] />
<fmt:setBundle>
basename 指定创建ResourceBundle实例对象的基名
c、<fmt:message>标签
<fmt:message key="username" bundle="${bundle}"/>
占位符:
<fmt:param>标签
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ page contentType="text/html;charset=gb2312" %>
<jsp:useBean id="now" class="java.util.Date" />
<%
session.setAttribute("number", new Integer(8888888));
%>
<fmt:setBundle basename="org.it315.greetings" var="greetings" />
<fmt:message>标签内嵌套<fmt:param>标签的情况:<br />
<fmt:message key="okKey" bundle="${greetings}">
<fmt:param value="${now}" />
<fmt:param value="${number}" />
</fmt:message><br /><hr />
<fmt:message>标签内没有嵌套<fmt:param>标签的情况:<br />
<fmt:bundle basename="org.it315.greetings" prefix="org.it315.">
<fmt:message key="okKey" />
</fmt:bundle>
4、文件的上传与下载
(1)、文件的上传
A、文件上传概述
实现web开发中的文件上传功能,需完成如下二步操作:
<input type=“file”>标签用于在web页面中添加文件上传输入项,设置文件上传输入项时须注意:
- 在web页面中添加上传输入项
- 在servlet中读取上传文件的数据,并保存到本地硬盘中。
<input type=“file”>标签用于在web页面中添加文件上传输入项,设置文件上传输入项时须注意:
- 必须要设置input输入项的name属性,否则浏览器将不会发送上传文件的数据。
- 必须把form的enctype属值设为multipart/form-data.设置该值后,浏览器在上传文件时,将把文件数据附带在http请求消息体中,并使用MIME协议对上传的文件进行描述,以方便接收方对上传数据进行解析和处理
如果表单的提交类型为multipart/form-data的话,在servlet方就不能采用传统方式获取表单数据
如何在Servlet中读取文件上传数据,并保存到本地硬盘中?
Request对象提供了一个getInputStream方法,通过这个方法可以读取到客户端提交过来的数据。但由于用户可能会同时上传多个文件,在servlet端编程直接读取上传数据,并分别解析出相应的文件数据是一项非常麻烦的工作,示例。
为方便用户处理文件上传数据,Apache 开源组织提供了一个用来处理表单文件上传的一个 开源组件( Commons-fileupload ),该组件 性能优异,并且其API 使用极其简单,可以让开发人员轻松实现web文件上传功能,因此在web开发中实现文件上传功能,通常使用Commons-fileupload组件实现。
使用Commons-fileupload组件实现文件上传,需要导入该组件相应的支撑jar包:Commons-fileupload和commons-io。commons-io 不属于文件上传组件的开发jar文件,但Commons-fileupload 组件从1.1 版本开始,它工作时需要commons-io包的支持。
Request对象提供了一个getInputStream方法,通过这个方法可以读取到客户端提交过来的数据。但由于用户可能会同时上传多个文件,在servlet端编程直接读取上传数据,并分别解析出相应的文件数据是一项非常麻烦的工作,示例。
为方便用户处理文件上传数据,Apache 开源组织提供了一个用来处理表单文件上传的一个 开源组件( Commons-fileupload ),该组件 性能优异,并且其API 使用极其简单,可以让开发人员轻松实现web文件上传功能,因此在web开发中实现文件上传功能,通常使用Commons-fileupload组件实现。
使用Commons-fileupload组件实现文件上传,需要导入该组件相应的支撑jar包:Commons-fileupload和commons-io。commons-io 不属于文件上传组件的开发jar文件,但Commons-fileupload 组件从1.1 版本开始,它工作时需要commons-io包的支持。
maven引入:
<!-- 文件上传下载-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
B、
核心API—DiskFileItemFactory
DiskFileItemFactory 是创建 FileItem 对象的工厂,这个工厂类常用方法:
public void setSizeThreshold(int sizeThreshold)
设置内存缓冲区的大小,默认值为10K。当上传文件大于缓冲区大小时, fileupload组件将使用临时文件缓存上传文件。
public void setRepository(java.io.File repository)
指定临时文件目录,默认值为System.getProperty("java.io.tmpdir").
public DiskFileItemFactory(int sizeThreshold, java.io.File repository)
构造函数
public void setSizeThreshold(int sizeThreshold)
设置内存缓冲区的大小,默认值为10K。当上传文件大于缓冲区大小时, fileupload组件将使用临时文件缓存上传文件。
public void setRepository(java.io.File repository)
指定临时文件目录,默认值为System.getProperty("java.io.tmpdir").
public DiskFileItemFactory(int sizeThreshold, java.io.File repository)
构造函数
C、
核心API—ServletFileUpload
ServletFileUpload 负责处理上传的文件数据,并将表单中每个输入项封装成一个
FileItem 对象中。常用方法有:
boolean isMultipartContent(HttpServletRequest request)
判断上传表单是否为multipart/form-data类型
List parseRequest(HttpServletRequest request)
解析request对象,并把表单中的每一个输入项包装成一个fileItem 对象,并返回一个保存了所有FileItem的list集合。
setFileSizeMax(long fileSizeMax)
设置上传文件的最大值
setSizeMax(long sizeMax)
设置上传文件总量的最大值
setHeaderEncoding(java.lang.String encoding)
设置编码格式
setProgressListener(ProgressListener pListener)
设置监听器(常用于进度条)
示例:
package cn.itcast.web.contorller;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
public class UploadServlet3 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try{
//1.得到解析器工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
//2.得到解析器
ServletFileUpload upload = new ServletFileUpload(factory);
//3.判断上传表单的类型
if(!upload.isMultipartContent(request)){
//上传表单为普通表单,则按照传统方式获取数据即可
return;
}
//为上传表单,则调用解析器解析上传数据
List<FileItem> list = upload.parseRequest(request); //FileItem
//遍历list,得到用于封装第一个上传输入项数据fileItem对象
for(FileItem item : list){
if(item.isFormField()){
//得到的是普通输入项
String name = item.getFieldName(); //得到输入项的名称
String value = item.getString();
System.out.println(name + "=" + value);
}else{
//得到上传输入项
String filename = item.getName(); //得到上传文件名 C:\Documents and Settings\ThinkPad\桌面\1.txt
filename = filename.substring(filename.lastIndexOf("\\")+1);
InputStream in = item.getInputStream(); //得到上传数据
int len = 0;
byte buffer[]= new byte[1024];
//用于保存上传文件的目录应该禁止外界直接访问
String savepath = this.getServletContext().getRealPath("/WEB-INF/upload");
System.out.println(savepath);
FileOutputStream out = new FileOutputStream(savepath + "\\" + filename); //向upload目录中写入文件
while((len=in.read(buffer))>0){
out.write(buffer, 0, len);
}
in.close();
out.close();
}
}
}catch (Exception e) {
e.printStackTrace();
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
文件上传的 注意事项:
(1)、为了保证服务器的安全,要把上传文件放到WEB-INF目录下面,禁止外界直接访问。
(2)、中文乱码问题
(3)、windows系统的一个文件夹下不能放超过10000个文件,不能只是用一个文件保存。
哈希算法进行打散
(4)、文件重名问题,唯一的文件名保存