JSP(Java Server Page)是一种动态网页
开发技术。之前的实践中我们使用Servlet对URL请求进行一些简单的响应,例如读取应用中的某个静态文件
(例如读取html文件直接在浏览器中显示,这种方法无法定制显示内容),或者直接将数据在浏览器上print出来
(该方法由于引入变量,可以定制显示内容)。
其实本质上而言,不直接读取静态资源的条件下,所有的网页显示结果都是Servlet打印出来的,但当我们是通过重定向直接读取html文件
的时候就不需要用servlet的打印功能。
有时候我突发奇想,就会将一个Html格式的文档保存为txt格式,然后再用输入输出流进行打印,这样同样可以显示出来html格式的内容。
不管是哪种方式,都会带来一些麻烦。例如我们需要不断增加我们的静态文件(假如是html文件,那么可能这些html文件之间只有很少的不同,但我们要为此新建一个全新的文件),如果直接依靠Servlet进行打印,那么会屈服于无休止的输出语句。
JSP一定程度上可以解决这些问题,它可以用于加载一些不同的内容。看起来它还是使用读取静态文件.jsp的方法(表面上好像不使用print方法显示结果,但其实是将这些打印操作自动化了,无需手动输入代码
),所以它不同于静态的html页面。它还是和直接print一样,可以“定制”显示内容。
JSP神奇的地方就在于这里,它可以将.jsp(仍旧不是html格式)中的网页标签和JSP脚本全部转化成Servlet程序的一部分,然后使用输出流打印出来。所以本质上.jsp是采用Servlet的输出流来展示网页结果的。而不是通过访问html文档之类的跳转到html文件来展示结果。
Tomcat服务器有默认的设置,以.jsp为扩展名的URL访问请求都是由org.apache.jasper.servlet.JspServlet来进行处理。处理什么呢?我们知道Servlet是用于处理URL请求的,也就是说Servlet要处理的是HttpServletRequest对象。这里也是同个道理,如果我们访问/*.jsp文件,就生成了一个HttpServletRequest对象,然后.jsp文件就会就会将自身的内容整合到JspServlet,然后由JspServlet来处理HttpServletRequest
。
至于URL格式上的不同(一个是/servlet,一个是/*.jsp),其实本质上是完全一样的,因为它们最终都是跳转到一个Servlet,
这可以从配置文件中看出来。
JSP的基本语法:
如果只是变量或者表达式,后面不能有分号,前面多一个等号;
如果是脚本片段后面则是必须要有分号;
//表达式
<%= expression%>
//脚本片段
<%
int x = 3;
out.println(x);
%>
这些代码片段不过是被原封不动转移到Servlet的_jspService()方法中(当然html的部分也会到程序中,例如<h>itcast</h>
就会被转成out.write("<h>itcast</h>"),而变量部分就会使用out.print(i)的方式进行输出),说白了,还是使用servlet中的输出方法。
如果是<% %>,那么里面的变量是局部变量,这些代码片段也只是被原封不动转移到Servlet的_jspService()方法中。如果我们尝试定义方法,就会出现方法嵌套的错误。
因此,如果想要定义方法,就需要采用<%! %>的格式。
这时候在里面声明的都是成员方法、成员变量、静态方法、静态变量、静态代码块等。这时候这些代码片段应该就是和jspService()方法并列(而不是被包含)的所在了。
JSP指令与JSP标签
除此以外,jsp还有一些指令可以实现功能。例如page指令可以用于对页面的特性进行描述。一个案例是使用errorPage属性来指定错误页面。
<%@page language="java" contentType="text/htm;charset=UTF-8" errorPage="error.jsp" %>
另外一个强大的功能是使用include指令来包含一个文件,后面可以使用JSP标签实现类似的功能,里面就有一个<jsp:include>标签,同样是可以将其他资源的输入内容插入到当前JSP页面的输出内容当中。
但是这两者也有区别,<jsp:include>标签要求动态引入的资源必须能够被web容器独立执行。而include指令只能够引入遵循jsp格式的文件,被引入文件与当前jsp文件需要共同合并才能翻译成为一个Servlet源文件。
而<jsp:forward>标签能够实现页面跳转。
JSP隐式对象
JSP的隐式对象可以起到简化代码的作用(不需要手动创建一些重要的对象,已经默认建好)。例如out对象,我们使用servlet进行输出的时候需要新建一个out对象,但是这里已经默认创建好了,所以可以直接使用out对象,
代码就少些了。这里的out对象不是PrintWriter类,而是javax.servlet.jsp.JspWriter类。它相当于一种带缓存功能的PrintWriter。要等到整个JSP页面结束,才会把数据输入Servlet引擎提供的缓冲区。当然这个缓冲区大小我们可以使用buffer参数手动进行设置。
除此以外,默认创建的隐式对象还有session、request、response等。当我们在URL中访问某个.jsp文件的时候,这时候就会有封装好的request和response对象,而这个.jsp文件本来就会转成某个Servlet的一部分,所以就相当于用同样的request来访问Servlet而已。然后服务器会通过getSession(True)方法来获取session(使用True是因为如果没有的时候会新建一个session)。application、page、pageContext、exception这些我们要到后面才能体验它的用法。其中pageContext除了可以获取各个隐式对象外,还能够存储其他数据,并且设定属性的作用范围。(PAGE_SCOPE,REQUEST_SCOPE,SESSION_SCOPE,APPLICATION_SCOPE)等。
备注:jsp的本质虽然是一个Servlet,也是由这个Servlet来执行部分再JSP页面中的语句,那么把这个java语句从Servlet中搬到jsp中有什么好处呢,后面的框架为什么只使用它的显示功能呢。