如何重写ApplicationTagLib的标准行为#createLink和g:link? [英] How to override standard behavior of ApplicationTagLib#createLink and g:link?

查看:90
本文介绍了如何重写ApplicationTagLib的标准行为#createLink和g:link?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有Grails 1.3.7应用程序,它使用 g:createLink g:链接在很多页面上。



最近我决定在url映射中做大的改动 - 介绍前面的路径元素。




  • 目前我有: / $ controller / $ action?/ $ id?


  • $ <$> $ $ $ $ $ $ $ $ $ $ $ $ $ b


很容易更改urlMappings,但我无法弄清楚如何轻松更改链接在应用程序中的构建方式。

基本上,我不想浏览每个网页并更改链接。但想在一个地方做到这一点。

问题
如何覆盖ApplicationTagLib#createLink功能,以便grails将使用此实现需要更改使用这个标签(或函数)的页面?



任何帮助大大appriciated!

解决方案

我无法用OOP解决这个问题。我的意思是我无法找到如何覆盖闭包。我尝试了几种方法,但没有成功。并且表示您无法覆盖关闭,您只能将其替换为新的(请纠正我,如果我错了)。

但是(!)我能够通过复制粘贴ApplicationTagLib的源代码来解决任务#createLink方法。
我认为这是一个残酷的解决方案,但经过8个小时与这个简单的任务作斗争 - 这是可以接受的。

因此,最后我需要做的是 - 定义这个类,grails会立即使用它进行链接生成(对于所有视图,不需要更改它们的代码):

  import java .text.SimpleDateFormat; 

导入groovy.time。*;
import java.text。*;

导入org.codehaus.groovy.grails.commons.GrailsControllerClass
导入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

类OverrideTagLib扩展ApplicationTagLib {

def createLink = {attrs - >
//获取regionId参数的值
def regionId = regionIdFinderService.currentRegionId

// add cutsom regionId参数
if(attrs){
if( attrs.params)
attrs.params.put(regionId,regionId);
else {
attrs.params = [regionId:regionId];



$ process
def writer = getOut()
//更喜欢URI属性
if(attrs.uri) {
作家<< handleAbsolute(attrs)
writer<< attrs.uri.toString()
}
else {
//偏好URL属性
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。事件){
params。_ eventId= urlAttrs.remove('event')
}
def url
if(id!= null)params.id = id
def urlMappings = applicationContext.getBean(grailsUrlMappingsHolder)
UrlCreator mapping = urlMappings.getReverseMapping(控制器,动作,参数)

//不能在绝对链接中使用jsessionid
if(useJsessionId&!attrs.absolute){
url = mapping.create URL(控制器,动作,参数,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<<网址
}
}
}
}
}


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

Recently I decided to make big change in url mappings - introduce preceding path element.

  • Currently I have: /$controller/$action?/$id?
  • But want to have: /$regionId/$controller/$action?/$id?

It was easy to change urlMappings, but I can't figure out how to easily change the behavior how links are built throught the application.

Basically, I don't want to go through each page and change links. But want to do this in one place.

Question How to override ApplicationTagLib#createLink functionality so grails will use this implementation without the need of changes pages which use this tag (or function)?

Any help greatly appriciated!

解决方案

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
                }
            }
        }
    }
}

这篇关于如何重写ApplicationTagLib的标准行为#createLink和g:link?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆