1. 개요
이 예제에서는 Thymeleaf 템플릿 의 Spring 기반 백엔드 애플리케이션에서 발생한 오류 메시지를 표시하는 방법을 살펴보겠습니다 .
데모 목적으로 간단한 Spring Boot 사용자 등록 앱을 만들고 개별 입력 필드의 유효성을 검사합니다. 또한 전역 수준 오류를 처리하는 방법의 예를 살펴보겠습니다.
먼저 백엔드 앱을 빠르게 설정한 다음 UI 부분으로 이동합니다.
2. 샘플 스프링 부트 애플리케이션
사용자 등록을 위한 간단한 Spring Boot 앱을 만들려면 컨트롤러, 리포지토리 및 엔터티가 필요합니다 .
그러나 그 전에도 Maven 의존성을 추가해야 합니다.
2.1. 메이븐 의존성
필요한 모든 Spring Boot 스타터 (MVC 비트용 Web , Hibernate 엔터티 유효성 검사용 유효성 검사, UI 용 Thymeleaf 및 리포지토리용 JPA )를 추가해 보겠습니다 . 또한 메모리 내 데이터베이스를 보유하려면 H2 의존성이 필요합니다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
<version>1.4.200</version>
</dependency>
2.2. 엔티티
사용자 엔터티 는 다음과 같습니다 .
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@NotEmpty(message = "User's name cannot be empty.")
@Size(min = 5, max = 250)
private String fullName;
@NotEmpty(message = "User's email cannot be empty.")
private String email;
@NotNull(message = "User's age cannot be null.")
@Min(value = 18)
private Integer age;
private String country;
private String phoneNumber;
// getters and setters
}
볼 수 있듯이 사용자 입력에 대한 여러 유효성 검사 제약 조건 이 추가되었습니다 . 예를 들어, 필드는 null이거나 비어 있으면 안 되며 특정 크기나 값을 가져야 합니다.
특히 국가 또는 전화번호 필드 에 제약 조건을 추가하지 않았습니다 . 전역 오류 또는 특정 필드에 연결되지 않은 오류를 생성하기 위한 예제로 사용하기 때문입니다.
2.3. 리포지토리
기본 사용 사례에 대해 간단한 JPA 리포지토리 를 사용합니다.
@Repository
public interface UserRepository extends JpaRepository<User, Long> {}
2.4. 컨트롤러
마지막으로 백엔드에서 모든 것을 함께 연결하기 위해 UserController 를 함께 구성해 보겠습니다 .
@Controller
public class UserController {
@Autowired
private UserRepository repository;
@GetMapping("/add")
public String showAddUserForm(User user) {
return "errors/addUser";
}
@PostMapping("/add")
public String addUser(@Valid User user, BindingResult result, Model model) {
if (result.hasErrors()) {
return "errors/addUser";
}
repository.save(user);
model.addAttribute("users", repository.findAll());
return "errors/home";
}
}
여기서 우리는 등록 양식을 표시하기 위해 /add 경로에서 GetMapping 을 정의하고 있습니다. 동일한 경로 의 PostMapping 은 양식이 제출될 때 유효성 검사를 처리하고 모든 것이 잘되면 저장소에 저장합니다.
3. 오류 메시지가 있는 Thymeleaf 템플릿
이제 기본 사항을 다루었으므로 문제의 핵심, 즉 UI 템플릿을 만들고 오류 메시지가 있는 경우 표시하는 문제에 도달했습니다.
표시할 수 있는 오류 유형에 따라 조금씩 템플릿을 구성해 보겠습니다 .
3.1. 필드 오류 표시
Thymeleaf는 주어진 필드에 오류가 있는지 여부에 따라 부울을 반환 하는 내장된 field.hasErrors 메서드를 제공합니다. th:if 와 결합하면 오류가 있는 경우 표시하도록 선택할 수 있습니다.
<p th:if="${#fields.hasErrors('age')}">Invalid Age</p>
다음으로 스타일을 추가하려면 조건부 로 th:class 를 사용할 수 있습니다 .
<p th:if="${#fields.hasErrors('age')}" th:class="${#fields.hasErrors('age')}? error">
Invalid Age</p>
우리의 간단한 포함된 CSS 클래스 오류 는 요소를 빨간색으로 바꿉니다.
<style>
.error {
color: red;
}
</style>
Thymeleaf의 또 다른 속성인 th:errors 는 이메일과 같이 지정된 선택자에 모든 오류를 표시하는 기능을 제공합니다 .
<div>
<label for="email">Email</label> <input type="text" th:field="*{email}" />
<p th:if="${#fields.hasErrors('email')}" th:errorclass="error" th:errors="*{email}" />
</div>
위 스니펫에서 CSS 스타일 사용의 변형도 볼 수 있습니다. 여기서 우리는 th:errorclass 를 사용하고 있는데, CSS를 적용하기 위해 조건부 속성을 사용할 필요가 없습니다 .
또는 th:each 를 사용하여 주어진 필드의 모든 유효성 검사 메시지를 반복하도록 선택할 수 있습니다 .
<div>
<label for="fullName">Name</label> <input type="text" th:field="*{fullName}"
id="fullName" placeholder="Full Name">
<ul>
<li th:each="err : ${#fields.errors('fullName')}" th:text="${err}" class="error" />
</ul>
</div>
특히 fullName 필드 에 대해 백엔드 앱에서 반환된 모든 유효성 검사 메시지를 수집하기 위해 여기에서 또 다른 Thymeleaf 메서드 인 fields.errors() 를 사용했습니다.
이제 이를 테스트하기 위해 Boot 앱을 실행하고 Endpoints http://localhost:8080/add 에 도달합니다 .
다음은 입력을 전혀 제공하지 않을 때 페이지의 모습입니다.
3.2. 모든 오류를 한 번에 표시
다음으로 모든 오류 메시지를 하나씩 표시하는 대신 한 곳에서 모두 표시할 수 있는 방법을 살펴보겠습니다.
이를 위해 Thymeleaf의 fields.hasAnyErrors() 메서드 를 사용합니다 .
<div th:if="${#fields.hasAnyErrors()}">
<ul>
<li th:each="err : ${#fields.allErrors()}" th:text="${err}" />
</ul>
</div>
보시다시피 HTML 양식의 모든 필드에 있는 모든 오류를 반복하기 위해 여기서 또 다른 변형 인 fields.allErrors() 를 사용했습니다.
fields.hasAnyErrors() 대신 #fields.hasErrors('*') 를 사용할 수 있습니다 . 마찬가지로 #fields.errors('*') 는 위에서 사용된 #fields.allErrors() 의 대안 입니다.
효과는 다음과 같습니다.
3.3. 양식 외부 오류 표시
다음. HTML 양식 외부에 유효성 검사 메시지를 표시하려는 시나리오를 생각해 봅시다.
이 경우 선택 또는 (*{….}) 를 사용하는 대신 (${….}) 형식의 정규화된 변수 이름을 사용하기만 하면 됩니다 .
<h4>Errors on a single field:</h4>
<div th:if="${#fields.hasErrors('${user.email}')}"
th:errors="*{user.email}"></div>
<ul>
<li th:each="err : ${#fields.errors('user.*')}" th:text="${err}" />
</ul>
이렇게 하면 이메일 필드 에 모든 오류 메시지가 표시됩니다 .
이제 모든 메시지를 한 번에 표시하는 방법을 살펴보겠습니다 .
<h4>All errors:</h4>
<ul>
<li th:each="err : ${#fields.errors('user.*')}" th:text="${err}" />
</ul>
페이지에 표시되는 내용은 다음과 같습니다.
3.4. 전역 오류 표시
실제 시나리오에서는 특정 필드와 구체적으로 연결되지 않은 오류가 있을 수 있습니다. 비즈니스 조건을 검증하기 위해 여러 입력을 고려해야 하는 사용 사례가 있을 수 있습니다 . 이를 전역 오류라고 합니다.
이를 증명하기 위해 간단한 예를 들어보겠습니다. 국가 및 전화 번호 필드 의 경우 지정된 국가에 대해 전화번호가 특정 접두사로 시작해야 하는지 확인하는 검사를 추가할 수 있습니다.
이 유효성 검사를 추가하려면 백엔드에서 몇 가지를 변경해야 합니다.
먼저 이 유효성 검사를 수행할 서비스 를 추가합니다.
@Service
public class UserValidationService {
public String validateUser(User user) {
String message = "";
if (user.getCountry() != null && user.getPhoneNumber() != null) {
if (user.getCountry().equalsIgnoreCase("India")
&& !user.getPhoneNumber().startsWith("91")) {
message = "Phone number is invalid for " + user.getCountry();
}
}
return message;
}
}
보시다시피 사소한 경우를 추가했습니다. 인도 국가 의 경우 전화번호는 접두사 91 로 시작해야 합니다 .
둘째, 컨트롤러의 PostMapping 을 조정해야 합니다 .
@PostMapping("/add")
public String addUser(@Valid User user, BindingResult result, Model model) {
String err = validationService.validateUser(user);
if (!err.isEmpty()) {
ObjectError error = new ObjectError("globalError", err);
result.addError(error);
}
if (result.hasErrors()) {
return "errors/addUser";
}
repository.save(user);
model.addAttribute("users", repository.findAll());
return "errors/home";
}
마지막으로 Thymeleaf 템플릿에서 이러한 유형의 오류를 표시하기 위해 전역 상수를 추가합니다 .
<div th:if="${#fields.hasErrors('global')}">
<h3>Global errors:</h3>
<p th:each="err : ${#fields.errors('global')}" th:text="${err}" class="error" />
</div>
또는 상수 대신 #fields.hasGlobalErrors() 및 #fields.globalErrors( ) 메서드를 사용 하여 동일한 결과를 얻을 수 있습니다.
유효하지 않은 입력을 입력하면 다음과 같이 표시됩니다.
4. 결론
이 예제에서는 Thymeleaf에 다양한 유형의 오류를 표시하는 방법을 보여주기 위해 간단한 Spring Boot 애플리케이션을 구축했습니다 .
필드 오류를 하나씩 표시한 다음 한 번에 모두 표시하는 방법, HTML 양식 외부의 오류 및 전역 오류를 살펴보았습니다.
항상 그렇듯이 소스 코드는 GitHub에서 사용할 수 있습니다 .