Я создал простой банковский проект Spring Boot со следующими API-интерфейсами REST:
Код: Выделить всё
/create
/getAccount
/deposit
/withdraw
/deleteAccount
- API работают правильно и обновляют базу данных, как и ожидалось.
- Пользовательский интерфейс Swagger показывает все конечные точки как задумано.
- Тесты Postman также работают без проблем.
Не удалось загрузить определение API. Статус ответа — 500 /v3/api-docs
И вот что странно: когда я удаляю классы исключений, Swagger снова начинает работать! Итак, очевидно, что в настройке обработки исключений есть что-то, вызывающее эту проблему.
Может ли кто-нибудь помочь мне понять, что происходит не так?
Класс ErrorResponse:
Код: Выделить всё
package com.bank.bankingApplication.exceptions;
import java.time.LocalDateTime;
public class ErrorResponse {
private String message;
private String timestamp;
private String path;
public ErrorResponse(String message, String path) {
this.message = message;
this.timestamp = LocalDateTime.now().toString();
this.path = path;
}
// Getters and Setters
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
Код: Выделить всё
package com.bank.bankingApplication.exceptions;
import com.bank.bankingApplication.controller.BankController;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
@ControllerAdvice
@RestControllerAdvice(assignableTypes = {BankController.class})
public class GlobalExceptionHandler {
// @ExceptionHandler(Exception.class)
// public ResponseEntity handleAllExceptions(Exception ex, HttpServletRequest request) {
// ErrorResponse error = new ErrorResponse(ex.getMessage(), request.getRequestURI());
// return new ResponseEntity(error, HttpStatus.INTERNAL_SERVER_ERROR);
// }
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ResponseEntity handleTypeMismatch(MethodArgumentTypeMismatchException ex, HttpServletRequest request) {
String msg = "Invalid type for parameter: " + ex.getName();
ErrorResponse error = new ErrorResponse(msg, request.getRequestURI());
return new ResponseEntity(error, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity handleIllegalArgs(IllegalArgumentException ex, HttpServletRequest request) {
ErrorResponse error = new ErrorResponse(ex.getMessage(), request.getRequestURI());
return new ResponseEntity(error, HttpStatus.BAD_REQUEST);
}
// You can add more specific ones like @ExceptionHandler(AccountNotFoundException.class) here.
}
Код: Выделить всё
package com.bank.bankingApplication.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import com.bank.bankingApplication.model.Account;
import com.bank.bankingApplication.repository.AccountRepository;
import com.bank.bankingApplication.service.AccountService;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
@RestController
@RequestMapping("/bank")
@Tag(name = "Bank Controller", description = "Handles operations related to bank accounts")
public class BankController {
@Autowired
private AccountService accountService;
@Autowired
private AccountRepository accountRepository;
@Operation(
summary = "Create a new bank account",
description = "This endpoint is used to create a new bank account for a user."
)
@PostMapping("/create")
public Account createAccount(@RequestBody Account account){
return accountService.createAccount(account);
}
@Operation(
summary = "Fetches the existing bank account",
description = "This endpoint is used to fetch an existing bank account for a user."
)
@PostMapping("/getAccount")
public ResponseEntity getAccountDetails(@RequestBody Account account) {
Long id = account.getId();
Optional accountOpt = accountRepository.findById(id);
if (accountOpt.isPresent()) {
return ResponseEntity.ok(accountOpt.get());
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Account not found");
}
}
@Operation(
summary = "Deposits the amount",
description = "This endpoint is used to deposit amount for a user."
)
@PostMapping("/deposit")
public ResponseEntity deposit(@RequestBody DepositAndWithdrawRequest request) {
Optional optionalAccount = accountRepository.findById(request.getId());
if (optionalAccount.isPresent()) {
Account account = optionalAccount.get();
account.setBalance(account.getBalance() + request.getAmount());
accountRepository.save(account);
DepositAndWithdrawResponse response = new DepositAndWithdrawResponse();
response.setId(account.getId());
response.setAccountHolder(account.getAccountHolder());
response.setBalance(account.getBalance());
response.setRemarks("Deposit successful. New balance: " + account.getBalance());
return ResponseEntity.ok(response);
} else {
return ResponseEntity.notFound().build();
}
}
@Operation(
summary = "withdraws the amount",
description = "This endpoint is used to withdraw amount for a user."
)
@PostMapping("/withdraw")
public ResponseEntity withdraw(@RequestBody DepositAndWithdrawRequest request) {
Optional optionalAccount = accountRepository.findById(request.getId());
if (optionalAccount.isPresent()) {
Account account = optionalAccount.get();
if(account.getBalance() >= request.getAmount()){
account.setBalance(account.getBalance() - request.getAmount());
accountRepository.save(account);
DepositAndWithdrawResponse response = new DepositAndWithdrawResponse();
response.setId(account.getId());
response.setAccountHolder(account.getAccountHolder());
response.setBalance(account.getBalance());
response.setRemarks("Withdraw successful. New balance: " + account.getBalance());
return ResponseEntity.ok(response);
}
else{
account.setBalance(account.getBalance());
accountRepository.save(account);
DepositAndWithdrawResponse response = new DepositAndWithdrawResponse();
response.setId(account.getId());
response.setAccountHolder(account.getAccountHolder());
response.setBalance(account.getBalance());
response.setRemarks("Withdraw unsuccessful because entered amount was greater than the current balance: " + account.getBalance());
return ResponseEntity.ok(response);
}
} else {
return ResponseEntity.notFound().build();
}
}
@DeleteMapping("/deleteAccount")
@Operation(
summary = "Deletes an existing bank account",
description = "This endpoint is used to delete an existing bank account for a user."
)
public ResponseEntity deleteAccountById(@RequestBody Map request) {
Long id = request.get("id");
Optional account = accountRepository.findById(id);
if (account.isPresent()) {
accountRepository.deleteById(id);
return ResponseEntity.ok("Account with ID " + id + " has been deleted successfully.");
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Account with ID " + id + " not found.");
}
}
}
Код: Выделить всё
spring.datasource.url=jdbc:mysql://localhost:3306/bank
spring.datasource.username=root
spring.datasource.password=MyPassword
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
Код: Выделить всё
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
org.springframework.boot
spring-boot-starter-parent
3.4.4
com.bank
bankingApplication
0.0.1-SNAPSHOT
bankingApplication
Demo project for Spring Boot
21
org.springframework.boot
spring-boot-starter-data-jpa
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-devtools
runtime
true
com.mysql
mysql-connector-j
runtime
org.springframework.boot
spring-boot-starter-test
test
org.springdoc
springdoc-openapi-starter-webmvc-ui
2.3.0
org.springframework.boot
spring-boot-maven-plugin
Подробнее здесь: https://stackoverflow.com/questions/795 ... atus-is-50
Мобильная версия