Added SignalServerException; Update ExceptionUtils and GlobalExceptionHandler; Used ExceptionUtils in SignalFacade instead of throwing SignalErrorException

This commit is contained in:
Mikhail Trofimov 2025-07-01 20:23:01 +03:00
parent fb8da59b1b
commit 43897c6cbb
8 changed files with 101 additions and 117 deletions

View file

@ -1,39 +1,25 @@
package ru.nbch.credit_tracker.config.rest;
import java.nio.charset.Charset;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import ru.nbch.credit_tracker.entities.response.errors.CommonError;
import ru.nbch.credit_tracker.entities.response.errors.MonitoringActivePackagesError;
import ru.nbch.credit_tracker.entities.response.errors.MonitoringDownloadError;
import ru.nbch.credit_tracker.entities.response.errors.MonitoringError;
import ru.nbch.credit_tracker.entities.response.errors.MonitoringPackageDeleteError;
import ru.nbch.credit_tracker.entities.response.errors.MonitoringReportListError;
import ru.nbch.credit_tracker.entities.response.errors.*;
import ru.nbch.credit_tracker.exceptions.SignalClientException;
import ru.nbch.credit_tracker.exceptions.SignalErrorException;
import ru.nbch.credit_tracker.exceptions.SignalException;
import ru.nbch.credit_tracker.utils.error.SimpleMessageResolver;
import java.nio.charset.Charset;
@RestControllerAdvice
public class GlobalExceptionHandler {
private final SimpleMessageResolver messageResolver = new SimpleMessageResolver();
@ExceptionHandler(value = SignalErrorException.class, produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<CommonError> handleInvalidUser(SignalErrorException ex) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType("application", "xml", Charset.forName("windows-1251")));
if (ex.isUserError()) {
return new ResponseEntity<>(ex.getError(), headers, HttpStatus.BAD_REQUEST);
} else {
return new ResponseEntity<>(ex.getError(), headers, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@ExceptionHandler(value = SignalClientException.class, produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<CommonError> handleClientException(SignalClientException ex) {
@ExceptionHandler(value = SignalException.class, produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<CommonError> handleClientException(SignalException ex) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType("application", "xml", Charset.forName("windows-1251")));
CommonError commonError = getCommonError(ex);
@ -41,10 +27,14 @@ public class GlobalExceptionHandler {
commonError.setErrorCode(ex.getErrorMessage().getSubject().getErrorCode());
commonError.setErrorText(messageResolver.resolve(ex.getErrorMessage()));
if (ex instanceof SignalClientException) {
return new ResponseEntity<>(commonError, headers, HttpStatus.BAD_REQUEST);
} else {
return new ResponseEntity<>(commonError, headers, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
private static CommonError getCommonError(SignalClientException ex) {
private static CommonError getCommonError(SignalException ex) {
CommonError commonError;
switch (ex.getErrorFormat()) {
case MonitoringError -> commonError = new MonitoringError();

View file

@ -5,14 +5,9 @@ import ru.nbch.credit_tracker.enums.EnumKeyMessage;
import ru.nbch.credit_tracker.enums.XmlErrorFormat;
@Getter
public class SignalClientException extends RuntimeException {
public class SignalClientException extends SignalException {
private final EnumKeyMessage errorMessage;
private final XmlErrorFormat errorFormat;
public SignalClientException(EnumKeyMessage errorMessage,
XmlErrorFormat errorFormat) {
this.errorMessage = errorMessage;
this.errorFormat = errorFormat;
public SignalClientException(EnumKeyMessage errorMessage, XmlErrorFormat errorFormat) {
super(errorMessage, errorFormat);
}
}

View file

@ -1,29 +0,0 @@
package ru.nbch.credit_tracker.exceptions;
import lombok.Getter;
import ru.nbch.credit_tracker.entities.response.errors.CommonError;
import ru.nbch.credit_tracker.enums.SignalError;
@Getter
public class SignalErrorException extends RuntimeException {
private final boolean isUserError;
private final CommonError error;
public SignalErrorException(SignalError signalError, String tag, CommonError error, boolean isUserError) {
this.isUserError = isUserError;
this.error = createErrorMessage(error, signalError, tag);
}
private CommonError createErrorMessage(CommonError errorMessage, SignalError error, String tag) {
errorMessage.setStatus("error");
errorMessage.setErrorCode(error.getCode());
if (tag != null) {
errorMessage.setErrorText(error.getKey() + " " + tag);
} else {
errorMessage.setErrorText(error.getKey());
}
return errorMessage;
}
}

View file

@ -0,0 +1,17 @@
package ru.nbch.credit_tracker.exceptions;
import lombok.Getter;
import ru.nbch.credit_tracker.enums.EnumKeyMessage;
import ru.nbch.credit_tracker.enums.XmlErrorFormat;
@Getter
public class SignalException extends RuntimeException {
private final EnumKeyMessage errorMessage;
private final XmlErrorFormat errorFormat;
public SignalException(EnumKeyMessage errorMessage,
XmlErrorFormat errorFormat) {
this.errorMessage = errorMessage;
this.errorFormat = errorFormat;
}
}

View file

@ -0,0 +1,12 @@
package ru.nbch.credit_tracker.exceptions;
import ru.nbch.credit_tracker.enums.EnumKeyMessage;
import ru.nbch.credit_tracker.enums.XmlErrorFormat;
public class SignalServerException extends SignalException {
public SignalServerException(EnumKeyMessage errorMessage, XmlErrorFormat errorFormat) {
super(errorMessage, errorFormat);
}
}

View file

@ -12,7 +12,6 @@ import ru.nbch.credit_tracker.entities.request.active_packages.MonitoringActiveP
import ru.nbch.credit_tracker.entities.request.monitoring_request.MonitoringRequest;
import ru.nbch.credit_tracker.entities.request.monitoring_request.Subject;
import ru.nbch.credit_tracker.entities.response.active_packages.MonitoringActivePackagesResponse;
import ru.nbch.credit_tracker.entities.response.errors.*;
import ru.nbch.credit_tracker.entities.response.success.MonitoringPackageDeleteResponse;
import ru.nbch.credit_tracker.entities.response.success.MonitoringReportListResponse;
import ru.nbch.credit_tracker.entities.response.success.MonitoringResponse;
@ -21,7 +20,6 @@ import ru.nbch.credit_tracker.enums.SignalError;
import ru.nbch.credit_tracker.enums.Status;
import ru.nbch.credit_tracker.enums.XmlErrorFormat;
import ru.nbch.credit_tracker.exceptions.SignalClientException;
import ru.nbch.credit_tracker.exceptions.SignalErrorException;
import ru.nbch.credit_tracker.service.SignalService;
import ru.nbch.credit_tracker.service.indic.PhoneService;
import ru.nbch.credit_tracker.service.scoring.AuthorizationService;
@ -42,7 +40,8 @@ import java.util.concurrent.ExecutorService;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.excp;
import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.clientExcp;
import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.serverExcp;
@Slf4j
@Service
@ -74,12 +73,8 @@ public class SignalFacade {
public ResponseEntity<MonitoringResponse> setupMonitoring(MultipartFile file) {
// первичные валидации
if (file.isEmpty()) {
throw new SignalErrorException(SignalError.ERROR_001, null, new MonitoringError(), true);
}
if (!isZipFile(file)) {
throw new SignalErrorException(SignalError.ERROR_001, null, new MonitoringError(), true);
if (file.isEmpty() || !isZipFile(file)) {
throw clientExcp(SignalError.ERROR_001, XmlErrorFormat.MonitoringError);
}
// Валидация Архива на количетсво файлов, размер и расширение
@ -90,10 +85,10 @@ public class SignalFacade {
zipInputStream = new ZipInputStream(file.getInputStream());
Optional<ZipEntry> xmlFileEntry = ZipUtils.extractValidEntry(zipInputStream);
if (xmlFileEntry.isEmpty()) {
throw excp(SignalError.ERROR_001, XmlErrorFormat.MonitoringError);
throw clientExcp(SignalError.ERROR_001, XmlErrorFormat.MonitoringError);
}
if (xmlFileEntry.get().getSize() > MAX_XML_FILE_SIZE) {
throw excp(SignalError.ERROR_009, XmlErrorFormat.MonitoringError);
throw clientExcp(SignalError.ERROR_009, XmlErrorFormat.MonitoringError);
}
zipInputStream.close();
@ -108,7 +103,7 @@ public class SignalFacade {
}
log.error(e.getMessage(), e);
//todo throw new SignalServerException(e);
throw excp(SignalError.ERROR_100, XmlErrorFormat.MonitoringError);
throw clientExcp(SignalError.ERROR_100, XmlErrorFormat.MonitoringError);
} finally {
if (zipInputStream != null) {
try {
@ -124,7 +119,7 @@ public class SignalFacade {
// валидация xml
try {
validateMonitoringRequest(monitoringRequest);
} catch (SignalErrorException e) {
} catch (SignalClientException e) {
signalService.rejectPackage(monitoringRequest);
throw e;
}
@ -134,22 +129,22 @@ public class SignalFacade {
AuthorizationService.AuthResult authResult = authorizationService.findAuthInfo(monitoringRequest.getUserId(), monitoringRequest.getPassword());
if (!authResult.isSuccess()) {
signalService.rejectPackage(monitoringRequest);
throw new SignalErrorException(authResult.getError(), null, new MonitoringError(), true);
throw clientExcp(authResult.getError(), XmlErrorFormat.MonitoringError);
}
// проверка на уникальность пакета
if (signalService.isPackageNotUnique(monitoringRequest)) {
signalService.rejectPackage(monitoringRequest);
throw new SignalErrorException(SignalError.ERROR_007, null, new MonitoringError(), true);
throw clientExcp(SignalError.ERROR_007, XmlErrorFormat.MonitoringError);
}
packageId = signalService.registerPackage(monitoringRequest);
} catch (Exception e) {
if (e instanceof SignalErrorException) {
throw (SignalErrorException) e;
if (e instanceof SignalClientException) {
throw (SignalClientException) e;
}
log.error(e.getMessage(), e);
throw new SignalErrorException(SignalError.ERROR_100, null, new MonitoringError(), false);
throw serverExcp(SignalError.ERROR_100, XmlErrorFormat.MonitoringError);
}
// в отдельном потоке запускаем поиск фидов и расчет флагов просрочек
@ -158,9 +153,9 @@ public class SignalFacade {
return ResponseEntity.ok().body(new MonitoringResponse());
}
private void validateMonitoringRequest(MonitoringRequest request) throws SignalErrorException {
private void validateMonitoringRequest(MonitoringRequest request) throws SignalClientException {
if (request == null) {
throw new SignalErrorException(SignalError.ERROR_011, null, new MonitoringError(), true);
throw clientExcp(SignalError.ERROR_011, XmlErrorFormat.MonitoringError);
}
validateReruqredTags(request);
@ -168,44 +163,44 @@ public class SignalFacade {
validateTagsTypes(request);
}
private void validateReruqredTags(MonitoringRequest request) throws SignalErrorException {
private void validateReruqredTags(MonitoringRequest request) throws SignalClientException {
if (request.getUserId() == null) {
throw new SignalErrorException(SignalError.ERROR_002, "UserId", new MonitoringError(), true);
throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "UserId");
}
if (request.getPackageName() == null) {
throw new SignalErrorException(SignalError.ERROR_002, "PackageName", new MonitoringError(), true);
throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "PackageName");
}
if (request.getPassword() == null) {
throw new SignalErrorException(SignalError.ERROR_002, "Password", new MonitoringError(), true);
throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "Password");
}
if (request.getSubjects() == null) {
throw new SignalErrorException(SignalError.ERROR_002, "Subjects", new MonitoringError(), true);
throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "Subjects");
}
if (request.getSubjects().getSubject().isEmpty()) {
throw new SignalErrorException(SignalError.ERROR_002, "Subject", new MonitoringError(), true);
throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "Subject");
}
}
private void validateTagsTypes(MonitoringRequest request) throws SignalErrorException {
private void validateTagsTypes(MonitoringRequest request) throws SignalClientException {
if (!ValidationUtil.validatePackageName(request.getPackageName())) {
throw new SignalErrorException(SignalError.ERROR_008, null, new MonitoringError(), true);
throw clientExcp(SignalError.ERROR_008, XmlErrorFormat.MonitoringError, "Subject");
}
Set<String> uniqueIds = new HashSet<>();
for (Subject subject : request.getSubjects().getSubject()) {
if (!ValidationUtil.validatePhone(subject.getClientId())) {
throw new SignalErrorException(SignalError.ERROR_003, null, new MonitoringError(), true);
throw clientExcp(SignalError.ERROR_003, XmlErrorFormat.MonitoringError);
}
if (!ValidationUtil.validateNPId(subject.getId())) {
throw new SignalErrorException(SignalError.ERROR_010, null, new MonitoringError(), true);
throw clientExcp(SignalError.ERROR_010, XmlErrorFormat.MonitoringError);
}
// проверка на уникальность Id внутри одного пакета
if (!uniqueIds.add(subject.getId())) {
throw new SignalErrorException(SignalError.ERROR_004, subject.getId(), new MonitoringError(), true);
throw clientExcp(SignalError.ERROR_004, XmlErrorFormat.MonitoringError, subject.getId());
}
}
}
@ -242,27 +237,27 @@ public class SignalFacade {
try {
AuthorizationService.AuthResult authResult = authorizationService.findAuthInfo(activePackagesRequest.getUserId(), activePackagesRequest.getPassword());
if (!authResult.isSuccess()) {
throw new SignalErrorException(authResult.getError(), null, new MonitoringActivePackagesError(), true);
throw clientExcp(authResult.getError(), XmlErrorFormat.MonitoringActivePackagesError);
}
MonitoringActivePackagesResponse response = signalService.findActivePackages(activePackagesRequest.getUserId());
if (response != null) {
return ResponseEntity.ok(response);
} else {
throw new SignalErrorException(SignalError.ERROR_015, null, new MonitoringActivePackagesError(), true);
throw clientExcp(SignalError.ERROR_015, XmlErrorFormat.MonitoringActivePackagesError);
}
} catch (Exception e) {
if (e instanceof SignalErrorException) {
throw (SignalErrorException) e;
if (e instanceof SignalClientException) {
throw (SignalClientException) e;
}
log.error(e.getMessage(), e);
throw new SignalErrorException(SignalError.ERROR_013, null, new MonitoringActivePackagesError(), false);
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringActivePackagesError);
}
}
public ResponseEntity<MonitoringPackageDeleteResponse> deletePackage(String username, String packageName) {
try {
if (!signalService.isPackageExists(username, packageName)) {
throw new SignalErrorException(SignalError.ERROR_016, packageName, new MonitoringPackageDeleteError(), true);
throw clientExcp(SignalError.ERROR_016, XmlErrorFormat.MonitoringPackageDeleteError, packageName);
}
MonitoringPackageDeleteResponse response = signalService.deletePackage(username, packageName);
@ -270,18 +265,18 @@ public class SignalFacade {
log.info("Package {} deleted", packageName);
return ResponseEntity.ok(response);
} catch (Exception e) {
if (e instanceof SignalErrorException) {
throw (SignalErrorException) e;
if (e instanceof SignalClientException) {
throw (SignalClientException) e;
}
log.error(e.getMessage(), e);
throw new SignalErrorException(SignalError.ERROR_017, null, new MonitoringPackageDeleteError(), false);
throw serverExcp(SignalError.ERROR_017, XmlErrorFormat.MonitoringPackageDeleteError);
}
}
public ResponseEntity<MonitoringReportListResponse> getReportList(String username, String packageName) {
try {
if (!signalService.isPackageExists(username, packageName)) {
throw new SignalErrorException(SignalError.ERROR_016, packageName, new MonitoringReportListError(), true);
throw clientExcp(SignalError.ERROR_016, XmlErrorFormat.MonitoringReportListError, packageName);
}
String memberCode = username.substring(0, 6);
@ -293,7 +288,7 @@ public class SignalFacade {
MonitoringReportListResponse.Reports reports = new MonitoringReportListResponse.Reports();
File[] files = folder.listFiles();
if (files == null) {
throw new SignalErrorException(SignalError.ERROR_012, packageName, new MonitoringReportListError(), true);
throw clientExcp(SignalError.ERROR_012, XmlErrorFormat.MonitoringReportListError, packageName);
}
for (File file : files) {
if (file.isFile() && file.getName().startsWith(filePrefix)) {
@ -302,7 +297,7 @@ public class SignalFacade {
}
if (reports.getReports().isEmpty()) {
throw new SignalErrorException(SignalError.ERROR_012, packageName, new MonitoringReportListError(), true);
throw clientExcp(SignalError.ERROR_012, XmlErrorFormat.MonitoringReportListError, packageName);
} else {
MonitoringReportListResponse response = new MonitoringReportListResponse();
response.setPackageName(packageName);
@ -311,14 +306,14 @@ public class SignalFacade {
}
} else {
log.error("Пакет {} был найден в бд для memberCode {}, но ни одного архива не было найдено в папке {}", packageName, username, dirPath);
throw new SignalErrorException(SignalError.ERROR_013, packageName, new MonitoringReportListError(), true);
throw clientExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringReportListError, packageName);
}
} catch (Exception e) {
if (e instanceof SignalErrorException) {
throw (SignalErrorException) e;
if (e instanceof SignalClientException) {
throw (SignalClientException) e;
}
log.error(e.getMessage(), e);
throw new SignalErrorException(SignalError.ERROR_013, null, new MonitoringReportListError(), false);
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringReportListError);
}
}
@ -334,15 +329,15 @@ public class SignalFacade {
return ResponseEntity.ok().body(new FileUrlResource(file.getPath()));
}
} else {
throw new SignalErrorException(SignalError.ERROR_014, null, new MonitoringDownloadError(), true);
throw clientExcp(SignalError.ERROR_014, XmlErrorFormat.MonitoringDownloadError);
}
throw new SignalErrorException(SignalError.ERROR_014, null, new MonitoringDownloadError(), true);
throw clientExcp(SignalError.ERROR_014, XmlErrorFormat.MonitoringDownloadError);
} catch (Exception e) {
if (e instanceof SignalErrorException) {
throw (SignalErrorException) e;
if (e instanceof SignalClientException) {
throw (SignalClientException) e;
}
log.error(e.getMessage(), e);
throw new SignalErrorException(SignalError.ERROR_013, null, new MonitoringDownloadError(), false);
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringDownloadError);
}
}
}

View file

@ -4,12 +4,15 @@ import ru.nbch.credit_tracker.enums.EnumKeyMessage;
import ru.nbch.credit_tracker.enums.IEnumKeyCode;
import ru.nbch.credit_tracker.enums.XmlErrorFormat;
import ru.nbch.credit_tracker.exceptions.SignalClientException;
import ru.nbch.credit_tracker.exceptions.SignalServerException;
public class ExceptionUtils {
// public static SignalClientException excp(IEnumKeyCode enumKeyCode, XmlErrorFormat xmlErrorFormat) {
// return new SignalClientException(new EnumKeyMessage(enumKeyCode), xmlErrorFormat);
// }
public static SignalClientException excp(IEnumKeyCode enumKeyCode, XmlErrorFormat xmlErrorFormat, Object... args) {
public static SignalClientException clientExcp(IEnumKeyCode enumKeyCode, XmlErrorFormat xmlErrorFormat, Object... args) {
return new SignalClientException(new EnumKeyMessage(enumKeyCode, args), xmlErrorFormat);
}
public static SignalServerException serverExcp(IEnumKeyCode enumKeyCode, XmlErrorFormat xmlErrorFormat, Object... args) {
return new SignalServerException(new EnumKeyMessage(enumKeyCode, args), xmlErrorFormat);
}
}

View file

@ -1,12 +1,13 @@
package ru.nbch.credit_tracker.utils.error;
import java.util.Arrays;
import ru.nbch.credit_tracker.enums.EnumKeyMessage;
import java.util.Arrays;
public class SimpleMessageResolver {
public String resolve(EnumKeyMessage errorMessage) {
if (errorMessage == null) return "null";
return String.format("(%s) args %s", errorMessage.getSubject().getKey(), Arrays.toString(errorMessage.getArgs()));
return String.format("%s %s", errorMessage.getSubject().getKey(), Arrays.toString(errorMessage.getArgs()));
}
}