最新代码更新
以下函数使用基于邮政编码(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)>
答案 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,但这里有一个小的重写,解决了四件事:
同样,这没有经过测试,但希望它有用:
<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")>