본문 바로가기
java

2024-02-05

by rewind 2024. 2. 5.

exception 패키지 생성

exception 패키지 내 CommonExceptionHandler.class 생성

@ControllerAdvice 어노테이션 선언 -> 예외처리 핸들러 클래스임을 명시!
@Slf4j 어노테이션 선언

handle 메소드 생성 - @ExceptionHandler 어노테이션 선언

@ExceptionHandler
=> 괄호 안에 설정한 예외 타입을 해당 메서드가 처리한다는 의미
=> IOException, SQLException, NullPointerException, ArrayIndexOutOfBoundsException,
=> ArtimeticException(0으로 나눌경우)

 

package kr.or.ddit.exception;

import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.NoHandlerFoundException;

import lombok.extern.slf4j.Slf4j;
//스프링 컨트롤러에서 발생하는 예외를 처리하는 핸들러 클래스임을 명시함
@Slf4j
@ControllerAdvice
public class CommonExceptionHandler {
	
	//괄호 안에 설정한 예외 타입을 해당 메소드가 처리한다는 의미
	//IOException, SQLException, NullPointerException, ArrayIndexOutOfBoundsException,
	//ArtimeticException(0으로 나눌경우)
	//Exception -> 최상위 에러 클래스
	@ExceptionHandler(Exception.class)
	public String handle(Exception e ,  Model model) {
		
		log.error("CommonExceptionHandler->handle : " + e.toString());
		e.getStackTrace();	// 배열형태로 온다 => jsp에서(view) 배열(c:forEach) 사용가능
		
		model.addAttribute("exception" , e);
		
		//forwarding : jsp
		return "error/errorCommon";
		
	}
	
	// 여기서 404오류를 처리하기 위해선??
	/*
	404를 프로그래밍적으로 처리하고 싶다면 404 발생 시 예외를 발생시키도록 설정해야 한다.
	(기본적으로 404는 exception 상황이 아니다.) 
	이를 위해 web.xml에서 DispatcherServlet을 등록할 때 throwExceptionIfNoHandlerFound 
	초기화 파라미터를 true로 설정한다.
	 */
	@ExceptionHandler(NoHandlerFoundException.class)
	@ResponseStatus(HttpStatus.NOT_FOUND)
	public String handle404(Exception e) {
		// Exception핸들러 어노테이션 선언
		log.error("CommonExceptionHandler -> handle404 : " + e.toString());
		
		return "error/error404";
	}
	
}

 

errorCommon.jsp 생성

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page isErrorPage="true" %>
<section class="content">
	<div class="error-page">
	<!-- model.addAttribute("exception" , e); -->
		<h2 class="headline text-warning">${exception.getMessage() }</h2>
		<div class="error-content">
		<c:forEach var="stack" items="${exception.getStackTrace()}" varStatus="stat">
		<!-- 오류메시지가 순서대로 반복문 형태로 출력 -->
			<h3>
				<i class="fas fa-exclamation-triangle text-warning"></i>${stack.toString()}
			</h3>
		</c:forEach>
			<p>
				<%=exception.getMessage()%> 만약 메인으로 이동하고자 하면 <a href="/">메인</a>을 클릭해주세요.
			</p>
			<form class="search-form">
				<div class="input-group">
					<input type="text" name="search" class="form-control"
						placeholder="Search">
					<div class="input-group-append">
						<button type="submit" name="submit" class="btn btn-warning">
							<i class="fas fa-search"></i>
						</button>
					</div>
				</div>

			</form>
		</div>

	</div>

</section>

 

-- 1교시 끝

 

web.xml 에서 주석처리 -> 컨트롤러에서 처리하기 위해서

<!-- 	<error-page> -->
<!-- 		<error-code>404</error-code> -->
<!-- 		<location>/error/error404</location> -->
<!-- 	</error-page> -->


servlet 부분에 아래코드 추가작성
		<!-- 404 오류를 처리할 수 있도록 설정 시작 -->
      <init-param>
         <param-name>throwExceptionIfNoHandlerFound</param-name>
         <param-value>true</param-value>
      </init-param>
		<!-- 404 오류를 처리할 수 있도록 설정 끝 -->

 

 

web.xml 에 아래 코드 추가

		<!-- 입력값을 검증하기 위한 라이브러리 의존 관계 정의 시작
			 스프링
			M(Model) : Service, ServiceImple, Mapper
			V(View) : JSP
			C(Controller) : Controller
			Bean(자바빈 클래스, ArticleVO) Validation(유효성검사) 기능을 이용해
			요청 파라미터 값이 바인딩된(멤버변수에 세팅된) 도메인 클래스(ArticleVO)의 입력값 검증을 함
			요청 파라미터 : ?articleNo=112&title=개똥이
			public String write(골뱅이ModelAttribute ArticleVO articleVO) -->
		<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>5.2.5.Final</version>
		</dependency>

		<!-- 입력값을 검증하기 위한 라이브러리 의존 관계 정의 끝 -->

 

// 2교시 끝

 

package kr.or.ddit.vo;

import java.util.List;

import org.hibernate.validator.constraints.NotBlank;

import lombok.Data;
/**
 * 스프링 MVC는 Bean Validation 기능을 이용해 요청 파라미터 값이 바인딩된 도메인 클래스의 입력값 검증을 함
// 요청 파라미터 : {studId=a001...}
// => 바인딩 
// articleVO.setArticleNo(12), articleVO.setWriterId("a001")
// 자바빈 클래스(=도메인 클래스)
// PoJo(Plain(단순한, 원래의) old(지향) Java Object)
 Bean Validation이 제공하는 제약 어노테이션
  - NotNull : 빈 값 체크(int타입)
  - NotBlank : null 체크, trim후 길이가 0인지 체크(String타입)
  - Size : 글자 수 체크
  - Email : 이메일 주소 형식 체크
  - Past : 오늘보다 과거 날짜(ex. 생일)
  - Future : 미래 날짜 체크(ex. 예약일)
  - AssertFalse : false 값만 통과 가능
  - AssertTrue : true 값만 통과 가능
  - DecimalMax(value=) : 지정된 값 이하의 실수만 통과 가능
  - DecimalMin(value=) : 지정된 값 이상의 실수만 통과 가능
  - Digits(integer=,fraction=) : 대상 수가 지정된 정수와 소수 자리수보다 적을 경우 통과 가능
  - Future : 대상 날짜가 현재보다 미래일 경우만 통과 가능
  - Past : 대상 날짜가 현재보다 과거일 경우만 통과 가능
  - Max(value) : 지정된 값보다 아래일 경우만 통과 가능
  - Min(value) : 지정된 값보다 이상일 경우만 통과 가능
  - NotNull : null 값이 아닐 경우만 통과 가능
  - Null : null일 겨우만 통과 가능
  - Pattern(regex=, flag=) : 해당 정규식을 만족할 경우만 통과 가능
  - Size(min=, max=) : 문자열 또는 배열이 지정된 값 사이일 경우 통과 가능
  - Valid : 대상 객체의 확인 조건을 만족할 경우 통과 가능
 */
//자바빈 클래스
//PoJo위배
@Data
public class StudVO {
	private int    rnum;
	@NotBlank
	private String studId;
	@NotBlank
	private String studNm;
	@NotBlank
	private String studPw;
	private String enabled;
	private String studDet;//학생 상세->STUD_DET
	private String[] hobby;//학생 취미들
	private String gender;//성별
	private String nationality;//국적
	
	//StudVO : StudAuthVO = 1 : N
	private List<StudAuthVO> studAuthVOList;
	
	//STUD : HOBBY = 1 : N
	//중첩된(Nested) 자바빈
	private List<HobbyVO> hobbyVOList;
	
	//일반 생성자
	public StudVO(String studId, String studNm, String studPw) {
		this.studId = studId;
		this.studNm = studNm;
		this.studPw = studPw;
	}
	//기본 생성자
	public StudVO() {}
	
}

 

 

SpringFormController에 register메소드 수정

	/*
	요청URI :  /springform/register
	요청파라미터 : {studId=a005,studNm=개똥이,studPw=java, studDet=상세정보
			  , hobby=[sports,movie], gender=female, nationality=korea}
	요청방식 : post
	*/
	//2. 컨트롤러 메서드의 매개변수로 자바빈즈 객체가 전달이 되면 
	//	  forwarding하는 JSP에 다시 화면으로 전달함
	// 입력값 검증을 할 도메인 클래스(StudVO)에 @Validated를 지정함
	// 입력값 검증 대상의 도메인 클래스 직후에 BindingResult를 정의함
	// BindingResult에는 요청 파라미터 데이터의 바인딩(set..) 오류와 입력값 검증 오류 정보가 저장됨
	// result.hasErrors() : 바인딩 도중 오류 발생 시 true를 반환함
	@PostMapping("/register")
	public String register(@Validated StudVO studVO , BindingResult result) {
		//StudVO[studId=a005,studNm=개똥이,studPw=java, enabled=null
		//	, studDet=상세정보, hobby=[sports,movie], hobbyVOList=null
		//  , gender=female, nationality=korea]
		log.info("register : " + studVO);
		log.error("바인딩 result : " + result.hasErrors());
		
//		int result = this.service.register(studVO);
//		log.info("register->result : " + result); // true(오류발생) , false(오류없음)
		
		//forwarding
		return "springform/registerForm";
	}
	/*

 

스프링 자체적으로 유효성 검증(validation)을 해준다

 

registerForm.jsp 에 해당 코드 작성

	<tr>
			<th>학생 명</th>
			<!-- name 및 id 속성이 path속성으로 합쳐짐 -->
			<td>
				<form:input path="studNm" />
				<font color="red">
					<form:errors path="studNm" />
				</font>
			</td>
		</tr>
		<tr>
			<th>학생 비밀번호</th>
			<!-- 포워딩 되면 바인딩 된 에러메시지가 출력된다 -->
			<td><form:password path="studPw" />
				<font color="red">
					<form:errors path="studPw" />
				</font>
			</td>
		</tr>

 

유효성 검증 방법

1. @Validated

2. <font color="red"><form:errors path="studNm" /></font>(form에러메세지)

3. 정규식 적용

등등..

 

 

@NotBlank 어노테이션에 메세지 값 설정 가능

확인

 

 

자동등록 버튼만들기?

create.jsp에 아래 코드 작성

		<div class="card-footer">
		<!-- ajax(button) 인지 submit인지 잘 체크!! -->
			<button type="submit" class="btn btn-primary">등록</button>
			<button type="button" id="btnAuto" class="btn btn-primary">자동입력</button>
<!-- 			<button type="button" id="btnAjaxSubmit" class="btn btn-primary">등록</button> -->
		</div>

 

위쪽 스크립트에서 function 부분에 아래 코드 작성

	$("#btnAuto").on("click" , function () {
		console.log("자동입력버튼 클릭")
		$("#emailAdres").val("test@test.com");
		$("#password").val("java");
		$("#no1").val("1111-1111-1111-1111");
		$("#validMonth1").val("202408");
		$("#no2").val("2222-2222-2222-2222");
		$("#validMonth2").val("202508");
		$("#likesTitle1").val("운동");
		$("#likesCont1").val("야구");
		$("#likesTitle2").val("독서");
		$("#likesCont2").val("추리소설");
	});

 

버튼 클릭 후 자동입력버튼 작동 하는지 확인

 

QuickController createPost메소드에 @Validated 선언

QuickVO에 유효성 검증 어노테이션 추가

package kr.or.ddit.vo;

import java.util.Date;
import java.util.List;

import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotBlank;
import org.springframework.web.multipart.MultipartFile;

import lombok.Data;

@Data
public class QuickVO {
	@NotBlank(message = "이메일을 입력해주세요")
	@Email
	private String emailAdres;
	@NotBlank(message = "비밀번호를 입력해주세요")
	private String password;
	private String registerId;
	private Date registDt;
	private String updaterId;
	private Date updateDt;
	
	private MultipartFile[] uploadFile;
	
	// QUICK : QUICK_ATTACH = 1 : N 
	private List<QuickAttachVO> quickAttachVOList;

	// QUICK : CARD = 1 : N QuickVO 테이블에 추가
	private List<CardVO> cardVOList;
	
	// QUICK : LIKES = 1 : N QuickVO 테이블에 추가
	private List<LikesVO> likesVOList;
}

 

package kr.or.ddit.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import kr.or.ddit.service.QuickService;
import kr.or.ddit.vo.QuickVO;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RequestMapping("/quick")
@Controller
public class QuickController {

	@Autowired
	QuickService quickService;
	/**
	Quick 폼화면
	 * @return
	 */
	@GetMapping("/create")
	public String create() {
		// forwarding : jsp
		
		return "quick/create";	// quick/create폴더
	}
	/**
		요청 URI : /quick/createPost
		요청파라미터 : {emailAdres=test@test.com,password=java,uploadFile=파일객체}
		요청방식 : post
		부모테이블(QUICK) : 자식테이블(QUICK_ATTACH) = 1 : N
		registerId : admin
	 */
	@ResponseBody
	@PostMapping("/createAjaxPost")
	public int createAjaxPost(QuickVO quickVO) {
		
		log.info("quickVO1 : " + quickVO);
		quickVO.setUpdaterId("admin");
		int result = this.quickService.createPost(quickVO);
		log.info("result : " + result);
		return result;
	}
	
	@PostMapping("/createPost")
	public String createPost(@Validated QuickVO quickVO , BindingResult brResult) {
		
		quickVO.setUpdaterId("admin");
		log.info("createPost -> quickVO : " + quickVO);
		log.error("BindingResult : " + brResult.hasErrors());//true : 오류발생 , false : 오류없음
		
		//오류가 발생한다면
		if(brResult.hasErrors()) {
			//검사 결과 오류 확인
			List<ObjectError> allErrors = brResult.getAllErrors();
			//객체와 관련된 오류
			List<ObjectError> globalErrors = brResult.getGlobalErrors();
			//멤버변수와 관련된 오류
			List<FieldError> fieldErrors = brResult.getFieldErrors();
        
	        for(ObjectError objectError : allErrors) {
	           log.info("allError : " + objectError);
	        }
	        
	        for(ObjectError objectError : globalErrors) {
	           log.info("globalError : " + objectError);
	        }
	        
	        for(FieldError fieldError: fieldErrors) {
	           log.info("fieldError : " + fieldError.getDefaultMessage());
	        }
		
	        // redirect로는 brResult가 안넘어가고 , forwarding일때만 바인딩 오류 정보가 넘겨짐
	        return "quick/create";	// if문 아래는 실행하지 않는다
		}

		int result = this.quickService.createPost(quickVO);
		log.info("createPost -> result : " + result);
		
		return "redirect:/quick/detail?emailAdres="+quickVO.getEmailAdres();
	}
/*
  * 요청URI : /quick/detail
	요청파라미터 : {emailAdres=test@test.com}
	요청방식 : get
*/
	@GetMapping("/detail")
	public String detail(@RequestParam("emailAdres") String emailAdres , Model model) {
		log.info("detail -> " + emailAdres);
		QuickVO quickVO = this.quickService.detail(emailAdres);
		
		model.addAttribute("quickVO" , quickVO);
		
		return "quick/detail";
	}
	
}

 

http://localhost/quick/create 페이지에서 이메일/패스워드 미 입력후 콘솔창 확인

 

if문에서 작성한 에러코드 콘솔에서 뜨는지 확인

 

jsp에서도 처리

 

quick/create.jsp에 아래 form 태그라이브러리 추가

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>

 

 

quick/create.jsp에서 폼태그 스프링 폼태그로 변환

<form:form modelAttribute="quickVO" action="/quick/createPost?${_csrf.parameterName}=${_csrf.token}"
		method="post" enctype="multipart/form-data">
		<div class="card-body">
			<div class="form-group">
				<label for="exampleInputEmail1">Email address</label>
				<!--  form:input => input type = "text" -->
				<form:input class="form-control" path="emailAdres" placeholder="이메일" />
				<font color="blue">
					<form:errors path="emailAdres" />
				</font>
			</div>
			<div class="form-group">
				<label for="exampleInputPassword1">Password</label>
				<!--  form:password => input type="password" -->
				<form:password class="form-control" path="password" placeholder="비밀번호" />
					<font color="red">
						<form:errors path="password" />
					</font>
			</div>
            ...
            ...
            ...
            ...
</form:form>

 

 

QuickController create메소드 수정 -> form 태그에서 model값을 지정하기 위해

@GetMapping("/create")
	public String create(@ModelAttribute("quickVO") QuickVO quickVO) {
		// <form:form modelAttribute="quickVO"
		// forwarding : jsp
		
		return "quick/create";	// quick/create폴더
	}

 

 

 

CRUD해보기

 

테이블 : CONTACT_INFO
컬럼 : 
CI_CD varchar2(10) N.N CI20240205001
CI_NAME varchar2(10) N.N 방문자명
CI_MAIL varchar2(10) N.N 이메일
CI_SUBJ varchar2(10) N.N 방문 주제
CI_MESG CLOB타입 방문 내용
CI_REG_DT DATE 방문 예정일
REGISTER_ID 'admin'
REGISTER_DT sysdate(default처리)

 

 

create.jsp에 아래 코드 추가

<script type="text/javascript" src="/resources/ckeditor5/ckeditor.js"></script>
<link type="text/css" rel="stylesheet" href="/resources/ckeditor5/css/sample.css" media="screen" />

 

마지막 줄에 아래 코드 추가

<script>
<script type="text/javascript">
ClassicEditor.create( document.querySelector('#hpropOpinion'),{ckfinder:{uploadUrl:'/image/upload?${_csrf.parameterName}=${_csrf.token}'}})
 .then(editor=>{window.editor=editor;})
 .catch(err=>{console.error(err.stack);});
</script>

 

 

에디터에 작성시 에디터 란에 추가 

$(function(){
	$(".ck-blurred").keyup(function () {
		
		console.log("str : " + window.editor.getData());
		$("#ciMesg").val(window.editor.getData());
	});
	
	$(".ck-blurred").on("focusout",function () {
	// focusout : 커서가 영역 밖으로 나올때 마지막 데이터까지 추가
		$("#ciMesg").val(window.editor.getData());
	});

 

 

UploadController 생성

package kr.or.ddit.controller;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
public class UploadController {

	//root-context.xml에 작성해놓은 경로 
	
	@Autowired
	String uploadFolderDirect;
	
	//ckeditor이미지 업로드 , data전송 -> ResponseBody어노테이션 추가(객체화)
	@ResponseBody
	@PostMapping("/upload/uploads")
	public Map<String , Object> uploads(MultipartHttpServletRequest request) throws IllegalStateException, IOException{
		// request에 이미지 객체가 담져겨 있다
		// ckeditor 에서 파일을 보낼 때 upload : [파일] 형식으로 해서 넘어오기 때문에 upload라는 키의 밸류를 받아서 uploadFile에 저장함
		// 열기 누르는 순간
		MultipartFile uploadFile = request.getFile("upload");
		log.info("uploads -> uploadFile : " + uploadFile);
		
		// 파일의 오리지널 명
		String originalFileName = uploadFile.getOriginalFilename();
		log.info("uploads -> originalFileName : " + originalFileName);
		
		// 파일의 확장자(개똥이.jpg)
		String ext = originalFileName.substring(originalFileName.indexOf("."));
		log.info("ext : " + ext);	// .jpg
		
		String newFileName = UUID.randomUUID() + ext;	// sadlfkjsafd.jpg
		
		// 이미지를 현재 경로와 연관된 파일에 저장하기 위해 현재 경로를 알아냄
	      // String realPath = request.getServletContext().getRealPath("/");
	    String url = request.getRequestURL().toString();
	    log.info("uploads->url(bef) : " + url);
	    // http://localhost/
	    // http://192.168.93.73/
	    url = url.substring(0, url.indexOf("/", 7));
	    log.info("uploads->url(aft) : " + url);
		
		// 업로드 폴더에 저장
		// 물리적 저장 경로.../upload + "\\" + sadlfkjsafd.jpg
		String savePath = this.uploadFolderDirect+ "\\" + newFileName;
		log.info("uploads -> savePath : " + savePath);
		
		// 웹 경로
		String uploadPath = "/resources/upload/" + newFileName;
		
		// 설계
		File file = new File(savePath);
		// 파일 업로드 처리
		uploadFile.transferTo(file);
		
		Map<String, Object>map = new HashMap<>();
		map.put("uploaded" , true);
		map.put("url" , url + uploadPath);
		// map : {uploaded = true  , url=http://localhost/resources/upload/asdasdasd~~.jpg}
		log.info("uploads -> map : " + map);
		
		return map;
		
	}

}

 

 

root-context.xml에 추가 -> 업로드 하는 동안까지의 이미지를 가져옴

	<bean id="uploadFolderDirect" class="java.lang.String">
      <constructor-arg value="C:\\eGovFrameDev-3.10.0-64bit\\workspace\\.metadata\\.plugins\\org.eclipse.wst.server.core\\tmp0\\wtpwebapps\\springProj\\resources\\upload"></constructor-arg>
   </bean>

 

 

validation 체크

package kr.or.ddit.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import kr.or.ddit.service.ContactService;
import kr.or.ddit.vo.ContactInfoVO;
import lombok.extern.slf4j.Slf4j;

@RequestMapping("/contactInfo")
@Controller
@Slf4j
public class ContactInfoController {
	@Autowired
	ContactService contactService;
	@Autowired
	String uploadFolder;	
	
	@GetMapping("/create")
	public String index() {
		
		log.info("");
		return "contactInfo/create";
	}
	
	/*
	   요청URI : /contactInfo/createPost
	   요청파라미터 : {ciName=개똥이,ciMail=test@test.com,ciSubj=채용상담,ciImgUrl=파일객체,
	             ciMesg=채용절차에 대한 상담,ciRegDt=2024/02/17}
	   요청방식 : post
	 */	
	@PostMapping("/createPost")
	public String createPost(@Validated ContactInfoVO contactInfoVO , BindingResult brResult) {
		
		log.info("createPost->contactInfoVO : " + contactInfoVO);
		
		contactInfoVO.setRegisterId("admin");
		// brResult : true(오류발생) , false(오류없음)

		// 파일업로드 및 insert처리(Impl에서..)
		
		return "redirect:/contactInfo/detail?ciCd="+contactInfoVO.getCiCd();
	}
}

 

package kr.or.ddit.vo;

import java.util.Date;

import javax.validation.constraints.Future;

import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotBlank;
import org.springframework.format.annotation.DateTimeFormat;

import lombok.Data;

@Data
public class ContactInfoVO {
	private String ciCd;
	@NotBlank(message="이름을 입력해 주세요")
	private String ciName;
	@NotBlank(message="이메일주소를 입력해 주세요")
	@Email
	private String ciMail;
	@NotBlank(message="제목을 입력해 주세요")
	private String ciSubj;
	private String ciImgUrl;
	private String ciMesg;
	// String타입인 "2024-02-17" -> Date타입으로 변환
	@DateTimeFormat(pattern="yyyy-MM-dd")
	@Future(message="오늘 이후의 날짜만 선택 가능합니다.")	// 오늘 이후의 날짜 체크(예약날짜이기 때문에)
	private Date ciRegDt;
	private String registerId;
	private Date registDt;

}