MVC:开发模式
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件架构模式,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中
- 控制器Controller:对请求进行处理,负责请求转发
- 视图View:界面设计人员进行图形界面设计
- 模型Model:程序编写程序应用的功能(实现算法等等)、数据库管理
注意:在我们进行Web开发时,MVC模式可对简化我们程序的后期维护和扩展,降低代码的耦合性,并且使程序某些部分的重用提供了方便。但是MVC并不是属于Java的东西,而是一种B/S结构的软件都采用了设计模式。
JavaWeb与MVC
JavaWeb的经历了JSP Model1、JSP Model1二代、JSP Model2三个时期。
- JSP Model1第一代:JSP Model1是JavaWeb早期的模型,它适合小型Web项目,开发成本低!Model1第一代时期,服务器端只有JSP页面,所有的操作都在JSP页面中,连访问数据库的API也在JSP页面中完成。也就是说,所有的东西都耦合在一起,对后期的维护和扩展极为不利。
- JSP Model1第二代:JSP Model1第二代有所改进,把业务逻辑的内容放到了JavaBean中,而JSP页面负责显示以及请求调度的工作。虽然第二代比第一代好了些,但还让JSP做了过多的工作,JSP中把视图工作和请求调度(控制器)的工作耦合在一起了。
- JSP Model2:JSP Model2模式已经可以清晰的看到MVC完整的结构了。
- JSP:视图层,用来与用户打交道。负责接收用来的数据,以及显示数据给用户
- Servlet:控制层,负责找到合适的模型对象来处理业务逻辑,转发到合适的视图
- JavaBean:模型层,完成具体的业务工作
JSP Model2适合多人合作开发大型的Web项目,各司其职,互不干涉,有利于开发中的分工,有利于组件的重用。但是,Web项目的开发难度加大,同时对开发人员的技术要求也提高了
JavaWeb经典三层框架
JavaWeb的三层框架表示的时:所谓三层是表述层(WEB层)、业务逻辑层(Business Logic),以及数据访问层(Data Access)。
- WEB层:包含JSP和Servlet等与WEB相关的内容;
- 业务层:业务层中不包含JavaWeb API,它只关心业务逻辑;
- 数据层:封装了对数据库的访问细节;
注意,在业务层中不能出现JavaWeb API,例如request、response等。也就是说,业务层代码是可重用的,甚至可以应用到非Web环境中。业务层依赖数据层,而Web层依赖业务层!
EL表达式
EL(Express Lanuage)表达式可以嵌入在jsp页面内部,减少jsp脚本的编写,EL出现的目的是要替代jsp页面中脚本语言(java)的编写。它的格式非常简单,具体格式为:${表达式}
,因此EL表达式可以简化我们的JSP页面,使我们的程序段更加简洁
EL运算符:EL表达式中支持运算符
- 1. 算数运算符:
+
、-
、*
、/或div
、%或mod
- 2. 比较运算符:
>
、<
、>=
、<=
、==
、!=
- 3. 逻辑运算符:
&&(and)
||(or)
!(not)
- 4. 空运算符:
empty
功能:用于判断字符串、集合、数组对象是否为null或者长度是否为0${empty list}:
判断字符串、集合、数组对象是否为null或者长度为0${not empty str}:
表示判断字符串、集合、数组对象是否不为null 并且 长度>0
EL最主要的作用是获得四大域中的数据,格式:${EL表达式}
- EL获得pageContext域中的值:
${pageScope.key};
- EL获得request域中的值:
${requestScope.key};
- EL获得session域中的值:
${sessionScope.key};
- EL获得application域中的值:
${applicationScope.key};
- EL从四个域中获得某个值:
${key};
依次从pageContext域,request域,session域,application域中获取属性,在某个域中获取后将不在向后寻找,EL表达式只能从域对象中取值。
忽略el表达式
jsp默认支持el表达式的。如果要忽略el表达式,我们可以设置jsp中page指令中:isELIgnored="true"
忽略当前jsp页面中所有的el表达式,或者设置:\${表达式}
:忽略当前这个el表达式
案例对比:
JSP代码
<!--输出两数之和-->
<%= a+b%>
<!--session对象中User对象的name属性-->
<%
User user=(User)session.getAttribute("userObj");
String name =user.getName();
out.print(name);
%>
EL表达式:
<!--输出两数之和-->
${a+b}
<!--session对象中User对象的name属性-->
${sessionScope.userObj.name}
EL表达式访问JavaBean对象与集合
在JSP页面中,如果我们想要访问JavaBean中的对象,我们会用到<jsp:getProperty>
动作标记,通过使用EL表达式可以简化这个过程。我们只需要使用${域名称.对象名称.属性名称}
或${对象名称.属性名称}
即可。而想要获取List集合时采用${域名称.键名[索引]}
,获取Map集合时使用:${域名称.键名.key名称}
。
隐式对象: EL表达式功能强大之处在于它能访问session、cookie、表单等对象,在它其中共包含11个隐式对象
隐式对象 | 说明 |
applicationScope | 应用程序范围内的scoped变量组成的集合 |
sessionScope | 所有会话范围的对象的集合 |
requestScope | 所有请求范围内的对象的集合 |
pageScope | 页面范围内所有对象的集合 |
cookie | 所有cookie组成的集合 |
header | HTTP请求头部,字符串 |
headerValues | HTTP请求头部,字符串集合 |
initParam | 全部应用程序参数组成的集合 |
pageContext | 当前页面的怕个Context对象,提供了对页面属性的访问 |
param | 所有请求参数字符串组成的集合 |
paramValues | 所有作为字符串集合的请求参数 |
- 与范围有关的隐式对象包括:
pageScope、requestScope、sessionScope、applicationScope
,则四个对象与jsp的pageContext、request、session、application
一样。但只能取值,即只能getAttribute(String name);
- 语法格式:
${appicationScope.username}
${sessionScope.username}
${requestScope.username}
${cookieScope.username}
- 与输入有关的隐式对象:包括
param与paramValues
,它相当于JSP语句中的request.getParameter(String name);
和request.getParameterValues(String name);
,语法格式${param.name}、${paramvalues.name}
cookie
隐式对象
输出user:cookie:${cookie.user}
输出user的name:cookie:${cookie.user.name}
输出user的value:cookie:${cookie.user.value}
header 和 headerValues
:header存储用户浏览器和服务器用来沟通的数据。 例如,获取用户浏览器的版本:${header["User-Agent"]};
,headerValues用于同一标头拥有不同的值的情况。initParam:
用于取得设定web站点的环境参数:${initParam.userid}
pageContext:
用来取得其他相关用户要求或页面的详细信息:${pageContext.request.contextPath}
JSTL
什么是JSTL
JSTL(JavaServer Pages Tag Library):JSP标准标签库,是由Apache组织提供的开源的免费的jsp标签,apache对EL表达式的扩展,通过使用JSTL可以简化和替换jsp页面上的java代码。JSTL是标签语言,它与JSP动作标签一定,只不过它不是JSP内置的标签,需要我们自己导包(jstl-1.2.jar)到指定标签库。
JSTL一共包含四大标签库:core:核心标签库、fmt:格式化标签库、sql:数据库标签库、xml:xml标签库。除了JSP动作标签外,使用其他第三方的标签库都需要导包,并在JSP页面中使用taglib指令导入标签库,例:导入JSTL的core标签库:<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
-
prefix="c"
:指定标签库的前缀,这个前缀可以随便给值,但大家都会在使用core标签库时指定前缀为c -
uri="http://java.sun.com/jstl/core"
:指定标签库的uri,它不一定是真实存在的网址,但它可以让JSP找到标签库的描述文件
core标签库常用标签:
- out: out标签可以在JSP页面中输出指定字符串,起作用类似于
"<%= %>"
,可以认为这个标签是一个增强了的EL表达式
out中的主要属性:
属性名称 | 说明 |
value | 需要输出的值 |
default | 如果value的值为null,显示default的值 |
escapeXML | 是否转换特殊字符串 |
- 样例:
- 输出aaa字符串常量:
<c:out value="str"/>
- 与
${str}
相同:<c:out value="${str}"/>
- 当
${str}
不存在时,输出xxx字符串:<c:out value="${str}" default="xxx"/>
- escapeXml为false时不会识别字符串中的标签
<c:out value="${str}" default="xxx" escapeXml="false" />
- set: set标签用来声明一个变量,我们可以声明在JSP页面中或JavaBean属性中。
set中的主要属性:
属性名称 | 说明 |
value | 要被存储的值 |
var | 要存入的变量名称 |
scopevar | 变量的JSP范围 |
traget | 一个JavaBean或Map对象 |
property | 指定target对象的属性 |
- 样例:
- 将属性值存储在session中:
<c:set value=" value" var="name" default="xxx" scope="session"/>
- 在pageContext中添加数据:
<c:set var="name" default="xxx"/>
- 将本体内容存储在范围为scope的name变量中:
<c:set var="name" default="xxx" scope="{page|request|session|application}"/>
- remove:remove标签用于移除指定范围内的变量,与set标签刚好相反。
删除所有域中指定名字的数据:<c:remove var="name"/>
、<c:out value="${name}" default="none"/>
删除pageContext中指定名字的数据:<c:remove var="a" scope="page"/>
- url:该标签会在需要URL重写时添加sessionId
url中的主要属性:
属性名称 | 说明 |
value | 被包含文件的地址 |
context | 相同服务器下的其他Web站点必须以 |
var | 存储被包含文件的内容 |
scope | var变量的存储范围 |
- 样例:
- 输出上下文路径:
<c:url value="/"/>
- 把本该输出的结果赋给变量,范围为request:
<c:url value="/" var="name" scope="request"/>
- 输出:/demo/Servlet1?username=abc&password=123
如果参数中包含中文,那么会自动使用URL编码!<c:url value="/Servlet1">
<c:param name="username" value="abc"/>
<c:param name="password" value="123"/>
</c:url>
- if:该标签的test属性必须是一个boolean类型的值,如果test的值为true,那么执行if标签的内容,否则不执行
if中的主要属性:
属性名称 | 说明 |
test | 表达式结果为true执行,否则不执行 |
var | 存储test的运算结果 |
scope | var变量的JSP范围 |
- 样例:
<c:set var="test" value="hello"/>
<c:if test="${not empty test}">
<c:out value="${test}"/>
</c:if>
- choose:choose标签对应Java中的if/else if/else结构。when标签的test为true时,会执行这个when的内容。当所有when标签的test都为false时,才会执行otherwise标签的内容
<c:set var="score" value="${param.score }"/>
<c:choose>
<c:when test="${score > 100 || score < 0}">错误的分数:${score }</c:when>
<c:when test="${score >= 90 }">A级</c:when>
<c:when test="${score >= 80 }">B级</c:when>
<c:when test="${score >= 70 }">C级</c:when>
<c:when test="${score >= 60 }">D级</c:when>
<c:otherwise>E级</c:otherwise>
</c:choose>
forEach:用来循环遍历数组、集合,还可以用来计数方式来循环,forEach当前就是循环标签了,forEach标签有两种使用方式: 使用循环变量,指定开始和结束值,类似for(int i = 1; i <= 10; i++) {}
循环遍历集合,类似for(Object o : 集合)
forEach中的主要属性:
属性名称 | 说明 |
var | 临时变量 |
begin | 循环开始位置 |
end | 循环结束位置 |
step | 设置步长,等同于Java中i++或i+=2,默认为1 |
count | 循环次数,从1开始 |
items | 遍历的集合对象 |
varStatus | 循环状态对象 |
样例:
<!--重复操作-->
<c:forEach var="i" begin="1" end="10">
${i}
</c:forEach>
<c:forEach begin="1" end="10" var="i" step="2" varStatus="s">
${i} ${s.index} ${s.count} <br>
</c:forEach>
<!--遍历集合-->
<c:forEach items="${list}" var="str" varStatus="s">
${s.index} ${s.count} ${str}<br>
</c:forEach>
fmt标签库常用标签
fmt标签库是用来格式化输出的,通常需要格式化的有时间和数字。 格式化时间:
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
......
<%
Date date = new Date();
pageContext.setAttribute("d", date);
%>
<fmt:formatDate value="${d }" pattern="yyyy-MM-dd HH:mm:ss"/>
格式化数字:
<%
double d1 = 3.5;
double d2 = 4.4;
pageContext.setAttribute("d1", d1);
pageContext.setAttribute("d2", d2);
%>
<fmt:formatNumber value="${d1 }" pattern="0.00"/><br/>
<fmt:formatNumber value="${d2 }" pattern="#.##"/>
自定义标签
我们在JSP页面中使用标签就等于调用某个对象的某个方法一样,例如:<c:if test=””>,这就是在调用对象的方法一样。自定义标签其实就是自定义类一样,定义标签处理类:必须是Tag或SimpleTag的实现类
SimpleTag接口内容如下:
- void doTag():标签执行方法
- JspTag getParent():获取父标签
- void setParent(JspTag parent):设置父标签
- void setJspContext(JspContext context):设置PageContext
- void setJspBody(JspFragment jspBody):设置标签体对象
public class HelloTag implements SimpleTag {
private JspTag parent;
private PageContext pageContext;
private JspFragment jspBody;
public void doTag() throws JspException, IOException {
pageContext.getOut().print("Hello Tag!!!");
}
public void setParent(JspTag parent) {
this.parent = parent;
}
public JspTag getParent() {
return this.parent;
}
public void setJspContext(JspContext pc) {
this.pageContext = (PageContext) pc;
}
public void setJspBody(JspFragment jspBody) {
this.jspBody = jspBody;
}
}
标签库描述文件(TLD):
标签库描述文件是用来描述当前标签库中的标签的!标签库描述文件的扩展名为tld,你可以把它放到WEB-INF下,这样就不会被客户端直接访问到了,创建hello.tld文件:
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd ">
<tlib-version>1.0</tlib-version>
<short-name>itcast</short-name>
<uri>http://www.itcast.cn/tags</uri>
<tag>
<name>hello</name>
<tag-class>cn.itcast.tag.HelloTag</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>
使用标签
在页面中使用标签分为两步:使用taglib导入标签库、使用标签
<%@ taglib prefix="it" uri="/WEB-INF/hello.tld" %>
......
<it:hello/>