У меня такая же проблема, как и у вас. У меня пока нет чистого решения, но я верю, что добился определенного прогресса, поэтому решил поделиться с вами тем, что нашел до сих пор.
Я исследовал использование перехватчиков в соответствии с предложением 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 (также не очень хорошо и не гибко).
Использование пользовательского аннотацииMethodHandlerAdapter
В настоящее время я смотрю на указание DefaultAnnotationHandlerMapping
непосредственно в моем xml (вместо mvc:annotation-driven
) и затем на предоставление ему пользовательского AnnotationMethodHandlerAdapter
.
Как я уже говорил ранее, я не достиг достаточного прогресса, чтобы представить полные результаты, однако направление, к которому я стремлюсь, таково:
Я думаю о AnnotationMethodHandlerAdapter как о поставляемом Spring MultiActionController, но для контроллеров pojo. Например, я уже знаю, как подключить к нему собственный распознаватель методов (см. Этот вопрос ) и другие полезности 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>
- Как уже упоминалось в комментарии, я развернулстенография.Мне пришлось явно определить два сопоставления обработчиков, а также определить два адаптера обработчиков.
- К сожалению, в моем унаследованном коде некоторые контроллеры являются транснациональными и передаются через cglib.
AnnotationMethodHandlerAdapter
плохо справляется с этим, поэтому я установил порядок элементов таким образом, чтобы устаревшие адаптеры отображения обработчиков и обработчиков действовали первыми, а адаптер сопоставления обработчиков на основе аннотаций - вторыми. - Я должен был явно определить Spring 10 *, но мне также пришлось расширить его своим собственным классом, потому что он не реализует интерфейс
Ordered
. - У меня была проблемаопределение валидатора, потому что у меня не было банки для 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;
}
}