Servlet和Jsp

servlet和CGI

我们知道Web服务器(如apache)只擅长提供静态页面,因此在动态应用场景,Web服务器会把请求转发给另一个能够动态处理的辅助应用(helper app),这个辅助应用就是CGI,而CGI可以用C、Python、PHP、Perl等等来实现。请求和应答如下图:

而Java的CGI实现就是Servlet,如下图:

由于servlet没有main()方法,因此它受控于web Container app(容器),而Tomcat就是一个这样的容器。Tomcat容器的作用提供通信支持、声明周期管理、多线程支持、声明方式实现安全、JSP支持等,看参考Tomcat初识。它的流程是这样的:

  1. Client发出一个请求到WebServer;
  2. WebServer接收到请求好转发给Web Container;
  3. Web Container根据URL在部署描述文件(web.xml)中找到对应的servlet;
  4. Web Container调用对相应的servlet的service()方法;
  5. servlet的service()方法根据请求的类型get/post调用相应的处理逻辑;
  6. 处理完毕后servlet返回结果;

servlet实例

  1. 构建项目

    我们使用Eclipse+Maven来构建Java的servlet应用,以前曾经写过一篇超入门级的:maven + eclipse + tomcat 实战JSP,文章里使用的maven构建再导入到eclipse中,当然你也可以从eclipse来使用maven插件来构建项目,我的测试项目如下:

    如果提示错误

    The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path

    这是因为没有添加servlet类库,可以在pom添加servlet的依赖库,也可以添加server runtime的tomcat server.

    默认的部署文件web.xml

    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
    </web-app>
  2. 运行

    建立完毕后我们可以通过Run As -> Run on Server就可以浏览index.jsp了(我用的Eclipse是Eclipse Java EE IDE for Web Developers.),显示“Hello World!”。

    添加Servlet:项目"mytest"右键->New->Other->Web->Servlet,ClassName填上“HelloOther”,Next会让设置URL路径,初始值等,再Next可以看到你需要的方法如doGet、doPost等,Finish后你会看到web.xml:

    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
      <servlet>
      	<servlet-name>HelloOther</servlet-name>
      	<display-name>HelloOther</display-name>
      	<description></description>
      	<servlet-class>net.oseye.web.HelloOther</servlet-class>
      </servlet>
      <servlet-mapping>
      	<servlet-name>HelloOther</servlet-name>
      	<url-pattern>/HelloOther</url-pattern>
      </servlet-mapping>
    </web-app>
    如上述原理,当Clinet请求”/HelloOther“时,Web Container会在部署描述文件web.xml中寻找servlet-name为的HelloOther的servlet配置,再找到处理这个请求的servlet类“net.oseye.web.HelloOther”。

    net.oseye.web.HelloOthe类的doGet方法体中编码:

    response.getWriter().println("Hello Other!");
    你访问”/HelloOther“就能看到结果了。
  3. 打包WAR    

    可以使用mvn命令创建WAR包:

    mvn package
    也可以使用Eclipse的Export菜单来导出WAR包。

PS:这里我们只使用Tomcat,没看到使用Web Server呀?这是因为Tomcat本身就具有基本的HTTP服务器的功能,只是没有Apache等专业的Web Server健壮和完整。

简单的MVC

前面的示例我们在servlet中使用了

response.getWriter().println("Hello Other!");

但如果是整个HTML页面将会非常麻烦,因此我们考虑使用MVC架构,servlet充当Controller角色,JSP充当View,Java Class充当Model,结构图如下:

通过Controller(servlet)从Model(DB)中获取数据,然后把数据包装成Servlet的请求属性,然后把请求(request和reponse)转发至Jsp(View),JSP生成一个HTML页面,并使用应答对象(response)返回至容器,示例图如下:

接着上面的示例代码,net.oseye.web.HelloOthe类的doGet方法体中编码:

request.setAttribute("word", "Hello Other!");
RequestDispatcher view=request.getRequestDispatcher("HelloOther.jsp");
view.forward(request, response);

HelloOther.jsp的代码如下:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<%=request.getAttribute("word")%>
</body>
</html>

这就实现了MVC结构,项目结构图如下:

后记

  1. ServletConfig和ServletConext
    Servlet的无参构造函数只是让Servlet变成一个对象,而init()方法让其成为一个Servleet对象,每个Servlet都有一个ServletConfig对象,用于访问部署配置文件信息,而且可以通过ServletConfig对象访问ServletContext。每个Web应用都有一个ServletContext对象,用来访问容器相关信息以及部署配置文件,其实ServletContext称为AppContext更合适一些。
    部署(DD)文件web.xml是这样的:
    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
      <context-param>
      	<param-name>email</param-name>
      	<param-value>kevin@oseye.net</param-value>
      </context-param>
    
      <servlet>
      	<servlet-name>HelloOther</servlet-name>
      	<display-name>HelloOther</display-name>
      	<description></description>
      	<servlet-class>net.oseye.web.HelloOther</servlet-class>
      	<init-param>
      		<param-name>tel</param-name>
      		<param-value>13910567832</param-value>
      	</init-param>
      </servlet>
    
      <servlet-mapping>
      	<servlet-name>HelloOther</servlet-name>
      	<url-pattern>/HelloOther</url-pattern>
      </servlet-mapping>
    
    </web-app>
    可以在net.oseye.web.HelloOther的doGet中编码获取:
    String tel=getServletConfig().getInitParameter("tel");
    String email=getServletContext().getInitParameter("email");
    response.getWriter().println("tel:"+tel+",email:"+email);
  2. 应答除了分派给JSP,还可以使用PrintWriter和ServletOutputStream,前者是字符,后者是流。获取方式:
    PrintWriter pr=response.getWriter();
    ServletOutputStream os=response.getOutputStream();
  3. 请求和应答常用的方法
    request.getParameter(arg0) //获取get/post参数值
    request.getHeader(arg0) //获取头信息
    request.getCookies() //获取cookies
    request.getSession() //获取session
    request.getRequestDispatcher(arg0) //分派请求
    
    response.sendRedirect(String arg0) //重定向
    response.setHeader(String arg0, String arg1) //设置头信息,如果重复就替换
    response.addHeader(String arg0, String arg1) //添加头信息
    response.setContentType(arg0) //设置ContentType,避免手动拼写错误
posted @ 2014-10-08 15:15  码农神说  阅读(148)  评论(0编辑  收藏  举报