jeecms是一个ssh+freemarker的优秀的cms系统,最近下载了一个版本装了一下,很不错,但是除了那一些自定义的freemarker标签外,还有些头大的事,就是很难查清楚它的自定义的伪静态的实现, htm是怎样对映到action上去的,最近花了几天看了一下,有点发现,记录下来.
如下图, 点击一个article的标题,会弹出一个像是静态的url, 这个显然是要提交到一个action上的,但是怎么实现的呢?
http://localhost:8080/JEECMS/movie/38.htm
查了一下每个aticle的静态页面,它的url都是有一定规则的,channel名加上article的id号,如果要分页还要加上一些附加的_*之类的url.
以下分析一下其大体的实现流程:
首先看一下它的struts2的全局配置:
struts.action.extension=do,htm,jspa,jspx,php,asp,aspx struts.objectFactory=spring struts.enable.DynamicMethodInvocation=false struts.devMode=true struts.locale=zh_CN struts.i18n.encoding=GBK struts.ui.theme=simple #struts.custom.i18n.resources=i18n struts.ui.templateDir=/WEB-INF/template #struts.multipart.saveDir=temp/ struts.multipart.maxSize=8388608 struts.enable.SlashesInActionNames=true
第一个配置说明surfix 以do, html, jspa,jspx,php,asp,aspx结尾的url都被视为struts2的action处理,那么显然这个
htm结尾的是要当做action处理的了。
下面看一下这个url是如何对应到一个action的.
在com.jeecms.cms的下面有一个struts-core-front.xml的配置文件,定义如下:
这个<action name="**" class="core.dynamicSystemAct">很明显会载到namespace 为"/"的所有action.
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd"> <struts> <!--动态系统--> <package name="core.front.dynamic" namespace="" extends="empty-default"> <action name="**" class="core.dynamicSystemAct"> <result type="chain"> <param name="namespace">${namespace}</param> <param name="actionName">${actionName}</param> </result> <interceptor-ref name="startTime"/> <interceptor-ref name="exception"/> <interceptor-ref name="domain"/> <interceptor-ref name="cookieIdentity"/> <interceptor-ref name="url"/> </action> </package> <package name="front.attachment" namespace="/front/attachment" extends="inde-default"> <action name="Com_*" method="{1}" class="core.attachmentAct"> <result name="edit">/WEB-INF/bbs_sys/topic/img.html</result> </action> </package> </struts>
由于是用的别名,在查到这个action后发现这个类实现了urlAware,如下, 这样它还会被一个UrlInterceptor的拦截器拦截,这个拦截器被设成struts2的default拦截器了, 在拦截器上打出了这个url请求的namespace 与action,确实附合动态系统action的条件, 通过UrlAware这个接口定义的方法,拦截器将一些url上的参数信息传给了action以进行动态处理,同时我也打出了DynamicSystemAct中生成的一些动态信息,如namespace与action.
package com.jeecms.common.struts2.interceptor; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.struts2.StrutsStatics; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor; /** * URL地址拦截器 * * 针对页面伪静态地址,需要传入多个参数 * * @author liufang * */ public class UrlInterceptor extends MethodFilterInterceptor { private static final long serialVersionUID = 1L; @Override protected String doIntercept(ActionInvocation invocation) throws Exception { Object action = invocation.getAction(); //check the name space. String namespace = invocation.getProxy().getNamespace(); String actionname =invocation.getProxy().getActionName(); if (!StringUtils.isBlank(namespace)) { if ("/".equals(namespace.trim())) { } else { namespace += "/"; } } System.out.println("namespace is "+namespace+"\n actionname is"+actionname); //============= ActionContext ctx = invocation.getInvocationContext(); HttpServletRequest req = (HttpServletRequest) ctx .get(StrutsStatics.HTTP_REQUEST); if (action instanceof UrlAware) { System.out.println("UrlInterceptor active.."); UrlAware aware = (UrlAware) action; String url = req.getRequestURL().toString(); System.out.println("request url is:"+url); int pointIndex = url.indexOf('.', url.lastIndexOf('/')); if (pointIndex == -1) { url += "index.do"; pointIndex = url.indexOf('.', url.lastIndexOf('/')); } String paramStr = req.getQueryString(); if (paramStr != null && !paramStr.trim().equals("")) { url += "?" + paramStr; } aware.setWholeUrl(url); int lineIndex = url.indexOf('_', url.lastIndexOf('/')); int mlineIndex = url.indexOf('-', url.lastIndexOf('/')); // 前路径结束点 int preIndex = 0; if (lineIndex != -1) { // 有下划线(有分页) preIndex = lineIndex; } else if (mlineIndex != -1) { // 有中划线(有定制参数) preIndex = mlineIndex; } else { // 什么都没有 preIndex = pointIndex; } aware.setPageLink(url.substring(0, preIndex)); // 后路径开始点 int suffixIndex = 0; if (mlineIndex != -1) { // 有中划线 suffixIndex = mlineIndex; } else { suffixIndex = pointIndex; } aware.setPageSuffix(url.substring(suffixIndex)); // 取页数和附加参数 if (preIndex == suffixIndex) { // 没有分页,为第一页。 aware.setPageNo(1); } else { // 去掉下划线"_"。 String page = url.substring(preIndex + 1, suffixIndex); aware.setPageNo(NumberUtils.toInt(page, 1)); } // 路径参数 String pathParm = ctx.getName(); lineIndex = pathParm.indexOf("_"); mlineIndex = pathParm.indexOf("-"); if (lineIndex != -1) { pathParm = pathParm.substring(0, lineIndex); } else if (mlineIndex != -1) { pathParm = pathParm.substring(0, mlineIndex); } aware.setPathParams(pathParm.split("/")); // 附加参数 if (mlineIndex != -1) { String otherParam = ctx.getName().substring(mlineIndex + 1); aware.setOtherParams(otherParam.split("-")); } //System.out.println(TypeUtil.typeToString("UrlAware--:\n",aware)); } //----------test the url interceptor------// else { System.out.println("UrlInterceptor ignored.."); } return invocation.invoke(); } }
package com.jeecms.cms.action; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import com.jeecms.common.struts2.interceptor.DomainNameAware; import com.jeecms.common.struts2.interceptor.UrlAware; import com.jeecms.core.Constants; import com.jeecms.core.entity.Website; import com.jeecms.core.manager.WebsiteMng; import com.opensymphony.xwork2.Action; @Scope("prototype") @Controller("core.dynamicSystemAct") public class DynamicSystemAct implements Action, DomainNameAware, UrlAware { public String execute() { System.out.println("comming into DynamicSystemAct"); Website web = websiteMng.getWebsite(domainName); if (web == null) { // 检查别名 web = websiteMng.getByAlias(domainName); if (web != null) { redirectUrl = web.getWebUrl(); return Constants.REDIRECT; } else { return Constants.WEBSITE_NOT_FOUND; } } String sys = web.getCurrentSystem(); namespace = "/jeedynamic/" + sys; actionName = "Page"; System.out.println("DynamicSystemAct namespace is "+namespace+"\n actionname is"+actionName); return SUCCESS; } private String namespace; private String actionName; private String pageName; private String pathName; private String domainName; private String[] pathParams; private String[] otherParams; private String wholeUrl; private String pageLink; private String pageSuffix; private int pageNo = 1; private String redirectUrl; @Autowired private WebsiteMng websiteMng; public void setDomainName(String domainName) { this.domainName = domainName; } public void setPathParams(String[] pathParams) { this.pathParams = pathParams; } public void setPageNo(int pageNo) { this.pageNo = pageNo; } public void setPageLink(String pageLink) { this.pageLink = pageLink; } public void setPageSuffix(String pageSuffix) { this.pageSuffix = pageSuffix; } public void setWholeUrl(String wholeUrl) { this.wholeUrl = wholeUrl; } public String getNamespace() { return namespace; } public void setNamespace(String namespace) { this.namespace = namespace; } public String getActionName() { return actionName; } public void setActionName(String actionName) { this.actionName = actionName; } public String getPageName() { return pageName; } public void setPageName(String pageName) { this.pageName = pageName; } public String getPathName() { return pathName; } public void setPathName(String pathName) { this.pathName = pathName; } public String getDomainName() { return domainName; } public String[] getPathParams() { return pathParams; } public String getWholeUrl() { return wholeUrl; } public String getPageLink() { return pageLink; } public String getPageSuffix() { return pageSuffix; } public int getPageNo() { return pageNo; } public String getRedirectUrl() { return redirectUrl; } public void setRedirectUrl(String redirectUrl) { this.redirectUrl = redirectUrl; } public String[] getOtherParams() { return otherParams; } public void setOtherParams(String[] otherParams) { this.otherParams = otherParams; } }
综合上面的信息,再查page这个action,在发现com.jeecms.cms.struts-font.xml中发现了它的定义.
<package name="cms.front.page" namespace="/jeedynamic/jeecms" extends="empty-default"> <action name="Page" class="cms.cmsPageAct"> <result>${tplPath}</result> <result name="pageCache" type="pageCache">${tplPath}</result> <interceptor-ref name="exception"/> <interceptor-ref name="chain"/> </action> </package>
由此最终指向了一个模板.真是山路十八弯啊.