
5.3 使用Servlet和JSP技术开发互联网系统
Java语言是一个面向对象的语言。每一个类可以看作是一个独立的个体,完成不同的功能,彼此功能不重叠。各个类之间互相协调工作,组成一个条理分明、工作有序的整体,从而使程序体可读性强、出错率低、易调试,编程速度和质量都大大提高。从工程的角度上说,开发费用和维护费用都有较大程度地降低。
Java的一个最大优势就是网络编程。当前Java Web应用的范围非常广泛,Servlet就是最主要的Java Web组件之一,它运行在服务端的Servlet容器当中,使用的是“request/response(请求/响应)”的工作模式。JSP(Java server page)技术作为Servlet的扩展,其目的是简化建立和管理动态网站的工作,能够很有效地分离业务逻辑和显示逻辑。
5.3.1 Servlet概述
Java Servlet是与平台无关的服务器端组件,它在Web服务器上或应用服务器上运行并扩展了该服务器的能力,Java Servlet API定义了Servlet和服务器之间的一个标准接口,这使得Servlet具有跨服务器平台的特性。
在传统的CGI中,每个请求都要启动一个新的进程,如果CGI程序本身的执行时间较短,启动进程所需要的开销很可能反而超过实际执行时间。而使用Servlet时,服务器上仅有一个Java虚拟机在运行,只有当Servlet被调用时,它才被加载,且直到Servlet更改时,它才会被再次加载。在传统CGI中,如果有N个并发的对同一CGI程序的请求,则该CGI程序的代码在内存中重复装载了N次;而对于Servlet,处理请求的是N个线程,只需要一份Servlet类代码。在性能优化方面,Servlet也比CGI有着更多的选择,比如缓存以前的计算结果,保持数据库连接的活动等。
通过使用Servlet API,开发人员不必担心服务器的内部运作方式。表格资料、服务器头、cookies等皆可通过Servlet处理。另外,因为Servlet是用Java写的,能将其从一个服务器移到另一个服务器以供发布,同时不必担心操作系统或服务器的类型。这一优点充分体现了Java“一次编写,随处运行”的优越特性。
Servlet可完成如下功能:
(1)创建并返回基于客户请求的动态HTML页面。
(2)创建可嵌入到现有HTML页面中的部分HTML页面(HTML片段)。
(3)与其他服务器资源(如文件、数据库或Java应用程序等)进行通信。
(4)接受多个客户机的输入,并将结果广播到多个客户机上。例如,Servlet可实现多人参与的游戏服务器。
(5)根据客户请求采用特定的MIME(multipurpose Internet mail extensions)类型对数据过滤,例如进行图像格式转换等。
Servlet的框架由两个Java包组成:javax.servlet和javax.servlet.http。在javax.servlet包中定义了必须实现或扩展的通用接口(interface)和类(class); javax.servlet.http包中定义的则是采用HTTP协议通信的HttpServlet类。Servlet框架的核心是javax.servlet.Servlet接口,所有的Servlet都必须实现这个接口。
5.3.2 JSP概述
JSP技术是由Servlet扩展出来的,结合传统网页的HTML标签和JSP标签就构成了JSP网页,可以被用来操作数据库、重定向网页以及发送E-mail等。
使用JSP可以有效地分离HTML编码和业务逻辑,通常JSP被用来实现动态的HTML页面,业务逻辑由其他可重用的组件(Servlet、JavaBean)和Java程序来实现,JSP可通过程序片断来访问这些业务组件。
一般情况下,JSP文件在Web服务器端会被解析成Servlet来执行,其过程是:当一个JSP请求发送过来之后,Web服务器就会对JSP文件进行解析生成Servlet源文件,然后会被编译器编译生成Java class,这个过程仅在JSP被初次调用时发生,如果JSP文件发生改变,服务器再去解析一遍重新编译产生class文件,过程如图5-14所示。

图5-14 Web服务器初次解析JSP流程
对于一个正常的JSP文件,通常包括以下一些主要内容:
1.JSP指令
用来设置和整个JSP页面相关的属性,如网页的编码方式和脚本语言等,这部分内容放在<%@和%>之间,指令的语法形式为<%@ 指令名 属性=“值”%>。常用的指令为page, include和taglib,例如:
<%@ page contentType=″text/html; charset=GBK″%><! --注释 指定响应结果类型--> <%@ page import=″cn.edu.pku.icst.dm.*″%><! --指定导入的软件包名-->
2.JSP声明
用于声明JSP所代表的Servlet类的成员变量和成员方法,代码放置在<%!和%>之间,例如:
<%! String stock_id=new String(″600000″); %> <! --注释 声明一个String类型变量-->
声明只在当前的JSP文件中有效,如果当前页面所包含的页面文件中存在声明,则同样在当前的JSP页面有效。
3.Java程序段(scriptlet)
由于JSP技术是基于Java的动态网页技术,所以会用到Java的相应程序代码,这些代码在JSP文件中被放在<%和%>之间,可以实现Java程序能够在前端实现的功能,例如:
<% if(session.isNew()! = true){ //判断会话是否已经过期 session.invalidate(); //使会话失效 } response.sendRedirect(″login.jsp″); //使页面转向login.jsp %>
4.变量表达式
Java变量表达式标记为<%=和%>,该表达式的值会被显示到前端页面上,以下是包含变量表达式的例子:
<%=stock_id%> //输出到网页上显示
5.隐含对象
Servlet/JSP容器提供了一系列的隐含对象,可以直接使用它们,不用进行声明,JSP有9个隐含对象,如表5-1所示。
表5-1 JSP隐含对象列表

5.3.3 JavaBean组件
JavaBean是Java类,它是一个Java Web应用的标准部件,被定义为一种可重复使用、跨平台的软件构件。JavaBean分为两种:一种是有界面(UI)的JavaBean,还有一种是没有界面的,主要负责处理事务的JavaBean。使用JSP可以访问JavaBean,通常JSP访问的是无界面的JavaBean,以实现某种逻辑功能。
JavaBean的实现需要一个公共(public)的Java类(class)的声明,该类需要有一个不带参数的构造方法,JavaBean中的属性通过setXXX()方法来进行设置,通过getXXX()方法进行属性获取,这样的方法通常都被声明成公共(public)的。JavaBean中除了可以定义set和get方法,也能定义一些其他的具有特定功能的方法来协助处理事务。
以下是一个JavaBean类的代码示例,该JavaBean名为StockBean,在这个JavaBean中定义了一个属性num,还定义了访问这个属性的方法setNum()和getNum():
package cn.edu.pku.icst.dm public class StockBean{ private int num=100; public StockBean(){} public int getNum(){ return num; } public void setNum(int num){ this.num= num; } }
JavaBean属于具有规范编码方式的组件,并且扩展了适应性和范围,允许用户访问内部的属性和方法。
在开发互联网信息挖掘系统中使用JavaBean,主要是通过和JSP搭配来处理相应的请求,同时还有Servlet进行相应事务和请求的处理,这样能够使得系统的开发更加规范和高效。
JavaBean结合JSP使用的优势主要体现在以下几个方面:
(1)JavaBean的使用可以更好地将HTML与Java代码进行分离,便于系统的维护工作。单一地依靠JSP来完成同样的功能会使得代码变得繁杂。
(2)分离地实现可以降低JSP网页编程人员对Java编码能力的要求,提高网页的实现效率。
(3)使用JSP重点实现动态网页,事务处理可交由JavaBean完成,能够充分利用JavaBean组件的可重用性特点。
在动态网页JSP中使用JavaBean的操作也很简单,首先是导入JavaBean类,使用<%@page import %>指令进行,举例如下:
<%@page import=″cn.edu.pku.icst.dm.StockBean″%>
接下来在下面的JSP文件中对JavaBean进行声明,使用<jsp:useBean>标签进行,如下:
<jsp:useBean id=″stockbean″class=″cn.edu.pku.icst.dm.StockBean″scope=″session″/>
然后就可以访问该JavaBean的属性了,通过标签<jsp:getProperty>和<jsp:setProperty>来操作使用:
<jsp:getProperty name=″stockbean″property=″num″/> <! --注释:得到属性值--> <jsp:setProperty name=″stockbean″property=″num″value=″50″/> <! --设置属性值-->
5.3.4 Java Web组件应用
运行在互联网上的系统一般采用当前很流行的Java Web组件技术,能够很方便地构造基于Web的应用程序。
考虑到MVC模式能够通过分离数据及其表示来分离控制逻辑和表现界面,使用该模式可降低系统中各个模块之间的耦合,从而增强代码的可重用性和可维护性。这里采用如图5-15所示的一个结构。

图5-15 系统设计模式图
图5-15中所示Servlet用来处理用户从浏览器提交的请求,通过相应的JavaBean实现到数据层的交互,最后经过JSP将响应发回到相应的用户端,数据库的连接由一个连接的缓冲池来建立,可以提高存取数据的效率。
这里简要介绍一个金融文件上传系统的基本功能设计实现过程,主要是Java Web组件的应用。金融信息的提交包含许多与上市公司相关的信息,如公司名称、地址、电话、传真以及人员信息等。为了更加有效地对这些信息资源进行管理,我们在系统中需要设计合理的数据库结构来配合系统的运行。
系统面向的对象有两个,即管理员、普通用户,他们各自的分工有所不同,管理员负责对所有用户和他们上传内容的管理,普通用户有权对上传的金融文件信息和个人资料进行调整。
按照上述的设计模式,成功地实现了一个金融文件信息的上传系统。
用Java实现的类主要有如下几个:
(1)Registerservlet,用户注册和修改个人资料功能;
(2)LoginServlet,用户登录验证功能;
(3)FileUploadServlet,信息及文件上传功能;
(4)PropertyConfig,为JavaBean,具有属性配置读取功能;

图5-16 类关系图
(5)DeleteServlet,信息删除功能;
(6)SendMail,发送邮件功能。
主要的类之间的逻辑关系如图5-16所示。
用户登录界面由JSP动态实现,包含一些供用户输入名称和密码的界面,并包含验证JavaBean来进行输入有效性检查,主要部分如下:
<%@page contentType=″text/html; charset=GB2312″%> <! --页面信息--> <%@page import=″cn.edu.pku.icst.dm.ValidateBean″%> <! --引入有效性验证包--> <html> <head> <title>金融文件上传系统 - 登录</title> ... <jsp:useBean id=″validate″class=″cn.edu.pku.icst.dm.ValidateBean″scope=″application″/> <! --对有效性验证JavaBean进行声明--> <% String username= request.getParameter(″user″); boolean isNamealidate= validate.isValicate(username); //调用JavaBean进行有效性验证 %> ... </html>
用户注册是用Servlet来实现的,用户输入基本信息,然后提交到系统,可以产生一个新的用户账号。这个类可以被用来更新用户个人资料,也就是通过改变传递的参数来区分是新注册用户还是老用户的资料修改。代码按照Servlet的写法,处理方法在doGet()中实现,如下:
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{ response.setContentType(CONTENT_TYPE); request.setCharacterEncoding(″GB2312″); //设置页面编码 String username= (String)request.getParameter(″username″); //获取用户资料参数 String email= (String)request.getParameter(″email1″); String addr= (String)request.getParameter(″addr″); String phonee= (String)request.getParameter(″phone″); register(username, pwd, email, addr, phone); //调用注册方法 }
用户登录也是用Servlet实现,用户在登录界面输入他的用户名和密码,如果正确则会被赋予一定的权限来进入到系统中,可以执行权限范围内的操作。
在模块的处理过程中首先会按照用户输入的名称进行查询,获取密码之后会和用户输入的密码进行比较,然后会从数据库中返回应有的权限,如果失败则回到登录页重新进入,利用doGet或doPost方法均可实现,只是接受参数的方式不一样,doGet方法实现如下:
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{ response.setContentType(CONTENT_TYPE); request.setCharacterEncoding(″GB2312″); //设置页面编码 String username= (String)request.getParameter(″username″); //获取用户输入参数 String password= (String)request.getParameter(″password″); checkUser(username, pwd); //调用检查用户方法 }
doPost方法中嵌入doGet的处理方式可以处理前端页面post方式提交过来的请求,代码如下:
public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{ doGet(request, response); }
系统中同时需要使用发送电子邮件(E-mail)通知用户的功能,对于这一功能我们通过编写一个JavaBean调用javamail包来实现,类名为SendMail,实现的相应功能方法如下:
private void sendMessage(String recipient, String subject, String message){ Properties props= new Properties(); props.put(″mail.smtp.auth″, ″false″); props.put(″mail.host″, SMTP_HOST); props.put(″mail.smtp.user″, ″″); props.put(″mail.smtp.password″, ″″); Session session= Session.getDefaultInstance(props, null); try{ Message msg= new MimeMessage(session);
msg.setFrom(new InternetAddress(SENDER_EMAIL_ADDRESS, SENDER_NAME)); msg.setRecipient(Message.RecipientType.TO, new InternetAddress(recipient)); msg.setSubject(subject); msg.setSentDate(new Date()); msg.setText(message); //设置发送的信息内容 Transport transport= session.getTransport(″smtp″); transport.connect((String)props.get(″mail.smtp.host″), props.getProperty(″mail.smtp.user″), props.getProperty(″mail.smtp.password″)); transport.sendMessage(msg, msg.getAllRecipients()); }catch(Exception e){ System.out.println(e); } }
关于Java Web组件的使用,限于篇幅的原因就不做过多的介绍了,相应系统的详细实现过程可以在后续的章节中看到。