카테고리 없음

[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