Jsp:Java Server Pages

http://127.0.0.1:8080/weba/hello.html

Tomcat执行过程:

浏览器通过http协议发送请求,以TCP协议作为底层,去tomcat的安装目录下找到webapps下的weba文件夹,再继续找到hello.html.

http协议有协议头和协议头,底层是TCP,是无状态的,两次连接。

127.0.0.1:找到服务器的IP地址

8080:根据端口号找到服务的指定应用 Tomcat,tomcat是一个中间件

访问结果通过response返回,静态代码tomcat不执行,java代码tomcat执行,执行后tomcat把执行结果嵌入到静态代码html中,由浏览器同一执行并且显示结果。

通过虚目录:context 设置

 

服务器先启动,浏览器发请求

Tomcat的目录结构:

bin:tomcat的启动和关闭信息

webapps:项目目录存放,

conf:server.xml,虚目录配置文件

log:存放日志文件

lib:jar包 j2ee jar包 和类库

work:存放生成的class字节码文件(临时文件)

 

web目录结构:

webapps-

      WEB-INF

           web.xml:部署文件

 

 

配置虚目录:(目的:安全性《名字 位置 存储》)

配置文件的路径webappsàconf-àserver.xml

<Context path=”/test” docBase=”f:\weba” />

path:虚拟访问路径

docBase:项目的真实访问路径

一个项目名可以配置多个虚目录名,但是一个虚目录名只能对应一个项目

 

 

表单数据存储在服务器,由浏览器执行。

Tomcat在执行jsp时,静态代码不会执行,会执行java代码。不同的java代码有不同的执行形式。

Web组件不能独立于web项目。不能直接把.jsp文件放在webapps下去执行。

Jsp是动态组件,服务器执行

标签包含:如果被包含页面是html静态页面,先包含不执行

tomcat执行.jsp文件的过程:先将.jsp文件变成.java文件,再编译为字节码文件hello.jspà hello-jsp.java 经过编译后变成 hello-jsp.class。虚拟机执行java代码,执行完的结果嵌入静态代码中

修改.jsp文件时,可能出现修改不成功,将tomcat目录下的work文件夹删掉,并且重启tomcat。

Servlet:需要自己手动先变成字节码文件,再让tomcat执行。

Jsp=静态代码+动态代码

静态代码放在服务端,由客户端执行。

 

注释:

静态注释:对静态代码的注释,<!—服务器不会执行,浏览器来执行-- >

动态注释:对动态代码的注释,<%--里面对el表达式,指令,标签,java代码进行注释 ,tomcat会执行,但是不会发给浏览器 --%>

对于原生的java代码,可以使用java中的注释  《 //aa  /*aa */  /**aa */ 》

在配置文件中,配置信息被静态注释时 ,被静态注释的配置信息还是由服务器执行。

行为:表示实际在操作一些事(实际代码完成操作)

思想:是在告诉你怎么做一件事情(配置信息是一种思想,为了指挥tomcat怎么做)

服务器中的配置信息由服务器解析。

 

Jsp变量

全局变量 :<%!  int i=0; %>//i为全局变量,只初始化一次(相当于java中的实例全局变量)

局部变量:<% int i=0;%>//i 为局部变量,没有 !号便是局部变量。

方法中的变量一般没有访问权限,都使用默认的。方法中的局部变量使用前需要初始化,因为它没有默认初始,构造方法也不能为它初始化,否则会发生编译错误。

Jsp中可以定义类,方法,变量,但是不推荐使用。<%  %>//就在里面定义

表达式:  

<%=i++ %>//使用response内置对象 ,jsp语法

特点:安全,简单,response自动将代码送回,一般只使用在jsp页面中(推荐使用response),发送完数据到浏览器就自动销毁。

<% out.println(i++);%>//使用out内置对象 ,java语法

特点:在任何组件和页面上都能取到out内置对象,就能使用。不安全,out可能会跟回浏览器。

 

 

打印99乘法表:

<table border=”1”>

<% for(int i=1;i<10;i++){    %>

<tr>

<% for(int j=1;j<i+1;j++){   %>

<td><%=i*j %></td>

<%      }    %>

</tr>

<%      }    %>

</table>

练习:写个下三角的99乘法表(指定行和列数的乘法表)

Jsp如何接收用户请求

表单代码由浏览器解析

Get请求:会在访问地址栏上显示输入的参数

Post请求:安全,输入的参数不会在地址栏上显示

 

服务器不关心请求的来源,因为表单最终也会变成 地址栏协议请求格式。

Request接收请求参数:

request.getParameter(“rownum”);

request.getParameter(“colnum”);

指令:

page:指定当前监听页面的处理方式,导包

静态编码:

<%@ page contentType=”text/html;  charset=gb2312” %>

用page做静态编码只能有一条,导包可以有多条。

Tomcat发现接收的是html文件,就算里面有java代码,tomcat也不会执行,会直接发给浏览器。

Jsp:真正的作用 : 拿到结果并且进行处理,把结果通过response放在http协议中发到浏览器。(用户看到的结果是由浏览器显示的)

Response:可以和浏览器建立信道(浏览器底层是TCP协议),把结果数据发送到浏览器。

Jsp:语法包括注释,变量,语法。

使用表单和用户做交互。

 GET:

http://127.0.0.1:8080/table/printTable.jsp?rownum=2&colnum=4

 

POST:

http://127.0.0.1:8080/table/printTable.jsp

 

pageEncoding:jsp本身的编码

charset:服务器发送给客户端的内容的编码

include指令:(包含) 静态包含

<%@include file=”hello.jsp” %>

先找到被包含页面,把该页面内容全部包含到当前页面中。

特点:先包含再执行,不识别被包含页面的类型。

要求:被包含页面不能有<html><body>,被包含页面不能和当前页面重复定义变量

request.getParameter(“param”);//当没有param参数时,返回的结果为 null

 

<jsp:include page=””>标签包含:动态包含

<jsp:include page=”hello.jsp”>

标签是java一行或者多行代码的标识,通过标识找到java代码再去执行,标签包含属于java语法范畴

找到被包含页面,然后执行,最后把执行的结果包含到当前页面中

特点:识别被包含页面类型

包含标签中如果有子标签,会先执行子标签中的内容再执行包含标签。

<jsp:param name=”ref” value=”ZTE”/>:执行此标签的意思是往该页面中对应的request内置对象中设置一个参数名为ref的参数,参数值为ZTE。

如果被包含页面是动态页面,就先执行再包含,当前页面通过子标签可以向被包含页面传递参数。通过request内置对象传递。

如果被包含页面是静态页面,就只包含不执行

主要缺点:被包含页面最好是不要是静态页面,静态页面中最好不要有动态代码

 

什么时候请求结束?

1、        此页面确实已经执行完

2、        此页面执行完,response要和浏览器建立信道,把结果数据放在信道上

 

 

 

标签包含

指令包含

共同点

把一个页面包含到当前页面中

语法

标签包含属于java语法

指令包含属于jsp语法

写法

<jsp:include page=””/>

<%@include file=””%>

是否识别文件类型

标签包含识别被包含文件类型

指令包含不识别类型

传参

动态页面可以传递参数,如果被包含的为静态页面则不能传参。

指令包含不能传递参数

包含与执行顺序

标签包含如果包含的为动态页面先执行后包含,如果为静态页面就只包含不执行

指令包含先包含后执行

缺点

包含静态页面时不能执行

不能有<html><body>,不能重复定义变量

总结

一般页面都写成jsp页面,然后使用标签包含(jsp:include

       

 

跳转:

服务端跳转:<jsp:forward page=””/>

用户只发一次请求,地址栏不改变,

只创建一个request内置对象,服务端跳转的各个组件和页面都能共享此request。

优点:安全,地址栏不改变,只发一次请求

1、<jsp:forward page=””/>

2、pageContext.forward();

3、 request.getRequestDispatcher("1.jsp").forward(request,response);

3、服务器端跳转“/”代表站点根路径

 

客户端跳转:response.sendRedirect(“”);

用户发多次请求,地址栏改变

每发一次请求会创建一个request内置对象,所以request不能用来传递参数。

请求都从客户端发出

1、链接跳转:<a href=””></a>

2、表单提交

3、Response.sendRedirect(“3.jsp”);

4、<mata http-equiv=”refresh”, content=”3;2.jsp”/>

5、response.setHeader(“refresh”,” 3;2.jsp”);

6、客户端跳转“/”代表服务器跟路径webapps

 

内置对象

为什么要用内置对象?(用来传递数据)

Tomcat为了接受用户请求自动创建的完成用户组件之间的数据交互和传递。

内置对象由tomcat自动创建。

 

九大内置对象:

request:用户一发请求时就创建,请求结束就销毁。传递数据(服务端跳转才能传递数据),用户请求参数只放在request内置对象中。作用域为 request

response: 用户一发请求时就创建,请求结束就销毁。将结果数据交给浏览器显示。作用域为page

pageContext:用户发请求访问jsp页面时创建,离开页面时就销毁。存放临时数据。作用域为page。

session:当用户第一次访问服务器动态组件时创建,用户下线15分钟后就销毁,或者使用invalidate()。作用:存放验证信息,客户端跳转。作用域为session.

application:服务器启动时创建,服务器关闭时销毁。只创建一个,公用的。作用域为application.

out:response创建,作用域为page.

config: 服务器启动时创建,创建一个。存放配置信息的初始化参数。作用域为page.

page: 用户发请求访问jsp页面时创建,离开页面时就销毁。存放临时数据。作用域为page。

exception:作用域为page

形参和实参进行数据传递,形参最好使用接口类型变量来接收。和工厂模式差不多。

父接口的类型变量可以执行子接口引用型变量。

四大作用域:

1、Page:页面范围 只在当前页面中

2、request内置对象分析(Request:请求范围)

后台结果数据叫做属性。

request.setAttribute(“name”,”张三”);//设置属性 属性名是字符串,属性值是任何类型

request.getAttribute(“name”);//拿到属性值,属性值为Object类型

request包含数据区和代码区

参数区:存放请求中的参数(表单中的数据getParameter(“”))String类型

属性区:存放后台设定的属性(setAttribute(“”,””);)Object类型

如果是服务端跳转,request可以传递数据。

每发一次请求,tomcat都会为这个请求创建一个新的request内置对象。

request的生命周期取决于服务端

3、session内置对象分析(Session:用户范围)

session用来存储验证信息,不管什么跳转都可以取得属性。

session.setAttribute(“key”,”value”);//往session中设定验证信息

session.getAttribute(“key”);//从session中取得验证信息

session的生命周期取决于客户端

4、application内置对象分析(Application:服务器范围)

一个application可以给多个项目服务

一个application可以给一个项目中的多个用户服务

application.setAttribute(“key”,”value”);//往application中设定信息

application.getAttribute(“key”);//从application中取得信息

缺点:不安全,占内存

application的生命周期取决于服务端

PageContext(不推荐使用)

pageContext.setAttribute(“key”,”value”,PageContext.APPLICATION_SCOPE);//将数据设置到application中

pageContext.setAttribute(“key”,”value”,PageContext.REQUEST_SCOPE);//将数据设置到request中

pageContext.setAttribute(“key”,”value”,PageContext.PAGE_SCOPE);//将数据设置到page中

pageContext.setAttribute(“key”,”value”,PageContext.SESSION_SCOPE);//将数据设置到session中

 

表单参数的收集:

复选框:<input type=”checkbox”  name=”interest” value=”sing” >唱歌</input>

<input type=”checkbox”  name=”interest” value=”dance”>尬舞</input>

一个参数名对应多个参数值,用字符串数组对象接收

String[] inst=request.getParameteValues(“interest”);//新字符串的长度,取决于值的个数

type=”text”:参数名为name,不输入数据时 ,显示参数值为 空串。

type=”checkbox”:参数名为interest,不输入数据是 ,显示的参数值为null。

如果复选框interest中没有选中任何值,那么inst数组对象为null,会产生空指针异常。

 

解决办法:

<%@page contentType="text/html;charset=UTF-8"%>//设置静态编码

<%@page import="java.util.*"%>//导入util包

request.setCharacterEncoding("UTF-8");//设置jsp动态代码的编码

把request中的所有参数都放入Enumatioin集合中

Enumeration enu=request.getParameterNames();//enu只收集有确切参数值的参数名,所以后面不会发生空指针异常 ,会收集空串,但是不收集null.先收集后迭代。

while(enu.hasMoreElements()){

String name=(String) enu.nextElement();

String[] values=request.getParameterValues(name);

for(int i=0;i<values.length;i++){

out.println(values[i]+”**==**”);

}

}

优点:健壮性好,拥抱需求

 

request.getRemoteAddr();//得到用户的MAC地址,IP地址:127.0.0.1

 

作业一: 解析Enumeration迭代取出表单中的参数名和参数值

在未知表单中的参数个数,一个参数对应的参数值的个数的情况下,使用Enumeration接口变量接收request域中有确切参数的参数名。

Enumeration enu=request.getParameterNames();//只收集有确切参数值的参数名,所以后面不会发生空指针异常 ,会收集空串,但是不收集null。先收集后迭代。

while(enu.hasMoreElements()){//判断集合中是否有元素

String name=(String) enu.nextElement();//取出表单中具有参数值的参数名

String[] values=request.getParameterValues(name);//用数组对象接收参数名对应的参数值,数组的长度取决于参数名对应参数值的个数。

for(int i=0;i<values.length;i++){//遍历输出当前参数名对应的所有参数值

out.println(values[i]+”**==**”);}}//将参数值发送到浏览器显示

 

request内置对象

从客户端拿数据:

request.getParameter();

request.getParameterValues();

request.getParameterNames();

 

动态编码:

1、String name=request.getParameter(“name”);//得到请求中的参数值

byte[] b=name.getBytes(“utf-8”);//把未经编码的汉字变成字节数组对象,然后对字节数组对象编码

name=new String(b);//把编码后的字节数组对象转换成字符串

编码优点:post请求和get请求都可以编码,编码成功率高。

编码缺点:代码量大,可行不可用,服务端跳转后从同一个request中拿数据也不用再编码

2、request.setCharacterEncoding(“UTF-8”);

对request中所有汉字做编码

编码优点:代码量小

编码缺点:只支持post请求,不支持get请求(只能对协议体中的汉字做编码,对协议体中的汉字不做编码),编码成功率不是很高

 

 

response:内置对象

接口:HttpServletResponse

采用http协议

主要作用:工作在jsp页面中,自动和客户端建立信道,把结果数据和静态代码通过信道发给浏览显示。

通过修改协议头,控制浏览器自动发请求

1、         定时刷新:response.setHeader(“refresh”,”1”);//往http协议头中设定控制信息

2、         定时跳转:response.setHeader(“refresh”,”1;URL=1.jsp”);

定时跳转,完成跳转的是浏览器;

定时刷新,完成刷新的是浏览器

3、         定时跳转:response.sendRedirect(“1.jsp”);//重定向,客户端跳转,服务器在协议头中设定控制信息,不会完成跳转,后面的代码依旧会执行。

服务端跳转:

<jsp:forward page=”1.jsp”/>//只能在jsp页面中使用

request.getRequestDispatcher(“1.jsp”).forward(request,response);//既可以完成页面之间的跳转,也可以完成页面和组件之间的跳转和组件与组件之间的跳转

服务端跳转不可重新传递参数,跳转代码后面代码不会被执行。

结论:正常流程使用服务端跳转,异常流程(出错流程)使用客户端跳转

服务端跳转和客户端跳转
相同点:都是完成跳转
不同点:

①语法不同。客户端 response.sendredirect(..)
服务端Request.getrequestDispatcher(…).forward(request,response)
②跳转实质不同
  客户端跳转:服务器向http头设置控制信息,真正完成跳转的是浏览器
服务器跳转:服务器完成跳转
③客户端跳转:浏览器要重新发请求 ,地址栏会发生变化
服务器跳转:不会重新发请求 地址栏不会发生变化
④客户端跳转:不能跨组件传递信息,因为重新发请求!第一个请求里的信息已经丢失,可以重新传参
服务器跳转:可以跨组件传递信息,不能重新传参
结论:正常流程用服务端跳转
异常流程用客户端跳转,给客户做一个提示!

 

 

超链接和表单:

共同点:

都属于前台技术,由浏览器执行

都能自动生成http协议,不用手动写

都可以传递参数

不同点:

超链接不能和用户做交互,表单可以和用户做交互

超链接不能产生post请求,不能把参数放入协议体中;表单可以

超链接不安全,不能使用动态编码

使用特点:

表单:和用户交互,安全性高的时候用表单

超链接:不能和用户交互,只是执行功能时使用,超链接简单

 

状态码:

状态代码有三位数字组成,第一个数字定义了响应的类别,且有五种可能取值:
1xx:指示信息--表示请求已接收,继续处理
2xx:成功--表示请求已被成功接收、理解、接受
3xx:重定向--要完成请求必须进行更进一步的操作
4xx:客户端错误--请求有语法错误或请求无法实现
5xx:服务器端错误--服务器未能实现合法的请求
常见状态代码、状态描述、说明:
200 OK //客户端请求成功
400 Bad Request //客户端请求有语法错误,不能被服务器所理解
401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 Not Found //请求资源不存在,eg:输入了错误的URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常

Application内置对象

application : 存放公共信息

application是指向实现ServletContext接口的类的对象,所以有时候application有时候也叫ServletContext。

得到application的方法: getServletContext();//取得实现ServletContext接口类的对象的地址。

只要往application中设定了信息,任何用户的任何请求都能获取application中的信息

application.setAttribute(String name,Object value);

application.getAttribute(String name);

主要作用:取得物理虚目录路径 getRealPath();

<%=this.getServletContext().getRealpath(“/”)%>

this代表的是什么?

this是当前jsp页面生成的一个对象。

this.getServletContext():从某种意义上讲是拿到application内置对象

 

getRealPath()如何找到虚目录的真实物理路径?

1、         从request中拿到请求字符串request.getRequestURL();

2、         对请求分析截取得到虚目录名 indexOf()  substring()

3、         从web.xml配置文件中Context配置中找到对应的docBase路径

 

如果页面放入WEB-INF下,客户端怎么发请求都无法访问,只能通过在web.xml文件中配置才能访问。

先配置映射名

<servlet >

<servlet-name>ddd</servlet-name>

<jsp-file>/WEB-INF/hello.jsp</jsp-file>

</servle >

 

<servlet-mapping>

      <servlet-name>ddd</servlet-name>

<url-pattern>/sky</url-pattern>

</servlet-mapping>

配置后可以通过 映射名sky访问放在WEB-INF下的hello.jsp文件

即便是不配置,服务端跳转也可以访问到hello.jsp,但是浏览器要访问的时候一定要配置web.xml.

 

Config内置对象:

Config:存放web组件在web.xml中组件配置信息的初始化参数

404错误,一般都是配置问题。

500错误,代码有问题

 

Tomcat一启动就会创建config 内置对象,一读取web.xml文件,就会把web.xml文件中的初始化信息设定到config内置对象当中, ·这些配置信息会放在此配置的组件中

例如: 如下配置 初始化参数 uname 配置在hello.jsp页面中

<servlet >

<servlet-name>ddd</servlet-name>

<jsp-file>/WEB-INF/hello.jsp</jsp-file>

<init-param>

  <param-name>uname</param-name>

  <param-value>zhangsan</param-value>

</init-param>

</servle >

 

<servlet-mapping>

      <servlet-name>ddd</servlet-name>

<url-pattern>/sky</url-pattern>

</servlet-mapping>

 

如何在组件中取出config中配置信息初始化参数

config.getInitParameter(“uname”);

 

如果配置信息中没有配置init-param,config能否取出信息?

取不出来,结果为null。

 

一个组件想从config中拿到初始化参数有什么条件?

1、         组件必须通过映射名访问,在web.xml文件中配置

2、         在组件的配置中要有init-param ,组件的初始化信息中必须要有配置初始化信息的参数。

一个组件只能取得本组件自己配置信息中的初始化参数,如果没有就会取出null。

 

 

ModelOne:自提交页面:

在 login.jsp页面的表单中 action=”login.jsp”

第一个分层思想:把业务逻辑和访问数据库的代码从jsp页面中独立出去

ModelOne缺点:健壮性差,代码复杂,可移植性差,用户体验不好

改正ModelOne的做法:第二次分离:把控制层和视图层分离//ModelTwo

 

登录验证:(解决空指针异常的方法)

表单里的用户名 和数据库里的用户名都是变量,表单里的用户名不会为null,用户不输入数据时只会出现空串,在验证的时候不会出现空指针异常。所以都会调用表单数据的 equals方法。从数据库中取出来的验证数据可能会为null。为了避免空指针异常,所以使用 表单的字符串.equals(数据库的字符串)。

 

得到session的创建时间:(计费型项目中的应用,上网!)

long time=Session.getCreateTime();//得到session创建的时间

long time1=Session.getLastAccessedTime();//得到用户最后一次发请求的时间

Date date=new Date(time);//将long型数据转换成Date类型

 

Cookie和session

Cookie:内置对象

Cookie的作用:把需要本应该保存在服务器中的数据以cookie的形式保存在客户端。

Cookie c1=new Cookie(“name”,”zs”);//创建cookie对象,将用户信息保存到cookie中,一个cookie对象一个只能存放一个信息

response.addCookie(c1);//将创建的cookie对象设置到客户端

c1.setMaxAge(60);//设定cookie保存时间,一分钟后自动销毁

http协议头中不仅有结果数据还有cookie信息

通过response将cookie信息设定到客户端,通过request取出cookie信息。

Cookie[] c=request.geCookies();//取出客户端的全部Cookie

for(int i=0;i<c.length;i++){

      c[i].getName();//得到cookie对象的名

      c[i].getValue();//得到cookie对象的值

}

Session的作用是标识用户,一个用户一个session。

sessionID,用户第一次发请求访问动态组件就会拿到sessionID,在请求结束时,先把sessioID作为name,把32位字符串作为value封装到cookie中。系统设置的默认的cookie数据---叫做系统cookie.

 

session:内置对象保存用户验证信息

生存周期:

Session创建:用户第一次访问动态组件,会创建session

session销毁:(四种方法)

1、用户关闭浏览器时,900秒以后session自动销毁

2、session.invalidate();//销毁session

3、在web.xml配置文件中配置 :

<session-config>

           <session-timeout>30</session-timeout>

</session-config>

4、<script language=”javaScript”>//通过javaScript监听窗口关闭事件,调用closeSession.jsp页面,在closeSession.jsp页面中调用session.invalidate()关闭session。

function window.onunload(){

}

</script>

 

session中的方法:

session.getId();//得到sessionID(存入Cookie中的sessionID和session)

如何判定发请求的用户是新用户还是非新用户?

session.isNew();//第一次访问动态组件时访问的session是新的,第一次访问动态组件时,请求中没有系统Cookie,服务器会从Cookie中找对应的sessionID,没找到就认为此用户是新的用户,tomcat就会在服务器中为此用户创建一个新的session,从新session中拿到新的sessionID,把sessionID封装到Cookie,请求结束时,response会把封装了sessionID的Cookie发到浏览器。当用户再次刷新时,请求中已经有了系统Cookie,tomcat可以通过request拿到系统Cookie,从Cookie中拿到session,找到了相应的sessionID,就判定此用户已经不是新的了。

Session.setAttribute(String name,Object value);//设置属性

Session.getAttribute(String name);//取出属性

Session.remove(String name);//移除属性

 

 

Session 和Cookie

 

都和用户有关,一个session关联一个用户,Cookie中存放session信息

不同:

Session在服务器中工作,Cookie存放在客户端浏览器

Session在各个组件传数据,Cookie在客户端和服务端传输。

Cookie很多会不安全 影响客户端不会影响到服务器,session很多会影响服务器

Session和Cookie有关系,session通过Cookie和客户端做关联。

Session创建sessionID,Cookie把sessionID存储到浏览器中。Cookie消失了,session也不会有什么用的。

 

首页 默认访问页面

访问本项目的时候就直接进入首页

配置首页后就会按照web.xml中 配置的文件进入首页,如果被配置的页面不存在,也不会再进入index.jsp页面中

如果没有配置 就会进入index.jsp页面中

配置在web.xml中

<welcome-file-list>

      <welcome-file >default.html</welcome-file >

       <welcome-file >default.jsp</welcome-file >

       <welcome-file >index.jsp</welcome-file >

</welcome-file-list>

 

作业:

保存用户名和密码在Cookie中,下次访问时不用输入密码就可以登录。

第一次发请求访问jsp页面时,是没有cookie的,因为还没有创建session,也不会封装cookie数据。所以在第一个页面中也不能拿到cookie对象。

如果表示是静态html,那么用户访问表单时不会创建session对象,也不会保存sessionID到cookie对象中,就不会有系统cookie。

 

作业二:写一个具有记住密码功能的登录,用Cookie记住用户名和密码

<%@page contentType="text/html;charset=utf-8"%>

<!--charset:对静态代码的编码 ,服务器发送给客户端的内容编码-->

<!--跳转到成功页面使用服务端跳转,跳转到失败页面使用客户端跳转-->

 

<%

//获得登录表单中的参数值

String username=request.getParameter("username");

String password=request.getParameter("password");

String[] flag=request.getParameterValues("flag");//创建数组对象接收复选框中的值

 

if("DFX".equals(username)&&flag!=null&&("123".equals(password)||"".equals(password))){

Cookie[] c=request.getCookies();//获取Cookie中的所有数据

boolean tag=false;//用来标记Cookie中是否已经保存了用户登录信息

if(c!=null){//当Cookie中有数据时,做用户信息判断

  for(int i=0;i<c.length;i++){//循环输出Cookie中的数据

       //String key=(String)c[i].getName();//得到Cookie中的name

       //String value=(String)c[i].getValue();//得到Cookie中的value

             if("DFX".equals(c[i].getName())&&c[i].getValue().equals("123")){//判断Cookie中的name和value是否和用户登录信息匹配

       tag=true;//匹配成功后,将标记置为true

       break;

  }

}

if(tag){//标记为true时,跳转到成功页面

request.getRequestDispatcher("loginSuccess.jsp").forward(request,response);

}

}

}

 

//Cookie中没有数据时

 

//当用户选择记录密码时

if(flag!=null){

//对表单中的参数值进行验证

if("DFX".equals(username)&&"123".equals(password)){

  Cookie cookie=new Cookie(username,password);//将登录成功的用户信息存入Cookie对象中

  response.addCookie(cookie);//将保存用户信息的cookie通过response发送给浏览器保存

  //验证成功,服务端跳转 到loginSuccess.jsp页面

request.getRequestDispatcher("loginSuccess.jsp").forward(request,response);

  }else{

  //验证失败,客户端跳转 到loginFail.jsp页面

  response.sendRedirect("loginFail.jsp");

 }

}else{//用户未选择记住密码时登录验证

if("DFX".equals(username)&&"123".equals(password)){

request.getRequestDispatcher("loginSuccess.jsp").forward(request,response);

}else{

response.sendRedirect("loginFail.jsp");

}

}

%>

JavaBean

视图层:显示结果信息

模型组件:

JavaBean:就是一个纯Java代码写的类,封装数据和业务逻辑

 

JavaBean的优点:

提高数据复用(代码)性,

提高可维护性,

便于实现分步开发(团队开发)

 

Javabean的种类:

1       封装数据bean-

1.1、    表单bean(VO/ActionForm):表单bean自动封装表单里的数据,表单bean里的属性的名字,个数,类型要和表单里参数的名字,个数,类型 一致。

1.2、    结果bean:封装数据库记录,结果bean的名字,类型,个数和记录的各个字段对应一致。

2       业务逻辑bean

2.1、业务bean :封装对请求的操作(封装业务操作),尽量不直接操作数据库

2.2、持久bean:封装对数据库的操作(存储和加载),每个数据库都有自己特定的持久bean

 

项目的目录结构:

项目的名是目录的根

 

表单bean的class文件会放在WEB-INF下的classes文件下。

项目的jar包,放在WEB-INF下的lib文件下。

 

表单bean:

四个要求:

1、         要有package做包申明,类的字节码文件必须放在与包对应的文件下才能使用

2、         要使用公有的类,不能有主方法,public class bean{}

3、         属性私有化,提供公有的set和get方法

4、         必须显示的写无参的构造方法

表单bean的部署:把表单bean的字节码文件放在tomcat指定能找到的位置上,WEB-INF的classes文件下的与bean导入的包对应的目录文件下

使用Javabean前的两个步骤:

1、         按照要求创建Javabean

2、         做好javabean的部署,把javabean放到WEB-INF下的classes下打包编译

 

在jsp中使用javaBean:

1、         导包<%@ page import=”cn.zte.bean.*”%>//Tomcat在项目的WEB-INF下的classes下找导入的包对应的目录结构。

2、         UserBean ub=new UserBean();//ub是对象的地址,在栈中开辟空间

3、         ub.setName(“Tom”);//设值

4、         <%=ub.getName()%>//取值

标签使用

<jsp:useBean id=”ub” scope=”page” class=”con.cte.bean.UserBean”/>

1、         if(page.getAttribute(“ub”==null){

UserBean ub=new UserBean();

page.setAttribute(“ub”,”ub”);

}

id=”ub”//即是内置对象的属性名,也是存放变量的地址

scope=”page”//表示将ub存储在page属性域中

class=”con.cte.bean.UserBean”//指定bean的位置

 

表单的自动收集:

<jsp:setProperty name=”ub” property=”*”/>//property * 表示收集表单中输入的值

先到scope中找到属性为ub的属性值---UserBean对象,

再给UserBean 的所有对象赋值,值来自表单。

相当于:

ub.setUsername(request.getParameter(“username”));

ub.setPassword(request.getParameter(“password”));

 

< jsp:getProperty name=”ub” property=”username”/>//获取ub对象中的name属性对应的值

ub.getUsername();

${ub.username}

 

如果表单中的属性名,类型和个数和bean中的不一样会怎么样哦?

1、         类型不同:

bean中:private int age

form中: type=”text” name=”age”

<jsp:setProperty>标签可以完成自动转换,在可以转换的前提下。  如果有字符就会出现转换异常。

 

 

2、         个数不同:

Bean中:name password age

Form中:name password

<jsp:setProperty name=”ub” property=”*”/>

request中没有age参数,则不设值,bean中的默认值为0;

request.getParameter(“age”);//从表单中取出来的参数age值为null

<jsp:getProperty name=”ub” property=”*”/>//从ub对象中取出的age属性值为bean中的默认值 0。

<jsp:setProperty name=”ub” property=”name”/>//只给表单中的name属性设值,参数值来自于表单 ,bean中其余属性不设值,按照原来的默认属性值。 Null 或者0.

<jsp:setProperty name=”ub” property=”name” param=”password”/>//取出ub对象,给name设值,所设值的值来自于表单中参数名为password的参数值。相当于: ub.setName(request.getParameter(“password”));

 

结论:

给表单bean的某个属性设值,可以不来自表单,可以通过标签给表单bean中的属性设值,但是标签中的value必须是字符串。

<jsp:setProperty name=”ub” property=”age” value=”21”/>

 

表单bean对象的数据范围:

javaBean的作用域范围:

page:页面范围

request:请求范围

session:用户范围

application:服务器范围

在通过使用jsp标签拿到javaBean中的属性时,会先从page 域中找,没有再从request域中找,还是没有再从session域中找,最后从application域中找。

会优先使用page域中的属性,以此类推。

如果在创建javaBean对象时,指定了scope,则会判断该域中是否有该对象,没有的话就会在该域中创建对象。但是使用的时候还是会按照优先级使用,并不是一定会创建当前页面创建的那个对象。

JSP标签的特点:

真正的jsp标签不能用来创建对象,只能用来使用对象

语法麻烦

不符合mvc模式

只在小型项目中使用,不适合大项目。

 

在实际项目中javaBean的应用:

表单bean在servlet中创建,servlet完成表单数据收集

结果bean在持久层创建。

 

如果表单中取出的参数值为空串,则在表单bean中设置为null。(容易出现空指针异常) 

Servlet

在MVC模式中中,Servlet作为控制器

Servlet的作用:

1、         CGI:通用网关接口,Servlet通过CGI的作用从Tomcat中拿到内置对象并且进行传递。

2、         创建表单bean对象,自动将表单中的数据收集到表单bean中。

3、         Servlet对请求做分析,根据请求分析结果决定调用相应业务对象的相应方法。

4、         接收业务对象返回的信息

5、         根据对业务对象的返回信息分析,转回到相应的视图页面

 

Servlet可以同时处理多个并发请求,servlet是线程安全的。(本对象的实例全局变量只能被别的对象使用,但是不能修改)

Servlet对象由服务器创建,只创建一次。Servlet的单例由系统保证的,不是人为控制的单例。

Tomcat一启动,用户通过表单发请求,Tomcat创建request内置对象接收请求参数,通过对请求字符串的分析,找到访问的组件,调用相应的组件处理请求,在web.xml中找到相应的servlet配置,找到servlet组件,在servlet的dopost方法中,把request和response直接注入到servlet中。把表单中的参数自动封装到表单bean中,持久层把结果数据放到结果bean中,返回给业务层,业务层接收结果返回给视图层。

Web项目流程解释图:

 
   

response

 

request

 

Web

Client

 

 

 

 

 

 

 

 

 

 

Servlet的语法:

1、         包声明 package cn.zte.servelt

2、         导包,import javax.servlet.*; Java代码,public class  extends HttpServlet

3、         复写doPost(),doGet()方法

 public void doPost(HttpServletRequest request,HttpServletResponse response)throws IOException,ServletException {

PrintWriter out=response.getWriter();//通过response拿到out内置对象

}

Servlet的部署:

1、         把Tomcat中的 libàservlet-api.jar放到JDK下的àjre àlibàext中

2、         编译后的LoginServlet.class放在WEB-INF下的classes文件中,对应的包目录结构下。

3、         在web.xml文件中,配置servlet

<servlet>

      <servlet-name>LoginServlet</servlet-name>

      <servlet-class>cn.zte.bank.LoginServlet</servelt-class>//这是对象

      <load-on-startup>0</load-on-startup>//tomcat一启动就会创建servlet对象,数值0:servlet支持多线程,数越小,执行的线程优先级越高,支持数值(0-9)

</servlet>

 

<servlet-mapping>

      <servlet-name> LoginServlet </servlet-name>

      <url-pattern>/ LoginServlet </url-pattern>

</servlet-mapping>

 

包名命名规则:cn.zte.bank.LoginServlet(域名 公司名 项目名 子项目名 类名)

 

Servlet的执行:

Tomcat一启动,扫描web.xml文件,根据配置<load-on-startup>0</load-on-startup>一启动就创建<servlet-class>对应的servlet对象。请求可以直接访问servlet。发请求的用户通过映射名找到映射名所对应的servlet对象。根据请求方式调用该对象相应的方法(doGet()或者doPost()),拿到request和response内置对象。

Servlet的生命周期:

public void init(ServletConfig config){}//servlet对象一创建,自动调用init(),自动注入config内置对象,拿到初始化参数。

public void destroy(){}//servlet对象一销毁时 ,执行destroy()方法。服务器关闭时,servlet对象销毁。

如果在web.xml中配置了<load-on-startup>,tomcat 一启动就会创建Servlet对象,如果没有配置就是第一次接收请求的时候创建servlet对象,默认调用有参的init(config)方法初始化,注入config内置对象,通过config拿到配置信息的初始化参数。(如果需要调用无参的init()方法,则不写有参的init()方法)初始化参数的传递:在servlet对象的中定义几个实例全局变量,把初始化信息赋值给这些实例全局变量。实例全局变量归该对象的所有方法共享。根据请求方式调用相应的doGet()和doPost()方法。doGet()和doPost()方法中注入request和response内置对象的地址,拿到请求参数,创建表单bean,将表单中的数据封装到表单bean中,对请求进行分析,创建业务对象,调用业务对象相应的方法。Tomcat一旦关闭,调用destroy()方法。销毁以后,GC将servlet移除。

 

关于初始化:

两个初始化方法:init(),init(ServletConfig config);

tomcat默认调用有参的init(config)方法,如果需要调用无参的init()方法则删掉有参的init()方法。如果两个方法都不存在,则不调用init()方法。

怎么将配置信息的初始化参数传给业务层?

<init-param>

      <param-name>username</param-name>

      <param-value>DFX</param-value>

</init-param>

只有jsp页面可以直接使用内置对象,其他组件不能直接使用内置对象。

在servlet类中定义实例全局变量,String username,将config拿到的初始化参数赋值给实例全局变量,在doget()或者doPost()方法中创建业务层对象,使用实例全局变量。

Tomcat一执行,调用有参的init方法,通过注入拿到config内置对象,

this.username=config.getInitParameter(“username”);//DFX

tomcat一启动先创建config内置对象,读取配置信息的初始化参数,再根据<load-on-startup>创建servlet对象。

初始化参数只归该配置组件使用,别的组件要使用需要创建实例全局变量来接收再调用。一般在servlet标签下的load-on-startup标签下配置。(在哪个servlet中配置的归哪个servlet使用)

通过表单如何调用Servlet:

<form action=”LoginServlet” method=”post”>

action后面一定是servlet映射名,使用servlet处理请求

test为项目名,表单在servlet文件夹下,发出请求访问servlet组件,如果出现404错误,test/servlet/LoginServlet不存在, servlet映射名应该为 /servlet/LoginServlet

Servlet映射名由两部分构成: 表单所在的项目路径  和 表单的action所标识的Servlet对象

如果在配置文件中,servlet的映射名没有配置表单所在的目录名,那么在表单中访问servlet时,需要先写出表单相对项目的当前文件目录。 action=”/servlet/LoginServlet”

Servlet会把访问LoginServlet的起始路径作为servlet转向的默认路径。

多个用户访问时,配置会很复杂,所以引入strust配置方式:

<url-pattern>*.do</url-pattern>

在访问servlet时,后面加上.do; action=”LoginServlet.do”,servlet也会记住映射名 路径,根据发送请求表单的位置 servlet/LoginServlet.do.

Response.sendRedirect(“demo.jsp”); servlet会去servlet/下面找demo.jsp

 

action=”a/LoginServlet.do”,servlet中转发时会以a/为基本路径

 

作业:使用servlet处理表单请求,验证登录信息:

package cn.servlet;

import javax.servlet.*;

import java.io.*;

import javax.servlet.http.*;

/**

使用servlet组件处理登录请求

登录成功通过服务端跳转到loginSuccess.jsp

登录失败通过客户端跳转到loginFail.jsp

*/

public class LoginServlet extends HttpServlet{

 

public void doGet(HttpServletRequest request,HttpServletResponse response)throws

IOException,ServletException{

      doPost(request,response);

 

}

public void doPost(HttpServletRequest request,HttpServletResponse response)throws  IOException,ServletException{

      request.setCharacterEncoding("utf-8");//对请求参数进行编码

      response.setContentType("text/html;charset=utf-8");//对发回浏览器的静态数据编码

//获取登录表单中的参数

String username=request.getParameter("username");

String password=request.getParameter("password");

      //对登录的参数进行验证

      if("DFX".equals(username)&&"123".equals(password)){

      //匹配成功通过服务端跳转到loginSuccess.jsp页面

    request.getRequestDispatcher("loginSuccess.jsp").forward(request,response);

      }else{

           //匹配失败通过客户端跳转到loginFail.jsp页面

           response.sendRedirect("loginFail.jsp");

   }

}

}

 

注意: 此LoginServlet.java文件需要放在WEB-INF下的classes文件下进行打包编译,表单发请求访问servlet组件时,需要根据表单的位置写出servlet的映射名,例如表单在webappsàloginforwardàjsp文件夹中,要么在web.xml文件中的映射名配置

为 /jsp/LoginServlet,要么在action中设为  action=”jsp/LoginServlet”  只能二选其一。并且要在当前项目下的web.xml文件中配置servlet信息如下:

<servlet>

      <servlet-name>loginServlet</servlet-name>

      <servlet-class>cn.servlet.LoginServlet</servlet-class>

</servlet>

 

<servlet-mapping>

      <servlet-name>loginServlet</servlet-name>

      <url-pattern>/jsp/LoginServlet</url-pattern>

</servlet-mapping>

 

Servlet的生命周期和内置对象的获取

Servlet的生命周期主要有:servletd对象的创建、初始化、服务、销毁、移除、

一、Servlet有两种创建方式:

      1:在web.xml文件中的servlet中配置< load-on-startup>0<load-on-startup>,使得servlet在启动服务器时自动创建对象。

      2:不做任何配置,则在用户第一次发请求访问Servlet时创建对象。

二、Servlet创建后会调用init():

默认调用有参的Init():会把封装的servlet初始化信息的config内置对象注入进来。

当需要调用无参的Init()时,则需要注释掉有参数的Init() 或者不写有参的Init();

三、用户发请求后,请求会被提交到tomcat中,tomcat会创建request 和 response对象,接受请求参数。Tomcat会根据请求找到servlet对象进行处理。

servlet会调用相应的doGet()或者doPost()方法,对请求做出相应的处理Tomcat会把request和response内置对象注入到servlet中。doPost()方法会创建表单bean,从request内置对象中拿到参数封装到表单bean中。Servlet会根据请求调用或创建持久对象的方法对请求进行处理。doPost()接受请求业务对象返回的结果bean放到request内置对象中,根据业务对象的返回信息转到相应的视图页面显示信息。

四、一旦tomcat关闭,servlet对象销毁,调用destroy()方法,关闭资源

五、最后通过GC把servlet的残余或者碎片移除。

 

如果在web.xml中配置了<load-on-startup>,tomcat 一启动就会创建Servlet对象,如果没有配置就是第一次接收请求的时候创建servlet对象,默认调用有参的init(config)方法初始化,注入config内置对象,通过config拿到配置信息的初始化参数。(如果需要调用无参的init()方法,则不写有参的init()方法)初始化参数的传递:在servlet对象的中定义几个实例全局变量,把初始化信息赋值给这些实例全局变量。实例全局变量归该对象的所有方法共享。根据请求方式调用相应的doGet()和doPost()方法。doGet()和doPost()方法中注入request和response内置对象的地址,拿到请求参数,创建表单bean,将表单中的数据封装到表单bean中,对请求进行分析,创建业务对象,调用业务对象相应的方法。Tomcat一旦关闭,调用destroy()方法。销毁以后,GC将servlet移除。

 

 

怎么从servlet中拿到session和application内置对象?

在servlet的doget和dopost方法中可以拿到request和response内置对象,通过request可以拿到session和application内置对象。

HttpSession session=request.getSession();//拿到session内置对象

在servlet中拿到application内置对象的三种方法

1、         ServletContext application=this.getSession().getServletContext();//拿到application内置对象,推荐使用(因为后两种都依赖于init())

2、         如果初始化init()方法是无参的,并且没有有参的init方法,servlet可以直接取得application内置对象   ServletContext application=this.getServletContext();

3、         如果init(config)方法是有参的,可以直接拿到config内置对象,在servlet类中定义一个实例全局变量,private ServletConfig  config; 在init()方法中 this.config=config;然后在doGet或者doPost方法中,ServletContext application=this.config.getServletContext();

 

Servlet中可以取出很多内置对象,除了page ,pageContext,exception

init()方法中注入config内置对象的地址

doGet()和doPost()方法中注入request和response内置对象的地址

通过request拿到session内置对象:HttpSession session=request.getSession();

通过request拿到application内置对象:

ServletContext application =request.getSession().getServletContext();

通过response拿到out内置对象:PrintWriter out=response.getWriter();

 

 一个servlet可以由多个servlet-mapping来匹配,根据url-pattern访问servlet。配置url-pattern 时最好不要省略扩展名 <url-pattern>*.do</url-pattern>,建议不要使用<url-pattern>/*</url-pattern>这种配置,容易引起混乱。

 

Filter过滤器/拦截器:

工作在客户端的和服务端交接的界面上。

Filter的作用:

1、         对请求做拦截

2、         对结果做拦截

Filter的语法:

1、         包声明:package cn.filter:字节码文件放在WEB-INF下的classes对应的包目录 结构下

2、         包导入: import java.io.*;import javax.servlet.*;import javax.servlet.http.*;

3、         定义类实现Filter接口: public class MyFilter implements Filter{}

4、         实现接口中的三个方法:(必须都实现)

public void init(FilterConfig config)throws ServletException{}//Filter对象一创建就调用

public void doFilter(ServletRequest request1,ServletResponse response1,FilterChain chain)throws IOException,ServletException{//如果对所有请求都拦截了,只要一发请求就会被调用

HttpServletRequest request=( HttpServletRequest)request1;//先造型为http协议的类型

HttpServletResponse response=( HttpServletResponse)response1;

<处于chain.doFilter方法之前对请求做拦截,这里写对请求的拦截代码>

chain.doFilter(request,response);//请求下传

注意:这里的request和response对象是造型以后的request和response内置对象

<处于chain.doFilter方法之后对结果做拦截,这里写对结果拦截的代码>

}

public void destroy(){}//tomcat关闭,Filter销毁时调用

5、         Filter的配置:(配置在WEB-INF下的web.xml文件中)

<filter>

  <filter-name>first</filter-name>

<filter-class>cn.filter.MyFilter</filter-class>

<!—这里可以配置初始化参数信息--->

<init-param>

   <param-name>name<param-name>

<param-value>hahaha</param-name>

</init-param>

</filter>

 

<filter-mapping>

  <filter-name>first</filter-name>

  <url-pattern>/*</url-pattern>//这里表示拦截所有组件

<filter-mapping>

 

Filter的执行过程:

tomcat一启动就创建Filter对象就调用init()方法(比servlet更早)

执行init()方法就会注入封装Filter初始化信息的FilterConfig内置对象的地址注入进来。

(前提:filter的配置中是对所有请求进行拦截)请求过来时 ,tomcat创建request内置对象接收请求参数,马上调用doFilter方法中chain.doFilter方法之前的代码对请求做拦截。

调用doFilter()方法时 会注入request,response,FilterChain对象的地址,接收的request和response为ServletRequest和ServletResponse类型,需要造型为HttpServletRequest 和HttpServletReponse类型。

对请求拦截过后调用 chain.doFilter(request,response)下传请求

chain.doFilter(request,response)的作用:请求拦截结束后,先判断有没有下一个拦截器,如果有下一个拦截器激活下一个拦截器,如果没有下一个拦截器就把请求下传交给请求访问的组件。

所有拦截器拦截后,将请求交给访问的组件,请求结束时,调用doFilter方法中的chain.doFilter方法后面的代码对结果进行拦截。

(注:Filter的url-pattern用户是不知道的)

 

如果想对任意请求都拦截并且不下传:

将chain.doFilter(request,response);这条语句注释掉。不让这条语句执行。(需要重新编译并且重启Tomcat)

执行结果:jsp页面中,没有任何结果输出,在后台只执行chain.doFilter方法之前的代码,后面的代码又回传一次当做请求被拦截。总之没有结果下传,没有结果发送到浏览器显示

 

编码拦截器:(对所有用户的所有请求都有效),和项目没有直接关系

1、         在web.xml中的配置

<filter>

  <filter-name>CharacterEncoding</filter-name>

<filter-class>cn.filter.CharacterFilter</filter-class>

<init-param>

   <param-name>encoding<param-name>

<param-value>gbk</param-name>

</init-param>

</filter>

 

<filter-mapping>

  <filter-name> CharacterEncoding </filter-name>

  <url-pattern>/*</url-pattern>//这里表示拦截所有请求

<filter-mapping>

2、         在CharacterFilter类中的布局

设置实例全局变量 private String encoding;

在CharacterFilter的init(FilterConfig config)方法中,注入config内置对象

this.encoding=config.getInitParameter(“encoding”);//将配置信息中的encoding值赋给实例全局变量。 Gbk

代码:

public void init(FilterConfig config)throws ServletException{

  this.encoding=config.getInitParameter(“encoding”);

}

在 doFilter()方法中 得到request内置对象,造型后, 统一设置编码

request.setCharacterEncoding(encoding);

 

请求验证拦截器

拦截所有的jsp页面

验证Session信息

如果发现请求是login.jsp或者regist.jsp不拦截了,直接下传

分析请求路径:拿到请求字符串,截取访问的页面的字符串,if判断页面是否为指定不需要验证的页面,如果是就不用验证直接下传,如果不是就验证,验证成功后再下传,验证不成功时就客户端跳转到登录界面。

String currentUrl=request.getRequestURL();//拿到请求字符串

拿到包含项目名项目名全部访问路径:currentUrl=/test/index.jsp

int index=currentUrl.indexOf(“/”,1);//从第一个位置(t)开始 取出/出现的第一个位置(其实我觉得这里应该使用lastIndexOf()来索引,反向搜索出第一个反斜杠/出现的位置,然后根据字符串的长度截取字符串。因为请求路径不一定是项目名+请求页面.jsp,可能还会有中间的文件夹名)

String url= currentUrl.substring(index);//截取从/开始的后面的所有的字符串  (/index.jsp)

 

if(!”/index.jsp”.equals(url)){

session验证

response.setnRedirect(request.getContextPath()+’’/index.jsp”);

request.getContextPath()//获取当前项目名,必须要加这个,不然可能会跳不过去,因为这不是jsp页面。

}else{

      请求下传

}

 

StringBuffer currentURL=request.getRequestURL();//得到当前访问路径

System.out.println("获取到的路径:"+currentURL);//

int index=currentURL.lastIndexOf("/",currentURL.length());//反向搜索,从最后一个字符开始搜索,找到反向第一次出现的反斜杠的位置(这个位置的下标还是从正向开始计数)

System.out.println("获取到最后一个反斜杠的位置:"+index);//

String url=currentURL.substring(index);//截取出反斜杠之后以及包括反斜杠的字符串

System.out.println("截取后的URL:"+url);

 

以上语句对应的输出结果为:

获取到的路径:http://user-20150330oi:8080/bank2.0/login.jsp

获取到最后一个反斜杠的位置:35

截取后的URL:/login.jsp

 

 

 

非法文字拦截器:

1、         在web.xml文件中的配置

<filter>

<filter-name> LetterFilter </filter-name>

<filter-class>cn.filter. LetterFilter </filter-class>

</filter>

 

<filter-mapping>

<filter-name> LetterFilter </filter-name>

<url-pattern>/*</url-pattern>//这里表示拦截所有请求

<filter-mapping>

2、         通过request内置对象获取请求中的字符串

使用 indexOf() 或者 contains() 方法判断请求参数中是否有非法文字,有的话就不下传请求,通过客户端跳转到非法页面,没有的会就请求下传,服务端跳转到请求页面。

 

懒加载拦截器:(结果拦截)

在请求即将结束的时候,回到拦截器。把Hibernate session连接关闭。

 

 

课后作业:

验证ELDemo

在银行项目中添加编码过滤器(encoding)和请求验证过滤器(session验证)util包中

任务:jquery 表单动态验证测试(加入到银行项目中登录和注册验证)

明天讲Listener ,下周讲 strust1.0

Listener

监听器的作用:

对内置对象的状态创建和销毁以及内置对象的属性的状态变化做监听。(设定属性,移除属性,替换属性)

常用的四个内置对象, page 和request内置对象的生存周期比较短,一般不做监听。

主要对session和application内置对象做监听。

监听器的工作原理:

和awt事件突发机制很像,写了一个监听器类部署到服务器上后,服务器最先创建的是监听器对象,监听器对象按照要求对session和application内置对象做监听,发现状态变化就调用相应的方法做处理。

状态变化包括 对象的创建和销毁以及属性的增加,移除和替换。

监听器的语法

1、         Application监听器

a)     包声明 package cn.listener.application (字节码文件放在WEB-INF下的classes对应的包目录结构下)

b)     包导入 import javax.servlet.*;

c)     实现对对象的监听 实现  ServletContextListener接口,实现两个方法

public class ApplicationDemo implements ServletContextListener{}

 

《Application对象创建时调用:服务器一启动就创建,调用》

public void contextInitialized(ServletContextEvent sce ){

ServletContext application=sce.getServletContext();//拿到application对象

}

《Application对象销毁时调用:服务器一关闭就销毁,调用》

public void contextDestroyed(ServletContextEvent sce ){}

d)     实现对属性的监听 实现ServeltContextAttributeListener接口,实现三个方法

public class ApplicationDemo implements ServletContextAttributeListener{}

 

《属性增加时调用:application.setAttribute(“name”,”zs”)时调用》

public void attributeAdded(ServletContextAttributeEvent scae){

      scae.getName();//设定的属性名 name

      scae.getValue();//设定的属性值 zs

}

《属性替换时调用:application.setAttribute(“name”,”ls”)时调用》

public void attributeReplaced(ServletContextAttributeEvent scae){

scae.getName();//被替换的属性名 name

      scae.getValue();//被替换的属性值(替换前) zs

 

}

《属性移除时调用:application.removeAttribute(“name”)时调用》

public void attributeRemoved(ServletContextAttributeEvent scae){

      scae.getName();//被移除的属性名

      scae.getValue();//被移除的属性值

 

}

 

在内置对象中取属性值,如果属性不存在会输出null,EL表达式会输出空串

 

 

e)     在web.xml中的配置(和用户请求没有关系,不用配置mapping)

<listener>

<listener-class>cn.listener.ApplicationDemo</listener-class>

</listener>

 

2、         将初始化信息设置到application中,所有用户都能拿到这个配置信息

<context-param>

  <param-name>name</param-name>

  <param-value>value</param-value>

</context-param>

ContextLoaderListener:对application对象的创建(contextInitialized())和销毁(contextDestroyed())做监听

拿到application对象  ServletContext application=(ServletContextEvent)sce.getServletContext();

拿到初始化信息 application.getInitParameter(“name”);

创建bean工厂

 

3、         Session监听器

a)     包声明 package cn.listener.session; (字节码文件放在WEB-INF下的classes对应的包目录结构下)

b)     包导入 import javax.servlet.http.*;

c)     实现接口 HttpSessionListener实现两个方法

Public class SessionDemo implements HttpSessionListener{}

<session对象创建时调用,用户发请求访问动态组件时创建>

public void  sessionCreated(HttpSessionEvent hse){

      HttpSession session=hes.getSession();//拿到session对象

}

 

<session对象销毁时调用 >

public void  sessionDestroyed(HttpSessionEvent hse){}

d)     实现接口 HttpSessionAttributeListener 实现三个方法

Public class SessionDemo implements HttpSessionAttributeListener{}

<session对象属性增加时调用:session.setAttribute(“name”,”zs”); >

public void attributeAdded(HttpSessionBindingEvent hsae){

      hsae.getName();//增加的属性名 name

      hase.getValue();//增加的属性值 zs

}

 

<session对象属性移除时调用:session.removeAttribute(“name”,”zs”); >

public void attributeRemoved(HttpSessionBindingEvent hsae){

      hsae.getName();//被移除的属性名 name

      hase.getValue();//被移除的属性值 zs

 

}

 

<session对象属性值修改时调用:session.removeAttribute(“name”,”宝贝”); >

public void attributeReplaced(HttpSessionBindingEvent hsae){

      hsae.getName();//被替换的属性名 name

      hase.getValue();//被替换的属性值 zs(替换前的)

 

}

 

 

4、         内置对象的创建顺序:

Listener àConfigàapplicationàfilteràsession

监听器对象在application内置对象创建以前创建

监听器对象对application对象做监听,调用相应的方法

 

JavaScript代码:(关闭session的方法)

function window.onunload(){

      if(((event.clientX>Document.body.clientWidth)&&

(event.clientY<0))||event.altKey||event.ctrlKey){

  indow.location.replace(“removeLine.jsp”);

}

}

removeLine.jsp页面中有销毁session的代码: session.invalidate();//销毁session

 

利用监听器做web聊天室 还有map集合和list集合  (session和application)

1、         定义一个监听器类,统计在线人数。

登录成功后,往session里面设定验证信息,被监听器监听 调用 attributeAdded() 方法,通过事件对象,拿到设定值的session,并且拿到session中的属性名和属性值。把session信息(用户名和密码)存入集合中容器中,(web聊天室没有对登录人数的限定)

2、         监听器用集合管理,集合应该放在application中,application对象一创建,设定一个空集合,application.setAttribute(“alluser”,new ArrayList()); 赋值到实例全局变量中

3、         在servlet中验证,验证成功往session中设定验证信息  设置的时候就会调用attributeAdded方法, 从application中拿到集合,把登录的用户放到application中。服务端跳转到显示所有用户的jsp页面,显示所有在线人数,(直接拿到list集合)迭代出在线名单

下线

使用注销链接,sessionDestoroyed ()  拿到在线用户集合,从集合中移除此用户,把移除后的集合存application中

私聊:

拿到对应私聊用户的session信息,根据session私聊 通过事件对象,

Se.getValue()作为key,se.getSession()作为value ,设置到map集合中

Map创建的时机:在application对象创建的方法中创建空map集合,list存放上线用户名,map存放 key 上线用户名,value 上线用户Session(每个用户只有一个session)

Map.put(se.getValue(),se.getSession())

私聊时输入聊天对象姓名:,聊天信息。提交给私聊 servlet

拿到application中的map集合,通过聊天姓名找到对应的session

往找到的session中设定聊天信息

 

接收页面:自己接收信息

 

公聊:

迭代出所有的session信息,往所有的session中设定信息

到application中找到所有在线的用户名,然后从map中根据用户名取出session

Web聊天室要记得做得漂亮点噢

 

私聊和公聊区分: 自己设定标记

使用html的frameset技术 或者是标签包含,对人数和信息不断刷新,包含过来,消息发送完毕后跳转到另一个jsp页面,显示接收的消息 show.jsp需要不断属性,接收消息。

 

 

不如就这样散了吧

 

 

 

JDBC和连接池

DBC  Java连接数据库的技术

Driver :com.mysql.jdbc.Driver

url:jdbc:mysql://localhost:3306/数据库名

数据存贮在文件中:

特点:先把文件中的所有数据读到内存

代码中需要设定对文件的操作(增删改查)

了解文件的存储结构(properties的结构为map<key,value>)

文件不受操作系统对的影响,也不受语言的影响,移植性好

两种文件不依赖底层和语言:xml和properties文件

数据库存储:

特点:不关心数据在数据库中怎么存放

所有的用户的数据都放在同一个数据库中

一旦数据库系统崩溃,数据全部泄漏(安全性低)

数据库不能移植(不同的数据库有不同的daoImpl)

ODBC:不需要考虑数据库的位置,内容,驱动,只考虑数据源的名称

Java连接数据库有两种技术:jdbc和ODBC

连接微软的Access数据库 ODBC

创建access数据库:

 

 连接数据库的步骤:

1、         加载驱动 :协议名+驱动名 Class.foName(com.mysql.jdbc.Driver);//加载驱动的目的,让java程序识别jdbc,识别这个数据库 在jdk的标准类库中找到对应驱动。

2、         创建连接:url:     =jdbc:mysql://localhost:3306/数据库名

Connection conn=DriverManager.getConntection(url);//创建连接意味着java程序和数据源建立信道

3、         写sql语句:String sql=”select * from user”;

创建操作,执行sql语句 PreparedStatement st=conn.createStatement();

4、         通过操作发指令:st.executeQuery(sql);//执行sql语句

如果是插入或者修改或者删除 st.executeUpdate(sql);//操作成功结果为正整数

5、         查询的时候需要收集结果 ResultSet rs= st.executeQuery(sql);

6、         关闭连接 rs.close()  st.close()  conn.close()

 

ODBC驱动:

Sun.jdbc.odbc.JdbcOdbcDriver

ResultSet rs;

结果集返回的文件指针的位置,指在所有记录之前

找到记录的各个字段的值,得先知道字段的类型

rs.getInt(“id”);

rs.getDouble(“money”);

rs.getString(“username”);

 

连接数据有关结果bean的知识

结果bean是通过持久层创建,在持久层把结果集中的数据封装到结果bean中。返回给业务层。

收集结果时,ID是主键,由数据库自动维护,通常不获取主键。

Jdbc连接数据库类中,在构造方法中 加载驱动和创建连接。

使用executeQuery();方法时

ResultSet rs=ps.executeQuery();

结果集  rs首次指在从数据库中查询出来的记录中上一个指针位置。所以如果要取出结果集 rs中的数据,需要 rs.next()才会指到第一个记录的位置。如果结果集rs查询到了多条记录则依次循环使用rs.next().  While(rs.next()){}

web.xml中存放 servlet filter listener的配置信息

 

数据库驱动包在项目中的存放位置

web项目的数据库驱动,放在项目名下的WEB-INF下的lib文件中。

Java项目的数据库驱动  jdkàjreàlbàext文件夹下

 

使用jdbc直接连接Oracle数据库 数据库名 mldn

Oracle的驱动程序就在oracle的安装目录下

Driver:oracle.jdbc.driver.OracleDriver

url: jdbc:oralce:thin:@localhost:1521:mldn(mldn为数据库名)

DBUSER:scott (默认用户名)

DBPASSWORD:tiger  (默认密码)

 

加载驱动 Class.forName(driver);

创建连接: DriverManager(url,DBUSER,DBPASSWORD);

 

使用jdbc直接连接sqlServer数据库

Sqlserver有三个驱动包,使用时要导入三个

Driver :com.microsoft.jdbc.sqlserver.SQLServerDriver

url:  jdbc.microsoft:sqlserver://localhost:1433;DatabaseName=数据库名;

username:  sa

password: 为空或者自己设定的密码值

加载驱动 Class.forName(driver);

创建连接: DriverManager(url,username,password);

 

 

Jdbc连接MySQL数据库

Mysql的驱动包要自己下载

Mysql 驱动名不唯一

Driver : com.jdbc.mysql.Driver(驱动一)

org.gjt.mm.mysql.Driver(驱动二)

Mysql的url可以省略端口号

url: jdbc:mysql://localhost:3306/数据库名

username:root

password:root

加载驱动 Class.forName(driver);

创建连接: DriverManager(url,username,password);

 

连接池

连接池管理类 DBConnManager:初始化的时候创建连接池,取得连接

Vector类型变量:Vector就是一个List子类集合,Vector是线程安全的,list 是线程不安全的集合。Vector存放连接池的 连接池名 驱动名,url,用户名,密码,最大连接数。

Vector poolName=new Vector();

Vector drivers=new Vector();

Vector url=new Vector();

Vector username=new Vector();

Vector password=new Vector();

Vector maxConns=new Vector();

 

HashTable是map集合,里面存放key和value。//连接池队列

 

在构造方法中,把不同的数据库的不同的连接信息设置到6个集合的相应的位置上。

第一个集合中的第0个元素放mysql数据库名 mysql

           第二个集合中的第0个元素放mysql数据库的驱动名

           第三个集合中的第0个元素放mysql数据库的url

           第四个集合中的第0个元素放mysql数据库的username

           第五个集合中的第0个元素放mysql数据库的password

           第六个集合中的第0个元素放mysql数据库的 maxConns

 

           第一个集合中的第1个元素放access数据库名 access

           第二个集合中的第1个元素放access数据库的驱动名

           第三个集合中的第1个元素放access数据库的url

           第四个集合中的第1个元素放access数据库的username

           第五个集合中的第1个元素放access数据库的password

           第六个集合中的第1个元素放access数据库的 maxConns

 

      以此类推,添加各种数据库的信息

 

建立连接 方法:

public void createConns(){

      for(int i=0;i<poolname.size();i++){

           poolname=poolname.elementAt(i).toString();

drivers==drivers.elementAt(i).toString();

url=url.elementAt(i).toString();

username=username.elementAt(i).toString();

password=password.elementAt(i).toString();

maxConns=Integer.parseInt(maxConns.elementAt(i));

创建连接池对象

DBConnPool  pool=new DBConnPool(poolname,drivers,url,username,password,maxConns);

connPools=Map.put(poolname,pool);

}

}

取出Vector集合中第0个元素

vector.getElementAt(0);

移除Vector集合中第0个元素

vector.removeElementAt(0);

 

//从连接池中找到连接对象

Public void getConnection(String name){

      DBConnPool   pool=( DBConnPool  )connPools.get(name);

      If(pool!=null){

  Return poo.getConnection();

}

}

 

DBConnPool  :是一个连接池对象的类

Public class DBConnPool  {

Private int inuser=0;//当前正在使用的连接数

Vector connections=new Vector();//空集合,接收请求连接的对象

      Private String poolame;

      Private Stirng driver;

      ……

      Private int maxConns;

 

Public DBConnPool  (String poolname,String driver,……,int maxConns){

      This.poolname=poolname;

      ……

      This.maxConns=maxConns;

}

}

Map 中:key是连接数据库名,value是连接池对象

 

连接池的关闭

到HashTable集合中拿到所有的连接池

Enumeration  allPools=map.elements()       (connPools.elements())

 

连接资源的释放,先到map中取得连接,调用对应数据库的连接池,把当前释放的连接放到空连接集合中,使用人数加一。

 

最后所有人都使用完了,就关闭所有连接资源。

 

Connections.removeAllElements();

使用连接池的目的:连接复用

连接池的核心思想是连接复用,通过建立一个数据库连接池以及一套连接使用,分配管理策略,使得连接池中的连接可以得到高效,安全的复用,避免了数据的频繁连接建立,关闭的开销。

连接池主要有三个部分:连接池的建立,连接池的连接使用管理,连接池的关闭

 

使用 Connectioins.properties建立连接池

一次创建一个连接池,创建什么连接池,取决于properties文件

在构造方法中,拿到连接池信息

创建连接池,一个连接池不用放在集合中 ,不用使用vector集合

 

连接池中的安全性问题:

连接池需要考虑线程安全。所以使用Vector集合,以及获取连接等方法都添加同步(synchronized)

Synchronized任何类的并发都可以访问,但是一个类的使用都不影响别的使用。

使用构造方法,只提供get方法不提供set方法,属性定义为final类型。

Synchronized表示一次只能有一个线程对数据进行修改操作,其余线程需要对数据进行修改时要等锁释放后才能进行修改。

Fail-fast迭代器:当线程试图在“结构上”更改集合时,抛出CurrnetModificationException异常。

 

周末计划:

1、         完善银行项目2.0,增加注销功能,以及对表单数据的验证(jquery),还有时间的话就把界面做的漂亮些

2、         修改老师的连接池类,完成作业

3、         Web聊天室,使用frameset包含页面,做好界面

4、         还有时间就把以前看过的框架视频笔记看一遍,然后看jquery视频

最重要的三个框架:Strust 1.0  hibernate mybatis

PreparedStatement:预操作可以对sql语句做动态填充,使用占位符(?)

HashMap和Hashtable的关系:

都实现了Map接口

不同点:

HashMap是非同步的(非 synchronzied)效率高,而Hashtable是同步的,单线程操作hashtable也是效率低的。

HashMap可以接收null为key或value,hashtable不可以

Hashmap使用Iterator进行迭代输出,Hashtable使用Enumeration集合迭代输出

Vector和List集合相似,底层都是数组,但是Vector是线程安全的 效率低,List不安全使用效率高。

 

设计模式:用在实践当中证明有效的思想来指导代码的开发

设计模式有两种:(架构模式和程序设计模式)

架构模式:指导项目的分层开发

程序设计(代码)模式: 23种设计模式,(工厂,单例,适配器,观察者,代理)

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

MVC设计模式:

Model模型层:javaBean 数据bean:表单bean在控制层创建和收集,结果bean 在持久层创建和收集。在结果层显示的是结果bean。业务bean:完成对请求的操作,

View视图层:jsp,接收用户请求数据,对结果信息进行显示

Control控制层:Servlet,拿到请求参数,把数据封装到表单bean中,分析请求,根据请求结果把相应请求转给相应的业务对象,根据请求结果转到相应界面显示

MVC设计模式的优点:

各司其职,互不干涉(某一层的变化不会影响到另一层)

有利于开发中的分工

有利于组件的重用

MVC模式是一种思想,影响到整个系统的设计。

JSP页面要求:

不能创建对象

不能修改结果bean数据

JSP页面中的相对url:

Action =”02Servlet/FormServlet” 转向demo.jsp

demo.jsp在02Servlet目录下

在demo.jsp 使用超链接 <a href=”a.jsp”></a> a.jsp也在02Servlet目录下

浏览器会把所有路径都看作是相对于servlet的URL。

在路径上面加上反斜杠,表示取绝对路径。<a href=”/first/a.jsp”/>

MVC流程:

浏览器发请求给控制层,控制层分析请求调用业务层对象相应方法,业务层访问数据库调用持久层的相应的方法,持久层把结果bean给业务层,业务层将信息返给控制层,控制层返给视图层,视图层拿到结果bean进行处理,然后通过response发给浏览器进行显示

Struts1.0流程:严格遵循MVC模式

MVC控制流程:

请求中 command=find&uname=”tom”//调用业务对象的find方法,传递请求参数 tom.

业务层返回字符串 跳转页面给控制层(”/show.jsp”)

控制层servlet根据业务层返回的字符串跳转到相应的页面

业务层中也会注入request和response内会对象,将处理请求 例如:

public class Contribute{

public Contribute(){}

public String getAllArticle(HttpServletRequest request,HttpServletResponse response) throws IOException,ServletException

{//在这里创建持久层对象,调用持久层方法 完成对数据库的操作

                                BankCustomer bc=new BankCustomer();

                                bc.setUserName("1xt008");

                                bc.setAge(100);

                                request.setAttribute("bcc",bc) ;

                                return "/showResult.jsp";

}

}

 

今天的作业:MVC模式,访问数据库 取出数据在jsp页面中显示。

下午的学生管理系统项目,会升级为struts版本的

EL表达式

概念:表达式语言

EL表达式的优点:

简单,功能强大,不容易出错,高效

EL表达式的作用:

El表达式是动态代码,由服务器执行,只能工作在jsp页面中

输出内置对象里的属性值或者计算内置对象里的属性值(主要用到page,request,response,application内置对象)

El表达式对环境有要求

对jsp版本必须是2.0版本以上,Tomcat4.0以上对应的jsp版本2.0以上。

El表达式的语法:

${内置对象的属性名}//不是参数名,是属性名

El表达式输出内置对象的顺序:

依次从page àrequestàsessionàapplication 找出对应属性,找到对应属性后,不会再从之后的scope域中找了,如果四个域中都没有找到则输出空串。

pageContext.setAttribute(“name”,”小仙女”);

<%=name %>//这里输出的是 小仙女

${name}//这里输出的是 小仙女

 

pageContext.setAttribute(“sname”,”小仙女”);

<%=name %>//这里输出的是 null

${name}//这里输出的是 空串,因为从内置对象中取出属性值,发现内置对象中不存在此属性名则输出空串,如果存在就调用该对象对应的get方法输出属性值。

 

pageContext.setAttribute(“sname”,”小少年”);

request.setAttribute(“sname”,”小仙女”);

${sname}//输出的是 小少年,因为先从page域中找对应属性,找到了就不会再往后找了

如果需要输出request域中的sname属性值,则需要通过隐式对象从特定的scope于中取出属性值

 ${reqeustScope.sname}//这里输出 小仙女

什么叫隐式对象?

隐式对象是指不需要显示声明可以直接使用的内置对象。Jsp页面中可以直接使用九大内置对象也叫隐式对象。EL表达式有四大隐式对象,(pageScope,requestScope,sessionScope,applicatonScope),requestScope是变量名,存放的是隐式对象的地址,该对象到request域中找到对应属性值。

El表达式的计算功能:

request.setAttribute(“a”,”30”);//30是String类型

pageContext.getAttribute(“b”,5);//5为Integer类型

request.getAttribute(“c”);//没有c属性,这里取出的为 空串

${a*b+c+6 }//这里输出结果为 156,EL会自动把字符串30转换成int类型30,把Integer类型的5自动拆箱,把空串c视为0 ,然后再进行计算。 EL表达式会自动根据实际情况对参与运算的数据进行类型转换。

${2+3*5}//输出17

${4>5}//输出false

 

在遇到不支持El表达式的环境中添加此条page指令:

<%@ page isELIgnored=”false”%>//设置是否支持EL表达式,true:表示禁止使用,false表示支持使用。使得当前jsp页面不要忽略EL表达式

 

业务层把结果数据设置到内置对象中,一般是设置到request内置对象中。

 

EL表达式拿到结果bean中的数据

Jsp:使用EL表达式显示结果数据,结果bean:封装结果数据,Servlet:控制结果转向

SimpleBean sb=new SimpleBean();

sb.setName(“哈哈哈”);

request.setAttribute(“sb”,sb);

在jsp页面中用EL 表达式取出结果bean的属性:  ${sb.name}//输出结果为 哈哈哈

sb1不存在,如果${sb1.name}//从scope域中取sb1属性值,没找到取出空串,之后就不再调用getName()方法。name代表的是 getName()方法,而不是name属性。

name1不存在,如果${sb.name1}//从scope域中取sb1属性值,继续调用getName1()方法,方法不存在则出现空指针异常。name1代表的是getName1()方法,而不是name1属性。

如果bean中没有name1属性而有getName1()方法,就不会出现空指针异常,如果没有getName1()方法,只有name1属性则会报出空指针异常。关键还是要有getName1()这个方法。EL表达式是通过调用get方法取值。

 

EL表达式的关联关系:(一对一,一对多,多对多)

对象之间有两种关系:继承(is a )和关联(has a )

推荐使用关联关系,因为继承关系会打破对象的封装性,关联关系不会。

一对多:关联属性在多的一方

关联属性的类型不能是基本类型,只能是自定义类型。

谁给关联属性设值谁就是在维护关系。

给关联属性设值也叫装配。

${student.teacher.name}//输出与student类相关联teacher类的name属性值,这里的student是属性名,通过student属性名找到student对象的地址。叫做深度导航。

 

多对多:关联属性在中间类(EmployeeBean)中

EmployeeBean雇佣类,Stuff 员工类,Company 公司类

在雇佣(EmployeeBean)类中 定义Stuff和Company类型的私有属性,并且提供set和get方法。

private  Stuff stuff;//一个员工可以被多个公司雇佣

private Company company;//一个公司可以雇佣多个员工

 

${employee }//输出emloyee对象的地址

${employee .stuff}//输出stuff对象的地址

${employee.stuff.name}//得到被雇佣的员工的姓名

${employee.company.name}//得到雇员工的公司的名称

 

El 表达式在集合中的应用:

List list=new ArrayList();//创建一个list集合

Student stu=null;

stu=new Student();//Student是一个javaBean

stu.setName(“zs”);//name为Student对象的一个属性

list.add(stu);//把Student对象的地址放入集合中

 

stu=new Student();//Student是一个javaBean

stu.setName(“ls”);//name为Student对象的一个属性

list.add(stu); //把Student对象的地址放入集合中

 

request.setAttribute(“all”,list);//将list集合设置到request内置对象中

在jsp页面中输出集合:

${all}//all是属性名,all的属性值为list集合对象的地址,集合复写了toString

${all[1]}//输出all所指集合对象地址所指的第一个元素的地址

${all[1]}这种输出方式只适合有序的集合 list集合,set和map集合不能这样输出

一般不建议使用list集合,一般使用set和map集合。

 

使用Iterator迭代输出:

List list=request.getAttribute(“all”);

Iterator it=list.iterator();

While(it.hasNext()){

      pageContext.setAttribute(“stu”,it.next());//将取出的对象存储到page域中

      ${stu.name}//依次取出从集合中迭代出来的元素所指对象的name属性

(这里第一次迭代输出 zs,第二次迭代输出 ls)

}

在jsp页面中借用jstl标签输出集合

导入jstl包:<%@ taglib prefix=”c” uri=”http:// java.sun.com/jsp/jstl/core” %>

使用<c:forEach var=”每个变量的名字” items=”要迭代的集合”  varStatus=”每个对象的状态” begin=”循环从哪里开始” end=”循环从哪里结束” step=”循环的步长” />标签输出

实例:<c:forEach var=”stu” items=”all”>

      ${stu.name}

</c:forEach>

 

 posted on 2018-03-09 17:48  阿叮339  阅读(593)  评论(0编辑  收藏  举报