How to override standard behavior of ApplicationTagLib#createLink and g:link?

后端 未结 3 1103
攒了一身酷
攒了一身酷 2021-01-02 04:03

Background: I have grails 1.3.7 application which uses g:createLink and g:link on many pages.

Recently I decided to make b

相关标签:
3条回答
  • 2021-01-02 04:48

    add regionId to params in createLink and g:link and grails is smart enough to match your urlmappings. i.e

    ${createLink(controller:'c',action:'a',id:1,params:[regionId:2])}
    
    0 讨论(0)
  • 2021-01-02 04:51

    I was unable to solve this problem in terms of OOP. I mean I can't find way how to override closure. I tried several approaches, but with no success. And documentation says that you can't override closure, you can only replace it with new implementation (please correct me if I wrong).

    But (!) I was able to solve task by copy-pasting source code of ApplicationTagLib#createLink method. I think this is brutal solution, but after 8 hours of fighting with this simple task - it's acceptable.

    So finally all I need to do - is define this class, grails will immediately use it for link generation (for all views, no need to change their code):

    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
                    }
                }
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-02 04:57

    I had a smilar problem. Actually you can decorate g:link tag like this.

    1) TagLib

    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) add to UrlMappings.groovy

    "/$region/$controller/$action?/$id?"{}
    
    0 讨论(0)
提交回复
热议问题