2015-03-25 1 views
2

У меня есть множество Spring RestControllers с методами, аннотированными RequestMapping. Теперь я хотел бы добавить пользовательский объект в эти методы RequestMapping и создать собственный экземпляр для каждого запроса.Внесите новый экземпляр объекта в каждый обработчик запроса

Я хотел бы написать что-то вроде следующего:

@RequestMapping("/search") 
public SomeReturnObject foobar(@RequestParam("query") String query, MyRequestFoo foo) { 
    // ... 
} 

Теперь я хотел бы создать механизм, где каждый вызов этого метода (т.е. каждый запрос) получить новый экземпляр MyRequestFoo создан и введен в метод. Если бы это улучшилось с помощью аннотации параметра вместо инъекции по типу, это также было бы хорошо (например, @MyRequestInject MyRequestFoo foo).

мне нужно знать, если я могу создать теперь метод, который создает новый экземпляр MyRequestFoo специально для этой просьбы, как следующее:

public MyRequestFoo createRequestInstanceSomehow(HttpServletRequest request) { 
    // extract some values from the HttpServletRequest and create a 
    // new MyRequestFoo instance from that and return it 
} 

Возможно ли это каким-либо образом, чтобы создать такой механизм, так что я могу добавлять пользовательские объекты запроса в мои методы обработки запросов?

ответ

3

Spring MVC имеет конструкцию резольвера аргументов, которая напрямую поддерживает ваш запрос. Каждый метод обработчика, аннотированный с помощью @RequestMapping, будет подвержен разрешению аргументов, где инфраструктура сканирует аргументы обработчика, проверяет тип и создает экземпляр соответствующего объекта. Это механизм для ввода запроса, модели и ряда других типов, просто объявляя объект в сигнатуре метода обработчика.

Вы можете написать собственный преобразователь аргументов, чтобы разрешить и использовать специальные методы в методе. Процедура проста три шага процесс

  1. сделать класс POJO, в вашем случае MyRequestFoo

  2. Сделать распознаватель, например,

    public class MyRequestFooResolver implements HandlerMethodArgumentResolver { 
    
         @Override 
         public boolean supportsParameter(MethodParameter parameter) { 
    
          return parameter.getParameterType().equals(MyRequestFoo.class); 
         } 
    
         @Override 
         public Object resolveArgument(MethodParameter parameter, 
                 ModelAndViewContainer mavContainer, 
                 NativeWebRequest webRequest, 
                 WebDataBinderFactory binderFactory) 
         throws Exception { 
    
          return new MyRequestFoo(); 
         } 
        } 
    

3.Register распознаватель

<mvc:annotation-driven> 
    <mvc:argument-resolvers> 
     <bean class="your.package.MyRequestFooResolver "></bean> 
    </mvc:argument-resolvers> 
</mvc:annotation-driven> 

или Java конфигурации

@Configuration 
@EnableWebMvc 
public class WebConfig extends WebMvcConfigurerAdapter { 

    @Override 
    public void addArgumentResolvers(List<Handlermethodargumentresolver> argumentResolvers) { 
     MyRequestFooResolver myRequestFooResolver = new MyRequestFooResolver(); 
     argumentResolvers.add(myRequestFooResolver); 
    } 
} 

Чем вы используете его, добавив тип в качестве метода обработчика аргумента

@RequestMapping("/search") 
public SomeReturnObject search(MyRequestFoo foo) { 
    // ... 
} 
+0

Я также написал ответ, который работает. Могли бы вы, возможно, разработать более чистый и «лучший» подход с точки зрения (или источников)? –

+1

Я видел дискуссию и отправил ответ в любом случае в качестве альтернативы, потому что разрешение пользовательских аргументов - это концепция, непосредственно поддерживающая ваше требование. Я бы отказался от обсуждения того, что лучше, но это тот подход, который я бы использовал. –

1

Как насчет того, чтобы ввести переменную экземпляра типа MyRequestFoo в классе Controller и Autowire, изменив область по умолчанию от «Singleton» до «Request» в определении Bean?

Отъезд this ссылка или лист весны!

+0

Но для этого требуется, чтобы весь контроллер был создан новым для каждого запроса? Создание контроллеров, новых для каждого запроса, не похоже на то, что должно быть сделано весной. Также мне нужно будет получить доступ к HttpServletRequest при создании экземпляра Autowired, как бы я это сделал? –

+0

Я считаю, что он предлагает изменить область * зависимости, а не на контроллер. – chrylis

+0

@chrylis, к сожалению, вы не можете автоувеличивать компоненты областей запросов в переменную экземпляра внутри beans-объекта без запроса (в данном случае контроллер). –

0

Я нашел решение, которое делает то, что я пытался сделать.

Просто создайте MyRequestFoo как боб с объемом «запросом» и вы можете получить доступ к текущему запросу через RequestContextHolder:

@Component 
@Scope("request") 
public class MyRequestFoo { 
    private final HttpServletRequest request; 

    public MyRequestFoo() { 
     request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); 
    } 

    // do whatever you want with the request 

} 

И теперь я могу просто придать новый экземпляр этого его типа в любой запрос обработчик метод:

@RequestMapping("/search") 
public SomeReturnObject search(MyRequestFoo foo) { 
    // ... 
} 

И Spring автоматически позаботится о создании экземпляра нового экземпляра.

Это не работает для autowire MyRequestFoo как переменная экземпляра, так как вы не можете авторизовать обработанные объекты в фасонные объекты без запроса.

+1

Магическая зависимость, захватывающая таким образом статические методы, является хрупкой моделью. В частности, это очень сложно проверить. – chrylis

0

Поскольку вам необходимо передать информацию о конкретном запросе вашему компоненту, я рекомендую вместо этого вставить компонент-компоновщик в ваш контроллер и вызвать builder.build(request) из вашего метода, чтобы создать новый экземпляр для каждого запроса.

+1

Я хотел избежать необходимости вводить HttpServletRequest в каждый обработчик запроса, чтобы затем написать одну и ту же строку строителя в каждый метод обработки запроса, так как мне это нужно для всех обработчиков. Хотя это будет работать, конечно. –

Смежные вопросы