找回密码
 FreeOZ用户注册
查看: 1202|回复: 10
打印 上一主题 下一主题

JSP的一些小知识 —— 小key出品

[复制链接]
跳转到指定楼层
1#
发表于 10-7-2009 13:33:25 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?FreeOZ用户注册

x
本文的目的是介绍/总结一些JSP开发时的一些小知识和技巧。
都是一些很小的东西。

[ 本帖最后由 key 于 10-7-2009 12:42 编辑 ]
回复  

使用道具 举报

2#
 楼主| 发表于 10-7-2009 13:40:20 | 只看该作者

一:快速编译和生成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 编辑 ]
回复  

使用道具 举报

3#
发表于 10-7-2009 13:42:30 | 只看该作者
没抢到沙发,占个板凳先~~
回复  

使用道具 举报

4#
 楼主| 发表于 10-7-2009 13:43:26 | 只看该作者
回复  

使用道具 举报

5#
发表于 10-7-2009 13:49:17 | 只看该作者
你的兴趣很广泛呀。
回复  

使用道具 举报

6#
 楼主| 发表于 10-7-2009 13:50:46 | 只看该作者

二:查看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:
  1. 29   public void _jspService(HttpServletRequest request, HttpServletResponse response)
  2. 30         throws java.io.IOException, ServletException {
  3. 31
  4. 32     PageContext pageContext = null;
  5. 33     HttpSession session = null;
  6. 34     ServletContext application = null;
  7. 35     ServletConfig config = null;
  8. 36     JspWriter out = null;
  9. 37     Object page = this;
  10. 38     JspWriter _jspx_out = null;
  11. 39     PageContext _jspx_page_context = null;
  12. 40
  13. 41
  14. 42     try {
  15. 43       response.setContentType("text/html");
  16. 44       pageContext = _jspxFactory.getPageContext(this, request, response,
  17. 45                 null, true, 8192, true);
  18. 46       _jspx_page_context = pageContext;
  19. 47       application = pageContext.getServletContext();
  20. 48       config = pageContext.getServletConfig();
  21. 49       session = pageContext.getSession();
  22. 50       out = pageContext.getOut();
  23. 51       _jspx_out = out;
  24. 52
  25. 53     } catch (Throwable t) {
  26. 54       if (!(t instanceof SkipPageException)){
  27. 55         out = _jspx_out;
  28. 56         if (out != null && out.getBufferSize() != 0)
  29. 57           try { out.clearBuffer(); } catch (java.io.IOException e) {}
  30. 58         if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
  31. 59       }
  32. 60     } finally {
  33. 61       _jspxFactory.releasePageContext(_jspx_page_context);
  34. 62     }
  35. 63   }
复制代码
回复  

使用道具 举报

7#
 楼主| 发表于 10-7-2009 14:27:49 | 只看该作者

三:玩转page指令的几个attributes

通过“二”,我们可以进一步来看看page的几个关键属性,包括:
1. session
2. errorPage
3. isErrorPage
4. buffer
5. autoFlush
6. contentType

1. session
不妨在empty.jsp中加入:
  1. <%@ page session="false" %>
复制代码
重新编译,你就会发现empty_jsp.java中的line-33
  1. 33     HttpSession session = null;
复制代码
和line-49不见了:
  1. 49       session = pageContext.getSession();
复制代码
2. errorPage
在empty.jsp加入:
  1. <%@ page errorPage="error.jsp" %>
复制代码
看到的是line-44 ~ line-45变了:
原来是:
  1. 44       pageContext = _jspxFactory.getPageContext(this, request, response,
  2. 45                 null, true, 8192, true);
复制代码
现在是:
  1. 44       pageContext = _jspxFactory.getPageContext(this, request, response,
  2. 45                 "error.jsp", true, 8192, true);
复制代码
3. isErrorPage
如果在empty.jsp中加入:
  1. <%@ page isErrorPage="true" %>
复制代码
相应地,在empty_jsp.java中会发现多了下面几行东西:
  1.     Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request);
  2.     if (exception != null) {
  3.       response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
  4.     }
复制代码
这里exception又是一个implicit variable,而它是Throwable类型,这个需要注意。

4. buffer
5. autoFlush


这两个属性是用来改变getPageContext()中的参数的,可以看到tomcat 6.0的缺省
buffer为8kb,和JSP Specification要求的最低值相同。

6. contentType
在empty.jsp中加入:
  1. <%@ page contentType="text/html; charset=UTF-8" %>
复制代码
line-43马上转变成:
  1. 43       response.setContentType("text/html; charset=UTF-8");
复制代码
回复  

使用道具 举报

8#
 楼主| 发表于 10-7-2009 15:30:57 | 只看该作者

四:<%@include%>与<jsp:include/>有什么不同?

同样是include,前者是一个指令,directive,后者是一个动作,action。
所有的指令,包括page, include都是在translation phase完成的。
而后者相法于RequestDispatcher.include()方法。

测试include directive
其中include_directive_test.jsp的内容如下:
  1.   1 <% out.println("before including"); %>
  2.   2 <%@ include file="include_directive_including.inc" %>
  3.   3 <% out.println("after including"); %>
复制代码
而include_directive_including.inc的内容如下:
  1.   1 <% out.println("including file content"); %>
复制代码
预编译后的java文件内容如下:
  1. 57
  2. 58  out.println("before including");
  3. 59       out.write('\n');
  4. 60  out.println("including file content");
  5. 61       out.write('\n');
  6. 62       out.write('\n');
  7. 63  out.println("after including");
  8. 64       out.write('\n');
复制代码
显然,转换器把整个including文件嵌入主文件之中,形成一个translation unit。
理解这个translation unit的概念很重要,因为在JSP/Servlet语法中,有不少东西是以translation unit
为单位进行约束的。比如page的所有属性中,除了import外,其他属性最多只能出现 1 次。

可能还有同学注意到,这个预编译的.java文件还有几行很特别的内容:
  1. 12   private static java.util.List _jspx_dependants;
  2. 13
  3. 14   static {
  4. 15     _jspx_dependants = new java.util.ArrayList(1);
  5. 16     _jspx_dependants.add("/include_directive_including.inc");
  6. 17   }
复制代码
这个让servlet container在每次执行更新检查的时候,需要注意把including文件一并进行
检查。

换成<jsp:include />看看
如果换成<jsp:include page="xxx" />的话,得到的结果是这样的:
  1.       org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "include_directive_including.inc", out, false);
复制代码
而更深入的了解需要看JspRuntimeLibrary.java的代码。相关部分代码如下:
  1. 948     public static void include(ServletRequest request,
  2. 949                                ServletResponse response,
  3. 950                                String relativePath,
  4. 951                                JspWriter out,
  5. 952                                boolean flush)
  6. 953         throws IOException, ServletException {
  7. 954
  8. 955         if (flush && !(out instanceof BodyContent))
  9. 956             out.flush();
  10. 957
  11. 965         String resourcePath = getContextRelativePath(request, relativePath);
  12. 966         RequestDispatcher rd = request.getRequestDispatcher(resourcePath);
  13. 967
  14. 968         rd.include(request,
  15. 969                    new ServletResponseWrapperInclude(response, out));
  16. 970
  17. 971     }
复制代码
一句rd.include()就把这司马昭之心暴露无遗了。

评分

参与人数 1威望 +30 收起 理由
ubuntuhk + 30 你太有才了!

查看全部评分

回复  

使用道具 举报

9#
 楼主| 发表于 10-7-2009 16:02:26 | 只看该作者

五: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的共享数据。
  1. + getAttributeNamesInScope(int scope) : Enumeration<String>
  2. + [u]APPLICATION_SCOPE[/u] : int
  3. + [u]SESSION_SCOPE[/u] : int
  4. + [u]REQUEST_SCOPE[/u] : int
  5. + [u]PAGE_SCOPE[/u] : int

  6. + findAttribute(String name) : Object
  7. + getAttributesScope(String name) : int 这里的 getAttributesScope()我估计是get Attribute's Scope的意思吧

  8. + getAttribute(String name, int scope) : Object
  9. + setAttribute(String name, Object obj, int scope) : void
  10. + removeAttribute(String name, int scope) : void
复制代码
显然,JSP Specification是希望PageContext能千秋万载一桶浆糊
回复  

使用道具 举报

10#
发表于 10-7-2009 20:26:41 | 只看该作者
虽然看得俺头疼,不过很支持技术型小Key

评分

参与人数 1威望 +30 收起 理由
key + 30 谢谢支持

查看全部评分

回复  

使用道具 举报

11#
发表于 26-8-2009 21:28:27 | 只看该作者

我支持

key同学是在做SCWCD讲座呀。
回复  

使用道具 举报

您需要登录后才可以回帖 登录 | FreeOZ用户注册

本版积分规则

小黑屋|手机版|Archiver|FreeOZ论坛

GMT+11, 2-11-2024 04:36 , Processed in 0.023251 second(s), 27 queries , Gzip On, Redis On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表