2011-06-03 39 views
10

背景: 我有grails 1.3.7應用程序,它在很多頁面上使用g:createLinkg:link如何覆蓋ApplicationTagLib的標準行爲#createLink和g:link?

最近我決定在url映射中做大的改動 - 介紹前面的路徑元素。

  • 目前我有:/$controller/$action?/$id?
  • 但是想有:/$regionId/$controller/$action?/$id?

這是很容易改變urlMappings,但我無法弄清楚如何輕易改變的行爲聯繫是如何建立通過應用程序。

基本上,我不想瀏覽每個頁面並更改鏈接。但想在一個地方做到這一點。

問題 如何覆蓋ApplicationTagLib#建立連結功能,所以Grails將使用此實現,而不需要其使用該標籤(或功能)改變頁面?

任何幫助大大appriciated!

回答

4

我無法解決這個問題的OOP方面。我的意思是我無法找到如何覆蓋閉包。我嘗試了幾種方法,但沒有成功。並且你不能覆蓋閉包的文檔says,你只能用新的實現來替換它(請糾正我,如果我錯了)。

但是(!)我能夠通過複製粘貼ApplicationTagLib#createLink方法的源代碼來解決任務。 我認爲這是殘酷的解決方案,但經過8個小時與這個簡單的任務作鬥爭 - 這是可以接受的。

所以最後所有我需要做的 - 是這個類定義,Grails將立即將其用於鏈接生成(對所有的意見,沒有必要改變他們的代碼):

import java.text.SimpleDateFormat; 

import groovy.time.*; 
import java.text.*; 

import org.codehaus.groovy.grails.commons.GrailsControllerClass 
import org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib; 
import org.codehaus.groovy.grails.web.mapping.UrlCreator 
import org.codehaus.groovy.grails.commons.ControllerArtefactHandler 
import org.springframework.web.context.request.RequestContextHolder 

class OverrideTagLib extends ApplicationTagLib { 

    def createLink = { attrs -> 
     // get value for regionId parameter 
     def regionId = regionIdFinderService.currentRegionId 

     // add cutsom regionId parameter 
     if (attrs) { 
      if (attrs.params) 
       attrs.params.put("regionId", regionId); 
      else { 
       attrs.params = ["regionId":regionId]; 
      } 
     } 

     // process 
     def writer = getOut() 
     // prefer URI attribute 
     if (attrs.uri) { 
      writer << handleAbsolute(attrs) 
      writer << attrs.uri.toString() 
     } 
     else { 
      // prefer a URL attribute 
      def urlAttrs = attrs 
      if (attrs.url instanceof Map) { 
       urlAttrs = attrs.remove('url').clone() 
      } 
      else if (attrs.url) { 
       urlAttrs = attrs.remove('url').toString() 
      } 

      if (urlAttrs instanceof String) { 
       if (useJsessionId) { 
        writer << response.encodeURL(urlAttrs) 
       } 
       else { 
        writer << urlAttrs 
       } 
      } 
      else { 
       def controller = urlAttrs.containsKey("controller") ? urlAttrs.remove("controller")?.toString() : controllerName 
       def action = urlAttrs.remove("action")?.toString() 
       if (controller && !action) { 
        GrailsControllerClass controllerClass = grailsApplication.getArtefactByLogicalPropertyName(ControllerArtefactHandler.TYPE, controller) 
        String defaultAction = controllerClass?.getDefaultAction() 
        if (controllerClass?.hasProperty(defaultAction)) { 
         action = defaultAction 
        } 
       } 
       def id = urlAttrs.remove("id") 
       def frag = urlAttrs.remove('fragment')?.toString() 
       def params = urlAttrs.params && urlAttrs.params instanceof Map ? urlAttrs.remove('params') : [:] 
       def mappingName = urlAttrs.remove('mapping') 
       if (mappingName != null) { 
        params.mappingName = mappingName 
       } 
       if (request['flowExecutionKey']) { 
        params."execution" = request['flowExecutionKey'] 
       } 

       if (urlAttrs.event) { 
        params."_eventId" = urlAttrs.remove('event') 
       } 
       def url 
       if (id != null) params.id = id 
       def urlMappings = applicationContext.getBean("grailsUrlMappingsHolder") 
       UrlCreator mapping = urlMappings.getReverseMapping(controller,action,params) 

       // cannot use jsessionid with absolute links 
       if (useJsessionId && !attrs.absolute) { 
        url = mapping.createURL(controller, action, params, request.characterEncoding, frag) 
        def base = attrs.remove('base') 
        if (base) writer << base 
        writer << response.encodeURL(url) 
       } 
       else { 
        url = mapping.createRelativeURL(controller, action, params, request.characterEncoding, frag) 
        writer << handleAbsolute(attrs) 
        writer << url 
       } 
      } 
     } 
    } 
} 
1

add regionId參數在createLink和g:link和grails足夠聰明以匹配您的url映射。即

${createLink(controller:'c',action:'a',id:1,params:[regionId:2])} 
+0

謝謝你的回答,但是這不會幫助,因爲兩個原因:1。 我不想更改所有視圖代碼; 2.更重要的是 - 當你想要指定參數值的時候,grails不夠聰明,其中一些是路徑元素和一些url參數。如果你將嘗試混合它們,grails會將它們全部作爲url參數傳遞。 – 2011-06-04 07:49:17

+0

2.'URL映射的另一個強大功能是它們自動定製鏈接標記的行爲,以便更改映射不要求您去更改所有鏈接。這是通過URL重寫技術來完成的,該技術反向設計URL映射中的鏈接。所以給定一個映射,比如前面一節中的博客 - 從Grails文檔 – netbrain 2011-06-04 08:53:12

13

我有一個smilar問題。其實你可以像這樣裝飾g:link標籤。

1)標籤庫

import org.codehaus.groovy.grails.plugins.web.taglib.* 

class OverrideDefaultTagLib { 

    static namespace = "g" 

    def link = { attrs, body -> 

     def c = "1" // Get it from session or somewhere else 

     if (attrs.params) { 
      attrs.params.put("region", c) 
     } else { 
      attrs.params = [region: c] 
     } 

     def applicationTagLib = grailsApplication.mainContext.getBean('org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib') 
      applicationTagLib.link.call(attrs, body) 
     } 
    } 
} 

2)添加到UrlMappings.groovy

"/$region/$controller/$action?/$id?"{} 
+0

+1跳過,以覆蓋namespace和getBean。 – Athlan 2014-04-18 17:22:32

+0

該文檔在哪裏? +1 tho,非常有幫助。 – 2014-10-23 13:49:08