Spring MVC @RequestMapping Inheritance - PullRequest
       1

Spring MVC @RequestMapping Inheritance

33 голосов
/ 11 марта 2011

Исходя из Struts2 Я привык объявлять аннотацию @Namespace для суперклассов (или package-info.java), и наследующие классы впоследствии выбирали значение в аннотации @Namespace своих предков и добавляли его к запросу.путь к действию.Сейчас я пытаюсь сделать что-то похожее в Spring MVC, используя аннотацию @RequestMapping следующим образом (код обрезан для краткости):

package au.test

@RequestMapping(value = "/")
public abstract class AbstractController {
    ...
}

au.test.user

@RequestMapping(value = "/user")
public abstract class AbstractUserController extends AbstractController {

    @RequestMapping(value = "/dashboard")   
    public String dashboard() {
        ....
    }
}

au.test.user.twitter

@RequestMapping(value = "/twitter")
public abstract class AbstractTwitterController extends AbstractUserController {
    ...
}

public abstract class TwitterController extends AbstractTwitterController {

    @RequestMapping(value = "/updateStatus")    
    public String updateStatus() {
        ....
    }
}
  • / работает как ожидалось
  • /user/dashboard работает как ожидалось
  • Однако, когда я ожидал, что /user/twitter/updateStatus не сработает, он не работает, и, проверяя журналы, я вижу запись в журнале, которая выглядит примерно так:

org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping - сопоставленный путь URL-адреса [/ tweeter / updateStatus] в обработчик 'twitterController'

Есть ли параметр, который можно включить, который будет сканироватьсуперклассы для @RequestMapping аннотаций и построения правильного пути?

Также я понимаю, что определение @RequestMapping для пакета в package-info.java является недопустимым?

Ответы [ 2 ]

27 голосов
/ 11 марта 2011

Следующее в основном становится /tweeter/updateStatus, а не /user/tweeter/updateStatus

public abstract class TwitterController extends AbstractTwitterController {

    @RequestMapping(value = "/updateStatus")    
    public String updateStatus() {
        ....
    }
}

Это ожидаемое поведение, поскольку вы переопределили исходный @RequestMapping, который вы объявили в AbstractController и AbstractUserController.

Фактически, когда вы объявили, что AbstractUserController, он также переопределяет @RequestMapping для AbstractController. Это просто дает вам иллюзию, что / из AbstractController было унаследовано.

"Можно ли включить параметр, который будет сканировать суперклассы на наличие @RequestMapping аннотаций и составить правильный путь?" Не то, что я знаю из.

5 голосов
/ 23 ноября 2016

В соответствии с методикой, описанной в Изменение @RequestMappings при запуске , да, можно создать шаблон URL из суперклассов так, как вы хотите.

По сути, вы должны создать подкласс RequestMappingHandlerMapping (скорее всего, это будет ваша реализация HandlerMapping , но сначала проверьте ее) и переопределить защищенный метод getMappingForMethod. Как только это станет возможным, вы полностью контролируете генерацию шаблона URL.

Из приведенного вами примера не совсем ясно, какая именно политика слияния, например, какой путь вы хотите использовать, если суперкласс AbstractTwitterController также реализует метод updateStatus() со своим собственным @RequestMapping, или как вы хотите объединить шаблоны URL по иерархии сверху вниз или снизу вверх (я предположил первый ниже), но, надеюсь, следующий фрагмент даст вам некоторые идеи:

    private static class PathTweakingRequestMappingHandlerMapping extends RequestMappingHandlerMapping {

                @Override
                protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
                    RequestMappingInfo methodMapping = super.getMappingForMethod(method, handlerType);
                    if (methodMapping == null)
                        return null;
                    List<String> superclassUrlPatterns = new ArrayList<String>();
                    boolean springPath = false;
                    for (Class<?> clazz = handlerType; clazz != Object.class; clazz = clazz.getSuperclass())
                        if (clazz.isAnnotationPresent(RequestMapping.class))
                            if (springPath)
                                superclassUrlPatterns.add(clazz.getAnnotation(RequestMapping.class).value()[0]);// TODO handle other elements in the array if necessary
                            else
                                springPath = true;
                    if (!superclassUrlPatterns.isEmpty()) {
                        RequestMappingInfo superclassRequestMappingInfo = new RequestMappingInfo("",
                                new PatternsRequestCondition(String.join("", superclassUrlPatterns)), null, null, null, null, null, null);// TODO implement specific method, consumes, produces, etc depending on your merging policies
                        return superclassRequestMappingInfo.combine(methodMapping);
                    } else
                        return methodMapping;
                }
    }

Еще один хороший вопрос - как перехватить создание экземпляра RequestMappingHandlerMapping. В Интернете существует множество различных примеров различных стратегий конфигурации. Однако с JavaConfig помните, что если вы укажете WebMvcConfigurationSupport в вашем наборе @Configuration, тогда ваш @EnableWebMvc (явный или неявный) перестанет работать. Я закончил со следующим:

@Configuration
public class WebConfig extends DelegatingWebMvcConfiguration{

    @Configuration
    public static class UnconditionalWebMvcAutoConfiguration extends WebMvcAutoConfiguration {//forces @EnableWebMvc 
    }

    @Override
    protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
        return new PathTweakingRequestMappingHandlerMapping();
    }

    @Bean
    @Primary
    @Override
    public RequestMappingHandlerMapping requestMappingHandlerMapping() { 
        return super.requestMappingHandlerMapping();
    }

}

но хотел бы узнать о лучших путях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...