来自Spring 4 REST端点的404

时间:2015-11-27 17:01:54

标签: spring rest spring-mvc

我有一个带有REST端点的Spring 4后端可以从我的AngularJS前端命中。问题是每当我从前端点击这些端点时,请求返回404。

当我启动Tomcat时,我查看了应用程序的日志文件,REST的url映射正由Spring正确映射到处理程序。这是显示我试图点击的网址的确切线。

2015-11-27 09:16:50,885 RMI TCP Connection(4)-127.0.0.1 INFO  annotation.RequestMappingHandlerMapping Mapped
"{[/rest/userAccount/createAccount],methods=[POST]}" onto public

我尝试使用REST测试应用程序点击端点并返回相同的内容。所以我的Angular前端并没有出错。作为参考,我试图击中的确切终点是 /gravytrack/rest/userAccount/createAccount

这是我的Spring配置文件:

的web.xml

<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
         http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <!-- Log4j configuration loading -->
    <listener>
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    </listener>
    <context-param>
        <param-name>log4jConfigLocation</param-name>
        <param-value>/WEB-INF/classes/log4j.xml</param-value>
    </context-param>
    <!-- Bootstrapping context loading -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/gravytrack-servlet.xml
            /WEB-INF/gravytrack-services.xml
            <!--/WEB-INF/gravytrack-security.xml-->
           </param-value>
    </context-param>
    <context-param>
        <param-name>webAppRootKey</param-name>
        <param-value>gravytrack.root</param-value>
    </context-param>

    <!-- session management listener -->
    <!--<listener>-->
        <!--<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>-->
    <!--</listener>-->
    <session-config>
        <!-- session times out if no activities for 30 minutes -->
        <session-timeout>30</session-timeout>
    </session-config>


    <!-- defining the DispatcherServlet -->
    <servlet>
        <servlet-name>gravytrack</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>gravytrack</servlet-name>
        <url-pattern>/rest/**</url-pattern>
    </servlet-mapping>
    <error-page>
        <error-code>404</error-code>
        <location>/404.html</location>
    </error-page>
    <welcome-file-list>
        <welcome-file>
      /index.html
    </welcome-file>
    </welcome-file-list>
</web-app>

gravytrack-servlet.xml中

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- the application context definition for the GravyTrack DispatcherServlet -->
    <context:component-scan base-package="com.gbsolutions.gravytrack.web" />
    <context:component-scan base-package="com.gbsolutions.gravytrack.service" />
    <context:component-scan base-package="com.gbsolutions.gravytrack.model" />
    <!--<context:component-scan base-package="com.gbsolutions.gravytrack.security" />-->
    <context:annotation-config />
    <mvc:annotation-driven />

    <!--<mvc:view-controller path="/dashboard" view-name="dashboard"/>-->
    <!--<mvc:view-controller path="/login" view-name="login"/>-->

    <mvc:resources mapping="/webjars/**" location="classpath:/webjars/"/>

    <bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basenames">
            <list>
                <value>classpath:/messages/messages</value>
                <value>classpath:/messages/errors</value>
                <value>classpath:/jdbc.properties</value>
                <value>classpath:/gravytrack.properties</value>
            </list>
        </property>
        <property name="cacheSeconds" value="1"/>
    </bean>

    <!--<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">-->
        <!--<property name="order" value="0" />-->
        <!--<property name="viewClass"-->
            <!--value="org.springframework.web.servlet.view.JstlView" />-->
        <!--<property name="prefix" value="/WEB-INF/jsp/" />-->
        <!--<property name="suffix" value=".jsp" />-->
    <!--</bean>-->
    <bean
        class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="order" value="1" />
        <property name="contentNegotiationManager">
            <bean class="org.springframework.web.accept.ContentNegotiationManager">
                <constructor-arg>
                    <list>
                        <bean
                            class="org.springframework.web.accept.PathExtensionContentNegotiationStrategy">
                            <constructor-arg>
                                <map>
                                    <entry key="json" value="application/json" />
                                    <entry key="xml" value="application/xml" />
                                    <entry key="html" value="text/html" />
                                </map>
                            </constructor-arg>
                        </bean>
                        <bean
                            class="org.springframework.web.accept.HeaderContentNegotiationStrategy" />
                    </list>
                </constructor-arg>
            </bean>
        </property>
        <property name="defaultViews">
            <list>
                <!-- JSON View -->
                <bean
                    class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />

                <!-- XML View -->
                <bean class="org.springframework.web.servlet.view.xml.MarshallingView">
                    <constructor-arg>
                        <bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
                            <property name="packagesToScan">
                                <list>
                                    <value>com.gbsolutions.gravytrack.model.domain</value>
                                </list>
                            </property>
                        </bean>
                    </constructor-arg>
                </bean>

            </list>
        </property>
    </bean>

</beans>

UserAccountController

package com.gbsolutions.gravytrack.web;

import com.gbsolutions.gravytrack.model.domain.UserAccount;
import com.gbsolutions.gravytrack.service.manager.UserAccountManager;
import com.gbsolutions.gravytrack.service.validator.CreateUserAccountValidator;
import com.gbsolutions.gravytrack.web.dto.GenericJsonDTO;
import com.gbsolutions.gravytrack.web.dto.JsonFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;
import java.util.ArrayList;

@Controller
@RequestMapping("/rest/userAccount")
@SessionAttributes("userAccount")
public class UserAccountController {

    @RequestMapping(value="/createAccount", method = RequestMethod.POST)//, consumes = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public GenericJsonDTO createAccount(@RequestBody UserAccount userAccount, BindingResult result, SessionStatus status){
        JsonFactory jsonFactory = new JsonFactory(result, "/gravytrack/dashboard");
        validator.validate(userAccount, result);

        if(!result.hasErrors()) {
            userAccountManager.createUserAccount(userAccount);
            status.setComplete();
        }
        return jsonFactory.getDto();
    }

    @RequestMapping(value="/signIn", method = RequestMethod.POST)//, consumes = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public GenericJsonDTO signIn(@RequestBody UserAccount userAccount, BindingResult result, SessionStatus status){
        System.out.println("signIn entered!");
        JsonFactory jsonFactory = new JsonFactory(result, "/gravytrack/dashboard");
        validator.validate(userAccount, result);

        if(!result.hasErrors()) {
            userAccountManager.createUserAccount(userAccount);
            status.setComplete();
        }
        return jsonFactory.getDto();
    }
}

这是我使用JSP转换为Angular的应用程序。所以我不得不修改配置文件,因为它不再需要很多配置了。

正如您在 web.xml gravytrack-servlet.xml 中所看到的,我已经注释掉了一些我认为不再需要的行。我完全注释掉了对Spring Security的任何引用,因为一旦我开始工作,我就必须设置它。

我尝试过很多不同的方式来改变我的配置,但似乎没有任何工作。什么可能导致这里的问题?

1 个答案:

答案 0 :(得分:1)

<servlet-mapping>
    <servlet-name>gravytrack</servlet-name>
    <url-pattern>/rest/**</url-pattern>
</servlet-mapping>

servlet映射错误,应该是/ rest / *而不是两个星号。 (我想/ gravytrack是应用程序的上下文路径)

另一件事是重复的rest网址前缀 - DispatcherServlet已映射到/rest,这是弹簧容器的根网址。控制器是一个子资源,并再次映射到/rest/.. - 因此生成的网址为/rest/rest/...

所以你需要从REST服务的RequestMapping中删除/rest前缀 - 这里是UserAccountController上的类级别注释,它必须看起来像@RequestMapping("/userAccount")