何为JSP?
JSP全称是Java server page。是一种在html中嵌入Java代码、来产生动态页面的web技术。讲道理的话,JSP就是一种servlet。
JSP的工作原理:
Web服务器在收到浏览器对JSP的访问请求后,把JSP翻译成一个Servlet。翻译的规则是这样的,所有的html部分,使用out.write()输出,所有JSP代码原封不动的放到servlet中。那么,这个out又是什么呢?我们打开apache-tomcat-6.0.45\work\Catalina\localhost\Day08\org\apache\jsp,可以看到jsp翻译成的servlet。其service有如下一段:
public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException {
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
JspWriter _jspx_out = null;
PageContext _jspx_page_context = null;
……
}
这其中就有九大 隐式对象中的八个,(另外的一个在下面的JSP中指令中出现)。
JSP的最佳实践:
JSP可以用来接受和处理请求(因为他也会被翻译成servlet嘛),但是,这不是JSP的最佳实践。
一般来说,JSP用来做显示的模板,而Servlet用来处理请求产生数据。
JSP的语法:
- 模板元素
- 脚本表达式
- 脚本片段
- JSP注释
- JSP指令
- JSP内置对象
- JSP标签
- 查找JSP中的错误
1。 模板元素:jsp中的html标签,他们构成了JSP的基本骨架。
2。脚本表达式: 用于做输出。
<%= “输出一端话” %>
3。脚本片段:用于放Java代码。
<% new Date(); %>
4。JSP注释:注释JSP文件中的内容
<%– –%>
一定要区别html的注释
JSP和html的注释区别,看如下代码:
<body>
下面有一段JSP注释<br>
<%--
<a>点我啊</a>
--%>
下面有一段html注释<br>
<!--
<a>点我啊</a>
-->
</body>
虽然我们在访问时,两端注释的内容都不会被显示。但是,你查看一下”网页源代码”。
结果:
<body>
下面有一段JSP注释<br>
下面有一段html注释<br>
<!--
<a>点我啊</a>
-->
</body>
所以啊,JSP代码是给服务器看的,服务器看到这种注释就不会理他,不做out.write(),但是他会理html的注释。而浏览器不去理html注释,遇到html注释不做解析。
此外,JSP的注释可以用来注释html的代码,而html的注释不可以注释JSP的代码。
5. JSP指令
这是个大问题,我们得慢点说。哎~
JSP指令 是给JSP引擎使用的指令。(JSP引擎就是将JSP翻译成Servlet的程序)。JSP的基本语法满足<%@ 指令类型 name="value" %>
。
JSP2.0规范中 指令的类型有 page、include、taglib
page指令
page指令作用于整个JSP,为了增强阅读性,一般把page指令放在JSP的头部。
//默认值放在前面
<%@
page
[language="java"]
[extends=""]
[import=""]
[session="true | false"]
[buffer="8KB | none | sizeKB"]
[autoflush="true | false"]
[isThreadSafe="true | false"]
[info=""]
[errorPage="relative_url"]
[isErrorPage="false | true"]
[contentType="text/html;charset=UTF-8"]
[pageEncoding="UTF-8"]
[isELIngored="true|false"]
%>
->language=”java” 说明在JSP嵌入的是何种编程语言。
->extends=”” 翻译成的Servlet继承哪个父类。
->import=”” 导入哪些包。
->session=”true | false” 是不是创建session对象。
->buffer=”8KB” 服务器在向浏览器回写数据时,是使用多大的缓冲。autoflush=”true | false “是否自动将缓冲写出。
->isThreadSafe=”true | false “是不是线程安全的,是否实现SingleThreadModel接口。
->info=”” 携带一些数据(卵用)。
->errorPage=”relative_url” 设置错误处理页面
除了在JSP中声明错误处理页面,我们还可以在web.xml中配置错误处理的页面、以及错误代号的处理页面。如下:
<error-page>
<exception-type>java.lang.ArithmeticException</exception-type>
<location>/errors/error.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/errors/error404.jsp</location>
</error-page>
->isErrorPage=”false | true ” 是不是错误处理页面,是的话将会向servlet传递exception
在JSP翻译成的Servelt的service方法中会出现如下:
Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request);
if (exception != null) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
这就是九大隐式对象的最后一个,面试题会考你有哪九个?一般都会丢掉最后这个。
->contentType=”text/html;charset=UTF-8” 设置页面的编码,这是给浏览器的。
->pageEncoding=”UTF-8” 设之页面的保存编码,这是给JSP引擎看的,告诉JSP引擎在翻译的时候将JSP翻译时查那个码表。
->isELIgnored=”true | false ” 忽不忽略EL表达式
include指令
顾名思义,就是把另一个JSP页面包含进来。看如下代码:
<body>
<%@ include file="/public/head.jsp"%>
<%= "aaaaa<br/>" %>
<%@ include file="/public/foot.jsp"%>
</body>
这样页面的内容就包含进来了。要理解我们使用页面包含的好处,我们的网站使用统一的页头和页尾,当我们想换掉所有的页头和页尾,我们为了可维护性,就把页头和页尾格式都使用一个JSP。
注意,除了include包含指令,我们还可以使用request的getRequestDispatcher(“relative_url”).include(request,response);
<%
request.getRequestDispatcher("/public/head.jsp").include(request, response);
response.getWriter().write("This is my JSP page. <br>");
request.getRequestDispatcher("/public/foot.jsp").include(request, response);
%>
注意,一定要区别这两种包含的不同(面试经常考)。JSP的include包含指令是静态的包含,在编译时,将JSP进行包含,只会生成一个servelt。而request的包含是动态包含,在运行时包含,生成多个Servlet。比效率的话,JSP的include指令优于request的RequestDispatcher。
taglib指令
将在后面的自定义标签部分进行介绍
6.JSP中的内置对象
request(Request)、response(Response)、session(Session)、application(ServletContext)、page(Object)、exception(Exception)、config(ServletConfig)、out(JspWriter)、pageContext(PageContext)
前面七个对象的作用和用法跟Servlet中的是一样的,就不再重复赘述。我们来了解一下,JSP中独有的两个对象:JSPWriter和PageContext
JSPWriter是个写出流,是一个带缓冲的写出流,缓冲区的大小就是我们在page指令中设置的大小。缓冲区的内容先写出到response的writer缓冲区中。所以,我们在写如下代码时,会出现与我们预先设定的不同。
<%
out.write("hahaha");
response.getWriter().write("wuwuwu");
%>
结果是,先输出wuwu后输出haha。于是你不要自作主张去使用response获取输出流,使用内置对象就好了。
内置对象之pageContext
这个是重中之重,pageContext有四个作用:
1.封装了其他八个隐式对象的引用。
2.用作“域”来封装属性
3.获取其他域中的属性
4.实现一些其他的作用
1.封装其他隐式对象的引用,用在自定义标签库上,以后再说。简单说一下原因,jsp页面中不允许写Java代码,需要将Java的代码段定义成自定义标签,那么这个Java类想要获取jsp中的所有内置对象只需要获取page对象即可。
2.用作域来封装属性,域的生命周期是:JSPServelt被调用,到显示结束,也就是整个页面显示的过程。
pageContext.setAttribute("data","aaa");
pageContext.getAttribute("data");
pageContext.removeAttribute("data");
3.获取其他域中的属性。
pageContext.getAttribute("data", PageContext.SESSION_SCOPE);//从指定的域中获取属性
pageContext.findAttribute("data");// page request session application 依次从这四个域中找,找不到返回null,否则返回先找到的。
4.实现一些其他的作用,比如说:实现页面的包含、实现页面的跳转等等
<%
pageContext.include("/1.jsp");//这个方法和requestDispatcher的include()效果相同,都是动态包含(运行时的),会产生多个servlet
pageContext.forward("/2.jsp");
%>
7.常见的标签
<jsp:forward page="/12.jsp">
<jsp:param name="user" value="xiaoming">
<jsp:param name="password" value="123">
</jsp:forward>
<jsp:forward>
标签也是用来实现转发,其中的<jsp:param>
标签是和转发标签配套使用的,用来向request中存入数据。
<jsp:include page="/index.jsp"></jsp:include>
这又是一种动态的页面包含。