安装
<meta http-equiv="refresh" content="3;URL=install/index.html"/> 您还没有安装JEECMS,3秒钟之后自动跳转到安装页面。<br/> 如果您的浏览器长时间没有反应,请直接点击<a href="install/index.html">JEECMS安装</a>。
|
install/index.html:一般是同意安装页
<script type="text/javascript"> function formSubmit() { if(document.getElementById('license_agree').checked==false){ alert('请同意我们的协议'); return false; } document.getElementById('license_form').submit(); } </script> <form id="license_form" action="install_params.jsp" method="post"> <input type="button" class="btn" onclick="formSubmit();" value="下一步 >"/> |
进入安装数据库和参数页:
<form action="install_setup.jsp" method="post" onsubmit="return formSubmit();"> <tr> <td height="30" align="right">域名:</td> <td align="left"><input name="domain" type="text" class="input" value="<%=request.getServerName()%>"/></td> <td align="left">系统已经检测出您的域名,请勿改动</td> </tr> <tr> <td height="30" align="right">部署路径:</td> <td align="left"><input name="cxtPath" type="text" class="input" value="<%=request.getContextPath()%>"/></td> <td align="left">系统已经检测出您的部署路径,请勿改动</td> </tr>
|
安装:
<%@page contentType="text/html; charset=gbk" language="java" import="com.jeecms.core.util.*,java.util.*"%> <% String dbFileName = "/install/db/jeecms-db-2.4.2-final.sql"; String initFileName = "/install/db/jeecms-init-2.4.2-final.sql"; //创建数据库 if ("true".equals(isCreateDb)) { Install.createDb(dbHost, dbPort, dbName, dbUser, dbPassword); } else { Install.changeDbCharset(dbHost, dbPort, dbName, dbUser, dbPassword); } //创建表 if ("true".equals(isCreateTable)) { String sqlPath = application.getRealPath(dbFileName); List<String> sqlList = Install.readSql(sqlPath); Install.createTable(dbHost, dbPort, dbName, dbUser, dbPassword, sqlList); } //初始化数据 if ("true".equals(isInitData)) { String initPath = application.getRealPath(initFileName); List<String> initList = Install.readSql(initPath); Install.createTable(dbHost, dbPort, dbName, dbUser, dbPassword, initList); } //更新配置 Install.updateConfig(dbHost, dbPort, dbName, dbUser, dbPassword, domain, cxtPath, port); //处理数据库配置文件 String dbXmlPath = application.getRealPath(dbXmlFileName); Install .dbXml(dbXmlPath, dbHost, dbPort, dbName, dbUser, dbPassword); //处理web.xml String webXmlFromPath = application.getRealPath(webXmlFrom); String webXmlToPath = application.getRealPath(webXmlTo); Install.webXml(webXmlFromPath, webXmlToPath); //在Util里面
|
jcaptcha 自定义验证码
(略)
Xml
<!-- Spring 刷新Introspector防止内存泄露 --> <listener> <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class> </listener>
<!-- session超时定义,单位为分钟 --> <session-config> <session-timeout>20</session-timeout> </session-config> <error-page> <error-code>404</error-code> <location>/404.html</location> </error-page> <error-page> <error-code>403</error-code> <location>/403.html</location> </error-page> <welcome-file-list> <welcome-file>index.jspa</welcome-file> <welcome-file>index.do</welcome-file> <welcome-file>index.html</welcome-file> </welcome-file-list> |
目录:之一
总共40张表 在Spring里面可以用这种方式:
<property name="mappingLocations"> <list> <value>classpath:/com/jeecms/core/entity/*.hbm.xml</value> <value>classpath:/com/jeecms/cms/entity/*.hbm.xml</value> <value>classpath:/com/jeecms/article/entity/*.hbm.xml</value> <value>classpath:/com/jeecms/download/entity/*.hbm.xml</value> <value>classpath:/com/jeecms/auxiliary/entity/*.hbm.xml</value> </list> </property> |
同样Hibernate也可以这样:
<property name="hibernateProperties"> <value> hibernate.dialect=org.hibernate.dialect.MySQLInnoDBDialect hibernate.show_sql=true hibernate.format_sql=false hibernate.query.substitutions=true 1, false 0 hibernate.jdbc.batch_size=20 hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider hibernate.cache.provider_configuration_file_resource_path=/ehcache-hibernate.xml </value> </property> |
Spring事务
<!-- 事务配置 --> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean>
<!-- 使用annotation 自动注册bean,并检查@Required,@Autowired的属性已被注入 --> <context:component-scan base-package="com.jeecms" />
<!-- 使用annotation定义事务 --> <tx:annotation-driven transaction-manager="txManager" /> Spring注解@Component、@Repository、@Service、@Controller区别 Spring 2.5 中除了提供 @Component 注释外,还定义了几个拥有特殊语义的注释,它们分别是:@Repository、@Service 和 @Controller。在目前的 Spring 版本中,这 3 个注释和 @Component 是等效的,但是从注释类的命名上,很容易看出这 3 个注释分别和持久层、业务层和控制层(Web 层)相对应。虽然目前这 3 个注释和 @Component 相比没有什么新意,但 Spring 将在以后的版本中为它们添加特殊的功能。所以,如果 Web 应用程序采用了经典的三层分层结构的话,最好在持久层、业务层和控制层分别采用 @Repository、@Service 和 @Controller 对分层中的类进行注释,而用 @Component 对那些比较中立的类进行注释。 @Service用于标注业务层组件,@Controller用于标注控制层组件(如struts中的action),@Repository用于标注数据访问组件,即DAO组件,而@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
|
Spring事务处理
@Repository public abstract class BaseDaoImpl<T extends Serializable> implements BaseDao<T> { protected Logger log = LoggerFactory.getLogger(getClass());
protected SessionFactory sessionFactory;
@Autowired public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; }
protected Session getSession() { return sessionFactory.getCurrentSession(); }
public T save(T entity) { Assert.notNull(entity); getSession().save(entity); return entity; }
public Object update(Object entity) { Assert.notNull(entity); getSession().update(entity); return entity; }
public Object saveOrUpdate(Object entity) { Assert.notNull(entity); getSession().saveOrUpdate(entity); return entity; }
public void delete(Object entity) { Assert.notNull(entity); getSession().delete(entity); }
public T deleteById(Serializable id) { Assert.notNull(id); T entity = load(id); getSession().delete(entity); return entity; }
@SuppressWarnings("unchecked") public T get(Serializable id) { Assert.notNull(id); return (T) getSession().get(getPersistentClass(), id); }
@SuppressWarnings("unchecked") public T load(Serializable id, boolean lock) { Assert.notNull(id); T entity = null; if (lock) { entity = (T) getSession().load(getPersistentClass(), id, LockMode.UPGRADE); } else { entity = (T) getSession().load(getPersistentClass(), id); } return entity; } public List<T> findAll() { return findByCriteria(); } @SuppressWarnings("unchecked") public List<T> findAll(OrderBy... orders) { Criteria crit = createCriteria(); if (orders != null) { for (OrderBy order : orders) { crit.addOrder(order.getOrder()); } } return crit.list(); }
public Pagination findAll(int pageNo, int pageSize, OrderBy... orders) { Criteria crit = createCriteria(); return findByCriteria(crit, pageNo, pageSize, null, OrderBy .asOrders(orders)); } |
在IMPL类:加:@Repository
在Action中:加:@Repository
目前对jeecms的事务还有点不清楚,因为jeecms用了大量的注解:
@Service
@Transactional
public class FunctionMngImpl
@Autowired 是自动生成set方法:
@Autowired
private ContextPvd contextPvd;
则不用写set了,但get还要写。
Struts2与Spring之间URL跳转
<struts> <include file="com/jeecms/cms/struts-default.xml" />
<include file="com/jeecms/cms/struts-core-admin.xml" /> <include file="com/jeecms/cms/struts-core-ajax.xml" /> <include file="com/jeecms/cms/struts-core-front.xml" /> </struts> //struts-login.xml 登录 <package name="cms.login" namespace="/login" extends="core-default"> <global-results> <result name="logout" type="redirectAction"> <param name="namespace">/login</param> <param name="actionName">Jeecms</param> </result> <result name="loginInput">/WEB-INF/cms_sys/login.html</result> </global-results> <action name="Jeecms" method="loginInput" class="cms.adminLoginAct"/> <action name="CmsLogout" method="logout" class="cms.adminLoginAct"/>
|
用使用annotation 自动注册bean spring整合Struts2的一种:
1, spring xml
<!-- 使用annotation 自动注册bean,并检查@Required,@Autowired的属性已被注入 --> <context:component-scan base-package="com.lch.spring.auto" /> |
2, 在Struts2里面:
<action name="auto" class="into.autoSpringAction" method="autoMethod" > |
3,写一个接口,和一个实现类
public interface InterfaceTest {
@Repository
public class AutoImpl implements InterfaceTest{
3, 在Struts2中用@Controller @Autowrited
@Scope("prototype") @Controller("into.autoSpringAction") public class AutoSpringAction extends ActionSupport{ @Autowired private InterfaceTest ift; public String autoMethod(){ ift.sayHelloAuto(); return SUCCESS; } |
如上面连set 都不用写,且spring里面没有Bean的配置用注解将接口和实现类装配进了。
以后台登陆为例:
http://localhost:8080/jeecms/login/Jeecms.do //从上面可以知道是cms.adminLoginAct
这时Jeecms用注解来跳转的。如下
@Scope("prototype")
@Controller("cms.adminLoginAct")
public class AdminLoginAct extends JeeCoreAction {
后台登陆
<global-results>
<result name="loginInput">/WEB-INF/cms_sys/login.html</result>
</global-results>
Next:<action name="CmsSubmit" method="login" class="cms.adminLoginAct">
下面是登录设计:good
public String login() { boolean isHuman = imageCaptchaService.validateResponseForID(contextPvd .getSessionId(false), checkCode); if (!isHuman) { addActionError("验证码错误!"); return loginInput(); } User user = userMng.authenticate(loginName, password); if (user == null) { addActionError("用户名不存在或密码错误!"); return loginInput(); } Admin admin = adminMng.getByUserId(getWebId(), user.getId()); if (admin == null) { addActionError("您没有本站的管理权限!"); return loginInput(); } else if (admin.getAdminDisabled()) { addActionError("您的帐号已经被禁止!"); return loginInput(); } // 清除以前登录信息 contextPvd.logout(); // 保存当前登录信息 contextPvd.setSessionAttr(User.USER_KEY, user.getId()); contextPvd.setSessionAttr(Admin.ADMIN_KEY, admin.getId()); userMng.updateLoginInfo(user); // 将权限集放入session Set<String> fiSet = functionMng.getFunctionItems(admin.getId()); contextPvd.setSessionAttr(Admin.RIGHTS_KEY, fiSet); // 处理次级域名单点登录 Website web = getWeb(); if (!StringUtils.isBlank(web.getBaseDomain())) { Cookie c = new Cookie(JSESSION_COOKIE, contextPvd .getSessionId(false)); c.setPath("/"); c.setDomain(web.getTopDomain(true)); contextPvd.addCookie(c); } return SUCCESS; } |
上面清除Session方法:
public void logout() {
HttpSession session = ServletActionContext.getRequest().getSession(
false);
if (session != null) {
session.invalidate();
}
}
登录成功之后的跳转:这个很好:将进入另外一个namespace
<result name="success" type="redirectAction"> <param name="actionName">Com_index</param> <param name="namespace">/admin/cms</param> </result> 进入这里 <!--后台首页--> <package name="cms.console" namespace="/admin/cms" extends="core-default"> <action name="Com_*" method="{1}" class="cms.adminConsoleAct"> <result name="index">/WEB-INF/cms_sys/index.html</result> <result name="main">/WEB-INF/cms_sys/main.html</result> <result name="left">/WEB-INF/cms_sys/left.html</result> <result name="right">/WEB-INF/cms_sys/right.html</result> </action> </package> |
进入:一个叫 index的方法里面
@SuppressWarnings("serial") @Scope("prototype") @Controller("cms.adminConsoleAct") public class AdminConsoleAct extends JeeCoreAction { public String index() { // @ TODO 检查管理员是否属于该系统。 // 多站点管理 websiteList = websiteMng.getListByUserId(getUserId()); sessionAppend = ";" + JSESSION_URL + "=" + contextPvd.getSessionId(false); return INDEX; }
public String main() { return "main"; }
public String left() { return LEFT; }
public String right() { if (pwdEncoder.isPasswordValid(getUser().getPassword(), "password")) { pwdWarn = true; } props = System.getProperties(); Runtime runtime = Runtime.getRuntime(); freeMemoery = runtime.freeMemory(); totalMemory = runtime.totalMemory(); usedMemory = totalMemory - freeMemoery; maxMemory = runtime.maxMemory(); useableMemory = maxMemory - totalMemory + freeMemoery; return RIGHT; }
|
后台使用frame T字形结构 进入index.html 之后 调用main方法
<!--主体框架Begin--> <iframe id="mainFrame" name="mainFrame" src="Com_main.do" frameborder="0" scrolling="no" style="width:100%;"></iframe> <!--主体框架End--> |
进入main.html
<frameset cols="170,*" frameborder="0" border="0" framespacing="0"> <frame src="Com_left.do" name="leftFrame" noresize="noresize" id="leftFrame" /> <frame src="Com_right.do" name="rightFrame" id="rightFrame" /> </frameset> <noframes><body></body></noframes> |
注意right方法里面修改初始密码
当此时URL:还是Com_index.do??OK I know it. 也就是在index html里面还有很多处理,所有数据:
当是初始密码时会弹出一个很漂亮的对话框,在 right html
<#include "/WEB-INF/cms_sys/head.ftl"/> <#if pwdWarn> <script type="text/javascript"> $(document).ready( function() { jAlert("您还在使用初始密码,请及时修改密码!","温馨提示"); }); </script> </#if> |
进入cms_sys/head.ftl 发现是query 的UI
jcaptcha 自定义验证码例子
http://hi.baidu.com/laihua2006/blog/item/e3af00002462df007bec2cd7.html
我将jcaptcha的使用写在这里。Jeecms就是用这个。
Hibernate Interceptor
及当系统运行时就执行
public class TreeIntercptor extends EmptyInterceptor { protected SessionFactory sessionFactory;
protected SessionFactory getSessionFactory() { if (sessionFactory == null) { WebApplicationContext wac = WebApplicationContextUtils .getRequiredWebApplicationContext(ServletActionContext .getServletContext()); sessionFactory = (SessionFactory) wac.getBean("sessionFactory", SessionFactory.class); } return sessionFactory; }
protected Session getSession() { return getSessionFactory().getCurrentSession(); }
|
Spring xml
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> 略 <property name="entityInterceptor"> <ref local="treeInterceptor"/> </property> </bean> <bean id="treeInterceptor" class="com.jeecms.TreeIntercptor"/> |
这点还不清楚
Spring jdbc
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location"> <value>classpath:jdbc.properties</value> </property> </bean> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver" /> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="autoCommitOnClose" value="true"/> <property name="checkoutTimeout" value="${cpool.checkoutTimeout}"/> <property name="initialPoolSize" value="${cpool.minPoolSize}"/> <property name="minPoolSize" value="${cpool.minPoolSize}"/> <property name="maxPoolSize" value="${cpool.maxPoolSize}"/> <property name="maxIdleTime" value="${cpool.maxIdleTime}"/> <property name="acquireIncrement" value="${cpool.acquireIncrement}"/> <property name="maxIdleTimeExcessConnections" value="${cpool.maxIdleTimeExcessConnections}"/> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mappingLocations"> <list> <value>classpath:/com/jeecms/core/entity/*.hbm.xml</value> <value>classpath:/com/jeecms/cms/entity/*.hbm.xml</value> <value>classpath:/com/jeecms/article/entity/*.hbm.xml</value> <value>classpath:/com/jeecms/download/entity/*.hbm.xml</value> <value>classpath:/com/jeecms/auxiliary/entity/*.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <value> hibernate.dialect=org.hibernate.dialect.MySQLInnoDBDialect hibernate.show_sql=true hibernate.format_sql=false hibernate.query.substitutions=true 1, false 0 hibernate.jdbc.batch_size=20 hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider hibernate.cache.provider_configuration_file_resource_path=/ehcache-hibernate.xml </value> </property> <property name="entityInterceptor"> <ref local="treeInterceptor"/> </property> </bean> <!--下面是事务à <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <context:component-scan base-package="com.jeecms" /> <tx:annotation-driven transaction-manager="transactionManager" /> |
用:c3p0.ComboPooledDataSource 更快classpath:jdbc.properties如下:
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/jeecms_2_4?characterEncoding=gbk jdbc.username=root jdbc.password=root
cpool.checkoutTimeout=5000 #cpool.minPoolSize=20 #cpool.maxPoolSize=50 cpool.minPoolSize=1 cpool.maxPoolSize=5
cpool.maxIdleTime=7200 cpool.maxIdleTimeExcessConnections=1800 #cpool.acquireIncrement=10 cpool.acquireIncrement=1 |
进入前台
注后台栏目将在下一文档解析
Web xml
<welcome-file-list> <welcome-file>index.jspa</welcome-file> <welcome-file>index.do</welcome-file> <welcome-file>index.html</welcome-file> </welcome-file-list> |
默认首页是先index.jspa is nothing and next page :index.do and next page: index.html so:
Into index.do
Struts-core-font.xml
<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> Next into Action: @Scope("prototype") @Controller("core.dynamicSystemAct") public class DynamicSystemAct implements Action, DomainNameAware, UrlAware { public String execute() { 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"; return SUCCESS; } |
Next into struts-font.xml
<!--JEECMS前台页面--> <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> Next into action: package com.jeecms.cms.action.front; CmsPageAct extends PageBaseAction |
这里有一个很好的设计,首页是在父类中打开的
public abstract class PageBaseAction extends IntegrityAction {
@Override public String execute() throws Exception { handlePathParams(); pageName = pathParams[len - 1]; if (len == 1 && pageName.equals(INDEX)) { // 首页 return sysIndex();//而这些是由子类去实现CmsPageAct } else if (len == 1 && NumberUtils.isDigits(pageName)) { // 内容 try { return content(null, Long.parseLong(pageName)); } catch (NumberFormatException nfe) { return pageNotFound(); } } else if (len == 1) { return alone(pageName); } else if (len == 2 && pageName.equals(INDEX)) { return chnlIndex(pathName); } else if (len == 2 && NumberUtils.isDigits(pageName)) { try { return content(pathName, Long.parseLong(pageName)); } catch (NumberFormatException nfe) { return pageNotFound(); } } else { return pageNotFound(); } } /** * 系统首页 */ protected abstract String sysIndex() throws IOException; /** * 栏目页 */ protected abstract String chnlIndex(String chnlName) throws IOException; /** * 内容页 */ protected abstract String content(String chnlName, Long id) throws IOException;
/** * 单页 */ protected abstract String alone(String chnlName) throws IOException;
/** * 页面找不到 * * @return */ protected abstract String pageNotFound(); |
用myeclipse debug find tplPath 模板地址 :如下
/WEB-INF/user_base/jeecms_com_www/template/article/default/index.html
Next into template index.html copte xecerpt:
<!--页头Begin--> [@cms.Include name='head.html' solution='default'/] <!--页头End--> <!--搜索栏Begin--> [@cms.Include name='search.html' solution='default'/] <!--搜索栏End--> <!--共同关注Begin--> <div class="page_row"> <div class="left"><img alt="" src="${root}/default/article/img/myjon.gif" /></div> <div class="left run_news"> [@cms.ArtiList chnlId='' attr='5' count='10' sysContent='2-1' titLen='20' dateFormat='3' datePosition='3' headMark='2' target='1' rollCols='2' rollSpeed='3' rollSleepTime='100'/]</div> <div style="clear: both"></div> </div> <!--共同关注End--> |
Jeecms used freemarker template ,that is the same used the most template technical in PHP. If you want to change the index.html header ,you could open the page head.html edit which you want.
Then we will start to pay attention the jeecms Tag.
标签解读
例如:[@cms.Include name='search.html' solution='default'/]
[@cms.ChnlList id='' inner='1';c]<li class="thisclass"><a href="${c.url}">${c.name}</a></li>[/@cms.ChnlList]
是怎么来的,为什么@cms.ChnlList 就能输出导航数据。
Tag是在Struts2里面定义的,struts-front xml
<!--栏目标签--> <package name="cms.front.tag" namespace="/jeecms/tag/cms" extends="tag-default"> <action name="ChnlList" method="chnlList" class="cms.chnlPartAct"> <result name="sysTpl">/WEB-INF/ftl_lib/jeecms/cms/chnl_list.ftl</result> <result>${tplPath}</result> </action> </package> |
extends="tag-default" 跟踪:
<package name="tag-default" abstract="true" extends="core-default"> <default-interceptor-ref name="tagStack" /> </package> |
tagStack:跟踪:
<!--标签栈--> <interceptor-stack name="tagStack"> <interceptor-ref name="startTime"/> <interceptor-ref name="exception"> <param name="logEnabled">true</param> <param name="logLevel">warn</param> </interceptor-ref> <interceptor-ref name="url"/> <interceptor-ref name="params"> <param name="excludeParams">dojo/..*</param> </interceptor-ref> </interceptor-stack> |
主要说一下在程序里面自定义的几个比较重要的拦截器(定义在jeecms/src/struts-default.xml文件中)。DomainNameInterceptorUrlInterceptorCookieIdentityInterceptor然后执行action自己的execute方法,产生 2个参数:namespace = "/jeedynamic/" + sys;actionName = "Page";这2个参数决定了程序的走向,组成转发路径:/jeedynamic /jeecms/Page.do,然后通过查找下面的配置信息 ${tplPath} ${tplPath} 注:其他的请求过程类似,先找到命名空间,然后找到对应的 acting进行处理。将请求转发给cms.cmsPageAct对象,同上的道理,对应到控制器:com.jeecms.cms.action.front.CmsPageAct。拦截器处理完毕后,执行自己的 execute方法,判断若是首页,则执行sysIndex()方法,返回一个模板路径tplPath:/WEB-INF/user_base/jeecms_com_www/template /article/default/index.html,找到这个文件,
Freemark:对于jeecms来说标签主要是freemark在支配。URL则是身是Struts2
freemarker.properties中:auto_import="/WEB-INF/ftl_lib/ponyjava.com/index.ftl" as p, "/WEB-INF/ftl_lib/jeecms/index.ftl" as cms @cms标签所用的ftl模板文件为index.ftl。 打开index.ftl文件,includes了多个ftl,其中有action_cms.ftl,该文件用标签#macro,自定义许多directive:ChnlList和CommentList 等。里面使用struts2标签@s.action来请求数据,整个的index.html页面就是这么加载出来的。通过 freemarker引擎来解析数据模型,最后显示到前台,展现给客户。index.html include head.html[@cms.ChnlList id='' inner='1';c]
|
OK:我们打开/WEB-INF/ftl_lib/jeecms/cms/chnl_list.ftl</result>看看
<ul> <#list list as chnl> <li><a href="${chnl.url}" class="${linkClass}"<#if linkTarget=="1"> target="_blank"</#if>>${chnl.name}</a></li> </#list> </ul> |
发现里面就是freemark生成的代码;
Jeecms标签参数说明:(部分)
id:父栏目ID。(默认为空:自动获取当前栏目ID)
orderBy:排序方式。【0:优先级升序;1:优先级降序;2:点击次数升序;3:点击次数降序】(默认0)
isDisplay:是否只获取显示的栏目。【0:获取所有;1:只获取显示的栏目】(默认1)
hasContent:是否只获取可以有内容的栏目。【0:获取所有;1:只获取可以有内容的栏目】(默认0)
linkClass:链接class
linkTarget:链接打开方式。【0:当前窗口;1:新窗口】(默认0)
style:标签内部样式。如果指定sysContent或userContent,则该项无效。【1:普通链接列表;】(默认1)
sysTpl:使用系统模板。【0:不使用;1:使用】(默认1)
sysContent:系统内容样式。(默认0)
userContent:自定义内容样式。如果指定了系统内容样式,则该项无效。(默认0)
sysPage:系统分页样式。【0:不分页;1:样式一;2:样式二】(默认0)
userPage:自定义分页样式。如果指定了系统分页样式,则该项无效。【0:不分页;1:样式一;2:样式二】(默认0)
custom:字符串数组。用于个性化处理。(默认空数组)------略
freemarker+struts2应用
http://hi.baidu.com/laihua2006/blog/item/e83d3b098c6a11d862d98694.html http://hi.baidu.com/laihua2006/blog/item/4684441fe6ad80fa1ad57668.html 上面是我写下的两个例子:一个是freemarker+servlet的例子建议先看这个 Action: @Scope("prototype")
private String mk="mkkk"; @Autowired public List<Member> getMlist() { public String getMk() { } struts.xml------ <action name="c3pSpring" class="spring.springCpoTest" method="method" > template:hello.ftl---- <html> <head> <title>Welcome!</title> </head> <body> <h1>Welcome</h1> <#list mlist as mem> </#list> </body> </html> 当然可以在src下面建一个叫freemarker.properties的文件写入如下: url_escaping_charset=UTF-8 template_update_delay=1 这些是干什么用的请看freemarker文档 |
最近jeecms3.0 去掉了struts2 ,用的是springMVC