简体   繁体   中英

Rest api using Spring boot not returning data to client via angular: yields 404 response from browser

I'm fairly new to all of this. This is the problem. I have a REST API using Spring Boot hooked up to MySQL. The URL to access my API is http://localhost/videogamereview/review/(id) . Whenever I access this URL I get my JSON object as expected.

I also have a separate angular project which connects to this API via its own routes. For instance: HTTP:localhost:8080/angular2/#!/ should make a call to the API, however I get a 404 response from the browser.

spring configuration file:

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/");
    }
}

my controller in 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();
    };

In the browser headers section, I can see that the URL which is being accessed is http://localhost/videogamereviews/review.json . So why am I getting a 404

response? Thanks in advance! Ashley

According to ReviewController reviews should be accesible through http://localhost/review and a review with given id should be accessible through http://localhost/review/YOUR_REVIEW_ID

so you have to remove .json from end of request url.

If http://localhost/videogamereview/review/(id) returns an expected JSON, so use it in your Angular script. That mean removing .json in uri when you want to retrieve a resource. http://localhost/videogamereview/review/(id) returns a JSON resource, but http://localhost/videogamereview/review/(id).json is not.

your url have colon (:) which is causing the issue. just paste your resource uri in browser(check in browser console about the response) or use postman. from your spring controller the GET Request should be as below:

  • for all ids: - 'localhost/videogamereviews/review'
  • for specific review with id: - 'localhost/videogamereviews/review/id/1234' consider 1234 sample review id.

also I am considering the localhost is mapped to localhost:{app server portno}. (ie localhost:8080) and context root is videogamereviews .

Apparently angular requested the resource at " http://localhost/videogamereviews/review "

However my api must be accessed at " http://localhost/videogamereviews/review / ".

So angulars default behavior is (from the documentation) "By default, trailing slashes will be stripped from the calculated URLs, which can pose problems with server backends that do not expect that behavior. This can be disabled by configuring the $resourceProvider like this:"

So in I app.js I needed to add the following:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM