투케이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 이미지 호출]

/* =========================== */

반응형
Comments