JSP的一些小知识 —— 小key出品
本文的目的是介绍/总结一些JSP开发时的一些小知识和技巧。都是一些很小的东西。
[ 本帖最后由 key 于 10-7-2009 12:42 编辑 ]
一:快速编译和生成servlet类
我们都知道,JSP的life-cycle有七步,其中前两步是JSP的转译与编译,后五步是servlet的生命周期的JSP对应版本。
而JSP的转译和编译是比较花时间的。我们会因为下面两个原因需要单独的
编译和生成servlet类,而不想执行它:
1. 快速测试JSP语法
2. 全面编译一次JSP网页,而避免用户第一次点击时响应时间过长
这里可以采用:
http://localhost:8080/<context-path>/<jsp-path>.jsp?jsp_precompile=true
来执行。如果你用linux或cygwin,还可以用:
curl "http://localhost:8080/<context-path>/<jsp-path>.jsp?jsp_precompile=true"
或者:
find <context-path> -name "*.jsp" -exec curl "http://localhost:8080/{}?jsp_precompile=true" \;
[ 本帖最后由 key 于 10-7-2009 12:42 编辑 ] 没抢到沙发,占个板凳先~~ 原帖由 formatc 于 10-7-2009 12:42 发表 http://www.freeoz.org/forum/images/common/back.gif
没抢到沙发,占个板凳先~~
多谢支持 你的兴趣很广泛呀。
二:查看jsp的implicit variable
参考JSP的书,可以找到关于implicit variable的说明。关于由JSP生成的Servlet类,我们知道它是implements Servlet, JspPage, HttpJspPage
这些接口(其实这些接口本身是继承关系)。尤其是Servlet接口,
我们必须记住相应的接口方法。
但除此以外,一些implicit variable则不容易记住。在开发的过程中,如果我们一时不记得
这些东西,可以做一件简单的事把这些变量找到:
1. touch empty.jsp,这个文件就是空文件。
2. curl http://localhost:8080/<context-path>/<jsp-path>.jsp?jsp_precompile=true
然后进入work目录下找到empty_jsp.java查看。下面是tomcat 6.0下的一个sample:29 public void _jspService(HttpServletRequest request, HttpServletResponse response)
30 throws java.io.IOException, ServletException {
31
32 PageContext pageContext = null;
33 HttpSession session = null;
34 ServletContext application = null;
35 ServletConfig config = null;
36 JspWriter out = null;
37 Object page = this;
38 JspWriter _jspx_out = null;
39 PageContext _jspx_page_context = null;
40
41
42 try {
43 response.setContentType("text/html");
44 pageContext = _jspxFactory.getPageContext(this, request, response,
45 null, true, 8192, true);
46 _jspx_page_context = pageContext;
47 application = pageContext.getServletContext();
48 config = pageContext.getServletConfig();
49 session = pageContext.getSession();
50 out = pageContext.getOut();
51 _jspx_out = out;
52
53 } catch (Throwable t) {
54 if (!(t instanceof SkipPageException)){
55 out = _jspx_out;
56 if (out != null && out.getBufferSize() != 0)
57 try { out.clearBuffer(); } catch (java.io.IOException e) {}
58 if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
59 }
60 } finally {
61 _jspxFactory.releasePageContext(_jspx_page_context);
62 }
63 }
三:玩转page指令的几个attributes
通过“二”,我们可以进一步来看看page的几个关键属性,包括:1. session
2. errorPage
3. isErrorPage
4. buffer
5. autoFlush
6. contentType
1. session
不妨在empty.jsp中加入:<%@ page session="false" %>重新编译,你就会发现empty_jsp.java中的line-3333 HttpSession session = null;和line-49不见了:49 session = pageContext.getSession();2. errorPage
在empty.jsp加入:<%@ page errorPage="error.jsp" %>看到的是line-44 ~ line-45变了:
原来是:44 pageContext = _jspxFactory.getPageContext(this, request, response,
45 null, true, 8192, true);现在是:44 pageContext = _jspxFactory.getPageContext(this, request, response,
45 "error.jsp", true, 8192, true);3. isErrorPage
如果在empty.jsp中加入:<%@ page isErrorPage="true" %>相应地,在empty_jsp.java中会发现多了下面几行东西: Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request);
if (exception != null) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}这里exception又是一个implicit variable,而它是Throwable类型,这个需要注意。
4. buffer
5. autoFlush
这两个属性是用来改变getPageContext()中的参数的,可以看到tomcat 6.0的缺省
buffer为8kb,和JSP Specification要求的最低值相同。
6. contentType
在empty.jsp中加入:<%@ page contentType="text/html; charset=UTF-8" %>line-43马上转变成:43 response.setContentType("text/html; charset=UTF-8");
四:<%@include%>与<jsp:include/>有什么不同?
同样是include,前者是一个指令,directive,后者是一个动作,action。所有的指令,包括page, include都是在translation phase完成的。
而后者相法于RequestDispatcher.include()方法。
测试include directive
其中include_directive_test.jsp的内容如下:1 <% out.println("before including"); %>
2 <%@ include file="include_directive_including.inc" %>
3 <% out.println("after including"); %>而include_directive_including.inc的内容如下:1 <% out.println("including file content"); %>预编译后的java文件内容如下: 57
58out.println("before including");
59 out.write('\n');
60out.println("including file content");
61 out.write('\n');
62 out.write('\n');
63out.println("after including");
64 out.write('\n');显然,转换器把整个including文件嵌入主文件之中,形成一个translation unit。
理解这个translation unit的概念很重要,因为在JSP/Servlet语法中,有不少东西是以translation unit
为单位进行约束的。比如page的所有属性中,除了import外,其他属性最多只能出现 1 次。
可能还有同学注意到,这个预编译的.java文件还有几行很特别的内容: 12 private static java.util.List _jspx_dependants;
13
14 static {
15 _jspx_dependants = new java.util.ArrayList(1);
16 _jspx_dependants.add("/include_directive_including.inc");
17 }这个让servlet container在每次执行更新检查的时候,需要注意把including文件一并进行
检查。
换成<jsp:include />看看
如果换成<jsp:include page="xxx" />的话,得到的结果是这样的: org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "include_directive_including.inc", out, false);而更深入的了解需要看JspRuntimeLibrary.java的代码。相关部分代码如下: 948 public static void include(ServletRequest request,
949 ServletResponse response,
950 String relativePath,
951 JspWriter out,
952 boolean flush)
953 throws IOException, ServletException {
954
955 if (flush && !(out instanceof BodyContent))
956 out.flush();
957
965 String resourcePath = getContextRelativePath(request, relativePath);
966 RequestDispatcher rd = request.getRequestDispatcher(resourcePath);
967
968 rd.include(request,
969 new ServletResponseWrapperInclude(response, out));
970
971 }一句rd.include()就把这司马昭之心暴露无遗了。
五:4种scope
JSP中数据共享有4个scope(我们一般会说servlet的共享范围有3个)。这四个范围对应了 8 个隐含对象中的 4 个(正好一半),分别是:
1. application
2. session
3. request
4. pageContext
其中,除了pageContext不可以枚举所有的共享名称外,
其他 3 个都可以用getAttributeNames()进行枚举。
很容易可以看到,前面3个scope和servlet是一致的,
但第4个pageContext就是JSP特有的。这是因为servlet是一个Java类,
JSP虽然说最终还是一个Java Servlet,但毕竟穿着马甲嘛,多少要装模作样一下。
各种scriptlet之间的数据如何进行通信,是一个问题。通过pageContext则可以解决
这个问题。
虽然PageContext本身没有getAttributeNames()方法,但他有更强大的方法。
事实上,你可以通过PageContext很方面地操作指定scope的共享数据。+ getAttributeNamesInScope(int scope) : Enumeration<String>
+ APPLICATION_SCOPE : int
+ SESSION_SCOPE : int
+ REQUEST_SCOPE : int
+ PAGE_SCOPE : int
+ findAttribute(String name) : Object
+ getAttributesScope(String name) : int 这里的 getAttributesScope()我估计是get Attribute's Scope的意思吧
+ getAttribute(String name, int scope) : Object
+ setAttribute(String name, Object obj, int scope) : void
+ removeAttribute(String name, int scope) : void显然,JSP Specification是希望PageContext能千秋万载一桶浆糊 虽然看得俺头疼,不过很支持技术型小Key:congra
我支持
key同学是在做SCWCD讲座呀。
页:
[1]