반응형
숨겨진 필드 요소

 

 

MemberController.java

package kr.or.ddit.controller;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import kr.or.ddit.mapper.ComCodeMapper;
import kr.or.ddit.service.MemberService;
import kr.or.ddit.vo.Address;
import kr.or.ddit.vo.Card;
import kr.or.ddit.vo.ComCodeVO;
import kr.or.ddit.vo.Member;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
public class MemberController {
	
	// DI(의존성 주입) / IoC(제어의 역전)
	@Autowired
	MemberService memberService;
	
	@Autowired
	ComCodeMapper comCodeMapper;
	
	@GetMapping("/registerForm05")
	public String registerForm05(@ModelAttribute("user") Member member,
				Model model) {

		member.setCoin(1000);
		
		//forwarding
		return "registerForm05";
	}
}

 

 

registerForm05.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<h2>Spring Form</h2>
<!-- modelAttribute 속성에 폼 객체의 속성명을 지정함 -->
<form:form modelAttribute="user" method="post" action="/registerForm01Post">
	<p>
		<!-- <input typd="hidden" id="coin" name="coin" /> -->
		<!-- 위의 코드와 같음 -->
		<form:hidden path="coin"/> 
	</p>
	
</form:form>

 

결과 화면1

 

 

 

라벨 요소

 

 

registerForm05.jsp

라벨을 클릭 시 포커스가 감

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<h2>Spring Form</h2>
<!-- modelAttribute 속성에 폼 객체의 속성명을 지정함 -->
<form:form modelAttribute="user" method="post" action="/registerForm01Post">
	<p><form:label path="userId">ID : </form:label>
		<form:input path="userId" placeholder="아이디" />
	</p>
	<p><form:label path="userName">이름 : </form:label>
		<form:input path="userName" placeholder="이름" />
	</p>
	<p><form:label path="password">패스워드 : </form:label>
		<form:input path="password" placeholder="패스워드" />
	</p>
</form:form>

 

결과 화면2

 

 

 

입력값 검증

 

 

스프링 MVC는 Bean Validation 기능을 이용해 요청 파라미터 값이 바인딩된 도메인 클래스(또는 커맨드 클래스)의 입력값 검증을 함 (VO에서 입력값 검증을 하는 절차로 진행됨)

 

 

환경 설정이 꼭 필요함

 

 

 

  • 환결 설정

pom.xml

</dependencies> 안에 추가

		<!-- 입력값을 검증하기 위한 라이브러리 의존 관계 정의 시작 
		스프링 
		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>

 

=> 추가한 후 run as에 maven build 해야 함

 

다운받아진 것을 확인할 수 있음

 

 

 

  • 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  대상 객체의 확인 조건을 만족할 경우 통과 가능

 

 

 

실습

 

 

Member.java

notNull인 컬럼을 VO에서 설정함

package kr.or.ddit.vo;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.NotBlank;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.multipart.MultipartFile;

import lombok.Data;

/*
1. 입력값 검증
스프링 MVC는 Bean Validation 기능을 이용해 요청 파라미터 값이 바인딩된
도메인 클래스(또는 커맨드 클래스)의 입력값 검증을 함
*/
/*
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 Member {
	//입력값 검증 규칙을 지정함
	@NotBlank
	private String userId;
	
	// 여러 개의 입력값 검증 규칙을 지정할 수 있음
	@NotBlank
	@Size(max=3)
	private String userName;
	
	private String password = "1234";
	@DateTimeFormat(pattern="yyyy-MM-dd") private Date regDate;
	private int coin;
	
	//스프링폼에서 radiobuttons의 path로 사용
	private String gender;
	//스프링폼에서 radiobuttons의 item로 사용
	private Map<String,String> genderCodeMap;
	
	private String email;
	private String birthDay;
	
	//스프링폼에서 select의 path로 사용
	private String nationality;
	//스프링폼에서 select의 item로 사용
	private Map<String,String> notionalityCodeMap;
	
	private String cars;
	private String[] carArray;
	
	//스프링폼에서 checkboxes의 path로 사용
	private ArrayList<String> carList;
	//스프링폼에서 checkboxes의 item으로 사용
	private Map<String, String> carMap;
	
	private String hobby;
	private String[] hobbyArray;
	
	//스프링폼에서 checkboxes의 path으로 사용
	private ArrayList<String> hobbyList;
	//스프링폼에서 checkboxes의 item으로 사용
	private Map<String,String> hobbyMap;
	
	private String developer;
	private boolean foreigner;
	
	private String introduction;
	private Date dateOfBirth;
	
	// 중첩된(nested) 자바빈즈
	// MEMBER : ADDRESS = 1 : 1
	private Address address;
	
	// MEMBER : CARD = 1 : N
	private List<Card> cardList;
	
	//스프링프레임워크에서 제공하는 MultipartFile 파일객체타입
	private MultipartFile picture;
	
	//<input type="file" name="pictures" multiple>
	// 위의 input과 name 값이 변수명과 같아야 함
	private MultipartFile[] pictures;
}

 

 

MemberController.java

package kr.or.ddit.controller;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import kr.or.ddit.mapper.ComCodeMapper;
import kr.or.ddit.service.MemberService;
import kr.or.ddit.vo.Address;
import kr.or.ddit.vo.Card;
import kr.or.ddit.vo.ComCodeVO;
import kr.or.ddit.vo.Member;
import lombok.extern.slf4j.Slf4j;
import oracle.jdbc.proxy.annotation.Post;

@Slf4j
@Controller
public class MemberController {
	
	// DI(의존성 주입) / IoC(제어의 역전)
	@Autowired
	MemberService memberService;
	
	@Autowired
	ComCodeMapper comCodeMapper;
	
	//1) 컨트롤러 메서드의 매개변수로 자바빈즈 객체가 전달이 되면 기본적으로 다시 화면으로 전달
	//컨트롤러는 기본적으로 자바빈즈 규칙에 맞는 객체는 다시 화면으로 폼 객체를 전달함
	//2) 폼 객체의 속성명은 직접 지정하지 않으면 폼 객체의 클래스명의 맨처음 문자를 소문자로 변환하여 처리함
	//3) ModelAttribute 애너테이션으로 폼 객체의 속성명을 직접 지정할 수 있음
	@GetMapping("/registerForm05")
	public String registerForm05(@ModelAttribute("user") Member member,
				Model model) {

//		model.addAttribute("member", new Member());
		
		//폼 객체의 프로퍼티에 값을 지정
//		member.setUserId("gaeddongi");
//		member.setUserName("개똥이");
		member.setCoin(1000);
		member.setPassword("java");
		member.setIntroduction("저는 개똥이 입니다.\n왜일까요?");
		
		//모델에  Map 타입의 데이터를 생성하여 추가한 후에 화면에 전달
		Map<String, String> hobbyMap = new HashMap<String, String>();
		hobbyMap.put("kmj", "Music");
		hobbyMap.put("ksy", "FootBall");
		hobbyMap.put("esb", "showping");

		member.setHobbyMap(hobbyMap);
		
		//Music을 미리 체크 처리
		String[] hobbyArray = {"ksy"};
		member.setHobbyArray(hobbyArray);
		
		member.setHobby("ksy");
		
		//보유자동차
		Map<String,String> carMap = new HashMap<String, String>();
		carMap.put("qm5", "qm5");
		carMap.put("sm6", "sm6");
		carMap.put("volvo", "volvo");
		
		member.setCarMap(carMap);
		
		//volvo을 미리 체크 처리
		String[] carArray = {"volvo"};
		member.setCarArray(carArray);
		
		//성별
		Map<String,String> genderCodeMap = new HashMap<String, String>();
		genderCodeMap.put("Male", "남성");
		genderCodeMap.put("Female", "여성");
		genderCodeMap.put("etc", "기타");
		
		member.setGenderCodeMap(genderCodeMap);
		
		//미리 선택 처리
		member.setGender("Female");
		
		//11. 셀렉트 박스 요소
		//국적 선택
		Map<String, String> notionalityCodeMap = 
				new HashMap<String, String>();
		notionalityCodeMap.put("Korea", "대한민국");
		notionalityCodeMap.put("Germany", "독일");
		notionalityCodeMap.put("Australia", "오스트레일리아");
		
		member.setNotionalityCodeMap(notionalityCodeMap);
		
		//국적 미리 선택
		member.setNationality("Korea");
		
		//국적을 공통코드로부터 가져와보자
		ComCodeVO comCodeVO = this.comCodeMapper.getComCode("natn");
		log.info("registerFOrm05->comCodeVO : " + comCodeVO);
		
		model.addAttribute("comCodeVO", comCodeVO);
		
		//forwarding
		return "registerForm05";
	}
	
	/*
	입력값 검증을 하기 위해서는 메서드 매개변수에 도메인 클래스를 정의하고 골뱅이Validated를 지정
	입력값 검증 대상의 도메인 클래스 직후에 BindingResult를 정의함
	BindingResult에는 요청 데이터의 바인딩 오류와 입력값 검증 오류 정보가 저장됨
	*/
	@PostMapping("/registerForm01Post")
	public String registerForm01Post(
			@Validated @ModelAttribute("user") Member member,
			BindingResult brResult,
			Model model
			) {
		log.info("registerForm01Post->member : " + member);
		//1)true : 문제 있음 / 2)false : 문제 없음
		log.info("brResult.hasErrors() : " + brResult.hasErrors());
		
		/*----*/
		//폼 객체의 프로퍼티에 값을 지정
		
		member.setCoin(1000);
		member.setPassword("java");
		member.setIntroduction("저는 개똥이 입니다.\n왜일까요?");
		
		//모델에 Map 타입의 데이터를 생성하여 추가한 후에 화면(jsp)에 전달
		Map<String,String> hobbyMap = 
		      new HashMap<String, String>();
		hobbyMap.put("Music", "음악");
		hobbyMap.put("FootBall", "축구");
		hobbyMap.put("Book", "도서");
		hobbyMap.put("Travel", "여행");
		
		member.setHobbyMap(hobbyMap);
		
		//Music을 미리 체크 처리
		String[] hobbyArray = {"kmj"};
		member.setHobbyArray(hobbyArray);
		
		member.setHobby("kmj");
		
		//보유자동차
		Map<String,String> carMap = 
		      new HashMap<String, String>();      
		carMap.put("qm5", "qm5");
		carMap.put("sm6", "sm6");
		carMap.put("volvo", "volvo");
		
		member.setCarMap(carMap);
		
		//volvo를 미리 체크 처리
		String[] carArray = {"volvo"};
		member.setCarArray(carArray);
		
		//성별
		Map<String,String> genderCodeMap = 
		      new HashMap<String, String>();
		genderCodeMap.put("Male", "남성");
		genderCodeMap.put("Female", "여성");
		genderCodeMap.put("etc", "기타");
		
		member.setGenderCodeMap(genderCodeMap);
		
		//미리 선택 처리
		member.setGender("Female");
		
		//11. 셀렉트 박스 요소
		//국적 선택
		Map<String,String> notionalityCodeMap = 
		      new HashMap<String, String>();
		notionalityCodeMap.put("Korea", "대한민국");
		notionalityCodeMap.put("Germany", "독일");
		notionalityCodeMap.put("Australia", "오스트레일리아");
		notionalityCodeMap.put("Canada", "캐나다");
		
		member.setNotionalityCodeMap(notionalityCodeMap);
		//국적 미리 선택
		member.setNationality("Korea");
		
		//국적을 공통코드로부터 가져와보자
		ComCodeVO comCodeVO = this.comCodeMapper.getComCode("natn");
		log.info("registerForm05->comCodeVO : " + comCodeVO);
		
		model.addAttribute("comCodeVO", comCodeVO);
		/*----*/
		
		
		return "registerForm05";
	}
}

 

 

registerForm05.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<h2>Spring Form</h2>
<!-- modelAttribute 속성에 폼 객체의 속성명을 지정함 -->
<form:form modelAttribute="user" method="post" action="/registerForm01Post">
<hr/>
	<p><form:label path="userId">ID : </form:label>
		<form:input path="userId" placeholder="아이디" />
	</p>
	<p><form:label path="userName">이름 : </form:label>
		<form:input path="userName" placeholder="이름" />
	</p>
	<p><form:label path="password">패스워드 : </form:label>
		<form:input path="password" placeholder="패스워드" />
	</p>
	
	<!-- 12. 숨겨진 필드 요소
	HTML 숨겨진 필드를 출력하려면 hidden 요소를 사용
	 -->
	<p>
		<!-- <input typd="hidden" id="coin" name="coin" /> -->
		<!-- 위의 코드와 같음 -->
		<form:hidden path="coin"/> 
	</p>
	
	<p>패스워드 : 
		<input type="password" name="password" id="password"/>
		<!-- 값을 설정해서 뷰에 전달하더라도 패스워드 필드에 반영 안 됨 -->
		<form:input path="password" /> <!-- 바인딩되어서 값이 들어옴 -->
	</p> 
	<p>소개글 :
		<form:textarea path="introduction" rows="6" cols="30"/> 
	</p>
	<p>개발자여부 : (String)
		<form:checkbox path="developer" value="Y" label="Y/없음"/>
	</p>
	<p>외국인여부 : (boolean)
		<form:checkbox path="foreigner" value="false" label="trud/false"/>
	</p>
	<p>성별 : (String gender)
		<form:radiobuttons items="${user.genderCodeMap}" path="gender"/>
	</p>
	<p>
		<form:radiobutton path="gender" value="Male" label="남성"/>&nbsp;
		<form:radiobutton path="gender" value="Female" label="여성"/>&nbsp;
		<form:radiobutton path="gender" value="etc" label="기타"/>
	</p>
	<p>취미 :
		<form:checkboxes items="${user.hobbyMap}" path="hobbyArray"/>
	</p>
	<p>
		<form:checkbox path="hobby" value="kmj" label="Music"/>&nbsp; 
		<form:checkbox path="hobby" value="ksy" label="FootBall"/>&nbsp; 
		<form:checkbox path="hobby" value="esb" label="showping"/>
	</p>
	<p>
		<form:checkbox path="hobbyArray" value="kmj" label="Music"/>&nbsp; 
		<form:checkbox path="hobbyArray" value="ksy" label="FootBall"/>&nbsp; 
		<form:checkbox path="hobbyArray" value="esb" label="showping"/>
	</p>
	<p>보유자동차 :
		<form:checkboxes items="${user.carMap}" path="carArray"/> 
	</p>
	<p>국적 : (String nationality)
		<form:select path="nationality" items="${user.notionalityCodeMap}"></form:select>
	</p>
	<!-- 국적을 공통 코드로부터 가져와보자 -->
	<select id="nationality" name="nationality">
		<c:forEach var="comCodeDetailVO" items="${comCodeVO.comCodeDetailVOList}" varStatus="stat">
			<option value="${comCodeDetailVO.comCodeDetail}">${comCodeDetailVO.comCodeDetailNm}</option>
		</c:forEach>
	</select>
	<p>
		<form:button name="register">등록</form:button>
	</p>
</form:form>

 

결과 화면3-1 : 값 안 넣고 등록 클릭시 3-2

 

결과 화면3-2 : brResult.hasErrors()이 true로 뜸

 

 

 

  • 검증오류 발생 시 확인 (null값일때, 이메일, 날짜)

 

MemberController.java

package kr.or.ddit.controller;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import kr.or.ddit.mapper.ComCodeMapper;
import kr.or.ddit.service.MemberService;
import kr.or.ddit.vo.Address;
import kr.or.ddit.vo.Card;
import kr.or.ddit.vo.ComCodeVO;
import kr.or.ddit.vo.Member;
import lombok.extern.slf4j.Slf4j;
import oracle.jdbc.proxy.annotation.Post;

@Slf4j
@Controller
public class MemberController {
	
	// DI(의존성 주입) / IoC(제어의 역전)
	@Autowired
	MemberService memberService;
	
	@Autowired
	ComCodeMapper comCodeMapper;
	
	//1) 컨트롤러 메서드의 매개변수로 자바빈즈 객체가 전달이 되면 기본적으로 다시 화면으로 전달
	//컨트롤러는 기본적으로 자바빈즈 규칙에 맞는 객체는 다시 화면으로 폼 객체를 전달함
	//2) 폼 객체의 속성명은 직접 지정하지 않으면 폼 객체의 클래스명의 맨처음 문자를 소문자로 변환하여 처리함
	//3) ModelAttribute 애너테이션으로 폼 객체의 속성명을 직접 지정할 수 있음
	@GetMapping("/registerForm05")
	public String registerForm05(@ModelAttribute("user") Member member,
				Model model) {

//		model.addAttribute("member", new Member());
		
		//폼 객체의 프로퍼티에 값을 지정
//		member.setUserId("gaeddongi");
//		member.setUserName("개똥이");
		member.setCoin(1000);
		member.setPassword("java");
		member.setIntroduction("저는 개똥이 입니다.\n왜일까요?");
		
		//모델에  Map 타입의 데이터를 생성하여 추가한 후에 화면에 전달
		Map<String, String> hobbyMap = new HashMap<String, String>();
		hobbyMap.put("kmj", "Music");
		hobbyMap.put("ksy", "FootBall");
		hobbyMap.put("esb", "showping");

		member.setHobbyMap(hobbyMap);
		
		//Music을 미리 체크 처리
		String[] hobbyArray = {"ksy"};
		member.setHobbyArray(hobbyArray);
		
		member.setHobby("ksy");
		
		//보유자동차
		Map<String,String> carMap = new HashMap<String, String>();
		carMap.put("qm5", "qm5");
		carMap.put("sm6", "sm6");
		carMap.put("volvo", "volvo");
		
		member.setCarMap(carMap);
		
		//volvo을 미리 체크 처리
		String[] carArray = {"volvo"};
		member.setCarArray(carArray);
		
		//성별
		Map<String,String> genderCodeMap = new HashMap<String, String>();
		genderCodeMap.put("Male", "남성");
		genderCodeMap.put("Female", "여성");
		genderCodeMap.put("etc", "기타");
		
		member.setGenderCodeMap(genderCodeMap);
		
		//미리 선택 처리
		member.setGender("Female");
		
		//11. 셀렉트 박스 요소
		//국적 선택
		Map<String, String> notionalityCodeMap = 
				new HashMap<String, String>();
		notionalityCodeMap.put("Korea", "대한민국");
		notionalityCodeMap.put("Germany", "독일");
		notionalityCodeMap.put("Australia", "오스트레일리아");
		
		member.setNotionalityCodeMap(notionalityCodeMap);
		
		//국적 미리 선택
		member.setNationality("Korea");
		
		//국적을 공통코드로부터 가져와보자
		ComCodeVO comCodeVO = this.comCodeMapper.getComCode("natn");
		log.info("registerFOrm05->comCodeVO : " + comCodeVO);
		
		model.addAttribute("comCodeVO", comCodeVO);
		
		//forwarding
		return "registerForm05";
	}
	
	/*
	입력값 검증을 하기 위해서는 메서드 매개변수에 도메인 클래스를 정의하고 골뱅이Validated를 지정
	입력값 검증 대상의 도메인 클래스 직후에 BindingResult를 정의함
	BindingResult에는 요청 데이터의 바인딩 오류와 입력값 검증 오류 정보가 저장됨
	*/
	@PostMapping("/registerForm01Post")
	public String registerForm01Post(
			@Validated @ModelAttribute("user") Member member,
			BindingResult brResult,
			Model model
			) {
		log.info("registerForm01Post->member : " + member);
		//1)true : 문제 있음 / 2)false : 문제 없음
		log.info("brResult.hasErrors() : " + brResult.hasErrors());
		
		
		/* 2. 입력값 검증 결과
		입력값 검증 대상의 도메인 클래스 직후에 BindingResult를 정의함
		BindingResult에는 요청 데이터의 바인딩 에러와 입력값 검증 에러 정보가 저장됨
		*/
		//검증 오류 발생 시 => insert 안함
		if(brResult.hasErrors()) {//true : 오류 발생
			//검사 결과 오류 확인
			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("globalErrors : " + objectError);
			}
			for (FieldError fieldError : fieldErrors) {
				log.info("fieldErrors : " + fieldError);
			}
			
			/*----*/
			//폼 객체의 프로퍼티에 값을 지정
			
			member.setCoin(1000);
			member.setPassword("java");
			member.setIntroduction("저는 개똥이 입니다.\n왜일까요?");
			
			//모델에 Map 타입의 데이터를 생성하여 추가한 후에 화면(jsp)에 전달
			Map<String,String> hobbyMap = 
			      new HashMap<String, String>();
			hobbyMap.put("Music", "음악");
			hobbyMap.put("FootBall", "축구");
			hobbyMap.put("Book", "도서");
			hobbyMap.put("Travel", "여행");
			
			member.setHobbyMap(hobbyMap);
			
			//Music을 미리 체크 처리
			String[] hobbyArray = {"kmj"};
			member.setHobbyArray(hobbyArray);
			
			member.setHobby("kmj");
			
			//보유자동차
			Map<String,String> carMap = 
			      new HashMap<String, String>();      
			carMap.put("qm5", "qm5");
			carMap.put("sm6", "sm6");
			carMap.put("volvo", "volvo");
			
			member.setCarMap(carMap);
			
			//volvo를 미리 체크 처리
			String[] carArray = {"volvo"};
			member.setCarArray(carArray);
			
			//성별
			Map<String,String> genderCodeMap = 
			      new HashMap<String, String>();
			genderCodeMap.put("Male", "남성");
			genderCodeMap.put("Female", "여성");
			genderCodeMap.put("etc", "기타");
			
			member.setGenderCodeMap(genderCodeMap);
			
			//미리 선택 처리
			member.setGender("Female");
			
			//11. 셀렉트 박스 요소
			//국적 선택
			Map<String,String> notionalityCodeMap = 
			      new HashMap<String, String>();
			notionalityCodeMap.put("Korea", "대한민국");
			notionalityCodeMap.put("Germany", "독일");
			notionalityCodeMap.put("Australia", "오스트레일리아");
			notionalityCodeMap.put("Canada", "캐나다");
			
			member.setNotionalityCodeMap(notionalityCodeMap);
			//국적 미리 선택
			member.setNationality("Korea");
			
			//국적을 공통코드로부터 가져와보자
			ComCodeVO comCodeVO = this.comCodeMapper.getComCode("natn");
			log.info("registerForm05->comCodeVO : " + comCodeVO);
			
			model.addAttribute("comCodeVO", comCodeVO);
			/*----*/
			
			//forwarding
			return "registerForm05";
		}
		
        
		/*----*/
		//폼 객체의 프로퍼티에 값을 지정
		
		member.setCoin(1000);
		member.setPassword("java");
		member.setIntroduction("저는 개똥이 입니다.\n왜일까요?");
		
		//모델에 Map 타입의 데이터를 생성하여 추가한 후에 화면(jsp)에 전달
		Map<String,String> hobbyMap = 
		      new HashMap<String, String>();
		hobbyMap.put("Music", "음악");
		hobbyMap.put("FootBall", "축구");
		hobbyMap.put("Book", "도서");
		hobbyMap.put("Travel", "여행");
		
		member.setHobbyMap(hobbyMap);
		
		//Music을 미리 체크 처리
		String[] hobbyArray = {"kmj"};
		member.setHobbyArray(hobbyArray);
		
		member.setHobby("kmj");
		
		//보유자동차
		Map<String,String> carMap = 
		      new HashMap<String, String>();      
		carMap.put("qm5", "qm5");
		carMap.put("sm6", "sm6");
		carMap.put("volvo", "volvo");
		
		member.setCarMap(carMap);
		
		//volvo를 미리 체크 처리
		String[] carArray = {"volvo"};
		member.setCarArray(carArray);
		
		//성별
		Map<String,String> genderCodeMap = 
		      new HashMap<String, String>();
		genderCodeMap.put("Male", "남성");
		genderCodeMap.put("Female", "여성");
		genderCodeMap.put("etc", "기타");
		
		member.setGenderCodeMap(genderCodeMap);
		
		//미리 선택 처리
		member.setGender("Female");
		
		//11. 셀렉트 박스 요소
		//국적 선택
		Map<String,String> notionalityCodeMap = 
		      new HashMap<String, String>();
		notionalityCodeMap.put("Korea", "대한민국");
		notionalityCodeMap.put("Germany", "독일");
		notionalityCodeMap.put("Australia", "오스트레일리아");
		notionalityCodeMap.put("Canada", "캐나다");
		
		member.setNotionalityCodeMap(notionalityCodeMap);
		//국적 미리 선택
		member.setNationality("Korea");
		
		//국적을 공통코드로부터 가져와보자
		ComCodeVO comCodeVO = this.comCodeMapper.getComCode("natn");
		log.info("registerForm05->comCodeVO : " + comCodeVO);
		
		model.addAttribute("comCodeVO", comCodeVO);
		/*----*/
		
		
		return "registerForm05";
	}
}

 

 

registerForm05.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<h2>Spring Form</h2>
<!-- modelAttribute 속성에 폼 객체의 속성명을 지정함 -->
<form:form modelAttribute="user" method="post" action="/registerForm01Post">
<hr/>
	<p><form:label path="userId">ID : </form:label>
		<form:input path="userId" placeholder="아이디" />
		<font color="red"><form:errors path="userId" /></font>
	</p>
	<p><form:label path="userName">이름 : </form:label>
		<form:input path="userName" placeholder="이름" />
		<font color="red"><form:errors path="userName" /></font>
	</p>
	<p><form:label path="password">패스워드 : </form:label>
		<form:input path="password" placeholder="패스워드" />
	</p>
	
	<p>
		<form:hidden path="coin"/> 
	</p>
	
	<p>패스워드 : 
		<input type="password" name="password" id="password"/>
		<form:input path="password" /> <!-- 바인딩되어서 값이 들어옴 -->
	</p> 
	<p>소개글 :
		<form:textarea path="introduction" rows="6" cols="30"/> 
	</p>
	<p>개발자여부 : (String)
		<form:checkbox path="developer" value="Y" label="Y/없음"/>
	</p>
	<p>외국인여부 : (boolean)
		<form:checkbox path="foreigner" value="false" label="trud/false"/>
	</p>
	<p><!-- <label for="email"  -->
		<form:label path="email">이메일 주소 :</form:label> 
		<!-- <input type="text" id="email" name="email" -->
		<form:input path="email" />
		<font color="red"><form:errors path="email" /></font>
	</p>
	<p><form:label path="dateOfBirth">생일 :</form:label> 
		<form:input path="dateOfBirth" placeholder="ex)2020-03-01" />
		<font color="red"><form:errors path="dateOfBirth" /></font>
	</p>
	<p>성별 : (String gender)
		<form:radiobuttons items="${user.genderCodeMap}" path="gender"/>
	</p>
	<p>
		<form:radiobutton path="gender" value="Male" label="남성"/>&nbsp;
		<form:radiobutton path="gender" value="Female" label="여성"/>&nbsp;
		<form:radiobutton path="gender" value="etc" label="기타"/>
	</p>
	<p>취미 :
		<form:checkboxes items="${user.hobbyMap}" path="hobbyArray"/>
	</p>
	<p>
		<form:checkbox path="hobby" value="kmj" label="Music"/>&nbsp; 
		<form:checkbox path="hobby" value="ksy" label="FootBall"/>&nbsp; 
		<form:checkbox path="hobby" value="esb" label="showping"/>
	</p>
	<p>
		<form:checkbox path="hobbyArray" value="kmj" label="Music"/>&nbsp; 
		<form:checkbox path="hobbyArray" value="ksy" label="FootBall"/>&nbsp; 
		<form:checkbox path="hobbyArray" value="esb" label="showping"/>
	</p>
	<p>보유자동차 :
		<form:checkboxes items="${user.carMap}" path="carArray"/> 
	</p>
	<p>국적 : (String nationality)
		<form:select path="nationality" items="${user.notionalityCodeMap}"></form:select>
	</p>
	<select id="nationality" name="nationality">
		<c:forEach var="comCodeDetailVO" items="${comCodeVO.comCodeDetailVOList}" varStatus="stat">
			<option value="${comCodeDetailVO.comCodeDetail}">${comCodeDetailVO.comCodeDetailNm}</option>
		</c:forEach>
	</select>
	<p>
		<form:button name="register">등록</form:button>
	</p>
</form:form>

 

 

Member.java

package kr.or.ddit.vo;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.validation.constraints.Past;
import javax.validation.constraints.Size;

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

import lombok.Data;

@Data
public class Member {
	//입력값 검증 규칙을 지정함
	@NotBlank
	private String userId;
	
	// 여러 개의 입력값 검증 규칙을 지정할 수 있음
	@NotBlank(message="사용자명을 입력해주세요.")
	@Size(max=3, message="최대 3글자까지만 작성해주세요.")
	private String userName;
	
	private String password = "1234";
	@DateTimeFormat(pattern="yyyy-MM-dd") private Date regDate;
	private int coin;
	
	//스프링폼에서 radiobuttons의 path로 사용
	private String gender;
	//스프링폼에서 radiobuttons의 item로 사용
	private Map<String,String> genderCodeMap;
	
	//이메일 주소 형식인지 검사
	@NotBlank(message="이메일주소를 입력해주세요.")
	@Email(message="올바른 이메일주소를 입력해주세요.")
	private String email;
	
	private String birthDay;
	
	//스프링폼에서 select의 path로 사용
	private String nationality;
	//스프링폼에서 select의 item로 사용
	private Map<String,String> notionalityCodeMap;
	
	private String cars;
	private String[] carArray;
	
	//스프링폼에서 checkboxes의 path로 사용
	private ArrayList<String> carList;
	//스프링폼에서 checkboxes의 item으로 사용
	private Map<String, String> carMap;
	
	private String hobby;
	private String[] hobbyArray;
	
	//스프링폼에서 checkboxes의 path으로 사용
	private ArrayList<String> hobbyList;
	//스프링폼에서 checkboxes의 item으로 사용
	private Map<String,String> hobbyMap;
	
	private String developer;
	private boolean foreigner;
	
	private String introduction;
	
	@DateTimeFormat(pattern="yyyy-MM-dd")
	@Past(message="과거 날짜를 입력해주세요")
	private Date dateOfBirth;
	
	// 중첩된(nested) 자바빈즈
	// MEMBER : ADDRESS = 1 : 1
	private Address address;
	
	// MEMBER : CARD = 1 : N
	private List<Card> cardList;
	
	//스프링프레임워크에서 제공하는 MultipartFile 파일객체타입
	private MultipartFile picture;
	
	//<input type="file" name="pictures" multiple>
	// 위의 input과 name 값이 변수명과 같아야 함
	private MultipartFile[] pictures;
}

 

결과 화면4-1 : ID, 이름 미입력 & 생일을 미래 날짜로 입력 & 이메일에 @ 없게 입력

 

결과 화면4-2

 

 

 

  • 검증오류 발생 시 확인 (중첩된 자바빈즈)

 

Member.java

추가 또는 변경함

	// 중첩된(nested) 자바빈즈
	// MEMBER : ADDRESS = 1 : 1
	/*
	4. 중첩된 자바빈즈 입력값 검증
	중첩된 자바빈즈와 자바빈즈의 컬렉션에서 정의한 프로퍼티에 대해
	입력값 검증을 할 때는 골뱅이Valid를 지정함
	*/
	//중첩된 자바빈즈의 입력값 검증을 지정함
	@Valid
	private Address address;
	
	// MEMBER : CARD = 1 : N
	//자바빈즈 컬렉션의 입력값 검증을 지정함
	@Valid
	private List<Card> cardList;

 

 

Address.java

package kr.or.ddit.vo;

import org.hibernate.validator.constraints.NotBlank;

import lombok.Data;

@Data
public class Address {
	//Member 자바빈 클래스의 프로퍼티
	private String userId;
	
	@NotBlank(message="우편번호를 입력해주세요")
	private String postCode; //우편번호
	
	@NotBlank(message="주소를 입력해주세요")
	private String location; //주소
}

 

 

Card.java

package kr.or.ddit.vo;

import java.util.Date;

import javax.validation.constraints.Future;

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

import lombok.Data;

@Data
public class Card {
	//Member 자바빈 클래스의 프로퍼티
	private String userId;
	
	@NotBlank(message = "카드 번호를 입력해주세요")
	private String no;
	
	@Future(message = "미래의 날짜를 입력해주세요")
	@DateTimeFormat(pattern = "yyyyMMdd")
	private Date validMonth;
}

 

 

registerForm05.jsp

</form:form> 안에 추가

	<p>주소 : 
		1) 우편번호 : <form:input path="address.postCode" />
			<font color="red"><form:errors path="address.postCode" /></font>
		<br />
		2) 주소 : <form:input path="address.location" />
			<font color="red"><form:errors path="address.location" /></font>
	</p>
	
	<p>카드 : 
		<form:input path="cardList[0].no" placeholder="카드번호"/>
			<font color="red"><form:errors path="cardList[0].no" /></font>
		<form:input path="cardList[0].validMonth"  placeholder="ex)20240517"/>
			<font color="red"><form:errors path="cardList[0].validMonth" /></font>
		<br />
		<form:input path="cardList[1].no" placeholder="카드번호"/>
			<font color="red"><form:errors path="cardList[1].no" /></font>
		<form:input path="cardList[1].validMonth"  placeholder="ex)20240517"/>
			<font color="red"><form:errors path="cardList[1].validMonth" /></font>
	</p>

 

결과 화면5-1 : 카드번호 null, 과거 날짜 입력

 

결과 화면5-2

 

 

 

@Range : int 할 때 씀

 

 

골뱅이Range(min = 1, message="정렬순서를 입력해주세요")
:  private int orderNo;

- 문자열을 다룰 때 사용
Size(min=?, max=?) // 최소 길이, 최대 길이 제한

 

- 숫자를 다룰 때 사용
Positive // 양수만 허용
PositiveOrZero // 양수와 0만 허용
Negative // 음수만 허용
NegativeOrZero // 음수와 0만 허용

 

 

 

  • 순서

1. 스프링폼으로
 - form:form
 - form:input
 - form:errors path.. 처리
 
2. 컨트롤러
 - @Validated
 - BindingResult -> brResult.hasErrors()

3. 자바빈 클래스(VO)
 - String 타입 : NotBlank
 - int    타입 : Range(min=1,message..) 

 

 

 

  • 실습

LprodController.java

package kr.or.ddit.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
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.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import kr.or.ddit.service.LprodService;
import kr.or.ddit.vo.LprodVO;
import kr.or.ddit.vo.ProductVO;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@RequestMapping("/lprod")
@Controller
public class LprodController {
	
	//DI(의존성 주입) / IoC(제어의 역전)
	@Autowired
	LprodService lprodService;
	
	/*
	요청URI : /lprod/create
	요청파라미터 : 
	요청방식 : get
	 */
	@RequestMapping(value="/create",method=RequestMethod.GET)
	public ModelAndView create(LprodVO lprodVO) {
		ModelAndView mav = new ModelAndView();
		
		// 데이터
		mav.addObject("title", "상품분류 등록");
		
		// jsp
		// /WEB-INF/views/ + lprod/create +     .jsp
		mav.setViewName("lprod/create");
		
		return mav;
	}
	
	/* 
	요청URI : /lprod/create
	요청파라미터 : {lprodId=14, lprodGu=P501, lprodNm=분식류}
	요청방식 : post
	*/
	@RequestMapping(value="/create", method=RequestMethod.POST)
	public String createPost(
			@Validated @ModelAttribute("lprod") LprodVO lprodVO,
			BindingResult brResult) {
		log.info("createPost->lprodVO : " + lprodVO);
		
		
		log.info("createPost -> brResult.hasErrors() : " + brResult.hasErrors());
		
		if(brResult.hasErrors()) {//true(오류 발생)
			//검사 결과 오류 확인
			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);
			}
			
			//forwording
			return "lprod/create";
		}
		
		
		int result = this.lprodService.createPost(lprodVO);
		log.info("createPost->result : " + result);
		
//		ModelAndView mav = new ModelAndView();
		
//		// redirect : 새로운 URI 요청
//		mav.setViewName("redirect:/lprod/create");
		
		return "redirect:/lprod/create";
	}
}

 

 

LprodVO.java

package kr.or.ddit.vo;

import java.util.List;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;

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

import lombok.Data;

@Data
public class LprodVO {
	@Range(min=1, message = "상품분류 아이디를 입력해주세요")
	private int lprodId;
	
	@NotBlank(message = "상품분류 코드를 입력해주세요")
	private String lprodGu;
	
	@NotBlank(message = "상품분류 명을 입력해주세요")
	private String lprodNm;
	
	//상품분류코드	: 상품		= 1 : N
	//LPROD		:PRODUCT	= 1 : N
	@Valid
	private List<ProductVO> productVOList;
	
	
	private MultipartFile[] pictures;
}

 

 

ProductVO.java

package kr.or.ddit.vo;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;

import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.Range;

import lombok.Data;

@Data
public class ProductVO {
	@NotBlank(message="상품아이디를 입력해주세요")
	private String productId;
	
	@NotBlank(message="상품명을 입력해주세요")
	private String pname;
	
	@Range(min=1,message="상품 가격을 입력해주세요")
	private int unitPrice;
	
	private String description;
	private String manufacturer;
	private String category;
	private int unitsInStock;
	private String condition;
	private String filename;
	private int quantity;
}

 

 

create.jsp

form: 태그로 변경 후 function fn_check() 추가, 등록 버튼 변경

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="/resources/js/jquery.min.js"></script>
<title>Insert title here</title>
<script type="text/javascript">
$(function(){
	// 상품분류 아이디 자동생성
	getLprodId();

 	$("#btnAuto").on("click",function(){
		let lprodGu = $("input[name='lprodGu']").val();
		
		if($.trim(lprodGu)==""){
			alert("상품분류코드를 작성해주세요");
			$("input[name='lprodGu']").focus();
			return;
		}
		$(".pArea").each(function(idx,row){
			$(this).children().first().val(lprodGu+(idx+1));
		});
	});

	
	// 상품 추가
	/* 
	before : 선택한 요소의 앞에 내용 삽입
	after : 선택한 요소의 뒤에 내용 삽입
	prepend : 선택한요소의 자식요소 앞에 내용삽입
	append : 선택한요소의 자식요소 뒤에 내용삽입 
	*/
	$("#btnPlus").on("click",function(){
		let pAreaLen = $(".pArea").length;
		
		let str = "";
			str += "<p class='pArea'>";
			str += "<input type='text' name='productVOList["+pAreaLen+"].productId' id='productId"+pAreaLen+"' class='form-control col-sm-3 float-left' placeholder='상품아이디'>";
			str += "<input type='text' name='productVOList["+pAreaLen+"].pname' id='pname"+pAreaLen+"' class='form-control col-sm-3 float-left' placeholder='상품명'>";
			str += "<input type='text' name='productVOList["+pAreaLen+"].unitPrice' id='unitPrice"+pAreaLen+"' class='form-control col-sm-3 float-left clsUnitPrice' placeholder='가격'>";
			str += "</p>";
			str += "<p style='clear:both;'></p>";
		$("#btnSubmit").parent().before(str);
		
	});
	
	$("#btnMinus").on("click",function(){
		let pAreaLen = $(".pArea").length;
		console.log("pAreaLen : ", pAreaLen);
		
		if(pAreaLen < 2) {
			alert("최소 하나는 존재해야 합니다.");
			return;
		}
		
		// next는 선택한 요소의 다음 형제 요소를 반환
		$(".pArea").last().next().remove();
		$(".pArea").last().remove();
	});
	
	
	$("#btnSubmit").on("click",function(){
		let lprodId = $("input[name='lprodId']").val();
		let lprodGu = $("input[name='lprodGu']").val();
		let lprodNm = $("input[name='lprodNm']").val();
		
		//<form></form>
		let formData = new FormData();
		
		formData.append("lprodId",lprodId);
		formData.append("lprodGu",lprodGu);
		formData.append("lprodNm",lprodNm);
		
		//<input type="file"...
		let fileObj = $("#pictures");
		//선택된 파일객체들
		let files = fileObj[0].files;
		console.log("files.length : ", files.length); //3
		
		for(let i=0;i<files.length; i++){ //0,1,2
			formData.append("pictures",files[i]); // 파일이 n개일때 하나씩 append 함
		}
		
		//<p class="pArea".. 반복됨
		$(".pArea").each(function(idx,data){
		   let productId = $(this).children().eq(0).val();
		   let pname = $(this).children().eq(1).val();
		   let unitPrice = $(this).children().eq(2).val();
		   
		   formData.append("productVOList["+idx+"].productId", productId);
		   formData.append("productVOList["+idx+"].pname", pname);
		   formData.append("productVOList["+idx+"].unitPrice", unitPrice);
		});
		
		
		//JSON오브젝트
		let data = {
			"lprodId":lprodId,
			"lprodGu":lprodGu,
			"lprodNm":lprodNm
		};
		
		console.log("data : ", data);
	});
});// end 달러(function)

function getLprodId(){
	//아작나서유..(피)씨다타써
	$.ajax({
		url:"/lprod/getLprodId",
		type:"post",
		dataType:"text",
		success:function(result){
			console.log("result : ", result);
			
			$("input[name='lprodId']").val(result);
		}
	});
}

function fn_check(){
	console.log("왔다");
	
	let flag = 1;
	
	/* 동적으로 생성된 것들이 있기에 */
	$(".clsUnitPrice").each(function(){
		let str = $(this).val();
		
		console.log("str : " + str);
		
		if(str=="") {
			alert("상품 가격을 입력해주세요");
			flag = 0;
		}
	});
	
	if(flag==1) {
		return true;
	} else {
		return false;
	}
}
</script>
</head>
<body>
<h1>상품분류 등록</h1>
 
 <!-- onsubmit : submit 버튼 클릭 시 핸들러함수로부터 true를 리턴 받아야 submit이 완료됨 -->
 <form:form modelAttribute="lprodVO" action="/lprod/create" method="post" enctype="multipart/form-data"
 	onsubmit="return fn_check()">
	 <p>
	 	<form:input path="lprodId" placeholder="상품분류 아이디(ex. 14)" readonly="true"/>
	 	<code><form:errors path="lprodId" /></code>
	 </p>
	 <p>
	 	<form:input path="lprodGu" placeholder="상품분류 코드(ex. P501)" required="true" />
	 	<code><form:errors path="lprodGu" /></code>
	 	<button type="button" name="btnAuto" id="btnAuto" class="btn btn-primary btn-xs col-sm-2">상품코드 자동생성</button>
	 </p>
	 <p>
	 	<form:input path="lprodNm" placeholder="상품분류 명(ex. 분식류)" />
	 	<code><form:errors path="lprodNm" /></code>
	 </p>
	 <hr />
	 <p><input type="file" name="pictures" id="pictures" multiple /></p>
	 <hr />
	 <p id="pFunc">
		<button type="button" class="btn btn-info btn-sm col-sm-1" id="btnPlus" >+</button>
		<button type="button" class="btn btn-danger btn-sm col-sm-1" id="btnMinus" >-</button>
	 </p>
	 
	 <!--
	 1) + : 영역이 하나 생김
	 2) - : 마지막 영역 삭제 
	  -->
	 <p class="pArea">
	 	<form:input path="productVOList[0].productId" id="productId0" class="form-control col-sm-3 float-left" placeholder="상품아이디" />
	 		<code><form:errors path="productVOList[0].productId" /></code>
	 	<form:input path="productVOList[0].pname" id="pname0" class="form-control col-sm-3 float-left" placeholder="상품명" />
	 		<code><form:errors path="productVOList[0].pname" /></code>
	 	<input type="number" name="productVOList[0].unitPrice" id="unitPrice0" class="form-control col-sm-3 float-left clsUnitPrice" placeholder="가격" />
	 		<code><form:errors path="productVOList[0].unitPrice" /></code>
	 </p>
	 <p style="clear:both;"></p>
	 <p>
	 	<form:button name="btnSubmit">등록</form:button>
	 </p>
 </form:form>
</body>
</html>

 

결과 화면6 : 등록 버튼 클릭 시 알람

 

 

반응형