Как переопределить стандартное поведение ApplicationTagLib # createLink и g: link? - PullRequest
11 голосов
/ 03 июня 2011

Фон : У меня есть приложение Grails 1.3.7, которое использует g:createLink и g:link на многих страницах.

Недавно я решил сделать большие изменения в отображениях URL - ввести предшествующий элемент пути.

  • В настоящее время у меня есть: /$controller/$action?/$id?
  • Но хочу иметь: /$regionId/$controller/$action?/$id?

Было легко изменить urlMappings, но я не могу понять, как легко изменить поведение, создаваемое ссылками через приложение.

По сути, я не хочу просматривать каждую страницу и менять ссылки. Но хочу сделать это в одном месте.

Вопрос Как переопределить функциональность ApplicationTagLib # createLink, чтобы grails использовал эту реализацию без необходимости изменений страниц, использующих этот тег (или функцию)?

Любая помощь очень ценится!

Ответы [ 3 ]

14 голосов
/ 27 июня 2012

У меня была проблема с улыбкой. На самом деле вы можете украсить тег g: link следующим образом.

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) добавить в UrlMappings.groovy

"/$region/$controller/$action?/$id?"{}
4 голосов
/ 07 июня 2011

Мне не удалось решить эту проблему с точки зрения ООП.Я имею в виду, я не могу найти способ переопределить закрытие.Я попробовал несколько подходов, но безуспешно.И документация говорит , что вы не можете переопределить закрытие, вы можете заменить его только новой реализацией (пожалуйста, исправьте меня, если я ошибаюсь).

Но (!) Мне удалось решить задачу путем вставки исходного кода метода 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 голос
/ 04 июня 2011

добавьте regionId к параметрам в createLink, а g: link и grails достаточно умны, чтобы соответствовать вашим urlmappings. * 1001 то есть *

${createLink(controller:'c',action:'a',id:1,params:[regionId:2])}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...