内置对象application
实现用户之间的数据共享
与session 对象不同的是,所有客户的 application 对象是相同的一个,即所有的客户共享这个内置的 application 对象
常用方法:
public Enumeration getAttributeNames() 该方法产生一个枚举对象,该枚举对象使用 nextElemets()遍历application 对象所含有的全部对象。
public void removeAttribue(String key)从当前 application 对象中删除关键字是 key 的对象。
public String getServletInfo()获取 Servlet 编译器的当前版本的信息。
pageContext 内置对象 代表了JSP页面编译后的内容。它封装了对其他8大内置对象的引用!,也就是说,通过pageContext可以获取到其他的8个内置对象!
<% System.out.println(pageContext.getSession()); System.out.println(pageContext.getRequest()); System.out.println(pageContext.getResponse()); System.out.println(pageContext.getException()); System.out.println(pageContext.getPage()); System.out.println(pageContext.getServletConfig()); System.out.println(pageContext.getServletContext()); System.out.println(pageContext.getOut()); %>
pageContext是 域对象 ,它代表着当前JSP页面(也就是page)!也就是说:pageContext域对象只在page范围内有效,超出了page范围就无效了!
三个方法:
- § setAttribute(String name,Objcet o)
- § getAttribute(String name)
- § removeAttribute(String name)
<% pageContext.setAttribute("name", "zhangsan"); %> <% String value = (String) pageContext.getAttribute("name"); System.out.println(value); %>
注意:pageContext域对象是可以访问request、session、application、page这几个域对象设置的值的
上面的pageContext默认是page范围的,但pageContext对象重载了set、get、removeAttribute这三个方法
- getAttribute(String name,int scope)
- setAttribute(String name,Object value,int scope)
- removeAttribute(String name,int scope)
- 多了一个设置域范围的一个参数,如果不指定默认就是page。当然了,pageContext把request、session、application、page这几个域对象封装着了静态变量供我们使用。
-
- PageContext.APPLICATION_SCOPE
- PageContext.SESSION_SCOPE
- PageContext.REQUEST_SCOPE
- PageContext.PAGE_SCOPE
- 刚才我们没有使用重载方法的时候,使用pageContext是无法获取到request域对象设置的属性的。现在我们使用重载后的方法就能获取得到了!
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <body> <% //使用重载的方法获取request域对象的属性 String value = (String) pageContext.getAttribute("name",pageContext.REQUEST_SCOPE); System.out.println(value); %> </body> </html>
pageContext还有这么一个方法:findAttribute(String name)
该方法会查找各个域的属性,从小到大开始寻找!也就是page—>request->session->application。
<% //使用findAttribute查找2.jsp中request域对象的属性 String value = (String) pageContext.findAttribute("name"); System.out.println(value); %>
对象的作用域
page作用域:
只在本JSP页面范围有效
pageContext.setAttribute(键,值)
pageContext.getAttribute(键)
request作用域内的对象则是与客户端的请求绑定在一起
<% String name = "request"; request.setAttribute("name",name); request.getRequestDispatcher("testTwo.jsp"). forward(request, response); %>
session作用域:一次会话
application作用域:整个web应用程序
cookie
cookie是Web服务器保存在客户端的一系列文本信息
cookie的作用
- 对特定对象的追踪
- 实现各种个性化服务
- 简化登录
- 但安全性能————容易泄露信息
使用:
常用方法
cookie与session的对比
JSP访问数据库
分层实现
数据访问层(DAO)
表示层(JSP) ————非空验证 提示错误信息并保留用户所填写的信息
JavaBean
一辆货车,在java端和web页面进行数据传递的载体
优势
- 解决代码重复编写,减少代码冗余
- 功能区分明确 提高了代码的维护性
分类
功能上可以分为 封装数据 封装业务
JSP 页面应当将数据的处理过程指派给一个或几个 beans 来完成,我们只需在 JSP 页面中调用这个 beans即可。不提倡大量的数据处理都用 java 程序片来完成。在 JSP 页面中调用 beans,可有效的分离的静态工作部分和动态工作部分,编写 javabeans 就是编写一个 java 的类。
工作过程:
当服务器上某个含有 useBean 标签的 JSP 页面被加载执行时,JSP 引擎将首先根据 id 的名字,查找 JSP 引擎内置 pageContent 对象中是否含有名字 id和作用域 scope 的对象,如果这个对象存在,JSP 引擎就分配一个这样的对象给客户,这样,客户就获得了一个作用域是 scope、名字是 id 的 beans。如果在 pageContent 中没有查找到指定作用域、名字是 id 的对象,就根据 class 指定的类创建一个名字是 id 对象,即创建了一个名字是 id 的 beans,并添加到 pageContent 内置对象中,并指定该 beans 的作用域是 scope,同时 JSP 引擎分配给客户一个作用域是 scope、名字是 id 的 beans。
² scope 取值 page
该 beans 的有效范围是当前页面,当客户离开这个页面时,JSP 引擎取消分配给该客户的 beans。
² scope 取值 session
该 beans 的有效范围是客户的会话期间,也就是说,如果客户在多个页面中相互连接,每个页面都含有一个 useBeans 标签,这些 useBean 标签中 id 的值相同,并且 scope 的值都是 session,那么,该客户在这些页面得到的 beans 是相同的一个。如果客户在某个页面更改了这个 beans 的属性,其它页面的这个 beans 的属性也将发生同样的变化。当客户关闭浏览器时,JSP 引擎取消分配给客户的 beans。
² scope 取值 request
该 beans 的有效范围是 request 期间。客户在网站的 访问期间可能请求过 多个页 面,如果这些页面含有 socope 取值是request 的 useBeans 标签,那么 pageCotent 对象在每个页面分配给客户的 beans 也是互不相同的。JSP 引擎对请求作出响应之后,取消分配给客户的这个 beans。
² scope 取值 application
所有客户共享这个 beans,如果一个客户改变这个 beans 的某个属性的值,那么所有客户的这个 beans 的属性值都发生了变化。这个 beans 直到服务器关闭才被取消。
注意事项:
当使用作用域是 session 的 beans 时,要保证客户端支持 Cooker.
为了使服务器的所有 web 服务目录下的 JSP 页面文件都能使用我们的 beans(假如是Circle.java),我们必须将上面编译通过生成的字节码类文件:Circle.class 拷贝到 JSP 引擎的 classes 文件夹下,即tomcat\classes 下。另外,在使用 beans 的 JSP 页面中,必须有如下的 import 指令:
<@page import= “Circle”>
特定的写法:
- 无参的构造函数
- 成员属性私有化
- 封装的属性如果需要被外所操作,必须编写public类型的setter、getter方法
三个对javabean操作的标签:
(1) jsp:useBean【在JSP页面中查找javaBean对象或者实例化javaBean对象
(2) jsp:setProperty【设置javaBean的属性】
(3) jsp:getProperty【获取javaBean的属性】
<jsp:useBean>标签用于在指定的域范围内查找指定名称的JavaBean对象:
(1)存在则直接返回该JavaBean对象的引用。
(2)不存在则实例化一个新的JavaBean对象并将它以指定的名称存储到指定的域范围中。
语法:
<jsp:useBean id="实例化对象的名称" class="类的全名" scope="bean 有效范围"/> 或者 <jsp:useBean id="实例化对象的名称" class="类的全名" scope="bean 有效范围"> </jsp:useBean>
举例:
<body> <jsp:useBean id="tom" class="Person" scope="page"/> <% tom.setName("tom"); System.out.println(tom.getName()); %> </body>
person类必须存在一个 空参构造 才能使用<jsp:useBean>标签不然不行
上例等价于:
<body> <% //new出对象 Person tom = new Person(); tom.setName("tom"); System.out.println(tom.getName()); %> </body>
jsp:setProperty 该标签可以设置 beans 的属性值
setProperty标签可以通过 3 种方式设置 beans的属性值。
(1)将 beans的属性值设置为一个表达式的值或字符串。
beans 的属性值设置为一个表达式的值:
<jsp:setProperty name= “beans的名字 ” property= “beans 的属性名 ” value=“<%=expression%>” />
beans 的属性值设置为一个字符串:
<jsp:setProperty name= “beans 的名字” property= “beans 的属性名” value= 字符串/>
(2)通过form表单的参数的值来设置 beans 的相应属性的值,要求表单参数名字必须与 beans 属性的名字相同。JSP
引擎会自动将表单中的数据(字符串)转换为 beans 属性的类型。
<jsp:setProperty name= "beans 的名字" property="*" />
该标签不用再具体指定 beans 的属性的值对应的是表单中的哪个参数的值,系统会自动
根据名字进行匹配。
(3)通过 request 的参数的值来设置 beans 的相应属性的值,要求 request 参数名字必须与 beans 属性的名字相同。
<jsp:setProperty name= "beans的名字" property="属性名" param= “参数名”/>
注:不能在<jsp:setProperty> 中同时使用 value 和 param。
jsp:getProperty
该标签可以获得 beans 的属性值,并将这个值用串的形式显示给客户.
语法格式:
<jsp:getProperty name= “beans 的名字” property= “beans 的属性” /> 或 <jsp:getProperty name= “beans 的名字” property= “beans 的属性” /> </jsp:getProperty>
举例:
<jsp:getProperty name="person" property="username"/> <jsp:getProperty name="person" property="age"/>
序列化
序列化:对象的寿命通常随着生成该对象的程序的终止而终止,有时候需要把在内存中的各种对象的状态(也就是实例变量,不是方法)保存下来,并且可以在需要时再将对象恢复。
总结:
Java 序列化技术可以使你将一个对象的状态写入一个Byte 流里(序列化),并且可以从其它地方把该Byte 流里的数据读出来(反序列化)
用途:
- 想把的内存中的对象状态保存到一个文件中或者数据库中时候
- 想把对象通过网络进行传播的时候
如何序列化:
只要一个类实现Serializable接口,那么这个类就可以序列化了。
例如,有一个 Person类,实现了Serializable接口,那么这个类就可以被序列化了。
class Person implements Serializable{ private static final long serialVersionUID = 1L; //下面解释这个是做什么的 String name; int age; public Person(String name,int age){ this.name = name; this.age = age; } public String toString(){ return "name:"+name+"\tage:"+age; } }
通过ObjectOutputStream 的writeObject()方法把这个类的对象写到一个地方(文件),再通过ObjectInputStream 的readObject()方法把这个对象读出来
File file = new File("file"+File.separator+"out.txt"); FileOutputStream fos = null; try { fos = new FileOutputStream(file); ObjectOutputStream oos = null; try { oos = new ObjectOutputStream(fos); Person person = new Person("tom", 22); System.out.println(person); oos.writeObject(person); //写入对象 oos.flush(); } catch (IOException e) { e.printStackTrace(); }finally{ try { oos.close(); } catch (IOException e) { System.out.println("oos关闭失败:"+e.getMessage()); } } } catch (FileNotFoundException e) { System.out.println("找不到文件:"+e.getMessage()); } finally{ try { fos.close(); } catch (IOException e) { System.out.println("fos关闭失败:"+e.getMessage()); } } FileInputStream fis = null; try { fis = new FileInputStream(file); ObjectInputStream ois = null; try { ois = new ObjectInputStream(fis); try { Person person = (Person)ois.readObject(); //读出对象 System.out.println(person); } catch (ClassNotFoundException e) { e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); }finally{ try { ois.close(); } catch (IOException e) { System.out.println("ois关闭失败:"+e.getMessage()); } } } catch (FileNotFoundException e) { System.out.println("找不到文件:"+e.getMessage()); } finally{ try { fis.close(); } catch (IOException e) { System.out.println("fis关闭失败:"+e.getMessage()); } }
输出结果为:
name:tom age:22
name:tom age:22
serialVersionUID ,实现了Serializable接口之后,Eclipse就会提示你增加一个 serialVersionUID,虽然不加的话上述程序依然能够正常运行。
序列化 ID 在 Eclipse 下提供了两种生成策略
- 一个是固定的 1L
- 一个是随机生成一个不重复的 long 类型数据(实际上是使用 JDK 工具,根据类名、接口名、成员方法及属性等来生成)
上面程序中,输出对象和读入对象使用的是同一个Person类。
如果是通过网络传输的话,如果Person类的serialVersionUID不一致,那么反序列化就不能正常进行。例如在客户端A中Person类的serialVersionUID=1L,而在客户端B中Person类的serialVersionUID=2L 那么就不能重构这个Person对象。
如果没有特殊需求的话,使用用默认的 1L 就可以,这样可以确保代码一致时反序列化成功。那么随机生成的序列化 ID 有什么作用呢,有些时候,通过改变序列化 ID 可以用来限制某些用户的使用。