ofbiz修复bug——使用内容组件创建博客文章时报错

78 篇文章 6 订阅
49 篇文章 2 订阅

使用内容组件创建博客文章时报错。


异常信息:

ERROR: Could not complete the Create a new Blog Entry [file:/F:/ofbiz/apache-ofbiz-16.11.02/applications/content/minilang/blog/BlogServices.xml#createBlogEntry] 
process [problem invoking the [createTextContent] service with the map named [createText] containing 
[{dataTemplateTypeId=NONE, ownerContentId=10030, mapKey=ARTICLE, description=自助机维护描述, locale=zh, contentName=自助机维护, contentPurposeTypeId=ARTICLE, userLogin=[GenericEntity:UserLogin][createdStamp,2017-05-26 09:27:16.0(java.sql.Timestamp)][createdTxStamp,2017-05-26 09:27:16.0(java.sql.Timestamp)][currentPassword,$SHA$RmNEvG$6nKzKSOBnQy3BZohBuYkSklOtw8(java.lang.String)][disabledBy,null()][disabledDateTime,2017-10-18 10:09:20.0(java.sql.Timestamp)][enabled,Y(java.lang.String)][externalAuthId,null()][hasLoggedOut,N(java.lang.String)][isSystem,null()][lastCurrencyUom,null()][lastLocale,zh(java.lang.String)][lastTimeZone,null()][lastUpdatedStamp,2017-11-06 07:59:33.0(java.sql.Timestamp)][lastUpdatedTxStamp,2017-11-06 07:59:33.0(java.sql.Timestamp)][partyId,admin(java.lang.String)][passwordHint,Auto-Generated Password(java.lang.String)][requirePasswordChange,N(java.lang.String)][successiveFailedLogins,0(java.lang.Long)][userLdapDn,null()][userLoginId,admin(java.lang.String)], textData=自助机维护常见维护方式 自助机维护常见维护方式 自助机维护常见维护方式, statusId=CTNT_INITIAL_DRAFT, contentAssocTypeId=SUB_CONTENT, contentIdFrom=10034, partyId=admin, dataResourceTypeId=ELECTRONIC_TEXT}]
: 找不到下列必须的参数: [IN] [createElectronicText.dataResourceId]]

分析查找原因:

根据异常提示信息,我们知道错误是发生在BlogServices.xml#createBlogEntry服务调用createTextContent服务时,传的参数createText不包含dataResourceId,所以异常了。

下面按流程查找相关配置:

1.提交时发出post请求


2.controller.xml根据请求映射进行相应的处理

<request-map uri="createBlogArticle">
        <security https="true" auth="true"/>
        <event type="service" invoke="createBlogEntry"/>
        <response name="error" type="view" value="EditBlogArticle"/>
        <response name="success" type="view" value="blogContent"/>
    </request-map>
3.通过ofbiz的服务引擎查看createBlogEntry服务的定义



从上面的定义可以看到,dataResourceId并不是必须要输入的参数。接着继续查找原因。


4.查看createBlogEntry服务的具体实现(apache-ofbiz-16.11.02\applications\content\minilang\blog\BlogServices.xml)

    <simple-method method-name="createBlogEntry" short-description="Create a new Blog Entry">
        <set field="contentAssocTypeId" value="PUBLISH_LINK"/>
        <set field="ownerContentId" from-field="parameters.blogContentId"/>
        <set field="contentIdFrom" from-field="parameters.blogContentId"/>
        <if-empty field="parameters.statusId">
            <set field="parameters.statusId" value="CTNT_INITIAL_DRAFT"/>
        </if-empty>
        <if-empty field="parameters.templateDataResourceId">
            <set field="parameters.templateDataResourceId" value="BLOG_TPL_TOPLEFT"/>
        </if-empty>

        <!-- determine of we need to create complex template structure or simple content structure -->
        <if-empty field="parameters.contentName">
            <add-error>
                <fail-property resource="ContentUiLabels" property="ContentArticleNameIsMissing"/>
            </add-error>
        </if-empty>
        <check-errors/>
        <!-- complex template structure (image & text) -->
        <set field="createMain.dataResourceId" from-field="parameters.templateDataResourceId"/>
        <set field="createMain.contentAssocTypeId"  from-field="contentAssocTypeId"/>
        <set field="createMain.contentName" from-field="parameters.contentName"/>
        <set field="createMain.description" from-field="parameters.description"/>
        <set field="createMain.statusId" from-field="parameters.statusId"/>
        <set field="createMain.contentIdFrom" from-field="contentIdFrom"/>
        <set field="createMain.partyId" from-field="userLogin.partyId"/>
        <set field="createMain.ownerContentId" from-field="ownerContentId"/>
        <set field="createMain.dataTemplateTypeId" value="SCREEN_COMBINED"/>
        <set field="createMain.mapKey" value="MAIN"/>
        <call-service service-name="createContent" in-map-name="createMain">
            <result-to-field result-name="contentId" field="contentId"/>
        </call-service>
        <!-- reset contentIdFrom to new contentId -->
        <set field="contentAssocTypeId" value="SUB_CONTENT"/>
        <set field="contentIdFrom" from-field="contentId"/>

        <if-not-empty field="parameters._uploadedFile_fileName">
            <!-- upload a picture -->
            <set field="createImage.dataResourceTypeId" value="LOCAL_FILE"/>
            <set field="createImage.dataTemplateTypeId" value="NONE"/>
            <set field="createImage.mapKey" value="IMAGE"/>
            <set field="createImage.ownerContentId" from-field="ownerContentId"/>
            <set field="createImage.contentName" from-field="parameters.contentName"/>
            <set field="createImage.description" from-field="parameters.description"/>
            <set field="createImage.statusId" from-field="parameters.statusId"/>
            <set field="createImage.contentAssocTypeId"  from-field="contentAssocTypeId"/>
            <set field="createImage.contentIdFrom" from-field="contentIdFrom"/>
            <set field="createImage.partyId" from-field="userLogin.partyId"/>
            <set field="createImage.isPublic" value="Y"/>
            <set field="createImage.uploadedFile" from-field="parameters.uploadedFile"/>
            <set field="createImage._uploadedFile_fileName" from-field="parameters._uploadedFile_fileName"/>
            <set field="createImage._uploadedFile_contentType" from-field="parameters._uploadedFile_contentType"/>
            <call-service service-name="createContentFromUploadedFile" in-map-name="createImage">
                <result-to-field result-name="contentId" field="imageContentId"/>
            </call-service>
        </if-not-empty>

        <if-not-empty field="parameters.articleData">
            <!-- create text data -->
            <set field="createText.dataResourceTypeId" value="ELECTRONIC_TEXT"/>
            <set field="createText.contentPurposeTypeId" value="ARTICLE"/>
            <set field="createText.dataTemplateTypeId" value="NONE"/>
            <set field="createText.mapKey" value="MAIN"/>
            <set field="createText.ownerContentId" from-field="ownerContentId"/>
            <set field="createText.contentName" from-field="parameters.contentName"/>
            <set field="createText.description" from-field="parameters.description"/>
            <set field="createText.statusId" from-field="parameters.statusId"/>
            <set field="createText.contentAssocTypeId"  from-field="contentAssocTypeId"/>
            <set field="createText.textData" from-field="parameters.articleData"/>
            <set field="createText.contentIdFrom" from-field="contentIdFrom"/>
            <set field="createText.partyId" from-field="userLogin.partyId"/>
            <set field="createText.mapKey" value="ARTICLE"/>
            <log level="info" message="calling createTextContent with map: ${createText}"/>
            <call-service service-name="createTextContent" in-map-name="createText">
                <result-to-field result-name="contentId" field="textContentId"/>
            </call-service>
        </if-not-empty>

        <if-not-empty field="contentId">
            <if-not-empty field="parameters.summaryData">
                <!-- create the summary data -->
                <set field="createSummary.dataResourceTypeId" value="ELECTRONIC_TEXT"/>
                <set field="createSummary.contentPurposeTypeId" value="ARTICLE"/>
                <set field="createSummary.dataTemplateTypeId" value="NONE"/>
                <set field="createSummary.mapKey" value="SUMMARY"/>
                <set field="createSummary.ownerContentId" from-field="ownerContentId"/>
                <set field="createSummary.contentName" from-field="parameters.contentName"/>
                <set field="createSummary.description" from-field="parameters.description"/>
                <set field="createSummary.statusId" from-field="parameters.statusId"/>
                <set field="createSummary.contentAssocTypeId"  from-field="contentAssocTypeId"/>
                <set field="createSummary.textData" from-field="parameters.summaryData"/>
                <set field="createSummary.contentIdFrom" from-field="contentIdFrom"/>
                <set field="createSummary.partyId" from-field="userLogin.partyId"/>
                <call-service service-name="createTextContent" in-map-name="createSummary"/>
            </if-not-empty>
        </if-not-empty>

        <field-to-result field="contentIdFrom" result-name="contentId"/>
        <field-to-result field="parameters.blogContentId" result-name="blogContentId"/>
    </simple-method>

从上面可以看到parameters.articleData不为空时,会调用createTextContent服务,就是这个服务调用时createText中没有包含dataResourceId,导致报错了。

5.查看createTextContent服务的定义(具体方法参照上面的办法,利用ofbiz的服务引擎):

    <service name="createTextContent" engine="group" auth="true">
        <description>Creates a Text Document DataResource and Content Records</description>
        <!-- uses createContent internally; additonal permission(s) not necessary -->
        <group>
            <invoke name="createDataText" result-to-context="true"/>
            <invoke name="createContent" result-to-context="true"/>
        </group>
    </service>
这个服务时个服务组,会调用2个服务createDataText和createContent。
6.查看createDataText服务的定义

<!-- generic create data text service; looks at the type id to determine if ELECTRONIC_TEXT is necessary -->
    <service name="createDataText" engine="route" auth="true">
        <description>Uses ECA to decide if we should call createElectronicText or just createDataResource (SHORT_TEXT)</description>
        <implements service="createDataResource"/>
        <implements service="createElectronicText"/>
    </service>

这个是一个route类型的服务,可以看到它继承了createDataResource和createElectronicText服务接口。而调用createElectronicText服务必须输入参数dataResourceId,否则就会报错。

    <!-- ElectronicText services -->
    <service name="createElectronicText" default-entity-name="ElectronicText" engine="entity-auto" invoke="create" auth="true">
        <description>Create a ElectronicText</description>
        <permission-service service-name="genericDataResourcePermission" main-action="CREATE"/>
        <implements service="createDataResource"/>
        <auto-attributes include="pk" mode="INOUT" optional="false"/>
        <auto-attributes include="nonpk" mode="IN" optional="true"/>
        <override name="dataResourceTypeId" default-value="ELECTRONIC_TEXT"/>
        <override name="textData" allow-html="any"/>
    </service>

<!-- DataResource services -->
    <service name="createDataResource" default-entity-name="DataResource" engine="simple"
            location="component://content/minilang/data/DataServices.xml" invoke="createDataResource" auth="true">
        <description>Create a DataResource</description>
        <permission-service service-name="genericDataResourcePermission" main-action="CREATE"/>
        <auto-attributes include="nonpk" mode="IN" optional="true"/>
        <attribute name="dataResourceId" type="String" mode="INOUT" optional="true"/>
        <attribute name="targetOperationList" type="List" mode="IN" optional="true"/>
        <attribute name="contentPurposeList" type="List" mode="IN" optional="true"/>
        <attribute name="skipPermissionCheck" type="String" mode="IN" optional="true"/>
        <attribute name="roleTypeId" type="String" mode="IN" optional="true"/>
        <attribute name="partyId" type="String" mode="IN" optional="true"/>
        <attribute name="dataResourceId" type="String" mode="OUT" optional="false"/>
        <attribute name="dataResource" type="org.apache.ofbiz.entity.GenericValue" mode="OUT" optional="true"/>
        <attribute name="uploadedFile" type="java.nio.ByteBuffer" mode="IN" optional="true"/>
        <override name="objectInfo" allow-html="any"/>
        <override name="dataResourceName" allow-html="any"/>
    </service>
7.查看ElectronicText实体的定义(路径:apache-ofbiz-16.11.02\applications\datamodel\entitydef\content-entitymodel.xml)

    <entity entity-name="ElectronicText"
            package-name="org.apache.ofbiz.content.data"
            title="Electronic Text Entity">
      <field name="dataResourceId" type="id-ne"></field>
      <field name="textData" type="very-long"></field>
      <prim-key field="dataResourceId"/>
      <relation type="one" fk-name="DATA_REC_TEXT" rel-entity-name="DataResource">
        <key-map field-name="dataResourceId"/>
      </relation>
    </entity>

从上面可以看到dataResourceId是dataResourceId实体的主键,而在createElectronicText服务的定义中,却有下面的配置:

<auto-attributes include="pk" mode="INOUT" optional="false"/>

说明dataResourceId是必须输入的参数。

问题的原因找到了,那么解决办法也就出来了,有2种办法:

1. 直接把上面的配置false修改true,即调用该服务主键可以不是必选参数,会自动生成主键。

<auto-attributes include="pk" mode="INOUT" optional="true"/>
2. 调用createTextContent服务时,传入的createText参数中包含dataResourceId。

具体采用哪一种,就要看dataResourceId在之前是否有其他实体使用并生成了,如果有,则构造createText时吧它传进去,否则就需要修改一下createElectronicText服务的定义。
经过分析,应该是使用第一种比较好。

理由:在apache-ofbiz-16.11.02\applications\content\servicedef\secas.xml中如下定义:

    <!-- electronic text; needs dataResourceId -->
    <eca service="createElectronicText" event="invoke">
        <condition field-name="dataResourceId" operator="is-empty"/>
        <set field-name="dataResourceTypeId" value="ELECTRONIC_TEXT"/>
        <action service="createDataResource" mode="sync" result-to-context="true"/>
    </eca>
说明当dataResourceId为null时,会自动触发该触发器,然后调用createDataResource服务添加记录。即调用createElectronicText服务时是允许dataResourceId为null的。

最终解决方案:

打开文件:apache-ofbiz-16.11.02\applications\content\servicedef\services_data.xml

修改createElectronicText服务的定义。

    <!-- ElectronicText services -->
    <service name="createElectronicText" default-entity-name="ElectronicText" engine="entity-auto" invoke="create" auth="true">
        <description>Create a ElectronicText</description>
        <permission-service service-name="genericDataResourcePermission" main-action="CREATE"/>
        <implements service="createDataResource"/>
        <!-- <auto-attributes include="pk" mode="INOUT" optional="false"/> -->
		<auto-attributes include="pk" mode="INOUT" optional="true"/>
        <auto-attributes include="nonpk" mode="IN" optional="true"/>
        <override name="dataResourceTypeId" default-value="ELECTRONIC_TEXT"/>
        <override name="textData" allow-html="any"/>
    </service>

经过测试,修改后重启ofbiz,再次发布文章能正常使用了。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值