본문 바로가기
java/spring

스프링 파일업로드

by rewind 2024. 2. 4.

파일 업로드 마무리

 

자바스크립트 이미지 오브젝트 배열 메소드 부연설명

 

https://talkwithcode.tistory.com/19

 

Array.prototype.slice.call() 정리, 분석

vanila javascript 프로젝트를 하다가 "Array.prototype.slice.call()" 코드를 보았을 때 당황했지만, 무언가를 한 가지 더 배울 수 있다는 생각에 행복했습니다. 이 글은 해당 코드를 자세히 분석해보았으며

talkwithcode.tistory.com

 

카드 테이블 생성

create table card(
    no varchar2(30),
    valid_month varchar2(10),
    constraint pk_card primary key(no)
);

select * from card;

 

 

카드 설명 추가 , CardVO 클래스 생성

package kr.or.ddit.vo;

import lombok.Data;

@Data
public class CardVO {

	private String no;
	private String validMonth;
	
}

 

card와 quick 테이블의 우선순위?

quick이 있어야 card가 존재( quick(부모) > card(자식) , 1 : N )

부모테이블 기본키 -> 자식테이블의 기본키로

 

관계 설정

1명의 회원 : 여러개의 카드 가질수있다(1 : N)

1개의 카드 : 1명의 회원 ( 1 : 1)

1*N = N

1*1 =1

-> 1 : N의 관계

다대다 관계시에만 관계테이블 생성

고객/상품

한명의 고객 -> 여러상품 구매가능( 1 : n )

하나의 상품 -> 여러고객이 구매 가능(1 : m)

(n : m)

 

부모테이블의 기본키가 자식테이블의 키로서 사용될때

1. 자식테이블에서 기본키로 사용될지 외래키로 사용될지 고려 여부

최소성 원리

카드테이블의 카드번호가 카드를 구분가능(각 카드 식별가능 , 카드번호가 이미 pk의 역할을 수행하고있음 , 복합키로 구성할 필요가 없다)

외래키가 기본키 -> 식별관계

 

외래키는 null을 허용하지만 일반적으로 허용하지 않는다.

 

테이블 제약조건 추가

 

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

 

QuickVO 테이블에 추가

 

quick/create 에서 카드번호 입력 후 등록시 DB로 넘어가는지 확인

 

 

--------------------------------------------------------------------

취미 추가 - > quick.jsp 아래

<div class="form-group">
				<label for="exampleInputEmail1">취미</label>
				<input type="email" class="form-control" name="hobby" id="emailAdres" placeholder="이메일" required />
			</div>

 

 

취미 테이블 생

-- 취미들
create table likes(
    likes_code varchar2(20),
    likes_title varchar2(90),
    likes_cont varchar2(300),
    CONSTRAINT pk_likes PRIMARY key(likes_code)    
);
comment on table likes is '취미정보';
comment on column likes.likes_code is '취미코드';
comment on column likes.likes_title is '취미명';
comment on column likes.likes_cont is '취미상세';
commit;

 

누구의 취미인지 -> quick에 존재하는 사람의 취미 정보

 

열추가 , 제약조건 추가 , LikesVO 클래스 생성

 

package kr.or.ddit.vo;

import lombok.Data;

@Data
public class LikesVO {
	
	private String  likesCode;
	private String  likesTitle;
	private String  likesCont;
	private String  emailAdres;
	
}

 

QuickVO클래스에 추가

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

 

mybatisAlias 추가

		<typeAlias type="kr.or.ddit.vo.LikesVO" alias="likesVO" />

 

likesCode에 기존에는 max+1 이었으나

LKS001의 형태로 처리

처리과

--LKS001 + 1
--LKS  (001+1)
--LKS  2
--LKS  002
--LKS002

취미부분 변경

<div class="form-group" id="divLikes">
				<div>
					<label for="likesTitle1">취미</label>
					<input type="email" class="form-control" name="likesVOList[0].likesTitle" id="likesTitle1" placeholder="취미명" required />
					<label for="likesCont1">취미상세</label>
					<input type="email" class="form-control" name="likesVOList[0].likesCont" id="likesCont1" placeholder="취미상세" required />
				</div>
				
			</div>

 

화면단에서 +버튼을 누를시 아래와 같이 적용되게 (작성란 추가)

<div class="form-group" id="divLikes">
				<div>
					<div style="width: 50%; float: left;">
					<label for="likesTitle1">취미</label>
					<input type="email" class="form-control" name="likesVOList[0].likesTitle" id="likesTitle1" placeholder="취미명" required />
					</div>
					<div style="width: 50%; float: left;">
					<label for="likesCont1">취미상세</label>
					<input type="email" class="form-control" name="likesVOList[0].likesCont" id="likesCont1" placeholder="취미상세" required />
					</div>
				</div>
				
				<div>
					<div style="width: 50%; float: left;">
					<label for="likesTitle2">취미</label>
					<input type="email" class="form-control" name="likesVOList[1].likesTitle" id="likesTitle2" placeholder="취미명" required />
					</div>
					<div style="width: 50%; float: left;">
					<label for="likesCont2">취미상세</label>
					<input type="email" class="form-control" name="likesVOList[1].likesCont" id="likesCont2" placeholder="취미상세" required />
					</div>
				</div>
			</div>

 

quick_SQL.xml 에 쿼리문 추가

-> selectkey 쿼리문 (기존 DB 값이 존재하면 에러뜸!)

<insert id="insertLikes" parameterType="likesVO">
		<selectKey resultType="String" order="BEFORE" keyProperty="likesCode">
			SELECT NVL(SUBSTR(MAX(LIKES_CODE),1,3) || TRIM(TO_CHAR(SUBSTR(MAX(LIKES_CODE),4)+1,'000')),'LKS001')
			  FROM LIKES		
		</selectKey>
	
		insert into likes(LIKES_CODE, LIKES_TITLE, LIKES_CONT, EMAIL_ADRES)
		values (#{likesCode} , #{likesTitle} , #{likesCont} , #{emailAdres})
	</insert>

 

이후 DB까지 데이터 넘어가는지 확인

 

버튼 태그 복사

<div class="col-lg-6">
<div class="btn-group w-100">
<span class="btn btn-success col fileinput-button dz-clickable">
<i class="fas fa-plus"></i>
<span>Add files</span>
</span>
<button type="submit" class="btn btn-primary col start">
<i class="fas fa-upload"></i>
<span>Start upload</span>
</button>
<button type="reset" class="btn btn-warning col cancel">
<i class="fas fa-times-circle"></i>
<span>Cancel upload</span>
</button>
</div>
</div>

 

script문 추가

	// 취미 + / -
	$(".divLikesAdd").on("click" , function () {
		console.log("취미 추가");
	});
	$(".divLikesMinus").on("click" , function () {
		console.log("취미 삭제");
	})

 

개발자 모드에서 console.log 찍히는지 확인

 

$(function(){
	// 취미 + / -
	$(".divLikesAdd").on("click" , function () {
		console.log("취미 추가");
		
		let len = $(".clsLikesTitle").length;
		console.log("len : " + len);
		
		let str="<div>";
			str += "<div style='width: 50%; float: left;'>";
			str += "<label for='likesTitle"+(len+1)+"'>취미명</label>";
			str += "<input type='text' class='form-control clsLikesTitle'";
			str += "name='likesVOList["+len+"].likesTitle' id='likesTitle+"+(len+1)+"'"
			str += "placeholder='취미명' />";
			str += "</div>";
			str += "<div style='width: 50%; float: left;'>";
			str += "<label for='likesCont"+(len+1)+"'>취미상세</label>";
			str += "<input type='text' class='form-control clsLikesCont'";
			str += "name='likesVOList["+len+"].likesCont' id='likesCont"+(len+1)+"'";
			str += "placeholder='취미상세' />";
			str += "</div>";
			str += "</div>";

			$("#divLikes").append(str);
			//divLikes의 자식요소에 추가
	});

 

+버튼 누를시 추가되는지 확인, index값 확인(console.log)

 

	// length를 인덱스에 추가
	$(".divLikesMinus").on("click" , function () {
		console.log("취미 삭제");
		
		let len = $(".clsLikesTitle").length;
		
		if(len<2){
			alert("취미 영역은 최소 한개가 있어야 합니다.");
		} else {

			$("#divLikes").children().last().remove();
			
		}
		// -버튼 누를시 자식요소 삭제
		/*
		<div id = "divLikes">
			<div></div>
			<div></div> -> 삭제된다!
		</div>
		*/
	});

 

삭제버튼 추가

 

http://localhost/quick/create 에서 +/- 버튼 눌러서 작동하는지 확인

 

에러코드

SQL.xml 에서 쿼리문에 세미콜론 포함되어있을시 -> 500에러

### The error may involve kr.or.ddit.mapper.QuickMapper.insertCard-Inline
### The error occurred while setting parameters
### SQL: insert into card(no , valid_month ,email_adres)   values (? , ? , ?)
### Cause: java.sql.SQLIntegrityConstraintViolationException: ORA-00001: unique constraint (JSPEXAM.PK_CARD) violated

; ORA-00001: unique constraint (JSPEXAM.PK_CARD) violated
; nested exception is java.sql.SQLIntegrityConstraintViolationException: ORA-00001: unique constraint (JSPEXAM.PK_CARD) violated
]을(를) 발생시켰습니다.
java.sql.SQLIntegrityConstraintViolationException: ORA-00001: unique constraint (JSPEXAM.PK_CARD) violated

 

해당 에러코드

 

에러코드

SQL.xml 에서 쿼리문에 컬럼명 불일치시 -> 500에러

2월 02, 2024 2:50:42 오후 org.apache.catalina.core.StandardWrapperValve invoke
심각: 경로 []의 컨텍스트 내의 서블릿 [appServlet]을(를) 위한 Servlet.service() 호출이, 근본 원인(root cause)과 함께, 예외 [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'likestitle' in 'class kr.or.ddit.vo.LikesVO']을(를) 발생시켰습니다.
org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'likestitle' in 'class kr.or.ddit.vo.LikesVO'

 

해당 에러코드

 

 

ajax 로 바꿔서

 

<div class="card-footer">
			<button type="button" id="btnAjaxSubmit" class="btn btn-primary">등록</button>
		</div>

 

버튼타입 submit -> button 으로 바꾸기 ,  id추가

 

비동기 방식으로 파일업로드 -> 카드 -> 취미 -> insert까지 확인

 

console.log 확인하

 

카드 사용내역?

 

부모 -> 자식 -> 자식

 

 

AJAX

 

 

 

 

web.xml 파일 열기

 

에러코드 종류 상태 코드를 사용하여 오류 페이지 설정 시작
HTTP 오류 코드 정리
- 400 : Bad Request. 문법 오류(잘못 입력한 url)
- 404* : Not Found. 요청한 문서를 찾지 못함(url확인 및 캐시 삭제가 필요한 상태)
- 405 : Method not allowed. 메소드 허용 안됨(메소드 매핑이 안 될 때 발생)
- 415 : 서버의 요청에 대한 승인 거부. (ContentType, Content Encoding 데이터 확인 필요)
- 500* : 서버 내부 오류. (웹 서버가 요청사항을 수행할 수 없을 때 발생)
- 505 : HTTP Version Not Supported.

 

web.xml 파일 하단에 추가

   <!-- 기본 오류 페이지 설정 시작 -->
<!--    <error-page> -->
<!--       <location>/error/errorDefault</location> -->
<!--    </error-page> -->
   <!-- 기본 오류 페이지 설정 시작 -->

<!-- HTTP 상태코드를 사용하여 오류페이지 설정 시작
	HTTP 오류 코드 정리
	- 400 : Bad Request. 문법 오류(잘못 입력한 url)
	- 404* : Not Found. 요청한 문서를 찾지 못함(url확인 및 캐시 삭제가 필요한 상태)
	- 405 : Method not allowed. 메소드 허용 안됨(메소드 매핑이 안 될 때 발생)
	- 415 : 서버의 요청에 대한 승인 거부. (ContentType, Content Encoding 데이터 확인 필요)
	- 500* : 서버 내부 오류. (웹 서버가 요청사항을 수행할 수 없을 때 발생)
	- 505 : HTTP Version Not Supported.
	-->
	<error-page>
		<error-code>400</error-code>
		<location>/error/error400</location>
	</error-page>
	<error-page>
		<error-code>404</error-code>
		<location>/error/error404</location>
	</error-page>
	<error-page>
		<error-code>500</error-code>
		<location>/error/error500</location>
	</error-page>
	<!-- HTTP 상태코드를 사용하여 오류페이지 설정 끝 -->
    
    <!-- 예외 타입을 사용한 에러 페이지 설정 시작 
   웹 컨테이너(tomcat서버) 설정 파일(web.xml)의 exception-type 태그 요소에 예외 타입을 설정하고
   location 요소에 이동 대상 페이지 및 URI를 지정함
   
   IOException, SQLException, NullPointerException, ArrayIndexOutOfBoundsException,
   ArtimeticException(0으로 나눌경우)
   -->
   <error-page>
      <exception-type>java.lang.Exception</exception-type>
      <location>/error/errorException</location>
   </error-page>
   <!-- 예외 타입을 사용하여 오류 페이지 설정 시작 -->

 

ErrorController 클래스 생성

package kr.or.ddit.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import lombok.extern.slf4j.Slf4j;
// 자바빈 선언
@Slf4j
@Controller
@RequestMapping("/error")
public class ErrorController {
	// error/error400
	@GetMapping("/error400")
	public String error400() {
		//forwarding : jsp
		return "error/error400";
	}
	@GetMapping("/error404")
	public String error404() {
		//forwarding : jsp
		return "error/error404";
	}
	@GetMapping("/error500")
	public String error500() {
		//forwarding : jsp
		return "error/error500";
	}

}

 

@Controller 어노테이션 선언

 

views -> error 폴더 생성 -> error400.jsp , error404.jsp , error500.jsp 생성

400 : url 오류

404 : page not pond

500 : 개발자 오류?