JSP 笔记

很久以前的笔记了,翻出来整理下。

有用的资源

在Tomcat的webapps/examples/ 目录下有很多实用详细的jsp代码例子。

JSP的本质

首先,JSP本质上是一个Servlet,jsp编绎器会把jsp文件编绎成一个对应的java类,而这个java类是实际上是一个servlet,从继承层次就可以看出来。

比如home.jsp,在tomcat下会生成一个home_jsp的类:

class home_jsp extends org.apache.jasper.runtime.HttpJspBase

class HttpJspBase extends javax.servlet.http.HttpServlet

Tomcat7生成为jsp对应的java代码在work目录下。如果是在eclipse里跑的tomcat,那么在eclipse的workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/work/Catalina/ 目录下。

一些JSP指令实际生成的代码

jsp:include指令:

<jsp:include page="xxx.jsp">
    <jsp:param name="age" value="20"/>
</jsp:include>

实际生成的Java代码:

org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "xxx.jsp" + (("xxx.jsp").indexOf('?')>0? '&': '?') + org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("age", request.getCharacterEncoding())+ "=" + org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("20", request.getCharacterEncoding()), out, false);

可以看出jsp:include指令和include编译指令是完全不同的,jsp:include是每次都动态加载,而include编绎指令是把两个jsp文件合起来,编绎成一个servlet。

jsp:useBean,jsp:setProperty,jsp:getProperty 三个指令的本质:

<jsp:useBean id="s1" class="com.test.Student" scope="application"></jsp:useBean>
<jsp:setProperty name="s1" property="name" value="hello"/>

实际生成的Java代码:

pageContext = _jspxFactory.getPageContext(this, request, response,
                  null, true, 8192, true);
application = pageContext.getServletContext();
synchronized (application) {
  s1 = (com.test.Student) _jspx_page_context.getAttribute("s1", PageContext.APPLICATION_SCOPE);
  if (s1 == null){
    s1 = new com.test.Student();
    _jspx_page_context.setAttribute("s1", s1, PageContext.APPLICATION_SCOPE);
  }
}
org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper(_jspx_page_context.findAttribute("s1"), "name", "hello", null, null, false);

可见jsp:useBean实际上得到一个对象,并调用setAttribute函数设置为scope的一个属性。比如scope="application",则实际和下面的代码差不多:

com.test.Student s1 = application.getAttribute("s1");
synchronized (application) {
    if(s1 == null){
        s1 = new com.test.Student();
        application.setAttribute("s1", s1);
    }
}

值得注意的是PageContext,即application对象在setAttribute时,要加上sync同步,因为servlet不是线程安全的。但是实际上有很多人手写的代码都没有注意到这点。

Tomcat7中session的实现

Tomcat7中session是通过cookie来实现的。实际上只有当调用request.getSession()函数时,才会设置cookie来支持session。如:

HttpSession session = req.getSession();
resp.getWriter().println("session id:" + session.getId());

当设置浏览器禁止cookie时,可以发现每一次请求,打印的session id都是不一样的,即都会有一个新的cookie值。并且这时如果调用session.setAttribute函数设置一些属性,则会发现属性设置是无效的。
实际上通过查看Tomcat7的源代码可以发现,是用一个HashMap来保存session id和session的关系。如果请求中没有session id,则当调用getSession()函数时,会生成一个新的id和一个新的session。

Tomcat7源代码中相关部分如下:

//ManagerBase.java
protected Map<String, Session> sessions = new ConcurrentHashMap<String, Session>();

//Request.java
    protected Session doGetSession(boolean create) {

        // There cannot be a session if no context has been assigned yet
        if (context == null) {
            return (null);
        }

        // Return the current session if it exists and is valid
        if ((session != null) && !session.isValid()) {
            session = null;
        }
        if (session != null) {
            return (session);
        }

        // Return the requested session if it exists and is valid
        Manager manager = null;
        if (context != null) {
            manager = context.getManager();
        }
        if (manager == null)
         {
            return (null);      // Sessions are not supported
        }
        if (requestedSessionId != null) {
            try {
                session = manager.findSession(requestedSessionId);
            } catch (IOException e) {
                session = null;
            }
            if ((session != null) && !session.isValid()) {
                session = null;
            }
            if (session != null) {
                session.access();
                return (session);
            }
        }

        // Create a new session if requested and the response is not committed
        if (!create) {
            return (null);
        }
        if ((context != null) && (response != null) &&
            context.getServletContext().getEffectiveSessionTrackingModes().
                    contains(SessionTrackingMode.COOKIE) &&
            response.getResponse().isCommitted()) {
            throw new IllegalStateException
              (sm.getString("coyoteRequest.sessionCreateCommitted"));
        }

        // Attempt to reuse session id if one was submitted in a cookie
        // Do not reuse the session id if it is from a URL, to prevent possible
        // phishing attacks
        // Use the SSL session ID if one is present.
        if (("/".equals(context.getSessionCookiePath())
                && isRequestedSessionIdFromCookie()) || requestedSessionSSL ) {
            session = manager.createSession(getRequestedSessionId());
        } else {
            session = manager.createSession(null);
        }

        // Creating a new session cookie based on that session
        if ((session != null) && (getContext() != null)
               && getContext().getServletContext().
                       getEffectiveSessionTrackingModes().contains(
                               SessionTrackingMode.COOKIE)) {
            Cookie cookie =
                ApplicationSessionCookieConfig.createSessionCookie(
                        context, session.getIdInternal(), isSecure());

            response.addSessionCookieInternal(cookie);
        }

        if (session == null) {
            return null;
        }

        session.access();
        return session;
   }

Tomcat7的生成session id的算法

另外,还有一点很有意思的地方,Tomcat7的生成session id的算法:

可以看到里面的随机数用了SecureRandom。这个很多人都没有注意到这个,实际上很多安全相关的随机数生成器应该用SecureRandom,如果用Random,有可能会遭到攻击。

private void getRandomBytes(byte bytes[]) {

    SecureRandom random = randoms.poll();
    if (random == null) {
        random = createSecureRandom();
    }
    random.nextBytes(bytes);
    randoms.add(random);
}
/**
 * Generate and return a new session identifier.
 */
public String generateSessionId() {

    byte random[] = new byte[16];

    // Render the result as a String of hexadecimal digits
    StringBuilder buffer = new StringBuilder();

    int resultLenBytes = 0;

    while (resultLenBytes < sessionIdLength) {
        getRandomBytes(random);
        for (int j = 0;
        j < random.length && resultLenBytes < sessionIdLength;
        j++) {
            byte b1 = (byte) ((random[j] & 0xf0) >> 4);
            byte b2 = (byte) (random[j] & 0x0f);
            if (b1 < 10)
                buffer.append((char) ('0' + b1));
            else
                buffer.append((char) ('A' + (b1 - 10)));
            if (b2 < 10)
                buffer.append((char) ('0' + b2));
            else
                buffer.append((char) ('A' + (b2 - 10)));
            resultLenBytes++;
        }
    }

    if (jvmRoute != null && jvmRoute.length() > 0) {
        buffer.append('.').append(jvmRoute);
    }

    return buffer.toString();
}
时间: 2024-11-01 04:23:32

JSP 笔记的相关文章

动态网页设计笔记

动态网页设计笔记    JavaScript.ASP.ASP.Net.JSP笔记   JavaScript ASP.net ASP 1.基本控件的使用6.客户端脚本的基本对象    ***41.常用的Javascript内建类的方法  ***2.让TextArea自动换行3.让TextArea支持Table键4.复制数据到剪贴板5.得到当前选中的文本7.保护自己编写的HTML和脚本的方法8.IE地址栏前换成自己的图标9.可以在收藏夹中显示出你的图标10.关闭输入法11.直接查看源代码12.在Ja

JSP学习笔记

js|笔记 1.JSP标签库(也称自定义库)可看成是一套产生基于XML脚本的方法,它经由JavaBeans来支持.在概念上说,标签库是非常简单和可以重用的代码构造.它可以大大简化你在页面中输入各种录入框的代码(诸如此类的代码:<input type="text" name="taxpayerName" value = " ,<select name="collectionItemCode" class="requi

JSP学习笔记(二)-----使用Tomcat运行JSP文件

js|笔记 有些网友不知道怎么才能运行自己的JSP文件,我在这里简单介绍一下,给大家提供一点参考: 1. 下载并安装tomcat.下载地址:http://jakarta.apache.org/tomcat 2. 编写自己的JSP网页和Java对象. 3. 配置自己的Web应用.配置方法: 在TOMCAT_HOME/conf/server.xml文件中加入一行: <Content path="/appName" docBase="webapps/appName"

JSP学习笔记(一)-----概述

js|笔记 1.JSP是Java Server Pages的简写. 2.用JSP开发的Web应用是跨平台的. 3.JSP技术是Servlet技术的扩展.Servlet是平台无关的,100%纯Java的Java服务端组件. 4.下面就是一个简单的JSP页面: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><HTML><HEAD><TITLE>欢迎访问网上商店<

JSP学习笔记(九)-----JSP标签库

js|笔记 1.JSP标签库(也称自定义库)可看成是一套产生基于XML脚本的方法,它经由JavaBeans来支持.在概念上说,标签库是非常简单和可以重用的代码构造.它可以大大简化你在页面中输入各种录入框的代码(诸如此类的代码:<input type="text" name="taxpayerName" value = " ,<select name="collectionItemCode" class="requi

JSP学习笔记(八)-----include的运用

include|js|笔记 1. 向JSP页面中插入指定的页面方法有两种:JSP命令<%@ include%>JSP动作<jsp:include />2. a.jsp代码如下:<html>huanghui<%@ include file="b.jsp"%><jsp:include page="b.jsp" flush="true"/></html>3. b.jsp代码如下:&

JSP学习笔记(七)-----猜数字游戏

js|笔记 1. 这是一个猜数字的游戏,通过使用JSP调用JavaBean2. 需要两个文件,number.jsp和NumberGuessBean.java3. 先看number.jsp代码:<html><jsp:useBean id="number" class="NumberGuessBean" scope="session" /><jsp:setProperty name="number"

JSP学习笔记(六)-----在多个JSP页面之间传递参数

js|笔记|页面 1. 怎么在多个JSP页面之间进行参数传递?需要使用JSP的内置作用域对象session.利用它的两个方法setAttribute(),getAttribute()2. 下面的这个实例实现了把第一个JSP页面的参数传递给第三个页面的功能3. 代码如下:1.jsp<html><form method=get action=2.jsp>what's your name<input type=text name=username><input type

JSP学习笔记(五)-----JSP中使用JavaBean

js|笔记 1. 该实例主要告诉我们怎么样在JSP代码中调用JavaBean构件2. 使用JavaBean的优点是简化了JSP代码,界面代码和逻辑代码互相分离,便于程序员查看和调试3. 该实例需要五个文件:login.jsp,test.jsp, userbean.class4. 首先看一下login.jsp <html><center><form method=post action="http://127.0.0.1:8000/test.jsp">