【JavaWeb学习笔记】4-JSP核心语法

一、JSP规范(语法)

Sun制定的JSP规范,包含了如何将JSP页面翻译成Servlet。Tomcat中的JSP翻译引擎,就遵循了这个JSP规范。

  • JSP注释
<%-- 这是JSP注释 -->
<!-- 也可以用HTML注释 -->
  • JSP的Java代码块
<%
    int i=5;
    System.out.println("i = "+i);  //被翻译到_jspService()方法中
%>
  • JSP的声明语句块
<!%
    //被放在类体中
    private int i=5;
    public void doSome(){
        System.out.println("---dosome---");
    }
%>
  • JSP的表达式块(表达式没有分号)
<%= a %>
<%= "张三" %>
<%-- out.print(a);
     out.print("张三"); --> 

二、JSP内置对象

在JSP的Java代码块、表达式块中可以直接使用的引用,称为JSP的内置对象。 
之所以可以直接使用是因为这九个对象就是_jspServer()方法的局部变量。

  • pageContext:

后面学EL表达式有用

  • application

application,即ServletContext。
方法:
String getInitParameter():获取web.xml的上下文参数值。
Enumeration getInitParameterNames():获取web.xml的所有上下文参数名称。
void setAttribute(String name,Object object):在ServletContext的域属性空间中,放入数据。
Object getAttribute(String name):从域属性空间中获取指定名称的数据。
void removeAttribute(String name):从域属性空间中删除指定名称的数据。
String getRealPath(String path):获取当前Web应用中指定文件或目录
String getContextPath:获取当前应用在Web容器中的名称。

  • out

继承Writer类,即out就是一个输出流对象。

  • page
filan java.lang.Object page=this; //Servlet对象本身。
  • exception

必须配合page指令使用。

  • 其他对象

request、response、session、config。用法与Servlet相同。

三、JSP指令(directive)

JSP指令的作用是为当前页面做一些基本设置,为当前的页面运行提供基本的环境。

  • page指令

用于设置当前JSP页面的相关信息。一个jsp文件卡宴包含多个page指令

<%@ page pageEncoding="utf-8" %>
<%-- response.setContextType("text/html;charset=UTF-8"); --%>
<% page contentType="text/html" %>
<%-- response.setContentType("text/html") -->
<%@ page import="java.util.Date,java.sql.*" %>
<%-- import java.util.Date; 
    import java.sql.*;
-->
<@ page errorPage="/error.jsp" %>
<%-- 用于指定,当前页面运行过程中发生异常是所要跳转到的页面-->

isErrorPage: <%@ page isErrorPage="true" pageEncoding="utf-8" %>
表示当前页面为一个“错误处理页面”,在_jspService()方法中多了一个exception变量。
可以使用<% exception.printStackTrace(); %>输出错误信息

  • include指令

即包含指令,用于将指定的文件包含的当前JSP文件中。

<%@ include file="/left.jsp" %>

编译后只生成一个.java文件,并不会生成left_jsp.java文件
说明include指令是在编译之前完成的,是在编译之前由JSP翻译引擎完成的,不是在程序运行期完成的。这种包含是一种静态包含,称为静态联编。

四、JSP动作(Action)

JSP动作是指,使用系统定义好的标签来完成本应由Java代码完成的功能。
常用动作:转发动作和包含动作。

  • forward动作
<%-- 只要有forward动作,当前页面的内容都无法显示。 --%>
<jsp:forward page="/next.jsp"/>
  • include动作

include动作用于完成将指定页面包含到当前页面的功能。

<jsp:include page="/left.jsp"/>

编译结果生成两个.java文件。
说明include动作是在运行期完成的,称为动态联编。

静态联编只生成一个Servlet,对资源的消耗少,可以共享同一个变量。
动态联编不能共享变量。

五、EL表达式

Expression Language,表达式语言,是一种在JSP页面中获取数据的简单方式。
在JSP页面的任何静态部分均可以通过 ${expression} 的形式获取到指定的表达式的值

  • 获取数据
	<!-- 从四大域中依次查找数据 -->
	<%
		//pageContext.setAttribute("stu", "张三");
		//request.setAttribute("stu", "张三");
		//session.setAttribute("stu", "张三");
		application.setAttribute("stu", "张三");
	%>
	<!-- 从pageContext依次查找到application域空间,效率低。 -->
	stu = ${stu }

	<!-- 从指定域中获取数据 -->
	<%
		pageContext.setAttribute("some", "pagValue");
		request.setAttribute("some", "reqValue");
		session.setAttribute("some", "sesValue");
		application.setAttribute("some", "appValue");
	%>
	<!-- 从指定域中获取数据,提高效率 -->
	some = ${pageScope.some }
	<br> some = ${requestScope.some }
	<br> some = ${sessionScope.some }
	<br> some = ${applicationScope.some }
	<br>

	<!-- 访问指定对象的属性 -->
	<%
		Student student = new Student("张三", 23);
		request.setAttribute("stu", student);
	%>
	studentName = ${requestScope.stu.name }
	<br> studentName = ${requestScope.stu['name'] }
	<br> studentName = ${requestScope.stu["name"] }
	<br>

	<!-- 获取数组中的元素 -->
	<%
		String[] studentName = { "张三", "李四", "王五" };
		pageContext.setAttribute("names", studentName);
	%>
	studentName[1]=${names[1] }
	<br>
	<!-- 越界不会报错! -->
	studentName[100]=${names[100] }
	<br>

	<!-- 取List中的元素(和数组类似,适用于Map) -->
	<%
		Student student1 = new Student("张三", 23);
		Student student2 = new Student("李四", 24);
		Student student3 = new Student("王五", 25);
		List<Student> students = new ArrayList();
		students.add(student1);
		students.add(student2);
		students.add(student3);
		request.setAttribute("stus", students);
	%>
	<!-- 输出王五 -->
	students[2].name=${stus[2].name }
	<br>
	<!-- 越界不会报错 -->
	students[200].name=${stus[200].name }
	<br>

EL无法输出Set集合的元素。因为Set集合的元素具有无序性,即没有索引的概念。无法索引获取元素。

  • 运算符

EL表达式可以进行各种运算,其中常用的运算有:

除了上诉运算符外,还有一个非常有用的运算符empty,其用法为${empty 变量},结果为布尔值。

<!-- EL表达式运算符 -->
	<%
		pageContext.setAttribute("name", "");
		pageContext.setAttribute("student", null);
		pageContext.setAttribute("list", new ArrayList());
	%>
	<!-- 下面输出结果都为true -->
	xxx变量未定义:${empty xxx}<br> 
	name变量为空字符串:${empty name }<br> 
	student对象为null:${empty student }<br>
	list集合没元素:${empty list }
  • EL内置对象

与代码块表达式类似,EL存在11个内置对象。

pageContext: 与JSP内置对象的pageContext是同一个对象。通过该对象可以获取request、response、session、servletContext、servletConfig

<form action="${pageContext.request.contextPath}/register.do" method="post">
    <!-- -->
</form>

param: 在EL中通过${param.参数名}可获取到请求中指定参数的值

<!-- 例:URL=127.0.0.1:8080/JSP_TEST/index.jsp?name=abc -->
para1m.name=${param.name }<br>
<!-- 若请求中同一参数具有多值 -->
<!-- 例:URL:127.0.0.1:8080/JSP_TEST/index.jsp?hobby=swimming&hobby=reading -->
hobby[0] = ${paramValues.hobby[0] }<br>
hobby[1] = ${paramValues.hobby[1] }<br>
<!-- 获取初始化参数 -->
<!-- web.xml内定义:
    <context-param>
        <param-name>Tooi</param-name>
        <param-value>1<param-value>
    </context-param>
-->
初始化参数Tooi的值为:${initParam.Tooi }<br>
  • 自定义EL函数

步骤: 1、定义函数:

public class StringFunctions {
	public static String lowerToUpper(String source) {
		return source.toUpperCase();
	}
}

2、注册函数:在/WEB-INF目录下,新建一个扩展名为.tld的XML文件

<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
	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"
	version="2.0">
	<tlib-version>1.0</tlib-version>
	<short-name>myfn</short-name>
	<uri>http://www.Tooi.com/jsp/myCustomTld</uri>
	
	<function>
		<name>myLowerToUpper</name>
		<function-class>ELFunction.StringFunctions</function-class>
		<function-signature>java.lang.String lowerToUpper( java.lang.String )</function-signature>
	</function>
</taglib>

<short-name>: 指定该函数库的名称,一个函数库一个名称。
<uri>: 指定函数库对应的URI,用于JSP文件引用。
<name>: 指定将来在JSP使用函数的名称。
<function-class>: 指定该函数定义在那个类中。
<function-signature>: 指定该函数的签名,即指定类中的哪个方法。

3、使用函数

<!-- 引入自定义的标签库 -->
<%@ taglib uri="http://www.Tooi.com/jsp/myCustomTld" prefix="myfn"%>
<!-- 只能使用常量或域属性作为参数 -->
abc=${myfn:myLowerToUpper("abc") }
<%
	request.setAttribute("username", "Tooi");
%>

name=${myfn:myLowerToUpper(username) }
  • JSTL中的EL函数

Apache已经定义好了一套标准的标签库规范,称为JSTL,JSP Standard Tag Libraray,即JSP标准标签库。
1、Apache官网下载:下载地址 

2、JSTL的EL函数标签库
 

3、16个EL函数 

4、EL函数用法:
两个jar文件不能放在/WEB-INF/lib目录下,不需要bulid path

<!-- 引入JSTL函数标准库 -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<body>
	abc=${fn:toUpperCase("abc") }
	<br>
	<%
		request.setAttribute("name", "Tooi");
	%>
	name=${fn:toUpperCase(name) }
	<br>
</body>
  • EL总结

EL不能出现在Java代码块、表达式块灯JSP动态代码部分。
EL只能从pageContext、request、session、application四大域属性空间中获取数据。
EL不会抛出空指针异常、数字访问越界异常。
EL不具有对字符串的处理能力,需要借助JSTL。

六、自定义标签

使用自定义标签替换一个Java代码片段,完成相同的功能,简化代码。

  • 1、定义标签处理器:

定义一个类来完成自定义标签的功能,需要实现接口:javax.servlet.jsp.tagext.SimpleTag。
但已经有javax.servlet.jsp.tagext.SimpleTagSuppord实现了接口,所以只要继承SimpleTagSuppord类。

doTag: 当JSP页面中执行到标签时,由服务器自动调用执行的方法。自定义标签功能的实现都在这个方法中。
getParent: 获取当前标签的父标签的引用。
setJspBody: 由服务器自动调用。服务器会将JSP代码片段传入给当前的Java类。
setJspContext: 由服务器自动调用。服务器会将PageContext对象传入给当前的Java类。注意,PageContext是JspContext的子类。
getJspContext: 获得JspContext,可以转为PageContext
setParent: 由服务器自动调用。服务器会将当前标签的父标签引用传给当前的Java类。

//没有标签体的标签处理器
public class ClientIpSimpleTag extends SimpleTagSupport{
	@Override 
	public void doTag() throws JspException,IOException{
		//获取PageContext对象
		PageContext pageContext = (PageContext)getJspContext();
		//获取客户端IP
		String clientIP=pageContext.getRequest().getRemoteAddr();
		//输出到浏览器
		pageContext.getOut().write(clientIP);
	}
}
//有标签体的标签处理器
public class ToUpperCaseSimpleTag extends SimpleTagSupport {
	@Override
	public void doTag() throws JspException, IOException {
		// 创建一个具有缓存功能的输出流,要求改输出流可以获取到缓存数据
		// 此时的输出流缓存数据为空
		StringWriter sw = new StringWriter();
		// 获取JSP片段,即标签文本对象
		JspFragment jspBody = this.getJspBody();
		// 将标签文本对象写入到输出流中,输出流中就有了数据
		jspBody.invoke(sw);
		// 获取到标准JSP输出流对象
		JspWriter out = this.getJspContext().getOut();
		// 获取到缓存中所存放的标签文本
		String tagText = sw.toString();
		// 将文本数据转换为大写字母
		String upperCase = tagText.toUpperCase();
		// 输出到浏览器
		out.write(upperCase);
	}
}
//有属性的标签处理器
public class IfSimpleTag extends SimpleTagSupport {
	private boolean test;

	public void setTest(boolean test) {
		this.test = test;
	}

	@Override
	public void doTag() throws JspException, IOException {
		if (test) {
			//没有指定输出流,则默认写入到JspWriter中
			this.getJspBody().invoke(null);
		}
	}
}
  • 2、注册标签处理器

在WEB-INF目录下,新建一个扩展名为.tld的xml文件。

<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
    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"
    version="2.0">
    <tlib-version>1.0</tlib-version>
    <short-name>mytag</short-name>
    <uri>http://www.Tooi.com/jsp/customtags</uri>
    <!-- 注册没有标签体的标签处理器 -->
    <tag>
    	<name>clientIp</name>
    	<tag-class>com.Tooi.SimpleTag.ClientIpSimpleTag</tag-class>
    	<body-content>empty</body-content>
    </tag>
    <!-- 注册有标签体的标签处理器 -->
    <tag>
    	<name>toUpperCase</name>
    	<tag-class>com.Tooi.SimpleTag.ToUpperCaseSimpleTag</tag-class>
    	<body-content>scriptless</body-content>
    </tag>
    <!-- 注册有属性的标签处理器 -->
    <tag>
    	<name>if</name>
    	<tag-class>com.Tooi.SimpleTag.ToUpperCaseSimpleTag</tag-class>
    	<body-content>scriptless</body-content>
    	<attribute>
    		<name>test</name>
    		<required>true</required>
    		<rtexprvalue>true</rtexprvalue>
    	</attribute>
    </tag>
</taglib>

<body-content>: 有4个选项:
empty:表示没有标签体。
scriptless:表示有标签体,版标签不能包含Java代码与Java表达式。可以包含EL表达式。
JSP:表示会将标签体的文本内容原样显示在浏览器,只要继承TagSupport类可以使用,继承SimpleTagSupport类使用会报错。
tagdepengent:会将标签体原样显示在浏览器,EL表达式也会显示原样。

有属性的标签必须添加<attribute/>子标签:
<name/>:指定属性名,标签处理器必须有相同的属性名。
<required/>:指定该属性是否是必须的,true为必须。
<rtexprvalue/>:指定该属性值是否可以来自运行时表达式的值,true表示可以。

  • 3、使用自定义标签
<!-- 导入自定义标签库 -->
<%@ taglib uri="http://www.Tooi.com/jsp/customtags" prefix="mytag" %>
<!-- 使用自定义标签 -->
<mytag:clientIp/>
<%
	pageContext.setAttribute("name", "Tooi");
%>
<mytag:toUpperCase>name= ${name }</mytag:toUpperCase>
<%
	pageContext.setAttribute("male", true);
%>
<mytag:if test="${male }">男</mytag:if>
  • 标签处理器实例的生命周期

标签处理器是是多例的。每执行一次自定义标签,都会创建一个标签处理器的实例。该标签执行完毕,则标签处理器实例销毁。

七、JSTL

JSP Standard Tag Library,即JSP标准标签库
核心标签库: 主要用于完成基本的逻辑运算。
格式化标签库: 主要用于完成日期、数字的格式化显示。
EL函数标签库: 定义螺杆EL函数。
SQL操作标签库: 完成SQL操作,不使用了,已经有Java代码完成。
XML操作标签库: 不使用,由Java代码完成

  • 核心标签库

c:set 用于变量的定义,并将变量放入指定的域属性空间;为Bean对象的属性赋值;为MAP的key与value赋值

<!-- 用于变量的定义,并将变量放入指定的域属性空间 -->
	<c:set value="张三" var="name" scope="request" />
	name = ${requestScope.name } <br>
	
	<!-- 为Bean的属性赋值 -->
	<jsp:useBean id="student" class="com.abc.beans.Student" scope="session"></jsp:useBean>
	<c:set value="李四" property="name" target="${sessionScope.student }"/>
	<c:set value="24" property="age" target="${sessionScope.student }"/>
	student = ${sessionScope.student }<br>
	
	<!-- 为MAP的key与value赋值 -->
	<%
		Map<String,String> map=new HashMap();
		pageContext.setAttribute("map", map);
	%>
	<c:set value="男" property="gender" target="${map }"/>
	<c:set value="1234567" property="mobile" target="${map }" />
	gender = ${map.gender }<br>
	monile = ${map.mobile }<br>
运行结果:
name = 张三 
student = Student [name=李四, age=24]
gender = 男
monile = 1234567

c:remove 从域属性空间中删除变量。标签不常用。

<c:remove var="name" scpoe="request" />
name = ${requestScope.name }<br>

c:out 用于在页面上输出EL表达式的值,不常用。

<!-- c:out -->
<c:set var="city" value="<h2>北京<h2>" /> 
city1= <c:out value="${city }" /><br>
city2= <c:out value="${city }" escapeXml="false" /> <br>
country1= <c:out value="${country }" default="中国"/> <br>
country2= ${country } <br>

escapeXml:是否忽略HTML标签,默认为true,忽略按照原样输出
default:指定默认值,若要输出的变量不存在则输出默认值。

c:catch: 用于捕获异常,不常用。

<c:catch var="ex">
	<!-- Student类没有score属性 -->
	double score=${student.score }
</c:catch>
ex=${ex.meeeage }<br> 

c:if: 用于对的条件的判断。

<c:set var="user" value="admin"></c:set>
<c:if test="${user=='admin' }" >
	<a href="">进入管理页面</a>
</c:if>

c:choose: 实现多分支判断

<c:choose>
	<%--共一页的情况 --%>
		<c:when test="${pageCount==1 }">
			首页		上一页	下一页	末页
		</c:when>
	<!-- 当前是第一页的情况 -->
		<c:when test="${pageNo==1 }">
			首页		上一页	<a href="#">下一页</a>	<a href="#">末页</a>
		</c:when>
	<!-- 当前是最后一页的情况 -->
		<c:when test="${pageNo==pageCount }">
			<a href="#">首页</a>		<a href="#">上一页</a>	下一页	末页
		</c:when>
	<!-- 当前是中间页的情况 -->
		<c:otherwise>
			<a href="#">首页</a>		<a href="#">上一页</a>	<a href="#">下一页</a>	<a href="#">末页</a>
		</c:otherwise>
</c:choose>

c:forEach:

	<%
		Object[] citys={"北京","上海","广州"};
		pageContext.setAttribute("citys", citys);
	%>
	<c:forEach items="${citys }" var="city">
		${city }<br>
	</c:forEach>
	<!-- 指定遍历索引,从0开始 -->
	<%
		Object[] countrys={"0中国","1美国","2德国","3英国","4法国",,"5日本","6韩国"};
		pageContext.setAttribute("countrys", countrys);
	%>
	<c:forEach items="${ countrys }" var="country" begin="1" end="2">
		${country }<br>
	</c:forEach>
	<!-- step:指定遍历时的步长 -->
	<c:forEach items="${ countrys }" var="country" begin="1" end="5" step="2">
		${country }<br>
	</c:forEach>
	运行结果:
	    1美国
	    2英国
	    5日本
<!-- 有很多高级应用,自行百度。 -->
  • 格式化标签库

fmt:formatDate: 用于使用不同的模式格式化日期

	<%
		Date now = new Date();
		request.setAttribute("now", now);
	%>
	<form action="">
		<!-- 直接显示在页面 -->
		<fmt:formatDate value="${now }" pattern="yyy-MM-dd"/> <br>
		<!-- 格式化的结果显示在表单元素中 -->
		<fmt:formatDate value="${now }" var="birth" pattern="yyyy-MM-dd"/>
		<input type="text" name="birthday" value="${birth }">
	</form>

value:将要格式化的数据
pattern:格式化的模式。
var:格式化后字符串所存放的变量名。
scpoe:变量存放的位置。默认page。

fmt:paresDate: 用于将指定的字符串转换为日期类型。

<!-- 转换后的日期类型直接显示在页面 -->
	<fmt:parseDate value="1949-10-01" pattern="yyy-MM-dd"></fmt:parseDate> <br>
	<!-- 将指定的日期字符串转换为日期类型,并存放到指定的变量中 -->
	<fmt:parseDate value="1949-10-01" var="countryBirth" pattern="yyyy-MM-dd"></fmt:parseDate>
	counntryBirth = ${countryBirth }<br>

fmt:formatNumber: 用于按照格式对数字进行格式化。
 

	<!-- 格式化后结果直接显示在页面 -->
	<fmt:formatNumber value="${12345.678 }" minIntegerDigits="6"
		maxFractionDigits="2"></fmt:formatNumber>
	<br>
	<fmt:formatNumber value="${12345 }" minFractionDigits="2"
		groupingUsed="false"></fmt:formatNumber>

fmt:parseNumber: 用于将指定字符串转换为数值类型

	<!-- 将解析后的结果直接显示 -->
	<fmt:parseNumber value="123,456.789" integerOnly="true"></fmt:parseNumber><br>
	<fmt:parseNumber value="123,456.789" integerOnly="false"></fmt:parseNumber><br>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值