⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 详细分析四.txt

📁 开源论坛实现
💻 TXT
📖 第 1 页 / 共 5 页
字号:
在分析三,我们已经分析出jsp页面如何通过struts2的标签与action配合,将数据在表示层传递(set/get),并且把主要的开始流程给分析完了。这里我们将前台的主要请求大致分析一下:从导航部分开始,对于社区首页in.bbscs我们已经讲过,它这里只不过是将框架的target=mainForm以便从任何位置转到首页!进入个人中心,点击修改签名,触发了signSet.bbscs:
<action name="signSet" class="signSetAction">
			<interceptor-ref name="mainUserAuthInterceptorStack"></interceptor-ref>//用户权限!
			<result name="success">/WEB-INF/jsp/signSet.jsp</result>
			<result name="input">/WEB-INF/jsp/signEdit.jsp</result>
		</action>
-->
注意到BaseMainAction:
	public String execute() {
		try {
			return this.executeMethod(this.getAction());
		} catch (Exception e) {
			logger.error(e);
			this.addActionError(this.getText("error.msg"));
			return ERROR;
		}
	}
而在BaseAction:private String action = "index";
	public String index() {
		String[] userSign = new String[3];
		userSign[0] = this.getUserSession().getSignDetail()[0];//从UserSession的SignDetail数组中把三个对象拿出来!
		userSign[1] = this.getUserSession().getSignDetail()[1];
		userSign[2] = this.getUserSession().getSignDetail()[2];
		userSign = BBSCSUtil.filterUserSign(userSign, this.getSysConfig().isSignUseHtml(), this.getSysConfig()
				.isSignUseUBB(), this.getSysConfig().isSignUseSmile());
		this.setUserSign0(userSign[0]);
		this.setUserSign1(userSign[1]);
		this.setUserSign2(userSign[2]);
		return SUCCESS;
	}
我们看一下signSet:
 <strong><a href="javascript:;" onclick="loadSignEditPage('0');"><s:text name="signset.sign"/>A</a></strong>
 <div id="signDiv0" class="signDivOff" onclick="loadSignEditPage('0');" onmouseover="over(this);" onmouseout="out(this);"><s:property value="%{userSign0}" escape="false"/></div>
需要注意到底部有个div:
 	<tr>
          <td colspan="2">
            <div id="signDetailChange"></div>
          </td>
        </tr>	
我们来看loadSignEditPage(signID):
function loadSignEditPage(signID) {
  Element.show("signDetailChange");
  $('signDetailChange').innerHTML = pageLoading;//在jsMsg.jsp中,var pageLoading = "<s:text name="js.pageLoading"/>";
  var url = getActionMappingURL("/signSet");
  var pars = "action=edit&ajax=shtml&signID=" + signID;

  var myAjax = new Ajax.Updater("signDetailChange", url, {method: 'get', parameters: pars});
}
我们看看这个/signSet?action=edit&ajax=shtml&singnID=0;
public String edit() {
		this.setAction("editdo"); //设置action!
		this.setSignDetail(this.getUserSession().getSignDetail()[this.getSignID()]);
		return INPUT;
	}
进入signEdit.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
%>
这里将显示出的内容到signDetailChange这个DIV内,而这里的内部有一个显示Smile的:
loadSmilePage('signDetail') 
-->
function loadSmilePage(inputName) {
  Element.show("smileDiv");
  $('smileDiv').innerHTML = pageLoading;
  var url = "smile.jsp";//根路径中!
  var pars = "inputName="+inputName;
  var myAjax = new Ajax.Updater("smileDiv", url, {method: 'get', parameters: pars});
}
这里有用到了smile.jsp,下面是显示表情图片的一个jsp代码:
<%
    int counter = 0;
    for (int i = 0; i < 85; i++) {
      if (counter == 0) {
        counter = 8;
        out.println("<tr>");
      }
  %>
    <td>
      <div align="center">
        <img id="smile<%=i%>" src="images/smile/<%=i%>.gif" alt="smile" onmousemove="this.style.cursor='hand';this.style.cursor='pointer'" onclick="insertSmile('<%=inputName%>','{<%=i%>}');"/>
      </div>
    </td>
  <%
    if (counter == 1) {
      counter = 0;
      out.println("</tr>");
    }
    else {
      counter = counter - 1;
    }
    }
  %>
当我们选择一个后,点击后将触发insertSmile('<%=inputName%>','{<%=i%>}');注意inputName为需要写入到哪个元素,这里当然是textarea的signDetail,所以才用loadSmilePage('signDetail').下面的js改变文本域内容:
function insertSmile(inputName,smlieTag) {
  $(inputName).value = $(inputName).value + smlieTag; //smileTag类似于{1}
  $(inputName).focus();
}
对于关闭:
function closeSmilePage() {
  $("smileDiv").innerHTML = "";
  Element.hide("smileDiv");
}
好,我们单击保存标签按钮:function signEditDo() {
  var signID = $('signID').value;
  var oSignEditAjax = new SignEditAjax(signID);//用到ajax请求
  oSignEditAjax.edit();
}
下面是其代码:
var SignEditAjax = Class.create();
SignEditAjax.prototype = {
  initialize: function(signID) { //构造
    this.signID = signID;
  },

  edit: function() {
    showExeMsg();
    var url = getActionMappingURL("/signSet");
    var pars = "action=editdo&ajax=xml&signID="+this.signID+"&signDetail="+encodeURIComponent($('signDetail').value);//将文本字符串编码为一个统一资源标识符 (URI) 的一个有效组件
    var myAjax = new Ajax.Request(url, {method: 'post', parameters: pars, onComplete: this.editCompleted.bind(this)});
  },

  editCompleted: function(res) {
    resText = res.responseText;
  	var jsonMsgObj = new JsonMsgObj(resText);
  	var codeid = jsonMsgObj.getCodeid();
    hiddenExeMsg();
    alert(jsonMsgObj.getMessage());//提示信息
    if (codeid == "0") {
      $('signDiv'+this.signID).innerHTML = jsonMsgObj.getText();//写入内容
      closeSignEditPage();//关闭编辑框!
    }
  }
};
这里又用致函一个函数:
function hiddenExeMsg() {
  var loade = document.getElementById("exeingdiv");
  if (loade != null) {
    loade.style.display = "none";
  }
}
OK!我们进入SignSet.java的editdo方法中:
public String editdo() {
		if (BBSCSUtil.getSysCharsetStrLength(this.getSignDetail()) > this.getSysConfig().getSignMaxLen()) { // 签名超过指定长度
/**
	public static int getSysCharsetStrLength(String txt) {
		try {
			return txt.getBytes(Constant.CHARSET).length;
		} catch (UnsupportedEncodingException ex) {
			return txt.length();
		}
	}
*/
			this.getAjaxMessagesJson().setMessage(
					"E_USER_SIGN_TOOLONG",
					this.getText("error.sign.toolong", new String[] { String.valueOf(this.getSysConfig()
							.getSignMaxLen()) }));
			return RESULT_AJAXJSON;
		}
		UserInfo ui = this.getUserService().findUserInfoById(this.getUserSession().getId());
		if (ui != null) {
			String signDetail = "";
			if (StringUtils.isBlank(this.getSignDetail())) { // 签名为空,设为默认签名
				signDetail = this.getText("bbscs.userdefaultsign");//系统用的资源
				switch (this.getSignID()) {
				case 0:
					ui.setSignDetail0(signDetail);
					break;
				case 1:
					ui.setSignDetail1(signDetail);
					break;
				case 2:
					ui.setSignDetail2(signDetail);
					break;
				}
			} else {
				signDetail = this.getSysConfig().bestrowScreen(this.getSignDetail()); // 过滤敏感词

				switch (this.getSignID()) {
				case 0:
					ui.setSignDetail0(signDetail);
					break;
				case 1:
					ui.setSignDetail1(signDetail);
					break;
				case 2:
					ui.setSignDetail2(signDetail);
					break;
				}
			}
			try {
				ui = this.getUserService().saveUserInfo(ui);
				this.getUserSession().getSignDetail()[this.getSignID()] = signDetail;
				signDetail = BBSCSUtil.filterText(signDetail, this.getSysConfig().isSignUseHtml(), this.getSysConfig()
						.isSignUseUBB(), this.getSysConfig().isSignUseSmile());
				this.getAjaxMessagesJson().setMessage("0", this.getText("sign.edit.ok"), signDetail);//设置message提示信息!
			} catch (BbscsException ex) {
				logger.error(ex);
				this.getAjaxMessagesJson().setMessage("E_USER_SIGN_ERROR", this.getText("error.sign.edit"));
			}
		}
		return RESULT_AJAXJSON;
	}
这里的关键是对文本信息的过滤(BBSCSUtil):
public String bestrowScreen(String txt) {  //将系统不允许出现的字词换成**
		if (StringUtils.isNotBlank(this.getScreenWord())) {
			String[] words = this.getScreenWord().split(";");
			for (int i = 0; i < words.length; i++) {
				txt = txt.replaceAll(words[i], this.getBestrowScreen());
			}
		}
		return txt;
	}
public static String filterText(String sign, boolean useHTML, boolean useUBB, boolean useSmile) {
		if (!useHTML) { //默认1
			sign = TextUtils.htmlEncode(sign);//转意字符!这里用的是com.opensymphony.xwork2.util工具类!
		}
		if (useUBB) {//0
			sign = getUBB2HTML(sign);
		}
		if (useSmile) {//1
			sign = replaceSmile(sign);
		}
		sign = sign.replaceAll("\n", "<BR/>");
		sign = filterScript(sign);
		return sign;
	}
-->
	public static String replaceSmile(String txt) {
		if (txt != null) {
			return txt.replaceAll("\\{(\\d{1,2})\\}", "<img src=\"images/smile/$1.gif\" alt=\"smile\"/>");//正则表达式!
		} else {
			return "";
		}
	}
	public static String filterScript(String txt) {
		return txt.replaceAll("[Ss][Cc][Rr][Ii][Pp][Tt]", "s.c.r.i.p.t");
	}
	public static String getUBB2HTML(String txt) {//UBB实现
		if (txt != null) {
			AutoFilter af = new AutoFilter(txt);
			txt = af.getFilteredStr();
		}
		return txt;
	}
AutoFilter继承了RegexFilter...而RegexFilter实现了Filter接口:
public interface Filter {
  public abstract String getFilteredStr();//我们便通过这个方法得到返回的结果的!
}
在AutoFilter的构造方法中有许多regex的reStr属性(在RegexFilter定义为protected)也有this.doFiltration();方法,我们看super(txt)方法:
 protected RegexFilter(String source) {
    this.source = source;
    this.tempSource = source;
  }
而每次代换doFiltration():
 protected void doFiltration() {
    this.applyFilter();
    this.tempSource = filter.getFilteredStr();
  }
用了 protected void applyFilter() {
    FilterBuilder builder = new RegFilterBuilder(regex, rpStr, tempSource);//注意这里用的是tempSource!
    FilterDirector direct = new FilterDirector(builder);//导演FilterDirector生成FilterBuilder的各种实现
    direct.construct();

    this.filter = builder.getFilter();
  }
我们看真正的执行者:RegFilterBuilder,实现了FilterBuilder中的所有方法:
public interface FilterBuilder {
  public abstract void buildFilter();
  public abstract Filter getFilter();
}
它使用的是JDK中的正则类:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
  public RegFilterBuilder(String regex, String rpStr, String source) {
    super();
    this.regex = regex;
    this.rpStr = rpStr;
    this.source = source;
  }
 public void buildFilter() {  //关键的方法!需重点理解之!请参考资料:http://wcjok.bokee.com/4293762.html
    if (this.regex == null) {
      return;
    }
    Pattern p = Pattern.compile(regex, 2);
    Matcher matcher = p.matcher(this.source);
    StringBuffer sb = new StringBuffer();
    String tempString = rpStr;
    int rpL = rpStr.split("\\$[0-9]+").length;
    while (matcher.find()) {
      for (int i = 0; (i < rpL) && (i < matcher.groupCount()); i++) {
        tempString = tempString.replaceAll("\\$" + i, matcher.group(i));
      }
      matcher.appendReplacement(sb, tempString);
    }
    matcher.appendTail(sb);
    this.result = sb.toString();
  }
public Filter getFilter() { //回调一个刚过滤的中间结果!
    return (new RegexFilter() {
      public String getFilteredStr() {
        return result;
      }
    });
当然我们还有一个FilterDirector!由它管理FilterBuilder对象和它的buildFilter方法!
public FilterDirector(FilterBuilder builder) {
    this.builder = builder;
  }
  public void construct() {
    builder.buildFilter();
  }
而getFilter则仍由Builder自己来返回this.filter = builder.getFilter();
接下来,我们分析nickNameSet.bbscs,它很简单:
	<action name="nickNameSet" class="nickNameSetAction">
			<interceptor-ref name="mainUserAuthInterceptorStack"></interceptor-ref>
			<result name="input">/WEB-INF/jsp/nickNameSet.jsp</result>
		</action>
	public String index() {
		this.setAction("edit");
		this.setNickName(this.getUserSession().getNickName());
		return INPUT;
	}
<s:form action="nickNameSet">
      <s:hidden name="action"></s:hidden>
      <tr>
        <td><s:text name="nickset.title"/></td>
        <td>
          <s:textfield id="nickName" name="nickName" cssClass="input2" size="40" maxlength="20" onkeypress="return handleEnter(this, event);"></s:textfield>//已经被填充!
        </td>
....
我们提交editNickName():
function editNickName() {
  var url = getActionMappingURL("/nickNameSet");
  var pars = "action=edit&ajax=xml&nickName="+encodeURIComponent($('nickName').value);
  var myAjax = new Ajax.Request(url, {method: 'post', parameters: pars, onComplete: editNickNameOK});

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -