1.Cookie
Cookie 的作用范围:可以作用当前目录和当前目录的子目录,当不能作用于当前目录的上一级目录。
可以通过 setPath 方法来设置 Cookie 的作用范围,其中 / 代表站点的根目录。
Cookie cookie = new Cookie("cookiePath","cookiePathValue");
cookie.setPath(request.getContextPath());
2.Session
1. 什么时候销毁 HttpSession 对象:
- 直接调用 HttpSession 的 invalidate() 方法:该方法使 HttpSession 失效。
- 服务器卸载了当前的 WEB 应用。
超出 HttpSession 的过期时间:
- 设置 HttpSession 的过期时间:session.setMaxInactiveInterval(5);单位:秒。
- 在 web.xml 文件中设置 HttpSession 的过期时间,单位:分钟。
<session-config> <session-timeout>30</session-timeout> </session-config>
- 并不是关闭了浏览器就销毁了 HttpSession.
2.重写 URL
如果浏览器不支持 Cookie,可以利用重写 URL 实现 Session 跟踪来保持 WEB 服务器连续的会话。
HttpServlet 接口中定义了两个用于完成 URL 重写方法:
- encodeURL 方法
- encodeRedirectURL 方法
3.相对路径和绝对路径
开发的时候建议写绝对路径:写绝对路径肯定没有问题,但写相对路径却可能出现问题。
例如:a.jsp-> /Servlet -转发-> b.jsp (有一个超链接:和 b.jsp 在同一个路径下的 c.jsp ) -> 无法得到页面。
原因:由于 Servlet 转发到 JSP 页面时,此时浏览器地址栏上显示的时 Servlet 的路径,若 JSP 页面的超链接还是相对于该 JSP 页面的地址,此时有可能会出现地址混乱的问题。
4.表单重复提交
重复提交情况:
- 表单提交到一个 Servlet 又通过请求转发方式响应一个 JSP(HTML) 页面,此时地址栏还保留着 Servlet 那个路径,在响应页面点击”刷新”。
- 在响应页面没有到达时重复点击 “提交按钮”。
- 点击 “返回”,再点击 “提交”。
不是重复提交的情况:点击 “返回”,”刷新” 原表单页面,再 “提交”。
如何避免表单的重复提交:
在表单中做一个标记,提交到 Servlet 时,查看标记是否存在并且和预定义的一致,若一致,则受理请求,并销毁标记;若没有标记或标记不一致,则直接响应
“重复提交信息”。
方案:利用隐藏域和 session 解决。
1).在原表单页面,生成一个随机标记值 flag.
2).在原表单页面,把生成的 flag 放在 session 属性中.
3).在原表单页面,把生成的 flag 放在隐藏域属性中.
4).在目标的 Servlet 中,获取 session 和隐藏域中的值.
5).比较两个值是否一致,若一致则受理请求,并把 session 中 flag 属性清除.
6).若不一致,则直接响应提示页面,"重复提交 ".
示例代码:
//login.jsp页面
<body>
<%
String flag = new Date().getTime() + "";
session.setAttribute("flag", flag);
%>
<form action="<%=request.getContextPath() %>/LoginServlet" method="post">
<input type="hidden" name = "flag" value="<%=flag %>">
username:<input type = "text" name = "name"/>
<input type = "submit" value = "Submit" />
</form>
</body>
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name = request.getParameter("name");
System.out.println("name:" + name);
HttpSession session = request.getSession();
String flag = (String) session.getAttribute("flag");
String flagValue = request.getParameter("flag");
if(flag != null && flag.equals(flagValue)){
//移除 flag。
session.removeAttribute("flag");
System.out.println("flag:" + flag);
System.out.println("flagValue:" + flagValue);
}else{
//如果是重复提交,重定向到错误提示页面。
response.sendRedirect(request.getContextPath() + "/SubmitForm/error.jsp");
return;
}
//执行相应的操作。
request.getRequestDispatcher("/SubmitForm/success.jsp").forward(request, response);
}
5.EL表达式
1.基本语法
EL表达式的基本形式为: var,所有的表达式都以” {”符号开头,以”}”符号结尾。例如以下Java表达式和El表达式的作用相同,都用于输出请求参数username:
Java表达式:<%=request.getParameter(“username”)%>
EL表达式:${param.username}
2.访问对象的属性及数组的元素
EL表达式语言可以使用点号运算符 “.” 和 [] 来访问。
<%
request.setAttribute("com.cg.test", "Test");
%>
<!-- 当名称中有特殊的字符时要用 [] 取得对应值 -->
${requestScope["com.cg.test"] }
3.EL 表达式的运算符
EL语言提供了一个用于测试对象是否为空的特殊运算符 “empty”,其语法形式为${empty var},它能判断var变量(确切地说,应该是命名变量)是否为空。在以下情况下empty运算符返回true:
var变量不存在,即没有定义。
var变量的值为null。
var变量引用集合(Set、List和Map)类型的对象,并且在集合对象中不包含任何元素。
empty运算符可以与 “!” 运算符一起使用。
<%
List<String> list = new ArrayList<String>();
list.add("aaa");
request.setAttribute("list", list);
%>
<!-- empty 可以判断对象是否为 null -->
list is empty:${empty requestScope.list }
<!-- 关系运算符 -->
5 == 5:${5 == 5 }
10 >= 100:${10 >= 100 }
4.EL表达式语言中的隐含对象
5.自动转换类型
EL 除了提供方便存取变量的语法之外,它另外一个方便的功能就是,自动转变类型。
例如:
${param.count + 20}假若窗体传来count的值为10时,那么上面的结果为30。之前没接触过JSP 的读者可能会认为上面的例子是理所当然的,
但是在JSP 1.2 之中不能这样做,原因是从窗体所传来的值,它们的类型一律是String,所以当你接收之后,必须再将它转为其他类型,如:int、float 等等,然后才能执行一些数学运算,下面是之前的做法:
String str_count =request.getParameter("count");
int count =Integer.parseInt(str_count);
count = count + 20;
6.JSTL
JSTL全名为JavaServer Pages Standard Tag Library,它的中文名称为 JSP 标准标签函数库。JSTL是一个标准的已制定好的标签库,可以应用于各种领域,如:基本输入输出、流程控制、循环、XML文件剖析、数据库查询及国际化和文字格式标准化的应用等。
Web程序开发人员能够利用JSTL和EL来开发Web程序,取代传统直接在页面上嵌入Java程序(Scripting)的做法,以提高程序可读性、维护性和方便性。
1.安装 JSTL
1).导入相关 .jar 包:jstl.jar、standard.jar.
2).声明标签库:<%@ taglib prefix=”c” uri=”http://java.sun.com/jsp/jstl/core” %>
2.核心标签库
首先介绍的核心标签库(Core)主要有:基本输入输出、流程控制、迭代操作和 URL 操作。详细分类如下表:
示例代码:
<h4>1. c:out</h4>
<%
request.setAttribute("book","<<Java>>");
%>
EL:${requestScope.book }<!-- 因为 value 中包含了特殊字符,EL 表达式未能正确打印出内容 -->
<br>
JSTL:<c:out value="${requestScope.book }"></c:out>
<br>
<h4>2. c:set</h4>
<!-- 为域区间某个对象赋值 -->
<c:set var = "temp" value="ZhangChao" scope="session"></c:set>
temp:${sessionScope.temp }<br>
<%
Customers cus = new Customers();
cus.setAge(18);
request.setAttribute("cus", cus);
%>
age:${requestScope.cus.age }<br>
<!-- 为 JavaBean 对象属性赋值 -->
<c:set target="${requestScope.cus}" property="age" value = "${param.age }"></c:set>
age:${requestScope.cus.age }<br>
<!-- 移除 -->
<h4>3. c:remove</h4>
<c:set var = "test" value="ZhangChao" scope="session"></c:set>
test:${sessionScope.test }<br>
<c:remove var="test"/>
test:-${sessionScope.test }+<br>
<h4>4. c:if(没有 else,但可以把判断的结果储存起来,以备之后使用)</h4>
<c:set var = "age" value="18" scope="session"></c:set>
<c:if test="${sessionScope.age >= 18 }">成年了</c:if><br>
<c:if test="${param.age >= 18 }" var = "isAdult" scope="session"></c:if>
isAdult:<c:out value="${sessionScope.isAdult }"></c:out><br><br>
<h4>
4. c:choose,c:when,c:otherwise:可以实现 if...else if...else if...else 的效果,但较为麻烦。
①:c:choose 以 c:when,c:otherwise 的父标签出现。
②:c:when,c:otherwise 不能脱离 c:choose 单独使用。
③:c:otherwise 必须在 c:when 之后使用 。
</h4>
<c:choose>
<c:when test="${param.age > 60 }">老年</c:when>
<c:when test="${param.age > 35 }">中年</c:when>
<c:when test="${param.age >= 18 }">青年</c:when>
<c:otherwise>未成年</c:otherwise>
</c:choose>
<br>
<h4>5. c:import 可以包含任何页面到当前页面</h4>
<c:import url="http://www.baidu.com"></c:import>
7.国际化
(1).概念
- 软件的本地化:一个软件在某个国家或地区使用时,采用该国家或地区的语言,数字,货币,日期等习惯。
- 软件的国际化:软件开发时,让它能支持多个国家和地区的本地化应用。使得应用软件能够适应多个地区的语言和文化风俗习惯。
(2).Locale 类
- Locale 实例对象代表一个特定的地理,政治或文化上的区域
- 一个 Locale 对象本身不会验证它代表的语言和国家地区信息是否正确,只是向本地敏感的类提供本地信息,与国际化相关的格式化和解析任务由本地敏感的类(若JDK中的某个类在运行时需要根据 Locale 对象来调整其功能,这个类就称为本地敏感类)去完成
public void testLocal(){
Locale locale = Locale.CHINA;
System.out.println(locale.getCountry());
System.out.println(locale.getLanguage());
System.out.println(locale.getDisplayCountry());
locale = new Locale("en", "US");
System.out.println(locale.getCountry());
System.out.println(locale.getLanguage());
}
(3).DateFormat 类
DateFormat 类可以将一个日期/时间对象格式化为表示某个国家地区的日期/时间字符串,也可以将表示某个本地的日期/时间的字符串解析为相应的日期/时间对象
DateFormat 类定义了一些用于描述日期/时间的显示模式的 int 型的常量,包括FULL, LONG, MEDIUM, DEFAULT, SHORT,这些常量用于描述表示日期/时间字符串的长度。这些常量说明表示的日期/时间的确切格式取决于具体的国家和地区
DateFormat 对象的方法:
- format: 将日期/时间对象格式化为符合某个本地环境习惯的字符串
- parse:将符合某个本地环境习惯的日期/时间字符串解析为日期/时间对象
@Test
public void testDate2() throws ParseException{
String dateStr = "1990-12-12 12:12:12";
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = dateFormat.parse(dateStr);
System.out.println(date);
System.out.println(dateFormat.format(new Date()));
}
@Test
public void testDate(){
//Locale 在 Java 中表示国家个地区的类
Locale locale = Locale.CHINA;
Date date = new Date();
System.out.println(date);
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, locale);
String str = dateFormat.format(date);
System.out.println(str);
}
(4).NumberFormat 类
NumberFormat 可以将一个数值格式化为符合某个国家地区习惯的数值字符串,也可以将符合某个国家地区习惯的数值字符串解析为对应的数值
NumberFormat 类的方法:
- format 方法:将一个数值格式化为符合某个国家地区习惯的数值字符串
- parse 方法:符合某个国家地区习惯的数值字符串解析为对应的数值
/**
* NumberFormat:格式化数字到数字字符串,或货币字符串的工具类。
* 1.通过工厂方法获取 NumberFormat 对象
* NumberFormat.getNumberInstance(locale)//仅格式化数字的字符串
* NumberFormat.getCurrencyInstance(locale) //格式化货币的字符串
* 2. 通过 format 方法来进行格式化
* 3.通过 parse 方法将一个字符串解析为一个 Number 类型
*/
@Test
public void testNumberFormat() throws Exception{
double d = 12345121546.12455d;
Locale locale = Locale.CHINA;
//转数字
NumberFormat numberFormat = NumberFormat.getNumberInstance(locale);
String str = numberFormat.format(d);
System.out.println(str);
//转货币
NumberFormat numberFormat2 = NumberFormat.getCurrencyInstance(locale);
str = numberFormat2.format(d);
System.out.println(str);
//解析字符串到对应值
System.out.println(numberFormat.parse("12,456,789.456"));
System.out.println(numberFormat2.parse("¥12,456,789.456"));
}
(5).MessageFormat 类
MessageFormat 类提供了一种参数替换模式字符串中的占位符的方式,它将根据模式字符串中包含的占位符产生一系列的格式化对象,然会调用这些格式化对象对参数进行格式化,并用格式化后的结果字符串替换模式字符串中的相应占位符。
格式化模式字符串的步骤:
- 创建 MessageFormat 对象:须指定格式化的模式字符串,也可以指定 Locale 对象来按某个国家地区的习惯进行格式化。
- 调用 MessageFormat 对象的 format 方法执行格式化操作:须为format 方法传递一个数组类型的参数,数组中的每个元素分别用于代替模式字符串中的与其索引号相对应的占位符
/*
* MessageFormat:可以格式化模式字符串。
* 模式字符串:带占位符的字符串:"Date:{0}, Salary:{1}"。
* 可以通过 format 方法对模式字符串进行格式化。
*/
@Test
public void testMessageFormat(){
String str = "Date:{0}, Salary:{1}";
Locale locale = Locale.CHINA;
Date date = new Date();
double sal = 8800.456;
DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM);
NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale);
String dateStr = dateFormat.format(date);
String salStr = numberFormat.format(sal);
String reslut = MessageFormat.format(str, dateStr,salStr);
System.out.println(reslut);
//运行结果:Date:2018-3-2, Salary:¥8,800.46
}
(6).ResourceBundle 类
ResourceBundle 类用于描述一个资源包,一个资源包用于包含一组与某个本地环境相关的对象,可以从一个资源包中获取特定于本地环境的对象。对于不同的本地环境,可以有不同的 ResourceBundle 对象与之关联,关联的 ResourceBundle 对象中包含该本地环境下专有的对象
资源包简介
在设计一个国际化应用时,应该把程序显示的文本内容从源程序中分离出来,放在独立的资源文件中,并针对不同的本地环境编写不同的资源文件。这些资源文件被称为应用程序的资源包
应用程序在运行时,将从与用户的本地环境相对应资源文件中读取名称项对应的值的内容,由于同一个名称项在各个资源文件中对应的值内容是随本地环境信息而改变的,这样就实现了程序的静态文本内容的国际化。
当要为应用程序添加某个新的本地化支持时,只需编写一个适合的本地环境的资源文件即可,不用修改源程序代码
i18n_en_US.properties:
Date=Date
Salary=Salary
i18n_zh_CN.properties:
Date=\u65E5\u671F
Salary=\u5DE5\u8D44
/*
* ResourceBundle:资源包类.
* 1.在类路径下必须要有对应的资源文件:baseName.properties.其中 baseName 是基名。
* 2.可以使用 基名_语言代码_国家代码.properties 来添加不同国家或地区的资源文件。比如:i18n_zh_CN.properties.
* 3.要求所有基名相同的资源文件的 key 必须相同。
* 4.可以调用 ResourceBundle 的 getBundle(基名,Locale 实例) 来获取 ResourceBundle 对象。
* 5.可以调用 ResourceBundle 的 getString(key) 来获取资源文件的 value 值。
* 6.结合 DateFormat,NumberFormat,MessageFormat 即可实现国际化。
*/
@Test
public void testResourceBundle(){
Locale locale = Locale.CHINA;
ResourceBundle resourceBundle = ResourceBundle.getBundle("i18n", locale);
String dateLable = resourceBundle.getString("Date");
String salLable = resourceBundle.getString("Salary");
String str = "{0}:{1}, {2}:{3} ";
Date date = new Date();
double sal = 8800.456;
DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM);
NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale);
String dateStr = dateFormat.format(date);
String salStr = numberFormat.format(sal);
String reslut = MessageFormat.format(str, dateLable,dateStr,salLable,salStr);
System.out.println(reslut);
}
/*运行结果:
CHINA:日期:2018-3-2, 工资:¥8,800.46
US: Date:2018-3-2, Salary:$8,800.46
......
*/
(7).国际化标签库
- 实现 web 应用国际化有两种方式:
- 针对不同语言和地区的用户开发出不同的 JSP 网页版本,当用户请求资源时,根据请求消息中携带的本地信息为用户提供合适的版本
- 将对本地环境敏感的资源数据(例如:错误提示信息,菜单文字等)从网页中分离出来,放在 .properties 属性资源文件中。对于应用程序中的数值,货币和日期/时间等本地敏感数据,可以通过占位符的方式设置它们的格式类型和格式模式
user_en_US.properties:
name=Name
sex=Sex
age=Age
tel=TEL
address=Address
date=Birthday
title=Please fill in your information
user_zh_CN.properties:
name=\u59D3\u540D
sex=\u6027\u522B
age=\u5E74\u9F84
tel=\u7535\u8BDD
address=\u5730\u5740
salary=\u85AA\u8D44
date=\u751F\u65E5
title=\u8BF7\u586B\u5199\u4FE1\u606F
index.jsp:
<%@page import="java.util.Locale"%>
<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<style type="text/css">
td{
width: 80px;
height: 40px;
}
</style>
</head>
<body>
<%
Date date = new Date();
String code = request.getParameter("code");
if("en".equals(code)){
session.setAttribute("Locale",Locale.US);
}else if("zh".equals(code)){
session.setAttribute("Locale",Locale.CHINA);
}
%>
<c:if test="${sessionScope.Locale != null }">
<fmt:setLocale value="${sessionScope.Locale }"/>
</c:if>
<fmt:setBundle basename="user"/>
<table border="1" cellspacing="0" cellpadding="10" >
<caption><fmt:message key="title"></fmt:message></caption>
<tr>
<td><fmt:message key="name" />:</td>
<td><input type = "text"/></td>
</tr>
<tr>
<td><fmt:message key="sex"></fmt:message>:</td>
<td><input type = ""text""/></td>
</tr>
<tr>
<td><fmt:message key="age"></fmt:message>:</td>
<td><input type = "text"/></td>
</tr>
<tr>
<td><fmt:message key="tel"></fmt:message>:</td>
<td><input type = ""text""/></td>
</tr>
<tr>
<td><fmt:message key="address"></fmt:message>:</td>
<td><input type = ""text""/></td>
</tr>
<tr>
<td><fmt:message key="date"></fmt:message>:</td>
<td><input type = "text"/></td>
</tr>
</table>
<br><br>
<a href="index.jsp?code=en">English</a>
<a href="index.jsp?code=zh">中文</a>
</body>
</html>
运行结果
1.英文:
2.中文:
点击中文将当前页面切换成 “中文” 状态,点击 “English” 将当前页面切换成英文状态。