# Application Programming Interface
API란? How to program interact with each other!
간단히! 키보드를 통해 정보를 입력하고 컴퓨터와 interacting
사용자 → API에게 장바구니 리스트 보여줘 요청 → 우리 서버에 요청 → 우리 서버는 JSon방식으로 응답 내려줘
API는 데이터를 주고 받을 수 있도록 하는 매개체 역할. 즉, SW가 SW에게 지정된 형식으로 요청, 명령 받을 수 있는 수단
※ JSon방식?
데이터를 주고 받을 때 특정 형식으로 데이터만 효율적으로 넘겨주는 방식.
왜 필요해? 우리는 서비스가 어떻게 구현돼있는진 몰라도 이미 만들어진 기능을 버튼처럼 가져다 쓸 수 있어.
API 종류 (서버와 통신 할 수 있는 다르게 생긴 키보드 일뿐) 어떠한 형식
1. 공공 API
ex - 카카오 맵이나 날씨 API.
잠실의 지도를 보고싶으면 한국의 지도를 갖고 있는 미리 작성된 서버에서 잠실의 지도를 요청.
너무 방대하기에 카카오(서버)에서는 자사 데이터를 활용해 카카오맵 API를 사용자에게 제공.
public API는 개방형으로 모두에게 공개되나 노출의 위험이 있기 때문에 접근 권한이 정해져있음.
2. REST API
주로 컴퓨터간 통신 채널을 제공한는 REST의 아키텍처 스타일로 지원되는 애플리케이션 프로그램 인터페이스.
(REST방식으로 데이터를 주고 받을 수 있게 해놓은 것)
기상청 서버에 정보을 요청하는 지정된 형식으로 여기는 날자, 여기는 지역 등등 이렇게 표시해서 해당 주소로 정보 요청.
※ HTTP API - HTTP 통신 규칙을 사용한 API
※ REST API - HTTP를 잘 활용하기 위한 원칙을 준수한 API
URI로 자원을 표현하고, 상태는 HTTP method(Get, Post, Put, Delete)로
[스캔파일 ECM에 보관] 스캔 프로그램을 ECM과 연동API제(자바lib)공해서 문서 업로드
DestinyAPOISet.jar 제공(API를 제공한다) → core 호출(해당하는 controller커스텀)
<고려해봐야 할 것>
1) createdummy session과 login(account) : createdummy session은 로그인 상태면 로그인 이력이 안생기겠지. login은 필요없는 이력이 쌓여.
파라미터 account를 request로 보내서 한번만 받도록?
자바 API 통신
1. URL 객체 생성과 연결
기본 정보 세팅 과정
[APISet.java]
public DestinyAPISet(String ecmUrl, String contextPath, String remoteAddr, String groupCode, String account, String systemID) {
this.ecmUrl = ecmUrl;
this.contextPath = contextPath;
this.remoteAddr = remoteAddr;
this.groupCode = groupCode;
this.account = account;
this.systemID = systemID;
this.connection = new DestinySLOConnectionImpl();
System.setProperty("storage.contextpath", contextPath);
}
당연하게 생성자는 APISet.java에 존재
[APISetTest.java]
private DestinyAPISet apiset = null;
/**
* DestinyAPISet Default Setting
*/
protected void setUp() throws Exception {
String ecmUrl = "http://127.0.0.1:8080"; // ECM URL
String contextPath = "";
String remoteAddr = "localhost"; // API를 호출하는 주소
String systemID = "IMG"; // API를 호출하는 시스템ID
String account = "test2";
String groupCode = "E000";
apiset = new DestinyAPISet(ecmUrl, contextPath, remoteAddr, groupCode, account, systemID);
}
apiset객체 생성해서 필요한 파라미터 값 넣어주고(특이하게 이 은행은 account를 고정해서 넣어준다.)
[APISet.java]의 생성자에서 this.connection = new DestinySLOConnectionImpl(); 호출->
[DestinySLOConnectionImpl.java]에서 init()을 호출하고 init()은 아래 코드, 여기서 SLOConnection의 역할은 끝으로 보임.
protected void init()
{
try
{
setErrorMsg();
setRegularExpression();
}
catch( Exception e){ e.printStackTrace();}
m_bInitialize = true;
}
여기까지 기본 정보 확인.
여기서부터 api 통신 시작
이후 문서 등록 API 호출할 건데
1) main함수에서 apiset.setUp();에서 위의 apiset객체 생성해서 파라미터 값넣어주는 apiset.setUp()호출하고
[APISetTest.java]
public static void main(String[] args) {
DestinyAPISetTest apiset = new DestinyAPISetTest();
try {
apiset.setUp();
String folderOID = "E000";
String documentName = "0728";
documentOID = apiset.testCreateDocument( folderOID, documentName);
apiset.testGetDocumentFiles( documentOID);
}
catch (Exception e) {
e.printStackTrace();
}
}
2) 그 파라미터값들 설정해서 api.testCreateDocument(folderOID, documentName);를 호출
public String testCreateDocument( String folderOID, String DocumentName) throws Exception {
// 파일정보 설정
String szLocalFilePath = "d:/temp/";
String fileName1 = "3333.txt";
String fileName2 = "4444.txt";
String[] arrFilesNames = { fileName1, fileName2};
File[] arrFiles = {
new File( szLocalFilePath + fileName1),
new File( szLocalFilePath + fileName2)
};
Map map = apiset.createDocument( folderOID, DocumentName, arrFilesNames, arrFiles);
String documentOID = ( String) map.get( "documentOID");
String[] fileOIDs = ( String[]) map.get( "fileOIDs");
String[] fileNames = ( String[]) map.get( "fileNames");
String[] storageFileIDs = ( String[]) map.get( "storageFileIDs");
System.out.println( "documentOID : " + documentOID);
for( int i = 0; fileOIDs != null && i < fileOIDs.length; i++) {
System.out.println( "fileOIDs[" + i + "] : " + fileOIDs[i]);
System.out.println( "fileNames[" + i + "] : " + fileNames[i]);
System.out.println( "storageFileIDs[" + i + "] : " + storageFileIDs[i]);
}
return documentOID;
}
3) 이제 Map map = apiset.createDocument( folderOID, DocumentName, arrFilesNames, arrFiles);로 [APISet.java]를 호츨할거야. 그래서
4) [APISet.java] 에 들어오면
[APISet.java]
public Map createDocument(String folderOID, String documentName) throws Exception {
String query = "/custom/apiset.do?method=createDocument";
JSONObject response = httpRequestPost(query, sb.toString());
if (hasError(response)) {
map.put( "exceptionCode", response.get( "exceptionCode"));
}else {
String documentOID = response.getJSONObject("params").getString("documentOID");
JSONArray fileOID = null;
if (response.getJSONObject("params").get("fileNames").toString().length() > 0) {
fileName = (JSONArray) response.getJSONObject("params").get("fileNames");
}
map.put("documentOID", documentOID);
map.put("fileOIDs", fileOIDs);
map.put("fileNames", fileNames);
} return map;
}
String query 선언해서 JSONObject response = httpRequestPost(query, sb.toString()); 에 넣어주는데
5) httpRequestPost메서드에서 String url = getECMContextUrl();로 메서드 호출해 url을 만들어주고 connection.setTargetURL(url + query); 로 넘기면
private JSONObject httpRequestPost(String query, String params) throws Exception {
String url = getECMContextUrl();
// connection.setTargetURL(ecmUrl + query);
connection.setTargetURL(url + query);
params += "&" + "account=" + account + "&" + "groupCode=" + groupCode + "&" + "systemID=" + systemID;
String result = connection.connect(params);
JSONObject json = new JSONObject(result);
return json;
}
6) [SLOConnection.java]로 와서 아래와 같이 세팅해서 값 설정해주고
public void setTargetURL( String szURL) {
m_szTargetURL = szURL;
m_bHasTarget = true;
}
7) 다시 5번으로 돌아와서 String result = connection.connect(params);에서 [SLOConnection.java]를 호출하면
[SLOConnection.java]
public String connect( String params) throws Exception
{
if( m_bHasTarget == false) throw new Exception( getMsg( MSG_SET_TARGET_URL));
if( m_bInitialize == false) throw new Exception( getMsg( MSG_INITIALIZE_FAIL));
// connect
URL url = new URL( m_szTargetURL);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
//URLConnection con = url.openConnection();
/*
con.setConnectTimeout( CONNECT_TIME_OUT);
con.setReadTimeout( READ_TIME_OUT);
*/
con.setDoInput( true);
con.setDoOutput( true);
con.setUseCaches( false);
con.setRequestMethod( "POST");
con.setConnectTimeout( 10000);
con.setAllowUserInteraction( true);
con.setRequestProperty( "Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
// set cookie
if( m_bUseCookie)
{
con.addRequestProperty( "Cookie", getCookieString());
}
PrintWriter pw = new PrintWriter( new OutputStreamWriter( con.getOutputStream(), "UTF-8"));
pw.write( params);
pw.flush();
// OutputStream os = con.getOutputStream();
// os.write( params.getBytes( "UTF-8"));
// os.flush();
// os.close();
// get Http Header
m_mHeader = con.getHeaderFields();
MessageFormat mf = new MessageFormat( "{0}={1}" + System.getProperty( "line.separator"));
String szHeader = getKeyValueStringFromMap( m_mHeader, mf);
// process by http status code
String szResource = "";
//if( reHttpStatus.match( szHeader))
Matcher mHttpStatus = pHttpStatus.matcher(szHeader);
if( mHttpStatus.find())
{
//String szHttpStatus = reHttpStatus.getParen( 1);
String szHttpStatus = mHttpStatus.group( 1);
int nHttpStatus = Integer.parseInt( szHttpStatus);
// 2XX
if( nHttpStatus >= 200 && nHttpStatus < 300)
{
// save cookie
saveCookie( szHeader);
szResource = getResourceFromStream( con.getInputStream());
}
}
else
{
throw new Exception( getMsg( MSG_HTTP_STATUS_NOT));
}
return szResource;
}
여기에 URL 객체 생성 URL url = new URL( m_szTargetURL); 하고
생성한 URL 객체에 대한 연결 객체를 얻어 HttpURLConnection con = (HttpURLConnection) url.openConnection();
2. HttpURLConnection 클래스
HttpURLConnection 클래스는 HTTP 프로토콜 통신을 위한 클래스입니다. 각각의 객체들은 하나의 요청을 위해 사용. HttpURLConnection 클래스를 살펴보면 URLConnection 클래스를 확장한(상속받은) 추상클래스임을 알 수 있음.
[HttpURLConnection .java]
abstract public class HttpURLConnection extends URLConnection {...}
1) HttpURLConnection 객체 생성
URL 객체의 openConnection() 메소드를 통해 URLConnection 객체를 얻을 수 있었음. HttpURLConnection객체는 URLConnection 객체를 확장하고(상속받고)있어 Type Casting을 통해 HttpURLConnection객체를 쉽게 얻을 수 있음.
결론적으로 url에 연결하는 HTTP 연결 객체를 생성하고 싶다면 다음과 같이 코드를 작성하면
URL url = new URL("https://www.google.com");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
2) 요청 메소드 설정
HTTP 요청을 위해서는 요청 메소드를 설정해야됨.
setRequestMethod() 메소드는 요청 메소드를 문자열 파라미터로 받아서 유효한 요청 메소드면 method 멤버 변수에 요청 메소드를 저장하고, 아니면 ProtocolException 예외를 발생. 처리할 수 있는 요청 메소드로는 GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE
[HttpURLConnection.java]
public void setRequestMethod(String method) throws ProtocolException {
if (connected) {
throw new ProtocolException("Can't reset method: already connected");
}
// This restriction will prevent people from using this class to
// experiment w/ new HTTP methods using java. But it should
// be placed for security - the request String could be
// arbitrarily long.
for (int i = 0; i < methods.length; i++) {
if (methods[i].equals(method)) {
if (method.equals("TRACE")) {
SecurityManager s = System.getSecurityManager();
if (s != null) {
s.checkPermission(new NetPermission("allowHttpTrace"));
}
}
this.method = method;
return;
}
}
throw new ProtocolException("Invalid HTTP method: " + method);
}
기본으로 GET으로 설정돼 있어서 [SLOConnection.java]에서 con.setRequestMethod( "POST");요렇게 설정해줘야됨.
3) 요청 헤더 설정
HttpURLConnection클래스가 확장(상속)하는 URLConnection클래스에 정의된 setRequestProperty() 메소드로 요청 헤더를 설정
[URLConnectuon.java]
public void setRequestProperty(String key, String value) {
if (connected)
throw new IllegalStateException("Already connected");
if (key == null)
throw new NullPointerException ("key is null");
if (requests == null)
requests = new MessageHeader();
requests.set(key, value);
}
String 타입의 key, value 파라미터를 받습니다. 각 파라미터를 통해 요청 헤더의 이름과 값을 설정할 수 있습니다. 만약 key값이 null이라면 NullPointerException 예외를 발생
4) Post 요청시 데이터 넘겨주기
4-1) POST 요청을 할 때에는 OutputStream 객체로 데이터를 전송. setDoOutput() 메소드를 통해 OutputStream 객체로 전송할 데이터가 있다는 옵션을 설정해야됨.
checkConnected() 메소드에서는 연결 객체가 연결되어있는지 확인하고, 이미 연결되어있다면 IllegalStateException 예외를 발생
[URLConnectuon.java]
public void setDoOutput(boolean dooutput) {
if (connected)
throw new IllegalStateException("Already connected");
doOutput = dooutput;
}
setDoOutput() 메소드는 boolean 타입의 dooutput 파라미터를 받아 doOutput멤버 변수에 저장.
doOutput 변수가 true이면 OutputStream으로 데이터를 전송한다는 뜻이고, false이면 하지 않음.
기본으로 false로 초기화되어있기 때문에 POST로 데이터를 전송하려면 꼭 옵션을 설정해줘야 됨.
4-2) getOutputStream() 메소드를 통해 연결에 사용할 OutputStream 객체를 얻을 수 있습니다. 프로토콜이 출력을 지원하지 않는다면 UnknownServiceException 예외를 발생
public OutputStream getOutputStream() throws IOException {
throw new UnknownServiceException("protocol doesn't support output");
}
5) 응답 코드 얻기
getResponseCode() 메소드를 통해 응답 코드를 얻음
6) 응답 데이터 얻기
getInputStream() 메소드를 통해 응답 데이터를 읽을 수 있는 InputStream객체를 얻을 수 있음. 응답을 문자열 타입으로 얻기 위해 BufferedReader 객체를 사용.
3. Controller와 연결
[APISet.java]에서
private JSONObject httpRequestPost(String query, String params) throws Exception {
String url = getECMContextUrl();
// connection.setTargetURL(ecmUrl + query);
connection.setTargetURL(url + query);
params += "&" + "account=" + account + "&" + "groupCode=" + groupCode + "&" + "systemID=" + systemID;
String result = connection.connect(params);
JSONObject json = new JSONObject(result);
return json;
}
connection.connect(params);으로 컨트롤러 갔다와서
4.Controller에서 문서 생성 메서드 실행
document = ( XDocument)(EDMServiceUtil.getDocumentService()).create( document, false, false);
문서 생성 메서드 타서 문서 생성하고 데이터 다 받고
5. 다시 돌아와서 [APISet.java]에서
private JSONObject httpRequestPost(String query, String params) throws Exception {
String url = getECMContextUrl();
// connection.setTargetURL(ecmUrl + query);
connection.setTargetURL(url + query);
params += "&" + "account=" + account + "&" + "groupCode=" + groupCode + "&" + "systemID=" + systemID;
String result = connection.connect(params);
JSONObject json = new JSONObject(result);
return json;
}
이전 [SLOConnection.java]에서 return 해준 szResource를 result에 담아서 json객체를 만들고 다시 이 json을 return해줘
6. map에 담아서 [APISetTest.java]에 리턴
[APISet.java]
map.put("documentOID", documentOID);
map.put("fileOIDs", fileOIDs);
map.put("fileNames", fileNames);
map.put("fileSizes", fileSizes);
map.put("fileLastModifiedAts", fileLastModifiedAts);
map.put("storageFileIDs", storageFileIDs);
}
return map;
컨트롤러를 다녀와서 받은 값을 map에 넣어서 [APISetTest.java]로 map을 return해줌