Java学习笔记-Day56 MVC模式、EL和JSTL
一、MVC模式
MVC(Model-View-Controller)是一种软件架构设计模式,MVC模式将软件的代码按照模型(M)、视图(V)、控制器(C)三部分组织。
使用MVC模式构建应用,具有以下优势:
- 耦合性低:视图层和业务层分离,耦合性降低,可以独立修改。
- 重用性高:可以用不同的视图访问模型部分,实现在不同终端上访问应用。
- 可维护性高:视图与业务分离,降低了维护成本。
MVC模式中有三个角色,分别是M模型,V视图,C控制器。使用不同的编程语言都可以实现MVC模式。
M指的是模型,实现业务逻辑。V指的是视图,实现显示页面。C指的是控制器,实现控制逻辑,接收视图的请求,调用业务逻辑处理,并跳转到不同的视图显示处理结果。在JavaEE中,M模型为Java类( Service、Bean(数据传递载体,实体类)、Dao),V视图为html和jsp,C控制器为Servlet。
在控制器和视图之间,常常需要共享数据。例如从数据查出来的商品列表信息,需要从控制器发送到视图。
Servlet和JSP之间共享数据一般使用请求、会话、上下文范围的属性进行。HttpServletRequest、HttpSession、ServletContext接口中都定义了存取、查询、删除属性的方法。使用原则:尽量用范围小的属性,即请求范围内共享就用请求,以此类推。否则会造成资源浪费,降低安全性。
MVC模式中,控制器和视图之间需要进行跳转,Servlet规范中,有三种跳转方式:
- redirect:调用响应接口的sendRedirect方法,响应重定向,相当于重新请求新的资源,当前请求对象不会到目标资源;
- forward: 调用请求转发器接口的forward方法,请求转发,将当前的请求、响应对象转发到目标资源;
- include:调用请求转发器接口的include方法,动态包含,将目标资源的请求、响应对象包含到当前资源;
二、EL和JSTL
1、EL
1.1、EL简介
EL是Expression Language的简称,即表达式语言。EL在JSP中使用,服务器会对其进行解析翻译,生成相应的Java代码。EL的作用是用来在JSP页面输出动态内容,可以替代JSP中的表达式元素 <%=%>
。使用EL只是让JSP编写起来更为简单。
EL的一般格式如下:以 ${
开始,以 }
结束, ${EL表达式}
。
${param.username}
等同于<%=request.getParameter(“username”)%>
1.2、内置对象
为了能够方便地输出数据,EL提供了11个内置对象:
- 2个内置对象为了方便输出请求参数: param、paramValues
- 4个内置对象为了方便输出各个范围的属性: pageScope、requestScope、sessionScope、applicationScope
- 2个与请求头有关的内置对象:header、headerValues
- 2个其他内置对象:cookie、initParam
- 1个特殊的内置对象:pageContext
隐式对象 | 描述 |
---|---|
pageScope | 来自页面范围的范围变量 |
requestScope | 来自请求范围的范围变量 |
sessionScope | 会话范围的范围变量 |
applicationScope | 应用范围的范围变量 |
param | 请求参数作为字符串 |
paramValues | 请求参数作为字符串集合 |
header | HTTP请求标头作为字符串 |
headerValues | HTTP请求标头作为字符串集合 |
initParam | 上下文初始化参数 |
cookie | Cookie值 |
pageContext | 当前页面的JSP PageContext对象 |
1.2.1、内置对象param
内置对象param:用来输出请求参数的值,格式为${param.请求参数名字}
使用表达式:<%=request.getParameter(“name”)%>
使用EL:${param.name}
1.2.2、内置对象paramValues
内置对象paramValues:用来获取一对多的参数值,返回一个数组。比如某请求参数是通过checkbox传递的,名字为hobbies,要输出所有hobbies值中的第一个值,可以使用如下两种方式:
使用表达式:<%=request.getParameterValues(“hobbies”)[0]%>
使用EL:${paramValues.hobbies[0]}
1.2.3、内置对象header
内置对象header:用来输出某一个请求头的值,格式为${header.请求头名字},例如输出请求头accept的值
${header.accept}
1.2.4、内置对象headerValues
内置对象headerValues:如果某个请求头的值有多个,则使用headerValues返回一个数组。如下代码所示:
${headerValues.cookie[0]}
上述代码将返回请求头cookie中的第一个值,例如:JSESSIONID=A6A22CA4AEE8F9E1111422C889740B24:
1.2.5、内置对象cookie
内置对象cookie:用来获取cookie的值,如下代码所示,将输出名字为JSESSIONID的cookie的值: JSESSIONID=A6A22CA4AEE8F9E1111422C889740B24:
${cookie.JSESSIONID.value}
1.2.6、内置对象initParam
内置对象initParam:用来输出上下文参数
在web.xml中配置上下文参数:
<context-param>
<param-name>path</param-name>
<param-value>/WEB-INF/props</param-value>
</context-param>
在JSP中使用EL输出path的值:
${initParam.path}
1.2.7、内置对象pageContext
内置对象pageContext:EL中的pageContext对象可以调用PageContext类中所有符合规范的getXxx方法,如PageContext类中有如下方法:public abstract ServletRequest getRequest(), 可以通过如下EL调用该方法:
${pageContext.request}
该方法将输出请求对象:org.apache.catalina.core.ApplicationHttpRequest@1b98cbb
既然该EL返回的是真正的请求对象,那么就可以继续调用HttpServletRequest中的其他getXxx方法,如:
${pageContext.request.remoteAddr}
上述表达式将调用请求中的getRemoteAddr方法,输出其返回值,例如:127.0.0.1
1.2.8、获取属性数据有关的内置对象
与获取属性数据有关的内置对象有四个,分别是:
- pageScope:页面范围
- requestScope:请求范围
- sessionScope:会话范围
- applicationScope:上下文范围
例如获得名字为user的请求属性的pwd属性值,EL为:${requestScope.user.pwd}
等同于 <%=((User)request.getAttribute(“user")).getPwd()%>
检索顺序:当不指定范围时,例如,${user.pwd},将自动从pageScope开始查找,直到applicationScope,如果没查到,则什么也不显示
pageScope作用域:与页面作用域(page)中的属性相关联的Map类,主要用于获取页面范围内的属性值。
requestScope作用域:与请求作用域(request)中的属性相关联的Map类,主要用于获取请求范围内的属性值。
sessionScope作用域:与会话作用域(session)中的属性相关联的Map类,主要用于获取会话范围内的属性值。
applicationScope作用域:与应用程序作用域(application)中的属性相关联的Map类,主要用于获取应用程序范围内的属性值。
默认的访问顺序:pageScope→requestScope→sessionScope→applicationScope
作用域 | Java代码取值 | EL取值 |
---|---|---|
请求作用域 | request.getAttribute(“goods”); | ${ requestScope.goods } |
会话作用域 | session.getAttribute(“username”); | ${ sessionScope.username } |
程序作用域 | application.getAttribute(“user”); | ${ applicationScope.user } |
页面作用域 | pageContext.getAttribute(“pageNum”); | ${ pageScope.pageNum } |
使用pageScope/requestScope/sessionScope/applicationScope中的某一个内置对象获取属性时,则是强制使用该作用域的属性。
页面范围user对象的pwd属性:
${pageScope.user.pwd}
请求范围user对象的pwd属性:${requestScope.user.pwd}
会话范围user对象的pwd属性:${sessionScope.user.pwd}
上下文范围user对象的pwd属性:${applicationScope.user.pwd}
1.3、EL运算符
EL算术运算符:+ 实现加法运算、- 实现减法运算、* 实现乘法运算、/或div实现除法运算、%或mod实现求模运算。
EL比较运算符:有6种比较运算符,可以对值进行比较,返回值为true或fasle。
==
或eq
表示等于!=
或ne
表示不等于<
或lt
表示小于>
或gt
表示大于<=
或le
表示小于等于>=
或ge
表示大于等于
EL逻辑运算符:EL中提供了3个逻辑运算符,可以对boolean类型的值进行运算,返回值为true或false。
&&
或and
表示交集,两个值都是true才返回true。||
或or
表示并集,两个值只要有一个是true,即返回true。!
或not
表示非
使用[]指定索引的方式可以获取数组或List中的元素;
返回请求范围内商品列表集合的第一个商品的名称:
${requestScope.productsList[0].productName}
EL其他运算符:除了算术、比较、逻辑运算符外,还有三种其他运算符。
- empty运算符:判断值是否为null,如果是null,返回true,否则返回false。
- 关系运算符:
${A?B:C}
如果A为true,则执行B,如果A为false,则执行C。 - ()运算符:通过
()
可改变优先级
2、JSTL
2.1、JSTL简介
JSP中的静态内容都使用HTML标签实现,如果动态内容也能够使用标签实现,将大大简化JSP。JSP中的标签库就是用Java类 ( 遵守一定规范,成为标签处理器类 ) 实现动态功能,将这些动态功能在tld文件 ( taglib description 标签库描述文件 ) 中描述为标签,在JSP中通过使用标签就可以实现动态功能,不用在JSP中编写复杂的Java代码。
标签库由 标签处理器类 和 描述文件tld文件组成。其作用:简化JSP文件,不需在JSP中写大量的Java脚本。标签可以重复使用,利于维护。
JSTL是一套定义好的标签库,可以直接使用。JSTL的全称是Jsp Standard Tag Library,即JSP标准标签库。JSTL包含很多标签,根据其作用可以分为:属性相关的标签、条件分支相关的标签、迭代标签、其他标签。
要使用JSTL,首先要把JSTL相关的资源文件保存到lib目录下,使用解压缩软件解压jar文件,主要包含两类内容:
tld文件中,对标签进行了描述,包括标签的名字,标签处理器类,标签的属性等,同时一个tld文件有一个唯一标记的uri。
2.2、JSTL标签库的使用
(1)将JSTL相关的两个jar文件保存到 WebContent/WEN-INF/lib 目录下。
(2)在JSP中使用taglib指令引入标签库。
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
uri是tld文件的唯一标记;需要查看tld文件获得。prefix指定使用该标签库时的前缀,只要不使用保留字,其他字符均可。不过一般如果使用c.tld标签库,前缀就用c,可增强可读性。
JSTL中与属性操作有关的标签有如下两个:
标签名字 | 所在标签库 | 作用 | 属性 |
---|---|---|---|
set | c.tld | 在指定范围内,将对象保存为属性; | var:属性名字 scope:属性范围 value:属性值,可以使用EL |
remove | c.tld | 在指定范围内,删除属性; | var:属性名字 scope:属性范围 |
<!--设置-->
<c:set var="path" scope="page" value="${pageContext.request.contextPath}"></c:set>
<!--使用-->
${path}
JSTL中与条件分支有关的标签有如下四个:
标签名字 | 所在标签库 | 作用 | 属性 |
---|---|---|---|
if | c.tld | 实现if逻辑,当条件为true,执行标签体内容; | test:返回值为布尔值的表达式,作为分支的条件; |
choose | c.tld | 实现if/else if/else逻辑,需要与when,otherwise结合使用 | |
when | c.tld | 实现else if逻辑,与choose、otherwise配合使用; | test:返回值为布尔值的表达式,作为分支的条件; |
otherwise | c.tld | 实现else逻辑,与 choose、when配合使用; |
<c:set var = "name" value = "Tom"/>
<c:if test= "${not empty name}">
<c:out value = "${name}"/>
</c:if>
<c:set var ="IDE" value= "Eclipse"/>
<c:choose>
<c:when test = "${IDE == 'IDEA' }">
<c:out value = "使用的工具是IDEA"/>
</c:when>
<c:when test = "${IDE == 'Eclipse' }">
<c:out value = "使用的工具是Eclipse"/>
</c:when>
<c:when test = "${IDE == 'MyEclipse' }">
<c:out value = "使用的工具是MyEclipse"/>
</c:when>
<c:otherwise>
<c:out value = "用记事本写代码!"/>
</c:otherwise>
</c:choose>
JSTL中与迭代有关的标签如下所示
标签名字 | 所在标签库 | 作用 | 属性 |
---|---|---|---|
forEach | c.tld | 迭代集合或数组; | items:需要迭代的数组或集合对象,可以使用EL表达式; var:迭代过程中的临时变量,存储在PageScope中; |
forToken | c.tld | 迭代字符串; | items:指定需要迭代的字符串; delims:表示分隔符; var:表示使用分隔符分割items产生的字符串; |
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!-- 加入taglib标记 -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
<style type="text/css">
td {
border: 1px solid black;
}
#tab {
width: 600px;
text-align: center;
}
</style>
<link href="${pagecontext.request.contextPath}/bootstrap-3.3.7/css/bootstrap.css">
</head>
<body>
<div id="div1">
<table id="tab" border="1" cellspacing="0" cellpadding="20">
<thead>
<tr>
<th>编号</th>
<th>名字</th>
<th>密码</th>
<th>年龄</th>
<th>性别</th>
</tr>
</thead>
<tbody>
<c:forEach items="${requestScope.list}" var="u">
<tr>
<td>${u.userid}</td>
<td>${u.uname}</td>
<td>${u.upwd}</td>
<td>${u.uage}</td>
<td>${u.usex==1?"男":"女"}</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
<script src="${pageContext.request.contextPath}/js/jquery-2.0.3.js"></script>
<script
src="${pageContext.request.contextPath}/bootstrap-3.3.7/js/bootstrap.min.js"></script>
</body>
</html>