Jeecms 源码剖析

 安装

<meta http-equiv="refresh" content="3;URL=install/index.html"/>

您还没有安装JEECMS3秒钟之后自动跳转到安装页面。<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里面

/**

 * 安装类

 *

 * @author admin

 *

 */

public class Install {

    public static void dbXml(String fileName, String dbHost, String dbPort,

           String dbName, String dbUser, String dbPassword) throws Exception {

       String s = FileUtils.readFileToString(new File(fileName));

       s = s.replaceFirst("DB_HOST", dbHost);

       s = s.replaceFirst("DB_PORT", dbPort);

       s = s.replaceFirst("DB_NAME", dbName);

       s = s.replaceFirst("DB_USER", dbUser);

       s = s.replaceFirst("DB_PASSWORD", dbPassword);

       FileUtils.writeStringToFile(new File(fileName), s);

    }

 

    public static Connection getConn(String dbHost, String dbPort,

           String dbName, String dbUser, String dbPassword) throws Exception {

       Class.forName("com.mysql.jdbc.Driver").newInstance();

       String connStr = "jdbc:mysql://" + dbHost + ":" + dbPort + "/" + dbName

              + "?user=" + dbUser + "&password=" + dbPassword

              + "&characterEncoding=GBK";

       Connection conn = DriverManager.getConnection(connStr);

       return conn;

    }

 

    public static void webXml(String fromFile, String toFile) throws Exception {

       FileUtils.copyFile(new File(fromFile), new File(toFile));

    }

 

    /**

     * 创建数据库

     *

     * @param dbHost

     * @param dbName

     * @param dbPort

     * @param dbUser

     * @param dbPassword

     * @throws Exception

     */

    public static void createDb(String dbHost, String dbPort, String dbName,

           String dbUser, String dbPassword) throws Exception {

       Class.forName("com.mysql.jdbc.Driver").newInstance();;

       String connStr = "jdbc:mysql://" + dbHost + ":" + dbPort + "?user="

              + dbUser + "&password=" + dbPassword + "&characterEncoding=GBK";

       Connection conn = DriverManager.getConnection(connStr);

       Statement stat = conn.createStatement();

       String sql = "drop database if exists " + dbName;

       stat.execute(sql);

       sql = "create database " + dbName

              + " CHARACTER SET GBK";

       stat.execute(sql);

       stat.close();

        conn.close();

    }

 

    public static void changeDbCharset(String dbHost, String dbPort,

           String dbName, String dbUser, String dbPassword) throws Exception {

       Connection conn = getConn(dbHost, dbPort, dbName, dbUser, dbPassword);

       Statement stat = conn.createStatement();

       String sql = "ALTER DATABASE " + dbName

              + " CHARACTER SET GBK";

       stat.execute(sql);

       stat.close();

       conn.close();

    }

 

    /**

     * 创建表

     *

     * @param dbHost

     * @param dbName

     * @param dbPort

     * @param dbUser

     * @param dbPassword

     * @param sqlList

     * @throws Exception

     */

    public static void createTable(String dbHost, String dbPort, String dbName,

           String dbUser, String dbPassword, List<String> sqlList)

           throws Exception {

       Connection conn = getConn(dbHost, dbPort, dbName, dbUser, dbPassword);

       Statement stat = conn.createStatement();

       for (String dllsql : sqlList) {

           stat.addBatch(dllsql);

       }

       stat.executeBatch();

       stat.close();

       conn.close();

    }

 

    /**

     * 更新配置

     *

     * @param dbHost

     * @param dbName

     * @param dbPort

     * @param dbUser

     * @param dbPassword

     * @param domain

     * @param cxtPath

     * @param port

     * @throws Exception

     */

    public static void updateConfig(String dbHost, String dbPort,

           String dbName, String dbUser, String dbPassword, String domain,

           String cxtPath, String port) throws Exception {

       Connection conn = getConn(dbHost, dbPort, dbName, dbUser, dbPassword);

       Statement stat = conn.createStatement();

       String sql = "update CORE_WEBSITE set DOMAIN='" + domain + "'";

       stat.executeUpdate(sql);

       sql = "update CORE_GLOBAL set CONTEXT_PATH='" + cxtPath + "',PORT="

              + port;

       stat.executeUpdate(sql);

       stat.close();

       conn.close();

    }

 

    /**

     * 读取sql语句。“/*”开头为注释,“;”sql结束。

     *

     * @param fileName

     *            sql文件地址

     * @return list of sql

     * @throws Exception

     */

    public static List<String> readSql(String fileName) throws Exception {

        BufferedReader br = new BufferedReader(new InputStreamReader(

                new FileInputStream(fileName), Constants.ENCODING));

        List<String> sqlList = new ArrayList<String>();

        StringBuilder sqlSb = new StringBuilder();

        String s = null;

        while ((s = br.readLine()) != null) {

            if (s.startsWith("/*")) {

                continue;

            }

            if (s.endsWith(";")) {

                sqlSb.append(s);

                sqlSb.setLength(sqlSb.length() - 1);

                sqlList.add(sqlSb.toString());

                sqlSb.setLength(0);

            } else {

                sqlSb.append(s);

            }

        }

        br.close();

        return sqlList;

    }

}

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还要写。

Struts2Spring之间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,自定义许多directiveChnlListCommentList 等。里面使用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
:标签内部样式。如果指定sysContentuserContent,则该项无效。【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")
@Controller("spring.springCpoTest")
public class SpringCpoTest extends ActionSupport {


private List<Member> mlist;

private String    mk="mkkk";

@Autowired
private MemberDAO mdao;
public String method(){
  mlist=mdao.findAll();
   return SUCCESS;
}

public List<Member> getMlist() {
   return mlist;
}
public void setMlist(List<Member> mlist) {
   this.mlist = mlist;
}

public String getMk() {
   return mk;
}
public void setMk(String mk) {
   this.mk = mk;
}

}

struts.xml------

   <action name="c3pSpring" class="spring.springCpoTest" method="method" >
    <result name="success" type="freemarker" >/template/hello.ftl</result>
    <result name="error" >/error.jsp </result>
   </action>

template:hello.ftl----

<html>

<head>

<title>Welcome!</title>

</head>

<body>

<h1>Welcome</h1>
${mk}

<#list mlist as mem>
${mem.id}| ${mem.uname}|${mem.password}<br>

</#list>

</body>

</html>

当然可以在src下面建一个叫freemarker.properties的文件写入如下:

url_escaping_charset=UTF-8

template_update_delay=1
datetime_format=yyyy-MM-dd HH:mm:ss
date_format=yyyy-MM-dd
time_format=HH:mm:ss

这些是干什么用的请看freemarker文档

最近jeecms3.0 去掉了struts2 ,用的是springMVC

 

 

 

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
jeecms v9.3 正式版 源码包 更新日志 1、栏目添加选择模型模板只选择一个报错 2、内容复用待审核查询报错(开源版) 3、根栏目添加内容报错 4、后台页面样式调整 5、后台编辑器分页问题 7、数据统计今日数据没有问题 8、公众号推送菜单和群发微信菜单获取微信端消息返回处理 9、OSS管理添加appkey_secretId后台未解密导致数据存储错误 10、会员中心留言列表报错 11、工作流节点空值处理 12、手机模板在静态页生成的情况下url错误处理 13、新增百度主动推送 14、内容删除同时删除静态页(含FTP) 15、栏目和内容静态化调整成只生成前10页 16、activation jcaptcha freemarker JAR部分用户反映下载不了,调整pom采用本地jar 17、栏目没有选择模型模板的情况下,发布内容选择不到模型问题处理 JEECMS简介 JEECMS是JavaEE版网站管理系统(Java Enterprise Edition Content Manage System)的简称。 · 基于java技术开发,继承其强大、稳定、安全、高效、跨平台等多方面的优点 · 采用hibernate3 spring mvc spring2 freemarker主流技术架构 · 懂html就能建站,提供最便利、合理的使用方式 · 强大、灵活的标签,用户自定义显示内容和显示方式 · 在设计上自身预先做了搜索引擎优化,增强对搜索引擎的友好性 · 完全生成全站静态页面,可自定义路径结构,无需urlrewrite · 轻松建设大规模网站,可通过次级域名建立子站群,各子站后台管理权限分离,全站实现单点登录 jeecms页面展示:   相关阅读 同类推荐:CMS系统

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值