JSP
java server page:java服务器端页面。其实就是一个特殊的页面,其中即可以写html文档,又可以写java代码。JSP本质上就是一个Servlet。
JSP的工作模式是请求/响应模式,客户端首先发出HTTP请求,JSP程序收到请求后进行处理并返回处理结果。在一个JSP文件第1次被请求时,JSP引擎(容器)把该JSP文件转换成为一个Servlet,而这个引擎本身也是一个Servlet。
像这种将前后端代码合在一起的技术成为模板引擎. Java常用的模板引擎除了 jsp 之外还有 Freemarker 和 Beetl.
使用
-
JSP脚本元素:是指嵌套在<%和%>之中的一条或多条Java程序代码。主要包括以下三种类型:
-
JSP脚本<% 代码 %>:这里写的代码会被放在service方法中,里面定义的变量都是局部变量。
-
JSP声明<%! 代码 %>:用于在JSP页面中定义全局的变量或方法,是Servlet的成员变量或成员方法。
-
JSP表达式<%= 代码 %>:可以是任何Java语言的完整表达式。该表达式的最终运算结果将被转换为字符串并输出到页面上。相当于 out.println()
<body> 计算3/2=<%= 3/2 %> <%-- JSP表达式不仅可以插入网页的文本中,用于输出文本内容,也可以插入HTML标记中,用于动态设置属性值。--%> </body>
-
-
注释
- JSP注释:<%-- --%> 服务器端注释,解析时将跳过这些代码,在客户端是查看源代码是看不到这些注释的。
- html注释:客户端注释,浏览器查看源代码是可以看到这些注释的。
-
JSP指令:用来设置JSP页面中的一些信息
-
page指令:用来对页面的某些特性进行描述,如:页面的编码方式、JSP 页面采用的语言等
格式:<%@ page 属性名1= "属性值1" 属性名2= "属性值2" ...%>
page指令常见属性:
注意:除了import属性外,其他的属性都只能出现一次,否则会编译失败。同时page指令的属性名称都是区分大小写的。<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="utf-8" %>
-
include指令:在实际开发时,有时需要在JSP页面静态包含一个文件,例如HTML文件、JSP等,这时,可以通过include指令来实现。不过该指令是静态包含,也就是说被包含文件中所有内容会被原样包含到该JSP页面中,即使被包含文件中有JSP代码,在包含时也不会被编译执行。使用include指令,最终将生成一个文件,所以在被包含和包含的文件中,不能有相同名称的变量。
格式:<%@ include file="被包含的文件地址"%>
注意:在应用include指令进行文件包含时,为了使整个页面的层次结构不发生冲突,建议在被包含页面中将<html>、<body>等标记删除。因为在包含该页面的文档中已经指定了这些标签。
top.jsp:<%@ page contentType="text/html;charset=UTF-8" language="java" %> <div style="background-color: antiquewhite;color: blue;font-size: x-large"><%="这是标题"%>></div> <!-- 使用include,两个页面的page指令必须一样-->
index.jsp:
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %> <!DOCTYPE html> <html> <head> <title>Hello World</title> </head> <body> <%@include file="top.jsp"%> <h1><%= "Hello World!" %> </h1> <br/> <a href="hello-servlet">Hello Servlet</a> </body> </html>
-
taglib:用来导入外部标签库。
<%taglib uri="" prefix=""%>
-
-
动作标识
-
包含文件标识<jsp:include>用于向当前页面中包含其他的文件。被包含的文件可以是动态文件,也可以是静态文件。
格式:<jsp:Include page=“url” flush=“false|true”/>
- <jsp:include>和include指令的比较
- include指令通过file属性指定被包含的文件,并且file属性不支持任何表达式;<jsp:include>动作标识通过page属性指定被包含的文件,而且page属性支持JSP表达式。
- 使用include指令时,被包含的文件内容会原封不动地插入包含页中,然后JSP编译器再将合成后的文件最终编译成一个Java文件;使用<jsp:include>动作标识包含文件时,当该标识被执行时,程序会将请求转发(注意是转发,而不是请求重定向)到被包含的页面,并将执行结果输出到浏览器中,然后返回包含页继续执行后面的代码。因为服务器执行的是多个文件,所以JSP编译器会分别对这些文件进行编译。
- 在应用include指令包含文件时,由于被包含的文件最终会生成一个文件,所以在被包含文件、包含文件中不能有重名的变量或方法;而在应用<jsp:include>动作标识包含文件时,由于每个文件是单独编译的,所以在被包含文件和包含文件中重名的变量和方法是不相冲突的。
- <jsp:include>和include指令的比较
-
请求转发标识<jsp:forword>:可以将请求转发到其他的Web资源,例如,另一个JSP页面、HTML页面、Servlet等。
格式:<jsp:forward page="url" />
-
参数传递标识<jsp:param>:可以作为其他标识的子标识,用于为其他标识传递参数。
格式:<jsp:param name="参数名" value="值">
<jsp:forward page="login.jsp" /> <jsp:param name="username" value="zhangsan" /> </jsp:forward>
通过<jsp:param>动作标识指定的参数,将以“参数名=值”的形式加入请求中。它的功能与在文件名后面直接加“?参数名=参数值一样。
-
9个内置对象
JSP提供了一些内置对象,不需要实例化就可以直接使用
-
out:字符输出流对象。可以将数据输出到页面上,和resp.getWriter()类似。
resp.getWriter()和out.write()的区别:在tomcat服务器真正给客户端做出响应之前,会先找resp缓冲区数据,再找out缓冲区数据。所以resp.getWriter()数据输出永远在out.write()之前out对象提供了print()和println()两种向页面中输出信息的方法。不过使用println方法在页面中看不到换行的效果。out.println()相当于
<%= %>
-
page:代表当前JSP页面本身,本质是包含当前Servlet接口引用的变量,可以看作是this关键字的别名。
page对象常用方法 -
exception:用来处理JSP文件执行时发生的所有错误和异常。只有在page指令中设置为isErrorPage属性值为true的页面中才可以被使用,在一般的JSP页面中使用该对象将无法编译JSP文件。
exception对象几乎定义了所有异常情况,在Java程序中,可以使用try...catch关键字来处理异常情况,如果在JSP页面中出现没有捕捉到的异常,就会生成exception对象,并把exception对象传送到在page指令中设定的错误页面中,然后在错误页面中处理相应的exception对象。
index.jsp页面产生错误,并传递给error.jsp<%@ page import="java.util.Date" %> <%@ page import="java.text.SimpleDateFormat" %> <%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" errorPage="error.jsp" %> <!DOCTYPE html> <html> <head> <title>Hello World</title> </head> <body> <% String str = "100元"; Float price = Float.parseFloat(str); %> </body> </html>
在error.jsp打印错误信息
<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %> <html> <head> </head> <body> <%=exception.getMessage() %> </body> </html>
-
PageContext:jsp独有的,Servlet中没有。是四大域对象(应用域ServletContext、会话域HttpSession、请求域ServletRequest、PageContext)之一的页面域对象,还可以操作其他三个域对象中的属性。生命周期和随着jsp的创建而存在,随着jsp的结束而消失。
常用方法:
父类JspContext的方法
案例:使用JSP获取上次访问页面的时间
<%@ page import="java.util.Date" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<%
long lastAccessedTime = session.getLastAccessedTime();//获取上次访问时间的毫秒数
Date date = new Date();
date.setTime(lastAccessedTime);//将毫秒数转成日期对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
String str_date = sdf.format(date);//格式化日期对象
%>
<%= str_date%>
</body>
</html>
JSP最佳实战-MVC模型
MVC模式:model + view + controller 模型+视图+控制器,是一种软件设计典范。
M:model,通常用于封装数据。具体的方法由普通的Java类实现, 一般起名为 xxxService. 如果要进行持久化存储, 还需要 dao 和 bean, 以便于和数据库交互.
V:view ,通常用于展示数据。动态展示用jsp页面,静态数据展示用html。
C:controller ,通常用于处理请求和响应。一般指的是Servlet。
JavaBean
Java规定了标准的类定义格式,符合这种格式的Java类就是一个JavaBean。要求如下:
- 所有属性为private
- 提供公共的无参构造方法
- 提供getter和setter
- 实现serializable接口
JavaBean在Java EE开发中,通常用于封装数据,对于遵循以上写法的JavaBean组件,其它程序可以通过反射技术实例化JavaBean对象(内省机制),并且通过反射那些遵循命名规范的方法,从而获知JavaBean的属性,进而调用其属性保存数据。
所以符合JavaBean规范的类,就算成员变量是私有的,也可以直接使用对象名.属性名修改。大大简化了jsp的代码。
EL
Expression Language表达式语言。用来替换和简化jsp页面中java代码的编写。
语法:${表达式}。注意EL用在jsp的java代码中,jQuery用在JavaScript中。
使用
获取四大域中的数据
找到了就输出,没找到就空着,不会输出null,比较美观。
-
el表达式只能从域对象中获取值
-
${域名称.键名}:从指定域中获取指定键的值
pageScope --> pageContext
requestScope --> request
sessionScope --> session
applicationScope --> application(ServletContext) -
${键名}:表示依次从最小的域中查找是否有该键对应的值,直到找到为止。
-
获取参数:${param.参数名} param是EL内置的对象
-
获取对象、List集合、Map集合的值
-
对象:${域名称.对象名.属性名}
package com.example.JSPDemo;//定义一个JavaBean类 public class Person { private String name;//属性都是私有的 private Date birthday; public Person(){} //提供无参构造 //getter、setter略 //成员方法 public String getInfo() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); return name + "出生于:"+sdf.format(birthday) ; } }
<%@ page import="com.example.JSPDemo.Person" %> <%@ page import="java.util.Date" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> </head> <body> <% //先使用java代码创建一个对象,再保存到域对象中,就可以使用EL表达式来访问了 Person person = new Person(); person.setBirthday(new Date()); person.setName("zhangsan"); request.setAttribute("p",person);//这一步是必需的,对象必须保存到域中,才可以用EL来访问 %> ${p.name}<br/> ${p.birthday}<br/> ${p.info}<br/><%--像访问属性一样调用方法,注意去掉方法名前的get、set,然后名称一律小写,直接调用--%> </body> </html>
-
List集合:${域名称.集合名[索引]}
-
Map集合:${域名称.集合名.key}或${域名称.集合名["key"]}
-
运算符
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page import="com.itheima.domain.User" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>EL两个特殊的运算符</title>
</head>
<body>
<%--空运算符: empty
功能:用于判断字符串、集合、数组对象是否为null或者长度是否为0
${empty list}:判断字符串、集合、数组对象是否为null或者长度为0
${not empty str}:表示判断字符串、集合、数组对象是否不为null 并且 长度>0
--%>
<% String str = null;
String str1 = "";
List<String> slist = new ArrayList<String>();
pageContext.setAttribute("str", str);
pageContext.setAttribute("str1", str1);
pageContext.setAttribute("slist", slist);
%>
${empty str}============当对象为null返回true<br/>
${empty str1 }==========当字符串为空字符串是返回true(注意:它不会调用trim()方法)<br>
${empty slist}==========当集合中的元素是0个时,是true
<hr/>
<%--三元运算符
条件?真:假
--%>
<% request.setAttribute("gender", "female"); %>
<input type="radio" name="gender" value="male" ${gender eq "male"?"checked":""} >男
<input type="radio" name="gender" value="female" ${gender eq "female"?"checked":""}>女
</body>
</html>
11个内置对象
EL表达式也为我们提供隐式对象,可以让我们不声明直接来使用,十一个对象见下表,需要注意的是,它和JSP的隐式对象不是一回事:
EL中的隐式对象 | 类型 | 对应JSP隐式对象 | 备注 |
---|---|---|---|
PageContext | Javax.serlvet.jsp.PageContext | PageContext | 完全一样 |
ApplicationScope | Java.util.Map | application | 应用层范围 |
SessionScope | Java.util.Map | session | 会话范围 |
RequestScope | Java.util.Map | request | 请求范围 |
PageScope | Java.util.Map | 没有 | 页面层范围 |
Header | Java.util.Map | 没有 | 请求消息头key,值是value(一个) |
HeaderValues | Java.util.Map | 没有 | 请求消息头key,值是数组(一个头多个值) |
Param | Java.util.Map | 没有 | 请求参数key,值是value(一个) |
ParamValues | Java.util.Map | 没有 | 请求参数key,值是数组(一个名称多个值) |
InitParam | Java.util.Map | 没有 | 全局参数,key是参数名称,value是参数值 |
Cookie | Java.util.Map | 没有 | Key是cookie的名称,value是cookie对象 |
注意:jsp和EL的pageContext对象其实就是同一个对象。
注意
EL没有空指针异常、没有索引越界异常、没有字符串拼接的效果
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>EL表达式的注意事项</title>
</head>
<body>
<%--EL表达式的三个没有--%>
第一个:没有空指针异常<br/>
<% String str = null;
request.setAttribute("testNull",str);
%>
${testNull}
<hr/>
第二个:没有数组下标越界<br/>
<% String[] strs = new String[]{"a","b","c"};
request.setAttribute("strs",strs);
%>
取第一个元素:${strs[0]}
取第六个元素:${strs[5]}
<hr/>
第三个:没有字符串拼接<br/>
<%--${strs[0]+strs[1]}--%>
${strs[0]}+${strs[1]}
</body>
</html>
JSTL
JSP tag library JSP标准标签库,用于简化和替换jsp页面上的java代码。由以下5个部分组成:
组成 | 作用 | 说明 |
---|---|---|
Core | 核心标签库。 | 通用逻辑处理 |
Fmt | 国际化有关。 | 需要不同地域显示不同语言时使用 |
Functions | EL函数 | EL表达式可以使用的方法 |
SQL | 操作数据库。 | 不用 |
XML | 操作XML。 | 不用 |
使用步骤:
- 导入jstl相关jar包
- 引入标签库:taglib指令:<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
- 使用标签
核心标签库
-
if:相当于java代码的if语句
- 属性:
- test 必须属性,接受boolean表达式
- 如果表达式为true,则显示if标签体内容,如果为false,则不显示标签体内容
- 一般情况下,test属性值会结合el表达式一起使用
- 注意:c:if标签没有else情况,想要else情况,就再定义一个c:if
- test 必须属性,接受boolean表达式
- 属性:
-
choose:相当于java代码的switch语句
- 使用choose标签声明 相当于switch声明
- 使用when标签做判断 相当于case
- 使用otherwise标签做其他情况的声明 相当于default
-
foreach:相当于java代码的for语句
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%--导入jstl标签库 --%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>JSTL的常用标签</title>
</head>
<body>
<%-- c:if c:choose c:when c:otherwise --%>
<% pageContext.setAttribute("score","F"); %>
<c:if test="${pageScope.score eq 'A' }">
优秀
</c:if>
<c:if test="${pageScope.score eq 'C' }">
一般
</c:if>
<hr/>
<c:choose>
<c:when test="${pageScope.score eq 'A' }">
AAA
</c:when>
<c:when test="${pageScope.score eq 'B' }">BBB
</c:when>
<c:when test="${pageScope.score eq 'C' }">CCC
</c:when>
<c:when test="${pageScope.score eq 'D' }">DDD
</c:when>
<c:otherwise>其他</c:otherwise>
</c:choose>
<%-- c:forEach 它是用来遍历集合的
属性:
items:要遍历的集合,它可以是EL表达式取出来的
var:把当前遍历的元素放入指定的page域中。 var的取值就是key,当前遍历的元素就是value
注意:它不能支持EL表达式,只能是字符串常量
begin:开始遍历的索引
end:结束遍历的索引
step:步长。i+=step
varStatus:它是一个计数器对象。里面有两个属性,一个是用于记录索引。一个是用于计数。
索引是从0开始。计数是从1开始
--%>
<hr/>
<% List<String> list = new ArrayList<String>();
list.add("AAA");
list.add("BBB");
list.add("CCC");
list.add("DDD");
list.add("EEE");
list.add("FFF");
list.add("GGG");
list.add("HHH");
list.add("III");
list.add("JJJ");
list.add("KKK");
list.add("LLL");
pageContext.setAttribute("list",list);
%>
<c:forEach items="${list}" var="s" begin="1" end="7" step="2">
${s}<br/>
</c:forEach>
<hr/>
<c:forEach begin="1" end="9" var="num">
<a href="#">${num}</a>
</c:forEach>
<hr/>
<table>
<tr>
<td>索引</td>
<td>序号</td>
<td>信息</td>
</tr>
<c:forEach items="${list}" var="s" varStatus="vs">
<tr>
<td>${vs.index}</td>
<td>${vs.count}</td>
<td>${s}</td>
</tr>
</c:forEach>
</table>
</body>
</html>