eterna框架-环境搭建(续)

本文从源码角度深入分析JAVAEE环境搭建配置过程,详细解读web.xml文件配置及EternaServlet工作原理。

这一篇博客,我将带着大家从源码的角度来分析环境搭建的配置。
我们都知道,一个JAVA EE程序基本的配置都是在web.xml文件中的,我们就从这个文件开始分析。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">
    <display-name>test</display-name>

    <servlet>
        <servlet-name>study</servlet-name>
        <servlet-class>self.micromagic.app.EternaServlet</servlet-class>
        <init-param>
            <param-name>initFiles</param-name>
            <param-value>cp:study/index.xml;</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>study</servlet-name>
        <url-pattern>/study.do</url-pattern>
    </servlet-mapping>

    <jsp-config>
        <taglib>
            <taglib-uri>http://code.google.com/p/eterna</taglib-uri>
            <taglib-location>/WEB-INF/tld/eterna.tld</taglib-location>
        </taglib>
    </jsp-config>

</web-app>

在web.xml文件中,我们定义了一个Servlet,映射了/study.do路径,这个Servlet是eterna为我们提供的一个实现,我们在学习的时候可以直接使用。在这个Servlet配置中,我们使用了一个初始化参数initFiles,表示要初始化的文件,我们可以查看EternaServlet的源码,看看还有那些配置可以使用。

代码清单1

/**
 * 用于加载eterna配置的servlet.
 *
 * 可设置的参数如下:
 *
 * defaultModel       当没有指定model名称时, 调用此属性指定的默认的model
 *                    默认值为: ModelCaller.DEFAULT_MODEL_NAME
 *
 * initFiles          需要加载的eterna的配置文件列表
 *
 * parentFiles        需要加载的eterna父配置文件列表
 *
 * charset            使用的字符集, 默认值为: UTF-8
 *
 *
 * @see ModelCaller#DEFAULT_MODEL_NAME
 * @see FactoryManager#CONFIG_INIT_FILES
 * @see FactoryManager#CONFIG_INIT_PARENTFILES
 *
 * @author micromagic@sina.com
 */

在EternaServlet类注释上,已经告诉我们了可以使用的配置参数。值得一提的是在参数中有parentFilesinitFiles都是配置文件列表,二者的关系有点像JAVA的继承,在子初始化文件中如果存在和父初始化文件中相同的组件,那么父初始化文件中的组件将被覆盖。在配置初始化文件时使用cp:表示classpath路径。

继续向下看这个类的源码

代码清单2

protected void service(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
{
    if (!this.charset.equals(request.getCharacterEncoding()))
    {
        request.setCharacterEncoding(this.charset);
    }
    response.setContentType("text/html;charset=" + this.charset);
    AppData data = AppData.getCurrentData();
    data.request = request;
    data.response = response;
    data.contextRoot = request.getContextPath();
    data.servletConfig = this.getServletConfig();
    data.position = AppData.POSITION_SERVLET;
    try
    {
        data.maps[AppData.REQUEST_PARAMETER_MAP] = RequestParameterMap.create(request);
        data.maps[AppData.REQUEST_ATTRIBUTE_MAP] = ValueContainerMap.createRequestAttributeMap(request);
        data.maps[AppData.SESSION_ATTRIBUTE_MAP] = ValueContainerMap.createSessionAttributeMap(request);

        String queryStr = request.getQueryString();
        if (queryStr != null)
        {
            String modelNameTag = this.getFactoryManager().getEternaFactory().getModelNameTag();
            int index;
            int plusCount = 2;
            if (queryStr.length() > 0 && queryStr.charAt(0) != '?')
            {
                if (queryStr.startsWith(modelNameTag + "="))
                {
                    index = 0;
                    plusCount = 1;
                }
                else
                {
                    index = -1;
                }
            }
            else
            {
                index = queryStr.indexOf("?" + modelNameTag + "=");
            }
            if (index == -1)
            {
                index = queryStr.indexOf("&" + modelNameTag + "=");
            }
            if (index != -1)
            {
                int endIndex = queryStr.indexOf('&', index + 1);
                if (endIndex != -1)
                {
                    data.modelName = queryStr.substring(index + modelNameTag.length() + plusCount, endIndex);
                }
                else
                {
                    data.modelName = queryStr.substring(index + modelNameTag.length() + plusCount);
                }
            }
        }

        request.setAttribute(ModelCaller.DEFAULT_MODEL_TAG, this.defaultModel);
        ModelExport export = this.getFactoryManager().getEternaFactory().getModelCaller().callModel(data);
        if (export != null)
        {
            data.export = export;
        }
    }
    catch (ConfigurationException ex)
    {
        log.warn("Error in service.", ex);
    }
    catch (SQLException ex)
    {
        log.warn("SQL Error in service.", ex);
    }
    catch (Throwable ex)
    {
        log.error("Other Error in service.", ex);
    }
    finally
    {
        try
        {
            if (data.export != null)
            {
                this.doExport(data, request, response);
            }
        }
        catch (Throwable ex)
        {
            log.error("Error in doExport.", ex);
        }
        data.modelName = null;
        data.export = null;
        data.servletConfig = null;
        data.clearData();
    }
}

这是Servlet处理客户端请求的方法,eterna首先会设置请求和响应的编码,然后对AppData中的属性做一些赋值操作(AppData会贯穿eterna整个处理过程),在EternaServlet中是通过解析QueryString来获得需要执行的Model的,所以正常情况下,请求地址应该形如:http://[domain]:[host]/[servletmapping]?model=[modelName],以搭建的环境为例,我们请求的地址应为:http://localhost/eterna/study.do?model=[modelName],而在我们之前测试的时候,我们并没有添加查询参数也可以访问,其实通过代码,我们不难理解,当不存在modelName时,eterna会使用默认的modelName,ModelCaller.DEFAULT_MODEL_NAME,其实也就是index,我们在测试时访问的地址就等价于:http://localhost/eterna/study.do?model=index

在eterna中是有日志的,在我们搭建的环境中并没有配置,所以需要看日志的小伙伴可以在src文件夹下添加commons-logging.properties文件,文件参考内容如下:

priority=100
org.apache.commons.logging.LogFactory=self.micromagic.util.Jdk14Factory

接下来,我们再来看index.xml,这个是eterna的配置文件

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE eterna-config PUBLIC "eterna" "http://eterna.googlecode.com/files/eterna_1_5.dtd">

<eterna-config>
    <factory>
        <objs>
            <export name="index.export" path="/view.jsp" viewName="index.view" />
            <model name="index" modelExportName="index.export"
                transactionType="notNeed" />
            <view name="index.view">
                <component name="div" type="div"
                    comParam="text:'this is my first eterna application.'" />
            </view>
        </objs>
    </factory>
</eterna-config>

eterna配置文件的根元素为eterna-config,在根元素下包含的唯一元素为factory,表示用于构造所有对象的工厂。
objs表示所有对象的集合。
export元素代表一个业务的出口。

属性名说明
name“export”的名称, 它在同一个”Factory”中必须是唯一的.
modelName指定转到下一个”model”的名称. 如果指定了modelName, 则不可指定viewName、path、redirect
path指定业务出口的页面,如果指定了path则不可指定modelName.另外modelName和path必须指定一个
viewName指定出口所使用的”view”对象
errorExport业务出口是否是一个出错的处理出口, 默认为”false”.
redirect业务出口是否需要redirect, 默认为”false”

model元素代表代表一个业务。

属性名说明
name“ModelAdapter”的名称, 它在同一个”Factory”中必须是唯一的
generator指定”ModelAdapter”的构造器, 这个类必须实现 [“self.micromagic.eterna.model.ModelAdapterGenerator”]接口
keepCaches是否需要保持所有的cache, 在退出这个model后和进入model前 一致, 默认为”false”.
frontModelName需要执行前置model的名称, 只有needFrontModel为”true”时, 这个属性才有效. 注: frontModel在一次完整的model请求期间只会执行一次
modelExportName指定业务的正常出口
errorExportName指定业务的异常(或出错处理)出口.
transactionType业务的事务处理方式, 默认为”requared”
dataSourceName使用的数据源名称
positions可执行此业务的位置, 默认为”servlet”和”portletRender”

model、view、export就是典型的MVC。

component对应html中的一个元素,具体属性的说明,我们可以查看配置文件的dtd,这里就不再赘述了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值