0

so im just getting started with spring boot and i try to implement a crud service. I got my code mostly from this tutorial Spring Boot Rest API Example, i just changed the variable names. I figured all my problems with starting spring boot etc out, but now i can't get access to the api on my localhost. I hope someone can help me :)

My Application.java

package demo.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(scanBasePackages= {"demo"})
public class App {

  public static void main(String[] args) {
  SpringApplication.run(App.class, args);
  }
}

My model Game.java:

package demo.model;


public class Game {

private long id;

private String name;
private String genre;
private String studio;
private String publisher;


public Game(long id, String name, String genre, String studio, String publisher) {
    this.id = id;
    this.name = name;
    this.genre = genre;
    this.studio = studio;
    this.publisher = publisher;
}

public long getId() {
    return id;
}
public void setId(long id) {
    this.id = id;
}
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
public String getGenre() {
    return genre;
}
public void setGenre(String genre) {
    this.genre = genre;
}
public String getStudio() {
    return studio;
}
public void setStudio(String studio) {
    this.studio = studio;
}
public String getPublisher() {
    return publisher;
}
public void setPublisher(String publisher) {
    this.publisher = publisher;
}

@Override
public String toString() {
    return "Game [id=" + id + ", name=" + name + ", genre=" + genre + ", studio=" + studio + ", publisher="
            + publisher + "]";
  }
}

The Api Controller RestApiController.java

package demo.app.controller;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
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 org.springframework.web.util.UriComponentsBuilder;

import demo.model.Game;
import demo.service.GameService;
import demo.util.CostumErrorType;


@RestController
@RequestMapping("/api")
public class RestApiController {
public static final Logger logger = LoggerFactory.getLogger(RestApiController.class);

@Autowired
GameService gameService; // Service which will do all data retrieval/manipulation work

//---------------Retrieve all games---------------------------------

@RequestMapping(value = "/game/", method = RequestMethod.GET)
public ResponseEntity<List<Game>> listAllGames() {
    List<Game> games = gameService.findAllGames();
    if(games.isEmpty()) {
        return new ResponseEntity(HttpStatus.NO_CONTENT);
        //TODO: vllt in HttpStatus.NOT_FOUND ändern
    }
    return new ResponseEntity<List<Game>>(games, HttpStatus.OK);
}

//---------------Retrieve Single Game---------------------------------


@RequestMapping(value = "/game/{id}", method = RequestMethod.GET)
public ResponseEntity<?> getGame(@PathVariable("id") long id) {
    logger.info("Fetching User with id {}", id);
    Game game = gameService.findById(id);
    if(game == null) {
        logger.error("Game with id {} not found.", id);
        return new ResponseEntity(new CostumErrorType("Game with id " + id + " not found"), HttpStatus.NOT_FOUND);
    }
    return new ResponseEntity<Game>(game, HttpStatus.OK);
}

//---------------Create a Game---------------------------------

@RequestMapping(value= "/game/", method = RequestMethod.POST)
public ResponseEntity<?> createGame(@RequestBody Game game, UriComponentsBuilder ucBuilder){
    logger.info("Creating Game: {}", game);

    if(gameService.isGameExist(game)) {
        logger.error("Unable to create. A Game with name {} already exists.", game.getName());
        return new ResponseEntity(new CostumErrorType("Unable to create. A Game with name " + game.getName() + "already exists."), HttpStatus.CONFLICT);    
    }
    gameService.saveGame(game);

    HttpHeaders headers = new HttpHeaders();
    headers.setLocation(ucBuilder.path("/api/game/{id}").buildAndExpand(game.getId()).toUri());
    return new ResponseEntity<String>(headers, HttpStatus.CREATED);
    }
}

The Service interface GameService.java:

package demo.service;

import java.util.List;

import demo.model.Game;

public interface GameService {

  Game findById(long id);

  Game findByName(String name);

  void saveGame(Game game);

  void updateGame(Game game);

  void deleteGameByName(String name);

  List<Game> findAllGames();

  void deleteAllGames();

  boolean isGameExist(Game game);

}

The Implentation of it GameServiceImpl.java:

package demo.service;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

import org.springframework.stereotype.Service;

import demo.model.Game;

@Service("gameService")
public class GameServiceImpl implements GameService{

private static final AtomicLong counter = new AtomicLong();

private static List<Game> games;

static {
    games = populateDummyGames();
}

public List<Game> findAllGames(){
    return games;
}

public Game findById(long id) {
    for(Game game : games) {
        if(game.getId() == id) {
            return game;
        }
    }
    return null;
}

public Game findByName(String name) {
    for(Game game : games) {
        if(game.getName().equalsIgnoreCase(name)) {
            return game;
        }
    }
    return null;
}

public void saveGame(Game game) {
    game.setId(counter.incrementAndGet());
    games.add(game);
}

public void updateGame(Game game) {
    int index = games.indexOf(game);
    games.set(index, game);
}

public void deleteGameById(long id) {

    for (Iterator<Game> iterator = games.iterator(); iterator.hasNext();) {
        Game game = iterator.next();
        if (game.getId() == id) {
            iterator.remove();
        }
    }
}

public void deleteGameByName(String name) {

    for (Iterator<Game> iterator = games.iterator(); iterator.hasNext();) {
        Game game = iterator.next();
        if (game.getName().equalsIgnoreCase(name)) {
            iterator.remove();
        }
    }
}

public boolean isGameExist(Game game) {
    return findByName(game.getName())!=null;
}

public void deleteAllGames() {
    games.clear();
}

private static List<Game> populateDummyGames(){
    List<Game> games = new ArrayList<Game>();
    games.add(new Game(counter.incrementAndGet(), "The Elder Scrolls V: Skyrim", "RPG", "Bethesda Game Studios", "Bethesda"));
    games.add(new Game(counter.incrementAndGet(), "Halo: Combat Evolved", "First-Person-Shooter", "Bungie", "Microsoft"));
    games.add(new Game(counter.incrementAndGet(), "Doom", "First-Person-Shooter", "ID-Studios", "Bethesda"));

    return games;
  }
}

After i start the spring boot app and send a request via curl to localhost:8080, there is no link to my api.

Edit I forgot to include my pom.xml file. Maybe it has something to do with the problem:

<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.7.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-rest</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
</project>

Edit:
I figured it out... i feel kinda stupid. In RestApiController.java, the RequestMapping for the first Method was set to

/game/  

which makes no sense to me. So i only tried to access it via localhost:8080/api/game. When accessed via localhost:8080/api/game/, it works fine.. Sorry guys.. But thanks for your help!

5
  • 2
    Do you know what @RequestMapping do? run your app and try using localhost:8080/api/game Commented Oct 17, 2017 at 14:52
  • There may be a context path that need to be used if the application is not started in root context. Commented Oct 17, 2017 at 19:29
  • What error you are getting when you are hitting localhost:8080/api/game, and also check mapping logs in your server logs, to check what is mapped url with dispatcher servlet and will each requestmapping endpoint Commented Oct 17, 2017 at 19:55
  • So if i hit localhost:8080/api/game, i get this response: >>mxd-md@mxdmd-VirtualBox:~$ curl localhost:8080/api/game {"timestamp":1508309023026,"status":404,"error":"Not Found","message":"No message available","path":"/api/game"}<< Commented Oct 18, 2017 at 6:45
  • @Pete there was a context path in a application.yml file (which i forgot to include in my post). I removed it and even then i can't get a response from localhost:8080/api/game Commented Oct 18, 2017 at 6:49

1 Answer 1

1

Well, I believe the problem is:

@SpringBootApplication(scanBasePackages= {"demo"})

try to change it to

@SpringBootApplication(scanBasePackages= {"demo.app"})

or

@SpringBootApplication
@EnableAutoConfiguration

With @EnableAutoConfiguration spring will automatically configure the beans you'll need.

Sign up to request clarification or add additional context in comments.

2 Comments

The @SpringBootApplication annotation is equivalent to using @Configuration, @EnableAutoConfiguration and @ComponentScan with their default attributes.
You need to put scanBasePackages if your controllers are not in same/child packages where you have defined SpringBootApplication. In this case SpringBoot is defined in demo.app and controllers are in demo.app.controller, so you don't need to put scanBasePackages

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.