I have an application that uses the grails multi-tenant-core plug-in to host multiple versions of a site. I want to be able to create custom GSPs for each site beyond what simple skinning will allow me to do. Essentially, I want to be able to have my grails-app/views
folder look something like:
views
|
|__template1
| |
| |__layouts
| | |
| | |__main.gsp
| |
| |__controller1
| |
| |__index.gsp
|
|__template 2
|
|__layouts
| |
| |__main.gsp
|
|__controller1
|
|__index.gsp
And then configure a specific tenant to use a specific set of GSPs. I am using a DNS resolver that's persisted in my database, so I could presumably add a property to the DomainTenantMap
domain class that assigns a templateDir
property to a particular tenant and sprinkle conditional logic all over the place in my GSPs and controllers. (followed by that 'can't...get...clean' feeling)
I haven't had any success finding an existing plug-in that provides this functionality. The other options I have considered seem to involve customizing fairly core pieces of grails (render tag, template engine, etc.) which makes me nervous.
I realize this is a fairly broad question; both specific solutions and general suggestions are appreciated.
EDIT:
I found another possible approach by creating a plug-in and meta-programming on a new method:
def configureTemplateRenderer(application, applicationContext) {
for (controllerClass in application.controllerClasses) {
controllerClass.metaClass.newRender = { args ->
println 'something'
if(args.view) {
args.view = "/somedir/${args.view}"
}
if(args.template) {
args.template = "/somedir/${args.template}"
}
delegate.render(args)
}
}
}
This is just a proof of concept to see if I can invoke the standard render
method through my new one (I can). Ideally, I could override the render
method entirely to modify the args.view
and args.template
property based on some sort of tenant/template mapping (not shown). However, I haven't been able to override the render
method successfully so this solution is really only marginally better than just sprinkling in some path variable to calls to render
.
A Solution!
I ended up creating a separate plug-in that essentially boils down to overriding the render method with one that checks a tenant/template map. Still testing but so far it looks promising, here's the gist of it:
def overrideRender = { application ->
for (controllerClass in application.controllerClasses) {
def original = controllerClass.metaClass.getMetaMethod("render", [Map] as Class[])
def originalRender = original.getClosure()
controllerClass.metaClass.originalRender = originalRender
controllerClass.metaClass.render = { Map atts ->
def templatePath = // some code to lookup against a TenantTenantMap
if(templatePath) {
if(atts.view) {
atts.view = "${templatePath}${atts?.view}"
}
if(atts.template) {
atts.template = "${templatePath}${atts?.template}"
}
}
delegate.originalRender(atts)
}
}
}
The only downside is that I have to use a slightly uglier directory structure than I wanted: views/controller/$template/action
instead of combining all the template gsps together under views/$template/controller/action
. I think I can live with that for now.
The solution I used:
def overrideRender = { application ->
for (controllerClass in application.controllerClasses) {
def original = controllerClass.metaClass.getMetaMethod("render", [Map] as Class[])
def originalRender = original.getClosure()
controllerClass.metaClass.originalRender = originalRender
controllerClass.metaClass.render = { Map atts ->
def templatePath = // some code to lookup against a TenantTenantMap
if(templatePath) {
if(atts.view) {
atts.view = "${templatePath}${atts?.view}"
}
if(atts.template) {
atts.template = "${templatePath}${atts?.template}"
}
}
delegate.originalRender(atts)
}
}
}
您可以尝试实现自己的Spring ViewResolver: http ://static.springsource.org/spring/docs/current/javadoc-api/org/springframework/web/servlet/ViewResolver.html
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.