'Postman is returning a 404 error on my Spring Boot API
I've built a spring boot rest api. However, when I try to test it in Postman, I am getting a 404 error. I have linked the code below. Please note that there might be a random @component annotation in some files. This was my tired brain trying anything it can.
Student.java
package StudentModel;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "Student")
public class Student {
public enum status {
PAID,
UNPAID,
PARTIAL
}
@Column
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long Id;
@Column(nullable = false)
private String FirstName;
@Column(nullable = false)
private String LastName;
@Column(nullable = false)
private long Phone;
@Column(nullable = false)
private String Email;
@Column(nullable = false)
private status PaymentStatus;
public long getId() {
return Id;
}
public void setId(long id) {
Id = id;
}
public String getFirstName() {
return FirstName;
}
public void setFirstName(String firstName) {
FirstName = firstName;
}
public String getLastName() {
return LastName;
}
public void setLastName(String lastName) {
LastName = lastName;
}
public long getPhone() {
return Phone;
}
public void setPhone(long phone) {
Phone = phone;
}
public String getEmail() {
return Email;
}
public void setEmail(String email) {
Email = email;
}
public status getPaymentStatus() {
return PaymentStatus;
}
public void setPaymentStatus(status paymentStatus) {
PaymentStatus = paymentStatus;
}
}
StudentController.java
package StudentController;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.DeleteMapping;
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.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import StudentModel.Student;
import StudentService.StudentService;
@Component
@RestController
@RequestMapping("/api/v1")
public class StudentController {
@Autowired
private StudentService studentService;
@PostMapping("/api/v1/addStudent")
public Student addStudent(@RequestBody Student student) {
return studentService.saveStudent(student);
}
@PostMapping("/api/v1/addStudents")
public List<Student> addStudents(@RequestBody List<Student> students) {
return studentService.saveStudents(students);
}
@GetMapping("/api/v1/students")
public List<Student> findAllStudents(){
return studentService.getStudents();
}
@GetMapping("/api/v1/students/{id}")
public Student findStudentById(@PathVariable long id) {
return studentService.getStudentById(id);
}
@GetMapping("/api/v1/students/{name}")
public Student findStudentByFirstName(@PathVariable String FirstName) {
return studentService.getStudentByFirstName(FirstName);
}
@PutMapping("/api/v1/update")
public Student updateStudent(@RequestBody Student student) {
return studentService.updateStudent(student);
}
@DeleteMapping("/api/v1/delete/{id}")
public String deleteStudent(@PathVariable long id) {
return studentService.deleteStudent(id);
}
}
StudentService.java
package StudentService;
import java.util.List;
import java.util.Optional;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import StudentModel.Student;
import StudentRepository.StudentRepository;
@Component
@Service
@Transactional
public class StudentService {
@Autowired
private StudentRepository studentRepository;
public Student saveStudent(Student student) {
return studentRepository.save(student);
}
public List<Student> saveStudents(List<Student> students) {
return studentRepository.saveAll(students);
}
public List<Student> getStudents() {
return studentRepository.findAll();
}
public Student getStudentById(long id){
return studentRepository.getById(id);
}
public Student getStudentByFirstName(String FirstName){
return studentRepository.findByFirstName(FirstName);
}
public Student getStudentByLastName(String LastName){
return studentRepository.findByLastName(LastName);
}
public Student getStudentByEmail(String Email){
return studentRepository.findByEmail(Email);
}
public Student getStudentByPhone(long Phone){
return studentRepository.findByPhone(Phone);
}
public String deleteStudent(long id) {
studentRepository.deleteById(id);
return "Student Deleted";
}
public Student updateStudent (Student student) {
Student existingStudent = studentRepository.getById(student.getId());
existingStudent.setFirstName(student.getFirstName());
existingStudent.setLastName(student.getLastName());
existingStudent.setEmail(student.getEmail());
existingStudent.setPhone(student.getPhone());
existingStudent.setPaymentStatus(student.getPaymentStatus());
return studentRepository.save(existingStudent);
}
}
StudentRepository.java
package StudentRepository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;
import StudentModel.Student;
@Component
public interface StudentRepository extends JpaRepository <Student, Long>{
// Student saveStudent (Student student);
Student findByFirstName(String FirstName);
Student findByLastName(String LastName);
Student findByEmail(String Email);
Student findByPhone(long Phone);
// Student findById(long id);
}
StudentApplication.java
package com.BusyQA;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@SpringBootApplication
@ComponentScan
public class BusyQaApplication extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(BusyQaApplication.class, args);
}
}
Any help would be greatly appreciated. Thank you.
Solution 1:[1]
As Dilermando mentioned in the comments, your @RequestMapping("/api/v1")
is setting its mapping, then you're extending onto that with @PostMapping("/api/v1/addStudent")
making the address {url}/api/v1/api/v1/addStudent
. You can resolve this by removing the /api/v1 from the Post/get mappings:
@RequestMapping("/api/v1")
public class StudentController {
@Autowired
private StudentService studentService;
@PostMapping("/addStudent")
public Student addStudent(@RequestBody Student student) {
return studentService.saveStudent(student);
}
...etc
}
Solution 2:[2]
There are 2 reason behind 404 not found
Problem 1
You main class is in com.BusyQA
package and Controller class is in StudentController
package so you have to scan controller class in main class.
Your StudentApplication.java
class should become:
@SpringBootApplication
@ComponentScan(basePackageClasses = StudentController.class) // Scan the controller class in main class.
public class BusyQaApplication extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(BusyQaApplication.class, args);
}
}
Problem 2
Remove pre path /api/v1
from all url mapping in controller. Now your mapping url should become
@RestController
@RequestMapping("/api/v1")
public class StudentController {
@Autowired
private StudentService studentService;
@PostMapping("/addStudent")
@PostMapping("/addStudents")
@GetMapping("/students")
@GetMapping("/students/{id}")
@GetMapping("/students/{name}")
@PutMapping("/update")
@DeleteMapping("/delete/{id}")
}
This is another mistake in your code:
Remove the
@Component
annotation from controller.Remove the
@Component
annotation from Service class.Remove the
@Component
annotation from Repository interface and add@Repository
annotation.
Solution 3:[3]
To make it work, you need some improvements:
- For
Controller
(REST API
requests):
- remove
@Component
annotation;- remove
/api/v1/
from request mappings;- add
DTO
to only transfer the required information;- fix the name of the variables, following the convention.
import java.util.ArrayList;
import java.util.List;
import com.example.demo.dto.StudentDTO;
import com.example.demo.entity.Student;
import com.example.demo.service.StudentService;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/v1")
public class StudentController {
private final StudentService studentService;
public StudentController(StudentService studentService) {
this.studentService = studentService;
}
@PostMapping("/addStudent")
public Student addStudent(@RequestBody StudentDTO studentDTO) {
Student student = new Student(studentDTO);
return studentService.saveStudent(student);
}
@PostMapping("/addStudents")
public List<Student> addStudents(@RequestBody List<Student> students) {
return studentService.saveStudents(students);
}
@GetMapping("/students")
public List<StudentDTO> findAllStudents() {
List<StudentDTO> studentDTOList = new ArrayList<>();
List<Student> studentList = studentService.getStudents();
for (Student student : studentList) {
StudentDTO studentDTO = new StudentDTO(student);
studentDTOList.add(studentDTO);
}
return studentDTOList;
}
@GetMapping("/students/id/{id}")
public Student findStudentById(@PathVariable long id) {
return studentService.getStudentById(id);
}
@GetMapping("/students/firstName/{firstName}")
public Student findStudentByFirstName(@PathVariable String firstName) {
return studentService.getStudentByFirstName(firstName);
}
@PutMapping("/update")
public Student updateStudent(@RequestBody StudentDTO studentDTO) {
Student student = new Student(studentDTO);
return studentService.updateStudent(student);
}
@DeleteMapping("/delete/{id}")
public String deleteStudent(@PathVariable long id) {
return studentService.deleteStudent(id);
}
}
- For
Service
class (Business logic):
- remove
@Component
annotation;- remove
@Transactional
annotation;- use
findById()
to retrieve an entity by itsId
;
import java.util.List;
import java.util.Optional;
import com.example.demo.entity.Student;
import com.example.demo.repository.StudentRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityNotFoundException;
@Service
public class StudentService {
private final StudentRepository studentRepository;
public StudentService(StudentRepository studentRepository) {
this.studentRepository = studentRepository;
}
public Student saveStudent(Student student) {
return studentRepository.save(student);
}
public List<Student> saveStudents(List<Student> students) {
return studentRepository.saveAll(students);
}
public List<Student> getStudents() {
return studentRepository.findAll();
}
public Student getStudentById(long id) {
return studentRepository.findById(id).orElseThrow(EntityNotFoundException::new);
}
public Student getStudentByFirstName(String firstName) {
return studentRepository.findByFirstName(firstName);
}
public Student getStudentByLastName(String lastName) {
return studentRepository.findByLastName(lastName);
}
public Student getStudentByEmail(String email) {
return studentRepository.findByEmail(email);
}
public Student getStudentByPhone(long phone) {
return studentRepository.findByPhone(phone);
}
public String deleteStudent(long id) {
studentRepository.deleteById(id);
return "Student Deleted";
}
public Student updateStudent(Student student) {
Student existingStudent = studentRepository.getById(student.getId());
existingStudent.setFirstName(student.getFirstName());
existingStudent.setLastName(student.getLastName());
existingStudent.setEmail(student.getEmail());
existingStudent.setPhone(student.getPhone());
existingStudent.setPaymentStatus(student.getPaymentStatus());
return studentRepository.save(existingStudent);
}
}
- The
Model
class:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import com.example.demo.dto.StudentDTO;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.Builder;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class Student {
public Student(StudentDTO studentDTO) {
this.id = studentDTO.getId();
this.firstName = studentDTO.getFirstName();
this.lastName = studentDTO.getLastName();
this.phone = studentDTO.getPhone();
this.email = studentDTO.getEmail();
this.paymentStatus = studentDTO.getPaymentStatus();
}
public enum Status {
PAID,
UNPAID,
PARTIAL
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column
private long id;
private String firstName;
private String lastName;
private long phone;
private String email;
private Status paymentStatus;
}
DTO
class:
import com.example.demo.entity.Student;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(NON_NULL)
public class StudentDTO implements Serializable {
public StudentDTO(Student student) {
this.id = student.getId();
this.firstName = student.getFirstName();
this.lastName = student.getLastName();
this.phone = student.getPhone();
this.email = student.getEmail();
this.paymentStatus = student.getPaymentStatus();
}
private long id;
private String firstName;
private String lastName;
private long phone;
private String email;
private Student.Status paymentStatus;
}
- The
Repository
class:
import com.example.demo.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {
Student findByFirstName(String firstName);
Student findByLastName(String lastName);
Student findByEmail(String email);
Student findByPhone(long phone);
}
and the main class of a Spring Boot
application:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
To test it, you can use endpoints by the same principle:
POST: localhost:8080/api/v1/addStudent
POST: localhost:8080/api/v1/addStudents
GET: localhost:8080/api/v1/students
GET: localhost:8080/api/v1/students/id/1
GET: localhost:8080/api/v1/students/firstName/testName
PUT: localhost:8080/api/v1/update
DELETE: localhost:8080/api/v1/delete/1
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | lew |
Solution 2 | |
Solution 3 |