此文爲轉載:http://www.diybl.com/course/1_web/webjs/2007113/82989.html
OK!return SUCCESS;到<result name="success" type="redirect">${tourl}</result>
當然,我們先講下cookieLogin方法先:它由check發現後轉到這裏...
public String check() {
if (StringUtils.isNotBlank(this.getUserCookie().getUserName())
&& StringUtils.isNotBlank(this.getUserCookie().getPasswd()))
{
return this.cookieLogin();
} else {
return this.index();
}
}
我們這裏可以觀察其不同點在於:
UserInfo ui = this.getUserService().findUserInfoByUserName(this.getUserCookie().getUserName
());
if (ui == null) {
this.addActionError(this.getText("error.user.notexist"));
return INPUT;
}
if (!this.getUserCookie().getPasswd().equals(ui.getRePasswd())) {
if (this.getSysConfig().isUseSafeLogin()) {
try {
this.getLoginErrorService().createLoginError
(ui.getId());
} catch (BbscsException ex1) {
logger.error(ex1);
}
}
this.addActionError(this.getText("error.login.passwd"));
return INPUT;
}
以及後面的tourl的設置,因爲check中並沒來的急設置它:
if (Constant.USE_URL_REWRITE) {
tourl = this.getBasePath() + "main.html";
} else {
tourl = this.getBasePath() +
BBSCSUtil.getActionMappingURLWithoutPrefix("main");
}
哦,我們還少分析了loginPass:
public String input() {
if (this.getSysConfig().getUsePass() == 0) {
return INPUT;
} else {
this.setActionUrl(this.getSysConfig().getPassUrl
());//http://www.laoer.com/login
return "loginPass";//而其對應的passLogin.jsp卻比login.jsp簡單...不知
有什麼用...
}
}
對了,我們還有
if (this.getAction().equalsIgnoreCase("admin")) {
this.setAction("login");
this.setHiddenLogin(0);
tourl = this.getBasePath() +
BBSCSUtil.getActionMappingURLWithoutPrefix("adminMain");//注意點
return this.input();
}
if (this.getAction().equalsIgnoreCase("relogin")) {
this.setAction("login");
this.setHiddenLogin(0);
if (Constant.USE_URL_REWRITE) {
tourl = this.getBasePath() + "main.html";
} else {
tourl = this.getBasePath() +
BBSCSUtil.getActionMappingURLWithoutPrefix("main");
}
this.addActionError(this.getText("error.login.re"));//注意點
return this.input();
}
首先我們看Login SUCCESS指的是什麼:
public interface Action
{ public abstract String execute()
throws Exception;
public static final String SUCCESS = "success";
public static final String NONE = "none";
public static final String ERROR = "error";
public static final String INPUT = "input";
public static final String LOGIN = "login";
}
OK,<result name="success" type="redirect">${tourl}</result>轉到tourl去/main.bbscs(未用
UrlRewriter)
爲了先把用戶這塊講完,我們選擇了註冊流程來分析:/reg/input
<package name="reg" extends="bbscs-default" namespace="/reg"> //namespace哦!
<global-results>
<result name="input">/WEB-INF/jsp/reg.jsp</result>
<result name="passreg" type="redirect">
${sysConfig.getPassRegUrl()}
</result>
</global-results>
<action name="input" class="regAction" method="input"></action>//注意它沒有
什麼result
我們到action-servlet.xml找到<bean id="regAction" class="com.laoer.bbscs.web.action.Reg"
scope="prototype" autowire="byName"></bean>
進入com.laoer.bbscs.web.action.Reg extends BaseAction implements RemoteAddrAware,
UserCookieAware:
它有
answer,email,nickName,passwd,question,rePasswd,userName,validateCode,authCode,useAuthCode=tr
ue,userRemoteAddr,userCookie,也注入了一此服務sysConfig,ipSeeker,templateMail,sysStatService
我們看下input:
public String input() throws Exception {
if (this.getSysConfig().getUsePass() == 1) {//使用通行證
return "passreg";
}
//usePass=0
if (this.getSysConfig().getOpenUserReg() == 0) { // 關閉註冊
addActionError(this.getText("error.reg.notallowreg"));
return ERROR;
}
this.setUseAuthCode(this.getSysConfig().isUseRegAuthCode());//=1
this.setAction("add");
return INPUT;
}
好,我們看reg.jsp:
<tr>
<td width="170"><div align="right"><s:text name="reg.username"/>:<span
class="font2">*</span></div></td>
<td width="180">
<s:textfield name="userName" id="userName" cssClass="input1" size="30" maxlength="20"
οnfοcus="changeStyle('usernameMsg','msg2');" οnblur="changeStyle
('usernameMsg','msg1');"></s:textfield>
</td>
<td width="370">
<div class="msg1" id="usernameMsg"><s:text name="reg.username.notice"/></div>
<s:fielderror theme="bbscs0"> //bbscs0的fielderror
<s:param>userName</s:param>
</s:fielderror>
</td>
</tr>
<tr>
<td class="t1"> </td>
<td valign="top"><div align="center">
<input type="button" name="Check" value="<s:text name="reg.checkusename"/>"
class="button1" οnclick="checkUserNameAction();"/> //觸發js
</div></td>
<td>
<div id="checkUserNameMsg">
</div>
</td>
</tr>
<s:if test="%{useAuthCode}">
<tr>
<td><div align="right"><s:text name="login.authcode"/>:<span
class="font2">*</span></div></td>
<td>
<s:textfield name="authCode" id="authCode" cssClass="input1" οnfοcus="changeStyle
('authCodeMsg','msg2');" οnblur="changeStyle('authCodeMsg','msg1');" size="5"
maxlength="50">
</s:textfield>
<img alt="<s:text name="login.authcode"/>" src="<%=basePath%>authimg"
align="absmiddle" />
</td>
<td><div class="msg1" id="authCodeMsg"><s:text name="reg.authcode.motice"/></div>
<s:fielderror theme="bbscs0">
<s:param>authCode</s:param>
</s:fielderror>
</td>
</tr>
</s:if>
對於這三段代碼,我們一個一個來分析之:
function changeStyle(elementID,toStyle) {
document.getElementById(elementID).className=toStyle;
}
注意到:
<link href="<%=basePath%>css/css1.css" rel="stylesheet" type="text/css">
<script type="text/javascript" src="<%=basePath%>js/jsMsg.jsp"></script>
<script type="text/javascript" src="<%=basePath%>js/prototype.js"></script>
<script type="text/javascript" src="<%=basePath%>js/comm.js"></script>
css1中有一段樣式如下:
.msg1 {
color: #999999;
padding: 6px;
}
.msg2 {
background-color: #EDF3FA;
border: 1px solid #408FD0;
padding: 5px 5px 5px 25px;
background-image: url(../images/standard_msg_warning.gif);
background-repeat: no-repeat;
background-position: 5px 5px;
}
.msg3 {
background-color: #F0FFF0;
border: 1px solid #00EA00;
padding: 5px 5px 5px 25px;
background-image: url(../images/standard_msg_ok.gif);
background-repeat: no-repeat;
background-position: 5px 5px;
}
.errormsg {
background-color: #FFEFEE;
border: 1px solid #FF6860;
padding: 5px 5px 5px 25px;
background-image: url(../images/standard_msg_error.gif);
background-repeat: no-repeat;
background-position: 5px 5px;
line-height: 16pt;
}
而第三個authcode是否要取決於useAuthCode:在Reg.java中private boolean useAuthCode = true;
對於s:fielderror用於theme bbscs0 且這個標籤帶param!請自行參看源代碼!
<div class="errormsg">
<#assign doneStartUlTag=true><#t/>
</#if><#t/>
<#list eValue as eEachValue><#t/>
<span class="errorMessage">${eEachValue}</span><br/>
</#list><#t/>
</#if><#t/>
</#list><#t/>
</#list><#t/>
<#if (haveMatchedErrorField && (!doneEndUlTag))><#t/>
</div>
我們這樣重點看下:checkUserNameAction,這個請求是基於Ajax的:
function checkUserNameAction() {
if ($('userName').value == "" || $('userName').length == 0) {
alert("<s:text name="reg.inputusername"/>");
return;
}
$('checkUserNameMsg').className = "msg2";
$('checkUserNameMsg').innerHTML = "<s:text name="bbscs.checking"/>";
var url = getActionMappingURL("/reg/check");
/**在comm.js中:
function getActionMappingURL(action) {
var value = contextPath;//變量大多在jsMsg中定義!
var servletMapping = servletMappingStr;
var queryString;
var question = action.indexOf("?");
if (question >= 0) {
queryString = action.substring(question);
}
var actionMapping = getActionMappingName(action);
if (startsWith(servletMapping,"*.")) {
value += actionMapping;
value += servletMapping.substring(1);
}
else if (endsWith(servletMapping,"/*")) {
value += servletMapping.substring(0, servletMapping.length - 2);
value += actionMapping;
}
else if (servletMapping == "/") {
value += actionMapping;
}
if (queryString != undefined) {
value += queryString;
}
return value;
}
*/
var pars = "userName=" + $('userName').value;
var myAjax = new Ajax.Request(url, {method: 'get', parameters: pars, onComplete:
showResult}); //prototype的Ajax.Request關鍵點
}
function showResult(res) {
resText = res.responseText;
var jsonMsgObj = new JsonMsgObj(resText);
/**
var JsonMsgObj = function(responseText) {
this.json = eval('(' + responseText + ')');
}
JsonMsgObj.prototype.getCodeid = function() {
return this.json.codeid;
}
JsonMsgObj.prototype.getMessage = function() {
return this.json.message;
}
JsonMsgObj.prototype.getText = function() {
return this.json.text;
}
*/
//alert(jsonMsgObj.getCodeid());
var codeid = jsonMsgObj.getCodeid();
if (codeid == "0") {
$('checkUserNameMsg').className = "msg3"; //OK
}
else {
$('checkUserNameMsg').className = "errormsg";
}
$('checkUserNameMsg').innerHTML = jsonMsgObj.getMessage();
}
這裏用了json和prototype,設置了傳回來的Json爲utf-8,而且把json數據直接扔進responseText回來後自
己eval的,OK!我們進入後端:/reg/check?userName=?
<action name="check" class="checkUserNameAction"></action>
-->
<bean id="checkUserNameAction"
class="com.laoer.bbscs.web.action.CheckUserName" scope="prototype"
autowire="byName">
<!--
<property name="userService">
<ref bean="userService" />
</property>
<property name="sysConfig">
<ref bean="sysConfig" />
</property>
<property name="ajaxMessagesJson"> //注意哦!
<ref bean="ajaxMessagesJson" />
</property>
-->
</bean>
由於它與Json有聯繫,因此寫在一個專門的文件中..它首先引入了
sysConfig,ajaxMessagJson,userService三個服務,也有一個屬性userName;下面是其execute方法
public String execute() {
if (StringUtils.isBlank(this.getUserName())) {
this.getAjaxMessagesJson().setMessage("E_USERNAME_001", "請填寫用戶
名!");
}
else if (!Util.validateUserName(this.getUserName())) {
/**
public static boolean validateUserName(String username) {
Pattern p = Pattern.compile("^/w+$");
Matcher m = p.matcher(username);
if (m.find()) {
return true;
}
return false;
}
*/
this.getAjaxMessagesJson().setMessage("E_USERNAME_002", "用戶名只能
由英文、數字和下劃線組成!");
}
else if (this.getSysConfig().isCanNotRegUserName(this.getUserName())) {
this.getAjaxMessagesJson().setMessage("E_USERNAME_004", "該用戶不能
註冊!");
}
else {
UserInfo userInfo = this.getUserService().findUserInfoByUserName
(this.getUserName());
if (userInfo != null) {
this.getAjaxMessagesJson().setMessage("E_USERNAME_003", "用
戶名已存在,請選擇其他用戶名!");
}
else {
this.getAjaxMessagesJson().setMessage("0", "該用戶名可以註冊
!");//返回0可以註冊哦!其它不行
}
}
// System.out.println(this.getAjaxMessagesJson().getJsonString());
return RESULT_AJAXJSON;//ajaxjson是個頁面,輸出json數據,這個我們可以看bbscs
-default package中的global-results中<result name="ajaxjson">/WEB-
INF/jsp/ajaxjson.jsp</result>
/**看BaseAction中的常量:
public static final String RESULT_AJAXJSON = "ajaxjson";
public static final String RESULT_HTMLERROR = "htmlError";
public static final String RESULT_ERROR = "error";
public static final String RESULT_JSONSTRING = "jsonstring";
而下面是ajaxjson.jsp的一部分:
<%
request.setAttribute("decorator", "none");
response.setHeader("Cache-Control","no-cache"); //HTTP 1.1
response.setHeader("Pragma","no-cache"); //HTTP 1.0
response.setDateHeader ("Expires", 0); //prevents caching at the proxy server
%>
<s:property value="ajaxMessagesJson.getJsonString()" escape="false"/>
*/
}
我們看下AjaxMessagesJson,它在com.laoer.bbscs.web.ajax(也就只有它一個文件):
public class AjaxMessagesJson {
private static final Log logger = LogFactory.getLog(AjaxMessagesJson.class);
private JSONObject json = new JSONObject();//用了json-lib-1.1-jdk15.jar
public void setMessage(String codeid, String message) {
try {
this.json.put("codeid", codeid);//codeid
this.json.put("message", message);//message
this.json.put("text", "");//空的text
} catch (JSONException e) {
logger.error(e);
}
}
public void setMessage(String codeid, String message, String text) {
try {
this.json.put("codeid", codeid);
this.json.put("message", message);
this.json.put("text", text);//不爲空的text
} catch (JSONException e) {
logger.error(e);
}
}
public String getJsonString() { //返回JsonString結果!
return this.json.toString();
}
}
好了,完成了用戶名的檢查和輸入其它字段,後我們點擊提交按鈕,我們看生成的html代碼:
<form id="add" name="add" οnsubmit="return true;" action="/bbscs8/reg/add.bbscs"
method="post">
好,進入struts.xml:
<action name="add" class="regAction" method="add">
<interceptor-ref name="remoteAddrInterceptorStack"></interceptor-
ref>
<interceptor-ref name="userCookieInterceptor"></interceptor-ref>
<result name="success" type="redirect">
/regSucceed.jsp
</result>
</action>
由於remoteAddrInterceptorStack包括defaultStack中的驗證validation!
<interceptor-stack name="remoteAddrInterceptorStack">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="remoteAddrInterceptor"></interceptor
-ref>
所以add請求會先執行Reg-validation.xml,再進入method=add中:
<field name="userName">
<field-validator type="requiredstring">//字段規則
<param name="trim">true</param>
<message key="error.reg.name.null"></message>
</field-validator>
<field-validator type="regex">
<param name="expression">w+</param>//正則!
<message key="error.reg.name0"></message>
</field-validator>
<field-validator type="stringlength">//長度
<param name="minLength">3</param>
<param name="maxLength">20</param>
<param name="trim">true</param>
<message key="error.reg.username.toolong"></message>
</field-validator>
</field>
<field name="rePasswd">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message key="error.reg.passwd.null"></message>
</field-validator>
<field-validator type="stringlength">
<param name="minLength">6</param>
<param name="maxLength">20</param>
<param name="trim">true</param>
<message key="error.reg.passwd.toolong"></message>
</field-validator>
<field-validator type="fieldexpression">//規則
<param name="expression">(rePasswd == passwd)</param>//兩字段相等
<message key="error.reg.passwd.notsame"></message>
</field-validator>
</field>
若出錯當然是到INPUT。檢查通過後便進入到add方法中:
public String add() {
if (this.getSysConfig().getUsePass() == 1) {
return "passreg"; //是否可通過
}
this.setUseAuthCode(this.getSysConfig().isUseRegAuthCode());//驗證碼是否使用
if (this.getSysConfig().getOpenUserReg() == 0) { // 關閉註冊
addActionError(this.getText("error.reg.notallowreg"));
return ERROR;
}
if (this.getSysConfig().isCanNotRegUserName(this.getUserName())) { // 不能注
冊的用戶名
addFieldError("userName", this.getText("error.reg.badusername", new
String[] { this.getUserName() }));//在字段錯誤中加入業務邏輯錯誤!
}
if (this.getSysConfig().getUseForbid() == 1) {
if (this.getSysConfig().isForbidIP(this.getUserRemoteAddr())) {
this.addFieldError("userName", this.getText
("error.reg.ipforbid", new String[] { this
.getUserRemoteAddr() }));//這裏說明userName
的FieldError可能有多個
}
if (this.getSysConfig().isForbidEmail(this.getEmail())) {
this.addFieldError("email", this.getText
("error.reg.emailforbid", new String[] { this.getEmail() }));
}
}
if (this.getSysConfig().isUseRegAuthCode()) {
if (!this.getUserCookie().getAuthCode().equals(this.getAuthCode()))
{
this.addFieldError("authCode", this.getText
("error.reg.authcode.same"));//注意驗證碼與cookie的關係!
}
}
if (this.hasFieldErrors()) {
return INPUT; //有錯誤到INPUT
}
UserInfo ui = this.getUserService().findUserInfoByUserName(this.getUserName
());
if (ui != null) {
this.addFieldError("userName", this.getText("error.reg.name1"));//更
高的業務邏輯考慮!
return INPUT;
}
ui = this.getUserService().findUserInfoByEmail(this.getEmail());
if (ui != null) {
this.addFieldError("email", this.getText("error.reg.emailerror"));
return INPUT;
}
ui = new UserInfo();//注意setPasswd和setRePasswd的不同
ui.setAcceptFriend(1);
ui.setAnswer(this.getAnswer());
ui.setArticleEliteNum(0);
ui.setArticleNum(0);
ui.setBirthDay(1);
ui.setBirthMonth(1);
ui.setBirthYear(1980);
ui.setEmail(this.getEmail());
ui.setExperience(0);
ui.setForumPerNum(0);
ui.setForumViewMode(0);
ui.setHavePic(0);
ui.setLastLoginIP("0.0.0.0");
ui.setLastLoginTime(new Date());
ui.setLifeForce(0);
ui.setLiterary(0);
ui.setLoginIP("0.0.0.0");
ui.setLoginTime(new Date());
ui.setLoginTimes(0);
ui.setNickName(this.getSysConfig().bestrowScreenNickName(this.getNickName
())); // 屏蔽敏感字
/**public String bestrowScreenNickName(String txt) {
if (StringUtils.isNotBlank(this.getCanNotUseNickName())) {
String[] words = this.getCanNotUseNickName().split(";");
for (int i = 0; i < words.length; i++) {
txt = txt.replaceAll(words[i], this.getBestrowScreen
());//bestrowScreen是固定值:在數據庫中爲**
}
}
return txt;
}
*/
ui.setPasswd(this.getPasswd());
ui.setPicFileName("");
ui.setPostPerNum(0);
ui.setQuestion(this.getQuestion());
ui.setReceiveNote(1);
ui.setRegTime(new Date());
ui.setRePasswd(Util.hash(this.getPasswd()));//其實hash方法是MD5加密!
ui.setSignDetail0(this.getText("bbscs.userdefaultsign"));
ui.setSignDetail1(this.getText("bbscs.userdefaultsign"));
ui.setSignDetail2(this.getText("bbscs.userdefaultsign"));
ui.setSignName0("A");
ui.setSignName1("B");
ui.setSignName2("C");
ui.setStayTime(0);
ui.setTimeZone("GMT+08:00");
ui.setUserFrom(this.getIpSeeker().getCountry(this.getUserRemoteAddr()));
ui.setUserKnow(0);
ui.setUserName(this.getUserName());
ui.setUserTitle(0);
if (this.getSysConfig().isCheckRegUser() || this.getSysConfig
().isCheckRegUserEmail()) { //默認兩者都爲0,審覈才能是會員!
ui.setValidated(0);
ui.setGroupID(Constant.USER_GROUP_UNVUSER);//未審覈
} else {
ui.setValidated(1);
ui.setGroupID(Constant.USER_GROUP_REGUSER);
}
ui.setEditType(-1);
ui.setUserLocale(this.getLocale().toString());//getLocale來自ActionSupport!
/**
public Locale getLocale()
{
return ActionContext.getContext().getLocale();
}
*/
ui.setValidateCode(RandomStringUtils.randomAlphanumeric(10));//用於審覈用的
,不是重複登錄用!隨機10位數
ui.setCoin(100);
UserDetail ud = new UserDetail();
ud.setBrief("");
ud.setDreamJob("");
ud.setDreamLover("");
ud.setFavourArt("");
ud.setFavourBook("");
ud.setFavourChat("");
ud.setFavourMovie("");
ud.setFavourMusic("");
ud.setFavourPeople("");
ud.setFavourTeam("");
ud.setGraduate("");
ud.setHeight("");
ud.setHomePage("");
ud.setIcqNo("");
ud.setInterest("");
ud.setMsn("");
ud.setOicqNo("");
ud.setSex((short) 0);
ud.setWeight("");
ud.setYahoo("");
ui.setUserDetail(ud);
ud.setUserInfo(ui);
try {
ui = this.getUserService().saveUserInfo(ui);
this.getSysStatService().saveAllUserNum(this.getUserService
().getAllUserNum(), this.getUserName());//重新從UserService得到最新的人數,還有最新的註冊名
寫入SysStatService!
if (this.getSysConfig().isCheckRegUserEmail()) {//需要用郵件來審覈之
String subject = this.getText("reg.validate.email.title",
new String[] { this.getSysConfig()
.getForumName() });
Map<String, String> root = new HashMap<String, String>();
root.put("website", this.getSysConfig().getForumName());
root.put("forumurl", this.getSysConfig().getForumUrl());
root.put("userName", ui.getUserName());
root.put("validateCode", ui.getValidateCode());//關鍵點...
this.getTemplateMail().sendMailFromTemplate(ui.getEmail(),
subject, "regValidate.ftl", root,
this.getLocale());
}//發信!
/**下面是模板文件的一段:
<table width="98%" border="0" align="center" cellpadding="5" cellspacing="0">
<tr>
<td><strong>非常感謝您成爲${website}的用戶</strong></td>
</tr>
<tr>
<td>您的帳戶尚處於未認證的狀態,只要你點擊下面的鏈接,即可通過認證</td>
</tr>
<tr>
<td><a href="${forumurl}/reg/validateuser.bbscs?userName=${userName}
&validateCode=${validateCode}" target="_blank">${forumurl}/reg/validateuser.bbscs?
userName=${userName}&validateCode=${validateCode}</a></td>
</tr>
</table>
*/
return SUCCESS;
} catch (BbscsException e) {
this.addActionError(this.getText
("error.reg.createrror"));//ActionError!
return ERROR;
}
}