Session的追踪技术
已知Session是利用cookie机制的server端技术。当client第一次訪问资源时 假设调用request.getSession() 就会在server端创建一个由浏览器独享的session空间,并分配一个唯一且名称为JSESSIONID的cookie发送到浏览器端,假设浏览器没有禁用cookie的话,当浏览器再次訪问项目中的Servlet程序时会将JSESSIONID带着。这时JSESSIONID就像唯一的一把钥匙 开启server端相应的session空间。进而获取到session中的内容(Session没有失效的情况下)。之所以第一次訪问会创建与浏览器相应的一个Session空间。是由于第一次訪问浏览器是不会携带相应的JSESSIONID,凡是不带有JSESSIONID的訪问
调用request.getSession()方法都会为client创建一个session空间。
当浏览器client禁用了cookie之后,浏览器端就无法保存JSESSIONID,就无法使用session。
不是说server端的Session空间丢失了,而是在server端找到打开相应Session空间的钥匙(JSESSIONID)丢失了。这时就须要使用Session的追踪技术。
session的销毁:
(1)非正常关闭server。注意:非正常关闭server是不会序列化session到本地的。会导致session丢失。
(2)手动正常关闭server。
不会导致session丢失(正常关闭server后,会在server中将session存储起来。再次启动server的时候 会被又一次载入到内存中)
(3)session的过期。默认是30分钟(在不关闭浏览器的情况下) 能够在server的web.xml文件里进行设置
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<session-timeout>30</session-timeout>
</session-config>
注意:关闭浏览器 后又一次訪问无法获取session内容 并非由于session被销毁 而是session仅仅是一次会话,其client的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); } }
正常关闭server
又一次启动server 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对client输出缓冲区的大小,默认是8kb (buffer="8k")
- autoFlush:设置默认自己主动刷新缓冲区(不须要改变),假设buffer溢出。设置成true时正常输出。设置成false时 出现异常 (autoFlush="true")
- errorPage: 处理异常事件时调用的JSP页面 ,指定错误页面 (errorPage="error.jsp")
- isErrorPage:设置此页能否够为其他页的errorPage目标 (设置值为true,能够是exception对象。设置成false不能使用exception对象)
- contentType:定义JSP页面响应的MIME类型(指定server端输出全部内容採用的编码 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>亲,server正在维护。!</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>亲。您訪问的资源恋爱了,不在服务区!!500.jsp</h3> </body> </html>
<%@ 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>亲。server正在维护,这回是真的维护!!</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
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; %>
<%@ 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>
执行结果:
打开Tomcatserver中的工作文件夹:
静态包括的原理是把 所包括的文件内容全然拷贝到一块,然后进行翻译成一个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() |
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对象
- 向client输出数据
- 管理server输出缓冲区
- 内部使用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> 文件包括(server端路径,没有项目名称)
<jsp:forward> 在JSP页面中完毕转发(server端路径。没有项目名称)
<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>
<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"/>
<%
}
%>
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全局架构标签,否则输出给client的内容将会是一个格式混乱的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>执行结果例如以下:
打开server中的工作文件夹查看例如以下:
原理例如以下:
接着測试 <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);
}
}
翻译成的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技术的WEBserver。
注意:有些Tomcatserver假设不能使用EL表达式。解决方法例如以下:
(1)升级成Tomcat6
(2)在JSP中增加 <%@ page isELIgnored="false" %>
EL获取数据(一)
- 使用EL表达式获取数据的语法:${标识符}
- EL表达式语句在运行时。会调用pageContext.findAttribute方法,用标识符为keyword,分别从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表达式保留keyword
所谓保留字的意思是指变量在命名时,应该避开上述的名字。以免程序编译时错误发生。
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对象 |
paramValues相当与request.getParameterValues();
${cookie.name.name} ${cookie.name.value}
${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>
<%@ 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>执行结果:
跳转后: