首页 > 代码库 > JAVAWEB开发之Session的追踪创建和销毁、JSP详解(指令,标签,内置对象,动作即转发和包含)、JavaBean及内省技术以及EL表达式获取内容的使用
JAVAWEB开发之Session的追踪创建和销毁、JSP详解(指令,标签,内置对象,动作即转发和包含)、JavaBean及内省技术以及EL表达式获取内容的使用
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-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
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>
运行结果:
打开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() |
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=http://www.mamicode.com/"{PV | "}/> *
</jsp:forward>
<jsp:forward page={"relativeURL" | "<%= expression %>"} >
<jsp:param name="PN" value=http://www.mamicode.com/"{PV | "}/> *
</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全局架构标签,否则输出给客户端的内容将会是一个格式混乱的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=http://www.mamicode.com/"meimei"/>>运行结果:
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=http://www.mamicode.com/"{string | }" |
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=http://www.mamicode.com/"登陆"/>>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对象 |
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=http://www.mamicode.com/"登陆"/>>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>运行结果:
跳转后:
JAVAWEB开发之Session的追踪创建和销毁、JSP详解(指令,标签,内置对象,动作即转发和包含)、JavaBean及内省技术以及EL表达式获取内容的使用
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。