如何覆盖 ApplicationTagLib#createLink 和 g:link 的标准行为? [英] How to override standard behavior of ApplicationTagLib#createLink and g:link?
问题描述
背景:我有 grails 1.3.7 应用程序,它在许多页面上使用 g:createLink
和 g:link
.
Background:
I have grails 1.3.7 application which uses g:createLink
and g:link
on many pages.
最近我决定对 url 映射进行重大更改 - 引入前面的路径元素.
Recently I decided to make big change in url mappings - introduce preceding path element.
- 目前我有:
/$controller/$action?/$id?
- 但是想要:
/$regionId/$controller/$action?/$id?
更改 urlMappings 很容易,但我不知道如何轻松更改通过应用程序构建链接的行为.
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.
问题如何覆盖 ApplicationTagLib#createLink 功能,以便 grails 将使用此实现,而无需更改使用此标记(或函数)的页面?
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)?
非常感谢任何帮助!
推荐答案
我无法从 OOP 的角度解决这个问题.我的意思是我找不到如何覆盖关闭的方法.我尝试了几种方法,但没有成功.和文档 说 你不能覆盖闭包,你只能用新的替换它实现(如果我错了,请纠正我).
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).
但是 (!) 我能够通过复制粘贴 ApplicationTagLib#createLink 方法的源代码来解决任务.我认为这是一个残酷的解决方案,但在为这个简单的任务奋斗了 8 个小时之后 - 这是可以接受的.
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.
所以最后我需要做的就是定义这个类,grails 将立即使用它来生成链接(对于所有视图,无需更改它们的代码):
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屋!