2011-06-03 23 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