Ответ 1
У меня та же проблема, что и вы. У меня пока нет чистого решения, но я считаю, что сделал некоторый прогресс, поэтому я решил поделиться с вами тем, что нашел до сих пор.
Я изучил использование перехватчиков, как это было предложено three_cups_of_java, но я столкнулся с различными проблемами (описанными ниже). В настоящее время я пытаюсь использовать пользовательский AnnotationMethodHandlerAdapter, но я еще не сделан с этими усилиями.
перехватчики
Так как перехватчики не имеют доступа к объекту контроллера, который они перехватывают ( коррекция:, у них есть к нему доступ, но с ограниченным контролем над потоком выполнения), контроллер и перехватчик должны общаться через объекты в сеансе.
Вот несколько упрощенный пример того, что я имею в виду:
В нашей старой архитектуре у нас есть собственный базовый контроллер, который все расширяют. Он сам расширяет MultiActionController и добавляет некоторое пользовательское поведение - например, в вашем примере, обновляя представление на стороне сервера после запроса на публикацию перед вызовом метода обработчика. Это работает, потому что все контроллеры обеспечивают реализацию метода шаблона (например, getViewKeyInSession()
).
Таким образом, пользовательский код в базовом контроллере выглядит примерно так:
// inside handleRequestInternal method
if (request.getMethod().equals("POST") {
updateViewAfterPost (session.get(getViewKeyInSession());
}
return super.handleRequestInternal();
Теперь, когда мы переместили этот код на перехватчик, мы сталкиваемся с несколькими проблемами:
- Перехватчик не может вызывать getViewKeyInSession(), заставляя нас использовать один и тот же ключ сеанса для всех контроллеров (не очень хорошо) или придерживаться какого-либо соглашения о том, что ключ сеанса для представления основан на URL-адресе или параметре запрос (пока это тоже не хорошо).
- Индивидуальные контроллеры больше не могут переопределять поведение
updateModelAfterPost
. Обычно это не нужно, но, к сожалению, это было необходимо для некоторых контроллеров. - Если контроллер предоставляет реализацию updateModelAfterPost и хочет сигнализировать перехватчику, что он не заинтересован в помощи перехватчика, это необходимо сделать, помещая объект-маркер в сеанс для просмотра перехватчика, и это необходимо сделать это во время предыдущего запроса GET (также не хорошо и не гибко).
Использование пользовательского параметра AnnotationMethodHandlerAdapter
В настоящее время я просматриваю указание DefaultAnnotationHandlerMapping
непосредственно в моем xml (вместо mvc:annotation-driven
), а затем поставляя ему пользовательский AnnotationMethodHandlerAdapter
.
Как я сказал ранее, я не добился достаточного прогресса, чтобы представить полные результаты, однако направление, на которое я нацеливаюсь, таково:
Я думаю об AnnotationMethodHandlerAdapter как Spring -supplied MultiActionController, но для контроллеров pojo. Например, я уже знаю, как подключить к нему свой собственный метод resolver (см. Этот question) и другие Spring лакомства.
Этот адаптер имеет несколько методов, которые вы можете переопределить, например,
invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
,
и возможно
handle(HttpServletRequest request, HttpServletResponse response, Object handler)
также.
В вашем пользовательском коде вы можете проверить класс обработчика, а затем действовать соответствующим образом. Чтобы продолжить мой предыдущий пример, если класс обработчика имеет метод updateViewAfterPost
или если он реализует определенный интерфейс, вы можете вызвать этот метод, а затем вызвать super
, чтобы Spring продолжить регулярный вызов. Таким образом, код выглядит примерно так:
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// inspect handler object, look for marker interface, methods and/or annotations
// perform pre-processing on the handler object
// e.g. handler.updateViewAfterPost(request, response)
ModelAndView mav = super.handle (request, response, handler);
// post-processing on the handler object
return mav;
}
(Разумеется, это просто пример игрушек. В реальном коде вам понадобится более эффективная обработка исключений)
UPDATE:
Я пробовал вышеупомянутую стратегию с помощью AnnotationMethodHandlerAdapter
, и это действительно работает. Я использовал интерфейс маркера на моем контроллере pojo и ввел жизненный цикл только один новый метод с именем updateModelAfterPost
, и он работает так, как ожидалось.
Есть несколько небольших оговорок, с которыми я столкнулся, главным образом потому, что я сочетал старые способы с новыми способами в одном и том же контексте mvc. Ниже вы можете увидеть изменения, которые я внес в контекст xml, а затем список проблем, которые, как мне кажется, стоит выделить.
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="order" value="2" />
</bean>
<bean class="com.sample.MyAnnotationMethodHandlerAdapter">
<property name="order" value="2" />
</bean>
<bean class="com.sample.MySimpleControllerHandlerAdapter" >
<property name="order" value="1" />
</bean>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="order" value="1" />
<property name="mappings">
<props>
...
</props>
</property>
</bean>
- Как упоминалось в комментарии, я развернул < mvc: annotation-driven > стенография. Я должен был явно определить два отображения обработчика, а также определить два адаптера обработчика.
- К сожалению, в моем устаревшем коде некоторые контроллеры являются трансациональными и проксируются cglib.
AnnotationMethodHandlerAdapter
не очень хорошо справляется с этим, поэтому я устанавливаю порядок элементов таким образом, чтобы сначала выполнялось сопоставление обработчика обработчика и адаптер обработчика, а привязка обработчика на основе аннотаций и адаптер обработчика выполнялись вторым. - Мне пришлось явно определить Spring
SimpleControllerHandlerAdapter
, но мне также пришлось расширять его с помощью моего собственного класса, потому что он не реализует интерфейсOrdered
. - У меня возникла проблема с определением валидатора, потому что у меня не было jar для jsr-303. Поэтому я отказался от объявления валидаторов и службы преобразования. Вышеупомянутый фрагмент xml - это именно то, что я использую, это упрощенная версия, упрощенная для ответа.
и, наконец, вот код для соответствующих классов:
package com.sample;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
public class MyAnnotationMethodHandlerAdapter extends AnnotationMethodHandlerAdapter {
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof MyMarkerInterface) {
MyMarkerInterface handler2 = (MyMarkerInterface) handler;
handler2.updateModelAfterPost(request);
}
return super.invokeHandlerMethod(request, response, handler);
}
}
package com.sample;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;
public class MySimpleControllerHandlerAdapter extends SimpleControllerHandlerAdapter implements Ordered {
private int order = 0;
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
}