JavaWeb开发与代码的编写(十三)
EL表达式
EL 全名为Expression Language。EL主要作用:
1、获取数据
EL表达式主要用于替换JSP页面中的脚本表达式,以从各种类型的web域 中检索java对象、获取数据。(某个web域 中的对象,访问javabean的属性、访问list集合、访问map集合、访问数组)
2、执行运算
利用EL表达式可以在JSP页面中执行一些基本的关系运算、逻辑运算和算术运算,以在JSP页面中完成一些简单的逻辑运算。${user==null}
3、获取web开发常用对象
EL 表达式定义了一些隐式对象,利用这些隐式对象,web开发人员可以很轻松获得对web常用对象的引用,从而获得这些对象中的数据。
4、调用Java方法
EL表达式允许用户开发自定义EL函数,以在JSP页面中通过EL表达式调用Java类的方法。
获取数据
使用EL表达式获取数据语法:"${标识符}"
EL表达式语句在执行时,会调用pageContext.findAttribute方法,用标识符为关键字,分别从page、request、session、application四个域中查找相应的对象,找到则返回相应对象,找不到则返回”” (注意,不是null,而是空字符串)。
EL表达式可以很轻松获取JavaBean的属性,或获取数组、Collection、Map类型集合的数据
el表达式获取数据范例:
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
2 <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
3 <%@page import="me.gacl.domain.Person"%>
4 <%@page import="me.gacl.domain.Address"%>
5 <!DOCTYPE HTML>
6 <html>
7 <head>
8 <title>el表达式获取数据</title>
9 </head>
10
11 <body>
12 <%
13 request.setAttribute("name","孤傲苍狼");
14 %>
15 <%--${name}等同于pageContext.findAttribute("name") --%>
16 使用EL表达式获取数据:${name}
17 <hr>
18 <!-- 在jsp页面中,使用el表达式可以获取bean的属性 -->
19 <%
20 Person p = new Person();
21 p.setAge(12);
22 request.setAttribute("person",p);
23 %>
24 使用el表达式可以获取bean的属性:${person.age}
25 <hr>
26 <!-- 在jsp页面中,使用el表达式可以获取bean中的。。。。。。。。。的属性 -->
27 <%
28 Person person = new Person();
29 Address address = new Address();
30 person.setAddress(address);
31
32 request.setAttribute("person",person);
33 %>
34 ${person.address.name}
35 <hr>
36 <!-- 在jsp页面中,使用el表达式获取list集合中指定位置的数据 -->
37 <%
38 Person p1 = new Person();
39 p1.setName("孤傲苍狼");
40
41 Person p2 = new Person();
42 p2.setName("白虎神皇");
43
44 List<Person> list = new ArrayList<Person>();
45 list.add(p1);
46 list.add(p2);
47
48 request.setAttribute("list",list);
49 %>
50
51 <!-- 取list指定位置的数据 -->
52 ${list[1].name}
53
54 <!-- 迭代List集合 -->
55 <c:forEach var="person" items="${list}">
56 ${person.name}
57 </c:forEach>
58 <hr>
59 <!-- 在jsp页面中,使用el表达式获取map集合的数据 -->
60 <%
61 Map<String,String> map = new LinkedHashMap<String,String>();
62 map.put("a","aaaaxxx");
63 map.put("b","bbbb");
64 map.put("c","cccc");
65 map.put("1","aaaa1111");
66 request.setAttribute("map",map);
67 %>
68
69 <!-- 根据关键字取map集合的数据 -->
70 ${map.c}
71 ${map["1"]}
72 <hr>
73 <!-- 迭代Map集合 -->
74 <c:forEach var="me" items="${map}">
75 ${me.key}=${me.value}<br/>
76 </c:forEach>
77 <hr>
78 </body>
79 </html>
运行效果如下:
执行运算
语法:${运算表达式},EL表达式支持如下运算符:
1、关系运算符
2、逻辑运算符:
3、empty运算符:检查对象是否为null(空)
4、二元表达式:${user!=null?user.name :""}
5、[ ] 和 . 号运算符
使用EL表达式执行运算范例:
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
2 <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
3 <%@page import="me.gacl.domain.User"%>
4 <!DOCTYPE HTML>
5 <html>
6 <head>
7 <title>el表达式运算符</title>
8 </head>
9
10 <body>
11 <h3>el表达式进行四则运算:</h3>
12 加法运算:${365+24}<br/>
13 减法运算:${365-24}<br/>
14 乘法运算:${365*24}<br/>
15 除法运算:${365/24}<br/>
16
17 <h3>el表达式进行关系运算:</h3>
18 <%--${user == null}和 ${user eq null}两种写法等价--%>
19 ${user == null}<br/>
20 ${user eq null}<br/>
21
22 <h3>el表达式使用empty运算符检查对象是否为null(空)</h3>
23 <%
24
25 List<String> list = new ArrayList<String>();
26 list.add("gacl");
27 list.add("xdp");
28 request.setAttribute("list",list);
29 %>
30 <%--使用empty运算符检查对象是否为null(空) --%>
31 <c:if test="${!empty(list)}">
32 <c:forEach var="str" items="${list}">
33 ${str}<br/>
34 </c:forEach>
35 </c:if>
36 <br/>
37 <%
38 List<String> emptyList = null;
39 %>
40 <%--使用empty运算符检查对象是否为null(空) --%>
41 <c:if test="${empty(emptyList)}">
42 对不起,没有您想看的数据
43 </c:if>
44
45 <br/>
46
47 <h3>EL表达式中使用二元表达式</h3>
48 <%
49 session.setAttribute("user",new User("孤傲苍狼"));
50 %>
51 ${user==null? "对不起,您没有登陆 " : user.username}
52
53 <br/>
54
55 <h3>EL表达式数据回显</h3>
56 <%
57 User user = new User();
58 user.setGender("male");
59 //数据回显
60 request.setAttribute("user",user);
61 %>
62 <input type="radio" name="gender" value="male" ${user.gender=='male'?'checked':''}>男
63 <input type="radio" name="gender" value="female" ${user.gender=='female'?'checked':''}>女
64 <br/>65 </body>
66 </html>
运行结果如下:
获得web开发常用对象
EL表达式语言中定义了11个隐含对象,使用这些隐含对象可以很方便地获取web开发中的一些常见对象,并读取这些对象的数据。
语法:${隐式对象名称}:获得对象的引用
测试EL表达式中的11个隐式对象:
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
2 <!DOCTYPE HTML>
3 <html>
4 <head>
5 <title>el隐式对象</title>
6 </head>
7
8 <body>
9 <br/>---------------1、pageContext对象:获取JSP页面中的pageContext对象------------------------<br/>
10 ${pageContext}
11 <br/>---------------2、pageScope对象:从page域(pageScope)中查找数据------------------------<br/>
12 <%
13 pageContext.setAttribute("name","孤傲苍狼"); //map
14 %>
15 ${pageScope.name}
16 <br/>---------------3、requestScope对象:从request域(requestScope)中获取数据------------------------<br/>
17 <%
18 request.setAttribute("name","白虎神皇"); //map
19 %>
20 ${requestScope.name}
21 <br/>---------------4、sessionScope对象:从session域(sessionScope)中获取数据------------------------<br/>
22 <%
23 session.setAttribute("user","xdp"); //map
24 %>
25 ${sessionScope.user}
26 <br/>---------------5、applicationScope对象:从application域(applicationScope)中获取数据------------------------<br/>
27 <%
28 application.setAttribute("user","gacl"); //map
29 %>
30 ${applicationScope.user}
31 <br/>--------------6、param对象:获得用于保存请求参数map,并从map中获取数据------------------------<br/>
32 <!-- http://localhost:8080/JavaWeb_EL_Study_20140826/ELDemo03.jsp?name=aaa -->
33 ${param.name}
34 <!-- 此表达式会经常用在数据回显上 -->
35 <form action="${pageContext.request.contextPath}/servlet/RegisterServlet" method="post">
36 <input type="text" name="username" value="${param.username}">
37 <input type="submit" value="注册">
38 </form>
39 <br/>--------------7、paramValues对象:paramValues获得请求参数 //map{"",String[]}------------------------<br/>
40 <!-- http://localhost:8080/JavaWeb_EL_Study_20140826/ELDemo03.jsp?like=aaa&like=bbb -->
41 ${paramValues.like[0]}
42 ${paramValues.like[1]}
43 <br/>--------------8、header对象:header获得请求头------------------------<br/>
44 ${header.Accept}<br/>
45 <%--${header.Accept-Encoding} 这样写会报错
46 测试headerValues时,如果头里面有“-” ,例Accept-Encoding,则要headerValues[“Accept-Encoding”]
47 --%>
48 ${header["Accept-Encoding"]}
49 <br/>--------------9、headerValues对象:headerValues获得请求头的值------------------------<br/>
50 <%--headerValues表示一个保存了所有http请求头字段的Map对象,它对于某个请求参数,返回的是一个string[]数组
51 例如:headerValues.Accept返回的是一个string[]数组 ,headerValues.Accept[0]取出数组中的第一个值
52 --%>
53 ${headerValues.Accept[0]}<br/>
54 <%--${headerValues.Accept-Encoding} 这样写会报错
55 测试headerValues时,如果头里面有“-” ,例Accept-Encoding,则要headerValues[“Accept-Encoding”]
56 headerValues["Accept-Encoding"]返回的是一个string[]数组,headerValues["Accept-Encoding"][0]取出数组中的第一个值
57 --%>
58 ${headerValues["Accept-Encoding"][0]}
59 <br/>--------------10、cookie对象:cookie对象获取客户机提交的cookie------------------------<br/>
60 <!-- 从cookie隐式对象中根据名称获取到的是cookie对象,要想获取值,还需要.value -->
61 ${cookie.JSESSIONID.value} //保存所有cookie的map
62 <br/>--------------11、initParam对象:initParam对象获取在web.xml文件中配置的初始化参数------------------------<br/>
63 <%--
64 <!-- web.xml文件中配置初始化参数 -->
65 <context-param>
66 <param-name>xxx</param-name>
67 <param-value>yyyy</param-value>
68 </context-param>
69 <context-param>
70 <param-name>root</param-name>
71 <param-value>/JavaWeb_EL_Study_20140826</param-value>
72 </context-param>
73 --%>
74 <%--获取servletContext中用于保存初始化参数的map --%>
75 ${initParam.xxx}<br/>
76 ${initParam.root}
77 </body>
78 </html>
RegisterServlet的代码如下:
package me.gacl.web.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RegisterServlet extends HttpServlet {
/*
* 处理用户注册的方法
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1、接收参数
String userName = request.getParameter("username");
/**
* 2、直接跳转回/ELDemo03.jsp页面,没有使用request.setAttribute("userName", userName)将userName存储到request对象中
* 但是在ELDemo03.jsp页面中可以使用${param.username}获取到request对象中的username参数的值
*/
request.getRequestDispatcher("/ELDemo03.jsp").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
测试结果如下:
注意:
测试header和headerValues时,如果头里面有“-” ,例Accept-Encoding,则要header["Accept-Encoding"]、headerValues["Accept-Encoding"]
测试cookie时,例${cookie.key}取的是cookie对象,如访问cookie的名称和值,须${cookie.key.name}或${cookie.key.value}
使用EL调用Java方法
EL表达式语法允许开发人员开发自定义函数,以调用Java类的方法。语法:${prefix:method(params)}
在EL表达式中调用的只能是Java类的静态方法,这个Java类的静态方法需要在TLD文件中描述,才可以被EL表达式调用。
EL自定义函数用于扩展EL表达式的功能,可以让EL表达式完成普通Java程序代码所能完成的功能。
EL Function开发步骤
一般来说, EL自定义函数开发与应用包括以下三个步骤:
1、编写一个Java类的静态方法
2、编写标签库描述符(tld)文件,在tld文件中描述自定义函数。
3、在JSP页面中导入和使用自定义函数
示例:开发对html标签进行转义的el function
1、编写html转义处理工具类,工具类中添加对html标签进行转义的静态处理方法,如下:
3 /**
4 * @ClassName: HtmlFilter
5 * @Description: html转义处理工具类
8 *
9 */
10 public class HtmlFilter {
11
12 /**
13 * @Method: filter
14 * @Description: 静态方法,html标签转义处理
17 * @param message 要转义的内容
18 * @return 转义后的内容
19 */
20 public static String filter(String message) {
21
22 if (message == null)
23 return (null);
24
25 char content[] = new char[message.length()];
26 message.getChars(0, message.length(), content, 0);
27 StringBuffer result = new StringBuffer(content.length + 50);
28 for (int i = 0; i < content.length; i++) {
29 switch (content[i]) {
30 case '<':
31 result.append("<");
32 break;
33 case '>':
34 result.append(">");
35 break;
36 case '&':
37 result.append("&");
38 break;
39 case '"':
40 result.append(""");
41 break;
42 default:
43 result.append(content[i]);
44 }
45 }
46 return (result.toString());
47 }
48 }
2、在WEB-INF目录下编写标签库描述符(tld)文件,在tld文件中描述自定义函数
elFunction.tld的代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" 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 web-jsptaglibrary_2_0.xsd">
<tlib-version>1.0</tlib-version>
<short-name>EL Function</short-name>
<!--
自定义EL函数库的引用URI,
在JSP页面中可以这样引用:<%@taglib uri="/ELFunction" prefix="fn" %>
-->
<uri>/ELFunction</uri>
<!--<function>元素用于描述一个EL自定义函数 -->
<function>
<description>html标签转义处理方法</description>
<!--<name>子元素用于指定EL自定义函数的名称-->
<name>filter</name>
<!--<function-class>子元素用于指定完整的Java类名-->
<function-class>me.gacl.util.HtmlFilter</function-class>
<!--<function-signature>子元素用于指定Java类中的静态方法的签名,
方法签名必须指明方法的返回值类型及各个参数的类型,各个参数之间用逗号分隔。-->
<function-signature>java.lang.String filter(java.lang.String)</function-signature>
</function>
</taglib>
3、在JSP页面中导入和使用自定义函数
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%--引入EL自定义函数库 --%>
<%@taglib uri="/ELFunction" prefix="fn" %>
<!DOCTYPE HTML>
<html>
<head>
<title>使用EL调用Java方法</title>
</head>
<body>
<%--使用EL调用filter方法--%>
${fn:filter("<a href=''>点点</a>")}
</body>
</html>
运行结果如下:
开发EL Function注意事项
编写完标签库描述文件后,需要将它放置到<web应用>\WEB-INF目录中或WEB-INF目录下的除了classes和lib目录之外的任意子目录中。
TLD文件中的<uri> 元素用指定该TLD文件的URI,在JSP文件中需要通过这个URI来引入该标签库描述文件。
<function>元素用于描述一个EL自定义函数,其中:
<name>子元素用于指定EL自定义函数的名称。
<function-class>子元素用于指定完整的Java类名,
<function-signature>子元素用于指定Java类中的静态方法的签名,方法签名必须指明方法的返回值类型及各个参数的类型,各个参数之间用逗号分隔。
EL注意事项
EL表达式是JSP 2.0规范中的一门技术 。因此,若想正确解析EL表达式,需使用支持Servlet2.4/JSP2.0技术的WEB服务器。
注意:有些Tomcat服务器如不能使用EL表达式
(1)升级成tomcat6
(2)在JSP中加入<%@ page isELIgnored="false" %>
EL表达式保留关键字
所谓保留字的意思是指变量在命名时,应该避开上述的名字,以免程序编译时发生错误,关于EL表达式的内容的总结就这么多。
EL函数库
由于在JSP页面中显示数据时,经常需要对显示的字符串进行处理,SUN公司针对于一些常见处理定义了一套EL函数库供开发者使用。
这些EL函数在JSTL开发包中进行描述,因此在JSP页面中使用SUN公司的EL函数库,需要导入JSTL开发包,并在页面中导入EL函数库,如下所示:
MyEclipse自带的JSTL开发包:
fn.tld就是EL函数库的对应的tld描述文件,如下图所示:
在页面中使用JSTL定义的EL函数:<%@taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
EL函数使用范例
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
2 <%@page import="me.gacl.domain.User"%>
3 <%--引入EL函数库 --%>
4 <%@taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
5 <!DOCTYPE HTML>
6 <html>
7 <head>
8 <title>EL函数库中的方法使用范例</title>
9 </head>
10
11 <body>
12 <h3>fn:toLowerCase函数使用范例:</h3>
13 <%--fn:toLowerCase函数将一个字符串中包含的所有字符转换为小写形式,并返回转换后的字符串,
14 它接收一个字符串类型的参数。fn:toLowerCase("")的返回值为空字符串--%>
15 <%--fn:toLowerCase("Www.CNBLOGS.COM") 的返回值为字符串“www.cnblogs.com” --%>
16 fn:toLowerCase("Www.CNBLOGS.COM")的结果是:${fn:toLowerCase("Www.CNBLOGS.COM")}
17 <hr/>
18 <h3>fn:toUpperCase函数使用范例:</h3>
19 <%--fn:toUpperCase函数将一个字符串中包含的所有字符转换为大写形式,并返回转换后的字符串,
20 它接收一个字符串类型的参数。fn:toUpperCase("")的返回值为空字符串--%>
21 fn:toUpperCase("cnblogs.com")的结果是:${fn:toUpperCase("cnblogs.com")}
22 <hr/>
23 <h3>fn:trim函数使用范例:</h3>
24 <%--fn:trim函数删除一个字符串的首尾的空格,并返回删除空格后的结果字符串,
25 它接收一个字符串类型的参数。需要注意的是,fn:trim函数不能删除字符串中间位置的空格。--%>
26 fn:trim(" cnblogs.com ")的结果是:${fn:trim(" cnblogs.com ")}
27 <hr/>
28 <h3>fn:length函数使用范例:</h3>
29 <%--fn:length函数返回一个集合或数组大小,或返回一个字符串中包含的字符的个数,返回值为int类型。
30 fn:length函数接收一个参数,这个参数可以是<c:forEach>标签的items属性支持的任何类型,
31 包括任意类型的数组、java.util.Collection、java.util.Iterator、java.util.Enumeration、
32 java.util.Map等类的实例对象和字符串。
33 如果fn:length函数的参数为null或者是元素个数为0的集合或数组对象,则函数返回0;如果参数是空字符串,则函数返回0
34 --%>
35 <%
36 List<String> list = Arrays.asList("1","2","3");
37 request.setAttribute("list",list);
38 %>
39 fn:length(list)计算集合list的size的值是:${fn:length(list)}
40 <br/>
41 fn:length("cnblogs.com")计算字符串的长度是:${fn:length("cnblogs.com")}
42 <hr/>
43 <h3>fn:split函数使用范例:</h3>
44 <%--
45 fn:split函数以指定字符串作为分隔符,将一个字符串分割成字符串数组并返回这个字符串数组。
46 fn:split函数接收两个字符串类型的参数,第一个参数表示要分割的字符串,第二个参数表示作为分隔符的字符串
47 --%>
48 fn:split("cnblogs.com",".")[0]的结果是:${fn:split("cnblogs.com",".")[0]}
49 <hr/>
50 <h3>fn:join函数使用范例:</h3>
51 <%--
52 fn:join函数以一个字符串作为分隔符,将一个字符串数组中的所有元素合并为一个字符串并返回合并后的结果字符串。
53 fn:join函数接收两个参数,第一个参数是要操作的字符串数组,第二个参数是作为分隔符的字符串。
54 如果fn:join函数的第二个参数是空字符串,则fn:join函数的返回值直接将元素连接起来。
55 --%>
56 <%
57 String[] StringArray = {"www","iteye","com"};
58 pageContext.setAttribute("StringArray", StringArray);
59 %>
60 <%--fn:join(StringArray,".")返回字符串“www.iteye.com”--%>
61 fn:join(StringArray,".")的结果是:${fn:join(StringArray,".")}
62 <br/>
63 <%--fn:join(fn:split("www,iteye,com",","),".")的返回值为字符串“www.iteye.com”--%>
64 fn:join(fn:split("www,iteye,com",","),".")的结果是:${fn:join(fn:split("www,iteye,com",","),".")}
65 <hr/>
66
67 <h3>fn:indexOf函数使用范例:</h3>
68 <%--
69 fn:indexOf函数返回指定字符串在一个字符串中第一次出现的索引值,返回值为int类型。
70 fn:indexOf函数接收两个字符串类型的参数,如果第一个参数字符串中包含第二个参数字符串,
71 那么,不管第二个参数字符串在第一个参数字符串中出现几次,fn:indexOf函数总是返回第一次出现的索引值;
72 如果第一个参数中不包含第二个参数,则fn:indexOf函数返回-1。如果第二个参数为空字符串,则fn:indexOf函数总是返回0。
73 --%>
74 fn:indexOf("www.iteye.com","eye")的返回值为:${fn:indexOf("www.iteye.com","eye")}
75 <hr/>
76
77 <h3>fn:contains函数使用范例:</h3>
78 <%--
79 fn:contains函数检测一个字符串中是否包含指定的字符串,返回值为布尔类型。
80 fn:contains函数在比较两个字符串是否相等时是大小写敏感的。
81 fn:contains函数接收两个字符串类型的参数,如果第一个参数字符串中包含第二个参数字符串,则fn:contains函数返回true,否则返回false。
82 如果第二个参数的值为空字符串,则fn:contains函数总是返回true。
83 实际上,fn:contains(string, substring)等价于fn:indexOf(string, substring) != -1
84 忽略大小的EL函数:fn:containsIgnoreCase
85 --%>
86 <%
87 User user = new User();
88 String likes[] = {"sing","dance"};
89 user.setLikes(likes);
90 //数据回显
91 request.setAttribute("user",user);
92 %>
93 <%--使用el函数回显数据 --%>
94 <input type="checkbox" name="like"
95 vlaue="sing" ${fn:contains(fn:join(user.likes,","),"sing")?'checked':''}/>唱歌
96 <input type="checkbox" name="like"
97 value="dance" ${fn:contains(fn:join(user.likes,","),"dance")?'checked':''}/>跳舞
98 <input type="checkbox" name="like"
99 value="basketball" ${fn:contains(fn:join(user.likes,","),"basketball")?'checked':''}/>蓝球
100 <input type="checkbox" name="like"
101 value="football" ${fn:contains(fn:join(user.likes,","),"football")?'checked':''}/>足球
102 <hr/>
103
104 <h3>fn:startsWith函数和fn:endsWith函数使用范例:</h3>
105 <%--
106 fn:startsWith函数用于检测一个字符串是否是以指定字符串开始的,返回值为布尔类型。
107 fn:startsWith函数接收两个字符串类型的参数,如果第一个参数字符串以第二个参数字符串开始,则函数返回true,否则函数返回false。
108 如果第二个参数为空字符串,则fn:startsWith函数总是返回true。
109 与fn:startsWith函数对应的另一个EL函数为:fn:endsWith,用于检测一个字符串是否是以指定字符串结束的,返回值为布尔类型。
110 --%>
111 fn:startsWith("www.iteye.com","iteye")的返回值为:${fn:startsWith("www.iteye.com","iteye")}
112 <br/>
113 fn:endsWith("www.iteye.com","com")的返回值为:${fn:endsWith("www.iteye.com","com")}
114 <hr/>
115
116 <h3>fn:replace使用范例:</h3>
117 <%--
118 fn:replace函数将一个字符串中包含的指定子字符串替换为其它的指定字符串,并返回替换后的结果字符串。
119 fn:replace方法接收三个字符串类型的参数,第一个参数表示要操作的源字符串,第二个参数表示源字符串中要被替换的子字符串,
120 第三个参数表示要被替换成的字符串。
121 --%>
122 fn:replace("www iteye com ", " ", ".")的返回值为字符串:${fn:replace("www iteye com", " ", ".")}
123 <hr/>
124
125 <h3>fn:substring使用范例:</h3>
126 <%--
127 fn:substring函数用于截取一个字符串的子字符串并返回截取到的子字符串。
128 fn:substring函数接收三个参数,第一个参数是用于指定要操作的源字符串,第二个参数是用于指定截取子字符串开始的索引值,
129 第三个参数是用于指定截取子字符串结束的索引值,第二个参数和第三个参数都是int类型,其值都从0开始。
130 --%>
131 fn:substring("www.it315.org", 4, 9) 的返回值为字符串:${fn:substring("www.it315.org", 4, 9)}
132
133 <h3>fn:substringAfter函数和fn:substringBefore函数使用范例:</h3>
134 <%--
135 fn:substringAfter函数用于截取并返回一个字符串中的指定子字符串第一次出现之后的子字符串。
136 fn:substringAfter函数接收两个字符串类型的参数,第一个参数表示要操作的源字符串,第二个参数表示指定的子字符串
137 与之对应的EL函数为:fn:substringBefore
138 --%>
139 fn:substringAfter("www.it315.org",".")的返回值为字符串:${fn:substringAfter("www.it315.org",".")}
140 <br/>
141 fn:substringBefore("www.it315.org",".")的返回值为字符串:${fn:substringBefore("www.it315.org",".")}
142 <hr/>
143 </body>
144 </html>
jsp页面中使用到的me.gacl.domain.User类的代码如下:
package me.gacl.domain;
public class User {
/**
* 兴趣爱好
*/
private String likes[];
public String[] getLikes() {
return likes;
}
public void setLikes(String[] likes) {
this.likes = likes;
}
}
运行结果如下:
国际化开发
java读取properties文件总结
在java项目中,操作properties文件是经常要做的,因为很多的配置信息都会写在properties文件中,这里主要是总结使用getResourceAsStream方法和InputStream流去读取properties文件,使用getResourceAsStream方法去读取properties文件时需要特别注意properties文件路径的写法,测试项目如下:
项目的目录结构
java读取properties文件代码测试
/* 范例名称:java读取properties文件总结
* 源文件名称:PropertiesFileReadTest.java
* 要 点:
* 1. 使用getResourceAsStream方法读取properties文件
* 2. 使用InPutStream流读取properties文件
* 3. 读取properties文件的路径写法问题
*/
package propertiesFile.read.test;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.Properties;
public class PropertiesFileReadTest {
/**
* @param args
*/
public static void main(String[] args) {
try {
readPropFileByGetResourceAsStream();
System.out.println("");
readPropFileByInPutStream();
} catch (Exception e) {
e.printStackTrace();// TODO: handle exception
}
}
/**
* 使用getResourceAsStream方法读取properties文件
*/
static void readPropFileByGetResourceAsStream() {
/**
* 读取src下面config.properties包内的配置文件
* test1.properties位于config.properties包内
*/
InputStream in1 = PropertiesFileReadTest.class.getClassLoader()
.getResourceAsStream("config/properties/test1.properties");
/**
* 读取和PropertiesFileReadTest类位于同一个包里面的配置文件
* test2.properties和PropertiesFileReadTest类在同一个包里面
*/
InputStream in2 = PropertiesFileReadTest.class
.getResourceAsStream("test2.properties");
/**
* 读取src根目录下文件的配置文件
* jdbc.properties位于src目录
*/
InputStream in3 = PropertiesFileReadTest.class.getClassLoader()
.getResourceAsStream("jdbc.properties");
/**
* 读取位于另一个source文件夹里面的配置文件
* config是一个source文件夹,config.properties位于config source文件夹中
*/
InputStream in4 = PropertiesFileReadTest.class.getClassLoader()
.getResourceAsStream("config.properties");
Properties p = new Properties();
System.out.println("----使用getResourceAsStream方法读取properties文件----");
try {
System.out
.println("----------------------------------------------");
p.load(in1);
System.out.println("test1.properties:name=" + p.getProperty("name")
+ ",age=" + p.getProperty("age"));
System.out
.println("----------------------------------------------");
p.load(in2);
System.out.println("test2.properties:name=" + p.getProperty("name")
+ ",age=" + p.getProperty("age"));
System.out
.println("----------------------------------------------");
p.load(in3);
System.out.println("jdbc.properties:");
System.out.println(String.format("jdbc.driver=%s",
p.getProperty("jdbc.driver")));// 这里的%s是java String占位符
System.out.println(String.format("jdbc.url=%s",
p.getProperty("jdbc.url")));
System.out.println(String.format("jdbc.usename=%s",
p.getProperty("jdbc.usename")));
System.out.println(String.format("jdbc.password=%s",
p.getProperty("jdbc.password")));
System.out
.println("----------------------------------------------");
p.load(in4);
System.out.println("config.properties:");
System.out.println(MessageFormat.format("dbuser={0}",
p.getProperty("dbuser")));// {0}是一个java的字符串占位符
System.out.println(MessageFormat.format("dbpassword={0}",
p.getProperty("dbpassword")));
System.out.println(MessageFormat.format("database={0}",
p.getProperty("database")));
System.out
.println("----------------------------------------------");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (in1 != null) {
try {
in1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in2 != null) {
try {
in2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in3 != null) {
try {
in3.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in4 != null) {
try {
in4.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 使用InPutStream流读取properties文件
*/
static void readPropFileByInPutStream() {
InputStream in1 = null;
InputStream in2 = null;
InputStream in3 = null;
InputStream in4 = null;
System.out.println("----使用InputStream流读取properties文件----");
try {
/**
* 读取src根目录下文件的配置文件
* jdbc.properties位于src目录
*/
in1 = new BufferedInputStream(new FileInputStream(
"src/jdbc.properties"));
/**
* 读取src下面config.properties包内的配置文件
* test1.properties位于config.properties包内
*/
in2 = new BufferedInputStream(new FileInputStream(
"src/config/properties/test1.properties"));
/**
* 读取和PropertiesFileReadTest类位于同一个包里面的配置文件
* test2.properties和PropertiesFileReadTest类在同一个包里面
*/
in3 = new BufferedInputStream(new FileInputStream(
"src/propertiesFile/read/test/test2.properties"));
/**
* 读取位于另一个source文件夹里面的配置文件
* config是一个source文件夹,config.properties位于config source文件夹中
*/
in4 = new FileInputStream("config/config.properties");
Properties p = new Properties();
System.out
.println("----------------------------------------------");
p.load(in1);
System.out.println("jdbc.properties:");
System.out.println(String.format("jdbc.driver=%s",
p.getProperty("jdbc.driver")));// 这里的%s是java String占位符
System.out.println(String.format("jdbc.url=%s",
p.getProperty("jdbc.url")));
System.out.println(String.format("jdbc.usename=%s",
p.getProperty("jdbc.usename")));
System.out.println(String.format("jdbc.password=%s",
p.getProperty("jdbc.password")));
System.out
.println("----------------------------------------------");
p.load(in2);
System.out.println("test1.properties:name=" + p.getProperty("name")
+ ",age=" + p.getProperty("age"));
System.out
.println("----------------------------------------------");
p.load(in3);
System.out.println("test2.properties:name=" + p.getProperty("name")
+ ",age=" + p.getProperty("age"));
System.out
.println("----------------------------------------------");
p.load(in4);
System.out.println("config.properties:");
System.out.println(MessageFormat.format("dbuser={0}",
p.getProperty("dbuser")));// {0}是一个java的字符串占位符
System.out.println(MessageFormat.format("dbpassword={0}",
p.getProperty("dbpassword")));
System.out.println(MessageFormat.format("database={0}",
p.getProperty("database")));
System.out
.println("----------------------------------------------");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (in1 != null) {
try {
in1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in2 != null) {
try {
in2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in3 != null) {
try {
in3.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in4 != null) {
try {
in4.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
运行结果:
国际化
软件的国际化:软件开发时,要使它能同时应对世界不同地区和国家的访问,并针对不同地区和国家的访问,提供相应的、符合来访者阅读习惯的页面或数据。
国际化(internationalization)又称为 i18n(读法为i 18 n,据说是因为internationalization(国际化)这个单词从i到n之间有18个英文字母,i18n的名字由此而来)
合格的国际化软件
软件实现国际化,需具备以下两个特征:
1、对于程序中固定使用的文本元素,例如菜单栏、导航条等中使用的文本元素、或错误提示信息,状态信息等,需要根据来访者的地区和国家,选择不同语言的文本为之服务。
2、对于程序动态产生的数据,例如(日期,货币等),软件应能根据当前所在的国家或地区的文化习惯进行显示。
固定文本元素的国际化
对于软件中的菜单栏、导航条、错误提示信息,状态信息等这些固定不变的文本信息,可以把它们写在一个properties文件中,并根据不同的国家编写不同的properties文件。这一组properties文件称之为一个资源包。
创建资源包和资源文件
一个资源包中的每个资源文件都必须拥有共同的基名。除了基名,每个资源文件的名称中还必须有标识其本地信息的附加部分。例如:一个资源包的基名是“myproperties”,则与中文、英文环境相对应的资源文件名则为: "myproperties_zh.properties" "myproperties_en.properties"
每个资源包都应有一个默认资源文件,这个文件不带有标识本地信息的附加部分。若ResourceBundle对象在资源包中找不到与用户匹配的资源文件,它将选择该资源包中与用户最相近的资源文件,如果再找不到,则使用默认资源文件。例如:myproperties.properties
资源文件的书写格式
资源文件的内容通常采用"关键字=值"的形式,软件根据关键字检索值显示在页面上。一个资源包中的所有资源文件的关键字必须相同,值则为相应国家的文字。
并且资源文件中采用的是properties格式文件,所以文件中的所有字符都必须是ASCII字码,属性(properties)文件是不能保存中文的,对于像中文这样的非ACSII字符,须先进行编码。
例如:
国际化的中文环境的properties文件
国际化的英文环境的properties文件
java提供了一个native2ascII工具用于将中文字符进行编码处理,native2ascII的用法如下所示:
编程实现固定文本的国际化
在JavaAPI中提供了一个ResourceBundle 类用于描述一个资源包,并且 ResourceBundle类提供了相应的方法getBundle,这个方法可以根据来访者的国家地区自动获取与之对应的资源文件予以显示。
ResourceBundle类提供了一个静态方法getBundle,该方法用于装载资源文件,并创建ResourceBundle实例:
Locale currentLocale = Locale.getDefault();
ResourceBundle myResources =ResourceBundle.getBundle(basename, currentLocale);
basename为资源包基名(且必须为完整路径)。
如果与该locale对象匹配的资源包子类找不到。一般情况下,则选用默认资源文件予以显示。
加载资源文件后, 程序就可以调用ResourceBundle 实例对象的 getString 方法获取指定的资源信息名称所对应的值。
String value = myResources.getString(“key");
范例:根据国家地区自动获取与之对应的资源文件
package me.gacl.i18n;
import java.util.Locale;
import java.util.ResourceBundle;
/**
*@ClassName: I18NTest
* @Description: 编程实现固定文本的国际化
*
*/
public class I18NTest {
public static void main(String[] args) {
//资源包基名(包名+myproperties)
String basename = "me.gacl.i18n.resource.myproperties";
//设置语言环境
Locale cn = Locale.CHINA;//中文
Locale us = Locale.US;//英文
//根据基名和语言环境加载对应的语言资源文件
ResourceBundle myResourcesCN = ResourceBundle.getBundle(basename,cn);//加载myproperties_zh.properties
ResourceBundle myResourcesUS = ResourceBundle.getBundle(basename,us);//加载myproperties_en.properties
//加载资源文件后, 程序就可以调用ResourceBundle实例对象的 getString方法获取指定的资源信息名称所对应的值。
//String value = myResources.getString(“key");
String usernameCN = myResourcesCN.getString("username");
String passwordCN = myResourcesCN.getString("password");
String usernameUS = myResourcesUS.getString("username");
String passwordUS = myResourcesUS.getString("password");
System.out.println(usernameCN+"--"+passwordCN);
System.out.println(usernameUS+"--"+passwordUS);
}
}
运行结果:
在WEB应用中实现固定文本的国际化
如下所示:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
<head>
<title>国际化(i18n)测试</title>
</head>
<%
//加载i18n资源文件,request.getLocale()获取访问用户所在的国家地区
ResourceBundle myResourcesBundle = ResourceBundle.getBundle("me.gacl.i18n.resource.myproperties",request.getLocale());
%>
<body>
<form action="" method="post">
<%=myResourcesBundle.getString("username")%>:<input type="text" name="username"/><br/>
<%=myResourcesBundle.getString("password")%>:<input type="password" name="password"/><br/>
<input type="submit" value="<%=myResourcesBundle.getString("submit")%>">
</form>
</body>
</html>
运行结果:
浏览器语言是中文环境下的显示效果:
浏览器语言是英文环境下的显示效果:
同样一个页面,在不同语言环境的浏览器下显示出了不同的语言文字效果,这样就实现了固定文本的国际化。
IE浏览器切换使用语言:工具→Internet选项
动态数据的国际化
数值,货币,时间,日期等数据由于可能在程序运行时动态产生,所以无法像文字一样简单地将它们从应用程序中分离出来,而是需要特殊处理。Java 中提供了解决这些问题的 API 类(位于 java.util 包和 java.text 包中)
Locale 类
Locale 实例对象代表一个特定的地理,政治、文化区域。
一个 Locale 对象本身不会验证它代表的语言和国家地区信息是否正确,只是向本地敏感的类提供国家地区信息,与国际化相关的格式化和解析任务由本地敏感的类去完成。(若JDK中的某个类在运行时需要根据 Locale 对象来调整其功能,这个类就称为本地敏感类)
DateFormat类(日期格式化)
DateFormat 类可以将一个日期/时间对象格式化为表示某个国家地区的日期/时间字符串。
DateFormat 类除了可按国家地区格式化输出日期外,它还定义了一些用于描述日期/时间的显示模式的 int 型的常量,包括FULL, LONG, MEDIUM, DEFAULT, SHORT,实例化DateFormat对象时,可以使用这些常量,控制日期/时间的显示长度。
实例化DateFormat类
实例化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 实例对象
DateFormat使用范例
package me.gacl.i18n;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Date;
import java.util.Locale;
/**
* @ClassName: DateFormatTest
* @Description: DateFormat类测试
* DateFormat类可以将一个日期/时间对象格式化为表示某个国家地区的日期/时间字符串
*
*/
public class DateFormatTest {
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);
}
}
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实例对象
范例:
package me.gacl.i18n;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
/**
* @ClassName: NumberFormatTest
* @Description: NumberFormat类测试
*
*/
public class NumberFormatTest {
public static void main(String[] args) throws ParseException {
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));
}
}
运行结果:
MessageFormat(文本格式化)
如果一个字符串中包含了多个与国际化相关的数据,可以使用MessageFormat类对这些数据进行批量处理。
例如:At 12:30 pm on jul 3,1998, a hurricance destroyed 99 houses and caused $1000000 of damage
以上字符串中包含了时间、数字、货币等多个与国际化相关的数据,对于这种字符串,可以使用MessageFormat类对其国际化相关的数据进行批量处理。
MessageFormat 类如何进行批量处理呢?
1.MessageFormat类允许开发人员用占位符替换掉字符串中的敏感数据(即国际化相关的数据)。
2.MessageFormat类在格式化输出包含占位符的文本时,messageFormat类可以接收一个参数数组,以替换文本中的每一个占位符。
模式字符串与占位符
模式字符串:
At {0} on {1},a destroyed {2} houses and caused {3} of damage
字符串中的{0}、{1}、{2}、{3}就是占位符
格式化模式字符串
1、实例化MessageFormat对象,并装载相应的模式字符串。
2、使用format(object obj[])格式化输出模式字符串,参数数组中指定占位符相应的替换对象。
范例:
package me.gacl.i18n;
import java.text.MessageFormat;
import java.util.Date;
import java.util.Locale;
/**
* @ClassName: MessageFormatTest
* @Description: MessageFormat类测试
*
*/
public class MessageFormatTest {
public static void main(String[] args) {
//模式字符串
String pattern = "On {0}, a hurricance destroyed {1} houses and caused {2} of damage.";
//实例化MessageFormat对象,并装载相应的模式字符串
MessageFormat format = new MessageFormat(pattern, Locale.CHINA);
Object arr[] = {new Date(), 99, 100000000};
//格式化模式字符串,参数数组中指定占位符相应的替换对象
String result = format.format(arr);
System.out.println(result);
}
}
运行结果:
占位符的三种书写方式
{argumentIndex}: 0-9 之间的数字,表示要格式化对象数据在参数数组中的索引号
{argumentIndex,formatType}: 参数的格式化类型
{argumentIndex,formatType,FormatStyle}: 格式化的样式,它的值必须是与格式化类型相匹配的合法模式、或表示合法模式的字符串。
范例:
package me.gacl.i18n;
import java.text.MessageFormat;
import java.util.Date;
import java.util.Locale;
/**
* @ClassName: MessageFormatTest
* @Description: MessageFormat类测试
*
*/
public class MessageFormatTest {
public static void main(String[] args) {
//模式字符串
String pattern = "At {0, time, short} on {0, date}, a destroyed {1} houses and caused {2, number, currency} of damage.";
//实例化MessageFormat对象,并装载相应的模式字符串
MessageFormat format = new MessageFormat(pattern, Locale.US);
Object arr[] = {new Date(), 99, 100000000};
//格式化模式字符串,参数数组中指定占位符相应的替换对象
String result = format.format(arr);
System.out.println(result);
}
}
运行结果:
在WEB应用中使用国际化标签库实现固定文本的国际化
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%--导入国际化标签库 --%>
<%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE HTML>
<html>
<head>
<title>国际化(i18n)测试</title>
</head>
<%--
//加载i18n资源文件,request.getLocale()获取访问用户所在的国家地区
ResourceBundle myResourcesBundle = ResourceBundle.getBundle("me.gacl.i18n.resource.myproperties",request.getLocale());
--%>
<body>
<%--
<form action="" method="post">
<%=myResourcesBundle.getString("username")%>:<input type="text" name="username"/><br/>
<%=myResourcesBundle.getString("password")%>:<input type="password" name="password"/><br/>
<input type="submit" value="<%=myResourcesBundle.getString("submit")%>">
</form>
--%>
<fmt:setBundle var="bundle" basename="me.gacl.i18n.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>
以上就是JavaWeb开发中国际化的总结内容。