'Data from MySQL table not showing in Spring Boot / Angular MatTable - GET error 404

I get the following error when I try to display data from MySQL table, in a MatTable from angular. I have a hard time troubleshooting since I am not sure if the problem is in my services, backend or component. I have looked at several guides as well but none of them seem to help my problem since they use different data sources etc.

I get the columns, pagination and sort to show but not the actual data from MySQL.

Application properties is set to the datasource url with my database schema, username and password.

GET http://localhost:4200/customers 404 (Not Found).

My Customers component

   @Component({
  selector: 'app-customers',
  templateUrl: './customers.component.html',
  styleUrls: ['./customers.component.css']
})

export class CustomersComponent implements OnInit, AfterViewInit {

  displayedColumns: string[] = ['id', 'company', 'contact', 'email', 'discount']; //'actions'

  dataSource: MatTableDataSource<Customersmodel> = new MatTableDataSource();

  customersmodel: Customersmodel[] = [];

  @ViewChild(MatPaginator) paginator!: MatPaginator;
  @ViewChild(MatSort) sort!: MatSort;

  constructor(private customersService: CustomersService,
              private router: Router,
              private httpClient: HttpClient) {
  }

  ngOnInit(): void {

    this.router.events.subscribe(value => {
      this.getCustomers();

  
    });

    console.log(this.dataSource);

    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;

  }

  public getCustomers(): void {
    this.customersService.getCustomers().subscribe(data => {
      this.customersmodel = data;
    });
  }

  ngAfterViewInit() {

  }

  applyFilter(event: Event) {

    const filterValue = (event.target as HTMLInputElement).value;
    this.dataSource.filter = filterValue.trim().toLowerCase();

    if (this.dataSource.paginator) {
      this.dataSource.paginator.firstPage();
    }
  }
}

My Customersmodel

export interface Customersmodel {
  id: number;
  company: string;
  contact: string;
  email: string;
  discount: string;
  actions: string;
}

Backend service for customers

@CrossOrigin(origins = "http://localhost:4200/customers")

@Service
public class CustomersService {

    private final CustomersRepository customersRepository;

    @Autowired
    public CustomersService(CustomersRepository customersRepository) {
        this.customersRepository = customersRepository;
    }
    public List <Customers> getCustomers() {
        return customersRepository.findAll();
    }

}

Frontend service for customers

@Injectable({
  providedIn: 'root'
})

export class CustomersService {

  private url = 'http://localhost:4200/customers';

  constructor(private httpClient: HttpClient) {
  }

 public getCustomers(): Observable<Customersmodel[]> {
    return this.httpClient.get<Customersmodel[]>(`${this.url}`);
  }
}

Controller for customers

@CrossOrigin(origins = "*")
@RequestMapping("/customers")

@RestController
public class CustomersController {

    @Autowired
    private final CustomersService customersService;

    public CustomersController (CustomersService customersService) {
        this.customersService = customersService;
    }
    @GetMapping("/customers")
    public ResponseEntity<List<Customers>> getCustomers() {
        List<Customers> customers = customersService.getCustomers();
        return new ResponseEntity<>(customers, HttpStatus.OK);
    }

Customers entity class

@Entity
@Table(name = "customers")

public class Customers implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)

    @Column(name ="id")
    private Long id;

    @Column(name = "company")
    private String company;

    @Column(name = "contact")
    private String contact;

    @Column(name = "email")
    private String email;

    @Column(name = "discount")
    private String discount;

    public Customers() {}

    public Customers(Long id, String company, String contact, String email, String discount) {
        super();
        this.id = id;
        this.company = company;
        this.contact = contact;
        this.email = email;
        this.discount = discount;

    }
    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }
    
    public String getCompany() {
        return company;
    }

    public void setCompany(String company) {
        this.company = company;
    }

    public String getContact() {
        return contact;
    }

    public void setContact(String contact) {
        this.contact = contact;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getDiscount() {
        return discount;
    }

    public void setDiscount(String discount) {
        this.discount = discount;
    }

@Override
public String toString() {

        return "Customers{"+
                "id=" + id +
                ", company=" + company + '\'' +
                ", contact=" + contact + '\'' +
                ", email=" + email + '\'' +
                ", discount=" + discount + '\'' +
                '}';

}
}

Repository

@Repository
@CrossOrigin(origins = "http://localhost:4200/")

public interface CustomersRepository extends JpaRepository<Customers, Long>{
    void deleteCustomersById(Long id);

    Optional <Customers> findCustomersById(Long id);
}

HTML

<mat-form-field appearance="outline" color="accent">
  <mat-label>Filtrera</mat-label>
 <input matInput (keyup)="applyFilter($event)" placeholder="Ex. Mia" #input>
</mat-form-field>

<div class="customers-table">
  <table mat-table [dataSource]="dataSource" matSort class="mat-elevation-z8" matSort matSortDisableClear>
    <ng-container matColumnDef="id">
      <th mat-header-cell *matHeaderCellDef mat-sort-header> ID </th>
      <td mat-cell *matCellDef="let element"> {{element.id}} </td>
    </ng-container>

    <ng-container matColumnDef="company">
      <th mat-header-cell *matHeaderCellDef mat-sort-header> Företag </th>
      <td mat-cell *matCellDef="let element"> {{element.company}} </td>
    </ng-container>

    <ng-container matColumnDef="contact">
      <th mat-header-cell *matHeaderCellDef mat-sort-header> Kontaktperson </th>
      <td mat-cell *matCellDef="let element"> {{element.contact}} </td>
    </ng-container>

    <ng-container matColumnDef="email">
      <th mat-header-cell *matHeaderCellDef mat-sort-header> Epost </th>
      <td mat-cell *matCellDef="let element"> {{element.email}} </td>
    </ng-container>

    <ng-container matColumnDef="discount">
      <th mat-header-cell *matHeaderCellDef mat-sort-header> Rabatt </th>
      <td mat-cell *matCellDef="let element"> {{element.discount}} </td>
    </ng-container>

    <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
    <tr mat-row *matRowDef="let element; columns: displayedColumns;"></tr>

     Row shown when there is no matching data.
    <tr class="mat-row" *matNoDataRow>
       <td class="mat-cell" colspan="4">Inget resultat för:  "{{input.value}}"</td>
    </tr>
  </table>
  <mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" aria-label="Föremål per sida" color="accent"></mat-paginator>
</div>


Solution 1:[1]

Based on your @RestController mappings. I believe it should be http://localhost:4200/customers/customers that you need to call. Unsure about the port though

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 grekier