73일: Spring 복습, 카테고리, ckeditor 이미지 업로드

Jiwontwopunch·2022년 2월 28일
0

국비기록

목록 보기
73/121
post-thumbnail

2022.02.28.Mon.

✍ 복습

Spring 복습

@postConstruct : 의존성 주입이 이루어진 후 초기화를 수행하는 메서드이다. @PostConstruct가 붙은 메서드는 클래스가 service(로직을 탈 때? 로 생각 됨)를 수행하기 전에 발생한다. 이 메서드는 다른 리소스에서 호출되지 않는다해도 수행된다.

@PreDestroy : Spring이 애플리케이션 컨텍스트에서 bean을 제거하기 직전에 단 한 번만 실행된다.
@Repository vs @Mapper :
1. @Repository
① 구조 >> @Controller - @Service - @Repository - Mapper.xml
<bean>에 SqlSessionFactory와 SqlSessionTemplate을 추가해준다
③ @Autowired를 통해 DAO클래스에 의존성을 주입(DI)한다
④ 스프링의 DI 어노테이션 @Autowired, 자바 표준 DI 어노테이션이 @Inject
⑤ 위의 예시코드처럼 DaoImpl에서 Mapper의 id와 insert 메소드안의 example.insertData를 일치해주는 방식이다.
⑥ 사용하는 DML이나 selectOne, selectList처럼 DB에서 받아오는 데이터의 종류에 따라 메소드의 이름을 알맞게 적어줘야 하는 방식이다.
2. @Mapper
① 구조 >> @Controller - @Service - @Mapper - Mapper.xml
② MyBatis 3.0부터 지원하는 기능이다.
③ @Mapper에서 interface로 작성 후, 따로 implements(구현)을 하지 않는다.
④ @Mapper에 작성한 메소드이름과 Mapper.xml에 작성한 Sql id는 일치해야 한다.
⑤ Mapper.xml의 namespace는 @Mapper의 경로를 작성해야 한다.
⑥ @Resource에 에러가 뜨면 pom.xml에 <dependency>를 추가해주면 된다.
출처 : https://limreus.tistory.com/3
DispatcherServletselect로만 구성되어 있을 때 @Transactional 어노테이션 지정 가능

카테고리 DB 작업 (self join)

대분류, 중분류, 소분류를 self join해서 한꺼번에 입력하기

create table category (
        code varchar2(3 char),
        name varchar2(10 char),
        parent varchar2(3 char),
        constraint category_pk_code primary key(code)
    );
    
    insert into category values('1', '가전', null);
    insert into category values('11', 'TV', '1');
    insert into category values('12', '홈시어터', '1');
    insert into category values('111', 'OLED', '11');
    insert into category values('112', 'QLED', '11');
    insert into category values('121', '스피커', '12');
    insert into category values('122', '사운드바', '12');
    insert into category values('2', 'PC', null);
    insert into category values('21', 'CPU', '2');
    insert into category values('22', '메모리', '2');
    insert into category values('211', '인텔', '21');
    insert into category values('212', 'AMD', '21');
    insert into category values('221', 'DDR4', '22');
    insert into category values('222', 'DDR5', '22');

대분류 먼저 읽어오기

대분류를 선택하면 중분류를 읽어낸다.

대분류가 '1' (가전) -> TV, 홈시어터가 읽어와야 한다.

중분류를 선택하면 소분류를 읽어낸다.

대분류, 중분류, 소분류 읽어내기 코드

카테고리 CategoryDao


where parent 중복, 삭제

카테고리 CategoryService

@Transactional(readOnly=true) : 성능 향상

카테고리 CategoryRestController

<?> 스프링부트가 타입을 자동으로 맞춰 준다.

@RequestParam(required=false)은 생략가능하지만 지금 같이 선택입력으로 지정하려면 사용해야한다.

카테고리 add.html

카테고리 add.html 정적으로 만들기

ckeditor 이미지 업로드

이미지 파일 경로 없어서 에러남..
ck는 이미지를 경로로 출력
이미지를 선택하면 그 순간 바로 업로드 → d:/upload/ckupload/사진이름 저장 ← 사진이름의 경로 /images/사진이름
ProductService에 application.properties의 값 넣기

package com.example.demo.controller.rest;

import java.io.*;
import java.nio.file.*;

import org.springframework.beans.factory.annotation.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.*;

import com.example.demo.dto.*;
import com.example.demo.service.*;

import lombok.*;

@RequiredArgsConstructor
@RestController
public class PrdouctRestController {
	private final ProductService service;
	@Value("${ck.image.folder}")
	private String CKImageFolder;
	
	// ck를 이용해 서버에 사진을 업로드하려면 사진의 파라미터 이름은 upload다
	// ck를 이용해 서버에 사진을 업로드하면 특정 형식으로 응답해야 한다 -> 값 3개를 모아서 클래스로 만들었다 
	@PostMapping(value="/product/image", produces = MediaType.APPLICATION_JSON_VALUE)
	public ResponseEntity<CKResponse> ckImageUpload(MultipartFile upload) {
		CKResponse ckResponse = service.ckImageUpload(upload);
		return ResponseEntity.ok(ckResponse);
	}
	
	// ck로 사진을 업로드하면 응답에 사진 경로를 "http://localhost:8081/images/사진이름"로 지정할 것이다
	// http://localhost:8081/images/dcafbe48-cafb-4809-b121-b31b190bf9cf-26237E4E5664EE3808.jpg
	// 이 사진 경로를 요청하면 사진을 보내주는 컨트롤러를 추가하자
	@GetMapping("/images/{imagename}")
	public ResponseEntity<byte[]> showImage(@PathVariable String imagename) {
		// 자바 파일 객체를 만들면 파일이 있으면 열고, 파일이 없으면 0바이트 파일을 만든다
		// file 생성이 실패하는 일은 없다 -> 0바이트 파일인지 확인하려면 exists() 메소드를 사용해야 한다
		File file = new File(CKImageFolder, imagename);
		if(file.exists()==false)
			return null;
		
		// 파일의 종류를 클라이언트에 가르쳐 주자
		// 파일은 파일의 내용과 헤더로 구성. 헤더에는 파일에 메타정보가 들어있다(크기, 만든 날짜....)
		// 자바를 이용해서 "Content-Disposition" 헤더를 추가 -> 이 값에 따라 브라우저의 동작이 바뀐다
		//		inline을 지정하면 미리보기하고, attachment를 지정하면 다운로드한다
		HttpHeaders headers = new HttpHeaders();
		
		// 헤더에 사진의 종류에 따른 MediaType을 지정
		// 1. 이미지의 확장자를 잘라내서 대문자로 변환
		String extension = imagename.substring(imagename.lastIndexOf(".")).toUpperCase();
		MediaType type = null;
		if(extension.equals("JPG"))
			type = MediaType.IMAGE_JPEG;
		else if(extension.equals("PNG"))
			type = MediaType.IMAGE_PNG;
		else if(extension.equals("GIF"))
			type = MediaType.IMAGE_GIF;
		
		// 2. 헤더에 파일의 종류를 저장
		headers.setContentType(type);
		
		// 3. 헤더에 미리보기하라고 지정
		headers.add("Content-Disposition", "inline;filename="  + imagename);
		
		// 2, 3번. 파일을 다운로드하도록 설정하려면
		// 데이터의 종류는 몰라요. 바이트 덩어리에요 라고 지정(OCTET은 통신쪽에서 byte 대신 사용)
		// headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
		// headers.add("Content-Disposition", "attachment;filename=" + originalFileName +";");
		
		
		// 4. 헤더를 추가해서 응답객체를 내보내자. 그런데 File을 byte[]로 바꿔서 내보내야 한다
		//	  데이터는 텍스트 데이터와 이진 데이터로 구별할 수 있다. 문자열은 아닌 데이터는 바이트 배열로 내보내면 된다
		//	  39라인에서 오픈한 파일을 byte[]로 변환해야 네트워크로 출력이 가능하다
		//    파일을 byte[]로 변환하는 방법을 찾아보면 여러 가지 있는데 그중 하나를 선택
		try {
			return ResponseEntity.ok().headers(headers).body(Files.readAllBytes(file.toPath()));
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	

}

0개의 댓글