背景:
我有grails 1.3.7应用程序,它在许多页面上使用g:createLink
和g:link
。
最近我决定对url映射进行重大更改 - 引入前面的path元素。
/$controller/$action?/$id?
/$regionId/$controller/$action?/$id?
很容易更改urlMappings,但我无法弄清楚如何轻松更改应用程序中链接的构建方式。
基本上,我不想浏览每个页面并更改链接。但是想在一个地方做到这一点。
问题 如何覆盖ApplicationTagLib#createLink功能,因此grails将使用此实现而无需使用此标记(或函数)的更改页面?
任何帮助都非常有用!
答案 0 :(得分:14)
我有类似的问题。实际上你可以像这样装饰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?"{}
答案 1 :(得分: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
}
}
}
}
}
答案 2 :(得分:1)
将createId添加到createLink中的params,g:link和grails足够智能,可以匹配您的urlmappings。即
${createLink(controller:'c',action:'a',id:1,params:[regionId:2])}