JSP-4

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对象存取
paramServletRequest.getParameter(String name)
paramValuesServletRequest.getParameterValues(String name)
headerHttpServletRequest.getHeader(String name)
headerValuesHttpervletRequest.getHeaders(String)
cookieHttpServletRequest.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之外的一个选择

ELrequest
${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&nbsp;&nbsp;2&nbsp;&nbsp;3&nbsp;&nbsp;4&nbsp;&nbsp;5&nbsp;&nbsp;6&nbsp;&nbsp;7&nbsp;&nbsp;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
核心标签chttp://java.sun.com/jsp/jstl/core
i18n国际化标签fmthttp://java.sun.com/jsp/jstl/fmt
SQL标签sqlhttp://java.sun.com/jsp/jstl/sql
XML标签xmlhttp://java.sun.com/jsp/jstl/xml
函数标签fnhttp://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&nbsp;&nbsp;2&nbsp;&nbsp;3&nbsp;&nbsp;4&nbsp;&nbsp;5&nbsp;&nbsp;6&nbsp;&nbsp;7&nbsp;&nbsp;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>

如果条件成立则执行标签体,否则不执行标签体
属性动态类型说明
testboolean条件表达式
varString输出判断结果的范围变量名称
scopeStringvar的范围
  • 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>
属性动态类型说明
varString储存指定的迭代成员
items集合对象迭代的集合对象
varStatusString储存指定迭代成员的状态内容
beginint迭代的开始值
endint迭代的结束值
stepint每次迭代的间隔值
<%
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
cparam标签

将属性值指定给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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值