大家好,欢迎来到IT知识分享网。
1 jsp工作原理
JSP的工作模式是请求/响应模式,客户端首先发出HTTP请求,JSP程序收到请求后进行处理并返回处理结果。在一个JSP文件第1次被请求时,JSP引擎(容器)把该JSP文件转换成为一个Servlet,而这个引擎本身也是一个Servlet。
了解了JSP的运行原理后,完全可以利用其中的一些步骤来做一些工作,如:可以在jspInit()中进行一些初始化工作(建立数据库的连接、建立网络连接、从配置文件中获取一些参数等),可以在jspDestroy()中释放相应的资源等
2 JSP脚本元素
JSP脚本元素是指嵌套在<%和%>之中的一条或多条Java程序代码。通过JSP脚本元素可以将Java代码嵌入HTML页面中,所有可执行的Java代码,都可以通过JSP脚本来执行
1.JSP ScriptletsJSP Scriptlets 是一段代码段。当需要使用Java实现一些复杂操作或控制时,可以使用它。JSP Scriptlets的语法格式如下所示。
<% java 代码(变量、方法、表达式等)%>
在JSP Scriptlets中声明的变量是JSP页面的局部变量,调用JSP Scriptlets时,会为局部变量分配内存空间,调用结束后,释放局部变量占有的内存空间。
2.JSP声明语句
JSP 的声明语句用于声明变量和方法,它以“<%!”开始,以“%>”结束,其语法格式如下所示。
<%!定义的变量或方法等%>
需要注意的是,<%!和%>里面定义的属性是成员属性,相当于类的属性,方法相当于全局的方法,也相当于类里面的方法,但是它是不可以进行输出的,因为它只是进行方法的定义和属性的定义。<%和%>可以进行属性的定义,也可以输出内容,但是它不可以进行方法的定义。因为这对标签里面的内容是在此JSP被编译为Servlet的时候,放在_jspService()方法里面的,这个方法就是服务器向客户端输出内容的地方,它本身就是一个方法。所以,如果在它里面定义方法的话,那么就相当于是在类的方法里面嵌套定义了方法,这在Java里面是不允许的。但是,可以在里面定义自己的私有变量,因为方法里面也可以定义变量,也可以调用方法,唯独不可以再定义方法了。
总之,<%!和%>是用来定义成员变量属性和方法的,<%和%>主要是用来输出内容的,因此,如果涉及到了成员变量的操作,那么就应该使用<%!和%>,而如果涉及到了输出内容,就使用<%和%>。
3 .JSP表达式
JSP表达式(expression)用于将程序数据输出到客户端,它将要输出的变量或者表达式直接封装在以“<%=”开头和以“%>”结尾的标记中,其基本的语法格式如下所示。<%= expression %>在上述语法格式中,JSP表达式中的变量或表达式的计算结果将被转换成一个字符串,然后插入到JSP页面输出结果的相应位置处。例如,对example01.jsp文件进行修改,将<body>内的脚本元素修改为表达式,具体如下。
<%=a+b %><br />
<%=print() %>
4 JSP注释
同其他各种编程语言一样,JSP也有自己的注释方式,其基本语法格式如下。
<%– 注释信息 –%>
5 page指令
在 JSP 页面中,经常需要对页面的某些特性进行描述,例如,页面的编码方式、JSP 页面采用的语言等,这时,可以通过page指令来实现。page指令的具体语法格式如下所示。<%@ page 属性名1= “属性值1” 属性名2= “属性值2” …%>
<%@ page language=”java” contentType=”text/html; charset=UTF-8″ pageEncoding=”UTF-8″ %>
<%@ page import=”java.awt.*” %>
<%@ page import=”java.util.*”,”java.awt.*” %>
除了import属性外,其他的属性都只能出现一次,否则会编译失败。需要注意的是,page指令的属性名称都是区分大小写的。
6 include指令
在实际开发时,有时需要在JSP页面静态包含一个文件,例如HTML文件、文本文件等,这时,可以通过include指令来实现。include指令的具体语法格式如下所示。
<%@ include file=”被包含的文件地址”%>
include指令只有一个file属性,该属性用来指定插入到JSP页面目标位置的文件资源。需要注意的是,插入文件的路径一般不以“/”开头,而是使用相对路径。
关于include指令的具体应用,有很多问题需要注意,接下来,将这些问题进行列举,具体如下。
(1)被引入的文件必须遵循 JSP 语法,其中的内容可以包含静态 HTML、JSP 脚本元素和JSP指令等普通JSP页面所具有的一切内容。
(2)除了指令元素之外,被引入的文件中的其他元素都被转换成相应的Java源代码,然后插入当前JSP页面所翻译成的Servlet源文件中,插入位置与include指令在当前JSP页面中的位置保持一致。
(3)file属性的设置值必须使用相对路径,如果以“/”开头,表示相对于当前Web应用程序的根目录(注意不是站点根目录),否则,表示相对于当前文件。需要注意的是,这里的 file属性指定的相对路径是相对于文件(file),而不是相对于页面(page)
7 JSP隐式对象
在JSP页面中,有一些对象需要频繁使用,如果每次都重新创建这些对象则会非常麻烦。为了简化Web应用程序的开发,JSP2.0规范中提供了9个隐式(内置)对象,它们是JSP默认创建的,可以直接在 JSP 页面中使用。
out对象
在JSP页面中,经常需要向客户端发送文本内容,这时,可以使用out对象来实现。out对象是javax.servlet.jsp.JspWriter类的实例对象,它的作用与ServletResponse.getWriter()方法返回的PrintWriter对象非常相似,都是用来向客户端发送文本形式的实体内容。不同的是,out对象的类型为JspWriter,它相当于一种带缓存功能的PrintWriter。
<%out.println(“first line<br />”);
response.getWriter().println(“second line<br />”); %>
尽管out.println();语句位于response.getWriter().println();语句之前,但它的输出内容却在后面。由此可以说明,out 对象通过 print 语句写入数据后,直到整个JSP页面结束,out对象中输入缓冲区的数据(即first line)才真正写入到Serlvet引擎提供的缓冲区中。而response.getWriter().println();语句则是直接把内容(即second line)写入Servlet引擎提供的缓冲区中,Servlet引擎按照缓冲区中的数据存放顺序输出内容。
有时候,开发人员会希望out对象可以直接将数据写入Servlet引擎提供的缓冲区中,这时,可以通过page指令中操作缓冲区的buffer属性来实现。
<%@ page language=”java” contentType=”text/html; charset=UTF-8″ buffer=”0kb”%>
8 pageContext对象
在JSP页面中,使用pageContext对象可以获取JSP的其他8个隐式对象。pageContext对象是javax.servlet.jsp.PageContext类的实例对象,它代表当前JSP页面的运行环境,并提供了一系列用于获取其他隐式对象的方法。
JspWriter getOut() 用于获取out隐式对象
Object getPage() 用于获取page隐式对象
ServletRequest getRequest() 用于获取request隐式对象
ServletResponse getResponse() 用于获取response隐式对象
HttpSession getSession() 用于获取session隐式对象
Exception getException() 用于获取exception隐式对象
ServletConfig getServletConfig() 用于获取config隐式对象
ServletContext getServletContext() 用于获取application隐式对象
9 pageContext对象
不仅提供了获取隐式对象的方法,还提供了存储数据的功能。
pageContext对象存储数据是通过操作属性来实现的,
表6-4列举了pageContext操作属性的一系列方法,
具体如下。表6-4
pageContext操作属性的相关方法
void setAttribute(String name,Object value,int scope)
Object getAttribute(String name,int scope)
void removeAttribute(String name,int scope)
void removeAttribute(String name)
Object findAttribute(String name)用于设置pageContext对象的属性用于获取pageContext对象的属性删除指定范围内名称为name的属性删除所有范围内名称为name的属性
其中,参数name指定的是属性名称,参数scope指定的是属性的作用范围。pageContext对象的作用范围有4个值,
具体如下。
• pageContext.PAGE_SCOPE:表示页面范围
• pageContext.REQUEST_SCOPE:表示请求范围
• pageContext.SESSION_SCOPE:表示会话范围
• pageContext.APPLICATION_SCOPE:表示Web应用程序范围
需要注意的是,当使用 findAttribute()方法查找名称为 name 的属性时,会按照page、request、session和application的顺序依次进行查找,如果找到,则返回属性的名称,否则返回null。接下来,通过一个案例来演示pageContext对象的使用。
<%
//pageContext.setAttribute(“str”, “Java”,PageContext.PAGE_SCOPE);
//pageContext.setAttribute(“str”, “Java Web”,PageContext.REQUEST_SCOPE);
HttpServletRequest req = (HttpServletRequest) pageContext.getRequest();
req.setAttribute(“str”, “Java Web”);
pageContext.setAttribute(“str”, “Java”,pageContext.PAGE_SCOPE);
String str2 = (String)pageContext.getAttribute(“str”,pageContext.PAGE_SCOPE);
String str1 = (String)pageContext.getAttribute(“str”,pageContext.REQUEST_SCOPE);
%>
<%= “request范围:” + str1 %><br />
<%= “page范围:” + str2 %><br />
10 exception对象
在 JSP 页面中,经常需要处理一些异常信息,这时,可以通过 exception 对象来实现。exception对象是java.lang.Exception类的实例对象,它用于封装JSP中抛出的异常信息。需要注意的是,exception 对象只有在错误处理页面才可以使用,即 page 指令中指定了属性<%@page isErrorPage=”true”%>的页面。
<%@ page language=”java” contentType=”text/html; charset=utf-8″
pageEncoding=”utf-8″ errorPage = “error.jsp” %>
–error.jsp
<%@ page contentType = “text/html; charset = utf-8”
language = “java” isErrorPage = “true” pageEncoding=”utf-8″%>
11 jsp处理异常
<%
try{
int a = 6;
int c = a/0 ;
}
catch(Exception exception)
{
out.println(exception.getClass());
out.println(exception.getMessage());
}
%>
12<jsp:include>标签
<jsp:include page=”included.jsp” flush=”true” />
• <jsp:include>标签中要引入的资源和当前JSP页面是两个彼此独立的执行实体,即被动态引入的资源必须能够被Web容器独立执行。而include指令只能引入遵循JSP格式的文件,被引入文件与当前JSP文件需要共同合并才能翻译成一个Servlet源文件。
• <jsp:include>标签中引入的资源是在运行时才包含的,而且只包含运行结果。而include指令引入的资源是在编译时期包含的,包含的是源代码。
• <jsp:include>标签运行原理与RequestDispatcher.include()方法类似,即被包含的页面不能改变响应状态码或者设置响应头,而include指令没有这方面的限制。
13 <jsp:forward>动作元素
<jsp:forward>动作元素将当前请求转发到其他Web资源(HTML页面、JSP页面和Servlet等),在执行请求转发之后的当前页面将不再执行,而是执行该元素指定的目标页面。其具体语法格式如下所示。
<jsp:forward page=”relativeURL” />
${pageContext.request.contextPath}会获取项目的名称chapter06并以“/”开头
13 什么是JavaBean
JavaBean是Java开发语言中一个可以重复使用的软件组件,它本质上就是一个Java类。为了规范JavaBean的开发,Sun公司发布了JavaBean的规范,它要求一个标准的JavaBean组件需要遵循一定的编码规范,具体如下。
(1)它必须具有一个公共的、无参的构造方法,这个方法可以是编译器自动产生的默认构造方法。
(2)它提供公共的setter方法和getter方法,让外部程序设置和获取JavaBean的属性。
如果一个属性只有getter方法,则该属性为只读属性。如果一个属性只有setter方法,则该属性为只写属性。如果一个属性既有getter方法,又有setter方法,则该属性为读写属性。通常来说,在开发JavaBean时,其属性都定义为读写属性。需要注意的是,对于 JavaBean 属性的命名方式有一个例外情况。如果属性的类型为boolean,它的命名方式应该使用 is/set,而不是 get/set。例如,有一个boolean 类型的属性married,该属性所对应的方法声明如下所示。
14 EL表达式
由于EL可以简化JSP页面的书写,因此,在JSP的学习中,掌握EL是相当重要的。要使用EL表达式,首先要学习它的语法。EL表达式的语法非常简单,都是以“${”符号开始,以“}”符号结束的,具体格式如下。
用户名:<%=request.getAttribute(“username”)%><br />
密 码:<%=request.getAttribute(“password”)%><br /> <hr />
使用EL表达式:<br />
用户名:${username}<br />
密 码:${password}<br />
15 EL隐式对象
pageContext对象:
请求URI为:${pageContext.request.requestURI}
<br />Content-Type响应头:${pageContext.response.contentType}
<br />服务器信息为:${pageContext.servletContext.serverInfo}
<br />Servlet注册名为:${pageContext.servletConfig.servletName}
16 Web域相关对象
使用pageScope、requestScope、sessionScope和applicationScope这4个隐式对象成功地获取到了相应JSP域对象中的属性值。需要注意的是,使用EL表达式获取某个域对象中的属性时,也可以不使用这些隐式对象来指定查找域,而是直接引用域中的属性名称即可,例如表达式${userName}就是在page、request、session、application这4个作用域内按顺序依次查找userName属性的。
<%
pageContext.setAttribute(“userName”, “itcast”);
%>
<%
request.setAttribute(“bookName”, “Java Web”);
%>
<%
session.setAttribute(“userName”, “itheima”);
%>
<%
application.setAttribute(“bookName”, “Java 基础”);
%>
表达式\${pageScope.userName}的值为:${pageScope.userName}
<br /> 表达式\${requestScope.bookName}的值为:${requestScope.bookName}
<br /> 表达式\${sessionScope.userName}的值为:${sessionScope.userName}
<br />
表达式\${applicationScope.bookName}的值为:${applicationScope.bookName}
<br /> 表达式\${userName}的值为:${userName}
17 param和paramValues对象
param 对象用于获取请求参数的某个值,它是 Map 类型,与request.getParameter()方法相同,在使用EL获取参数时,如果参数不存在,返回的是空字符串,而不是null。param对象的语法格式比较简单,具体示例如下。
${param.num}
如果一个请求参数有多个值,可以使用paramValues对象来获取请求参数的所有值,该对象用于返回请求参数所有值组成的数组。如果要获取某个请求参数的第1个值,可以使用如下代码。
${paramValues.nums[0]}
举例:
<form action=”${pageContext.request.contextPath}/param.jsp”>
num1:<input type=”text” name=”num1″><br />
num2:<input
type=”text” name=”num”><br />
num3:<input type=”text”
name=”num”><br /> <br />
<input type=”submit” value=”提交” />
<input type=”submit” value=”重置” />
<hr />
num1:${param.num1}<br />
num2:${paramValues.num[0]}<br />
num3:${paramValues.num[1]}<br />
</form>
18 .Cookie对象
在JSP开发中,经常需要获取客户端的Cookie信息,为此,在EL表达式中,提供了Cookie隐式对象,该对象是一个代表所有Cookie信息的Map集合,Map集合中元素的键为各个Cookie的名称,值则为对应的Cookie对象,具体示例如下。
获取cookie对象的信息:${cookie.userName}
获取cookie对象的名称:${cookie.userName.name}
获取cookie对象的值:${cookie.userName.value}
举例:
Cookie对象的信息:
<br />${cookie.userName }
<br />Cookie对象的名称和值:
<br />${cookie.userName.name }=${cookie.userName.value }
<%
response.addCookie(new Cookie(“userName”, “itcast”));
%>
19 什么是JSTL
从JSP 1.1规范开始,JSP就支持使用自定义标签,使用自定义标签大大降低了JSP页面的复杂度,同时增强了代码的重用性。为此,许多Web应用厂商都定制了自身应用的标签库,然而同一功能的标签由不同的Web应用厂商制定可能是不同的,这就导致市面上出现了很多功能相同的标签,令网页制作者无从选择。为了解决这个问题,Sun 公司制定了一套标准标签库(JavaServer Pages Standard Tag Library),简称JSTL。
使用JSTL标签库报错,可将 jstl.jar 和 standard.jar 这两个文件复制到 chapter07项目的 lib 目录下,复制到tomcat的lib目录下即可。
<%@ page language=”java” contentType=”text/html; charset=utf-8″
pageEncoding=”utf-8″%>
<%@ taglib uri=”http://java.sun.com/jsp/jstl/core” prefix=”c”%>
<html>
<head></head>
<body>
<c:out value=”Hello World!”></c:out>
<c:out value=”${param.username}” default=”unknown”/>
</body>
</html>
在<c:out>标签中将escapeXml的属性值设置为false,因此,<c:out>标签不会对特殊字符进行HTML转换,<meta>标签便可以发挥作用,在访问c_out2.jsp页面时就会跳转到www.itcast.cn网站。如下,escapeXml设置为了false,在没有HTML转换的情况下meta发挥了作用。
<c:out value=”${param.username }” escapeXml=”false”>
<meta http-equiv=”refresh” content=”0;url=http://www.itcast.cn” />
</c:out>
20 <c:if>标签
<c:if test=”testCondition” var=”result”[scope=”{page|request|session|application}”]>body content</c:if>
• test属性用于设置逻辑表达式。
• var属性用于指定逻辑表达式中变量的名字。
• scope属性用于指定var变量的作用范围,默认值为page。如果属性test的计算结果为true,那么标签体将被执行,否则标签体不会被执行。
举例:
<c:set value=”1″ var=”visitCount” property=”visitCount” />
<c:if test=”${visitCount==1 }”>
This is you first visit. Welcome to the site!
</c:if>
由于使用了<c:set>标签将visitCount的值设置为1,因此,表达式${visitCount==1}的结果为true,便会输出<c:if>标签体中的内容。
21 <c:choose>标签
在程序开发中不仅需要使用if条件语句,还经常会使用if-else语句。为了在JSP页面中也可以完成同样的功能,Core标签库提供了<c:choose>标签,该标签用于指定多个条件选择的组合边界,它必须与<c:when>、<c:otherwise>标签一起使用。<c:choose>标签没有属性,在它的标签体中只能嵌套一个或多个<c:when>标签和零个或一个<c:otherwise>标签,并且同一个<c:choose>标签中所有的<c:when>子标签必须出现在<c:otherwise>子标签之前,其语法格式如下。
<c:choose>
<c:when test=”${empty param.username}”> unKnown user.
</c:when>
<c:when test=”${param.username==’itcast’ }”> ${ param.username} is manager. </c:when>
<c:otherwise>
${ param.username} is employee.
</c:otherwise>
</c:choose>
22 <c:forEach>标签
在 JSP 页面中,经常需要对集合对象进行循环迭代操作,为此,Core 标签库提供了一个<c:forEach>标签,该标签专门用于迭代集合对象中的元素,如Set、List、Map、数组等
<% String[] fruits = { “apple”, “orange”, “grape”, “banana” };%>
String数组中的元素:
<br />
<c:forEach var=”name” items=”<%=fruits%>”> ${name}<br /> </c:forEach>
<% Map userMap = new HashMap();
userMap.put(“Tom”, “123”); userMap.put(“Make”, “123”); userMap.put(“Lina”, “123”);%>
<hr />
HashMap集合中的元素:
<br />
<c:forEach var=”entry” items=”<%=userMap%>”>
${entry.key} ${entry.value}<br />
</c:forEach>
<c:forEach>标签的varStatus属性用于设置一个javax.servlet.jsp.jstl.core.LoopTagStatus类型的变量,这个变量包含了从集合中取出元素的状态信息。使用<c:forEach>标签的varStatus属性可以获取以下信息。
• count:表示元素在集合中的序号,从1开始计数。
• index:表示当前元素在集合中的索引,从0开始计数。
• first:表示当前是否为集合中的第1个元素。
• last:表示当前是否为集合中的最后一个元素。
<c:forEach var=”name” items=”<%=userList%> “varStatus=”status”>
<tr><td>${status.count}</td><td>${status.index}</td><td>${status.first}</td> <td>${status.last}</td><td>${name}</td> </tr>
</c:forEach>
23 <c:param>标签用于在URL地址中附加参数,它通常嵌套在<c:url>标签内使用。<c:param>标签有两种语法格式,具体如下。
语法1:使用value属性指定参数的值<c:param name=”name” value=”value”>
语法2:在标签体中指定参数的值<c:param name=”name”>parameter value</c:param>
24 构造URL
使用绝对路径构造URL:
<br /><c:url var=”myURL” value=”http://localhost:8080/chapter07/register.jsp”><c:param name=”username” value=”张三” /><c:param name=”country” value=”中国” /></c:url> <a href=”${myURL}”>register.jsp</a><br />
使用相对路径构造URL:<br /> <c:url var=”myURL” value=”register.jsp?username=Tom&country=France” /> <a href=”${ myURL}”>register.jsp</a>
25 什么是FilterFilter
被称作过滤器,其基本功能就是对Servlet容器调用Servlet的过程进行拦截,从而在Servlet 进行响应处理前后实现一些特殊功能。
实现如下:
1定义拦截类,实现Filter接口
public class MyFilter implements Filter
//在doFilter中进行拦截
public void doFilter(ServletRequest request,ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 用于拦截用户的请求,如果和当前过滤器的拦截路径匹配,该方法会被调用 PrintWriter out=response.getWriter();
out.write(“Hello MyFilter”);
}
2 在web.xml中进行配置拦截类
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>cn.itcast.chapter08.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/MyServlet</url-pattern>
</filter-mapping>
在上述代码中,设置了过滤器对“/MyServlet”请求资源进行拦截,将在请求到达MyServlet程序前执行MyFilter程序。
26 使用通配符“*”拦截用户的所有请求
27 拦截不同方式的访问请求
在 web.xml 文件中,一个<filter-mapping>元素用于配置一个 Filter 所负责拦截的资源。<filter-mapping>元素中有一个特殊的子元素<dispatcher>,该元素用于指定过滤器所拦截的资源被Servlet容器调用的方式,<dispatcher>元素的值共有4个,具体如下。
1)REQUEST当用户直接访问页面时,Web 容器将会调用过滤器。如果目标资源是通过Request Dispatcher的include()或forward()方法访问的,那么该过滤器将不会被调用。
2)INCLUDE如果目标资源是通过RequestDispatcher的include()方法访问的,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
3)FORWARD如果目标资源是通过RequestDispatcher的forward()方法访问的,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
4)ERROR如果目标资源是通过声明式异常处理机制调用的,那么该过滤器将被调用。除此之外,过滤器不会被调用。
举例:
<filter>
<filter-name>ForwardFilter</filter-name><filter-class>cn.itcast.chapter08.filter.ForwardFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ForwardFilter</filter-name>
<url-pattern>/first.jsp</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
28 Filter链
在一个Web应用程序中可以注册多个Filter程序,每个Filter程序都可以针对某一个URL进行拦截。如果多个Filter程序都对同一个URL进行拦截,那么这些Filter就会组成一个Filter链(也叫过滤器链)。Filter链用FilterChain对象来表示,FilterChain对象中有一个doFilter()方法,该方法的作用就是让Filter链上的当前过滤器放行,使请求进入下一个Filter。
<filter-name>MyFilter01</filter-name><filter-class>cn.itcast.chapter08.filter.MyFilter01</filter-class></filter><filter-mapping><filter-name>MyFilter01</filter-name><url-pattern>/MyServlet</url-pattern></filter-mapping><filter><filter-name>MyFilter02</filter-name><filter-class>cn.itcast.chapter08.filter.MyFilter02</filter-class></filter><filter-mapping><filter-name>MyFilter02</filter-name>
<url-pattern>/MyServlet</url-pattern></filter-mapping><servlet><servlet-name>MyServlet</servlet-name><servlet-class>cn.itcast.chapter08.filter.MyServlet</servlet-class></servlet><servlet-mapping><servlet-name>MyServlet</servlet-name><url-pattern>/MyServlet</url-pattern></servlet-mapping>
MyServlet首先被MyFilter01拦截了,打印出MyFilter01中的内容,然后被MyFilter02拦截,直到MyServlet被MyFilter02放行后,浏览器才显示出MyServlet中的输出内容。
29 java解码
分析:当调用request.getParameter()函数时,会自动进行一次URI的解码过程,
调用时内置的解码过程会导致乱码出现。
而URI 编码两次后,request.getParameter()函数得到的是原信息URI编码一次的内容。
再用可控的解码函数 java.net.URLDecoder.decode()就可解出原始的正确的信息。
30 java编码
java.net.URLEncoder.encode(strBuf,”UTF-8″); .
31 Listener监听器
上述监听器根据监听事件的不同可以将其分为3类,具体如下。
(1)用于监听域对象创建和销毁的事件监听器(ServletContextListener接口、HttpSession Listener接口、ServletRequestListener接口)。
(2)用于监听域对象属性增加和删除的事件监听器(ServletContextAttributeListener接口、HttpSessionAttributeListener接口、ServletRequestAttributeListener接口)。
(3)用于监听绑定到 HttpSession 域中某个对象状态的事件监听器(HttpSessionBinding Listener接口、HttpSessionActivationListener接口)。
在Servlet规范中,这3类事件监听器都定义了相应的接口,在编写事件监听器程序时只需实现对应的接口就可以。Web 服务器会根据监听器所实现的接口,把它注册到被监听的对象上,当触发了某个对象的监听事件时,Web容器将会调用Servlet监听器与之相关的方法对事件进行处理。
设置监听超时信息为了尽快地查看到HttpSession对象销毁的过程,可以在chapter08应用的web.xml文件中设置session的超时时间为2min,具体代码如下。
<session-config><session-timeout>2</session-timeout></session-config>
监听域对象的属性变更
1)jsp中设置属性
<%getServletContext().setAttribute(“username”, “itcast”);
getServletContext().setAttribute(“username”, “itheima”);
getServletContext().removeAttribute(“username”);
session.setAttribute(“username”, “itcast”);
session.setAttribute(“username”, “itheima”);
session.removeAttribute(“username”);
request.setAttribute(“username”, “itcast”);
request.setAttribute(“username”, “itheima”);
request.removeAttribute(“username”);%>
2)编写一个名称为MyAttributeListener的监听器类,该类实现了ServletContextAttributeListener、HttpSessionAttributeListener 和ServletRequestAttributeListener接口,并实现这些接口中的所有方法
3)web.xml中添加
<listener><listener-class>listener.MyAttributeListener</listener-class></listener>
32 数据库连接池
为了避免频繁地创建数据库连接,数据库连接池技术应运而生。数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用现有的数据库连接,而不是重新建立。
数据源中包含数据库连接池。如果数据是水,数据库就是水库,数据源就是连接到水库的管道,终端用户看到的数据集是管道里流出来的水。一些开源组织提供了数据源的独立实现,常用的有DBCP数据源和C3P0数据源。
DBCP数据源
DBCP是数据库连接池(DataBase Connection Pool)的简称,是Apache组织下的开源连接池实现,也是Tomcat服务器使用的连接池组件。单独使用DBCP数据源时,需要在应用程序中导入两个JAR包,具体如下。1.commons-dbcp.jar包commons-dbcp.jar 包是 DBCP 数据源的实现包,包含所有操作数据库连接信息和数据库连接池初始化信息的方法,并实现了DataSource接口的getConnection()方法。2.commons-pool.jar包commons-pool.jar包是DBCP数据库连接池实现包的依赖包,为commons-dbcp.jar包中的方法提供了支持。可以这么说,没有该依赖包,commons-dbcp.jar包中的很多方法就没有办法实现。
C3P0数据源
当使用 C3P0数据源时,首先需要创建数据源对象,创建数据源对象可以使用ComboPooledDataSource 类,该类有两个构造方法,分别是ComboPooledDataSource()和 ComboPooledDataSource(String configName)。
1.通过ComboPooledDataSource()构造方法创建数据源对象
导入JAR包c3p0-0.9.1.2.jar
public class Example03 {
public static DataSource ds = null;
//初始化C3P0数据源
static {
ComboPooledDataSource cpds = new ComboPooledDataSource();
// 设置连接数据库需要的配置信息
try {
cpds.setDriverClass(“com.mysql.jdbc.Driver”);
cpds.setJdbcUrl(“jdbc:mysql://localhost:3306/world”);
cpds.setUser(“root2”);
cpds.setPassword(“caicai123”);
// 设置连接池的参数
cpds.setInitialPoolSize(5);
cpds.setMaxPoolSize(15);
ds = cpds;
}
catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
public static void main(String[] args) throws SQLException {
// 获取数据库连接对象
System.out.println(ds.getConnection());
}
}
2 通过读取配置文件创建数据源对象
使用ComboPooledDataSource(String configName)构造方法读取c3p0-config.xml 配置文件,从而创建数据源对象,然后获取数据库连接对象。
(1)在src根目录下创建一个c3p0-config.xml文件,用于设置数据库的连接信息和数据源的初始化信息
<?xml version=”1.0″ encoding=”UTF-8″?>
<c3p0-config>
<default-config>
<property name=”driverClass”>com.mysql.jdbc.Driver</property>
<property name=”jdbcUrl”>jdbc:mysql://localhost:3306/world</property>
<property name=”user”>root</property>
<property name=”password”>caicai123</property>
<property name=”checkoutTimeout”>30000</property>
<property name=”initialPoolSize”>10</property>
<property name=”maxIdleTime”>30</property>
<property name=”maxPoolSize”>100</property>
<property name=”minPoolSize”>10</property>
<property name=”maxStatements”>200</property>
</default-config>
<named-config name=”itcast”>
<property name=”driverClass”>com.mysql.jdbc.Driver</property>
<property name=”jdbcUrl”>jdbc:mysql://localhost:3306/world</property>
<property name=”user”>root</property>
<property name=”password”>caicai123</property>
<property name=”initialPoolSize”>5</property>
<property name=”maxPoolSize”>15</property>
</named-config>
</c3p0-config>
(2)在使用ComboPooledDataSource(String configName)方法创建对象时必须遵循以下两点。1)配置文件名称必须为c3p0-config.xml或者c3p0.properties,并且位于该项目的src根目录下。2)当传入的configName值为空或者不存在时,则使用默认的配置方式创建数据源。
public class Example04 {
public static DataSource ds = null;
// 初始化C3P0数据源8
static {
// 使用c3p0-config.xml配置文件中的named-config节点中name属性的值
ComboPooledDataSource cpds = new ComboPooledDataSource(“itcast”);
ds = cpds;
}
public static void main(String[] args) throws SQLException {
System.out.println(ds.getConnection());
}
}
33 DBUtils工具介绍
为了更加简单地使用JDBC,Apache组织提供了一个DBUtils工具,它是操作数据库的一个组件,实现了对JDBC的简单封装,可以在不影响性能的情况下极大地简化JDBC的编码工作量.
DBUtils工具的核心是org.apache.commons.dbutils.QueryRunner类和org.apache.commons. dbutils.ResultSetHandler接口.
QueryRunner类QueryRunner类简化了执行SQL语句的代码,它与ResultSetHandler组合在一起就能完成大部分的数据库操作,大大地减少了编码量。QueryRunner类提供了带有一个参数的构造方法,该方法以javax.sql.DataSource作为参数传递到 QueryRunner 的构造方法中来获取 Connection 对象。针对不同的数据库操作, QueryRunner类提供了几种常见的方法,具体如下。
• query(String sql, ResultSetHandler rsh, Object… params)方法该方法用于执行查询操作,它可以从提供给构造方法的数据源 DataSource 或使用的setDataSource()方法中获得连接。
• update(String sql, Object… params)方法该方法用于执行插入、更新或者删除操作,其中,参数params表示SQL语句中的置换参数。
• update(String sql)方法该方法用来执行插入、更新或者删除操作,它不需要置换参数。
ResultSetHandler接口ResultSetHandler接口用于处理ResultSet结果集,它可以将结果集中的数据转为不同的形式。根据结果集中数据类型的不同,ResultSetHandler提供了几种常见的实现类,具体如下。
• BeanHandler:将结果集中的第1行数据封装到一个对应的JavaBean实例中。
• BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,并存放到List里。
• ScalarHandler:将结果集中某一条记录的其中某一列的数据存储成Object对象。另外,在ResultSetHandler接口中,提供了一个单独的方法handle (java.sql.ResultSet rs),如果上述实现类没有提供想要的功能,可以通过自定义一个实现 ResultSetHandler 接口的类,然后通过重写handle()方法,实现结果集的处理。
34 mysql Jar 包下载
https://dev.mysql.com/downloads/connector/j/
35 DBUtils Cannot create chapter10.User: class org.apache.commons.dbutils.BeanProcessor (in module commons.dbutils)
发生这种情况是因为Apache Commons DBUtils的未命名模块无法访问您的类。
发生这种情况是因为您正在使用 Java平台模块系统。
要解决此问题,您需要导出软件包,以便Apache模块可以看到它们。
module chapter10 {
requires java.sql;
requires c3p0;
requires java.desktop;
requires commons.dbutils;
exports chapter10;
}
36 DBUtils举例如下,定义两个类去访问beanhandler,beanlisthandler
1.定义BaseDao类查询数据库
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.commons.dbutils.ResultSetHandler;
public class BaseDao {
//优化查询
public static Object query(String sql,ResultSetHandler<?> rsh,Object… params) throws SQLException
{
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
//获得链接
conn = JDBCUtils.getConnection();
//预编译sql
pstmt = conn.prepareStatement(sql);
//将参数设置进去
for(int i=0;params != null && i < params.length;i++)
{
pstmt.setObject(i+1, params[i]);
}
//发送sql
rs = pstmt.executeQuery();
//让调用者实现对结果集的处理
Object obj = rsh.handle(rs);
return obj;
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
//释放资源
JDBCUtils.release(pstmt, conn);
}
return rs;
}
}
2.封装User类
package chapter10;
public class User {
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
private int id;
private String name;
private String password;
}
3. Bean Handler类对结果集的处理
BaseDao basedao = new BaseDao();
String sql = “select * from user where id=?”;
User user = (User)basedao.query(sql, new BeanHandler(User.class), 1);
BeanListHandler类对结果集的处理
BaseDao basedao = new BaseDao();
String sql = “select * from user”;
ArrayList<User> list = (ArrayList<User>)basedao.query(sql, new BeanListHandler(User.class));
在使用DBUtils工具操作数据库时,如果需要输出结果集中一行数据的指定字段值,可以使用ScalarHandler类
BaseDao basedao = new BaseDao();
String sql = “select * from user where id=?”;
Object arr = (Object) basedao.query(sql, new ScalarHandler(“name”), 1);
37 使用DBUtils实现增删改查
//查询所有
创建QueryRunner对象
QueryRunner runner = new QueryRunner(C3p0Utils.getDataSource());
// 写SQL语句
String sql = “select * from user”;
// 调用方法
List list = (List) runner.query(sql,new BeanListHandler(User.class));
//查询单个对象
// 写SQL语句
String sql = “select * from user where id=?”;
// 调用方法
User user = (User) runner.query(sql,new BeanHandler(User.class), new Object[] { id });
添加用户的操作
// 写SQL语句37
String sql = “insert into user (name,password) values (?,?)”;
// 调用方法
int num = runner.update(sql,new Object[] { user.getName(), user.getPassword() });
//更改用户
// 写SQL语句
String sql = “update user set name=?,password=? where id=?”;
// 调用方法
int num = runner.update(sql, new Object[] { user.getName(),user.getPassword(),user.getId() });
// 删除用户
String sql = “delete from user where id=?”;
// 调用方法65
int num = runner.update(sql, id);
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/54724.html