Add: custom Exception for fine-grain error handling. Add: env variables for deploying in prod.
This commit is contained in:
@@ -2,24 +2,55 @@
|
||||
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>net.miarma</groupId>
|
||||
<artifactId>backend</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<artifactId>backlib</artifactId>
|
||||
<groupId>net.miarma</groupId>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<properties>
|
||||
<java.version>25</java.version>
|
||||
<spring.boot.version>4.0.1</spring.boot.version>
|
||||
<maven.compiler.source>25</maven.compiler.source>
|
||||
<maven.compiler.target>25</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>MiarmaGit</id>
|
||||
<url>https://git.miarma.net/api/packages/Gallardo7761/maven</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>MiarmaGit</id>
|
||||
<url>https://git.miarma.net/api/packages/Gallardo7761/maven</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>MiarmaGit</id>
|
||||
<url>https://git.miarma.net/api/packages/Gallardo7761/maven</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring Boot -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
@@ -33,22 +64,6 @@
|
||||
<artifactId>mariadb-java-client</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.validation</groupId>
|
||||
<artifactId>jakarta.validation-api</artifactId>
|
||||
<version>3.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>8.0.0.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.42</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
@@ -72,11 +87,5 @@
|
||||
<version>0.11.5</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.miarma</groupId>
|
||||
<artifactId>backlib</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,65 @@
|
||||
package net.miarma.backlib.dto;
|
||||
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
public class ApiErrorDto {
|
||||
private int status;
|
||||
private String error;
|
||||
private String message;
|
||||
private String path;
|
||||
private Instant timestamp;
|
||||
|
||||
public ApiErrorDto(int status, String error, String message, String path) {
|
||||
this.status = status;
|
||||
this.error = error;
|
||||
this.message = message;
|
||||
this.path = path;
|
||||
this.timestamp = Instant.now();
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public void setError(String error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public Instant getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(Instant timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public String toJson() {
|
||||
return new ObjectMapper().writeValueAsString(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.miarma.backlib.exception;
|
||||
|
||||
public class BadRequestException extends RuntimeException {
|
||||
public BadRequestException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.miarma.backlib.exception;
|
||||
|
||||
public class ConflictException extends RuntimeException {
|
||||
public ConflictException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.miarma.backlib.exception;
|
||||
|
||||
public class ForbiddenException extends RuntimeException {
|
||||
public ForbiddenException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package net.miarma.backlib.exception;
|
||||
|
||||
public class NotFoundException extends RuntimeException {
|
||||
public NotFoundException(String message) { super(message); }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.miarma.backlib.exception;
|
||||
|
||||
public class UnauthorizedException extends RuntimeException {
|
||||
public UnauthorizedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.miarma.backlib.exception;
|
||||
|
||||
public class ValidationException extends RuntimeException {
|
||||
public ValidationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package net.miarma.backlib.http;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import net.miarma.backlib.dto.ApiErrorDto;
|
||||
import net.miarma.backlib.exception.*;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
@ExceptionHandler(NotFoundException.class)
|
||||
public ResponseEntity<ApiErrorDto> handleNotFound(
|
||||
NotFoundException ex, HttpServletRequest req) {
|
||||
|
||||
ApiErrorDto error = new ApiErrorDto(
|
||||
HttpStatus.NOT_FOUND.value(),
|
||||
HttpStatus.NOT_FOUND.getReasonPhrase(),
|
||||
ex.getMessage(),
|
||||
req.getRequestURI()
|
||||
);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
|
||||
}
|
||||
|
||||
@ExceptionHandler(BadRequestException.class)
|
||||
public ResponseEntity<ApiErrorDto> handleBadRequest(
|
||||
BadRequestException ex, HttpServletRequest req) {
|
||||
|
||||
ApiErrorDto error = new ApiErrorDto(
|
||||
HttpStatus.BAD_REQUEST.value(),
|
||||
HttpStatus.BAD_REQUEST.getReasonPhrase(),
|
||||
ex.getMessage(),
|
||||
req.getRequestURI()
|
||||
);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
|
||||
}
|
||||
|
||||
@ExceptionHandler(UnauthorizedException.class)
|
||||
public ResponseEntity<ApiErrorDto> handleUnauthorized(
|
||||
UnauthorizedException ex, HttpServletRequest req) {
|
||||
|
||||
ApiErrorDto error = new ApiErrorDto(
|
||||
HttpStatus.UNAUTHORIZED.value(),
|
||||
HttpStatus.UNAUTHORIZED.getReasonPhrase(),
|
||||
ex.getMessage(),
|
||||
req.getRequestURI()
|
||||
);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(error);
|
||||
}
|
||||
|
||||
@ExceptionHandler(ForbiddenException.class)
|
||||
public ResponseEntity<ApiErrorDto> handleForbidden(
|
||||
ForbiddenException ex, HttpServletRequest req) {
|
||||
|
||||
ApiErrorDto error = new ApiErrorDto(
|
||||
HttpStatus.FORBIDDEN.value(),
|
||||
HttpStatus.FORBIDDEN.getReasonPhrase(),
|
||||
ex.getMessage(),
|
||||
req.getRequestURI()
|
||||
);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(error);
|
||||
}
|
||||
|
||||
@ExceptionHandler(ConflictException.class)
|
||||
public ResponseEntity<ApiErrorDto> handleConflict(
|
||||
ConflictException ex, HttpServletRequest req) {
|
||||
|
||||
ApiErrorDto error = new ApiErrorDto(
|
||||
HttpStatus.CONFLICT.value(),
|
||||
HttpStatus.CONFLICT.getReasonPhrase(),
|
||||
ex.getMessage(),
|
||||
req.getRequestURI()
|
||||
);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CONFLICT).body(error);
|
||||
}
|
||||
|
||||
@ExceptionHandler(ValidationException.class)
|
||||
public ResponseEntity<ApiErrorDto> handleValidation(
|
||||
ValidationException ex, HttpServletRequest req) {
|
||||
|
||||
ApiErrorDto error = new ApiErrorDto(
|
||||
HttpStatus.UNPROCESSABLE_CONTENT.value(),
|
||||
HttpStatus.UNPROCESSABLE_CONTENT.getReasonPhrase(),
|
||||
ex.getMessage(),
|
||||
req.getRequestURI()
|
||||
);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.UNPROCESSABLE_CONTENT).body(error);
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<ApiErrorDto> handleAll(
|
||||
Exception ex, HttpServletRequest req) {
|
||||
|
||||
ApiErrorDto error = new ApiErrorDto(
|
||||
HttpStatus.INTERNAL_SERVER_ERROR.value(),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(),
|
||||
"Internal server error",
|
||||
req.getRequestURI()
|
||||
);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package net.miarma.backlib.http;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import net.miarma.backlib.dto.ApiErrorDto;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
public class RestAccessDeniedHandler implements AccessDeniedHandler {
|
||||
|
||||
@Override
|
||||
public void handle(HttpServletRequest request, HttpServletResponse response,
|
||||
AccessDeniedException accessDeniedException) throws IOException {
|
||||
|
||||
ApiErrorDto error = new ApiErrorDto(
|
||||
HttpStatus.FORBIDDEN.value(),
|
||||
HttpStatus.FORBIDDEN.getReasonPhrase(),
|
||||
"Forbidden",
|
||||
request.getRequestURI()
|
||||
);
|
||||
|
||||
response.setStatus(HttpStatus.FORBIDDEN.value());
|
||||
response.setContentType("application/json");
|
||||
response.getWriter().write(error.toJson());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package net.miarma.backlib.http;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import net.miarma.backlib.dto.ApiErrorDto;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
public class RestAuthEntryPoint implements AuthenticationEntryPoint {
|
||||
|
||||
@Override
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException authException) throws IOException {
|
||||
|
||||
ApiErrorDto error = new ApiErrorDto(
|
||||
HttpStatus.UNAUTHORIZED.value(),
|
||||
HttpStatus.UNAUTHORIZED.getReasonPhrase(),
|
||||
"Unauthorized",
|
||||
request.getRequestURI()
|
||||
);
|
||||
|
||||
response.setStatus(HttpStatus.UNAUTHORIZED.value());
|
||||
response.setContentType("application/json");
|
||||
response.getWriter().write(error.toJson());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,10 +34,6 @@ public class JwtService {
|
||||
|
||||
@PostConstruct
|
||||
public void init() throws Exception {
|
||||
System.out.println("user.name = " + System.getProperty("user.name"));
|
||||
System.out.println("user.home = " + System.getProperty("user.home"));
|
||||
System.out.println("privateKeyPath = " + privateKeyPath);
|
||||
|
||||
this.privateKey = loadPrivateKey(privateKeyPath);
|
||||
this.publicKey = loadPublicKey(publicKeyPath);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user