Attempting to write a Java RESTful API When I run mvn clean install I build no problem. When I run mvn spring-boot run I get the following runtime error. I have included the pom.xml and classes that I think are relevant. I also have a service layer and entity class not listed, though I don't think they are the issue. I can add if maybe someone would like to see them as well. Any help would be greatly appreciated.Thank you in advance.
org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:161) ~[spring-boot-2.3.3.RELEASE.jar:2.3.3.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:545) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) ~[spring-boot-2.3.3.RELEASE.jar:2.3.3.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) ~[spring-boot-2.3.3.RELEASE.jar:2.3.3.RELEASE]
below is code that I think could potentially be causing the problem:
pom.xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.myproject</groupId>
<artifactId>Java_API</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.3.3.RELEASE</version>
<scope>provided</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.0.2</version>
</plugin>
</plugins>
</build>
</project>
Main.java
package com.example.myproject;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Main {
public static void main(String[] args)
{
SpringApplication.run(myController.class,args);
}
}
myController.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class myController {
#Autowired
private EmployeeService employeeService;
#GetMapping("/employee/{id}")
public Employee getEmployee(#PathVariable int id) {
return employeeService.getEmployee(id);
}
#PostMapping("/employee")
public void createEmployee(#RequestBody Employee employee) {
EmployeeService.createEmployee(employee);
}
}
I have tried only having starter-web instead of both starter-web and starter-tomcat, but it yields the same result. The versioning seems right.
tried adding <scope>provided</scope>, granted I'm not entirely sure what it does.
A number of other things that may come to me, blanking on everything I have tried. Really stumped on what it does not like.
Change Main.java
change SpringApplication.run(myController.class,args);
to
SpringApplication.run(Main.class, args);
public static void main(String[] args)
{
//SpringApplication.run(myController.class,args);
SpringApplication.run(Main.class, args);
}
pom.xml
you can remove spring-boot-starter-tomcat
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.myproject</groupId>
<artifactId>Java_API</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
<!--
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.3.3.RELEASE</version>
<scope>provided</scope>
</dependency>
-->
</dependencies>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.0.2</version>
</plugin>
</plugins>
</build>
</project>
package and run
mvn clean package spring-boot:run
test
curl http://localhost:8080/employee/22
I can't get enough information from your question. I change my test code:
myController.java
package com.example.myproject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class myController {
//#Autowired
//private EmployeeService employeeService;
#GetMapping("/employee/{id}")
public Employee getEmployee(#PathVariable int id) {
Employee e1=new Employee();
e1.setId(id);
e1.setName("Hello World");
return e1;
//return employeeService.getEmployee(id);
}
#PostMapping("/employee")
public void createEmployee(#RequestBody Employee employee) {
System.out.println("DEBUG-"+ employee.getId()+"\t"+employee.getName());
//EmployeeService.createEmployee(employee);
}
}
Employee.java
package com.example.myproject;
public class Employee {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I use the following code to test on my machine and it can be executed. At the same time, when you change SpringApplication.run(Main.class, args); back to SpringApplication.run(myController.class, args) ;, when executed it throws the same error message as in the question, Unable to start web server; nested exception is org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.
If there are other error messages generated, it should be part of your EmployeeService. You did not provide enough information.
Related
I have just started a Spring tutorial. I do everything the same as the lecturer, but if I make a getRequest nothing changes. I also do not have any grey globe icons next to the #RequestMapping and #GetMapping annotations ss of grey globe icon. Would be happy to have any suggestions. Here is the erorr I get when I call the controller endpoint error page
package Controller;
import model.Il;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import java.util.List;
#RestController
#RequestMapping("/iller")
public class ILController {
#GetMapping
public ResponseEntity<List<Il>> getIller(){
Il il1 = new Il("34", "Istanbul");
Il il2 = new Il("06", "Ankara");
List<Il> iller = Arrays.asList(il1, il2);
return new ResponseEntity<>(iller, HttpStatus.OK);
}
}
Il class:
package model;
import lombok.Data;
#Data
public class Il {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Il(){
this.id = "defaultId";
this.name = "defaultName";
}
public Il(String id, String name){
this.id = id;
this.name = name;
}
}
I built your example from scratch with Intellij. Could you try re-editing your code as in the screenshot? If you need help with Spring, please write.
you need to fill the annotation #GetMapping with a path that defines your GET method.
For example, try something like this:
#GetMapping(value = "/GetIller")
public ResponseEntity<List<Il>> getIller(){
Il il1 = new Il("34", "Istanbul");
Il il2 = new Il("06", "Ankara");
List<Il> iller = Arrays.asList(il1, il2);
return new ResponseEntity<>(iller, HttpStatus.OK);
}
Same for other HTTP methods (POST, PUT, PATCH, DELETE ...)
Please check the pom also:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
server:
port: 9090
Application.java
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Regarding the Glob Icon feature, I think that feature is only available in the IntelliJ Enterprise version.
By clicking that grey globe icon it gives 3 options -
Go to declaration or usage
Generate request in HTTP Client
Show all endpoints of module
Thank you in advance, Hello I am new to spring boot. I am facing a problem with spring boot. When I run my URL in postman it shows an error below. I have also uploaded my code below. I don't find any idea what wrong with my code.
{
"timestamp": "2021-07-09T06:43:57.429+00:00",
"status": 404,
"error": "Not Found",
"path": "/todo"
}
Controller code
This is a code for my controller code.
package com.assignment.todo.Todo.Controller;
import com.assignment.todo.Todo.Repo.*;
import java.util.List;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.assignment.todo.Todo.Model.*;
import com.assignment.todo.Todo.Repo.*;
#RestController
#RequestMapping(value="/todo")
public class TodoController {
#Autowired
private TodoRepo todoRepo;
#GetMapping
public List<TodoModel> findAll(){
return todoRepo.findAll();
}
#PostMapping
public TodoModel save(#Valid #NotNull #RequestBody TodoModel todoItem) {
return todoRepo.save(todoItem);
}
}
Model
code for my model class
package com.assignment.todo.Todo.Model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.validation.constraints.NotBlank;
import org.springframework.data.annotation.Id;
#Entity
public class TodoModel {
private Long id;
#NotBlank
private String title;
private boolean done;
public TodoModel() {
}
public TodoModel(long id, String title, boolean done) {
this.id=id;
this.title=title;
this.done=done;
}
#Id
#GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public boolean isDone() {
return done;
}
public void setDone(boolean done) {
this.done = done;
}
}
Repo
code for my repo class
package com.assignment.todo.Todo.Repo;
import com.assignment.todo.Todo.Model.*;
import org.springframework.data.jpa.repository.JpaRepository;
public interface TodoRepo extends JpaRepository<TodoModel, Long> {
}
MainClass
package com.assignment.todo.Todo;
import com.assignment.todo.Todo.Controller.*;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import com.assignment.todo.Todo.Repo.*;
#SpringBootApplication(scanBasePackages = "TodoRepo.java")
public class TodoApplication {
public static void main(String[] args) {
SpringApplication.run(TodoApplication.class, args);
}
}
pom.xml
My pom.xml file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.assignment.todo</groupId>
<artifactId>Todo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Todo</name>
<description>Assignment in Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-mongodb -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>3.1.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepositosry.com/artifact/org.springframework/spring-web -->
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.sun.istack/maven-istack-commons-plugin -->
<!-- https://mvnrepository.com/artifact/com.sun.istack/maven-istack-commons-plugin -->
<dependency>
<groupId>com.sun.istack</groupId>
<artifactId>maven-istack-commons-plugin</artifactId>
<version>2.11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.0.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-jpa -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>2.5.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.persistence/javax.persistence-api -->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
#RestController("/todo")// you can give any URL here
public class TodoController {
#Autowired
private TodoRepo todoRepo;
#GetMapping("/getAll")// you can give any URL here
public List<TodoModel> findAll(){
return todoRepo.findAll();
}
#PostMapping("/save")// you can give any URL here
public TodoModel save(#Valid #NotNull #RequestBody TodoModel todoItem) {
todoRepo.save(todoItem);
return todoItem;
}
}
you give the mapping to the method like this. you can give any URL name. This is the main reason you get a 404 error.
There is issue in your mapping. You didn't specify the mapping path so findAll and save has default mapping as empty then controller could not understand which API you calling. Add below things and try.
#GetMapping(value="/findAll")
#PostMapping(value=/save")
The TodoApplication class must be above this one level.
change this:
from
package com.assignment.todo.Todo;
to
package com.assignment.todo;
I have an error that I can't track down. I'm new so sorry if I missed this in the searches, but I tried several things and no luck.
UserApi.java:
package com.jsp.jsp;
import com.jsp.models.User;
import com.jsp.services.UserService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
#RestController
class UserApi {
private final UserService userService;
public UserApi(UserService userService) {
this.userService = userService;
}
#RequestMapping(value="/api/user", method=RequestMethod.POST)
public User createUser(
#RequestParam(value="name", required=true) String name,
#RequestParam(value="email", required=true) String email,
#RequestParam(value="password", required=true) String password,
#RequestParam(value="confirm", required=true) String confirm)
{
User u = this.userService.createUser(new User(name, email, password));
return u;
}
}
UserRepository.java:
package com.jsp.repositories;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
import com.jsp.models.User;
import org.springframework.data.repository.CrudRepository;
#Repository
public interface UserRepository extends CrudRepository<User, Long> {
List<User> findByEmail(String email);
Optional<User> findById(Long id);
List<User> findAll();
}
Server.java
package com.jsp.jsp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
// import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#SpringBootApplication(scanBasePackages={"com.jsp.models","com.jsp.repositories","com.jsp.services"})
#RestController
public class Server {
public static void main(String[] args) {
SpringApplication.run(Server.class, args);
}
}
UserService.java
package com.jsp.services;
import java.util.List;
import com.jsp.models.User;
import com.jsp.repositories.UserRepository;
import org.springframework.stereotype.Service;
#Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public List<User> allUsers() {
return this.userRepository.findAll();
}
public User createUser(User u) {
return this.userRepository.save(u);
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.jsp</groupId>
<artifactId>jsp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.5</version>
</dependency>
<dependency>
<groupId>org.mindrot</groupId>
<artifactId>jbcrypt</artifactId>
<version>0.4</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.11.7.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
So in short, when I run the above project in VSCode, it errors out with the following:
2019-02-23 19:07:52.744 WARN 25412 --- [ restartedMain]
ConfigServletWebServerApplicationContext : Exception encountered
during context initialization - cancelling refresh attempt:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'userService' defined in file
[C:\Users\Alex\Documents\dojo\javatown\everything\target\classes\com\jsp\services\UserService.class]:
Unsatisfied dependency expressed through constructor parameter 0;
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'com.jsp.repositories.UserRepository'
available: expected at least 1 bean which qualifies as autowire
candidate. Dependency annotations: {}
My understanding is that the repository I made should be automatically turned into a bean and then wire itself up to the service I made. However, that seems to be not happening. My example videos are using MySQL -- will that make a difference? Am I using the right driver for Postgres 11? I'm super lost.
Some remarks and suggestions:
1.add autowired annotation on your constructor, it is clearer what you need spring to do.
#Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
2. I don't understand #RestController annotation on your main class.
#SpringBootApplication(scanBasePackages {"com.jsp.models","com.jsp.repositories","com.jsp.services"})
#RestController --> THIS CAN BE REMOVED
public class Server {
public static void main(String[] args) {
SpringApplication.run(Server.class, args);
}
}
3.You should add #EnableJpaRepositories("com.jsp.repositories") on your spring boot application => it will scan the repositories in that package.
#SpringBootApplication(scanBasePackages {"com.jsp.models","com.jsp.repositories","com.jsp.services"})
#EnableJpaRepositories("com.jsp.repositories")
public class Server {
public static void main(String[] args) {
SpringApplication.run(Server.class, args);
}
}
My sample spring boot REST web service gives 404 error, and I am not sure what went wrong
package com.in28minutes.springboot.studentservices;
#SpringBootApplication
public class StudentServicesApplication {
public static void main(String[] args) {
SpringApplication.run(StudentServicesApplication.class, args);
}
}
package com.in28minutes.springboot.controller;
#RestController
public class StudentController {
#Autowired
private StudentService studentService;
#GetMapping("/students/{studentId}/courses")
public List<Course> retrieveCoursesForStudent(#PathVariable String
studentId) {
return studentService.retrieveCourses(studentId);
}
#GetMapping("/students/{studentId}/courses/{courseId}")
public Course retrieveDetailsForCourse(#PathVariable String studentId,
#PathVariable String courseId) {
return studentService.retrieveCourse(studentId, courseId);
}
}
My Request from POSTMan REST request sender:
http://localhost:8080/students/stu1/courses/course1
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.in28minutes.springboot</groupId>
<artifactId>student-services</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>student-services</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Response:
{
"timestamp": "2018-12-28T02:48:00.185+0000",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/students/stu1/courses/course1"
}
As assumed, you have Controller classes in different package com.in28minutes.springboot.controller; and Spring boot main class in different package com.in28minutes.springboot.studentservices;
#SpringBootApplication
By default #SpringBootApplication will only scan from the package of the class that declares this annotation.
This is a convenience annotation that is equivalent to declaring #Configuration, #EnableAutoConfiguration and #ComponentScan.
If specific packages are not defined, scanning will occur from the package of the class that declares this annotation.
use #ComponentScan to scan controller package
#ComponentScan(basePackages = {"com.in28minutes.springboot.controller"})
#SpringBootApplication
public class StudentServicesApplication {
public static void main(String[] args) {
SpringApplication.run(StudentServicesApplication.class, args);
}
}
More Info : ref
The issue is resolved, #Component needed to be added to Service class, along with #ComponentScan in the main application class:
package com.in28minutes.springboot.service;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.stereotype.Component;
import com.in28minutes.springboot.model.Course;
import com.in28minutes.springboot.model.Student;
#Component
public class StudentService {
public List<Course> retrieveCourses(String studentId) {
Map<String, Course> courses = Student.getStudentObj(studentId).getCourses();
List<Course> courseList =
courses.values().parallelStream().collect(Collectors.toList());
return courseList;
}
public Course retrieveCourse(String studentId, String courseId) {
return Student.getStudentObj(studentId).getCourses().get(courseId);
}
}
package com.in28minutes.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#ComponentScan("com.in28minutes.springboot")
public class StudentServicesApplication {
public static void main(String[] args) {
SpringApplication.run(StudentServicesApplication.class, args);
}
}
I'm working through a Spring tutorial at http://spring.io/guides/gs/validating-form-input/, and get a 404 upon attempting to access the localhost root.
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Wed Aug 06 02:36:15 CDT 2014
There was an unexpected error (type=Not Found, status=404).
I modified the workflow a bit to use Eclipse's Maven project settings. The steps I took, that were different from the tutorial, in order:
Created a Maven Project in Eclipse
Replaced the pom.xml that was generated with the one from the tutorial
The tutorial instruct to have the template HTML files in resources/templates, and Spring threw this exception (quite a few internal exceptions, actually), Caused by: java.lang.IllegalStateException: Cannot find template location: class path resource [templates/] (please add some templates or check your Thymeleaf configuration)
To resolve, I moved the templates form.html and results.html to /templates on the classpath.
I checked with the debugger the WebController class, and none of it's code is being hit. I don't believe it is a local configuration issue, because the completed tutorial in their git repo behaves as expected.
If anyone has any insight at all, it would be much appreciated. Thank you!
These are the files from my non-working attempt.
WebController.java
package hello;
import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
public class WebController extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/results").setViewName("results");
}
#RequestMapping(value="/", method=RequestMethod.GET)
public String showForm(Person person) {
return "form";
}
#RequestMapping(value="/", method=RequestMethod.POST)
public String checkPersonInfo(#Valid Person person, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "form";
}
return "redirect:/results";
}
}
Application.java
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
Person.java
package hello;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class Person {
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Person [name=")
.append(name)
.append(", age=")
.append(age)
.append("]");
return builder.toString();
}
#Size(min=2, max=30)
private String name;
#NotNull
#Min(18)
private Integer age;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-validating-form-input</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.1.4.RELEASE</version>
</parent>
<properties>
<!-- use UTF-8 for everything -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<start-class>hello.Application</start-class>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>http://repo.spring.io/libs-release</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>http://repo.spring.io/libs-release</url>
</pluginRepository>
</pluginRepositories>
</project>
There is no #Controller on your controller. As far as Spring is concerned this class is just a simple pojo that it shouldn't care about: it's not defined anywhere and it's not picked up by classpath scanning since it does not have the proper annotation on it.