Webhook URL 형식 검증 로직 분리 및 재사용성 개선:
eapim-portal CI / build (push) Has been cancelled
eapim-portal Test / test (push) Has been cancelled

- WebhookUrlValidator 추가: URL 형식 검증 전담
- Service/Controller에서 공통 Validator 활용하도록 수정
This commit is contained in:
Rinjae
2026-08-25 15:39:00 +09:00
parent a456ed9bb0
commit 80b072983f
6 changed files with 50 additions and 13 deletions
@@ -11,6 +11,7 @@ import com.eactive.apim.portal.djb.webhook.dto.WebhookDTO;
import com.eactive.apim.portal.djb.webhook.dto.WebhookRegistrationDTO;
import com.eactive.apim.portal.djb.webhook.service.WebhookEventTypeProvider;
import com.eactive.apim.portal.djb.webhook.service.WebhookService;
import com.eactive.apim.portal.djb.webhook.service.WebhookUrlValidator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -375,10 +376,9 @@ public class WebhookController {
private void validateStep1(WebhookRegistrationDTO dto, BindingResult bindingResult) {
String url = dto.getTargetUrl() == null ? "" : dto.getTargetUrl().trim();
if (!bindingResult.hasFieldErrors("targetUrl")
&& !url.startsWith("http://") && !url.startsWith("https://")) {
if (!bindingResult.hasFieldErrors("targetUrl") && !WebhookUrlValidator.isValid(url)) {
bindingResult.rejectValue("targetUrl", "invalid.url",
"URL은 http:// 또는 https:// 로 시작해야 합니다.");
"올바른 URL 형식이 아닙니다. http:// 또는 https:// 로 시작하는 전체 주소를 입력해주세요.");
}
if (dto.getEventTypes() == null || dto.getEventTypes().isEmpty()) {
bindingResult.rejectValue("eventTypes", "empty.eventTypes",
@@ -170,9 +170,8 @@ public class WebhookService {
}
private void validate(WebhookRegistrationDTO dto) {
String url = dto.getTargetUrl() == null ? "" : dto.getTargetUrl().trim();
if (!url.startsWith("http://") && !url.startsWith("https://")) {
throw new IllegalArgumentException("URL은 http:// 또는 https:// 로 시작해야 합니다.");
if (!WebhookUrlValidator.isValid(dto.getTargetUrl())) {
throw new IllegalArgumentException("올바른 URL 형식이 아닙니다. http:// 또는 https:// 로 시작하는 전체 주소를 입력해주세요.");
}
if (dto.getEventTypes() == null || dto.getEventTypes().isEmpty()) {
throw new IllegalArgumentException("EventType을 1개 이상 선택해주세요.");
@@ -0,0 +1,30 @@
package com.eactive.apim.portal.djb.webhook.service;
import java.net.URI;
import java.net.URISyntaxException;
/**
* Webhook 수신 URL 형식 검증. 컨트롤러(필드 에러 표시)와 서비스(방어적 재검증) 양쪽에서 공용으로 쓴다.
*
* http/https 스킴 + host 존재까지 확인한다("http://" 만 있고 host 가 없는 값 등을 차단).
* 순수 문법 검증만 하며, 실제 도달 가능성(DNS/네트워크)은 검사하지 않는다.
*/
public final class WebhookUrlValidator {
private WebhookUrlValidator() {
}
public static boolean isValid(String url) {
if (url == null || url.trim().isEmpty()) {
return false;
}
try {
URI uri = new URI(url.trim());
String scheme = uri.getScheme();
return ("http".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme))
&& uri.getHost() != null && !uri.getHost().isEmpty();
} catch (URISyntaxException e) {
return false;
}
}
}
+8 -6
View File
@@ -25733,29 +25733,31 @@ input[type=checkbox]:checked + .custom-checkbox {
padding: 24px 16px 60px;
font-family: "Spoqa Han Sans Neo", "Noto Sans CJK KR", sans-serif;
}
.webhook-container .field-help {
.step1-wrap .field-help {
color: #64748b;
font-size: 13px;
margin-top: 6px;
}
.webhook-container .field-help-red {
.step1-wrap .field-help-red {
color: #f4253c;
font-size: 13px;
margin-top: 6px;
font-weight: 500;
}
@media (max-width: 768px) {
.webhook-container .field-help-red {
.step1-wrap .field-help-red {
font-size: 11px;
}
}
.webhook-container .field-error,
.webhook-container .webhook-field-error {
.step1-wrap .field-error,
.step1-wrap .webhook-field-error {
color: #f4253c;
font-size: 13px;
font-weight: 600;
margin-top: 6px;
}
.webhook-container .req {
.step1-wrap .req {
color: #f4253c;
}
File diff suppressed because one or more lines are too long
@@ -14,7 +14,12 @@ $wh-bg-soft: #f9f9f9;
margin: 0 auto;
padding: 24px 16px 60px;
font-family: 'Spoqa Han Sans Neo', 'Noto Sans CJK KR', sans-serif;
}
// 실제 페이지 마크업은 .webhook-container 가 아닌 .step1-wrap 으로 감싸여 있어
// (webhookRegisterStep1/webhookModifyStep1/webhookList 공통) 여기로 스코프한다.
// 위 .webhook-container 블록은 미사용이라 색상 규칙이 전혀 적용되지 않았었다.
.step1-wrap {
.field-help {
color: $wh-muted;
font-size: 13px;
@@ -36,6 +41,7 @@ $wh-bg-soft: #f9f9f9;
.webhook-field-error {
color: $wh-danger;
font-size: 13px;
font-weight: 600;
margin-top: 6px;
}