Как определить конвертер сообщений на основе расширения URL в Spring MVC? - PullRequest
2 голосов
/ 08 сентября 2010

Как я могу повлиять на процесс выбора конвертера сообщений в AnnotationMethodHandlerAdapter для полученного POJO по расширению URL?Я хотел бы иметь больше представлений одного объекта данных, в то время как представление данных должно быть выбрано запрошенным расширением URL, например /users/2.xml или /users/2.json.

Текущая конфигурация обработчиков сообщений, которая должна выбираться на основерасширение URL:

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
            <bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter"
                p:marshaller-ref="xmlMarshaller" p:unmarshaller-ref="xmlMarshaller" />
        </list>
    </property>
</bean>

Есть один способ, который мне почти удобен и который использует ContentNegotiatingViewResolver , однако я бы хотел обойти процесс разрешения представления и напрямую использоватьконвертеры сообщений.Также при создании действий использование ResponseEntity в public ResponseEntity<User> showUser() обеспечивает детальный контроль над получающимися определениями кодов состояния http (OK, NOT_FOUND, NO_CONTENT, ..).Я не смог найти способ использования ResponseEntity с ContentNegotiatingViewResolver, который также удовлетворил бы мои потребности.

Другим способом могло бы быть изменение заголовка запроса accept на application/xml или application/json на основе URLрасширение.Таким образом, вся обработка должна идти непосредственно к сконфигурированному конвертеру сообщений.Однако я не знаю разумного способа подделать заголовки запроса.

Спасибо.

Ответы [ 2 ]

3 голосов
/ 08 сентября 2010

Поскольку при выборе HttpMessageConverter s используется заголовок запроса Accept, возможно, самый простой способ реализовать согласование содержимого - это заменить этот заголовок требуемым типом носителя, указанным расширением URL.

Это может быть реализовано либо как Filter (с использованием HttpServletRequestWrapper для замены значения заголовка), либо путем переопределения AnnotationMethodHanlderAdapter.createHttpInputMessage(), как предлагается в SPR-7517 (требуется Spring 3.0.2).

См. Также SPR-6993 .

2 голосов
/ 05 апреля 2012

У меня была такая же потребность, и я взломал фильтр сервлетов для выполнения задачи.Не произведение искусства, но выполняет свою работу:

public class UrlExtensionFilter implements Filter {

public void init(FilterConfig filterConfig) throws ServletException {
}

public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
    HttpServletRequest httpServletRequest = (HttpServletRequest)request;
    if (httpServletRequest.getRequestURI().endsWith(".json")) {
        MyAcceptHeaderRequest acceptHeaderRequest = new MyAcceptHeaderRequest(httpServletRequest);
        acceptHeaderRequest.setAcceptHeader("application/json");
        filterChain.doFilter(acceptHeaderRequest, response);
    } else if (httpServletRequest.getRequestURI().endsWith(".xml")) {
        MyAcceptHeaderRequest acceptHeaderRequest = new MyAcceptHeaderRequest(httpServletRequest);
        acceptHeaderRequest.setAcceptHeader("text/xml");
        filterChain.doFilter(acceptHeaderRequest, response);
    } else {
        filterChain.doFilter(request, response);
    }
}

public void destroy() {
}

public class MyAcceptHeaderRequest extends HttpServletRequestWrapper {

    private String accept = "application/json";

    public MyAcceptHeaderRequest(HttpServletRequest request) throws IOException {
        super(request);
    }

    public void setAcceptHeader(String value) {
        accept = value;
    }

    @Override
    public String getHeader(String name) {
        if (name.equalsIgnoreCase("accept") || name.equalsIgnoreCase("content-type")) {
            return accept;
        } else {
            return super.getHeader(name);
        }
    }

    @Override
    public Enumeration getHeaders(String name) {
        if (name.equalsIgnoreCase("accept") || name.equalsIgnoreCase("content-type")) {
            Enumeration enumeration = new StringTokenizer(accept);
            return enumeration;
        } else {
            return super.getHeaders(name);
        }
    }

    @Override
    public String getContentType() {
        return accept;
    }

    @Override
    public String getParameter(String name) {
        // When we're using this class and it is a POST operation then the body is JSON or XML so don't allow
        // attempts to retrieve parameter names to consume the input stream
        if (this.getMethod().equals("POST")) {
            return null;
        } else {
            return super.getParameter(name);
        }
    }

    @Override
    public String[] getParameterValues(String name) {
        // When we're using this class and it is a POST operation then the body is JSON or XML so don't allow
        // attempts to retrieve parameter names to consume the input stream
        if (this.getMethod().equals("POST")) {
            return null;
        } else {
            return super.getParameterValues(name);
        }
    }
}
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...