카테고리 없음
[SpringBoot] QnA게시판 질문,답변등록 유효성 검사
오늘 하루s
2023. 8. 27. 23:58
728x90
더보기
Day82. 230825
Spring Boot Validation
Spring Boot에서제공하는 데이터 유효성 검증.
Spring Boot Validation에 사용되는 어노테이션
@NotNull null금지 /""과 " "허용
@NotEmpty null과 ""금지/ " "허용
@NotBlank null과 ""과 " "금지
Spring Boot Validation 사용
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation/3.1.2
Spring Boot Validation을 사용하기 위해 gradle을 추가해 주었다.
build.gradle>
implementation 'org.springframework.boot:spring-boot-starter-validation'
질문 등록 유효성 검사
QuestionController>
package com.mycom.app.question.controller;
import com.mycom.app.answer.validation.AnswerForm;
import com.mycom.app.question.entity.Question;
import com.mycom.app.question.service.QuestionService;
import com.mycom.app.question.validation.QuestionForm;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RequestMapping("/question")
@RequiredArgsConstructor
@Controller
public class QuestionController {
private final QuestionService questionService;
/*질문등록폼 보여줘 요청
요청방식 get
요청주소 http://localhost:포트/question/add
모델
view temlpates/question_detail.html */
@GetMapping("/add")
public String add(QuestionForm questionForm){
return "question_form";
}
/*질문등록 처리 요청
요청방식 post
요청주소 http://localhost:포트/question/add
모델
view temlpates/question_detail.html */
@PostMapping("/add")
/*파라미터
@Valid QuestionForm questionForm - 유효성검사를 거친 QuestionForm객체타입으로 유저가 입력한 값을 받았다.
@Valid을 적용하면 QuestionForm클래스의 @NotEmpty,@Size이 적용된다.
BindingResult bindingResult - @Valid이 적용된 결과(유효하다고 검증된 데이터)를 의미
@Valid가 붙은 파라미터 뒤에 작성한다.*/
//public String questionAdd(@RequestParam String subject,@RequestParam String content){
public String questionAdd(@Valid QuestionForm questionForm, BindingResult bindingResult){
//1.파라미터받기
//2.비지니스로직
if(bindingResult.hasErrors()) { //에러가 존재하면
return "question_form"; //question_form.html문서로 이동
}
//questionForm.getSubject():(제시한 유효성검사를 통과한 데이터)폼에서 subject필드값 가져오기
//questionForm.getContent():(제시한 유효성검사를 통과한 데이터)폼에서 content필드값 가져오기
questionService.add(questionForm.getSubject(), questionForm.getContent());
//3.Model
//4.View
return "redirect:/question/list"; //(질문목록조회요청을 통한)질문목록페이지로 이동
}
//질문상세조회
@GetMapping("/detail/{id}")
public String detail(@PathVariable("id") Integer id, Model model, AnswerForm answerForm){
//1.파라미터받기
//2.비지니스로직수행
Question question = questionService.getQuestion(id);
//3.Model
model.addAttribute("question",question);
//4.View
return "question_detail"; //templates폴더하위 .html
}
//질문목록조회
@GetMapping("/list")
public String questionList(Model model){
List<Question> questionList = this.questionService.getList();
model.addAttribute("questionList",questionList);
return "question_list"; //templates폴더하위 question_list문서
}
}
@Valid 유효성 검증에 사용되는 어노테이션
@Valid QuestionForm questionForm 나온 후 BindingResult bindingResult가 나와야 한다.(순서 주의)
BindingResult에 결과값 담김.
question_form.html>
<html layout:decorate="~{layout}">
<div layout:fragment="content" class="container">
<h5 class="my-3 border-bottom pb-2">질문등록</h5>
<form id="questionForm" th:obgect="${questionForm}" th:action="@{/question/add}" method="post">
<!--유효성검사시 에러메세지 출력영역-->
<div class="alert alert-danger" role="alert" th:if="${#fields.hasAnyErrors()}">
<div th:each="err:${#fiels.allErrors()}" th:text="${err}"></div>
</div>
<div class="mb-3">
<label for="subject" class="form-label">제목</label>
<input type="text" name="subject" id="subject" class="form-control"/>
</div>
<div class="mb-3">
<label for="content" class="form-label">내용</label>
<textarea name="content" id="content" class="form-control" rows="8"></textarea>
</div>
<input type="submit" value="질문등록(처리)" class="btn btn-primary my-2"/>
</form>
</div>
</html>
에러가 있을 때만 에러 메세지 출력
QuestionForm>
package com.mycom.app.question.validation;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;
//질문등록폼(question_form.html)의 입력값에 대한 유효성검사
/*@NotNull null금지 /""과 " "허용
@NotEmpty null과 ""금지/ " "허용
@NotBlank null과 ""과 " "금지*/
@Getter
@Setter
public class QuestionForm {
//제목
@NotEmpty(message = "제목은 필수 입력 입니다.")
@Size(max = 200)//Question Entity에서 @Colum(lenth=200)에 맞추
private String subject;
//내용
@NotEmpty(message = "내용은 필수 입력 입니다.")
private String content;
}
제목과 내용에 대한 유효성 검사가 적용된다.
답변 유효성 검사
AnswerController>
package com.mycom.app.answer.controller;
import com.mycom.app.answer.service.AnswerService;
import com.mycom.app.answer.validation.AnswerForm;
import com.mycom.app.question.entity.Question;
import com.mycom.app.question.service.QuestionService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.xml.validation.Validator;
@RequestMapping("/answer")
@RequiredArgsConstructor
@Controller
public class AnswerController {
private final QuestionService questionService;
private final AnswerService answerService;
/*요청방식
요청주소 /answer/add/10 질문번호*/
//답변등록처리
@PostMapping("/add/{id}")
public String addAnswer(@PathVariable("id") Integer id,Model model
,@Valid AnswerForm answerForm, BindingResult bindingResult){
//1.파라미터받기
//2.비지니스로직
//특정글번호의 질문상세 가져오기=>Answer테이블의 fk에 해당하는 질문객체
/*Answer 엔티티의 속성으로 @ManyToOne private Question question 존재*/
Question question= questionService.getQuestion(id); //특정글번호의 질문상세조회
if(bindingResult.hasErrors()){ //유효성검사를 통과하지못하여 에러가 존재하면
model.addAttribute("question",question);
return "question_detail"; //question_detail.html로 이동
}
answerService.add(question,answerForm.getContent());
//3.Model
//4.View
return String.format("redirect:/question/detail/%d",id); //question_detail
}
}
question_detail>
<html layout:decorate="~{layout}">
<div layout:fragment="content" class="container my-3">
<!--질문-->
<h2 class="border-bottom py-2" th:text="${question.subject}"></h2>
<div class="card my-3">
<div class="card-body">
<div class="card-text" style="white-space:pre-line;" th:text="${question.content}"></div>
<div class="d-flax justify-content-end">
<div class="badge bg-light text-dark p-2 text-start" th:text="${#temporals.format(question.createDate,'yyyy-MM-dd HH:mm')}"></div>
</div>
</div>
</div>
<!-- 답변갯수 출력 -->
<h5 th:text="|${#lists.size(question.answerList)}개의 답변이 있습니다.|"></h5>
<!-- 반복:답변목록시작 -->
<div>
<ul>
<li th:each="answer:${question.answerList}" th:text="${answer.content}"></li>
</ul>
</div>
<!-- 반복:답변목록끝 -->
<!-- 답변등록폼 -->
<form id="answerForm" class="my-3" th:object="${answerForm}" th:action="@{|/answer/add/${question.id}|}" method="post" >
<!--유효성검사시 에러메세지 출력영역-->
<div class="alert alert-danger" role="alert" th:if="${#fields.hasAnyErrors()}">
<div th:each="err:${#fields.allErrors()}" th:text="${err}"></div>
</div>
<textarea th:field="*{content}" rows="8" class="form control"></textarea>
<input type="submit" value="답변등록" class="btn btn-primary my-2"/>
</form>
</div>
유효성 검사 추가
QuestionController>
질문 상세 조회 할 때 AnswerForm추가
AnswerForm>
package com.mycom.app.answer.validation;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;
//(question_detail.html)답변등록폼의 입력값에 대한 유효성검사
/*@NotNull null금지 /""과 " "허용
@NotEmpty null과 ""금지/ " "허용
@NotBlank null과 ""과 " "금지*/
@Getter
@Setter
public class AnswerForm {
//내용
@NotEmpty(message = "내용은 필수 입력 입니다.")
private String content;//내용
}
답변 부분도 유효성 검사가 된다.
728x90