Notice
Recent Posts
Recent Comments
Link
투케이2K
11. (spring/스프링) BLOB 이미지 (Image) 저장 및 이미지 조회 실시 - api , ajax 통신 , oracle db , mybatis 본문
Spring
11. (spring/스프링) BLOB 이미지 (Image) 저장 및 이미지 조회 실시 - api , ajax 통신 , oracle db , mybatis
투케이2K 2021. 7. 14. 18:13/* =========================== */
[ 개발 환경 설정 ]
개발 툴 : inteli j
개발 언어 : spring
/* =========================== */
/* =========================== */
[폴더 및 파일 추가]
/* =========================== */
/* =========================== */
[소스코드 : 오라클 BLOB 테이블 생성]
/*[테이블 생성]*/
CREATE TABLE TEST_BLOB
(
T_IDX VARCHAR2(5 BYTE) NOT NULL,
T_BLOB BLOB NOT NULL
);
/*[테이블 삭제]*/
DROP TABLE TEST_BLOB CASCADE CONSTRAINTS;
[소스코드 : application.yml]
spring:
devtools:
livereload:
enabled: true
datasource:
driver-class-name: oracle.jdbc.OracleDriver
url: jdbc:oracle:thin:@115.68.176.215:1521:username
username: userschema
password: pw1234
server:
port: 7000
mybatis:
mapper-locations: classpath:mappers/*.xml
type-aliases-package: com.project.solutionpackage.model
[소스코드 : model >> Insert_DB_Image_Model]
package com.project.solutionpackage.model;
import lombok.Data;
@Data
public class Insert_DB_Image_Model {
/**
* [클래스 설명]
* 1. insert 포맷 형태 정의 클래스
* 2. controller 에서 사용한다
* */
private String idx;
private byte[] img;
public Insert_DB_Image_Model(String idx, byte[] img) {
this.idx = idx;
this.img = img;
}
}
[소스코드 : mappers >> DBMapper.xml]
<?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 >> interface 매핑 : id 값 중요 (interface 메소드) -->
<mapper namespace="com.project.solutionpackage.mapper.DBMapper">
<!-- insert 데이터 삽입 실시 : 이미지 저장 -->
<insert id="saveImage">
<![CDATA[
insert into TEST_BLOB (T_IDX, T_BLOB)
values (#{idx}, #{img})
]]>
</insert>
<!-- select 조건 절 조회 : 이미지 조회 -->
<select id="selectImage" resultType="map">
<![CDATA[
select t_blob
from test_blob
where t_idx = #{idx}
]]>
</select>
</mapper>
[소스코드 : mapper >> DBMapper]
package com.project.solutionpackage.mapper;
import com.project.solutionpackage.model.Insert_DB_Image_Model;
import org.apache.ibatis.annotations.Mapper;
import java.sql.Blob;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Mapper
public interface DBMapper {
/**
* [클래스 설명]
* 1. DBMapper.xml 쿼리 조회 결과 >> DB 데이터를 담을 그릇
* 2. service 에서 참조해서 사용한다
* */
// [DBMapper.xml 쿼리에서 선언한 변수 개수 및 타입에 맞게 파라미터 선언]
int saveImage(Insert_DB_Image_Model userImage); // 리턴값으로 int 사용 [상태값 확인 성공, 실패 여부]
// [DBMapper.xml 쿼리에서 선언한 변수 개수 및 타입에 맞게 파라미터 선언]
Map<String, Object> selectImage(int idx); // 리턴값으로 map 사용 [출력]
}
[소스코드 : service >> DBService]
package com.project.solutionpackage.service;
import com.project.solutionpackage.mapper.DBMapper;
import com.project.solutionpackage.model.Insert_DB_Image_Model;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.Blob;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class DBService {
/**
* [클래스 설명]
* 1. DBMapper 인터페이스 호출 및 controller 에 반환 할 리턴 값 정의
* 2. controller 에서 사용한다
* */
// [DBMapper 인터페이스 설정 : db 데이터 참조 [DBMapper.xml]]
@Autowired
private DBMapper dbMapper;
// [DBMapper 인터페이스 지정 >> DBApiController 리턴 값 지정]
public int saveImage(Insert_DB_Image_Model userImage) {
return dbMapper.saveImage(userImage); //컨트롤러에 리턴 실시
}
// [DBMapper 인터페이스 지정 >> DBApiController 리턴 값 지정]
public Map<String, Object> selectImage(int idx) {
return dbMapper.selectImage(idx); //컨트롤러에 리턴 실시
}
}
[소스코드 : controller >> DBApiController]
package com.project.solutionpackage.controller;
import com.project.solutionpackage.model.*;
import com.project.solutionpackage.service.DBService;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Base64Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.configurationprocessor.json.JSONException;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.util.Base64Utils;
import org.springframework.web.bind.annotation.*;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.sql.Blob;
import java.util.*;
// [rest 방식 컨트롤러 / Controller = view 연결]
@RestController
public class DBApiController {
/**
* [클래스 설명]
* 1. api 호출 경로 및 리턴 데이터 반환 실시
* 2. 실제로 api 호출 (req) 및 반환 (res) 이루어지는 클래스
* */
// [service 설정 : 로직 연결 위함]
// [로직 : 사용자 API 호출 >> 컨트롤러에서 서비스 호출 >> 서비스에서 DB Mapper 호출]
@Autowired
private DBService dbService;
// [post body json : Map 방식]
// [경로 지정 : http://localhost:7000/saveImage]
// [body json 데이터 : {"idx":"1", "image":"data:image/png;base64,iVBORw ...."}]
// [input : 서비스에서 설정한 파라미터 개수와 같아야합니다]
// [output : 모델에서 설정한 return 타입으로 결과를 반환합니다]
@PostMapping("/saveImage")
public String saveImage(@RequestBody Map<String, String> param) {
System.out.println("\n");
System.out.println("=======================================");
System.out.println("[DBApiController] : [saveImage]");
System.out.println("[request keySet] : " + String.valueOf(param.keySet()));
System.out.println("[request idx] : " + String.valueOf(param.get("idx")));
System.out.println("[request idx] : " + String.valueOf(param.get("image")));
System.out.println("=======================================");
System.out.println("\n");
// DATA URL 을 바이트로 변환 실시
byte imageArray [] = null;
final String BASE_64_PREFIX = "data:image/png;base64,";
try {
String base64Url = String.valueOf(param.get("image"));
if (base64Url.startsWith(BASE_64_PREFIX)){
imageArray = Base64.getDecoder().decode(base64Url.substring(BASE_64_PREFIX.length()));
System.out.println("\n");
System.out.println("=======================================");
System.out.println("[DBApiController] : [saveImage]");
System.out.println("[imageArray] : " + new String(imageArray));
System.out.println("=======================================");
System.out.println("\n");
}
}
catch (Exception e){
e.printStackTrace();
}
// 모델 객체에 idx 및 byte 지정 실시 [오라클 blob 컬럼은 byte 로 되어있다]
Insert_DB_Image_Model userImage = new Insert_DB_Image_Model(param.get("idx"), imageArray);
if (dbService.saveImage(userImage) > 0) {
System.out.println("\n");
System.out.println("=======================================");
System.out.println("[DBApiController] : [saveImage]");
System.out.println("[response] : " + new Return_DB_Json_Model("T", "Success"));
System.out.println("=======================================");
System.out.println("\n");
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("state", "T");
jsonObject.put("message", "Success");
} catch (JSONException e) {
e.printStackTrace();
}
return jsonObject.toString(); //정상 삽입 완료 시 상태값 반환
} else {
System.out.println("\n");
System.out.println("=======================================");
System.out.println("[DBApiController] : [saveImage]");
System.out.println("[response] : " + new Return_DB_Json_Model("F", "Failed"));
System.out.println("=======================================");
System.out.println("\n");
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("state", "F");
jsonObject.put("message", "Fail");
} catch (JSONException e) {
e.printStackTrace();
}
return jsonObject.toString(); //정상 삽입 완료 시 상태값 반환
}
}
// [get : Map 방식]
// [경로 지정 : http://localhost:7000/selectImage?idx=1]
// [input : 서비스에서 설정한 파라미터 개수와 같아야합니다]
// [output : data url return 타입으로 결과를 반환합니다]
@GetMapping("/selectImage")
public String selectImage(@RequestParam Map<String, String> param) {
System.out.println("\n");
System.out.println("=======================================");
System.out.println("[DBApiController] : [selectImage]");
System.out.println("[request keySet] : " + String.valueOf(param.keySet()));
System.out.println("[request idx] : " + String.valueOf(param.get("idx")));
System.out.println("=======================================");
System.out.println("\n");
//서비스 호출 및 리턴 받은 데이터 확인 실시
int data = Integer.valueOf(param.get("idx"));
Map<String, Object> result = dbService.selectImage(data);
System.out.println("\n");
System.out.println("=======================================");
System.out.println("[DBApiController] : [selectImage]");
System.out.println("[Map keySet] : " + String.valueOf(result.keySet()));
System.out.println("[Map msg] : " + String.valueOf(result.get("T_BLOB")));
System.out.println("=======================================");
System.out.println("\n");
//blob 데이터를 byte로 변환 실시 [필요시 base64 인코딩 >> data url 생성 가능]
byte arr[] = blobToBytes((Blob) result.get("T_BLOB"));
System.out.println("\n");
System.out.println("=======================================");
System.out.println("[DBApiController] : [selectImage]");
System.out.println("[blobToBytes] : " + Arrays.toString(arr));
System.out.println("=======================================");
System.out.println("\n");
//data url 리턴 실시
if(arr.length > 0 && arr != null){ //데이터가 들어 있는 경우
//바이트를 base64인코딩 실시
String base64Encode = byteToBase64(arr);
base64Encode = "data:image/png;base64," + base64Encode;
System.out.println("\n");
System.out.println("=======================================");
System.out.println("[DBApiController] : [selectImage]");
System.out.println("[base64Encode] : " + base64Encode);
System.out.println("=======================================");
System.out.println("\n");
return base64Encode;
}
else {
return "";
}
}
// [blob 데이터를 바이트로 변환해주는 메소드]
private static byte[] blobToBytes(Blob blob) {
BufferedInputStream is = null;
byte[] bytes = null;
try {
is = new BufferedInputStream(blob.getBinaryStream());
bytes = new byte[(int) blob.length()];
int len = bytes.length;
int offset = 0;
int read = 0;
while (offset < len
&& (read = is.read(bytes, offset, len - offset)) >= 0) {
offset += read;
}
} catch (Exception e) {
e.printStackTrace();
}
return bytes;
}
// [byte를 base64로 인코딩 해주는 메소드]
private static String byteToBase64(byte[] arr) {
String result = "";
try {
result = Base64Utils.encodeToString(arr);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
[소스코드 : blob 이미지 저장 방식]
type : post body json
url : http://localhost:7000/saveImage
data :
{
"idx": "1",
"image" : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAMAAADVRocKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAzUExURQAAABAgMBggOBUgNRgcOBYdNhgdOBceNxYeOBceNxYeOBcfNxcdOBceNxceOBceNxceOLFQWucAAAAQdFJOUwAQIDBAUGBwgI+fr7/P3+8jGoKKAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAByklEQVRoQ+3Y0XKDIBAF0BCxARHw/7+2E71OTcKyumw7feA8JndujEKA3Lqu67q/ZaybY84xeItXVBmflx/+jpe1vNY/ebyjwwTUHkSDNxUMCaUv8oC3m5mIyjdZ6TuU7s8mItHIoa7AIdLEvI+fg6wxWitfYFkmhFoUR9AuI9RgRBXhCzG56h3SuEfkGN3MiMkRk2zX/hCqz1jjAyqzYIWYHHOLEmJyM5oI7T9HHk2E9mHKTLQRsQbVp6yxJEzoKgoItTDoKtFZNX97walMBa2NhSF+LlTWs9VQHElZYYjuShuXqLt7fKB2l53ixm5ljvMhz9qb39Xo57TkFMOoffXdv2Dsw/vwPKOlOUzOqR7T7qOLn3M5Tg+VsWpdZdlPrYdBU2vfhIbdqf04WpYF2QOxzIblKF3/GsPJq9/Fax/xee7mXfn5tuyjLTm/AAkuf3Py74X3teWCU5/wJb3+pxN36d7Svyz8k2YOfRz+Jl2YXiX8gYQ5k3H4MxuCYqihISeGGhpyYqihISeGGhpyYqihISeGGhpyYqihISeGGhpyYqihISeGGhpyYqihISeGGhpyYqihISeGGhpyYqihISeGmq7ruk7R7fYNxnmhp0mQS0oAAAAASUVORK5CYII"
}
[소스코드 : blob 이미지 조회 요청 Ajax]
/* 이벤트 함수 정의 */
function requestGet(){
var urlData = "http://localhost:7000/selectImage";
var contentData = "idx=1";
console.log("");
console.log("[requestGet] : [start]");
console.log("[request url] : " + urlData);
console.log("[request data] : " + contentData);
console.log("[request format] : " + urlData+"?"+contentData);
console.log("[request method] : " + "GET");
console.log("");
$.ajax({
/* 요청 시작 부분 */
url: urlData, //주소
data: { //전송 데이터
"idx" : 1
},
type: "GET", //전송 타입
async: true, //비동기 여부
dataType: "TEXT", //응답받을 데이터 타입 (XML,JSON,TEXT,HTML)
/* 응답 확인 부분 */
success: function(response) {
console.log("");
console.log("[requestGet] : [result]");
console.log("[response] : " + response);
console.log("");
// 정상적으로 리턴된 data url 있는 경우 src 에 표시 실시
if(response.length > 0 && response != null){
document.getElementById("preview-image").src = response;
}
},
/* 에러 확인 부분 */
error: function(xhr) {
console.log("");
console.log("[requestGet] : [result]");
console.log("[error] : " + xhr);
console.log("");
},
/* 완료 확인 부분 */
complete:function(data,textStatus) {
console.log("");
console.log("[requestGet] : [result]");
console.log("[complete] : " + textStatus);
console.log("");
}
});
};
/* =========================== */
/* =========================== */
[결과 출력]
[BLOB 이미지 저장]
[BLOB 이미지 호출]
/* =========================== */
반응형
'Spring' 카테고리의 다른 글
Comments