'분류 전체보기'에 해당되는 글 223건
- 2011.08.22 Oracle JDBC : "스트림이 이미 종료되었습니다" 혹은 "java.sql.SQLException: Stream has already been closed" 익셉션
- 2011.08.22 mybatis 에서 Oracle LONG, CLOB Select 시 에러날때 : getCLOB not implemented for class oracle.jdbc.driver.XXX
- 2011.08.22 bean property 간단하게 설정하기 : http://www.springframework.org/schema/p 활용 1
- 2011.08.19 Java JSON 처리 라이브러리 Jackson JSON Processor #2 : Map, List <--> JSON String 상호변환 1
- 2011.08.19 ContentNegotiatingViewResolver 활용 : 하나의 RequestMapping 으로 JSP, JSON, JSONP 처리하기
Oracle JDBC : "스트림이 이미 종료되었습니다" 혹은 "java.sql.SQLException: Stream has already been closed" 익셉션
Java 2011. 8. 22. 16:02
Oracle JDBC 로 CLOB 나 LONG 같은, 값을 Stream 형태로 읽어야 하는 타입들을 Select 할때 발생하는 Exception 이다.
나같은 경우는 mybatis로 select 할때 쿼리문과 쿼리결과를 Log4j 로그로 찍었는데 시쭈구리하게도 logger 에서 ResultSet을 로그로 찍었기 때문에 나는 에러였다.
찍혀 있는 로그를 가만히 살펴보면 쿼리문이랑 ResultSet 결과가 먼저 쭉 찍힌뒤 그 뒤로 익셉션이 쭉 발생하고 있었다.
고말인 즉슨, 로거에서 찍을때는 정상적으로 값을 가져왔다는 말이된다.
가만 입다물고 생각해보면, 로거에서 ResultSet을 찍을려고 값을 가져오면서 Stream이 닫혀 버렸기 때문에 나는 에러 같았다.
기존 log4j.xml 설정은
고것을
나는 어떤 쿼리가 실행됬는가 까지는 꼭 알고 싶어서..
이것도 왠지 버그인것 같은 느낌이 문득 들지만 언젠가는 해결될것이라고 믿는다. 아니면 내가 잘못 쓰고 있는건가????
테스트 라이브러리 버전
나같은 경우는 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)
'Java' 카테고리의 다른 글
mybatis 에서 Oracle LONG, CLOB Select 시 에러날때 : getCLOB not implemented for class oracle.jdbc.driver.XXX
Java 2011. 8. 22. 14:37
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 파일
TypeHandler 는 org.apache.ibatis.type.TypeHandler 인터페이스를 implements 해서 간단하게 메소드 3개를 구현하면 된다.
stove99.handler.CLOBHandler 의 소스는 다음과 같다.
내 나름대로 이해하고 있는걸 적어놓은 것이니 미심쩍다는 사람들은 첨부파일 pdf 에서 14쪽을 참고하셈~
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쪽을 참고하셈~
'Java' 카테고리의 다른 글
bean property 간단하게 설정하기 : http://www.springframework.org/schema/p 활용
Spring 2011. 8. 22. 10:04
bean 의 property 를 설정하기 위해서
프로퍼티를 설정하는 다른 방법으로 스프링 설정 xml 파일 상단에 xmlns:p="http://www.springframework.org/schema/p" 요런걸 추가해 주고
가독성 측면에는 위에것 처럼 property 태그를 사용하는게 뭐 아무래도 쪼금 더 좋겠지만 그냥 위처럼 설정할 프로퍼티가 딸랑 하나밖에 없는 bean 은 심플하게 죠래 한줄로 설정하는것도 괜찮을것 같다.
property 에 value 를 설정할때는 p:maxUploadSize="값" 요렇게 설정하고
property 에 다른 bean을 참조시키게 할때는 p:maxUploadSize-ref="다른bean ID" 요것처럼 뒤에다 -ref 를 붙여주면 된다.
그리고 만약 이클립에 STS 가 설치되 있다면 p: 한 다음에 컨트롤 + 스페이스 키를 누르면 자동완성 기능도 동일하게 작동된다.
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="10000000" /> </bean>요런식으로 property 태그를 이용해서 설정한다.
프로퍼티를 설정하는 다른 방법으로 스프링 설정 xml 파일 상단에 xmlns:p="http://www.springframework.org/schema/p" 요런걸 추가해 주고
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" p:maxUploadSize="10000000"/>요렇게도 설정할 수 있다.
가독성 측면에는 위에것 처럼 property 태그를 사용하는게 뭐 아무래도 쪼금 더 좋겠지만 그냥 위처럼 설정할 프로퍼티가 딸랑 하나밖에 없는 bean 은 심플하게 죠래 한줄로 설정하는것도 괜찮을것 같다.
property 에 value 를 설정할때는 p:maxUploadSize="값" 요렇게 설정하고
property 에 다른 bean을 참조시키게 할때는 p:maxUploadSize-ref="다른bean ID" 요것처럼 뒤에다 -ref 를 붙여주면 된다.
그리고 만약 이클립에 STS 가 설치되 있다면 p: 한 다음에 컨트롤 + 스페이스 키를 누르면 자동완성 기능도 동일하게 작동된다.
'Spring' 카테고리의 다른 글
Spring @ResponseBody 로 리턴시 한글이 깨질때 (0) | 2013.04.16 |
---|---|
<util:properties/> 와 Spring EL 로 값 가져오기 (0) | 2013.04.12 |
Spring 개발시 개발, 운영환경 프로퍼티 파일 관리하기 (1) | 2011.10.11 |
ContentNegotiatingViewResolver 활용 : 하나의 RequestMapping 으로 JSP, JSON, JSONP 처리하기 (0) | 2011.08.19 |
<context:property-placeholder/> 를 사용할때 property file의 encoding 지정하기 (0) | 2011.08.03 |
Java JSON 처리 라이브러리 Jackson JSON Processor #2 : Map, List <--> JSON String 상호변환
Java 2011. 8. 19. 23:30
JSON 문자열을 Map 이나 List Object 로 변환하는 것이랑
JSON 문자열을 xml 다루듯이 트래버싱 하는것,
Map 이나 List Object 를 JSON 문자열로 변환하는것 요래 정리를 해 보았다.
뭐 요정도만 알면 대충 할 수 있는건 다 할 수 있을듯하다. 뭐 필요하면 더 그때가서 더 찾아보면 되긋지~
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() 등등 유용한 함수 많음~ } }
'Java' 카테고리의 다른 글
ContentNegotiatingViewResolver 활용 : 하나의 RequestMapping 으로 JSP, JSON, JSONP 처리하기
Spring 2011. 8. 19. 19:28
뭔가를 맨들다 보면 데이터를 가져와서 대부분 JSP 를 이용해서 랜더링을 하게 되지만 똑같은 데이터를 ajax 호출을 통해 json 형식으로 받고 싶은 경우도 종종 있다.
그리고 JSONP 형식으로 같은 도메인이 아닌 다른 도메인으로 데이터를 제공하고 싶은 경우도 있다.
고럴때 ContentNegotiatingViewResolver 를 활용하면 하나의 리퀘스트 핸들러를 맹글어 놓고 맨 뒤에 URL 만 살짝 바꾸면 URL 에 따라 다른 View 를 이용해서 랜더링 시킬 수 있다.
예를 들어
http://127.0.0.1:8080/test/view 요럴땐 jsp 로 랜더링
http://127.0.0.1:8080/test/view.json 요럴땐 json 형식으로 랜더링
http://127.0.0.1:8080/test/view.jsonp 요럴땐 jsonp 형식으로 랜더링~
또 약간의 노력을 더해주면 xml 형식이나 rss 형식으로도 랜더링 시킬 수 있다.
죠런 기능을 구현하기 위해서 ContentNegotiatingViewResolver 를 사용하도록 설정해 주고 필요에 따라 AbstractView 클래스를 구현해서 원하는 View를 맹글면 된다.
스프링 설정파일
stove99.views.JSONPView 클래스 소스
컨트롤러 소스
테스트 결과 화면
그리고 JSONP 형식으로 같은 도메인이 아닌 다른 도메인으로 데이터를 제공하고 싶은 경우도 있다.
고럴때 ContentNegotiatingViewResolver 를 활용하면 하나의 리퀘스트 핸들러를 맹글어 놓고 맨 뒤에 URL 만 살짝 바꾸면 URL 에 따라 다른 View 를 이용해서 랜더링 시킬 수 있다.
예를 들어
http://127.0.0.1:8080/test/view 요럴땐 jsp 로 랜더링
http://127.0.0.1:8080/test/view.json 요럴땐 json 형식으로 랜더링
http://127.0.0.1:8080/test/view.jsonp 요럴땐 jsonp 형식으로 랜더링~
또 약간의 노력을 더해주면 xml 형식이나 rss 형식으로도 랜더링 시킬 수 있다.
죠런 기능을 구현하기 위해서 ContentNegotiatingViewResolver 를 사용하도록 설정해 주고 필요에 따라 AbstractView 클래스를 구현해서 원하는 View를 맹글면 된다.
스프링 설정파일
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> <!-- ViewResolver 우선순위 설정 --> <property name="order" value="1" /> <property name="mediaTypes"> <!-- 맵핑될 확장자 정의 --> <map> <entry key="json" value="application/json" /> <entry key="jsonp" value="javascript/jsonp" /> </map> </property> <property name="defaultViews"> <list> <!-- JSON 요청을 처리할 뷰 --> <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/> <!-- JSONP 요청을 처리할 뷰 --> <bean class="stove99.views.JSONPView"> <property name="contentType" value="javascript/jsonp"/> </bean> </list> </property> <property name="ignoreAcceptHeader" value="true" /> </bean> <!-- 맵핑되는 확장자가 없을때 JSP 로 뷰 처리 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="order" value="2" /> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean>mediaTypes에 정의된 entry 들은 URL 맨 뒤에 붙은 확장자와 mediaType 을 설정한다. 여기에서 설정된 mediaType 정보를 바탕으로 아래쪽 defaultViews 목록에 정의된 View 들 중에서 랜더링 가능한 View 를 찾아서 그 View 로 랜더링 시킨다. 뭐 설명이 허접하긴 하지만 내가 이해한 바로는 그렇다.
stove99.views.JSONPView 클래스 소스
package stove99.views; import java.io.Writer; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.codehaus.jackson.map.ObjectMapper; import org.springframework.web.servlet.view.AbstractView; public class JSONPView extends AbstractView{ @Override protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { String callback = request.getParameter("callback"); ObjectMapper om = new ObjectMapper(); String json = om.writeValueAsString(model); Writer out = response.getWriter(); out.append(callback).append("(").append(json).append(")"); } }
컨트롤러 소스
package stove99.controller; import java.util.HashMap; import java.util.Map; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/test/*") public class TestController { @RequestMapping public void view(ModelMap model) { Map<String, String> data = new HashMap<String, String>(); data.put("data1", "value1"); data.put("data2", "value2"); data.put("data3", "value3"); model.addAttribute("model", data); } }
테스트 결과 화면
ContentNegotiatingViewResolverTest.war
'Spring' 카테고리의 다른 글
Spring @ResponseBody 로 리턴시 한글이 깨질때 (0) | 2013.04.16 |
---|---|
<util:properties/> 와 Spring EL 로 값 가져오기 (0) | 2013.04.12 |
Spring 개발시 개발, 운영환경 프로퍼티 파일 관리하기 (1) | 2011.10.11 |
bean property 간단하게 설정하기 : http://www.springframework.org/schema/p 활용 (1) | 2011.08.22 |
<context:property-placeholder/> 를 사용할때 property file의 encoding 지정하기 (0) | 2011.08.03 |