Java 使用SpringBoot的RESTAPI不通过angular向客户端返回数据:从浏览器产生404响应

Java 使用SpringBoot的RESTAPI不通过angular向客户端返回数据:从浏览器产生404响应,java,angularjs,json,spring,spring-mvc,Java,Angularjs,Json,Spring,Spring Mvc,我对这一切都不熟悉。这就是问题所在。我有一个RESTAPI,使用SpringBoot连接到MySQL。访问我的API的URL是。每当我访问此URL时,我都会得到我的 JSON对象,如预期的那样 我还有一个单独的angular项目,它通过自己的API连接到此API 路线。例如:HTTP:localhost:8080/angular2/#!/应该调用API,但是我从浏览器得到404响应 spring配置文件: package com.init; import java.util.Propertie

我对这一切都不熟悉。这就是问题所在。我有一个RESTAPI,使用SpringBoot连接到MySQL。访问我的API的URL是。每当我访问此URL时,我都会得到我的 JSON对象,如预期的那样

我还有一个单独的angular项目,它通过自己的API连接到此API 路线。例如:HTTP:localhost:8080/angular2/#!/应该调用API,但是我从浏览器得到404响应

spring配置文件:

package com.init;

import java.util.Properties;

import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@ComponentScan(basePackages = "com")
@EnableTransactionManagement

public class MvcConfiguration extends WebMvcConfigurerAdapter {

    private static final String DATABASE_DRIVER = "com.mysql.jdbc.Driver";
    private static final String DATABASE_URL = "jdbc:mysql://localhost:3306/videogamereviews?verifyServerCertificate=false&useSSL=true";
    private static final String DATABASE_USERNAME = "root";
    private static final String DATABASE_PASSWORD ="random";

    private static final String HIBERNATE_DIALECT = "org.hibernate.dialect.MySQLDialect";
    private static final String HIBERNATE_SHOW_SQL = "true";
    private static final String ENTITYMANAGER_PACKAGES_TO_SCAN = "com.model";
    private static final String HIBERNATE_HBM2DDL_AUTO = "create-drop";
//  private static final String HIBERNATE_HBM2DDL_AUTO = "update";

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(DATABASE_DRIVER);
        dataSource.setUrl(DATABASE_URL);
        dataSource.setUsername(DATABASE_USERNAME);
        dataSource.setPassword(DATABASE_PASSWORD);
        return dataSource;
    }

    @Bean
    public CorsFilter corsFilter() {

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true); // you USUALLY want this
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("PUT");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }



    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource());
        sessionFactoryBean.setPackagesToScan(ENTITYMANAGER_PACKAGES_TO_SCAN);
        sessionFactoryBean.setHibernateProperties(hibernateProperties());
        return sessionFactoryBean;
    }

    private Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", HIBERNATE_DIALECT);
        properties.put("hibernate.show_sql", HIBERNATE_SHOW_SQL);
        properties.put("hibernate.hbm2ddl.auto", HIBERNATE_HBM2DDL_AUTO);
        return properties;
    }

    @Bean
    public HibernateTransactionManager transactionManager() {
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(sessionFactory().getObject());
        return transactionManager;
    }

    @Bean
    public ViewResolver getViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/jsp/");
        resolver.setSuffix(".jsp");
        return resolver;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/css/**").addResourceLocations("/resources/");
    }
}
我的spring控制器:ReviewController.java

package com.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.model.Review;
import com.service.ReviewService;

@RestController
@RequestMapping(value = "review")
@CrossOrigin(origins="http://localhost:8080")

public class ReviewController {

    @Autowired
    private ReviewService rs;

    @RequestMapping(value="/",method = RequestMethod.GET)
    public List<Review> getReviews() {
        return rs.getReviews();
    }

    @RequestMapping(value = "{id}", method = RequestMethod.GET)
    public Review showReviewWithId(@PathVariable long id) {
        return rs.getReviewById(id);

    }


    @RequestMapping(value = "{id}", method = RequestMethod.PUT)
    public String updateReviews(@PathVariable long id, @RequestBody Review review) {
        rs.updateReview(id,review);
        return "review updated";
    }

    @RequestMapping(value = "{id}", method = RequestMethod.DELETE)
    public String delete(@PathVariable long id) {
        rs.deleteReview(id);
        return "review deleted";
    }



    @RequestMapping(value="/",method = RequestMethod.POST)
    public String postReview(@RequestBody Review review) {
        rs.saveReview(review);
        return "review created";
    }

}



angular setup: app.js
    'use strict';

    var VideogameReviewsApp = angular.module('VideogameReviewsApp', ['ngRoute','ngResource']).
         config(['$routeProvider', function ($routeProvider) {
            $routeProvider.
                when('/', { controller: ReviewCtrl, templateUrl: 'review.html' }).
                otherwise({ redirectTo: '/' });
         }]);

    VideogameReviewsApp.factory('Review', function ($resource) {
        return $resource('http://localhost/videogamereviews/review/:id.json', { id: '@id' }, 


                { update: { method: 'PUT' } });
    });

    var ReviewCtrl = function ($scope,Review) {
        alert("haha");
        $scope.reviews = Review.query();
    };
package.com.controller;
导入java.util.List;
导入org.springframework.beans.factory.annotation.Autowired;
导入org.springframework.web.bind.annotation.CrossOrigin;
导入org.springframework.web.bind.annotation.PathVariable;
导入org.springframework.web.bind.annotation.RequestBody;
导入org.springframework.web.bind.annotation.RequestMapping;
导入org.springframework.web.bind.annotation.RequestMethod;
导入org.springframework.web.bind.annotation.RestController;
导入com.model.Review;
导入com.service.ReviewService;
@RestController
@请求映射(value=“review”)
@交叉原点(原点=”http://localhost:8080")
公共类审阅控制器{
@自动连线
私人审稿服务;
@RequestMapping(value=“/”,method=RequestMethod.GET)
公共列表getReviews(){
返回rs.getReviews();
}
@RequestMapping(value=“{id}”,method=RequestMethod.GET)
公共评论showReviewWithId(@PathVariable long id){
返回rs.getReviewById(id);
}
@RequestMapping(value=“{id}”,method=RequestMethod.PUT)
公共字符串更新视图(@PathVariable long id,@RequestBody Review){
rs.updateReview(id,review);
返回“审查更新”;
}
@RequestMapping(value=“{id}”,method=RequestMethod.DELETE)
公共字符串删除(@PathVariable long id){
rs.deleteReview(id);
返回“已删除审阅”;
}
@RequestMapping(value=“/”,method=RequestMethod.POST)
公共字符串postReview(@RequestBody Review){
rs.saveReview(review);
返回“已创建审阅”;
}
}
角度设置:app.js
"严格使用",;
var VideogameReviewsApp=angular.module('VideogameReviewsApp',['ngRoute','ngResource'])。
配置(['$routeProvider',函数($routeProvider){
$routeProvider。
when('/',{controller:ReviewCtrl,templateUrl:'review.html'})。
否则({重定向到:'/'});
}]);
VideoGameReviewApp.factory('Review',函数($resource){
返回$resource('http://localhost/videogamereviews/review/:id.json“,{id:'@id'}”,
{update:{method:'PUT'}});
});
var ReviewCtrl=功能($scope,Review){
警惕(“哈哈”);
$scope.reviews=Review.query();
};
在浏览器标题部分,我可以看到正在访问的URL是 . 那我为什么要拿到404

回应?提前谢谢!
Ashley

根据审查,应通过 并且具有给定id的审阅应该可以通过

因此,您必须从请求结束url中删除.json。

如果返回预期的json,请在脚本中使用它。这意味着当您想要检索资源时,要删除uri中的
.json
。返回一个JSON资源,但不是。

您的url有冒号(:),这是导致问题的原因。只需在浏览器中粘贴您的资源uri(在浏览器控制台中检查响应)或使用postman即可。从spring控制器获得的GET请求应如下所示:

  • 对于所有ID:-'localhost/videogamereviews/review'
  • 对于id为的特定评论:-'localhost/videogamereviews/review/id/1234' 考虑1234个样本审查ID。

我还考虑将localhost映射到localhost:{app server portno}。(即localhost:8080)且上下文根为videogamereviews

请求的资源位于“”

但是,必须在以下位置访问我的api: “/

所以angulars的默认行为是(从文档中) 默认情况下,将从计算的URL中删除尾部斜杠,这可能会对不希望出现这种行为的服务器后端造成问题。可以通过如下配置$resourceProvider来禁用此功能:

因此,在I app.js中,我需要添加以下内容:

app.config(['$resourceProvider', function($resourceProvider) {
  // Don't strip trailing slashes from calculated URLs
  $resourceProvider.defaults.stripTrailingSlashes = false;
}]);

为什么是/review.json?在你的控制器中,它看起来像/回顾我也觉得很奇怪,我在一个教程中看到了这一点。但是,即使我删除了它,它仍然不起作用……因为这行代码:VideoGameReviewApp.factory('Review',function($resource){return$resource('')。如果我删除了.json,url就会像预期的那样,但仍然不起作用。将app.js中的url更改为VideoGameReviewApp.factory('Review',function($resource){return$resource('')(“”,{id:'@id'},{update:{method:'PUT'}}});});但它仍然无法打开浏览器调试(F12)然后选择“网络”选项卡,然后重新加载页面,我想查看所有网络请求。嗨,我修复了它。Angular删除了尾随斜杠bij默认值。因此Angular使用URL生成请求:但是API响应URL:。所以我通过覆盖angulars默认行为修复了它