使用Web服务代码简化

时间:2010-08-29 23:34:46

标签: web-services coldfusion

最新代码更新

以下函数使用基于邮政编码(CEP)返回地址详细信息的Web服务。我正在使用此函数来解析xml并使用地址详细信息填充空查询。我想知道是否有更优雅的方法来实现相同的结果。创建一个空查询并填充它似乎是一种浪费......

任何想法都可以修改我的方法或代码因素/简化?

<!--- ****** ACTION: getAddress (consumes web-service to retrieve address details) --->
<cffunction name="getAddress" access="remote" returntype="any" output="false">

    <!--- Defaults: strcep (cep (Brazilian zip-code) string webservice would look for), search result returned from webservice --->
    <cfargument name="cep" type="string" default="00000000">
    <cfset var searchResult = "">
    <cfset var nodes = "">
    <cfset var cfhttp = "">
    <cfset var stateid = 0>
    <cfset var tmp = structNew()>

    <!--- Validate cep string --->
    <cfif IsNumeric(arguments.cep) AND Len(arguments.cep) EQ 8>

        <cftry>

            <!--- Consume webservice --->                
            <cfhttp method="get" url="http://www.bronzebusiness.com.br/webservices/wscep.asmx/cep?strcep=#arguments.cep#"></cfhttp>
            <cfset searchResult = xmlparse(cfhttp.FileContent)>
            <cfset nodes = xmlSearch(searchResult, "//tbCEP")>

            <!--- If result insert address data into session struct --->
            <cfif arrayLen(nodes)>

                <cfset tmp.streetType = nodes[1].logradouro.XmlText>
                <cfset tmp.streetName = nodes[1].nome.XmlText>
                <cfset tmp.area = nodes[1].bairro.XmlText>
                <cfset tmp.city = nodes[1].cidade.XmlText>
                <cfset tmp.state = nodes[1].uf.XmlText>
                <cfset tmp.cep = arguments.cep>

                <!--- Get state id and add to struct --->
                <cfset stateid = model("state").findOneByStateInitials(tmp.state)>
                <cfset tmp.stateid = stateid.id>

                <cfreturn tmp>

            </cfif>

            <!--- Display error if any --->
            <cfcatch type="any">
                <cfoutput>
                    <h3>Sorry, but there was an error.</h3>
                    <p>#cfcatch.message#</p>
                </cfoutput>
            </cfcatch>

        </cftry>

    </cfif>

</cffunction>
<!--- ****** END ACTION getAddress --->

主叫代码:

        <!--- Get address data based on CEP --->
        <cfset session.addressData = getAddress(cep=params.newMember.cep)>

2 个答案:

答案 0 :(得分:1)

这看起来非常简单。 CF没有(但是?)有任何神奇的XML-to-Query功能,但这很酷。如果你愿意的话,你可能会编写一个XSL转换来从XML转到WDDX,这样你就可以使用cfwddx标签......但是这可能会把购物车放在马前。

你需要将arrayLen()if block移动到try块中。就目前而言,如果cfhttp标记抛出错误,那么nodes变量将是一个字符串而不是一个数组,从而导致arrayLen()抛出另一个错误。

Minor nitpick:在arrayLen()块内部,我不会向查询添加行。这样,调用代码可以检查recordCount以查看结果是否成功。

除此之外......这几乎就是它的完成方式。

答案 1 :(得分:1)

我无法测试这个,因为我没有要测试的示例XML文件/ CEP,但这里有一个小的重写,解决了四件事:

  • 您应该将CEP作为参数传递给函数,而不是使用cfparam和一些奇怪的“params”结构。
  • 该功能不应直接修改会话数据。相反,您应该返回结果并让调用代码将其分配给会话(或者可能需要的任何其他地方)。我将在第二个代码示例中显示此内容。
  • 为每个CEP缓存xml结果 - 假设这不会经常更改。 (如果您希望基于时间的手动缓存失效,则必须进一步改进,但如果需要,我可以帮助添加)
  • 不要使用StructInsert。这不是必要的,你只是为了长篇大论而写它很长的路。 没有任何好处

同样,这没有经过测试,但希望它有用:

<cffunction name="getAddress" access="remote" returntype="any" output="false">
    <cfargument name="cep" type="string" default="00000000" /><!--- (cep (Brazilian zip-code) string webservice would look for) --->
    <cfset var searchResult = "">
    <cfset var nodes = "">
    <cfset var cfhttp = "">
    <cfset var stateid = 0 />
    <cfset var tmp = structNew()>

    <!--- Validate cep string --->
    <cfif IsNumeric(arguments.cep) AND Len(arguments.cep) EQ 8>

        <cfif not structKeyExists(application.cepCache, arguments.cep)><!--- or cache is expired: you'd have to figure this part out --->

            <!--- Consume webservice --->
            <cftry>
                <cfhttp method="get" url="http://www.bronzebusiness.com.br/webservices/wscep.asmx/cep?strcep=#arguments.cep#" />
                <cfset searchResult = xmlparse(cfhttp.FileContent)>
                <cfset nodes = xmlSearch(searchResult, "//tbCEP")>

                <!--- If result insert address data into session struct --->
                <cfif arrayLen(nodes)>

                    <cfset tmp.streetType = nodes[1].logradouro.XmlText />
                    <cfset tmp.streetName = nodes[1].nome.XmlText />
                    <cfset tmp.area = nodes[1].bairro.XmlText />
                    <cfset tmp.city = nodes[1].cidade.XmlText />
                    <cfset tmp.state = nodes[1].uf.XmlText />
                    <cfset tmp.cep = arguments.cep />

                    <!--- Get state id and add to struct --->
                    <cfset stateid = model("state").findOneByStateInitials(session.addressData.state)>
                    <cfset tmp.stateid = stateid.id />

                </cfif>

                <cfreturn duplicate(tmp) />

                <!--- Display error if any --->
                <cfcatch type="any">
                    <h3>Sorry, but there was an error.</h3>
                    <p>#cfcatch.message#</p>
                </cfcatch>

            </cftry>

        <cfelse>

            <!--- cache exists and is not expired, so use it --->
            <cfreturn duplicate(application.cepCache[arguments.cep]) />

        </cfif>

    </cfif>
<!---
    <!--- Redirect to page two of the sign up process --->
    <cfset redirectTo(controller="assine", action="perfil")>
--->

</cffunction>

请注意,我注释掉了最后的重定向。那是因为使用我的函数,你将返回一个值,重定向应该在那之后完成,如下所示:

<cfset session.addressData = getAddress("some-CEP-value") />
<cfset redirectTo(controller="assine", action="perfil")>

如果您要省略缓存(正如您在评论中所说的那样),那么这是一个不会尝试缓存的版本:

<cffunction name="getAddress" access="remote" returntype="any" output="false">
    <cfargument name="cep" type="string" default="00000000" /><!--- (cep (Brazilian zip-code) string webservice would look for) --->
    <cfset var searchResult = "">
    <cfset var nodes = "">
    <cfset var cfhttp = "">
    <cfset var stateid = 0 />
    <cfset var tmp = structNew()>

    <!--- Validate cep string --->
    <cfif IsNumeric(arguments.cep) AND Len(arguments.cep) EQ 8>

        <!--- Consume webservice --->
        <cftry>
            <cfhttp method="get" url="http://www.bronzebusiness.com.br/webservices/wscep.asmx/cep?strcep=#arguments.cep#" />
            <cfset searchResult = xmlparse(cfhttp.FileContent)>
            <cfset nodes = xmlSearch(searchResult, "//tbCEP")>

            <!--- If result insert address data into session struct --->
            <cfif arrayLen(nodes)>

                <cfset tmp.streetType = nodes[1].logradouro.XmlText />
                <cfset tmp.streetName = nodes[1].nome.XmlText />
                <cfset tmp.area = nodes[1].bairro.XmlText />
                <cfset tmp.city = nodes[1].cidade.XmlText />
                <cfset tmp.state = nodes[1].uf.XmlText />
                <cfset tmp.cep = arguments.cep />

                <!--- Get state id and add to struct --->
                <cfset stateid = model("state").findOneByStateInitials(session.addressData.state)>
                <cfset tmp.stateid = stateid.id />

            </cfif>

            <cfreturn duplicate(tmp) />

            <!--- Display error if any --->
            <cfcatch type="any">
                <h3>Sorry, but there was an error.</h3>
                <p>#cfcatch.message#</p>
            </cfcatch>

        </cftry>

    </cfif>

<!---
    <!--- Redirect to page two of the sign up process --->
    <cfset redirectTo(controller="assine", action="perfil")>
--->

</cffunction>

请注意,我确实离开了使用duplicate()。这样做是返回对象的副本(在本例中为struct)。当您开始处理将复杂值一次又一次地传入和传出函数的应用程序时,这一点就更为重要。使用duplicate()会导致事情passed by value instead of by reference。在这种情况下,它可能不会咬你,但这是一个很好的习惯。

我还会使用函数参数并返回一个值 - 但可以说这是我个人的偏好。在某种程度上。我认为应该完全封装一个函数;一个完整的“黑匣子”。你给它一些输入,它会给你一些输出。它本身不应该修改任何东西。 (再次,只是我的意见。)

因此,假设您将此功能用作更大的多步骤过程的一部分,您仍应按照我上面描述的方式使用它。唯一的区别是您将会话变量设置在函数体之外。就像以前一样:

<cfset session.addressData = getAddress("some-CEP-value") />
<cfset redirectTo(controller="assine", action="perfil")>