12.3.2 account-web的主代码

account-web的主代码包含了2个JSP页面和4个Servlet,它们分别为:

signup.jsp:账户注册页面。

login.jsp:账户登录页面。

CaptchaImageServlet:用来生成验证码图片的Servlet。

LoginServlet:处理账户注册请求的Servlet。

ActivateServlet:处理账户激活的Servlet。

LoginServlet:处理账户登录的Servlet。

Servlet的配置可以从web.xml中获得,该文件位于项目的src/main/webapp/WEB-INF/目录。其内容见代码清单12-9。

代码清单12-9 account-web的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>Sample Maven Project:Account Service</display-name>

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener

</listener-class>

</listener>

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>

classpath:/account-persist.xml

classpath:/account-captcha.xml

classpath:/account-email.xml

classpath:/account-service.xml

</param-value>

</context-param>

<servlet>

<servlet-name>CaptchaImageServlet</servlet-name>

<servlet-class>com.juvenxu.mvnbook.account.web.CaptchaImageServlet</serv-

let-class>

</servlet>

<servlet>

<servlet-name>SignUpServlet</servlet-name>

<servlet-class>com.juvenxu.mvnbook.account.web.SignUpServlet</servlet-

class>

</servlet>

<servlet>

<servlet-name>ActivateServlet</servlet-name>

<servlet-class>com.juvenxu.mvnbook.account.web.ActivateServlet</serv-

let-class>

</servlet>

<servlet>

<servlet-name>LoginServlet</servlet-name>

<servlet-class>com.juvenxu.mvnbook.account.web.LoginServlet</servlet-

class>

</servlet>

<servlet-mapping>

<servlet-name>CaptchaImageServlet</servlet-name>

<url-pattern>/captcha_image</url-pattern>

</servlet-mapping>

<servlet-mapping>

<servlet-name>SignUpServlet</servlet-name>

<url-pattern>/signup</url-pattern>

</servlet-mapping>

<servlet-mapping>

<servlet-name>ActivateServlet</servlet-name>

<url-pattern>/activate</url-pattern>

</servlet-mapping>

<servlet-mapping>

<servlet-name>LoginServlet</servlet-name>

<url-pattern>/login</url-pattern>

</servlet-mapping>

</web-app>


web.xml首先配置了该Web项目的显示名称,接着是一个名为ContextLoaderListener的ServletListener。该listener来自spring-web,它用来为Web项目启动Spring的IoC容器,从而实现Bean的注入。名为contextConfigLocation的context-param则用来指定Spring配置文件的位置。这里的值是四个模块的Spring配置XML文件,例如classpath://account-persist.xml表示从classpath的根路径读取名为account-persist.xml的文件。我们知道account-persist.xml文件在account-persist模块打包后的根路径下,这一JAR文件通过依赖的方式被引入到ac-count-web的classpath下。

web.xml中的其余部分是Servlet,包括各个Servlet的名称、类名以及对应的URL模式。

下面来看一个位于src/main/webapp/目录的signup.jsp文件,该文件用来呈现账户注册页面。其内容如代码清单12-10所示。

代码清单12-10 signup.jsp


<%@page contentType="text/html;charset=UTF-8"language="java"%>

<%@page import="com.juvenxu.mvnbook.account.service.*,

org.springframework.context.ApplicationContext,

org.springframework.web.context.support.WebApplicationContextUtils"%>

<html>

<head>

<style type="text/css">

……

</style>

</head>

<body>

<%

ApplicationContext context=WebApplicationContextUtils.getWebApplicationContext(

getServletContext());

AccountService accountervice=(AccountService)context.getBean("accountSer-

vice");

String captchaKey=accountervice.generateCaptchaKey();

%>

<div class="text-field">

<h2>注册新账户</h2>

<form name="signup"action="signup"method="post">

<label>账户ID:</label><input type="text"name="id"></input><br/>

<label>Email:</label><input type="text"name="email"></input>

<br/>

<label>显示名称:</label><input type="text"name="name"></input>

<br/>

<label>密码:</label><input type="password"name="password"></input>

<br/>

<label>确认密码:</label><input type="password"name="confirm_password">

</input><br/>

<label>验证码:</label><input type="text"name="captcha_value"></in-

put><br/>

<input type="hidden"name="captcha_key"value="<%=captchaKey%>"/>

<img src="<%=request.getContextPath()%>/captcha_image?key=<%=cap-

tchaKey%>"/>

</br>

<button>确认并提交</button>

</form>

</div>

</body>

</html>


该JSP的主题是一个name为signup的HTML FORM,其中包含了ID、Email、名称、密码等字段,这与一般的HTML内容并无差别。不同的地方在于,该JSP文件引入了Spring的ApplicationContext类,并且用此类加载后台的accountService,然后使用accountService先生成一个验证码的key,再在FORM中使用该key调用captcha_image对应的Servlet生成其标识的验证码图片。需要注意的是,上述代码中略去了css片段。

账户注册页面如图12-1所示。

12.3.2 account-web的主代码 - 图1

图 12-1 账户注册页面

上述JSP中使用到了/captcha_image这一资源获取验证码图片。根据web.xml,我们知道该资源对应了CaptchaImageServlet。下面看一下它的代码,见代码清单12-11。

代码清单12-11 CaptchaImageServlet.java


package com.juvenxu.mvnbook.account.web;

import java.io.IOException;

import……

public class CaptchaImageServlet

extends HttpServlet

{

private ApplicationContext context;

private static final long serialVersionUID=5274323889605521606L;

@Override

public void init()

throws ServletException

{

super.init();

context=WebApplicationContextUtils.getWebApplicationContext(getServ-

letContext());

}

public void doGet(HttpServletRequest request,HttpServletResponse response)

throws ServletException,

IOException

{

String key=request.getParameter("key");

if(key==null| |key.length()==0)

{

response.sendError(400,"No Captcha Key Found");

}

else

{

AccountService service=(AccountService)context.getBean("account-

Service");

try

{

response.setContentType("image/jpeg");

OutputStream out=response.getOutputStream();

out.write(service.generateCaptchaImage(key));

out.close();

}

catch(AccountServiceException e)

{

response.sendError(404,e.getMessage());

}

}

}

}


CaptchaImageServlet在init()方法中初始化Spring的ApplicationContext,这一context用来获取Spring Bean。Servlet的doGet()方法中首先检查key参数,如果为空,则返回HTTP 400错误,标识客户端的请求不合法;如果不为空,则载入AccountService实例。该类的generateCaptchaImage()方法能够产生一个验证码图片的字节流,我们将其设置成image/jpeg格式,并写入到Servlet相应的输出流中,客户端就能得到图12-1所示的验证码图片。

代码清单12-10中FROM的提交目标是signup,其对应了SignUpServlet。其内容如代码清单12-12所示。

代码清单12-12 SignUpServlet.java


public class SignUpServlet

extends HttpServlet

{

private static final long serialVersionUID=4784742296013868199L;

private ApplicationContext context;

@Override

public void init()

throws ServletException

{

super.init();

context=WebApplicationContextUtils.getWebApplicationContext(getServ-

letContext());

}

@Override

protected void doPost(HttpServletRequest req,HttpServletResponse resp)

throws ServletException,

IOException

{

String id=req.getParameter("id");

String email=req.getParameter("email");

String name=req.getParameter("name");

String password=req.getParameter("password");

String confirmPassword=req.getParameter("confirm_password");

String captchaKey=req.getParameter("captcha_key");

String captchaValue=req.getParameter("captcha_value");

if(id==null| |id.length()==0| |email==null| |email.length()==0| |

name==null

| |name.length()==0| |password==null| |password.length()==0| |con-

firmPassword==null

| |confirmPassword.length()==0| |captchaKey==null| |captchaKey.length

()==0| |captchaValue==null

| |captchaValue.length()==0)

{

resp.sendError(400,"Parameter Incomplete.");

return;

}

AccountService service=(AccountService)context.getBean("accountSer-

vice");

SignUpRequest request=new SignUpRequest();

request.setId(id);

request.setEmail(email);

request.setName(name);

request.setPassword(password);

request.setConfirmPassword(confirmPassword);

request.setCaptchaKey(captchaKey);

request.setCaptchaValue(captchaValue);

request.setActivateServiceUrl(getServletContext().getRealPath("/")+

"activate");

try

{

service.signUp(request);

resp.getWriter().print("Account is created,please check your mail box

for activation link.");

}

catch(AccountServiceException e)

{

resp.sendError(400,e.getMessage());

return;

}

}

}


SignUpServlet的doPost()接受客户端的HTTP POST请求,首先它读取请求中的id、name、email等参数,然后验证这些参数的值是否为空,如果验证正确,则初始化一个Sign-UpRequest实例,其包含了注册账户所需要的各类数据。其中的activateServiceUrl表示服务应该基于什么地址发送账户激活链接邮件,这里的值是与signup平行的activate地址,这正是ActivationServlet的地址。SignUpServlet使用AccountService注册账户,所有的细节都已经封装在AccountService中,如果注册成功,服务器打印一条简单的提示信息。

上面介绍了一个JSP和两个Servlet,它们都非常简单。鉴于篇幅的原因,这里就不再详细解释另外几个JSP及Servlet。感兴趣的读者可以自行下载本书的样例源码。