Java Server Page (JSP)
原理解析
JSP 就是一个Java代码和HTML标签一起使用的页面,其本质上就是一个 Servlet
JSP 被服务器解析后,会先找是否有 index.jsp/index.html/index.htm 页面(在TOMCAT Web.xml 可以看到),然后将 index.jsp 页面转换为 _index.java 文件,最后转换为 _index.class 文件,将 .class 文件发送给客户端,所以其本质就是 Servlet(IDEA WEB \work\Catalina\localhost\book\org\apache\jsp\pages\user)
服务器开启后,打印在控制台上的第一条文件路径可以找到被解析的 index.jsp 的 .java 和 .class 文件。
在 .java 文件中,可以看到里面的内容,就是一个 Servlet,只不过有脚本帮我们自动转换我们的 java 代码,并且输出到页面上了,看下面
下面我们就逐个的讲解JSP的每个信息
关于 JSP 的脚本信息,其实就是解析 Java 语句的脚本,定义格式和 Java 规范一样。
下面我们就挨个的讲解每个脚本
定义的Java代码,会定义在_index.java中Server方法中,用分号结尾。
<% 代码; %> // 只要可以定义在 server 方法中的语句,都可以写
这个里面只能定义变量,且在 _index.java 中的位置是在 类的成员变量 上。
<%! int i; %> // 只允许定义变量
最后这个,就是一个 System.out.println("@语句"); 我们在这个脚本里面定义的所有东西,相当于存放在 @语句 的这个位子当中
<%= 输出的东西; %>; // 注意,这个脚本,一个里面只能定义一条语句,不需要分号
关于指令的讲解
指令,主要用于配置 JSP 页面,导入资源文件
格式:<%@ 指令名称 属性名1=属性值2…%>
此指令主要用于配置整个JSP页面的大部分信息(不过在实际开发中,应该少用这个指令,因为一个JSP又有标签又有代码,看起来很费力费事)
<%@ page ContextType="text/html;charset=utf-8" language="java"%>; // 这个是一般格式
Page 一栏指令的属性:
ContextType:主要用来配置JSP页面的编码内容,其还需配置下面一样东西
pageEncoding=“utf-8”; 这个指令是让低级的IDE可以配置当前页面的字符集,因为 ContextType 只能高级IDE解析
import:这个是用来导包的,和java里面的导包一样
errrorPage=“资源路径”; 这个是当 JSP 页面发生异常时会跳转过去的设置,主要目的是不让用户看到异常界面
isErrorPage=“true/false”; 这个就是标识当前的JSP页面时错误页面,设置 true 可以解锁一个 Exception 对象
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
下面这个指令主要用于导入一些重复页面,比如某官网的页眉都是重复的,就可以创建一个设置页眉的jsp,然后再home页面直接导入即可
<%@ include file="资源路径"%>; // 资源路径不需要加
这此指令主要用于导入标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>;
属性:
prefix=“自定义名称,一般用C即可”
url=“http://java.sun.com/jsp/jstl/core”,一般我们用这个标签库即可
此标签库,和HTML标签一样使用
<c:XXX>; // 我们后面会具体的介绍jstl标签库
下面我们讲内置对象,其实就是不需要创建的对象,一共九个
以下四个对象,均可用 set/get/remove Attribute(); 方法
pageContext=PageContext; // 作用范围于当前页面,在<%%>脚本里创建属性,并且是用来获取其它8个对象的对象,用getXXX();
request=HttpServletRequest; // 作用范围于一次请求的多个资源(转发),跟正常java代码一样编写
session=HttpSession; // 作用返回于一次会话的多个请求,获取服务器中的 Session
application=ServletContex; // 作用范围最广,服务器开启后存在,关闭后消逝,所有用户的共享数据
以下5个对象是具体操作的对象
response=HttpServletResponse; // 响应对象,和java代码一样使用
page=Object; // 相当于java代码中 this
out=JspWriter; // 输出对象,输出到页面上
config=ServletConfig; // Servlet的配置对象
exception=Trowable; // 异常对象,一般只有当 isErrorPage=true; 时才可以使用
JSP重要的两部分,EL表达式和JSTL,这节我们讲EL表达式,JSTL放在下面
EL表达式中只能获取存储域中的 value,其获取依据是 key
语法:${域名称.键};
域名称,其实就是变量名变了,后面+Scope。域名称也是隐式对象,其中有一个特殊的隐式对象,在下面
pageScope = pageContext
reuqestScope = HttpServletRequest
SessionScope = HttpSession
application = ContextServlet
如:${sessionScope.key}
特殊:${pageContext.request.contextPath()} 这个可以用来获取虚拟目录,比较常用,需要注意
运算符
算术运算符:+ - * /(div) %(mod)
比较运算符:> < >= <= == !=
逻辑运算符:&&(and) ||(or) !(not)
空运算符:empty
${empty sessionScope.list} list是key,其value是一个list集合,这个就是判断其value是否为空,且长度是否为0
${not empty sessionScope.list} 这个就是取反的意思,判断其是否不为 null,且长度>0
EL表达式,在JSP中默认是可以使用的,不过我们也可以手动设置其忽视
isELIgnored = "true"; // 将这个属性设置在 page 指令里面,就可以忽视EL表达式了
下面挨个讲解获取的方式,可以获取 对象、list集合、map集合这三种格式,我们先在下面创建jsp页面,里面对各种参数进行了创建,大家可以复制到编译器中自行获取一下
<%
User user = new User("张江苏","男",16,new Date);
request.setAttribute("user",user);
List<User> list = new ArrayList();
list.add(new User("赵中国","男",17,new Date));
list.add(new User("华天下","女",21,new Date));
request.setAttribute("list",list);
Map<String,User> map = new HashMap();
map.put("name","张江苏");
map.put("user",user);
request.setAttribute("map",map);
%>
注意,在获取的时候,可以不加域名称,这样系统就会从最小的域开始往上找个key,直到找到为止,如果没有获取到key,则输出空字符串
但是如果获取key之后,又获取了一个对象里面的get/set方法,且没有这个方法的话,就会爆一个异常。
// 先获取普通的属性
${域名称.key.属性名}; // 如果有get/set方法,不需要写get/set前缀
${requestScope.user}; // 直接加key就可以,这个获取的结果是一个 哈希地址值
${user.name}; // JavaBean中定义了get/set方法,JSP会自动解析省略掉get前缀和set前缀,这个获取的结果就是 16
// 获取list集合
${域名称.key[index]}; // index就是编号,0获取第一个元素,以此类推
${list[0]}; // 这里输出的就是 第一个user对象的 哈希地址值
${list[1].name}; // 这里输出的就是 张三
// 获取map集合,map集合的获取比较麻烦,并且有两次,个人推荐第二种,可读性高
${域名称.key.map的key}; // 这个是第一种方式,有了key后,获取的方式就和前面没有两样
${域名称.key["map的key"]}; // 第二种方式,可读性比较高
${map.name}; // 获取到的值为 张江苏
${map["user"].birthday}; // 这里输出的就是 date 日期格式,我们也可以在Bean中定义一个格式化日期的方法,直接调用那个也可以
最后我们要讲的就是JSTL了,它其实就是一个标签库,可以通过 taglib 导入
JSTL 标签库,里面有三种标签我们简单了解下,if、choose、foreach
首先我们讲if。if里面有个属性需要注意
text="这个里面接收 boolean 表达式,可以用 EL表达式的运算符"
如果text=true,则输出标签里面的内容,否则不输出
但是要注意,if标签没有else,所以如果需要判断第二种情况,就必须再重新创建一个 if 标签
完整的代码
<c:if text="${empty list}"></c:if>; // 这个标签就是判断list的value的值是否为空
下面我们讲 choose
choose里面有两个属性,需要我们注意
when text=""; when 相当于 case,后面跟着判断条件
otherwise; 这个就相当于 default
完整代码,日期案例
<c:choose>
<c:c:whenwhen text="${number == 1}">星期一</c:when>;
<c:c:whenwhen text="${number == 2}">星期二</c:when>;
<c:c:whenwhen text="${number == 3}">星期三</c:when>;
<c:c:whenwhen text="${number == 4}">星期四</c:when>;
<c:c:whenwhen text="${number == 5}">星期五</c:when>;
<c:c:whenwhen text="${number == 6}">星期六</c:when>;
<c:c:whenwhen text="${number == 7}">星期日</c:when>;
<c:otherwise>其他数值</c:otherwise>
</c:choose>;
最后,我们讲一下 foreach
foreach 有两种模式,一种循环普通的数值,一种循环集合这类的值,里面有许多属性需要注意
第一种模式需要的属性:
begin = 开始值; 相当于 i = 开始值
end = 结束值; 相当于 i <= 结束值
var = 临时变量; 相当于 int i
step = 步长; 相当于 i++;,这里 step = 1,就是i++
varStatus = “不和临时变量冲突的变量名,这里取 s”; 这个主要是为了服务下面两个属性
s.index; 这个的意思就是索引,如果是 i+2,从0开始,循环3次,那么s.index值分别为:0,2,4
s.count; 就是计数循环了多少次
第二种模式需要的属性:
items = 容器对象; 就是需要遍历的对象
var = 临时变量; 像 String str;
varStatus = “不和临时变量冲突的变量名,这里取 s”; 这个主要是为了服务下面两个属性
==s.index;==这个的意思就是索引,如果是 i+2,从0开始,循环3次,那么s.index值分别为:0,2,4
s.count; 就是计数循环了多少次
下面通过这些例子来展现
<%
ArrayList<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
list.add("赵六");
request.setAttribute("list",list);
%>
<c:forEach begin="0" end="5" var="i" step="2" varStatus="s">
${list[i]} ${s.index} ${s.count} <br/> // 只会输出 王五 2 2,4 3
</c:forEach>
<%= "分割线---------------------分割线" %>
<c:forEach items="${list}" var="str">
${str} <br/> // 循环打印 list 集合中的数据
</c:forEach>;
到这里,我们关于JSP的一个入门学习知识已经学完了。