D+57::Validation 유효성검사/어노테이션정리

Am.Vinch·2022년 9월 16일
0
post-thumbnail

20220916_FRI

어노테이션


validation

순서

    1. porm.xml파일에서 dependencies 태그 안에서 아무곳이나 오른쪽 버튼 클릭시, add starter클릭 > validation 검색 후 추가하기. next클릭시, 어느 곳에 추가할 지 위치 선택가능 finish 클릭하면 추가된다.
    • 아래 태그가 추가된다.
      <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>

    1. VO에서 어노테이션 추가한다.
      @NotBlank(message = "id는 필수입력입니다.") :null,""," " 모두 허용하지않는다.
    • cf)@Notnull사용하지않은 이유는?
      : 빈값과 공백값도 허용하기때문에 허용하지않도록 하기위해서
  • 3.컨트롤러에서 @valid 어노테이션과 BindingResult bindingResult , Model model 매개변수 추가한다.
    • BindingResult : 검증 대상 객체(memberVO)와 검증 결과의 대한 정보를 담고 있는 객체. 검증객체 바로 다음에 선언되어야 한다.
      :실제로 input태그에 입력한 데이터가 memberVO에 들어오는 걸 바인딩이라고하는데, 그 결과를 말한다.
    • @Valid : post로 전달된 데이터(memberVO)가 검증 규칙을 따르는지 판단하는 어노테이션 그래서, 검증할 객체가 valid 다음 바로 와야한다. 순서가 중요하다!!!

정규식

: 정규식 비밀번호 영어숫자 코드(암기할 필요x)
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,16}$"
링크 > https://tjddnjs625.tistory.com/28

실습내용

    1. 로그인 화면에도 validation
    1. 회원 가입 기능구현
    • 회원가입 성공 후, 게시글 목록 페이지로 이동
    1. 로그인 기능구현(session기능 사용o + ajax 사용 x)
    • 로그인 실패 시, 다시 로그인 페이지로 이동
      (로그인 페이지로 되돌아 왔을때, id 및 pw는 input 태그에 그대로 남아있도록 기능 구현)
    • 로그인 성공 시, 게시글 목록페이지로 이동
  • MemberVO


import java.util.Iterator;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

import groovy.transform.ToString;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@ToString
public class MemberVO {
	//참고//
	//@NotNull //javax로시작하는 어노테이션 사용 : null허용x / "", " "빈값,공백 허용가능
	
	@NotBlank(message = "id는 필수입력입니다.") //null,""," " 모두 허용x
	private String memberId;
	
	//정규식 코드 사용해야한다.(복사붙여넣기)
	// 8-16자리, 영어대소문자,특수문자포함(#은 포함시키지않음! 주의!)
    @Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,16}$" 
    		, message = "비밀번호 형식에 맞지 않습니다")
	private String memberPw;
	
	@NotBlank(message = "이름은 필수입력입니다.")
	@Size(max = 5,message = "제한된 길이를 초과했습니다.")// max : 영어숫자 상관없이 최대문자길이 뜻함
	private String memberName;
	
	@Size(min = 9, max = 12)
	private String memberTell;//01012345678
	
	private String isAdmin;
	private String memberStatus;
	
	private String[] memberTells;//010,1234,5678
	
	public String getMemberTell() {
		/* return memberTells[0] + memberTells[1] + memberTells[2]; */
		if (memberTells == null) {
			return null;
		}		
		else {// 연락처가 null이 아니라면, 배열에서 하나씩 값을 빼와서 문자열을 누적시켜서 result값으로 데이터 던진다
			String result = "";
			for(String tell : memberTells) {//010,1234,5678
				result += tell;//01012345678
			}
			return result; //01012345678 
		}
	}
}
  • member-mapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--해당 파일에 모든 쿼리문을 작성 -->
<mapper namespace="memberMapper">
	<!-- 패키지명 클래스명 -->
 	 <resultMap type="kh.study.board.member.vo.MemberVO" id="selectMember">
		<id column="MEMBER_ID" 	property="memberId"/>
		<result column="MEMBER_PW" property="memberPw"/>
		<result column="MEMBER_NAME" property="memberName"/>
		<result column="MEMBER_TELL" property="memberTell"/>
		<result column="IS_ADMIN" property="isAdmin"/>
		<result column="MEMBER_STATUS" property="memberStatus"/>
	</resultMap>  

<!-- 회원가입 -->
<insert id="join">
INSERT INTO BOARD_MEMBER (
		MEMBER_ID, MEMBER_PW, MEMBER_NAME, MEMBER_TELL,MEMBER_STATUS
) VALUES(
		#{memberId},#{memberPw},#{memberName},#{memberTell},'ACTIVE'
)
</insert>   

<!-- 로그인 -->
<select id="login" resultMap="selectMember">
SELECT MEMBER_ID , MEMBER_PW
FROM BOARD_MEMBER
WHERE MEMBER_ID = #{memberId} 
and MEMBER_PW = #{memberPw} 
</select>

</mapper> 
  • MemberService
package kh.study.board.member.service;

import kh.study.board.member.vo.MemberVO;

public interface MemberService {
 void join(MemberVO memberVO);
 MemberVO login(MemberVO memberVO);
}
  • memberServiceImpl
package kh.study.board.member.service;

@Service("memberService")
public class MemberServiceImpl implements MemberService{
	@Autowired//어노테이션으로 객체생성
	private SqlSessionTemplate sqlSession;

	//회원가입
	@Override
	public void join(MemberVO memberVO) {
		sqlSession.insert("memberMapper.join", memberVO);
	}
	//로그인
	@Override
	public MemberVO login(MemberVO memberVO) {
		return sqlSession.selectOne("memberMapper.login", memberVO);
	}
	
}
  • boardController
@Controller
@RequestMapping("/board")
public class BoardController {
	//목록페이지
	@GetMapping("/list")
	public String boardList() {
		return "content/board/board_list";
	}
  • MemberController
@Controller
@RequestMapping("/member")
public class MemberController {
	@Resource(name = "memberService")
	private MemberService memberService;


	// ---------------------- 커맨드객체 정의 -------------------------------------------//
	// 커맨드객체는 html로 데이터를 전달하는 코드를 작성하지 않아도 자동으로 넘어간다.
	// 이때 데이터가 넘어가는 이름은 클래스명에서 앞글자만 소문자로 변경된 이름으로 넘어간다.
	//-----------------------------------------------------------------------------------//
	
	// 회원가입
	// a태그로 top파일에서 넘어올 때 get매핑
	@GetMapping("/join") // a태그는 무조건 get 방식!!!(암기)
	public String join(MemberVO memberVO) {
		// 자동으로 커맨드 객체는 넘어간다.(memberVO) //커맨드객체에 아이디값 임의로 넣어주면, html로 넘어갈때 데이터 넘어감
		System.out.println(memberVO);

		return "content/member/join";
	}

	// 회원가입
	// form태그로 top파일에서 넘어올 때 get매핑
	// @Valid : post로 전달된 데이터가 검증 규칙을 따르는지 판단하는 어노테이션
	// 해당 어노테이션 다음에는 반드시 검증할 객체가 valid 다음 바로 와야한다
	// BindingResult :검증 대상 객체와 검증 결과의 대한 정보를 담고 있는 객체.
	// 검증객체 바로 다음에 선언되어야 한다.
	// 실제로 input태그에 입력한 데이터가 memberVO에 들어오는 걸 바인딩이라고하는데, 그 결과를 말함.
	// model도 매개변수로 넣어준이유?
	// : model 같이 매개변수 사용하면 데이터를 굳이 담지않아도(눈에보이지않아도) 바인딩결과의 오류여부정보와 검증한 객체memberVO 값을
	// 자동으로 리턴값 join.html에 보내준다.
	@PostMapping("/join")
	public String joinProcess(@Valid MemberVO memberVO, BindingResult bindingResult, Model model) {

		System.out.println("!!!!!!" + memberVO.getMemberTell()); // "010,1111,2222"
		System.out.println("!!!!!!" + memberVO.getMemberPw()); // "010,1111,2222"
		/*
		 * String[] tells = memberVO.getMemberTells(); for(String e : tells) {//리스트는
		 * 반복문으로 데이터꺼내기 System.out.println(e); }
		 */

		// 1) validation 체크 (데이터 유효성 검증)
		if (bindingResult.hasErrors()) {// 바인딩하는데 오류가 생겼니?
			System.out.println("error발생");
			return "content/member/join";// 에러발생하면 join페이지로 다시 이동
		}

		// 2)회원가입 쿼리 실행
		memberService.join(memberVO);

		// 3)페이지이동
		return "redirect:/board/list";
	}

	// 로그아웃
	@GetMapping("/logout")
	public String logout(HttpSession session) {
		session.removeAttribute("loginInfo");
		
		return "redirect:board/list";
	}
	
	// 로그인
	// a태그로 top파일에서 넘어올 때
	@GetMapping("/login") // a태그는 무조건 get 방식!!!(암기)
	public String login(MemberVO memberVO) {
		System.out.println("로그인 a태그로 클릭해서 넘어왔다!!!!!!!!!!!!!!!!!!");
		
		return "content/member/login";
	}
	
	// 로그인
	// form태그로 top파일에서 넘어올 때
	@PostMapping("/login")//a태그는 무조건 get 방식!!!(암기)
	public String loginProcess(HttpSession session, MemberVO memberVO
			, Model model) {
		//!!로그인은 유효성검사 필요없다
		//로그인 쿼리 실행
		MemberVO loginInfo = memberService.login(memberVO);
		System.out.println("넘어왔다");
		if (loginInfo != null) {
			session.setAttribute("loginInfo", loginInfo);
		}
		else {
			System.out.println("로그인실패!!!!!!!!!!!!!!!!!!!!!!!!!!");
			return "redirect:/member/login";
		}
		return "redirect:/board/list";
	}
}
  • top.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<div th:fragment="topFragment">
<!-- 로그인 클릭시 로그인html파일 이동방법 -->
	<!-- 1번 <a href="/board/login">login</a> -->
	<!-- 2번 <a th:href="@{/board/login}"> login</a><!-- 타임리프 경로이동시!!! 골뱅이+중괄호 -->
	<div class="row">
		<div class="col text-end" style="color:#224B0C;">
			<th:block th:if="${session.loginInfo == null}">
				<a th:href="@{/member/login}">login</a><!-- a태그 -> get방식!!! -->
				<a th:href="@{/member/join}">join</a><!-- a태그 -> get방식!!! -->
				<!-- <span th:onclick="location.href='/board/join';"></span> -->
			</th:block>
			<th:block th:unless="${session.loginInfo == null}">
				<a th:href="@{/member/login}">
					[[${session.loginInfo.memberName}]]님 반갑습니다✔✔	</a><!-- a태그 -> get방식!!! -->
				<a th:href="@{/member/logout}">LOGOUT</a><!-- a태그 -> get방식!!! -->
			</th:block>
		</div>
	</div>
	<div class="row">
		<div class="col text-center" style="background-color: #EEF2E6;">
			<span style="font-weight: bold; font-size: 50px; color: #3D8361;">Board</span>
		</div>
	</div>
</div>

</html>
  • join.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultra.net.nz/thymeleaf/layout"
	layout:decorate="~{layout/base_layout}">

<!-- th 타임리프사용하려면 경로이동은!!! 골뱅이+{}사용하기!!! -->
<!-- th:object="${memberVO}" 는 데이터받기위해 사용 : 컨트롤러에서 보낸 객체 받아오기!!! 
커맨드객체 memberVO는 자동으로 데이터 가져와서 사용가능하다  -->
<!-- 단, th:field는 th:object와 반드시 함께 사용하는 애트리뷰트 -->
<!-- formx태그에 th:object로 넘어오는 커맨드객체를 지정할 경우
	해당 폼 태그 내에서 th:field 속성으로 자동으로 id,name,value 값을 세팅할 수 있다. -->
<!-- 개발자모드 콘솔을 보면 th:feild속성값만으로 name,id,value값 모두 확인가능하다!!! -->

<!-- th:field 받지않고 원래 사용하던 방법  -->
<!-- id :<input type="text" name="memberId" id="memberId"> -->

<!-- th:field  받아와서 사용하는 방법 -->
<!-- *{memberId}라는 값으로 들어오는 데이터 받아와서 사용하겠다. -->

<div layout:fragment="content">
	<!-- row justify-content-center : 가운데 정렬 -->
	<div class="row justify-content-center">
		<div class="col-6">
			<form th:action="@{/member/join}" class="row g-3" method="post" th:object="${memberVO}">
				<div class="col-12">
					<label for="memberId" class="form-label"> ID </label> 
					<input type="text" class="form-control" th:field="*{memberId}">
					<!-- 이 html파일에 위의 object의 해당하는 memberVO라는 객체를 던져줬기때문에 에러발생있는지 알수있는 것이다. -->
					<!--  field 는 변수를 의미한다.-->
					<!-- * 와 {} 표기 :  object의 객체(memberVO에 담긴 데이터)로 인식한다.  -->
					<div class="hasError" th:if="${#fields.hasErrors('memberId')}" th:errors="*{memberId}"></div>
				</div>
				<div class="col-12">
					<label for="memberPw" class="form-label">PASSWORD</label> 
					<input type="password" class="f orm-control" th:field="*{memberPw}">
					<div class="hasError" th:if="${#fields.hasErrors('memberPw')}" th:errors="*{memberPw}"></div>
				</div>
				<div class="col-12">
					<label for="memberName" class="form-label">NAME</label> 
					<input type="text" class="form-control" th:field="*{memberName}">
					<div class="hasError" th:if="${#fields.hasErrors('memberName')}" th:errors="*{memberName}"></div>
				</div>
				
				<div class="col-4">
					<!-- 연락처는 타임리프 사용하면 에러난다!!! -->					
					<label for="memberTells" class="form-label">TELL</label> 
					<select name="memberTells" class="form-select" >
						<option value="010" selected>010</option>
						<option value="">011</option>
					</select>
				</div>
				<div class="col-4">
					<label for="" class="form-label">&nbsp;</label> 
					<input type="text" class="form-control" name="memberTells">
				</div>
				<div class="col-4">
					<label for="" class="form-label">&nbsp;</label> 
					<input type="text" class="form-control" name="memberTells">
				</div>
				<!-- div태그 밖으로 빼놓고 데이터를 memberTell 로 넣어준다 (memberTells 아님!! 주의) -->
					<div class="hasError" th:if="${#fields.hasErrors('memberTell')}" th:errors="*{memberTell}"></div>

				<div class="col-12 d-grid gap-2">
					<button type="submit" class="btn btn-primary">JOIN</button>
				</div>
			</form>
		</div>
	</div>
</div>

</html>
  • login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultra.net.nz/thymeleaf/layout" 
	layout:decorate="~{layout/base_layout}">
<div layout:fragment="content">
		
	<div class="row justify-content-center">
		<div class="col-6">
			<form th:action="@{/member/login}" class="row g-3" method="post" th:object="${memberVO}">
				<div class="col-12">
					<label for="memberId" class="form-label" >ID</label>
					<input type="text" class="form-label" name="memberId" th:text="${memberVO.memberId}" th:value="${memberVO.memberId}" >
					                                                      <!-- value값에  ${memberVO.memberId} 가능 -->
				</div>
				<div class="col-12">
					<label for="memberPw" class="form-label" >PW</label>
					<input type="password" class="form-label" name="memberPw" >
				</div>
				<div class="col-12 d-grid gap-2">
					<button type="submit" class="btn btn=primary">로그인</button>
					<button type="button" class="btn btn=primary" onclick="location.href='/member/join';" >회원가입</button>
				</div>
			</form>
		</div>
	</div>	
</div>
</html>
profile
Dev.Vinch

0개의 댓글