'Java'에 해당되는 글 26건

  1. 2011.08.23 Apache HttpComponents를 이용한 GET, POST 요청하기 7
  2. 2011.08.22 Oracle JDBC : "스트림이 이미 종료되었습니다" 혹은 "java.sql.SQLException: Stream has already been closed" 익셉션
  3. 2011.08.22 mybatis 에서 Oracle LONG, CLOB Select 시 에러날때 : getCLOB not implemented for class oracle.jdbc.driver.XXX
  4. 2011.08.19 Java JSON 처리 라이브러리 Jackson JSON Processor #2 : Map, List <--> JSON String 상호변환 1
  5. 2011.08.12 Java JSON 처리 라이브러리 Jackson JSON Processor #1 : Map, List 를 JSON String으로~ 5

Apache HttpComponents를 이용한 GET, POST 요청하기

예전에는 Jakarta Commons HttpClient 프로젝트로 commons 프로젝트들이랑 옹기종기 같이 모여 있었는데 문득 사이트에 가보니 

프로젝트명이 Apache HttpComponents 로 바껴있고  라이브러리 사용하는 것도 훅 달라진것 같았다.

테스트겸 겸사겸사 GET, POST 요청을 하는 클래스를 맹글어 보았다.



소스코드
package proxy;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

public class HttpProxy {
	/**
	 * POST 요청
	 * @param url       요청할 url
	 * @param params    파라메터
	 * @param encoding  파라메터 Encoding
	 * @return 서버 응답결과 문자열
	 */
	public String post(String url, Map params, String encoding){
		HttpClient client = new DefaultHttpClient();
		
		try{
			HttpPost post = new HttpPost(url);
			System.out.println("POST : " + post.getURI());
			
			List<NameValuePair> paramList = convertParam(params);
			post.setEntity(new UrlEncodedFormEntity(paramList, encoding));
			
			ResponseHandler<String> rh = new BasicResponseHandler();

			return client.execute(post, rh);
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			client.getConnectionManager().shutdown();
		}
		
		return "error";
	}
	
	public String post(String url, Map params){
		return post(url, params, "UTF-8");
	}

	
	
	
	/**
	 * GET 요청
	 * POST 와 동일
	 */
	public String get(String url, Map params, String encoding){
		HttpClient client = new DefaultHttpClient();

		try{
			List<NameValuePair> paramList = convertParam(params);
			HttpGet get = new HttpGet(url+"?"+URLEncodedUtils.format(paramList, encoding));
			System.out.println("GET : " + get.getURI());
			
			ResponseHandler<String> rh = new BasicResponseHandler();
			
			return client.execute(get, rh);
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			client.getConnectionManager().shutdown();
		}
		
		return "error";
	}
	
	public String get(String url, Map params){
		return get(url, params, "UTF-8");
	}
	
	
	
	private List<NameValuePair> convertParam(Map params){
		List<NameValuePair> paramList = new ArrayList<NameValuePair>();
		Iterator<String> keys = params.keySet().iterator();
		while(keys.hasNext()){
			String key = keys.next();
			paramList.add(new BasicNameValuePair(key, params.get(key).toString()));
		}
		
		return paramList;
	}
	
	

	// Test
	public static void main(String[] args) {
		HttpProxy p = new HttpProxy();
		
		Map params = new HashMap();
		params.put("w", "tot");
		params.put("q", "한예슬");
		
		System.out.println(p.get("http://m.search.daum.net/search", params));
	}
}

HttpProxy.java






라이브러리 다운로드는  http://hc.apache.org/downloads.cgi 요기에 가서 다운로드 받던지

Maven을 사용하고 있다면 디펜던시에
<dependency>
	<groupId>org.apache.httpcomponents</groupId>
	<artifactId>httpclient</artifactId>
	<version>4.1.2</version>
</dependency>
 요걸 추가해 주면 된다.




그리고~ http://hc.apache.org/downloads.cgi 요기에서 다운받아 보면 압축파일안에  examples, tutorial, api 문서도 같이 들어 있어서 참고하기 좋다~

※ 위 예제를 실행하기 위해서 꼭 필요한 jar 파일은 httpclient-4.1.2.jar, httpcore-4.1.2.jar, commons-codec-1.4.jar, commons-logging-1.1.1.jar
요것들 4개고 모두 lib 디렉토리 안에 들어 있음.

Oracle JDBC : "스트림이 이미 종료되었습니다" 혹은 "java.sql.SQLException: Stream has already been closed" 익셉션

Oracle JDBC 로 CLOB 나 LONG 같은, 값을 Stream 형태로 읽어야 하는 타입들을 Select 할때 발생하는 Exception 이다.

나같은 경우는 mybatis로 select 할때 쿼리문과 쿼리결과를 Log4j 로그로 찍었는데 시쭈구리하게도  logger 에서 ResultSet을 로그로 찍었기 때문에 나는 에러였다.

찍혀 있는 로그를 가만히 살펴보면 쿼리문이랑 ResultSet 결과가 먼저 쭉 찍힌뒤 그 뒤로 익셉션이 쭉 발생하고 있었다.
고말인 즉슨, 로거에서 찍을때는 정상적으로 값을 가져왔다는 말이된다.



가만 입다물고 생각해보면, 로거에서 ResultSet을 찍을려고 값을 가져오면서 Stream이 닫혀 버렸기 때문에 나는 에러 같았다.

기존 log4j.xml 설정은
<logger name="java.sql">
	<level value="debug" />
</logger>
 요렇게 되 있어서 java.sql 패키지에 포함된 모든클래스에서 발생하는 로그들을 다 찍게 되 있었다.




고것을
<logger name="java.sql.Connection">
	<level value="debug" />
</logger>

<logger name="java.sql.PreparedStatement">
	<level value="debug" />
</logger>
요래 바꿔서 ResultSet 에 대한 로그를 안찍게 바꾸니 해결되었다. 로그가 아예 필요없다면 다 지워도 되고~
나는 어떤 쿼리가 실행됬는가 까지는 꼭 알고 싶어서..



이것도 왠지 버그인것 같은 느낌이 문득 들지만 언젠가는 해결될것이라고 믿는다. 아니면 내가 잘못 쓰고 있는건가???? 

테스트 라이브러리 버전
mybatis :  3.0.6-SNAPSHOT.jar
oracle jdbc driver : ojdbc6.jar (11.2.0.2.0) 

mybatis 에서 Oracle LONG, CLOB Select 시 에러날때 : getCLOB not implemented for class oracle.jdbc.driver.XXX

MySQL 에서는 어떤지 잘 모르겠지만 아무튼 오라클에서는 Long Type이나 CLOB Type 컬럼을 select 할때 getCLOB() 가 구현되지 않았다면서 에러가 난다.

mybatis 에서 패치를 해줘야 되나 오라클에서 패치를 해 줘야 하나 쫌 거시기 하지만 아무튼 지금! 현재는 Long 을 가져오질 못한다 -_-

누군가는 패치를 해주긋지~

현재 라이브러리 버전은 요렇다.!
mybatis :  3.0.6-SNAPSHOT.jar
oracle jdbc driver : ojdbc6.jar (11.2.0.2.0)

지금 당장 하기는 해야 겠고 고쳐줄때 까지 기다릴수 없으니 해결하기 위해선 mybatis config 파일에서 LONG TYPE에 대해 TypeHandler 를 설정해 주면 된다.

mybatis config 파일
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 
  "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
	<typeHandlers>
		<typeHandler handler="stove99.handler.CLOBHandler" javaType="String" jdbcType="LONGVARCHAR"/>
	</typeHandlers>
</configuration>
설정을 보면 대략 알겠지만 LONG 타입을 뜻하는 LONGVARCHAR jdbcType 에 대하여 처리할 핸들러를 설정해 주는 것이다.





TypeHandler 는 org.apache.ibatis.type.TypeHandler 인터페이스를 implements 해서 간단하게 메소드 3개를 구현하면 된다.
stove99.handler.CLOBHandler 의 소스는 다음과 같다.
package stove99.handler;

import java.io.StringReader;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;

public class CLOBHandler implements TypeHandler{

	@Override
	// 파라메터 셋팅할때
	public void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) 
           throws SQLException {
		String s = (String) parameter;
		StringReader reader = new StringReader(s);
		ps.setCharacterStream(i, reader, s.length());
	}

	@Override
	// Statement 로 SQL 호출해서 ResultSet 으로 컬럼값을 읽어올때
	public Object getResult(ResultSet rs, String columnName) throws SQLException {
		return rs.getString(columnName);
	}

	@Override
	// CallableStatement 로 SQL 호출해서 컬럼값 읽어올때
	public Object getResult(CallableStatement cs, int columnIndex) throws SQLException {
		return cs.getString(columnIndex);
	}
}

내 나름대로 이해하고 있는걸 적어놓은 것이니 미심쩍다는 사람들은 첨부파일 pdf 에서 14쪽을 참고하셈~

MyBatis-3.0.3-User-Guide.pdf

 

Java JSON 처리 라이브러리 Jackson JSON Processor #2 : Map, List <--> JSON String 상호변환

JSON 문자열을 Map 이나 List Object 로 변환하는 것이랑

JSON 문자열을 xml 다루듯이 트래버싱 하는것,

Map 이나 List Object 를 JSON 문자열로 변환하는것  요래 정리를 해 보았다.

뭐 요정도만 알면 대충 할 수 있는건 다 할 수 있을듯하다. 뭐 필요하면 더 그때가서 더 찾아보면 되긋지~
package test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;

public class Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception{
		// 테스트 데이터 : 맵에 string 2개랑 list 하나가 들어가 있는 형태
		List<String> list = new ArrayList<String>();
		list.add("list1");
		list.add("list2");
		list.add("list3");

		Map<String, Object> d = new HashMap<String, Object>();
		d.put("list", list);
		d.put("a", "va");
		d.put("b", "vb");
		////////////////////////////////////////////////
		
		
		
		ObjectMapper om = new ObjectMapper();
		
		// Map or List Object 를 JSON 문자열로 변환
		String jsonStr = om.writeValueAsString(d);
		System.out.println("object to json : " + jsonStr);

		
		// JSON 문자열을 Map or List Object 로 변환
		Map<String, Object> m = om.readValue(jsonStr, new TypeReference<Map<String, Object>>(){});
		System.out.println("json to object : " + m);
		
		
		// JSON 문자열을 xml 다루는것과 비슷하게 트리로 맨들어서 트래버싱하기(Tree Model)
		JsonNode root = om.readTree(jsonStr);
		
		// 단일값 가져오기
		System.out.println("b의 값 : " + root.path("b").getValueAsText());
		
		// 배열에 있는 값들 가져오기
		if( root.path("list").isArray() ){
			Iterator<jsonnode> it = root.path("list").iterator();
			
			// 요래 해도 됨
			// Iterator<jsonnode> it = root.path("list").getElements()
			while(it.hasNext()){
				System.out.println(it.next().getTextValue());
			}
		}
		
		// 이외 getXXXValue() 시리즈, findParent(), findValue() 등등 유용한 함수 많음~
	}
}

Test.java


Java JSON 처리 라이브러리 Jackson JSON Processor #1 : Map, List 를 JSON String으로~

Java 에서 JSON 을 처리하기 위한 라이브러리는 많이 있겠지만 요즘은 사람들이 Jackson 라이브러리를 많이 쓰는것 같다.

프로젝트 홈페이지(http://jackson.codehaus.org/)에 가보면 "High-performance JSON processor!" 요런 문구가 제일 상단에 떡 있는걸 봐서는 성능도 좋은것 같다!  

일단 그냥 써보자. 계속 쓰다보면 잘 알게 된다.

먼저 라이브러리를 써묵기 위해서 jar 파일을 받아야 한다. 프로젝트 홈페이지 다운로드 메뉴(http://wiki.fasterxml.com/JacksonDownload)로 가서  

쭉 있는것들중에 core-aslmapper-asl 을 다운로드 받아 클래스 패스가 참조하는 폴더에 복사해 주면된다.

웹 프로젝트 같은 경우 WEB-INF/lib 디렉토리에 복사하면 되긋다~

메이븐 프로젝트일 경우는 간단히  pom.xml 에
<dependency>
	<groupId>org.codehaus.jackson</groupId>
	<artifactId>jackson-mapper-asl</artifactId>
	<version>1.8.5</version>
</dependency>
를 추가해 주면 사용할 수 있다.

지금 현재 최신 버전이 1.8.5 이기 때문에 version 란에다 1.8.5를 적어준 것이고 나중에 또 업데이트가 될것이니

 http://mvnrepository.com/artifact/org.codehaus.jackson/jackson-mapper-asl 여기에서 확인해 보고 최신버전으로 바꿔주면 될것이다.


간단한 샘플을 보자.
// 맵에 데이터들이 들어가 있는 형태
Map dummyData1 = new HashMap();
dummyData1.put("value1", "값1");
dummyData1.put("value2", "값2");

ObjectMapper om = new ObjectMapper();

try {	
	System.out.println(om.defaultPrettyPrintingWriter().writeValueAsString(dummyData1));
} catch (JsonGenerationException e) {	
	e.printStackTrace();
} catch (JsonMappingException e) {	
	e.printStackTrace();
} catch (IOException e) {	
	e.printStackTrace();
}
출력결과
{  "value1" : "값1",  "value2" : "값2"}
Jackson 라이브러리로 하는 짓들의 대부분은 ObjectMapper 라는 클래스의 인스턴스 생성을 한다음에 한다.

생성된 고것을 가지고 Json 문자열을 객체로 변환한다던가 객체를 JSON 문자열로 변환한다던가 한다. 뭐 다른 쓸만한 것도 많을 것이다.
뭐 아직 많이 모르니깐~

아무튼 Map 이나 List에 들어가 있는 데이터들을 쪽바로 잘 변환해 준다.

물론 getter 와 setter 메소드 시리즈가 있는 도메인 오브젝트,
예를 들어 User, Account 뭐 이런 종류의 오브젝트도 writeValueAsString 메소드의 파라메터로 넣으면 잘 변환된다.


아무튼~ 각설하고~ List 인 경우도 한번 해보자

// List 에 맵이 들어가 있는 형태
List dummyData2 = new ArrayList();
Map m = new HashMap();
m.put("value1", "값1");
m.put("value2", "값2");
dummyData2.add(m);

m = new HashMap();
m.put("value1", "값3");
m.put("value2", "값4");
dummyData2.add(m);

ObjectMapper om = new ObjectMapper();

try {	
	System.out.println(om.defaultPrettyPrintingWriter().writeValueAsString(dummyData2));
} catch (JsonGenerationException e) {	
	e.printStackTrace();
} catch (JsonMappingException e) {	
	e.printStackTrace();
} catch (IOException e) {	
	e.printStackTrace();
}
출력결과
[ {  "value1" : "값1",  "value2" : "값2"}, {  "value1" : "값3",  "value2" : "값4"} ]
역시 기대했던 대로 잘 변환된다. 

위의 샘플들은 오브젝트를 String으로 변환하는 샘플이고 String 으로 변환활 필요가 없으면(웹요청처리, JSON 파일로 저장하는 경우)  ObjectMapper 클래스의 writeValue() 메소드를 이용해 OutputStream이나 Writer 에 Stream으로 출력해 버려도 된다.
ObjectMapper om = new ObjectMapper();

om.writeValue(response.getWriter(), dummyData);
prev 1 2 3 4 5 6 next