77일차 2023-06-27

2023. 6. 27. 18:57RestController

Spring Boot 

Rest Controller

RestTemplate

 

 

구글 api사용법

https://cloud.google.com/vision/docs/object-localizer?hl=ko#detect_objects_in_a_local_image


1.  Google Cloud Platform(GCP) 프로젝트 및 인증 설정

    google cloud console로 검색후  콘솔로 이동
	https://console.cloud.google.com
	
	-GCP프로젝트 생성
	새 프로잭트(기존 프로젝트 있는 경우 기존 프로젝트 클릭후 새 프로젝트) -> 프로젝트명 입력 후 ->만들기 클릭
	
	프로젝트 선택후 대시보드 ->시작하기 섹션의 API탐색 및 사용설정 클릭->상단의 API 및 서비스 사용설정 클릭->Cloud Vision API 검색->사용 클릭
	
	
	-서비스 계정 생성하기
	
	※Google Cloud CLI를 설치후 gcloud auth print-access-token명령어로 ACCESS TOKEN을 발급 받는다
	 이 명령어를 사용하여 생성된 액세스 토큰은 기본적으로 1시간 동안 유효
	 토큰의 유효 기간을 설정하는 옵션은 제공되지 않는다
	※대부분의 Google Cloud APIs는 API 키를 지원하지 않는다. 
	 이 인증 방법을 사용하기 전에 사용하려는 API가 API 키를 지원하는지 확인해야한다.
	 API 키는 청구 및 할당 목적으로 요청을 Google Cloud 프로젝트와 연결한다. 
	 API 키가 호출자를 식별하지 않기 때문에 종종 공개 데이터 또는 리소스에 액세스하는 데 사용된다.
	 많은 Google Cloud API가 인증용으로 API 키를 수락하지 않는다. 
	 API 키 지원 여부를 확인하기 위해 사용하려는 서비스 또는 API에 대해 인증 문서를 확인해야 한다.
	
	좌측의 사용자 인증 정보 클릭->서비스 계정관리 클릭->상단의 서비스 계정 만들기 클릭
	서비스 계정명입력후 ->만들고 계속하기 클릭->역할 선택에서 소유자 선택->계속 클릭후 완료 버튼 클릭
	목록의 우측 3 Dot 메뉴에서 키관리 클릭->키 추가 클릭->새 키 만들기->JSON선택후 다운로드(클라우드 리소스 액세스를 허용)
	
	
	-Google Cloud CLI를 설치 초기화
	  
	 https://cloud.google.com/sdk/docs/install?hl=ko
	 
		Google Cloud CLI설치
	
			 PowerShell 터미널을 관리자 권한으로 열고 다음 PowerShell 명령어를 실행
			 
			 (New-Object Net.WebClient).DownloadFile("https://dl.google.com/dl/cloudsdk/channels/rapid/GoogleCloudSDKInstaller.exe", "$env:Temp\GoogleCloudSDKInstaller.exe")

			 & $env:Temp\GoogleCloudSDKInstaller.exe
			 
			 안내에 따라 설치한다(수 분이 걸린다)
		 
		Google Cloud CLI 설치후 초기화
			
			Google Cloud SDK Shell 실행후 아래 입력
			C:\Users\kosmo\AppData\Local\Google\Cloud SDK>gcloud init
			
		
		    이후 이 Application에 대한 인증절차를 마친다
			혹은 아래 명령어로 추후에 인증할 수도 있다
			C:\Users\kosmo\AppData\Local\Google\Cloud SDK>gcloud auth application-default login
			
2. 스프링 프로젝트에 적용하기
	
	선행 작업: 환경변수 등록 혹은 이클립스 프로젝트 선택후 마우스 우클릭->Run as ->Run Configuration (Google Cloud APIs필요시 사용) 
	Name : GOOGLE_APPLICATION_CREDENTIALS
	Value : 다운받은 json파일의 위치

	2-1. REST로 적용시
	
		-객체 감지]
		
		HTTP 메서드 및 URL:
		POST https://vision.googleapis.com/v1/images:annotate
		JSON 요청 바디:
		{
		  "requests": [
			{
			  "image": {
				"content": "BASE64_ENCODED_IMAGE"
			  },
			  "features": [
				{
				  "maxResults": RESULTS_INT,
				  "type": "OBJECT_LOCALIZATION"
				},
			  ]
			}
		  ]
		}
		
		혹은 
		{
		  "requests": [
			{
			  "image": {
				"source": {
				  "imageUri": "CLOUD_STORAGE_IMAGE_URI"
				}
			  },
			  "features": [
				{
				  "maxResults": RESULTS_INT,
				  "type": "OBJECT_LOCALIZATION"
				},
			  ]
			}
		  ]
		}
		요청 헤더:
		"Authorization: Bearer $(gcloud auth print-access-token)" 
		"x-goog-user-project: PROJECT_ID" 
		"Content-Type: application/json; charset=utf-8" 
		
		-OCR]
		
		HTTP 메서드 및 URL:
		POST https://vision.googleapis.com/v1/images:annotate
		JSON 요청 바디:
		{
		  "requests": [
			{
			  "image": {
				"content": "BASE64_ENCODED_IMAGE"
			  },
			  "features": [
				{
				  "type": "TEXT_DETECTION"
				}
			  ]
			}
		  ]
		}
		
		혹은
		{
		  "requests": [
			{
			  "image": {
				"source": {
				  "imageUri": "CLOUD_STORAGE_IMAGE_URI"
				}
			   },
			   "features": [
				 {
				   "type": "TEXT_DETECTION"
				 }
			   ]
			}
		  ]
		}
		
		
		요청 헤더:
		
		"Authorization: Bearer $(gcloud auth print-access-token)" 
		"x-goog-user-project: PROJECT_ID" 
		"Content-Type: application/json; charset=utf-8" 

	2-2.자바코드로 적용시

	-pom.xml에 라이브러 추가
		<dependency>
			<groupId>com.google.cloud</groupId>
			<artifactId>google-cloud-vision</artifactId>
			<version>3.1.0</version>
		</dependency>
	
	 
	 
	-구글 사이트에 있는 언어별 소스 사용

		import com.google.cloud.vision.v1.AnnotateImageRequest;
		import com.google.cloud.vision.v1.AnnotateImageResponse;
		import com.google.cloud.vision.v1.BatchAnnotateImagesResponse;
		import com.google.cloud.vision.v1.EntityAnnotation;
		import com.google.cloud.vision.v1.Feature;
		import com.google.cloud.vision.v1.Feature.Type;
		import com.google.cloud.vision.v1.Image;
		import com.google.cloud.vision.v1.ImageAnnotatorClient;
		import com.google.cloud.vision.v1.LocalizedObjectAnnotation;
		import com.google.protobuf.ByteString;
		
		
		
		
		//이미지 객체 검출
		public static void detectLocalizedObjects(String filePath,HttpServletRequest req) throws IOException {
			
			String path=req.getSession().getServletContext().getRealPath("/upload");
			
			List<AnnotateImageRequest> requests = new ArrayList<>();

			  ByteString imgBytes = ByteString.readFrom(new FileInputStream(path+File.separator+"pizza.jpg"));

			  Image img = Image.newBuilder().setContent(imgBytes).build();
			  AnnotateImageRequest request =
				  AnnotateImageRequest.newBuilder()
					  .addFeatures(Feature.newBuilder().setType(Type.OBJECT_LOCALIZATION))
					  .setImage(img)
					  .build();
			  requests.add(request);

			  // Initialize client that will be used to send requests. This client only needs to be created
			  // once, and can be reused for multiple requests. After completing all of your requests, call
			  // the "close" method on the client to safely clean up any remaining background resources.
			  try (ImageAnnotatorClient client = ImageAnnotatorClient.create()) {
				// Perform the request
				BatchAnnotateImagesResponse response = client.batchAnnotateImages(requests);
				List<AnnotateImageResponse> responses = response.getResponsesList();

				// Display the results
				for (AnnotateImageResponse res : responses) {
				  for (LocalizedObjectAnnotation entity : res.getLocalizedObjectAnnotationsList()) {
					System.out.format("Object name: %s%n", entity.getName());
					System.out.format("Confidence: %s%n", entity.getScore());
					System.out.format("Normalized Vertices:%n");
					entity
						.getBoundingPoly()
						.getNormalizedVerticesList()
						.forEach(vertex -> System.out.format("- (%s, %s)%n", vertex.getX(), vertex.getY()));
				  }
				}
			  }
			}
			
			//OCR
			
			public static void detectText(HttpServletRequest req) throws IOException {
			// TODO(developer): Replace these variables before running the sample.
			String path=req.getSession().getServletContext().getRealPath("/upload");
			String filePath =path+File.separator+ "sign_small.jpg";
			detectText(filePath);
		  }
		
		// Detects text in the specified image.
		  public static void detectText(String filePath) throws IOException {
			List<AnnotateImageRequest> requests = new ArrayList<>();

			ByteString imgBytes = ByteString.readFrom(new FileInputStream(filePath));

			Image img = Image.newBuilder().setContent(imgBytes).build();
			Feature feat = Feature.newBuilder().setType(Feature.Type.TEXT_DETECTION).build();
			AnnotateImageRequest request =
				AnnotateImageRequest.newBuilder().addFeatures(feat).setImage(img).build();
			requests.add(request);

			// Initialize client that will be used to send requests. This client only needs to be created
			// once, and can be reused for multiple requests. After completing all of your requests, call
			// the "close" method on the client to safely clean up any remaining background resources.
			try (ImageAnnotatorClient client = ImageAnnotatorClient.create()) {
			  BatchAnnotateImagesResponse response = client.batchAnnotateImages(requests);
			  List<AnnotateImageResponse> responses = response.getResponsesList();

			  for (AnnotateImageResponse res : responses) {
				if (res.hasError()) {
				  System.out.format("Error: %s%n", res.getError().getMessage());
				  return;
				}

				// For full list of available annotations, see http://g.co/cloud/vision/docs
				for (EntityAnnotation annotation : res.getTextAnnotationsList()) {
				  System.out.format("Text: %s%n", annotation.getDescription());
				  System.out.format("Position : %s%n", annotation.getBoundingPoly());
				}
			  }
			}
		  }

몇몇 링크들:

https://console.cloud.google.com/

이미 만들었지만 My VisionAPI란 이름으로 프로젝트 생성하면된다 첨에 생성시에는 key가 없음
JSON으로 생성

 

https://cloud.google.com/sdk/docs/install?hl=ko 

powersel

 

1번 선택(내가 만든 프로젝트:my vision api)
대기
이 코드로 토큰을 생성함 (1시간인가? 유효함)
이런식으로 생성됨

 

https://cloud.google.com/vision/docs/object-localizer?hl=ko

이 페이지를 보면서 코드 작성

 

 

 

 

 

 

 

환경변수 설정

 

pom.xml

 

 

com.kosmo.restapi.config패키지에 RestTemplateConfig.java

package com.kosmo.restapi.config;

import java.util.concurrent.TimeUnit;

import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

//RestTemplate 커넥션 풀 사용하기 위한 빈 등록
@Configuration
public class RestTemplateConfig {
	/*
	 * 반환 타입:IOC컨테이너(스프링 컨테이너)에 등록할 빈(싱글 톤)
	 * 메소드명:생성된 빈의 이름(아이디값)
	 * 예:RestTemplate restTemplate = new RestTemplate(ClientHttpRequestFactory)
	 */
	
	/*
	 사전 작업:POM.XML에 아래 등록(RestTemplate사용시 커넥션 풀을 사용하기 위함)
	 <dependency>
	    <groupId>org.apache.httpcomponents</groupId>
	    <artifactId>httpclient</artifactId>
	    <version>4.5.13</version>
	 </dependency>		  
	 */
	@Bean
	public RestTemplate restTemplate() {
		//1.커넥션 풀 사용을 위한 HttpClient객체 생성
		CloseableHttpClient httpClient = HttpClientBuilder.create()
				.setMaxConnTotal(50)//연결을 유지할 최대 Http커넥션 수
				.setMaxConnPerRoute(50)//Route당(요청 URI주소당) 최대 Http커넥션 수
				.setConnectionTimeToLive(5,TimeUnit.SECONDS)//커넥션 연결 유지시간
				.build();
		//2.타임아웃 설정을 위한 객체 생성
		HttpComponentsClientHttpRequestFactory factory=new HttpComponentsClientHttpRequestFactory();
		factory.setConnectionRequestTimeout(3000);//요청 타임아웃 시간
		factory.setHttpClient(httpClient);
		
		return new RestTemplate(factory);
	}
}

 

 

 

com.kosmo.restapi.model패키지에 ObjectDetectDTO.java

[]:대괄호를 클래스로, 그 속에 있는 것을 요소로 보고 생성(원래는 아래 preview)으로 POJO로 변환시키는 것이지만 더 간단히 만들기 위해서)

package com.kosmo.restapi.model;

import java.util.List;

import lombok.Getter;
import lombok.Setter;

//구글의 객체감지 요청 본문(JSON형식)을 자바빈으로 변환

@Getter
@Setter
public class ObjectDetectDTO {
	
	private List<Request> requests;
	
	@Getter
	@Setter
	public static class Request{
		private Image image;
		private List<Feature> features;
		private ImageContext imageContext;
	}
	@Getter
	@Setter
	public static class Feature{
		private int maxResults;
		private String type;
	}
	@Getter
	@Setter
	public static class Image{
		private Source source;
	}
	@Getter
	@Setter
	public static class  Source {
		private String imageUri;
	}
	//응답을 한글로 받기(디폴트는 영어)
	@Getter
	@Setter
	public static class ImageContext{
		private List<String> languageHints;
	}
}

 

 

 

FileUtils.java는 전, springapp프로젝트에서 com.kosmo.springapp.basic.fileupdown패키지에서 가져온다(복붙)

 

com.kosmo.restapi.controller패키지에 RestApiController.java

package com.kosmo.restapi.controller;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.servlet.http.HttpServletRequest;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kosmo.restapi.model.FileUtils;
import com.kosmo.restapi.model.ObjectDetectDTO;
import com.kosmo.restapi.model.UsersDto;
import com.kosmo.restapi.model.UsersMapper;

import io.swagger.annotations.ApiOperation;


@RestControllerAdvice
@RestController
public class RestApiController {

	@Autowired
	private UsersMapper mapper;
	
	//1.데이타를 key=value쌍으로 받아서 입력
	//-FORM태그를 이용해서 요청하거나
	//-jQuery ajax로 요청시에는 data:"username=KIM&password=1234&name=김길동",
	// 혹은 data:{username:"KIM",password:"1234",name:"김길동"}
	//-POSTMAN으로 요청시에는 Body탭의 x-www-form-urlencoded 선택후 key와 value입력
	//요청 형식
	//POST http://localhost:8080/users	
	/*
	@PostMapping("/users")
	public UsersDto join(UsersDto dto) {		
		int affected= mapper.save(dto);		
		return dto;
	}*/
	//2.데이타를 JSON으로 받아서 입력
	//-jQuery ajax로 요청시에는 data:JSON.stringify({키:"값",키2:"값2"}),
	//                       contentType:"application/json"
	//-POSTMAN으로 요청시에는 Body탭의 raw 선택 및 json선택 후 json형태로 데이터 작성
	//요청 형식
	//POST http://localhost:8080/users	
	@PostMapping("/users")
	@ApiOperation(value = "회원가입",notes = "JSON형식의 데이타를 받아 JSON형식의 데이타 반환")
	public UsersDto join(@RequestBody UsersDto dto) {		
		int affected= mapper.save(dto);		
		return dto;
	}
	//3.회원의 모든 데이타 조회
	/*
	  -FORM태그 혹은 A태그
	  -jQuery ajax
	  -POSTMAN
	 */
	//요청 형식
	//GET http://localhost:8080/users
	@GetMapping("/users")
	@CrossOrigin
	public List<UsersDto> getAllUsers(){
		return mapper.find();
	}
	//4.URI 파라미터(패스 파라미터)로 회원 조회
	/*
	  -FORM태그 혹은 A태그
	  -jQuery ajax
	  -POSTMAN
	 */
	//요청 형식
	//GET http://localhost:8080/users/:username
	@GetMapping("/users/{username}")	
	public UsersDto getUserByUsername(@PathVariable String username ) {
		return mapper.findByUsername(username);
	}
	//5.데이타를 JSON으로 받아서 수정(반드시 JSON으로 받아야 한다)
	//AJAX 혹은 POSTMAN으로 요청
	//※PUT이나 DELETE도 데이타는 요청바디에 싣는다	
	//DTO에는 수정할 비번과 이름을 받자
	//예]{
	//		"password":"5678",
	//		"name":"이길동"
	//	}	
	//요청 형식
	//PUT http://localhost:9090/users/:username
	@PutMapping("/users/{username}")
	public UsersDto editUser(@PathVariable String username,@RequestBody UsersDto dto) {
		//어느 회원을 수정할지 자바빈에 설정
		dto.setUsername(username);
		mapper.update(dto);
		return dto;
	}
	//6.키를 URL파라미터로 받아서 삭제
	//AJAX 혹은 POSTMAN으로 요청	
	//데이타는 필요없다	
	//요청 형식
	//DELETE http://localhost:9090/users/:username
	/*
	@DeleteMapping("/users/{username}")
	public UsersDto removeUser(@PathVariable String username) {
		UsersDto dto= mapper.findByUsername(username);
		mapper.delete(username);
		return dto;
	}*/
	/*
	//반환타입 MAP
	/*
	@DeleteMapping("/users/{username}")
	public Map removeUser(@PathVariable String username) {
		UsersDto dto= mapper.findByUsername(username);
		mapper.delete(username);
		//DTO를 Map으로 변경
		//방법1:직접 DTO를 MAP으로 (MAP를 DTO로)
		
		//Map map = new HashMap();
		//map.put("username", dto.getUsername());
		//map.put("password", dto.getPassword());
		//map.put("name", dto.getName());
		//map.put("joindate", dto.getJoindate());
		//방법2:apache common의 BeanUtils.describe(DTO객체); 혹은 Jackson 의 ObjectMapper사용
		ObjectMapper oMapper = new ObjectMapper();
		Map map = oMapper.convertValue(dto, Map.class);
		return map;
	}*/
	//반환타입 STRING
	/*
	@DeleteMapping("/users/{username}")
	public String removeUser(@PathVariable String username) throws JsonProcessingException {
		UsersDto dto= mapper.findByUsername(username);
		mapper.delete(username);
		//DTO(MAP)를 문자열(JSON형태)로 변환
		ObjectMapper oMapper = new ObjectMapper();
		return oMapper.writeValueAsString(dto);
	}*/
	//반환타입 RESPONSEENTITY
	@DeleteMapping("/users/{username}")
	public ResponseEntity<UsersDto> removeUser(@PathVariable String username){
		UsersDto dto= mapper.findByUsername(username);
		mapper.delete(username);
		HttpHeaders headers= new HttpHeaders();
		headers.set("Content-Type", "application/json;charset=UTF-8");
		return ResponseEntity.ok().headers(headers).body(dto);
	}
	//7.파일 업로드
	//key=value 형태로 전송
	//FORM태그(enctype="multipart/form-data") 혹은 AJAX 혹은 POSTMAN으로 요청	
	//POSTMAN으로 요청시에는 Body탭의 form-data 선택후
	//key와 value입력
	//파일인 경우 key입력시 옆에 file선택 
	//요청 형식
	//POST http://localhost:8080/files
	@CrossOrigin
	@PostMapping(value = "/files",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
	//public ResponseEntity<Map> upload(HttpServletRequest req,@RequestParam List<MultipartFile> files) throws IllegalStateException, IOException{
	public ResponseEntity<Map> upload(HttpServletRequest req,@RequestPart List<MultipartFile> files) throws IllegalStateException, IOException{//@RequestPart로 받아야 스웨거에서 파일찾기 버튼이 생긴다
		//서버의 물리적 경로 얻기
		String path = req.getServletContext().getRealPath("/upload");
		for(MultipartFile muFile:files) {
			//2]File객체 생성	
			//파일 중복시 이름 변경
			String newFilename=FileUtils.getNewFileName(path, muFile.getOriginalFilename());
			File file = new File(path+File.separator+newFilename);
			//3]파일 업로드
			muFile.transferTo(file);
		}
		Map map = new HashMap();
		map.put("success", true);
		return ResponseEntity.ok().header("Content-Type", "application/json;charset=UTF-8").body(map);
	}
	
	@ExceptionHandler({Exception.class})
	public ResponseEntity<String> error(){
		return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
				.header("Content-Type", "text/plain;charset=UTF-8")
				.body("업로드 최대용량 초과 했어요");
	}
	/*
	 [RestTemplate]
	 -Spring 3.0부터 지원하는 내장 클래스로 스프링 서버에서 REST한 방식으로 HTTP 통신을 하기위한 API
	 -Rest방식으로 다른 서버와 HTTP 통신을 동기 방식으로 쉽게 할수 있는  템플릿
	  (AsyncRestTemplate는 비동기 통신)
	 -기본적으로 Connection pool을 사용하지 않아서
	  많은 요청을 하면 TIME_WAIT로 인해 자원이 점점 부족해져 
     서비스에 어려움이 있다

	 -내부적으로 java.net.HttpURLConnection 사용
	 -요청을 보낼때는 HttpEntity< Map혹은 DTO,HttpHeaders>타입에 요청바디(데이타)와 요청헤더와 설정
	 ※클라이언트가 보내는 데이타가 Key=Value쌍(application/x-www-form-urlencoded)일때는 반드시 MultiValueMap 사용
	   데이타가 JSON일때는 (application/json)일때는 MultiValueMap 혹은 Map 사용
	 -응답을 받을때는 ResponseEntity<Map혹은 DTO>

	 */
	 //JSON을 자바객체로 변환하기
	 //https://www.jsonschema2pojo.org
	//※단,서버에서 받은 JSON의 키에 _가 포함되어 있는 경우 자동으로 카멜 케이스로 바뀌니까 _로 다시 수정해주자
	//구글 비전 API 사용
	//객체 감지
	//POST https://vision.googleapis.com/v1/images:annotate
	/*
	JSON 요청 본문:
		{
		  "requests": [
		    {
		      "image": {
		        "source": {
		          "imageUri": "CLOUD_STORAGE_IMAGE_URI"
		        }
		      },
		      "features": [
		        {
		          "maxResults": RESULTS_INT,
		          "type": "OBJECT_LOCALIZATION"
		        },
		      ]
		    }
		  ]
		}
	요청 헤더	
	-H "Authorization: Bearer $(gcloud auth print-access-token)" \
    -H "x-goog-user-project: PROJECT_ID" \
    -H "Content-Type: application/json; charset=utf-8" \
	 */
	@Autowired
	private RestTemplate restTemplate;
	
	@CrossOrigin
	@PostMapping("/vision/object-detect")
	public Map objectDetect(@RequestBody Map paramMap) throws IOException {
		//401:인증 오류시 아래 에러 핸들러 추가
		restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
		restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {

			@Override
			public boolean hasError(ClientHttpResponse response) throws IOException {
				HttpStatus status= response.getStatusCode();
				return status.series() == HttpStatus.Series.SERVER_ERROR;
			}			
		});
		//1.요청헤더 설정용 객체 생성
		HttpHeaders headers = new HttpHeaders();
		headers.add("Authorization", "Bearer ya29.a0AWY7CklGZ1PW9zWPZznG3vg_v-uif5bO9KKU2mpolxqTodPyR9nqTQOynSliP1rosBAeQcsQXai_FMR0NUg_m0hgDumI_gKnoy2ONg8aA4of2rXpvbj108jRWNWS7u5P1UxESAhs5okAkP_Dz_o-urPn66D1T35QiqYQ4waCgYKARESARASFQG1tDrpjg-HQhb_gh7hjwPytmZswg0173");
		headers.add("x-goog-user-project", "nomadic-genre-391102");
		headers.add("Content-Type", "application/json; charset=utf-8");
		
		//2.구글의 요청본문(JSON형태)과 동일한 구조의 DTO로 요청바디 설정
		
		//방법1:자바빈에 요청바디 설정
		ObjectDetectDTO requestBody =  new ObjectDetectDTO();
		ObjectDetectDTO.Source source = new ObjectDetectDTO.Source();
		//source.setImageUri("https://ilyo.co.kr/contents/article/images/2019/1004/1570150763720629.jpg");
		source.setImageUri(paramMap.get("url").toString());
		ObjectDetectDTO.Image images = new ObjectDetectDTO.Image();
		images.setSource(source);
		
//		 "LABEL_DETECTION": 이미지에 포함된 물체나 개념을 탐지하고 관련된 라벨을 제공.
//		"TEXT_DETECTION": 이미지에서 텍스트를 감지하고 추출.
//		"DOCUMENT_TEXT_DETECTION": 이미지에 포함된 문서 전체의 텍스트를 감지하고 추출다.
//		"FACE_DETECTION": 이미지에서 얼굴을 감지하고 얼굴에 대한 특성과 감정을 분석.
//		"LOGO_DETECTION": 이미지에서 로고를 감지하고 관련 정보를 제공.
//		"LANDMARK_DETECTION": 이미지에서 유명한 랜드마크를 감지하고 식별.
//		"IMAGE_PROPERTIES": 이미지의 색상 정보를 분석하고 주요 색상 및 이미지 특성을 제공.
//		"SAFE_SEARCH_DETECTION": 이미지에 대한 안전한 검색 결과를 제공하고 불순한 콘텐츠를 필터링.
		 
		ObjectDetectDTO.Feature feature = new ObjectDetectDTO.Feature();
		feature.setMaxResults(20);
		//feature.setType("FACE_DETECTION");
		feature.setType(paramMap.get("type").toString());
		
		ObjectDetectDTO.Request request= new ObjectDetectDTO.Request();
		request.setImage(images);
		request.setFeatures(Arrays.asList(feature));
		
		ObjectDetectDTO.ImageContext imageContext = new ObjectDetectDTO.ImageContext();
		imageContext.setLanguageHints(Arrays.asList("ko"));
		request.setImageContext(imageContext);
		
		requestBody.setRequests(Arrays.asList(request));
		/*
		//방법2:리소스의 클래스 패스상에 요청본문형식의 JSON파일 생성후
		//     읽어서 맵으로 변환
		ClassPathResource resource = new ClassPathResource("json");        
        //물리적 경로 얻기
        File file = resource.getFile();
        String directoryPath = file.getAbsolutePath();
        //생성할 파일의 경로를 지정.
        String newFilePath = directoryPath + File.separator + "detect.json";
		ObjectMapper objectMapper= new ObjectMapper();
		Map bodyMap=objectMapper.readValue(new File(newFilePath), Map.class);
		System.out.println("json파일 읽기:"+bodyMap.get("requests"));
		*/
		//3.요청 헤더정보등을 담은 HttpEntity객체 생성		
		//DTO혹은 Map에는 요청시 서버에 보낼 데이타를 담는다.
		//※데이타가 Key=Value쌍(application/x-www-form-urlencoded)일때는 반드시 MultiValueMap 사용
		//  데이타가 JSON일때는 (application/json)일때는 MultiValueMap 혹은 Map 사용
		//HttpEntity<DTO혹은 Map> entity = new HttpEntity(DTO혹은 Map객체,headers);
		
		HttpEntity entity = new HttpEntity(requestBody,headers);
		
		//4.RestTemplate으로 요청 보내기
		//String url="한글이 포한된 요청URI";
		//요청 URL에 한글 포함시는 UriComponents로 객체 생성후 사용시는 uri.toString()해서 사용한다
		//UriComponents uri = UriComponentsBuilder.fromHttpUrl(url).build();
		String url="https://vision.googleapis.com/v1/images:annotate";
		
		//외부 OPEN API(구글)서버로부터 받은 데이타 타입이
		//{}인 경우 Map 혹은 DTO
		//[{},{},....]인 경우 List<Map 혹은 DTO>
		
		ResponseEntity<Map> responseEntity = restTemplate.exchange(
												url, //요청 URI
												HttpMethod.POST,//요청 메소드
												entity,//HttpEntity(요청바디와 요청헤더)
												Map.class//응답 데이타가 {}일때
												//DTO계열.class//응답 데이타가 {}일때	
												//List.class//응답 데이타가 [{},{},....]일때
												);
		
		System.out.println("응답코드:"+responseEntity.getStatusCodeValue());
		System.out.println("응답헤더:"+responseEntity.getHeaders());
		System.out.println("응답바디:"+responseEntity.getBody());
		
		return responseEntity.getBody();
		
	}///////////////////////////////
	
	@CrossOrigin
	@PostMapping("/vision/ocr")
	public Map ocr(@RequestParam String base64) {
		//401:인증 오류시 아래 에러 핸들러 추가
		restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
		restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {

			@Override
			public boolean hasError(ClientHttpResponse response) throws IOException {
				HttpStatus status= response.getStatusCode();
				return status.series() == HttpStatus.Series.SERVER_ERROR;
			}			
		});
		
		//1.요청헤더 설정용 객체 생성
		HttpHeaders headers = new HttpHeaders();
		headers.add("Authorization", "Bearer ya29.a0AWY7CklGZ1PW9zWPZznG3vg_v-uif5bO9KKU2mpolxqTodPyR9nqTQOynSliP1rosBAeQcsQXai_FMR0NUg_m0hgDumI_gKnoy2ONg8aA4of2rXpvbj108jRWNWS7u5P1UxESAhs5okAkP_Dz_o-urPn66D1T35QiqYQ4waCgYKARESARASFQG1tDrpjg-HQhb_gh7hjwPytmZswg0173");
		headers.add("x-goog-user-project", "nomadic-genre-391102");
		headers.add("Content-Type", "application/json; charset=utf-8");
		//2.구글의 요청본문(JSON형태)과 동일한 구조의 맵(방법3)으로 요청바디 설정
		Map<String,List> requestBody = new HashMap<>();
		List value = new Vector();
		Map map = new HashMap();
		Map imageValue = new HashMap();
		imageValue.put("content", base64);
		map.put("image", imageValue);
		List featureValue = new Vector();
		Map featureMap = new HashMap();
		featureMap.put("type","TEXT_DETECTION");
		featureValue.add(featureMap);
		map.put("features", featureValue);
		value.add(map);		
		requestBody.put("requests", value);
		
		//3.요청 헤더정보등을 담은 HttpEntity객체 생성	
				
		HttpEntity entity = new HttpEntity(requestBody,headers);
		
		//4.RestTemplate으로 요청 보내기
				
		String url="https://vision.googleapis.com/v1/images:annotate";
		
		//외부 OPEN API(구글)서버로부터 받은 데이타 타입이
		//{}인 경우 Map 혹은 DTO
		//[{},{},....]인 경우 List<Map 혹은 DTO>
		
		ResponseEntity<Map> responseEntity = restTemplate.exchange(
												url, //요청 URI
												HttpMethod.POST,//요청 메소드
												entity,//HttpEntity(요청바디와 요청헤더)
												Map.class//응답 데이타가 {}일때
												//DTO계열.class//응답 데이타가 {}일때	
												//List.class//응답 데이타가 [{},{},....]일때
												);
		
		System.out.println("응답코드:"+responseEntity.getStatusCodeValue());
		System.out.println("응답헤더:"+responseEntity.getHeaders());
		System.out.println("응답바디:"+responseEntity.getBody());
		
		return responseEntity.getBody();
				
	}
	
}

전 프로젝트(springapp)에서 webapp->WEB-INF->views->ajax10폴더에서 Ajax.jsp 

에서 Rest Controller부분을 함 11~13까지

 

3가지 부분

 

Ajax.jsp

Ajax.jsp의 script부분

//11]스프링 REST API서버로 자체 데이타 요청
	$('#btnSelfRestApi').click(function(){
		$.ajax({
			url:"http://localhost:8080/users",
			dataType:'json'
		}).done(function(data){
			console.log(data);
		});
		
	});
	//12]스프링 REST API서버로 요청(구글 비젼-객체 탐지)
	$('#btnGoogleRestApi').click(function(){
		$.ajax({
			method:"post",
			url:"http://localhost:8080/vision/object-detect",
			dataType:'json',
			contentType:"application/json",
			data:JSON.stringify({"url":"https://cdn.imweb.me/upload/S201911194483dd7a28d0d/ea7d24ddebffb.png","type":"TEXT_DETECTION"})
		}).done(function(data){
			console.log(data);
			var detect=data.responses[0]['localizedObjectAnnotations'];
			$.each(detect,function(index,item){
				console.log("객체명:%s,정확도:%s",item.name,item.score*100+'%');
			});
		});
	});
	//13]OCR
	//https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL
	//https://developer.mozilla.org/ko/docs/Web/API/FormData/FormData
	$('input[name=files]').change(function(e){
		var formData = new FormData();//AJAX로 파일 업로드시 사용
		console.log("e.target.files:",e.target.files);
		//append(첫번째 인자 파라미터명,두번째 인자 File객체)
		formData.append("files",e.target.files[0]);
		$.ajax({
			url:"http://localhost:8080/files",
			processData:false,
			contentType:false,
			data:formData,
			method:'post'
		}).done(function(data){
			console.log('업로드 성공:',data);
			var reader = new FileReader();//이미지파일을 Base64로 인코딩용
			
			reader.onload=function(e){				
				//이미지 미리보기
				$('#preview').attr("src",e.target.result);
				//Base64인코딩
				var base64=e.target.result;
				console.log(base64.split(",")[1]);
				 //여기서 Base64인코딩된 문자열을 스프링 REST API서버로 전송한다
				 $.ajax({
					 url:"http://localhost:8080/vision/ocr",
					 method:'post',
					 data:"base64="+encodeURIComponent(base64.split(",")[1]),
					 dataType:'json'
				 }).done(function(data){
					 console.log('구글 서버로부터 받은 데이타:',data);
					 console.log(data['responses'][0]['fullTextAnnotation']['text'])
				 });
			};
			
			//미리보기용
			reader.readAsDataURL(e.target.files[0]);
			
		});
	});

결과)

파일업로드 하고 그걸 미리보기
이런 식의 결과가 나옴

'RestController' 카테고리의 다른 글

76일차 2023-06-26  (0) 2023.06.26