一个例子搞懂Servlet&JSP

<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
	version="2.4">
	
	<servlet>
		<servlet-name>AllInOneServlet</servlet-name>
		<servlet-class>com.cdai.web.j2ee.AllInOneServlet</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>AllInOneServlet</servlet-name>
		<url-pattern>/j2ee</url-pattern>
	</servlet-mapping>
	
	<!-- Servlet mappings END -->	

</web-app>
package com.cdai.web.j2ee;

import java.io.DataOutputStream;
import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
public class AllInOneServlet extends HttpServlet {

	public AllInOneServlet() {
		System.out.println("Servlet constructed");
	}

	@Override
	public void init() {
		System.out.println("Servlet init");
	}
	
	@Override
	public void destroy() {
		System.out.println("Servlet destory");
	}
	
	@Override
	public void service(HttpServletRequest request, HttpServletResponse response)
	        throws ServletException, IOException {
		
		System.out.println("Servlet served");

		// 1.Get parameter from HTTP header
		String goWhere = request.getParameter("goto");
		
		if (goWhere == null || "1".equals(goWhere)) {
			
			// 2.Set response header
			response.setContentType("text/html");
			
			// 3.Get useful info from TCP & HTTP header
			System.out.println(
					"Request from: " + request.getRemoteAddr() + ":" + 
					request.getRemotePort() + " by method " + 
					request.getMethod());
			
			// 4.Print html(out is built-in object in JSP)
			DataOutputStream out = new DataOutputStream(response.getOutputStream());
			out.writeUTF("Hello Servlet");
			out.writeUTF("<br>");
			out.close();
		}
		else if ("2".equals(goWhere)) {
			RequestDispatcher dispather = request.getRequestDispatcher("/main.jsp?param1=java");
			request.setAttribute("param2", "servlet");
			dispather.forward(request, response);
		}
		else if ("3".equals(goWhere)) {
			response.sendRedirect("http://www.google.com?newwindow=1&q=java&oq=java");
		}
		
	}
	
}
<!-- 1.Compile instruction -->
<%@page 
	import="java.util.concurrent.atomic.*, com.cdai.web.j2ee.TestBean" 
	contentType="text/html;charset=utf-8" 
%>

<!-- 2.Declaration: member variable and method -->
<%! 

	private AtomicInteger count = new AtomicInteger(1);
	private ThreadLocal<Integer> curCountStorage = new ThreadLocal<Integer>();
	
	private int getCount() {
		int curCount = count.getAndIncrement();
		curCountStorage.set(curCount);
		return curCount;
	}
%>

<!-- 3.JSP code & 4.Built-in object -->
<%
	Object curCount = session.getAttribute("count");
	if (curCount == null) {
		curCount = getCount();
		session.setAttribute("count", curCount);
	}
	
	out.println(request.getParameter("param1") + " - " + request.getAttribute("param2"));
%>

<br> This is main.jsp. You're the <%=curCount%> visitor.

<!-- 5.Runtime action -->
<jsp:useBean id="testBean" class="com.cdai.web.j2ee.TestBean" scope="page"/>
<br>Message in TestBean is: <jsp:getProperty property="message" name="testBean"/>

这是一个很简单的例子,通过http://127.0.0.1:8080/ssh/j2ee可以访问到AllInOneServlet。通过传给它
不同的goto参数,可以控制它是:(1)自己生成一个hello servlet的响应页面(2)转发到main.jsp生成
一个统计访问量的页面(3)重定向到Google首页。通过这个例子,让我们来一起来搞懂Servlet和JSP
这两个J2EE开发中最基础的组件。


一、Servlet基础

1.Servlet的生命周期

根据日志输出,当发送HTTP请求到Servlet时,Tomcat才创建Servlet。首先执行的是Servlet的构造函数,
之后是init()方法,然后才是service()方法。如果没有覆写service(),那么它会根据HTTP请求是Get还是
Post来调用doGet()和doPost()方法。

这一个Servlet会一直存在,被处理各个HTTP请求的线程调用,因此Servlet要尽量含有避免synchronized
代码。最后,当Tomcat移出了Servlet时会调用destory()方法(应用被卸载或Servlet文件发生变化)。

2.读请求头,设置响应头

通过Servlet的API可以很方便的从TCP和HTTP数据包中读出很多有用的信息,底层已经帮我们解析好了。
以后有空会写一个简单的Web服务器,模拟一下J2EE容器的一些基本功能。

3.读URL中参数

这也是Web开发中最常用的方法,通过getParameter()方法可以取出URL中的参数。

4.重定向和转发

很重要的两个概念。重定向一般是返回给浏览器一个外部的URL,让它去那里请求,所以浏览器实际上
请求了两次才得到最终的内容。而转发一般是在当前Web应用内部,从一个组件转发到另一个组件(比如
从Servlet到JSP),主要用于组件间协同工作。可以通过setAttribute来传递一些数据。


二、JSP基础

JSP看似比Servlet内容多而且复杂,其实学习JSP时只要关注两件事:
哪些代码是编译时用的,哪些是运行时执行。
各种标签在编译成Servlet代码后变成了什么样。

1.指令

指令是编译期间执行的代码,常用的有:page、include、taglib。语法是<%@page ... %>。
在这个例子中通过page指令的import设置JSP引用的Java类,这样JSP编译成Servlet时才不会
有编译错误。

2.声明

声明的变量和方法最终编译成Servlet中的成员变量和方法。语法是<%! ... %>。这里的代码
都会生成在service()方法外,所以声明的变量是编译后Servlet的成员变量,而且可以声明方法。
这是声明与后面将要介绍的普通JSP代码的区别。

3.动作

动作是运行期执行的代码。<jsp:include>、<jsp:forward>、<jsp:useBean>等等。<jsp:include>
是动态引入其他文件,如果代码不执行到这里就不会引入,一定要与include指令区分开。
<jsp:forward>与Servlet中的forward方法功能相同,而<jsp:useBean>、<jsp:property>稍后在JSP
转换成的Servlet源文件中会看到它们的真身。

4.JSP代码

编译后会生成到service()方法中,因此在这里声明的变量是局部变量,也就不能在这里声明方法了。
语法是<% ... %>。

5.内置对象

out、page、session、application、config、exception、request、response、pageContext。
可以在JSP中直接使用。这些内置对象没有什么神秘的,在Servlet中都是可以获得到的,只不过
在JSP中它们都有了简短的名字,所以用起来很方便而已。

6.JSP表达式

插入一个简单的Java代码得到一个值,语法是<%= ... %>。

下面就要揭开本例中JSP神秘的面纱了,在Tomcat的work目录中我们可以找到JSP转成的Servlet源文件文件。
package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import java.util.concurrent.atomic.*;
import com.cdai.web.j2ee.TestBean;

public final class main_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent {

 

	private AtomicInteger count = new AtomicInteger(1);
	private ThreadLocal<Integer> curCountStorage = new ThreadLocal<Integer>();
	
	private int getCount() {
		int curCount = count.getAndIncrement();
		curCountStorage.set(curCount);
		return curCount;
	}

  private static java.util.List _jspx_dependants;

  public Object getDependants() {
    return _jspx_dependants;
  }

  public void _jspService(HttpServletRequest request, HttpServletResponse response)
        throws java.io.IOException, ServletException {

    JspFactory _jspxFactory = null;
    PageContext pageContext = null;
    HttpSession session = null;
    ServletContext application = null;
    ServletConfig config = null;
    JspWriter out = null;
    Object page = this;
    JspWriter _jspx_out = null;
    PageContext _jspx_page_context = null;


    try {
      _jspxFactory = JspFactory.getDefaultFactory();
      response.setContentType("text/html;charset=utf-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
      			null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write("<!-- 1.Compile instruction -->\r\n");
      out.write("\r\n");
      out.write("\r\n");
      out.write("<!-- 2.Declaration: member variable and method -->\r\n");
      out.write("\r\n");
      out.write("\r\n");
      out.write("<!-- 3.JSP code & 4.Built-in object -->\r\n");

	Object curCount = session.getAttribute("count");
	if (curCount == null) {
		curCount = getCount();
		session.setAttribute("count", curCount);
	}
	
	out.println(request.getParameter("param1") + " - " + request.getAttribute("param2"));

      out.write("\r\n");
      out.write("\r\n");
      out.write("<br> This is main.jsp. You're the ");
      out.print(curCount);
      out.write(" visitor.\r\n");
      out.write("\r\n");
      out.write("<!-- 5.Runtime action -->\r\n");
      com.cdai.web.j2ee.TestBean testBean = null;
      synchronized (_jspx_page_context) {
        testBean = (com.cdai.web.j2ee.TestBean) _jspx_page_context.getAttribute("testBean", PageContext.PAGE_SCOPE);
        if (testBean == null){
          testBean = new com.cdai.web.j2ee.TestBean();
          _jspx_page_context.setAttribute("testBean", testBean, PageContext.PAGE_SCOPE);
        }
      }
      out.write("\r\n");
      out.write("<br>Message in TestBean is: ");
      out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString((((com.cdai.web.j2ee.TestBean)_jspx_page_context.findAttribute("testBean")).getMessage())));
      out.write('\r');
      out.write('\n');
    } catch (Throwable t) {
      if (!(t instanceof SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          out.clearBuffer();
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
      }
    } finally {
      if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
}
怎么样?对照着JSP的源码来看,是不是毫无神秘之处。


三、Cookie和Session

在这个例子中我们使用Session,借助Cookie保存一个Session ID在浏览器端。这种Cookie也叫做会话Cookie。
在同一个Chrome进程的打开多个不同页面访问http://127.0.0.1:8080/ssh/j2ee?goto=2都能够获得Session
中保存的数据,从而达到了使无状态的HTTP看起来好像有状态一样。




四、多线程安全

由于每个Servlet只有一个实例,被所有请求线程共享,所以在Servlet中要尽量避免代码同步、资源竞争,
否则服务器的响应速度会很慢。除了Servlet,还要注意一些会被共享的内置对象,比如在一个用户的所有
请求内被共享的Session对象,也是有可能发生并发问题的。有共享,就会有并发,所以在J2EE各个层的
开发中,Servlet/JSP -> Service -> DAO -> Database都要注意并发问题。

顺序如下: 1、多种字体大小显示 2、c:out标记输出 3、获取当前时间 4、include包含语句 5、建立错误处理页面的范例程序 6、jsp:forward 7、简单计数器 8、设置页面属性 9、使用GB2312编码 10、使用Big5编码 11、c:catch的用法 12、 begin、end和step的用法 13 、 循环 14、 varStatus 的四种属性 15、 的用法 16、从客户端传送数据至服务端 17、使用Unicode转义字符 18、使用朝鲜语字符集 19、JSP中最简单的国际化程序 20、错误检测 21、抛出异常 22、 的用法 23、和 的用法 24、 的用法 25、jsp-include的用法 26、汉字处理 27、网页重定向 28、自动更新网页 29、存取session 30、 的用法 31、单选型列表框 32、jsp文件中定义类 33、取得 JSP Container 版本 34、javax.servlet.jsp.JspWriter - out 对象 35、page 隐含对象 36、application 对象 37、PageContext 对象 38、Page范围 - pageContext 39、测试要显示的中文 40、IF控制符的操作 41、HttpServletRequest 接口所提供的方法 42、 网上测验 43、HttpSession - session 对象 44、 多选型列表框 45、解决浏览器 cache 的问题 46、使用 EL、JSTL 处理表单数据 47、 EL隐含对象 param、paramValues 48、EL隐含对象 pageContext 49、EL算术运算符 50、EL关系运算符 51、EL的运算符 52、选择钮的使用 53、检查框的使用 54、群组检查框的使用 55、数字、货币、百分数格式化 56、日期格式化 57、JSTL设置语言地区 58、Cookie数据的存取 59、session有效时间的设置与取得 60、session时间与ID 61、Cookie有效时间的设置 62、利用隐藏字段传送数据 63、JSP 使用 JavaBean 的方法 64、JSP 使用 JavaBean 65、范围为 Page 的 JavaBean范例程序 66、范围为 Request的 JavaBean 67、范围为 Session 的 JavaBean 68、范围为 Application 的 JavaBean 69、删除 JavaBean 70、url重组 71、Switch语句 72、环境变量 73、forward重定向 74、文件的建立与删除 75、取得文件属性 76、取得目录中的文件 77、目录的建立与删除 78、自Cookie存取日期/时间数据 79、管理Session变量 80、数据库中的记录数与记录指针位置 81、利用absolute方法设置记录位置 82、使用jsp指令生成Word文档 83、JSP网页模板 84、判断是否空白文件 85、cookie 用户登录次数 86、获取用户的真实IP地址 87、获取用户的浏览器信息 88、在客户端进行数据检查 89、在JSP中获取当前绝对路径 90、读取表单中所有参数 91、分行写入数据 92、显示请求URL 93、判断session是否过期 94、参数式查询数据库 95、取得数据库中各栏名称 96、使用JavaBean、设置和获取Bean的属性 97、设置Bean的一个属性与输入参数关联 98、实现基于数据库的站内搜索 99、DOM读取XML文档 100、SAX读取XML文档
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值