#grails #filter
#grails #Фильтр
Вопрос:
У меня есть фильтр и controllerName
var, получающий цель контроллера.
Например: когда пользователь пытается получить доступ /myApp/book/index
, срабатывает мой фильтр и controllerName
равно book
. Как я могу получить экземпляр BookController?
Tks
Редактировать:
Я могу получить Artefact
с помощью:
grailsApplication.getArtefactByLogicalPropertyName("Controller", "book")
Но что я делаю с этим артефактом?
Комментарии:
1. Зачем вам нужен экземпляр контроллера? Звучит как недостаток дизайна.
2. Мне нужно вызвать действие из моего фильтра, а затем перенаправить во внешнее приложение (подготавливая мое приложение к приему будущих запросов). Другими словами, мне нужно обновить мою модель перед перенаправлением.
Ответ №1:
Контроллер будет зарегистрирован как компонент spring. Просто возьмите его по имени:
applicationContext.getBean('mypackage.BookController') // or
def artefact = grailsApplication.getArtefactByLogicalPropertyName("Controller", "book")
applicationContext.getBean(artefact.clazz.name)
Ответ №2:
Как сказал Берт, вы, вероятно, не хотите, чтобы один экземпляр контроллера находился внутри вашего фильтра. Это неправильный способ решения вашей проблемы.
Контроллеры Grails автоматически вводятся Spring Framework, и при их создании используется некоторая черная магия и процедуры. Итак, я могу заверить вас, что это не способ решить эту проблему.
Как вы сами описали, вы хотите вызвать свое действие, и я могу представить, что вы пытаетесь повторно использовать некоторый код, который находится в вашем действии, возможно, для генерации некоторых данных в вашей базе данных или даже для работы с вашим HTTP-сеансом, я прав?
Итак, вы можете сделать две вещи, чтобы решить проблему такого рода.
1) Просто перенаправьте поток запросов на свой контроллер / действие следующим образом:
if (something) {
redirect controller: 'xpto', action: 'desired'
return false
}
2) Или вы можете получить логику внутри своего действия (которое выполняет ту грязную работу, которую вы хотите запустить), разделить эту логику внутри одного сервиса и повторно использовать сервис в обоих классах (действие / сервис) таким образом:
MyService.groovy
class MyService {
def methodToReuse() {
(...)
}
}
MyController.groovy
class MyController {
def myService //auto-injected by the green elf
def myAction = {
myService.methodToReuse()
}
}
MyFilters.groovy
class MyFilters {
def myService //auto-injected by the red elf
(...)
myService.methodToReuse()
(...)
}
[]s,
Комментарии:
1. @lucastex, спасибо за объяснение. Я работаю над проектом вне времени, поэтому мне нужен самый быстрый способ для этого — вы знаете, о чем я говорю :). Но в следующем выпуске я последую вашему совету и использую сервис для повторного использования кода.
2. Что было бы быстрее, чем скопировать код действия в новый файл и использовать этот файл в обеих точках? Если вы «создадите экземпляр» нового контроллера, у вас могут возникнуть некоторые другие странные проблемы, поскольку все это управляется фреймворком.
Ответ №3:
Вы должны иметь возможность вызывать newInstance
полученный вами артефакт. newInstance
работает точно так же, как конструктор, поэтому вы можете предоставить любые параметры для обычного вызова конструктора.
Таким образом, вы, вероятно, можете просто сделать:
def bookController = grailsApplication.getArtefactByLogicalPropertyName("Controller", "book").newInstance()
Ответ №4:
Рабочий код:
import org.codehaus.groovy.grails.web.context.ServletContextHolder
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes
import org.springframework.context.ApplicationContext
ApplicationContext applicationContext = (ApplicationContext) ServletContextHolder.getServletContext().getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT)
def grailsApplication
String nameController = "search"
def artefact = grailsApplication.getArtefactByLogicalPropertyName("Controller", nameController)
def controller = applicationContext.getBean(artefact.clazz.name)