我们要返回HTML给浏览器,在Servlet中的做法是使用,out.write()的方式把HTML写回,这种方式看起来非常的不直观,还要求后台的开发人员懂得前台的技术,不利于分工,还不利于代码重利用,我们可以通过使用JSP解决上诉的问题。
JSP中有要显示的HTML和一些其他能够跟容器进行交互的元素,其在执行的时候会被容器编译成servlet,比如在tomcat的work目录下就能找到JSP编译之后的Servlet文件。为了方便开发JSP中可以存在如下元素:directive指令、declarations声明、scriptlets脚本、expression表达式、action事件。
directive指令
在JSP中使用<%@ %>的方式来进行定义,目前可以有page,include,taglib三种指定可以定义。
page的声明格式为:<%@page attribute="" %>其中attribute主要有:
- import 翻译成servlet的时候会变成类上面的import,表示导入一个类或者是包
- session="true/false"。表示在jsp中是否包含session这个变量,默认是true指定false的时候任何使用session的引用的操作都会抛出异常。
- isELIgnored 表示是否能够使用EL表达式,默认为true。
- isErrorPage 表示这个JSP页面有一个error对象,可以作为其他页面或者是servelt错误处理的页面。这个页面将会有一个变量exception是一个Throwable的引用,因此可以得到出错地方的异常信息,默认是false。
- errorPage表示出错之后跳转到得页面。
- contentType MIME 用来创建response的头,可以设定字符集,contentType="TYPE;charset=CHARSET"。
除了page之外还有include。
<%@ include file="relativeUrl" %> 表示引入一个文件片段,可以是JSP,HTML等等,会在引入之后跟原来的文件组合成一个文件进行编译,因此字符集是原来页面设定的,两个文件中也不能重复定义变量。
另外一个跟这个容易混淆的概念是<jsp:include page=""/> 这个表示的是引用一段可以应答请求的代码,是在翻译完成之后引用的,需要单独定义字符集。
最后是taglib
<%@ taglib uri="tagLibraryUri" prefix="tagPrefix"%>,表示的引用一个标签,tagLibraryUri表示的是在DD中定义uri,prefix表示在当前页面使用的时候代表这个标签的引用名。
Declarations声明
使用<%! declaration%>的形式进行声明,跟java类中声明类变量是一样的。在编译成servelt的,是在service之外的语句。
Scriptlets脚本
用<% %>直接包括的java代码,编译成servlet的时候会直接作为代码拷贝到service方法中。
还包括了<%-- --%>备注。编译的将忽略的代码。这个跟<!-- -->不同,后者是html的注释,是能够在浏览器中查看代码的时候看到的。
Expressions表达式
使用<%= expression%>来把一个表达式输出到页面中,可以是变量或者是表达式,或者是在declarations声明的方法等,在编译的时候会编译成out.print()。
JSP翻译成servelt
- 根据容器的实现不同会有所不同,对于tomcat来说会继承HttpJspBase。
- 然后查看JSP中指定中的import部分,转为servelt中的import部分。
- 如果有生ing,则写入到servelt中service()方法的上面。
- 创建service方法,tomcat中的名字为_jspService(),这个方法中会被service()方法调用。
- 把JSP页面中的HTML代码使用out.write()方式输出。
- 把脚本直接写入在_jspService方法中。
- 把表达式转化为out.print()。
初始化JSP
这个操作一遍用不到,基本上有两种方式可以实现。
一种是使用DD。同样是使用servelt标签进行定义,只是把<servlet-class>标签替换为<jsp-file>来指定JSP的路径。
另一种办法是在生命中覆盖jspInit()方法。例如:
<%! public void jspInit(){...}%>
JSP内置对象
为了方便开发,在JSP的脚本和声明中,我们有一些已经存在的内置对象能够直接使用:
- request - HttpServletRequest
- response - HttpServletResponse
- pageContext - The PageContext for this JSP
- session - HttpSession (需要在指令中,指定了session="true")
- application - ServletContext
- config - ServletConfig
- out - JspWriter
- pageContext - 表示的是上下文,这个具体的后面会说
- exception - Throwable 只有在isErrorPage="true"的时候才存在
JSP中的属性
JSP中的属性有四个作用域,在每个域中都能够设置和取得属性
- Application - getServletContext().setAttribute - application.setAttribute
- Request - request.setAttribute - request.setAttribute
- Session - request.getSession().setAttribute - session.setAttribute
- Page - 没有 - pageContext 如果不适用自定义标签基本上用不到这个域,所以在自定义标签中再说
但是这还没有完,通过pageContext,还能操作任何一个作用域的属性。
- pageContext.setAttribute("","",PageContext.SESSION_SCOPE):
- pageContext.getAttribute(,,);
- pageContext.find("").这个方法会从page作用于开始,直到找到属性。
虽然从out.print到JSP页面已经是一个比较大的提升了,但是在JSP页面中使用脚本来进行编程,同样会有可读性已经分工的问题,因此我们需要办法来解决这个问题,有el表达式,或者是action,都能够起到把脚本移除JSP页面的作用。具体的后面会讲。
为了规范代码,我们还能够定义JSP页面不能够使用脚本(包括,脚本,声明和表达式):
还能够在页面中定义不能够使用EL表达式。
action是页面中能够存在的另外一种元素,其实是对标签的引用。后面也会详细讲到
错误处理
在处理异常的页面中加入:<%@ page isErrorPage="true" %>
在出现错误的页面加入:<%@ page errorPage="MyJsp.jsp"%>
如果出现错误之后就会跳转到MyJsp.jsp页面。
这样看来我们需要在每个页面都加入指令,并且所有的错误还都只能够抛向一个页面,还有我们有更好的解决办法,使用DD。
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/errorPage.jsp</location>
</error-page>
设置了之后不光在jsp中出现的错误会跳转到errorPage.jsp。在servelt中出现的错误也会跳转到错误页面。
我们还能够进行更加详细的设定,比如制定某一类错误到某个页面上。
<error-page>
<exception-type>java.lang.ArithmeticException</exception-type>
<location>/arithmeticError.jsp</location>
</error-page>
或者是根据错误代码的不同条找到不同的页面。
<error-page>
<error-code>404</error-code>
<location>/notFoundError.jsp</location>
</error-page>
在错误页面中能够通过<%=exception %>或者是${pageContext.exception }展示错误信息。