對天乙社區bbscs8實現的詳細分析十四

此文爲轉載: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">&nbsp;</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;
}
}

發佈了76 篇原創文章 · 獲贊 4 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章