Session的追踪技术
已知Session是利用cookie机制的服务器端技术,当客户端第一次访问资源时 如果调用request.getSession() 就会在服务器端创建一个由浏览器独享的session空间,并分配一个唯一且名称为JSESSIONID的cookie发送到浏览器端,如果浏览器没有禁用cookie的话,当浏览器再次访问项目中的Servlet程序时会将JSESSIONID带着,这时JSESSIONID就像唯一的一把钥匙 开启服务器端对应的session空间,进而获取到session中的内容(Session没有失效的情况下)。之所以第一次访问会创建与浏览器对应的一个Session空间,是因为第一次访问浏览器是不会携带对应的JSESSIONID,凡是不带有JSESSIONID的访问 调用request.getSession()方法都会为客户端创建一个session空间。
当浏览器客户端禁用了cookie之后,浏览器端就无法保存JSESSIONID,就无法使用session。不是说服务器端的Session空间丢失了,而是在服务器端找到打开对应Session空间的钥匙(JSESSIONID)丢失了。这时就需要使用Session的追踪技术。
session的销毁:
(1)非正常关闭服务器。注意:非正常关闭服务器是不会序列化session到本地的。会导致session丢失。
(2)手动正常关闭服务器。不会导致session丢失(正常关闭服务器后,会在服务器中将session存储起来,再次启动服务器的时候 会被重新加载到内存中)
(3)session的过期,默认是30分钟(在不关闭浏览器的情况下) 可以在服务器的web.xml文件中进行设置
<session-config>
<session-timeout>30</session-timeout>
</session-config>
注意:关闭浏览器 后重新访问无法获取session内容 并不是因为session被销毁 而是session只是一次会话,其客户端的JSESSIONID是保存在内存里的,关闭浏览器后JSESSIONID在内存里被释放。
(4)调用session.invalidate() 手动销毁session 。
示例如下:
SessionDemo1.java 路径:/session1
public class SessionDemo1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// session域对象
HttpSession session = request.getSession();
session.setAttribute("username", "小风");
// DD64756D56885AF87E883B887BF77E6C jsessionid=DD64756D56885AF87E883B887BF77E6C
System.out.println(session.getId());
response.sendRedirect("/day12/session2");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
SessionDemo2.java /session2
package cn.itcast.session;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class SessionDemo2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 手动传入jsessionid=DD64756D56885AF87E883B887BF77E6C
HttpSession session = request.getSession();
String username = (String) session.getAttribute("username");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("<h4>访问到了..."+username+"</h4>");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
正常关闭服务器
重新启动服务器 session又被反序列化到内存中
禁用浏览器的cookie之后
重新访问:
发现cookie被浏览器被禁用之后,无法获取session空间的内容。可以使用cookie追踪技术,就是在跳转路径后加上;jsessionid=DE3D5641D0D1D248D66C7A3D67E47F8E 访问路径即http://localhost/day12/session2;jsessionid=DE3D5641D0D1D248D66C7A3D67E47F8E 效果如下:
session的域对象:
ServletContext:代表整个web应用,数据库连接
session:一次会话,存放个人信息
request:一次请求,存放错误处理
JSP设置与页面的注释
(1)设置JSP文件的打开方式(以便快速打开)window -- 选项 -- General -- Editors -- 文件关联 -- *.jsp -- 选择MyEclipse JSP Editor -- default
(2)设置JSP的编码(用于显示中文)window -- 搜索JSP -- 找到JSP -- 选择UTF-8 -- OK
JSP页面的注释:
(1)HTML的注释 <!-- --> JSP文件的阶段存在,在翻译成Java文件后也存在,在页面也存在。
(2)Java的注释 JSP文件的阶段存在,在翻译成Java文件也存在,在页面不存在。
<%
// 单行
/**/ 多行
/**
* 文档注释
*/
%>
(3)JSP的注释 <%-- JSP的注释 --%> 只存在于JSP文件阶段。
JSP指令元素
功能:用于指示JSP执行某些步骤 或用于指示JSP表现特定行为。
语法格式:<%@ directive [attribute="value"]*%> 即 <%@ 指令元素 属性名=属性值 %>
分类:page指令标记、include指令标记、taglib指令标记
page指令标记
(1)page属性包含在" <%@ page " 和 "%>" 之间。
(2)这些属性可以单独使用,也可以几个或多个同时使用。
(3)在JSP页面中,只有import可以出现多次,其他属性都只能出现一次。
page指令属性:
- language:声明使用脚本的种类,即JSP文件运行嵌入的语言。目前只支持Java一种语言(不需要改变)例如:language="java"
- extends:JSP翻译成Servlet的Java文件时,Servlet继承的类(不需要改变)例如:extends="src.class"
- session:例如session="true",指定一个Http会话是否使用session对象,默认值是true 可以直接使用session。设置成false不能直接使用session(如果设置成false 要想获取session 只能使用Java代码 <% HttpSession session2 = request.getSession() %>)
- import: 用于导入Java包或类的列表 (可以使用后多次 import="java.util.Date")
- buffer:指定JSP对客户端输出缓冲区的大小,默认是8kb (buffer="8k")
- autoFlush:设置默认自动刷新缓冲区(不需要改变),如果buffer溢出,设置成true时正常输出,设置成false时 出现异常 (autoFlush="true")
- errorPage: 处理异常事件时调用的JSP页面 ,指定错误页面 (errorPage="error.jsp")
- isErrorPage:设置此页是否可以为其它页的errorPage目标 (设置值为true,可以是exception对象,设置成false不能使用exception对象)
- contentType:定义JSP页面响应的MIME类型(指定服务器端输出所有内容采用的编码 contentType="text/html,charset=utf-8")
- pageEncoding:JSP页面字符编码,其优先权高于contentType(JSP翻译成Servlet文件时采用的编码 pageEncoding="gb2312")
- isELIgnored:用于指定EL(表达式语言)是否被忽略。true则忽略,false则计算表达式的值 (isELIgnored="false")
重点:session import contentType pageEncoding isELIgnored
配置全局的错误页面
在项目中的web.xml中进行配置:
<error-page>
<error-code>404</error-code>
<location>/404.jsp</location>
<error-page>
<error-page>
<error-code>500</error-code>
<location>/500.jsp</location>
</error-page>
注意:所有的请求出现错误后 都会跳转到对应的错误页面。errorPage属性的优先级大于全局错误页面的优先级。如果一个JSP的page指令属性后指定了errorPage属性,出现了错误的话,会跳转到errorPage指定的页面。
在WebRoot下新建jsp的文件夹,在jsp文件夹下新建demo.jsp、error.jsp, 在WebRoot根目录下下新建全局的错误页面404.jsp、500.jsp 进行测试page指令有关的属性
error.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" isErrorPage="true" %>
<!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>
</head>
<body>
<h3>亲,服务器正在维护!!</h3>
<%=exception.getMessage() %>
</body>
</html>
404.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>
</head>
<body>
<h3>亲,您访问的资源恋爱了,不在服务区!!</h3>
</body>
</html>
500.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>
</head>
<body>
<h3>亲,服务器正在维护,这回是真的维护!!</h3>
</body>
</html>
demo.jsp
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" session="true" buffer="8kb" autoFlush="true"
errorPage="/jsp/error.jsp" isELIgnored="false"%>
<!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>
</head>
<body>
<h4>欢迎</h4>
<%
List list = new ArrayList();
// int a = 10 / 0;
request.setAttribute("username", "小风");
%>
<!-- HTML的文本 -->
${ username }
</body>
</html>
首先测试errorPage属性,屏蔽demo.jsp代码中除了 int a=10/0; 以外的代码 运行结果如下:
去掉demo.jsp中page指令中的errorPage属性 再次运行
如果访问的路径错误 会跳转到全局的404错误页面
屏蔽错误代码 运行如下:
将demo.jsp 中page属性中的isELIgnored设置为true 运行如下:
include指令标记
include指令的语法格式如下:<%@ include file="filename"%> <%@ include file="要包含文件(静态包含)" %>
include指令的作用是在jsp页面中静态包含一个文件,同时由JSP解析包含的文件内容。
静态包含的含义:
file不能为一变量
<% String url="index.html" %>
<%@ include file="<%= url %>" %>
不可以在file所指定的文件后接任何参数
<%@ include file = "jw.jsp?nm=browser" %>
静态包含举例:
包含的是目标文件的源码;包含过来,一起翻译
main.jsp
<%
String s = “abc”;
%>
<%include file=“part.jsp” %>
part.jsp
<%=s %> 没有定义变量s
尽管part.jsp本身会有错误
但是运行main.jsp就可以正确引入part.jsp
测试include,在WebRoot中新建include文件夹,在include文件夹内新建body.jsp、head.jsp、foot.jsp、menu.jsp
body.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!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>
</head>
<body>
<%@ include file="/include/head.jsp" %>
<%@ include file="/include/menu.jsp" %>
<h3>网站的新闻(数据变化)</h3>
<%@ include file="/include/foot.jsp" %>
</body>
</html>
head.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<h3>网站的LOGO</h3>
<% int a = 100; %>
menu.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<h3>网站的超链接</h3>
<%= a %>
foot.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<h3>网站的友情链接</h3>
运行结果:
打开Tomcat服务器中的工作目录:
静态包含的原理是把 所包含的文件内容完全复制到一块,然后进行翻译成一个jsp文件,编译运行
JSP九大内置对象
request response session application out pageContext page config exception
内置对象 |
真实的对象 |
方法 |
request |
HttpServletRequest |
setAttribute() getAttribute() |
response |
HttpServletResponse |
addCookie() getWriter() |
session |
HttpSession |
setAttribute() getAttribute() |
application |
ServletContext |
setAttribute() getAttribute() |
config |
ServletConfig |
getInitParameter() getInitParameterNames() |
exception |
Throwable(所有的异常父类) |
getMessage() |
page |
Object |
(当前的Servlet对象 this(HttpServlet)) |
out |
JspWriter |
write() print() |
pageContext |
PageContext |
setAttribute() getAttribute() |
具体可以查看 由JSP翻译成的Servlet对象 查看如下:
exception对象:
(1)exception对象是java.lang.Throwable
(2)(使用前 isErrorPage="true")
(3)exception对象用来处理JSP文件在执行时所有发生的错误和异常
(4)exception对象可以和page指令一起使用,通过指定某一个页面为错误处理页面,对错误进行处理
<%@ page isErrorPage=true %> 的页面内使用
page对象(Servlet对象)
- "page" 对象代表了正在运行的由JSP文件产生的类对象(一般不建议使用)
- page对象是指向当前JSP程序本身的对象this
- page对象其实是java.lang.Object类的实例对象
out对象
- 向客户端输出数据
- 管理服务器输出缓冲区
- 内部使用PrintWriter对象来输出文本级数据
- 通过page指令的buffer属性来调整缓冲区的大小,默认的缓冲区是8kb
JSPWriter PrintWriter response.getWriter()
程序实例如下:在jsp文件夹下新建out.jsp
out.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>
</head>
<body>
<!-- BBBB HELLO AAAA CCCC -->
<%= "HELLO" %>
<% out.print("AAAA"); %>
<% response.getWriter().print("BBBB"); %>
<% out.print("CCCC"); %>
</body>
</html>
运行结果如下:
查看最后返回的页面源代码如下:
pageContext对象
pageContext对象也是域对象,代表当前的页面范围,在当前的页面范围内获取数据。
向JSP的四个作用域范围内存数据。
Servlet中有三个域,而JSP中有四个域
JSP中多了多了pageCOntext的域范围,代表当前页面范围。
域对象
自己存取值 setAttribute(String name, Object value)
向其他的域存取值
setAttribute(String name,Object value, int scope)
getAttribute(String name,int scope)
findAttribute(String name)
获取其它8个内置对象
编写框架、通用性较高的代码。
pageContext中的方法:
setAttribute(String name, Object value)
setAttribute(String name, Object value, int scope)
getAttribute(String name)
getAttribute(String name, int scope)
removeAttribute(String name)
removeAttribute(String name, int scope)
findAttribute(String name)
通过pageContext对象获得其它对象:
getException方法返回exception隐式对象
getPage方法返回page隐式对象
getRequest方法返回request隐式对象
getResponse方法返回response隐式对象
getServletConfig方法返回config隐式对象
getServletContext方法返回application隐式对象
getSession方法返回session隐式对象
getOut方法返回out隐式对象
实例如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>
</head>
<body>
<%=request.getParameter("username") %>
<h4>pageContext向其他域中存入值</h4>
<%
pageContext.setAttribute("name", "美美");
// 下面这句等价于上面
pageContext.setAttribute("name", "美美", pageContext.PAGE_SCOPE);
request.setAttribute("name", "小凤");
// 向request域中存入值
pageContext.setAttribute("name", "小凤", pageContext.REQUEST_SCOPE);
// 向session域存入值
pageContext.setAttribute("name", "小苍", pageContext.SESSION_SCOPE);
// 向ServletContext域存入值
pageContext.setAttribute("name", "小班长", pageContext.APPLICATION_SCOPE);
%>
<%= pageContext.getAttribute("name", pageContext.SESSION_SCOPE)%>
<%= session.getAttribute("name") %>
${ pageScope.name }
${ requestScope.name }
${ sessionScope.name }
${ applicationScope.name }
</body>
</html>
JSP标签
JSP标签也称之为JSP Action(jsp动作)元素,它用于在JSP页面中提供业务逻辑代码,避免在JSP页面中直接编写Java代码,造成jsp页面难以维护。
<jsp:useBean> 使用一个ID和一个给定作用范围和同一ID的JavaBean相关联。
<jsp:setProperty> 设置JavaBean的属性值
<jsp:getProperty> 取得JavaBean的属性值
<jsp:include> 文件包含(服务器端路径,没有项目名称)
<jsp:forward> 在JSP页面中完成转发(服务器端路径,没有项目名称)
<jsp:param> 需要写在 <jsp:forward>的中间
<jsp:forward> 和 <jsp:param>
将请求传递给另一个JSP页面 <jsp:forward page="转发路径" />
<jsp:param> 用来传递参数,可以写在<jsp:forward>中间,可以使用request.getParameter(); 来接收参数。
<jsp:forward>之后的代码不执行
语法格式如下:
<jsp:forward page={"relativeURL" | "<%= expression %>"} />
<jsp:forward page={"relativeURL" | "<%= expression %>"} >
<jsp:param name="PN" value="{PV | <%= expression %>"}/> *
</jsp:forward>
在Servlet中如果使用request.getRequestDispatcher.forward进行页面跳转,那么该语句以后的代码会执行:
request.getRequestDispatcher.forward(“XXX”);
System.out.println(“It can execute…”);
但是JSP中<jsp:forward>后面的代码不会执行,因为翻译的时候,Serlvet容器自动为<jsp:forward>后面添加了return语句,例如:
<%
String s=request.getRemoteAddr();
if(s.startsWith("10.28.176.",0)){
%>
<jsp:forward page="index_inner.jsp"/>
<%}else{ %>
<jsp:forward page="index_outter.jsp"/>
<%
}
%>
<jsp:include>与include指令的比较
- <jsp:include>标签是动态引入,<jsp:include>标签涉及到的2个JSP页面会被翻译成2个servlet,这2个Servlet的内容在执行时进行合并。
- 而include指令是静态引入,涉及到的2个JSP页面会被翻译成一个Servlet,其内容是在源文件级别进行合并。
- 不管是<jsp:include>标签,还是include指令,它们都会把两个JSP页面内容合并输出,所以这两个页面不要出现重复的HTML全局架构标签,否则输出给客户端的内容将会是一个格式混乱的HTML文档。
include两种用法的区别:
主要有两个方面的不同:
(1)执行时间上
<%@ include file="relativeURI" %> 是在翻译阶段执行
<jsp:include page="relativeURI" flush="true" />
(2)引入的内容不同
<%@ include file="relativeURI" %> 引入静态文本(html, jsp),在JSP页面被转化成Servlet之前和它融合在一起。
<jsp:include page="relativeURI" flush="true" /> 引入执行页面或Servlet所生成的应答文本。另外两种方法中的file和page属性都被翻译成一个相对的URI。如果它以斜杠开头,那么它就是一个环境相关的路径,将根据赋给应用程序的URI的前缀进行解释;如果它不是以斜杠开头,那么就是页面相关的路径,就根据引入这个文件的页面所在的路径进行解释。
举例说明两种包含的区别:
如果被包含的JSP页面有错误的话,静态包含是无法编译执行的。而动态包含则不受影响。
实例验证动态包含和<jsp:forward>
在WebRoot下新建action的文件夹,在action文件夹中新建body.jsp、head.jsp、menu.jsp、foot.jsp
head.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
int a = 10;
%>
<%= a %>
<h3>网站的LOGO</h3>
menu.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<h3>网站的超链接</h3>
foot.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<h3>网站的友情链接</h3>
body.jsp
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<jsp:include page="/action/head.jsp"></jsp:include>
<jsp:include page="/action/menu.jsp"></jsp:include>
<h3>网站的新闻(数据变化)</h3>
<jsp:include page="/action/foot.jsp"></jsp:include>
</body>
</html>
运行结果如下:
打开服务器中的工作目录查看如下:
原理如下:
接着测试 <jsp:forward> 在action文件夹下新建forward.jsp
forward.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>
</head>
<body>
<h4>JSP的动作标签</h4>
<jsp:forward page="/jsp/pageContext.jsp">
<jsp:param name="username" value="meimei"/>
</jsp:forward>
</body>
</html>
运行结果:
JavaBean及内省
什么是JavaBean?
(1)JavaBean是一个遵循特定写法的Java类,它通常具有如下特点:
这个Java类必须具有一个无参的构造函数
属性私有化
私有化的属性必须通过public类型的方法暴露给其他程序,并且方法的命名也必须遵守一定的命名规范。
(2)JavaBean在J2EE开发中,通常用于封装数据,对于遵循以上写法的JavaBean组件,其他程序可以通过反射技术实例化JavaBean对象,并且通过反射那些遵守命名规范的方法,从而获知JavaBean的属性,进而调用属性保存数据。
JavaBean的属性:
- JavaBean的属性可以是任意类型,并且一个JavaBean可以有多个属性。每个属性通常都需要具有setter、getter方法,setter方法称为属性的修改器,getter方法称为属性访问器。
- 属性修改器必须以小写的set前缀开始,后跟属性名,且属性名的第一个字母要大写,例如,name属性的修改器名称为setName,password属性修改器名称为setPassword
- 属性访问器通常以小写的get前缀开始,后跟属性名,且属性名的第一个字母也要改为大写,例如,name属性访问器名称为getName,password属性访问器是getPassword
- 一个JavaBean的某个属性也可以只有set方法或get方法,这样的属性通常也称之为只写、只读属性。(JavaBean的属性不是由对象中定义的变量决定的,是由get或者set方法决定的)
在JSP中使用JavaBean:
JSP技术提供了三个关于JavaBean组件的动作元素,即JSP标签,它们分为如下几种。
<jsp:useBean>标签:用于在JSP页面中查找或实例化一个JavaBean组件。
<jsp:setProperty>标签:用于在JSP页面中设置一个JavaBean组件的属性。
<jsp:getProperty>标签:用于在JSP页面中获取一个JavaBean组件的属性。
编写表单页面,把数据提交到另一个JSP的页面,可以使用传统方式封装数据,也可以使用<jsp:useBean>来封装数据。设置属性是<jsp:setProperty name="u" property="*"> *代表所有的属性。
<jsp:useBean>标签
<jsp:useBean>标签用于在指定的域范围内查找指定名称的JavaBean对象:
如果存在则直接返回该JavaBean对象的引用。
如果不存在则实例化一个新的JavaBean对象并将它以指定的名称存储到指定的域范围内。
常用语法:
<jsp:useBean id="beanName" class="cn.itcast.Test" scope="" /
>
id 属性用于指定JavaBean实例对象的引用名称和其存储在域范围中的名称。
class属性用于指定JavaBean的完整类名(即必须带包名)
scope属性用于指定JavaBean实例对象所存储的域范围,其取值只能是page、request、session、application等四个值中的一个,其默认值是page。
<jsp:useBean>执行原理:
<jsp:useBean id="currentDate" class="java.util.Date"/>
翻译成的Servlet源码:
java.util.Date currentDate = null;
synchronized (_jspx_page_context) {
currentDate = (java.util.Date) _jspx_page_context.getAttribute(
"currentDate", PageContext.PAGE_SCOPE);
if (currentDate == null){
currentDate = new java.util.Date();
_jspx_page_context.setAttribute("currentDate",
currentDate, PageContext.PAGE_SCOPE);
}
}
带标签体的<jsp:useBean>标签
语法:
<jsp:useBean...>
Body
</jsp:useBean>
功能:Body部分的内容只在<jsp:useBean> 标签创建JavaBean的实例对象时才执行。
<jsp:setProperty>标签
<jsp:setProperty>标签用于设置和访问JavaBean对象的属性
语法格式:
<jsp:setProperty name="beanName"
{
property="propertyName" value="{string | <%= expression%>}" |
property="propertyName" [ param="perameterName" ] |
property="*"
}
/>
name 属性用于指定JavaBean对象的名称。
property属性用于指定JavaBean实例对象的属性名。
value属性用于指定JavaBean对象的某个属性的值,value的值可以是字符串,也可以是表达式。为字符串时,该值会自动转化为JavaBean属性相关的类型,如果value的值是一个表达式,那么该表达式的计算结果必须与所要设置的JavaBean属性的类型一致。
param 属性用于将JavaBean实例对象的某个属性值设置为一个请求参数值,该属性的值同样会自动转换成要设置的JavaBean属性的类型。
<jsp:getProperty>标签
<jsp:getProperty>标签用于读取JavaBean对象的属性,也就是调用JavaBean对象的getter方法,然后将读取的属性值转换成字符串后插入进输出的响应正文中。
语法:
<jsp:getProperty name="beanInstanceName" property="PropertyName" />
name属性用于指定JavaBean实例对象的名称,其值应与<jsp:useBean>标签的id属性值相同。
property属性用于指定JavaBean实例对象的属性名。
如果一个JavaBean实例对象的某个属性的值为null,那么,使用<jsp:getProperty>标签输出该属性的结果将是一个内容是null的字符串。
内省(Introspector)——JavaBean
访问JavaBean属性的两种方式:
直接调用bean的setXXX或getXXX方法
通过内省技术访问(java.beans包提供了内省的API)
内省技术是基于反射技术的
通过Introspector类获得Bean对象的BeanInfo,然后通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后通过反射机制来调用这些方法。
关键代码示例:
public void populate(Map<String, String[]> map, User user) throws Exception {
BeanInfo info = Introspector.getBeanInfo(user.getClass());
PropertyDescriptor [] pds = info.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
String attrName = pd.getName();
if(map.containsKey(attrName)){
Method m = pd.getWriteMethod();
m.invoke(user, map.get(attrName)[0]);
}
}
}
在src下新建cn.itcast.test包,在包内新建InstrospectorTest.java测试类
package cn.itcast.test;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import org.junit.Test;
import cn.itcast.vo.User;
/**
* 测试类
* @author Administrator
*
*/
public class IntrospectorTest {
@Test
public void run() throws Exception{
User user = new User();
// 获取类的信息
BeanInfo info = Introspector.getBeanInfo(user.getClass());
// 获取属性的描述
PropertyDescriptor [] pds = info.getPropertyDescriptors();
// 循环遍历,获取属性的名称
for (PropertyDescriptor pd : pds) {
// System.out.println(pd.getName());
if(!"class".equals(pd.getName())){
// 获取写的方法
Method m = pd.getWriteMethod();
m.invoke(user, "admin");
}
}
System.out.println(user.getUsername());
System.out.println(user.getPassword());
}
}
运行结果:
内省—— beanutils工具包
需求:虽然JDK中的内省技术可以实现基本数据类型比如(String、float等)Bean属性的映射,但是对于别的类型例如Date日期类都不能进行映射。
Apache组织开发了一套用于操作JavaBean的API,这套API考虑到了很多实际开发中的应用场景,因此在实际开发中很多程序员使用这套API操作JavaBean,以简化程序代码的编写。
使用步骤:
首先导入需要使用的两个jar包(commons-beanutils-xxx.jar和commons-logging-xxx.jar)
Beanutils工具包的常用类:
BeanUtils
populate(Object bean, Map properties)
自定义转换器
ConvertUtils.register(Converter convert, Class clazz)
传入日期类型的Date.class
实现默认把字符串转换成日期类型
编写一个类,实现Converter接口。重写该方法。把字符串转换日期。
在封装数据之前进行注册。ConvertUtils.register(Converter converter, Class clazz) Date.class
关键代码如下:
public class MyConvert implements Converter{
/**
* 实现转换的方法
* clazz:类型
* obj:输入的内容
*/
public Object convert(Class clazz, Object obj) {
String sDate = (String)obj;
// 把字符串转换成日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date;
try {
date = sdf.parse(sDate);
} catch (ParseException e) {
e.printStackTrace();
throw new RuntimeException("日期转换错误");
}
return date;
}
}
// 进行日期转换注册
ConvertUtils.register(new MyConvert(), Date.class);
程序实例如下:
在src下新建cn.itcast.vo包(用来存储Bean类)在里面新建User.java Bean类
package cn.itcast.vo;
import java.util.Date;
/**
* User的JavaBean
* @author Administrator
*
*/
public class User {
private String username;
private String password;
private double money;
private Date birthday;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
在src下新建cn.itcast.utils包(工具类) 在里面新建MyDateConverter.java 类(用于注册其他类型的Bean)
MyDateConverter.java
package cn.itcast.utils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.commons.beanutils.Converter;
/**
* 字符串转换日期类
* @author Administrator
*
*/
public class MyDateConverter implements Converter{
/**
* 字符串转换成日期
*/
public Object convert(Class clazz, Object obj) {
// 把输入的字符串,转换成日期类型,返回
String dDate = (String) obj;
// 把字符串转换成日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date;
try {
date = sdf.parse(dDate);
} catch (ParseException e) {
e.printStackTrace();
throw new RuntimeException("转换日期错误");
}
return date;
}
}
在src下新建cn.itcast.servlet包,在包内新建UserServlet.java类(实现内省)和UserBeanUtilServlet.java(实现日期属性为Bean赋值)
UserServlet.java 路径:/user
package cn.itcast.servlet;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.itcast.vo.User;
/**
* 获取请求参数,封装数据
* @author Administrator
*
*/
public class UserServlet extends HttpServlet {
private static final long serialVersionUID = 6390620317553505800L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取请求参数,创建User对象,设置值。
/**
*
* // 获取表单的内容
String username = request.getParameter("username");
String password = request.getParameter("password");
// 创建User对象,set设置值
User user = new User();
user.setUsername(username);
user.setPassword(password);
*/
// 获取输入的数据
Map<String, String []> map = request.getParameterMap();
// 创建User对象
User user = new User();
// 自己编写封装数据的方法
try {
populate(map,user);
} catch (Exception e) {
e.printStackTrace();
}
// 完成数据封装
System.out.println(user.getUsername());
System.out.println(user.getPassword());
}
/**
* 完成的数据
* @param map
* @param user
* @throws Exception
*/
private void populate(Map<String, String[]> map, User user) throws Exception {
BeanInfo info = Introspector.getBeanInfo(user.getClass());
// 获取属性的描述
PropertyDescriptor [] pds = info.getPropertyDescriptors();
// 循环遍历
for (PropertyDescriptor pd : pds) {
// 获取到属性的名称
String name = pd.getName();
// map的key
if(map.containsKey(name)){
// 获取属性的写的方法
Method m = pd.getWriteMethod();
// 执行之
m.invoke(user, map.get(name)[0]);
}
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
UserBeanUtilServlet.java /userBeanUtil
package cn.itcast.servlet;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import cn.itcast.utils.MyDateConverter;
import cn.itcast.vo.User;
/**
* 使用BeanUtils完成数据的封装
* @author Administrator
*
*/
public class UserBeanUtilServlet extends HttpServlet {
private static final long serialVersionUID = 3625882115495534032L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取数据
Map<String, String []> map = request.getParameterMap();
// 创建User对象
User user = new User();
// 完成注册
ConvertUtils.register(new MyDateConverter(), Date.class);
// 完成封装
try {
BeanUtils.populate(user, map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
// 打印
System.out.println(user.getUsername());
System.out.println(user.getPassword());
System.out.println(user.getMoney());
System.out.println(user.getBirthday());
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
在WebRoot下新建文件夹bean文件夹,在文件夹下新建login.jsp 和success.jsp文件
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>
</head>
<body>
<h4>表单提交到JSP的页面</h4>
<form action="/day12/bean/success.jsp" method="POST">
姓名:<input type="text" name="username" /><br/>
密码:<input type="password" name="password" /><br/>
<input type="submit" value="登陆"/>
</form>
<h4>表单提交到Servlet程序</h4>
<form action="/day12/user" method="POST">
姓名:<input type="text" name="username" /><br/>
密码:<input type="password" name="password" /><br/>
<input type="submit" value="登陆"/>
</form>
<h4>表单提交到Servlet(BeanUtils)程序</h4>
<form action="/day12/userBeanUtil" method="POST">
姓名:<input type="text" name="username" /><br/>
密码:<input type="password" name="password" /><br/>
余额:<input type="text" name="money" /><br/>
生日:<input type="text" name="birthday" /><br/>
<input type="submit" value="登陆"/>
</form>
</body>
</html>
success.jsp ( <jsp:setProperty>等指令实现bean的赋值)
<%@page import="cn.itcast.vo.User"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>
</head>
<body>
<h3>传统方式封装数据</h3>
<%
// 获取表单的内容
String username = request.getParameter("username");
String password = request.getParameter("password");
// 创建User对象,set设置值
User user = new User();
user.setUsername(username);
user.setPassword(password);
%>
<!-- 使用jsp的标签封装数据 -->
<jsp:useBean id="u" class="cn.itcast.vo.User"></jsp:useBean>
<jsp:setProperty property="*" name="u"/>
<jsp:getProperty property="username" name="u"/>
<jsp:getProperty property="password" name="u"/>
</body>
</html>
跳转后如下:
EL表达式简介(运算及获取数据和web开发常用对象)
EL全名为Expression Language。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表达式注意事项:
EL表达式是JSP 2.0(JavaEE1.4)规范中的一门技术 。因此,若想正确解析EL表达式,需使用支持Servlet2.4/JSP2.0技术的WEB服务器。
注意:有些Tomcat服务器如果不能使用EL表达式,解决方法如下:
(1)升级成Tomcat6
(2)在JSP中加入 <%@ page isELIgnored="false" %>
EL获取数据(一)
- 使用EL表达式获取数据的语法:${标识符}
- EL表达式语句在执行时,会调用pageContext.findAttribute方法,用标识符为关键字,分别从page、request、session、application四个域中查找相应的对象,找到则返回相应的对象,找不到则返回 "" (注意:不是null而是空字符串)
- 示例:${user}
EL获取数据(二)
EL表达式也可以很轻松获取JavaBean的属性,或获取数组、Collection、Map类型集合的数据,例如:
${user.address.city}
${ user.list[0] }:访问有序集合某个位置的元素。
${ map.key }:获得map集合中指定key的值
[]和. 的区别:
数组或List有下标这种使用[],获得对象的属性的值的时候使用 . 如果属性中有特殊字符,需要使用[], 例如:map.put("ddd.eee","老师");——${ map["ddd.eee"] }
EL执行运算(三)
语法:${运算表达式},EL表达式支持如下运算符:
关系运算符 |
说明 |
范例 |
结果 |
== 或eq |
等于 |
${ 5 == 5 } 或${ 5 eq 5 } |
true |
!= 或 ne |
不等于 |
${ 5 != 5 } 或 ${ 5 nq 5} |
false |
< 或 lt |
小于 |
${ 3 < 5 } 或 ${ 3 lt 5 } |
true |
> 或 gt |
大于 |
${ 3 > 5 } 或 ${ 3 gt 5 } |
false |
<= 或 le |
小于等于 |
${ 3 <= 5 } 或 ${ 3 le 5 } |
true |
>= 或 ge |
大于等于 |
${ 3 >= 5 } 或 ${ 3 ge 5 } |
false |
逻辑运算符 |
说明 |
范例 |
结果 |
&& 或 and |
交集 |
${ A && B } 或 ${ A and B } |
true/false |
|| 或 or |
并集 |
${ A || B } 或 ${ A or B } |
true/false |
! 或 not |
非 |
${ !A } 或 ${ not A } |
true/false |
empty运算符:检查对象是否为null 或 "空"
二元表达式:${ user != null?user.name:""}
关键代码:
<%
request.setAttribute("n1", 10);
request.setAttribute("n2", 20);
request.setAttribute("n3", 30);
request.setAttribute("n4", 40);
%>
<h3>算术运算</h3>
${ n1 + n2 }
<h3>关系运算</h3>
${n1 > n2 }${n1 gt n2 }<br/>
${n1 < n2 }${n1 ltn2 }<br/>
${n1 >= n2 }${n1 gen2 }<br/>
${n1 <= n2 }${n1 len2 }<br/>
${n1 == n2 }${n1 eqn2 }<br/>
${n1 != n2 }${n1 nen2 }<br/>
<h3>逻辑运算</h3>
${n1>n2 && n3>n4 }${n1>n2 and n3>n4 }<br/>
${n1>n2 || n3>n4 }${n1>n2 or n3>n4 }<br/>
${ !(n1>n2) }${not (n1>n2)}<br/>
EL表达式保留关键字
所谓保留字的意思是指变量在命名时,应该避开上述的名字,以免程序编译时发生错误。
EL表达式获得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对象 |
param相当于request.getParameter();
paramValues相当与request.getParameterValues();
${cookie.name.name} ${cookie.name.value}
测试各个隐式对象
注意事项:
测试headerValues时,如果头里面有"-",例如Accept-Encoding,则要headerValues["Accept-Encoding"]
测试cookie时,例${cookie.key} 取的时cookie对象,如访问cookie的名称和值,须${cookie.key.name} 或${cookie.key.value}
实例如下:
在WebRoot下新建 el文件夹。在文件夹内新建jsp进行验证:
elDemo1.jsp
<%@page import="cn.itcast.vo.User2"%>
<%@page import="cn.itcast.vo.User"%>
<%@page import="java.util.HashMap"%>
<%@page import="java.util.Map"%>
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>
</head>
<body>
<h4>获取域对象中的值</h4>
<%
pageContext.setAttribute("name", "黄海波");
request.setAttribute("name", "美美");
%>
${ pageScope.name }
${ requestScope.name }
<h4>域中数组的值</h4>
<%
String [] arrs = {"美美","波波","东东","名名"};
request.setAttribute("arrs", arrs);
%>
${ arrs[2] }
<h4>域中集合的值</h4>
<%
List<String> list = new ArrayList<String>();
list.add("美美");
list.add("小凤");
list.add("芙蓉");
request.setAttribute("list", list);
%>
${ list[1] }
<h4>域中Map集合的值</h4>
<%
Map<String,String> map = new HashMap<String,String>();
map.put("aa", "美美");
map.put("bb", "小凤");
request.setAttribute("map", map);
%>
${ map.bb }
<h4>域中集合中有对象的值</h4>
<%
List<User2> uList = new ArrayList<User2>();
uList.add(new User2("banzhang","123"));
uList.add(new User2("美美","abc"));
request.setAttribute("uList", uList);
%>
${ uList[1].username }
</body>
</html>
运行结果:
注意:如果name前没有指定范围 ${name} , 会默认从域范围从小到大进行查找 先从pageScope—> requestScope—>sessionScope —>applicationScope
elDemo2.jsp (EL进行算术和逻辑运算)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>
</head>
<body>
<h4>EL的运算</h4>
<%
request.setAttribute("n1", 10);
request.setAttribute("n2", 20);
request.setAttribute("n3", 30);
request.setAttribute("n4", 40);
%>
<h4>加法运算</h4>
${ n1 + n2 }
<h3>关系运算</h3>
<h4>大于</h4>
${ n1 > n2 } ${ n1 gt n2 }
<h4>小于</h4>
${ n1 < n2 } ${ n1 lt n2 }
<h4>等于</h4>
${ n1 == n2 } ${ n1 eq n2 }
<h4>不等于</h4>
${ n1 != n2 } ${ n1 ne n2 }
<h4>大于等于</h4>
${ n1 >= n2 } ${ n1 ge n2 }
<h4>小于等于</h4>
${ n1 <= n2 } ${ n1 le n2 }
<h3>逻辑运算</h3>
<h4>与</h4>
${ n1 > n2 && n3 > n4 } ${ n1 > n2 and n3 > n4 }
<h4>或</h4>
${ n1 > n2 || n3 > n4 } ${ n1 > n2 or n3 > n4 }
<h4>非</h4>
${ !(n1 > n2) } ${ not (n1 > n2) }
</body>
</html>
结果:
elDemo3.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>
</head>
<body>
<h4>EL的运算</h4>
<form action="/day12/el/elDemo4.jsp" method="POST">
姓名:<input type="text" name="username" /><br/>
<input type="submit" value="登陆"/>
</form>
</body>
</html>
elDemo4.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>
</head>
<body>
<h4>EL的WEB对象</h4>
${ param.username }
<h4>获取请求头</h4>
${ header.referer }
<h4>获取全局初始化参数</h4>
${ initParam.username }
<h4>pageContext对象</h4>
${ pageContext.request.contextPath }
</body>
</html>
运行结果:
跳转后: