jsp开发模型
Sun(Oracle)为了指导开发,提出了2种开发模型
jspModel1
Jsp页面与JavaBeans共同协作完成任务
Model 1模式的实现比较简单,适用于快速开发小规模项目。但从工程化的角度看,它的局限性非常明显:JSP页面身兼View和Controller两种角色,将控制逻辑和表现逻辑混杂在一起,从而导致代码的重用性非常低,增加了应用的扩展性和维护的难度。
早期有大量ASP和JSP技术开发出来的Web应用,这些Web应用都采用了Model 1架构。
输入页面login1.jsp
<form action="login_do.jsp" method="post">
<input name="username" value="<%=request.getParameter("username")!=null?request.getParameter("username"):""%>"/>
<input type="submit" value="登录系统"/>
</form>
接收数据的页面login_do.jsp,其中负责接收数据并进行数据校验,然后调用javaBean完成业务逻辑处理,最后根据处理结果跳转对应的页面
<%@ page import="com.yan.dao.IUserDao" %>
<%@ page import="com.yan.util.DaoFactory" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:useBean id="user" class="com.yan.entity.UserBean">
<jsp:setProperty name="user" property="*"/>
</jsp:useBean>
<%!
private IUserDao userDao= DaoFactory.getUserDao();
%>
<%
boolean bb=userDao.login(user);
System.out.println(user.getUsername());
if(bb){
session.setAttribute("user",user);
response.sendRedirect("login_succ.jsp");
}else{
request.setAttribute("msg","登录失败!请重新登录");
request.getRequestDispatcher("login1.jsp").forward(request,response);
}
%>
javaBean负责处理实际的业务逻辑,采用的是DAO模式:1个接口,若干实现,1个值bean,1个工厂
public class UserDaoImpl implements IUserDao{
@Override
public boolean login(UserBean user) throws Exception {
return true;
}
}
最后再定义对应的显示页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
欢迎您,
<%
Object obj=session.getAttribute("user");
if(obj!=null && obj instanceof UserBean){
UserBean ub=(UserBean)obj;
out.println(ub.getUsername());
}
%>
</body>
</html>
jspModel2
Jsp Model2中使用了三种技术JSP、Servlet和JavaBeans
- Jsp负责生成动态网页,只用显示业务数据和收集客户动作
- Servlet负责流程控制,用来处理各种请求的分派
- JavaBeans负责业务逻辑和业务数据,对数据库的操作
Jsp Model2优点
消除了Jsp Model1的缺点:
- 该模式适合多人合作开发大中型的Web项目
- 各司其职,互不干涉
- 有利于开发中的分工
- 有利于组件的重用
Jsp Model2缺点
Web项目的开发难度加大,同时对开发人员的技术要求也提高了
各个部分的开发难度降低,总体难度加大
lombok
Lombok 是一种 Java 实用工具,可用来帮助开发人员消除 Java 的冗长,尤其是对于简单的 Java 对象(POJO)。它通过注释实现这一目的。通过在开发环境中实现 Lombok,开发人员可以节省构建诸如 hashCode() 和 equals() 这样的方法以及以往用来分类各种 accessor 和 mutator 的大量时间。
依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
开发工具中需要安装插件
java -jar lombok.jar
定义POJO
@Data
public class CatalogBean implements Serializable {
private Long id;
private String title;
}
在编译时会自动添加所有属性的get/set方法,以及构造器和hashcode/equals方法
@ToString:作用于类,覆盖默认的toString()方法,可以通过of属性限定显示某些字段,通过exclude属性排除某些字段。
@Getter/@Setter: 作用类上,生成所有成员变量的getter/setter方法;作用于成员变量上,生成该成员变量的getter/setter方法。可以设定访问权限及是否懒加载等。
@EqualsAndHashCode:作用于类,覆盖默认的equals和hashCode
@NonNull:主要作用于成员变量和参数中,标识不能为空,否则抛出空指针异常。
@NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor:作用于类上,用于生成构造函数。有staticName、access等属性。
@NoArgsConstructor:生成无参构造器;
@RequiredArgsConstructor:生成包含final和@NonNull注解的成员变量的构造器;
@AllArgsConstructor:生成全参构造器
@Data:作用于类上,是以下注解的集合:@ToString @EqualsAndHashCode @Getter @Setter @RequiredArgsConstructor
@Builder:作用于类上,将类转变为建造者模式
@Log:作用于类上,生成日志变量。针对不同的日志实现产品,有不同的注解:
@Synchronized:作用于方法级别,可以替换synchronize关键字或lock锁
@SneakyThrows:可以对受检异常进行捕捉并抛出
@Cleanup:自动关闭资源,针对实现了java.io.Closeable接口的对象有效
#页面种的EL
配置了上下文参数
<context-param>
<param-name>project</param-name>
<param-value>闫氏书店</param-value>
</context-param>
页面显示
<title><%=application.getInitParameter("project")!=null?application.getInitParameter("project"):""%> - 欢迎页</title>
如何避免jsp页面中读取4大范围中数据的麻烦
- 传递数据使用的4大范围
- page
- request
- session
- application
jsp提供了EL表达式语言解决
表达式语言
JSTL定制标记支持另一种用于指定动态属性值的机制。可以用简化的表达式语言EL而不使用完整的 JSP 表达式来指定 JSTL 操作的属性值
EL提供了一些标识符、存取器和运算符,用来检索和操作驻留在 JSP 容器中的数据
- EL擅长寻找对象及其特性,然后对它们执行简单操作;它不是编程语言,甚至不是脚本编制语言
- EL与JSTL标记一起使用时,它就能使用简单而又方便的符号来表示复杂的行为
- EL表达式的格式是这样的:用美元符号$定界,内容包括在花括号{ }
- 不允许在EL表达式中直接调用方法,例如${abc.trim()}
JSP2开始将Expression Language整合进JSP标准规格
- EL并非全新的语言,最早出现于JSTL 1.0当中,被用来简化数据存取的相关操作
- 由于EL已是JSP的标准,因此用户可以选择直接在JSP网页当中使用EL替代Java进行数据的存取操作
例如:
<title>${initParam.project} - 欢迎页</title>
EL脚本语言的配置
对于一个单个JSP页面,可以使用定义page指令来设置jsp页面是否支持EL
默认是支持EL,如果要页面不支持EL,设置为isELIgnored=true;
<%@ page isELIgnored="true|false"%>
###运算符
运算符 | 说 明 |
---|---|
. | 存取bean property 或是map entry |
[] | 存取 array or List 元素 |
() | 改变运算顺序 |
? : | 条件式三元运算 condition ? ifTrue : ifFalse |
+ - * /或div %或mod | 加、减、乘、除、模数学运算 |
无论action elements 或是隐含对象的数据内容,均是一种集合collection对象,EL可以通过点运算符.或是方括号[]对其作存取
${ param.yearValue}
${ param["yearValue"] }
<h1><jsp:useBean id="now" class="java.util.Date" scope="session"/>
<%
request.setAttribute("now",new Random());
%>
${now} 自动从小到大在4大范围中查找key=now的对象,类似于pageContext.findAttribute("now")。如果找不到返回为"",不是null
样例2:可以通过.或者[]两种不同方式访问对象的属性,如果查找不到对象,不会出现空指针异常,反而有默认值
<jsp:useBean id="now" class="java.util.Date" scope="session"/>
${now.year+1900}--${now['month']+1} 形式上看似乎是直接访问属性,但是访问属性实际上是调用对应的getXXX方法
${now2.year+1900}--${now2['month']+1}
运算符 | 说明 |
---|---|
==或eq !=或ne | 对等运算与不相等运算 |
< 或lt > 或gt | 小于比较运算与大于比较运算 |
<= 或le >= 或ge | 小于或等于比较运算与大于或等于比较运算 |
&& 或and || 或or ! 或not | 逻辑AND运算、逻辑OR运算、逻辑非运算 |
empty | 判空运算 |
<%
request.setAttribute("now3","");
%>
<%
//非空字符串判断
out.println(pageContext.findAttribute("now3")!=null && pageContext.findAttribute("now3").toString().trim().length()>0);
%>
${empty now3}-- ${not empty now3} empty针对一般对象判断null,如果是集合判断null或者空集合,针对字符串判断null或者空串,注意判空串时不会自动调用trim()方法
11个内建对象
内建对象 | 说明 |
---|---|
pageContext | 取得网页运行环境的相关信息 |
pageScope | 取得page范围内特定属性的属性值 |
requestScope | 取得request范围内特定属性的属性值 |
sessionScope | 取得session范围内特定属性的属性值 |
applicationScope | 取得application范围内特定属性的属性值 |
param | 取得request对象的单一参数值 |
paramValues | 取得request对象的参数值 |
header | 取得request对象单一标头值 |
headerValues | 取得request对象标头值 |
cookie | 取得request对象的cookie |
initParam | 取得网页运行环境的初始参数值 |
- 4大范围xxxScope,例如pageScope、requestScope、sessionScope和applicationScope,用于操作其中的attribute数据
- 请求参数 param和paramValues
- 请求头参数 header和headerValues
- 特殊的参数 cookie initParam pageContext
EL对象与request对象存取
EL对象 | Request对象存取 |
---|---|
param | ServletRequest.getParameter(String name) |
paramValues | ServletRequest.getParameterValues(String name) |
header | HttpServletRequest.getHeader(String name) |
headerValues | HttpervletRequest.getHeaders(String) |
cookie | HttpServletRequest.getCookies() |
<%=request.getParameter("name")%> -- ${param.name}<br/>
<%=request.getParameterValues("hobby")%> -- ${paramValues.hobby}<br/>
<%
Cookie[] cks=request.getCookies();
for(Cookie ck:cks){
out.println(ck.getName()+":::"+ck.getValue()+":::"+ck.getDomain()+":::"+ck.getMaxAge());
}
%> -- ${cookie.JSESSIONID.value}
范围变量
EL中4个与范围有关的隐含对象,pageScope、requestScope、sessionScope和applicationScope,可直接用来存取属于特定范围内的变量值,它们与JSP内建所的隐含对象基本上是相同的
- pageScope对应pageContext、 requestScope对应request、sessionScope对应session、applicationScope对应application
- 在JSP网页当中取得特定范围变量属性,必须引用getAttribute(),并且指定所要取得的变量名称
application.getAttribute("cname")
- 通过EL的存取方式
${applicationScope.cname}
param & paramValues
EL对象param与paramValues被设计用来提供使用request之外的一个选择
EL | request |
---|---|
${param.paraName} | request.getParameter(paraName) |
${paramValues.name} | request.getParameterValues(name) |
param内容包含当前网页所有的request参数,这段程序代码取得其中名称为yearValue的参数值${param.yearValue}
针对取得的参数内容,进一步对其作运算${param.yearValue+100}
param与paramValues最大的好处便是简化了request参数数据的存取
cookie
提供直接读取cookie所需的语法${cookie.cname.value}
如果想要了解此cookie的识别名称,省略value即可${cookie.cname}
initParam
网站一开始启动的时候,通常需要设定某些与网站有关的参数 ,这些参数在网站根目录底下WEB-INF数据夹的web.xml文件里面作设定
<web-app>
<context-param>
<param-name>admin</param-name>
<param-value>tea</param-value>
</context-param>
</web-app>
引用initParam读取系统参数非常的容易,指定所要取得的参数名称即可。${initParam.admin}
小结
EL表达式语言Expression Language是JSTL的两个组成部分之一
- JSP 标准标签库专家组和 JSP 2.0 专家组共同开发了 JSP EL
- JSP 表达式语言用于访问存储于JavaBean中的数据
- JSP 表达式语言可以用于任何静态文本和标准标签或自定义标签
开发书店
欢迎首页
<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>${initParam.project} - 欢迎页</title>
</head>
<body>
<jsp:forward page="books.do"/>
</body>
</html>
web.xml
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
定义商品显示
Servlet负责调用javaBean完成数据加载,然后将数据存放在4大范围中,最后跳转页面进行显示
public class BookServlet extends BaseServlet {
private IBookDao bookDao= DaoFactory.getBookDao();
@Override
public void show(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<BookBean> bookList=bookDao.selectByExample();
request.setAttribute("bookList",bookList); //由于Servlet不负责数据显示,所以将数据存放在4大范围中,传递到jsp页面显示
request.getRequestDispatcher("books/list.jsp").forward(request,response);
}
}
修改BookDaoImpl提供对应的实现操作
public class BookDaoImpl implements IBookDao{
private JdbcUtil ju=JdbcUtil.getInstance();
@Override
public List<BookBean> selectByExample()throws Exception {
List<BookBean> res=new ArrayList<>();
Connection conn=null;
ResultSet rs=null;
try{
conn=ju.getConnection();
String sql="select b.*,c.title ctitle from t_books b inner join t_catalog c on b.catalog_id=c.id where 1=1";
rs=ju.executeQuery(conn,sql);
while(rs.next()){
BookBean bb=new BookBean();
bb.setId(rs.getLong("id"));
bb.setTitle(rs.getString("title"));
bb.setUnit(rs.getString("unit"));
bb.setPrice(rs.getDouble("price"));
bb.getCatalog().setId(rs.getLong("catalog_id"));
bb.getCatalog().setTitle(rs.getString("ctitle"));
res.add(bb);
}
}finally{
ju.close(rs,null,conn);
}
return res;
}
}
jsp页面负责从request中获取Servlet传递的数据,同时进行遍历显示
<%@ page import="java.util.List" %>
<%@ page import="com.yan.entity.BookBean" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>${initParam.project} - 产品展示</title>
<link rel="stylesheet" type="text/css" href="css/css1.css">
<link rel="stylesheet" type="text/css" href="css/pub.css">
<base href="http://${pageContext.request.serverName}:${pageContext.request.serverPort}/${pageContext.request.contextPath}/">
</head>
<body>
<div id="container">
<!-- 页头 -->
<%@include file="../commons/head.jsp"%>
<!-- 主体 -->
<div id="pagebody">
<!-- 左侧 -->
<%@ include file="../commons/left.jsp"%>
<!-- 右侧 -->
<div id="mainbody">
商品类别:所有
<TABLE cellSpacing=1 cellPadding=1 width="100%" border=1 bordercolor="black">
<TBODY>
<TR bgColor=#e1e1e1>
<TD class=txt align=middle width="8%" height=25><FONT
color=#000000>商品ID</FONT></TD>
<TD class=txt align=middle width="20%" height=25><FONT
color=#000000>商品名称</FONT></TD>
<TD class=txt align=middle width="14%" height=25><FONT
color=#000000>商品类别</FONT></TD>
<TD class=txt align=middle width="13%" height=25><FONT
color=#000000>单位数量</FONT></TD>
<TD class=txt align=middle width="15%" height=25><FONT
color=#000000>单价</FONT></TD>
<TD class=txt align=middle width="10%" height=25><FONT
color=#000000>购买</FONT></TD>
</TR>
<%
Object obj=request.getAttribute("bookList");
if(obj!=null && obj instanceof List &&((List)obj).size()>0){
List<BookBean> blist=(List<BookBean>)obj;
for(BookBean temp:blist){
%>
<TR bgColor=#ffffff>
<TD class=txt align=middle width="8%"><%=temp.getId()%></TD>
<TD class=txt align=middle width="20%"><%=temp.getTitle()%></TD>
<TD class=txt align=middle width="20%"><%=temp.getCatalog().getTitle()%></TD>
<TD class=txt align=middle width="14%"><%=temp.getUnit()%></TD>
<TD class=txt align=middle><%=temp.getPrice()%></TD>
<TD
οnmοuseοver="this.style.cursor='hand';this.style.backgroundColor='#eeeeee';"
οnclick=""
οnmοuseοut="this.style.backgroundColor='#ffffff';"
noWrap align=middle><image src="images/cart.gif" style="border:0px"></TD>
</TR>
<%} %>
<tr><td colspan=3 align=center>1 2 3 4 5 6 7 8</td>
<td colspan=3 align=center>每页:15个 页码:1/8页 共有:87个</td></tr>
<%}else{%>
<tr><td colspan="6">没有任何图书信息</td></tr>
<%}%>
</table>
</div>
</div>
<!-- 页脚 -->
<%@ include file="../commons/foot.jsp"%>
</div>
</body>
</html>
问题
jsp页面到底谁负责实现
html归前端 ,但是由于jsp页面中包含java的代码,由前端负责是不合理的
解决方案:引入自定义标签库,页面前端负责。工程化管理的需要
- 将Java代码封装在一个标签中,当在页面种使用标签时,实际上就是调用java代码段
自定义标签
定义一个类直接或者间接的实现标签接口,例如Tag
public class MyTag implements Tag {
private PageContext pageContext;
@Override
public void setPageContext(PageContext pc) {
this.pageContext=pc;
}
@Override
public void setParent(Tag t) {
}
@Override
public Tag getParent() {
return null;
}
/*
<font color=red>abcd</font>
标签起始 属性 标签体 标签结尾
*/
@Override
public int doStartTag() throws JspException {
//标签头的回调方法
//获取请求参数中name对应的值,如果没有name则默认 tag
ServletRequest sr=pageContext.getRequest();
String name=sr.getParameter("name");
if(name==null || name.trim().length()<1)
name="Tag";
//输出问候信息
JspWriter out=pageContext.getOut();
try {
out.write("<h1>Hello "+name+"!</h1>");
} catch (IOException e) {
throw new JspException(e);
}
//Tag.EVAL_BODY_INCLUDE 表示处理标签体;
//Tag.SKIP_BODY 跳过标签体
return Tag.SKIP_BODY;
}
@Override
public int doEndTag() throws JspException {
//遇到标签尾的回调方法
// Tag.EVAL_PAGE 继续处理后续标签
// Tag.SKIP_PAGE 不处理后续标签
return Tag.EVAL_PAGE;
}
@Override
public void release() {
//销毁标签对象时 释放资源
}
}
在/WEB-INF/下创建一个文件xxx.tld
- tld后缀的意思是标签库描述文件,用于配置标签库中的每个标签
<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
version="2.1">
<!--定义标签库的版本号-->
<tlib-version>5.0</tlib-version>
<!--标签的短名称,即标签的前缀-->
<short-name>yan</short-name>
<!--设置标签库的URI地址-->
<uri>/WEB-INF/yan.tld</uri>
<tag>
<!--标签名称,根据配置调用方法为yan:hello-->
<name>hello</name>
<!--标签处理类的全名称-->
<tag-class>com.yan.tags.MyTag</tag-class>
<!--允许的标签体内容类型-->
<body-content>empty</body-content>
<!--标签属性声明-->
<attribute>
<!-- 属性名称 -->
<name>var</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
</taglib>
页面中如何调用
<!-- 第一步引入标签库,prefix标签前缀对应tld文件中的short-name,uri为tld文件中的uri配置-->
<%@ taglib prefix="yan" uri="/WEB-INF/yan.tld" %>
<!--直接按照前缀名+标签名的方式使用标签-->
<yan:hello/>
随着时间的推荐,标签库越来越多,缺少标准,使用比较混乱
解决方案:标准标签库JSTL
JSTL
JSP标准标签库JSTL是一个JSP标签集合,它封装了JSP应用的通用核心功能。
JSTL支持通用的、结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签,SQL标签。 除了这些,它还提供了一个框架来使用集成JSTL的自定义标签。
JSP标准标记库JSTL是 JSP定制标记库集,这些标记库实现大量服务器端 Java 应用程序常用的基本功能
-
通过为典型表示层任务(如数据格式化和迭代或条件内容)提供标准实现,JSTL 使 JSP 作者可以专注于特定于应用程序的开发需求,而不是为这些通用操作另起炉灶
-
根据JSTL标签所提供的功能,可以将其分为5个类别:核心标签、格式化标签、SQL标签、XML标签和JSTL函数
##JSTL标签库
JSTL 标签种类 | 说 明 |
---|---|
核心标签 | 包含JSTL核心操作所需的标签,例如数据输出、循环流程控制以及URL操作等 |
i18n国际化标签 | 进行数值与日期数据格式化、国际化资源网页设定所需的标签 |
SQL标签 | 运用SQL与操作资库所需的标签 |
XML标签 | 剖析XML文件所需的标签 |
函数标签 | 包含字符串处理与其它特定功能之JSTL标签 |
标签种类 | 前缀词 | uri |
---|---|---|
核心标签 | c | http://java.sun.com/jsp/jstl/core |
i18n国际化标签 | fmt | http://java.sun.com/jsp/jstl/fmt |
SQL标签 | sql | http://java.sun.com/jsp/jstl/sql |
XML标签 | xml | http://java.sun.com/jsp/jstl/xml |
函数标签 | fn | http://java.sun.com/jsp/jstl/functions |
依赖配置pom.xml
<!--如果使用tomcat10 -->
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jakarta.servlet.jsp.jstl</artifactId>
<version>2.0.0</version>
</dependency>
<!--如果使用Tomcat9或者更低版本使用-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
###核心标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:if test="${not empty requestScope.bookList}">
<c:forEach items="${bookList}" var="book">
<TR bgColor=#ffffff>
<TD class=txt align=middle width="8%">${book.id}</TD>
<TD class=txt align=middle width="20%">${book.title}</TD>
<TD class=txt align=middle width="20%">${book.catalog.title}</TD>
<TD class=txt align=middle width="14%">${book.unit}</TD>
<TD class=txt align=middle>${book.price}</TD>
<TD οnmοuseοver="this.style.cursor='hand';this.style.backgroundColor='#eeeeee';"
οnclick=""
οnmοuseοut="this.style.backgroundColor='#ffffff';"
noWrap align=middle><image src="images/cart.gif" style="border:0px"></TD>
</TR>
</c:forEach>
<tr><td colspan=3 align=center>1 2 3 4 5 6 7 8</td>
<td colspan=3 align=center>每页:15个 页码:1/8页 共有:87个</td></tr>
</c:if>
c:if用于条件判断
无本体内容
<c:if test="条件表达式" var="存储变量名" [scope="存储范围{page |request |session |application }"]/>
包含本体内容
<c:if test="条件表达式" [var="存储变量名"] [scope="存储范围{page |request |session |application}"]> 标签体</c:if>
如果条件成立则执行标签体,否则不执行标签体
属性 | 动态 | 类型 | 说明 |
---|---|---|---|
test | 是 | boolean | 条件表达式 |
var | 否 | String | 输出判断结果的范围变量名称 |
scope | 否 | String | var的范围 |
- test 是最重要的属性,为标签的条件判断式
- var用来储存判断式的输出結果
<c:if test="${not empty requestScope.bookList}">
...
</c:if>
等价于
Object obj=request.getAttribute("bookList");
if(obj!=null && ((List)obj).size()>0){
......
}
c:forEach循环标签
迭代对象集合内容
<c:forEach [var="循环控制变量名"] items="需要循环迭代的集合" [varStatus="循环状态变量"] [begin="起始值"] [end="终止值"] [step="循环步长值"]>
标签体
</c:forEach>
- var用来指定网页当中所要迭代的对象
- items则是每一次迭代所取得的对象内容
- varStatus为目前对象的相关内容信息
- begin、end以及step则是相关的属性,分别代表迭代的开始、结束以及区间,这三个值相互影响,设定不正确可能导致程序流程的运行错误
迭代特定次数
<c:forEach [var="varName"] [varStatus="varStatusName"] begin="begin" end="end" [step="step"]>
body content
</c:forEach>
九九乘法口诀表
<table width="80%">
<c:forEach var="k" begin="1" end="9">
<tr>
<c:forEach var="i" begin="1" end="${k}">
<td>${i}*${k}=${k*i}</td>
</c:forEach>
</tr>
</c:forEach>
</table>
属性 | 动态 | 类型 | 说明 |
---|---|---|---|
var | 否 | String | 储存指定的迭代成员 |
items | 是 | 集合对象 | 迭代的集合对象 |
varStatus | 否 | String | 储存指定迭代成员的状态内容 |
begin | 是 | int | 迭代的开始值 |
end | 是 | int | 迭代的结束值 |
step | 是 | int | 每次迭代的间隔值 |
<%
String atts[] = new String [5]; atts[0]="hello"; atts[1]="this"; atts[2]="is"; atts[3]="a"; atts[4]="pen"; request.setAttribute("atts", atts);
%>
<c:forEach items="${atts}" var="item" begin="1" end="4" step="2" >
${item}</br>
</c:forEach>
结果是只显示atts[1]和atts[3]的内容
<%
Map map=new HashMap();
map.put("111","aaa");
map.put("222","bbb");
map.put("333","ccc");
pageContext.setAttribute("map",map);
%>
<c:forEach items="${map}" var="ff">
<c:out value="${ff.key}"/>:<c:out value="${ff.value}" /><br>
</c:forEach>
用c:forEach 中varStatus的属性可以获得迭代的自身状态
<c:forEach var="" items="" varStatus="status">
<c:out value=“${status.index}”/> 此次迭代的索引
<c:out value=“${status.count}”/> 已经迭代的数量
<c:out value=“${status.first}”/> 是否是第一个迭代对象
<c:out value=“${status.last}”/> 是否是最后一个迭代对象
</c:forEach>
<c:forEach var="item" items="${contents}" varStatus="status">
<tr
<c:if test="${status.count%2==0}"> bgcolor="#CCCCFE" </c:if>
align="left">
${item.username}
</tr>
</c:forEach>
建立URL
<c:url>
标签在JSP网页动态指定一个网址字符串
<c:url value="value" [context="context"] [var="varName"] [scope="{ page | request | session | application }"]>
<c:param> subtags <c:param>
</c:url>
- value代表所要设定的网页资源位置
- context用来指定一个外部资源
- var代表一个变量,如果有指定,URL资源的内容将被输出至指定的变量
- scope则是变量的范围,var变量只在这个范围里面有效
c:param
将属性值指定给value属性
<c:param name="name" value="value"/>
应用场景
<a href="<c:url value='/login.jsp' />">现在就登录</a>
<c:param>
标签放在<c:url>
本体內容当中,可用来设定连接所要传递的参数內容
<c:param>
所指定的参数值firstPara,与URL字符串一同被送出:urlstring? FirstPara=123456
<c:url value="/login.jsp" var="loginURL" > login.jsp?username=yanjun&password=123456
<c:param name="username" value=“yanjun"/>
<c:param name="password" value=“123456"/>
</c:url>
<a href="<c:out value='${loginURL}'/>">现在就登录</a>
##考虑如何实现分页
由于页面显示需求,则定义一个用于传递分页相关参数的POJO
@Data
public class PageBean implements Serializable {
private int pageNum;//当前页码值
private int maxPage;//最大页码值
private int rowsNum;//总行数
private int rowsPerPage=15;//每页行数
}
修改DAO接口传递PageBean参数
public interface IBookDao {
List<BookBean> selectByExample(PageBean pages) throws Exception;
}
修改实现类添加针对分页的支持处理
public class BookDaoImpl implements IBookDao{
private JdbcUtil ju=JdbcUtil.getInstance();
@Override
public List<BookBean> selectByExample(PageBean pages)throws Exception {
List<BookBean> res=new ArrayList<>();
Connection conn=null;
ResultSet rs=null;
try{
conn=ju.getConnection();
String sql="select b.*,c.title ctitle from t_books b inner join t_catalog c on b.catalog_id=c.id where 1=1";
if(pages!=null && pages.getRowsPerPage()>0){
if(pages.getPageNum()<1)
pages.setPageNum(1);
if(pages.getMaxPage()<1){
int rowsNum=0;
String ss="select count(*) "+sql.substring(sql.indexOf(" from "));
rs=ju.executeQuery(conn,ss);
if(rs.next())
rowsNum=rs.getInt(1);
if(rowsNum<1)
return res;
int maxPage=rowsNum/pages.getRowsPerPage();
if(rowsNum%pages.getRowsPerPage()!=0)
maxPage++;
pages.setRowsNum(rowsNum);
pages.setMaxPage(maxPage);
}
if(pages.getPageNum()>pages.getMaxPage())
pages.setPageNum(pages.getMaxPage());
int begin=(pages.getPageNum()-1)*pages.getRowsPerPage();
sql=sql+" limit "+begin+","+pages.getRowsPerPage();
}
rs=ju.executeQuery(conn,sql);
while(rs.next()){
BookBean bb=new BookBean();
bb.setId(rs.getLong("id"));
bb.setTitle(rs.getString("title"));
bb.setUnit(rs.getString("unit"));
bb.setPrice(rs.getDouble("price"));
bb.getCatalog().setId(rs.getLong("catalog_id"));
bb.getCatalog().setTitle(rs.getString("ctitle"));
res.add(bb);
}
}finally{
ju.close(rs,null,conn);
}
return res;
}
}
Sevlet中接收客户端提交的参数,并调用DAO完成指定页的查询
public class BookServlet extends BaseServlet {
private IBookDao bookDao = DaoFactory.getBookDao();
private int rowsPerPage=15; //允许使用xml配置
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
String ss=config.getInitParameter("rowsPerPage");
try{
rowsPerPage=Integer.parseInt(ss);
} catch (Exception e){
rowsPerPage=15;
}
}
@Override
public void show(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
PageBean pb=new PageBean();
String ss=request.getParameter("page");
int pageNum=0;
try{
pageNum=Integer.parseInt(ss);
}catch (Exception e){
pageNum=1;
}
pb.setPageNum(pageNum);
pb.setRowsPerPage(rowsPerPage);
List<BookBean> bookList = bookDao.selectByExample(pb);
request.setAttribute("pages",pb);
request.setAttribute("bookList", bookList);
request.getRequestDispatcher("books/list.jsp").forward(request, response);
} catch (Exception e) {
if (ConsoleUtil.DEBUG)
e.printStackTrace();
throw new ServletException(e);
}
}
}
jsp分页导航
<c:url var="u1" value="/books.do">
<c:param name="page" value="1"/>
</c:url>
<a href="${u1}">第一页</a>
<c:if test="${pages.pageNum gt 1}">
<c:url var="u1" value="/books.do">
<c:param name="page" value="${pages.pageNum-1}"/>
</c:url>
<a href="${u1}">上一页</a>
</c:if>
<c:if test="${pages.pageNum lt pages.maxPage}">
<c:url var="u1" value="/books.do">
<c:param name="page" value="${pages.pageNum+1}"/>
</c:url>
<a href="${u1}">下一页</a>
</c:if>
<c:url var="u1" value="/books.do">
<c:param name="page" value="${pages.maxPage}"/>
</c:url>
<a href="${u1}">末尾页</a>
Web页面之间的关系有3种
- 请求转发
- 重定向
- 包含
- 静态包含
- 动态包含
问题:
显示所有商品类别:
- 所有用户共享 —application
- 商品类别很少修改
在服务器启动时自动加载数据,并存储在application中,供所有用户浏览查看
- 解决方案:监听器 xxxListener
- 当服务器启动时自动执行一些方法
ServletContextListener
可以监听application对象的创建和销毁,当执行创建后或者销毁前会自动执行监听器中的特定方法
default public void contextInitialized(ServletContextEvent sce) {} 在application对象创建初始化后立即执行
default public void contextDestroyed(ServletContextEvent sce) {} 在application对象销毁时执行
方法参数为ServletContextEvent类型的事件对象,通过这个参数可以获取事件源
编程实现
1、定义类实现ServletContextListener接口,在contextInitialized方法中从数据库中加载所有的类别信息
public class CatalogListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext application = sce.getServletContext();
try {
List<CatalogBean> clist = DaoFactory.getCatalogDao().getAllCatalogs();
if(clist!=null && clist.size()>0)
application.setAttribute("catalogList",clist);
} catch (Exception e) {
application.log(this.getClass().getName(),e);
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
ServletContext application = sce.getServletContext();
application.removeAttribute("catalogList");
}
}
2、在web.xml中配置监听器
<listener>
<listener-class>com.yan.listeners.CatalogListener</listener-class>
</listener>