【问题标题】:Spring invokes wrong controller mappingSpring调用错误的控制器映射
【发布时间】:2012-08-08 09:33:01
【问题描述】:

我正在使用 Spring 构建非常基本的 mvc 应用程序。它有一个控制器,应该在请求正文上调用验证。问题是,如果我在 web.xml 中定义映射,它会停止寻找正确的控制器,但是当我修改 servlet 应用程序上下文时,Spring 星会即时进行一些新的绑定,但是这次基于注释的验证被忽略了。如何在调用基于注释的验证的同时控制 web.xml 中的映射?

以下是详细信息:

控制器:

@Controller
@RequestMapping("/api")
public class UserActionsController {

    @RequestMapping(value="/choice", method = RequestMethod.POST)
    public @ResponseBody NameValue addUserChoice(@Valid @RequestBody NameValue action)
    {       
        return action;
    }
}

这是 servlet 应用程序上下文:

<mvc:annotation-driven/>

<context:component-scan base-package="com.my.package" />

<bean
    class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="mediaTypes">
        <map>
            <entry key="json" value="application/json" />
        </map>
    </property>
    <property name="defaultContentType" value="application/json" />
    <property name="defaultViews">
        <list>
            <bean
                class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
        </list>
    </property>
</bean>

网页 xml:

<servlet>
    <servlet-name>action-api</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>action-api</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

上面的配置正在运行。当我尝试更改 web.xml 时问题就开始了,因此控制器将只负责“/api/*”。我将其更改为&lt;url-pattern&gt;/api/*&lt;/url-pattern&gt;。在这种情况下,Spring 找不到合适的控制器。

(DispatcherServlet:819) - DispatcherServlet with name 'action-api' processing POST request for [/api/choice]
(RequestMappingHandlerMapping:209) - Looking up handler method for path /choice
(RequestMappingHandlerMapping:219) - Did not find handler method for [/choice]
(PageNotFound:1080) - No mapping found for HTTP request with URI [/api/choice] in DispatcherServlet with name 'action-api'
(DispatcherServlet:913) - Successfully completed request

修改 servlet 应用程序上下文会有所帮助,Spring 现在能够找到控制器,但不再调用验证。

<bean
    class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="alwaysUseFullPath" value="true" />
    <property name="messageConverters">
        <util:list id="beanList">
            <bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
            <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
        </util:list>
    </property>
</bean>

<bean
    class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    <property name="alwaysUseFullPath" value="true" />
</bean>

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="alwaysUseFullPath" value="true" />
</bean>

这是日志:

(DispatcherServlet:819) - DispatcherServlet with name 'action-api' processing POST request for [/api/choice]
(RequestMappingHandlerMapping:209) - Looking up handler method for path /choice
(RequestMappingHandlerMapping:219) - Did not find handler method for [/choice]
(DefaultAnnotationHandlerMapping:124) - Mapping [/api/choice] to HandlerExecutionChain with handler [com.my.package.controller.UserActionsController@1f86dbd] and 1 interceptor
(HandlerMethodInvoker:638) - Reading [com.my.package.model.NameValue] as "application/json" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter@2059ef]
(HandlerMethodInvoker:173) - Invoking request handler method: public com.my.package.model.NameValue com.citypath.dima.controller.UserActionsController.addUserChoice(com.my.package.model.NameValue)
(AnnotationMethodHandlerAdapter:1037) - Written [com.my.package.model.NameValue@166685b] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter@2059ef]
(DispatcherServlet:957) - Null ModelAndView returned to DispatcherServlet with name 'action-api': assuming HandlerAdapter completed request handling
(DispatcherServlet:913) - Successfully completed request

看起来 Spring 进行了一些即时绑定,但这次验证器被忽略了。 我需要有 2 个控制器,比如“/api”和“/something”。如何在 web.xml 中定义它,以便 Spring 能够找到它们并调用验证?

谢谢。

【问题讨论】:

    标签: java validation tomcat spring-mvc


    【解决方案1】:

    Spring @Controllers URL 总是相对于处理它们的 Spring Dispatcher Servlet 进行解释。因此,如果您将调度程序 servlet 映射到 web.xml 中的 /api/*,那么上面控制器的 URL 是 /api/api/choice

    所以你可以在 web.xml 中配置两个 spring dispatcher servelts,一个映射到 web.xml 中的 /api,一个映射到 web.xml 中的 /somethingelse 然后你可以从 @RequestMappings 中删除 /api

    在我的应用程序中,我为 api 和 UI 使用单个 Dispatcher Servlet,并在我的各种 API 控制器中使用称为 URL 的公共静态最终字符串来构建 API 公开的各种资源的路径。下面是我的 API 中的一个示例。

    @Controller
    @RequestMapping(CompanyPermissionsResourceController.PATH)
    public class CompanyPermissionsResourceController extends BaseApiController
    {
        public static final String PATH = CompanyResourceController.PATH + "/permissions"; 
    

    【讨论】:

    • 谢谢。 /api/api/choice 实际上帮助我理解了为什么 Spring 找不到控制器。如果我没有在控制器中定义“api”部分,那么在 web.xml 中一切都很好。甚至在控制器和方法级别进行映射。就像它假设的那样工作。
    • 这个答案帮助我找到了我的问题的根本原因,即我的@ComponentScan 没有包含我的控制器的包
    【解决方案2】:

    您确定要向/api/choice 发出post 请求吗?

    @RequestMapping(value="/choice", method = RequestMethod.POST)
    

    尝试更改为

    @RequestMapping(value="/choice", method = RequestMethod.GET)
    public @ResponseBody NameValue addUserChoice(@Valid @RequestBody NameValue action)
    {       
        return action;
    }
    

    【讨论】:

    • 正如我所提到的,第一个配置有效。所以客户端没有问题。 (我正在使用 Fiddler,这完全没问题)
    【解决方案3】:

    我不认为它是这样工作的。将所有路径/api/choice放在方法级别。

    【讨论】:

    • 你能解释一下为什么它不应该工作吗?支持控制器级别的@RequestMapping。当 web.xml 没有指定除 /* 之外的任何路径时,它工作正常
    • 我认为 Spring 只是不添加从类级别的 RequestMapping 到方法级别的 RequestMapping 的路径。当然,我可能是错的。我从未尝试过这种方法。您需要在方法级别定义 RequestMapping 以使其正常工作,这是肯定的。如果您在类级别使用路径对 RequestMapping 进行了参数化,则不必使用路径对其进行参数化。问题是:你需要这种方法吗?
    猜你喜欢
    • 2018-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-16
    • 2012-05-12
    • 1970-01-01
    相关资源
    最近更新 更多