JSP(Java Server Pages)是由sun公司定义的一种用于开发动态web资源的技术,遵循JSP/Servlet规范。相当于能够执行Java语句的Html页面,从而能够输出动态内容,本质上就是一个封装好的Servlet
JSP原理
JSP文件无法被直接执行,其遵循以下执行步骤:
(1)服务器引擎将JSP内容翻译成纯Java代码,并进行编译(可以查看目录/work/Catalina/localhost/项目名/org/apache/jsp
,里面有对应的.java
和.class
文件)
(2)执行编译后生成的.class
文件
(3)当.class
文件存在且JSP内容没被修改时,则不会执行上面步骤,而是直接执行.class
文件
JSP语法
脚本元素
主要分有三种:
1.脚本段:<% java代码 %>
,可以放各种java代码,这里面的变量相当于方法内部的临时变量
2.声明段:<%! 变量/方法声明 %>
,可以声明多个变量和方法,用分号隔开,这里面的变量相当于类的成员变量,在当前整个JSP页面中有效
3.表达式:<%=表达式%>
,输出一个表达式结果,其本质就相当于out.print(表达式)
,所以后面不要有分号
注:
输出方式有两种,一个是表达式输出,还有一个是通过out.print()
输出,从上面可以知道表达式输出的原理就是一个包装好的out.print()
方法,因此对于输出表格的一列,前者可能是:<td><%=xxx%></td>
,而后者则是:out.print("<td>xxx</td>")
,可以看出前者很好的将HTML代码和JSP代码分离,而后者不行,所以尽量使用第一种方法
注释
主要分为以下几种:
1.<!-- -->
:显式注释,直接用HTML代码的注释,前端可见
2.//
//* */
:隐式注释,java代码自带的注释,只能在脚本段(<% %>
)中用,前端不可见
3.<%-- --%>
:隐式注释,JSP自带的注释,前端不可见
三个指令
指令语法:<%@指令 属性1=值 属性2=值 ...%>
,主要指令有以下几个:
1.page
指令
用于定义JSP的全局属性,其下有常用属性如下:
(1)contentType
:有设置MIME类型(浏览器的打开方式,一般设置成html),举例:
<%page contentType="text/html; charset=GBK" %> //设置编码
(2)pageEncoding
:设置JSP引擎的翻译编码
(3)import
:导包属性,导入可使用的java类,是page
下唯一一个可以多次设置的属性,如果要导入多个包,则用逗号隔开,举例:
<%@page import="java.util.*,java.net.Socket"%>
(4)errorPage
:当原来的JSP页面出现错误时,将会自动跳转到指定页面,默认是相对路径,如果以/
开头则代表从项目根目录开始的路径,举例:
<%@ page errorPage="error.jsp" %>
(5)isErrorPage
:是否为错误页面,默认是false
,如果设置为true
则会多一个Throwable
对象exception
,可以用来查看错误信息,举例:
<%@ page isErrorPage="true" %>
...
<%=exception.getMessage()%>
(6)isELIgnored
:是否忽略EL表达式,默认为false
2.include
指令
用于在JSP页面中静态包含一个文件,可以是JSP、HTML、TXT文件等,也可以是一段Java代码,使用该指令的JSP页面在翻译前会自动插入包含的文件或者代码,其中该指令有两种语法:
<%@include file="xxx.html" %> //第一种
<jsp:include page="xxx.jsp" /> //第二种,不是指令方法,属于动作元素
前者为静态包含文件,其会在翻译JSP之前就把包含文件的内容加进来,即合并成一个文件,然后一起翻译、编译和执行;后者为动态包含,其会先翻译、编译和执行原来的JSP文件,当执行到包含文件的语句时,则会对该文件也进行翻译、编译和执行,并且还可以在包含文件时传入参数,举例:
<jsp:include page="xxx.jsp"> //按成对标签情况结尾没有斜杠
<jsp:param name="xxx" value="xxx" /> //单标签情况结尾用斜杠结束
...
</jsp:include>
3.taglib
指令
在页面中导入JSTL标签库,替换JSP中的java代码片段,包括if、forEach、import等
附:JSTL标签
Java Server Page Standard Tag Library,JSP标准连接库,主要用于简化Java代码,导入库方式:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> //导入标签库,并取名为c
有以下核心标签库:
(1)set
:声明变量,有var
、value
、scope
三个属性
(2)out
:输出,有value
和default
属性
(3)remove
:移除变量,有var
属性,使用举例:
<c:set var="name" value="${1}" scope="page"/> //name=1
<c:out value="${name}"/>
<c:remove var="name"/>
<c:out value="${name}" default="nothing"/> //name不存在,输出nothing
(4)if
:判断语句,当test
属性的内容为true
即输出,举例:
<c:if test="${6>5}">
fasfdsgs
</c:if>
(5)choose
:相当于switch
语句,里面用when
标签来选,举例:
<c:set var="score" value="${61}" />
<c:choose>
<c:when test="${score<60 && score>=0}">不及格</c:when>
<c:when test="${score>=60 && score<80}">及格</c:when>
<c:when test="${score>=80}">优秀</c:when>
<c:otherwise>其他</c:otherwise>
</c:choose>
(6)forEach
:循环用,有var
、begin
、end
、step
等属性,举例:
<c:forEach var="i" begin="1" end="10" step="2">
${i}
</c:forEach>
该标签下还有items
属性,主要用于存放迭代器和数组等,还有varStatus
属性代表给迭代器取名,则该迭代器下有自带的四个属性(通过getter方法调用):index
(从0开始的索引),count
(从1开始的计数),first
/last
(是否为第一个/最后一个),举例:
<%
ArrayList li = new ArrayList();
li.add("aaa");
li.add("bbb");
li.add("ccc");
String[] s = { "dsa", "Fsdg", "Hrhe" };
request.setAttribute("list", s);
%>
<table border="1">
<c:forEach items="${list}" var="l" varStatus="vs">
<tr>
<td>${l}</td>
<td>${vs.index}</td>
<td>${vs.count}</td>
<td>${vs.first}</td>
<td>${vs.last}</td>
</tr>
</c:forEach>
</table>
结果为:
dsa 0 1 true false
Fsdg 1 2 false false
Hrhe 2 3 false true
六个动作
与指令元素不同,动作元素在请求处理阶段起作用,使用XML语法,语法格式:
<jsp:动作 属性=值 ... /> //格式1
<jsp:动作 属性=值 ... >...</jsp:动作> //格式2
可以看出在格式2中可以多个动作元素进行嵌套使用。常用的有以下几种:
1.<jsp:include page="" />
:动态包含文件
2.<jsp:param name="" value="" />
:设置请求参数值,相当于url?name=value
3.<jsp:forward page="" />
:跳转到页面,为服务端跳转,假如后面还有语句,则不会执行
4.<jsp:useBean id="实例化对象" class="对象对应的包.类" scope="对象使用范围" />
:用于创建javabean对象,举例:
<jsp:useBean id="user" class="cn.aaa.User" scope="page" />
实质上就相当于:
<%
User user = new User();
%>
5.<jsp:setProperty name="javabean对象" property="属性" />
:设置javabean对象属性值,其中有四种方法设置:
<jsp:setProperty name="XXX" property="*" /> //根据参数名称自动进行设置,利用了反射机制,通过传递的参数找到对应方法
<jsp:setProperty name="XXX" property="yyy" /> //指定属性
<jsp:setProperty name="XXX" property="yyy" param="zzz" /> //将指定参数的值给指定属性
<jsp:setProperty name="XXX" property="yyy" value="zzz" /> //设置指定值给指定属性
第一种方法将根据前端传来的参数名称自动匹配,举例:
javabean对象:
public class User {
String name;
String password;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
表单数据:
<form action="index.jsp" method="post">
<input type="text" name="name">
<input type="password" name="password">
<input type="submit" value="submit">
</form>
jsp中:
<jsp:useBean id="u1" class="com.aaa.User" />
<jsp:setProperty property="*" name="u1"/>
<jsp:getProperty property="name" name="u1"/>
<jsp:getProperty property="password" name="u1"/>
结果将会自动设置name和password的值并获取。
6.<jsp:getProperty name="javabean对象" property="属性"/>
:获取指定对象属性
九大内置对象
Java中一般使用对象前需要进行实例化,而下面的9个对象则可以无需实例化直接调用,即内置对象
1.pageContext
当前页面上下文,其可以获得request
/session
等对象,因此也可以操作requset
/session
/application
的数据,常用方法:
(1)getRequest()
:获取当前页面的request
对象,其他几个对象也都可以通过相应的get方法获得,如:getResponse()
、getServletContext()
、getOut()
等
(2)setAttribute()
:设置属性值,还有对应的getAttribute()
和removeAttribute()
,但和其他的属性操作方法不同的是,这三个方法可以比原来都多1个参数,用来设置作用域,举例:
pageContext.setAttribute("aaa", "bbb", pageContext.APPLICATION_SCOPE); //提供了四个作用域常量,分别对应数字1-4
(3)findAttribute()
:和getAttribute()
一样是获取属性,但是该方法可以无视作用域,依次从page
->request
->session
->application
里面查找,找到则取值并结束查找
(4)forward()
:跳转
(5)include()
:包含
2.request
常用方法:
(1)getParameter()
:接收表单参数
(2)setCharacterEncoding(编码)
:上面的方式直接接收数据容易出现乱码,于是最好通过该方法先设置接收编码,举例:
<% String name = request.getParameter("username"); %>
(3)getParameterValues()
:当遇到像复选框这样有多个参数的情况,上面的方法只能接收到第一个参数,因此需要使用该方法来接收一组参数,返回的是个数组
(4)getRemoteAddr()
:取得客户端的IP地址
(5)getCookies()
:获取所有cookie对象,返回一个cookie数组,举例:
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int i = 0;
Cookie cs[] = request.getCookies();
for (Cookie c : cs) {
System.out.println(c.getName() + ":" + c.getValue());
}
response.addCookie(new Cookie("name", "" + i++));
}
(6)getSession()
:返回一个HttpSession
对象
3.response
常用方法:
(1)setHeader(name, value)
:设置头信息的内容,获取头信息则可以用getHeader(name)
,如果要获取所有头信息名字,则用:getHeaderNames()
,其中有个定时跳转的属性为refresh
,举例:
response.setHeader("refresh","1"); //1秒刷新一次
response.setHeader("refresh","2;URL=xxx.jsp"); //2秒后跳转到xxx.jsp,此处为客户端跳转
(2)sendRedirect(url)
:重定向到页面,为客户端跳转,并且如果后面还有语句,则会在后面的语句都执行完后才进行跳转,也可以通过设置响应头来实现。
(3)addCookie(cookie)
:给客户端设置cookie,需要建立个Cookie
对象来设置cookie,举例:
Cookie c1 = new Cookie("name","aaa");
Cookie c2 = new Cookie("password","bbb");
response.addCookie(c1);
response.addCookie(c2);
(4)setContentType(type)
:设置内容的返回类型
4.session
对于服务器来说,每一个上网者是通过session id来区分的,而该id是用户第一次连接到服务器时服务器自动分配的,常用于系统登录中。有以下常用方法:
(1)isNew()
:是否为新session
(2)getId()
:返回session id
(3)invalidate()
:让session失效
5.application
即Servlet中的ServletContext
,常用方法:
(1)getRealPath()
:获取虚拟目录对应的真实路径
注:
一般很少直接用application
,而用getServletContext()
来表示application
6.config
ServletConfig对象
7.out
相当于PrintWriter
对象,即输出页面信息用的
8.page
当前Servlet实例对象,即this
9.exception
当设置isErrorPage
为true
时才存在,可以输出错误信息
四大域对象
属性范围即设置的属性可以在经过多少个页面后仍可访问的范围,范围越大,越影响性能
1.page
仅能在当前页中取得,通过pageContext
来设置
2.request
在一次服务器的跳转中有效,所以只要是服务器跳转,就可以将属性一直传递(所以使用超链接跳转则属性消失)
3.session
一个用户设置的内容,只要和该用户相关的页面都可访问,所以不论怎么跳转都可以取到值,但是新开一个浏览器,则无法取得属性
4.application
整个服务器上设置的属性,所有人都可以访问,但是服务器一旦关闭,该属性也会随之消失,并且因为范围太大,影响效率,且不安全,尽量少用
属性操作
对于上面的几种属性范围,都提供了以下的几个属性操作方法:
(1)setAttribute(name, value)
:设置属性
(2)getAttribute(name)
:获取属性,返回Object
对象,需要进行强转
(3)removeAttribute(name)
:删除属性
使用举例:
<%
pageContext.setAttribute("name", "aaa"); //设置page属性
%>
EL表达式
expression language,即表达式语言,用于简化java代码,是JSP中获取数据的一种规范
格式及原理
格式一——获取域对象数据
${内容}
举例:
<%=request.getAttribute("aaa") %>
<%=session.getAttribute("aaa") %>
那么上面两个语句都可以用下面这一句来表示:
${aaa}
但有点不同的是如果获取的数据不存在,则不是null
,而是空字符串。从以上可以发现EL表达式的底层代码差不多就是:
out.print(pageContext.findAttribute("aaa") != null?pageContext.findAttribute("aaa"):"");
格式二——获取数据属性
${对象.xxx}
${对象["xxx"]} //用单引号也可以
对于获取的数据如果是对象,则可以用.属性
或者["属性"]
来获取属性,如果获取的属性还是个对象,还能继续用该方法继续往下获取属性...但这些表达式获取属性的本质是调用了对象的getter方法,而并非直接调用属性。
两种获取属性区别:
前者能做到的,后者都能做到,但是在比如列表索引下标时,只有后者能够做到
格式三——判空运算
${ empty 内容}
判断内容是否为空,是则为true
,举例:
<%
request.setAttribute("l1", new ArrayList());
request.setAttribute("l2", new String[10]);
request.setAttribute("l3", "");
%>
${empty l1} //空列表,为true
${empty l2} //10个null的数组,为false
${empty l3 ? "空字符串":"非空字符串"} //空字符串
格式四——引用隐式对象
${隐式对象.内容}
可以获得指定对象的数据,举例:
<%
pageContext.setAttribute("aaa", "aaa", 1);
pageContext.setAttribute("aaa", "bbb", 2);
pageContext.setAttribute("aaa", "ccc", 3);
pageContext.setAttribute("aaa", "ddd", 4);
%>
${applicationScope.aaa} //指定获取application对象的aaa,因此输出ddd
${param.aaa} //url?aaa=asd,则输出asd
其中其包括11个隐式对象:
(1)pageContext
(2)pageScope
:页面范围的数据
(3)requestScope
:请求范围的数据
(4)sessionScope
:会话范围的数据
(5)applicationScope
:应用范围的数据
(6)param
:一个请求参数,相当于request.getParameter()
(7)paramValues
:重名请求参数(如多选框)
(8)header
:请求消息头
(9)headerValues
:重名请求消息头
(10)initParam
:web.xml的全局参数
(11)cookie
:cookie对象的name