'분류 전체보기'에 해당되는 글 2491건

  1. 2012.03.12 USB 메모리를 우분투 Live CD로 만들기 (초간단!)
  2. 2012.03.12 [spring/TIP] STS를 이용하여 순식간에 기본환경 구축하기
  3. 2012.03.12 [spring/TIP] Eclipse에서 maven을 이용하여 Spring MVC 기본환경 구축하기
  4. 2012.03.10 [node.js] 신기술이 뭔가 체험해 봤다 -_-
  5. 2012.03.10 Node.js란?
  6. 2012.03.10 Node.js란?
  7. 2012.03.10 Node.js v0.6.12 Manual & Documentation
  8. 2012.03.05 ibatis 다중 update 1
  9. 2012.02.13 [펌] 이클립스 + 톰캣 + 스프링 MVC + maven 개발환경 구축
  10. 2012.02.06 jreports.pdf
  11. 2012.02.06 JasperReports - Data Source Sample (version 4.5.0)
  12. 2012.02.06 Compile & Fill Jasper Report - XML datasource
  13. 2012.02.02 Creating Jasper subreports via iReport with multilple java beans 1
  14. 2012.02.01 eclispe jar 만들기 (외부 jar 포함)
  15. 2012.01.31 Simple을 사용하여 XML 직렬화하기
  16. 2012.01.31 XStream을 통해 XML 다루기
  17. 2012.01.27 초간단 xml 파싱
  18. 2012.01.27 jar 파일 생성 시 MANIFEST.MF 작성
  19. 2012.01.26 Serializing an object to XML
  20. 2012.01.26 자바 객체 <-> XML 변환
  21. 2012.01.26 JAXB를 활용한 Java 객체의 XML 자동 변환 1
  22. 2012.01.26 How to create XML file in Java – (JDOM Parser)
  23. 2012.01.26 How to modify XML file in Java – (JDOM Parser)
  24. 2012.01.26 How to read XML file in Java – (JDOM Parser)
  25. 2012.01.25 JavaBeans as datasource in JasperReports
  26. 2012.01.19 Manual for iReport
  27. 2012.01.19 Connections and Datasources
  28. 2012.01.19 iReport Download
  29. 2012.01.19 Jasper / IReport
  30. 2012.01.19 Jaspersoft iReport: How to pass a parameter to a sub-dataset
61.Linux2012. 3. 12. 16:16
반응형

예전엔 우분투(ubuntu) 같은 리눅스를 설치하려고 CD를 굽곤 했었는데요, 요즘엔 USB 부팅을 많이 지원하기 때문에 굳이 CD로 구울 필요가 없어졌습니다. "남는 USB 메모리를 우분투 Live CD로 만들기"입니다.

1.우분투 공식 사이트, 혹은 우분투 한국 사용자 모임(www.ubuntu.or.kr)에서 ISO 이미지를 내려받습니다.

2. Universal USB Installer 를 내려받아 실행합니다.

3. ISO 이미지 파일과 USB 드라이브 경로를 선택하고 create 를 누릅니다.


4. 침착하게 기다리면 끝!


이제 이 USB로 다른 PC에서 우분투 Live로 부팅해 우분투를 쓰거나 install 할 수 있습니다.

ps.
Universal USB Installer 대신 UNetbootin를 사용해도 동일합니다.


출처 : http://blog.doortts.com/
Posted by 1010
반응형

1. STS 다운로드
STS란?

SpringSource Tool Suite™ provides the best Eclipse-based development environment for building Spring-powered enterprise applications. STS supplies all the tools you need for developing with the latest enterprise Java, Spring, Groovy and Grails based technologies.

흠.. 쉽게말해 eclipse기반에 spring 코드작성에 커스터마이징된 IDE라고 생각하면 됨.

2. STS를 이용한 Project 생성
-ctrl+n -> Spring Template Project -> Spring MVC Project


Project name 작성 and top-level package명 작성 ( package명을 3단으로 작성해야 넘어간다.
ex> com.spring.app ) finish! 버튼 클릭



기본구조, tomcat에 붙여서 테스트하기 위해서 2개의 파일을 살짝 수정해야한다.


HomeController.java
노란색 부분을 "/test" 로 변경 (/일경우 동작하지를 않는데 이유아시는분??)



home.jsp
양키 기준이라 한글은 UTF-8로 인코딩해줘야 안깨진다. 노란색부분 추가


브라우져에서 URL을 입력하여 테스트


STS에 깔려있다는 가정하에 10분도 안되서 완료했으리라 생각됨!
이렇게 해서 Spring MVC 기본셋팅 끝

어때요? 참쉽죠?.. =ㅂ=안쉽다고요?..



출처 : http://beans9.tistory.com/99
Posted by 1010
반응형

환경정보

- eclipse indigo
- java1.6
- spring3.0
- tomcat7


1. project 생성


- group id는 도메인으로 입력(본인취향대로)
- artifact id는 프로젝트명


2. 프로젝트 생성후 프로젝트 properties > project facets 변경


- convert to faceted from 클릭

- Dynamic Web Module 체크
- 하단에 노란 박스 Further configuration available 클릭



- content directory 를 webapps로 변경
- Gernerate web.xml deployment descriptor 체크

- 모두 OK후에 webapps 폴더를 src/main/으로 이동

아래처럼 변경



3. 프로젝트 생성후 프로젝트 properties > Deployment Assembly 변경

- add 클릭하여 java build path Entries "Next" 후 maven 고르고 Finish


- 기존에 Deploy Path "/"를 Romove하고 새로 추가

- Folder 선택 후 src/main/webapps 로 선택하여 추가




- 모두 추가되어 완료된 모습.


4. 여기서부터 소스 추가 및 수정

src/main/webapps/WEB-INF/spring 폴더 추가
src/main/webapps/WEB-INF/spring/root-context.xml 파일생성

root-context.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

<!-- Root Context: defines shared resources visible to all other web components -->

</beans>


src/main/webapps/WEB-INF/spring/appServlet 폴더추가
src/main/webapps/WEB-INF/spring/appServlet/servlet-context.xml 파일생성

servlet-context.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans:beans xmlns="http://www.springframework.org/schema/mvc"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:beans="http://www.springframework.org/schema/beans"

xmlns:context="http://www.springframework.org/schema/context"

xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">


<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->

<!-- Enables the Spring MVC @Controller programming model -->

<annotation-driven />


<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->

<resources mapping="/resources/**" location="/resources/" />


<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->

<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">

<beans:property name="prefix" value="/WEB-INF/views/" />

<beans:property name="suffix" value=".jsp" />

</beans:bean>

<context:component-scan base-package="www.beans9.com" />

</beans:beans>

* 빨간글씨 부분은 본인 프로젝트 도메인 및 폴더명과 동일해야함.

src/main/webapps/WEB-INF/web.xml 파일 변경

web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"

id="WebApp_ID" version="3.0">

<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>/WEB-INF/spring/root-context.xml</param-value>

</context-param>

<!-- Creates the Spring Container shared by all Servlets and Filters -->

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>


<!-- Processes application requests -->

<servlet>

<servlet-name>appServlet</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<init-param>

<param-name>contextConfigLocation</param-name>

<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>

</init-param>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>appServlet</servlet-name>

<url-pattern>/</url-pattern>

</servlet-mapping>

</web-app>

* 경로가 써져있는부분이 실제 경로와 동일해야함

src/main/java/www/beans9/com/HomeController.java 파일생성

HomeController.java

package www.beans9.com;


import java.text.DateFormat;

import java.util.Date;

import java.util.Locale;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;


@Controller

public class HomeController {

private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

@RequestMapping(value = "/", method = RequestMethod.GET)

public String home(Locale locale, Model model) {

logger.info("Welcome home! the client locale is "+ locale.toString());

Date date = new Date();

DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

String formattedDate = dateFormat.format(date);

model.addAttribute("serverTime", formattedDate );

return "home";

}

}


src/main/webapps/WEB-INF/views 폴더 생성
src/main/webapps/WEB-INF/views/home.jsp 파일 생성

home.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"

pageEncoding="UTF-8"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Insert title here</title>

</head>

<body>

${serverTime }

</body>

</html>


자 이제 was를 기동시켜 Spring MVC가 제대로 동작하는지 확인



이상없이 출력된다면 ^^ 기본 환경 구축 완료.

해당 프로젝트 실제 파일경로들 /

혹 해당파일이 필요하신분들을 위해 프로젝트 Achiev파일을 올려놓으니^^ 사용하셔도 됩니다.


작성자 : beans9 (http://beans9.tistory.com)
다른곳에 기재하실경우 작성자표시를 꼭 해주시기 바랍니다.
Posted by 1010
98..Etc/node.js2012. 3. 10. 12:26
반응형

최근들어 node.js가 화제가 되고 있다. 계속 이어지고 있다고 해야되나. 새로운 관련 모듈이나 프레임웍이 나올 때 마다 찬양 일색이다. 도데체 뭐길래 그렇게 뜨고 있는 걸까.

딱히 할 일도 없고 해서 (- _ -) 한번 설치해서 뭔가를 돌려봤다.

설치


http://nodejs.org/

여기서 Download메뉴를 통해 타르볼을 받거나 저장소 소스를 긁어서 빌드하면 되는 듯. 공식사이트가 깔끔한게 너무 마음에 든다.

맥포트에 있나 싶어 검색해 봤더니 역시나 있다.
sudo port install nodejs

돌려보기


공식 홈페이지에 가장 첫 예제코드. 전통적으로 첫 코드 답게 Hello World를 찍어주는 서버를 만드는 코드다.
var http = require('http');
http.createServer(function (req, res) {
    res.writeHead(200, {'ContentType': 'text/plain'});
    res.end('Hello World\n');
}).listen(1337, "127.0.0.1");
console.log('Server running at 127.0.0.1:1337/');
실행도 시켜 보고...
node example.js
웹브라우저로 http://127.0.0.1:1337/ 로 접속해 보니 잘 돌아간다.
별 다른 프레임웍 없이 이 정도까지 간단하게 된다는 건 칭찬해 줄 만 하다.

그래서 뭐 대단한 거 있나?


node.js의 이름에서 .js라는 명칭은 javascript를 연상시키는 이름. 딱 맞다. 'V8 JavaScript 언어를 기반으로 만들어진 모듈 및 프레임웍 덩어리' 라는게 node.js를 설명하는 가장 간단한 용어 같다.

node.js가 뜬 이유는 웹 서버를 구축하는데 비동기(asynchronous) 구조를 가지게 하는게 가장 큰 특징이었는데, 알고보면 그다지 대단한게 아니다. 비동기 모델은 예전부터 이미 사용되고 있었다. (특히 POSIX의 select 시스템을 안다면 -_-). 세월이 흐르면서 코드 디자인 상으로 볼 때 동기(synchronous) 모델에 비해 코드가 직관적이지 않다는 단점이 있어서 오히려 멀티스레드를 이용한 동기화 모델이 크게 발달하게 되었는데... 이제는 비동기 모델을 띄워주고 있다.

node.js의 홈페이지 에서도 설명하고 있지만 비동기 모델이 가지는 장점은 코드의 가독성과는 전혀 딴판인 이야기다. 멀티스레드 혹은 멀티프로세스의 전통적인 서버 구조에 비해 비동기형 이벤트 기반의 시스템이 가지는 이점 말이다. 설명할 것도 없다. 빠르다는 것이지. 이벤트가 없으면 서버가 아예 sleep 상태가 되니 서버가 편해지겠구나. ;;

웹소켓이니 뭐니 일단 좋아보이는 기술을 사용할 수 있다는 것도 장점이긴 하겠지만 기존 request and receive 기반 구조와 차이가 있는건 아니니 아키텍쳐 면에서는 대단한 신기술은 전혀 발견할 수 없다.

그냥 JavaScript 언어 기반이라는게 뜨게 된 가장 큰 원인이 아닐까. 내 주관적으로 꼽자면, 비동기 모델을 아주 쉽고 간편하게 만들 수 있다는 게 가장 큰 의의인 것 같지만...


출처 : http://seorenn.blogspot.com/2011/05/nodejs.html
Posted by 1010
98..Etc/node.js2012. 3. 10. 12:23
반응형


IBM dW기사로 나온 node.js에 대한 기사입니다. 사실 훨씬더 일찍 나왔어야 하는 기사입니다. 왜냐하면 우리나라 분위기와는 달리 외국에서는 node.js에 대한 이야기가 훨씬 더 북적북적 많이 되고 있는 상황입니다. 2010년에 이어서 2011년에 주목해야 하는 기술을 뽑는다면 TOP3에 들어갈만한 기술일 겁니다.

구글 크롬은 구글에서 만든 브라우저라는 걸로 유명하지만, 그 내부적으로는 v8이라 불리는 고성능 자바스크립트 엔진의 출현이 더 많은 엔지니어들에게 충격을 줍니다. 나름 꽤 빠르다던 firefox 진형은 깜놀해서 자신의 엔진을 새롭게 개발하게 되었고, IE는 좀 더 심하게 조롱을 당하면서 마찬가지로 MS의 엔지니어들을 분발시켰습니다.

이와는 별개로 v8 javascript engine이 자바스크립트를 고속으로 해석해낸다는 점 + javascript의 functional language로써의 특징과 자바스크립트 고유의 이벤트 기반의 동작방식을 응용해서 서버프로그래밍 프레임워크가 나옵니다. 그게 바로 node.js입니다.

언제나 그렇듯 IBM 기사의 내용은 앞 부분이 훅~ 빠져있기때문에 잘 이해하기 위해서는 선행 학습이 필요합니다.

몇 가지 추천 링크를 적어보면 이렇습니다.

outsider님의 블로그 (한글이좋죠~ : )
node.js는 무엇인가? #1
node.js는 무엇인가? #2

node.js 공식사이트 (뭐든 공식사이트는 기본이죠~)
http://nodejs.org/

따라하기식으로 배우는 node.js 튜터리얼
http://dailyjs.com/tags.html#lmawa
굉장히 쉽게 잘 되어 있고 ,밑에 달린 코멘트들의 질답도 읽어볼만 합니다. 더불어 관련 프레임워크들도 배우게 됩니다.

사실 node.js가 뜨게 된데는 그 성능상의 놀라움 때문이 큰데요, 한때는 이벤트 기반의 non-blocking I/O 서버인 nginx와의 성능대결도 화제이곤 했습니다만, 지금은 node.js를 nginx와 mixin 해서 함께 사용하기도 하는군요.


효율을 높이기 위해 static 파일등의 front-end 처리와 proxy 기능은 nginx가 처리하고 애플리케이션 기능을 node.js가 처리하는 방식입니다. 이런 방식의 절대적인 효용에 대해서는 아직은 조금 더 지켜봐야 하는 것 같습니다만 다양한 시도는 좋은 것 같습니다. : )


출처 : http://blog.doortts.com/189
Posted by 1010
98..Etc/node.js2012. 3. 10. 12:22
반응형

소개

Node에 대해 들어본 적이 있거나 node가 얼마나 대단한지 주장하는 기사를 읽어본 적이 있다면 "대체 Node.js가 무엇인가?"라고 궁금해할 수 있다. Node의 자체 홈 페이지를 읽은 후에도 Node가 무엇인지에 대해 여전히 의문을 가질 수도 있다. Node는 분명히 모든 프로그래머에게 맞는 것은 아니지만, 일부에게는 올바른 선택이 될 수도 있다.

이 기사는 Node.js가 해결하는 문제의 간단한 배경지식을 제공하여 Node. js가 무엇이고 어떻게 작업하며 간단한 애플리케이션을 실행하는 방법과 마지막으로 어디에서 Node가 훌륭한 솔루션인지에 대해 응답을 찾을 것이다. 이 기사는 복잡한 Node 애플리케이션을 쓰는 방법을 다루거나 Node에 대한 완전한 튜토리얼이 되지는 않을 것이다. 독자가 이 기사를 읽으면 자체적인 비즈니스에서 Node 학습을 더 심도있게 추구해야 하는지 여부를 결정하는 데 도움이 될 것이다.


Node가 어떤 문제를 해결하는가?

Node의 명시된 최우선 순위의 목표는 "확장 가능한 네트워크 프로그램을 빌드하기 위해 간편한 방법을 제공하는 것"이다. 현재 서버 프로그램의 문제는 무엇인가? 계산을 해보자. Java™ 및 PHP와 같은 언어에서 각 연결은 이와 함께 잠재적으로 수반하는 2MB 메모리가 있는 새 스레드를 생성한다. 8GB RAM을 갖춘 시스템에서 동시적 연결의 이론적인 최대 숫자로 약 4000명의 사용자를 연결시킨다. 클라이언트 기반이 성장하면서, 더 많은 사용자를 지원하는 웹 애플리케이션을 원했다면 점점 더 서버를 추가해야 했다. 물론, 이는 비즈니스의 서버 비용, 트래픽 비용, 인건비 및 기타 등등에 더해진다. 이러한 비용을 더하는 것은 잠재적인 기술 문제이다 — 사용자는 각 요청에 대해 다른 서버를 사용할 수 있으므로, 어느 공유 자원이나 모든 서버에 걸쳐서 공유되어야 한다. 이러한 모든 이유로 인해, 전체 웹 애플리케이션 아키텍처(트래픽 처리량, 프로세서 속도 및 메모리 속도 포함)에서 병목은 서버가 처리할 수 있는 동시 연결의 최대 숫자였다.

Node는 연결이 서버로 설정되는 방법을 변경하여 이 문제를 해결한다. 각 연결에 대해 새 OS 스레드를 생성하는(그리고 이와 수반하는 메모리를 할당하고) 대신에 각 연결은 Node 엔진의 프로세스 내에서 이벤트 실행을 촉발한다. Node는 허용된 잠금이 없고 I/O 호출에 대해 직접 차단하지 않기 때문에 교착 상태가 절대 없다고 주장한다. Node는 수 만개의 동시 연결을 지원할 수 있는 서버 실행을 주장한다.

그러므로 수 만개의 동시 연결을 처리할 수 있는 프로그램이 있으므로 Node로 실제로 무엇을 빌드할 수 있는가? 이 많은 연결에 필요한 웹 애플리케이션이 있다면 멋질 것이다. 이는 "이 문제가 있다면 문제가 아니다" 종류의 문제 중 하나이다. 이를 다루기 전에 Node가 어떻게 작업하는지 그리고 실행하도록 어떻게 설계되는지에 대해 살펴보자.


Node가 절대 아닌 것

그렇다. Node는 서버 문제이다. 하지만, 기본 Node 제품은 Apache 또는 Tomcat과 절대 같지 않다. 이러한 서버는 기본적으로 설치 준비된(ready-to-install) 서버 제품이고 앱을 즉시 배치할 준비가 되었다. 이러한 제품으로 바로 서버를 켜고 실행할 수 있다. Node는 절대 이러한 것은 아니다. Apache가 개발자들이 동적 웹 페이지를 작성하도록 허용하기 위해 PHP 모듈을 추가하고 안전한 연결을 위해 SSL 모듈을 추가할 수 있는 방법과 마찬가지로 Node는 Node 핵심에도 추가될 수 있는 모듈의 개념이 있다. Node로부터 선택하는 모듈은 그야말로 수 백 가지가 있고, 커뮤니티는 매일 많은 모듈을 제작하고 게시하며 업데이트하는 데 매우 활동적이다. 이 기사의 이후 부분에서 Node의 전체 모듈 부분에 대해 논의할 것이다.


Node가 작동하는 방법

Node는 그 자체로 V8 JavaScript를 실행한다. 잠깐, 뭐라고 했는가? 서버에서 JavaScript란 말인가? 그렇다. 독자가 제대로 읽었다. 서버측 JavaScript는 클라이언트에서 JavaScript로 독점적으로 작업한 모든 사람들에게 새로운 개념이 될 수 있지만, 그 생각 자체는 너무 멀리에서 도입한 것은 아니다 — 서버에서 사용하는 클라이언트의 동일한 프로그래밍 언어를 왜 사용하지 않는가?

V8은 무엇인가? V8 JavaScript 엔진은 Google이 Chrome 브라우저로 사용하는 내재된 JavaScript 엔진이다. 적은 수의 사람들이 클라이언트에서 JavaScript로 실제로 무엇이 발생하는지에 대해 생각한다. JavaScript 엔진은 실제로 코드를 해석하고 실행한다. V8을 통해 Google은 또 다른 고유한 측면으로 C++로 쓰여진 초고속 해석기를 제작했다. 이 엔진을 다운로드하고 원하는 어느 애플리케이션에나 임베드할 수 있다. 이는 브라우저에서 실행하도록 제한되지 않는다. 그러므로, Node는 실제로 Google이 쓴 V8 JavaScript 엔진을 사용하고 서버에서 사용하도록 용도를 변경한다. 완벽하다! 이미 훌륭한 솔루션이 사용 가능할 때 새로운 언어를 작성할 이유는 없다.

이벤트 구동형 프로그래밍

많은 프로그래머들은 오브젝트 지향 프로그래밍이 완벽한 프로그래밍 설계라고 생각하고 다른 것을 사용하지 않도록 교육받았다. Node는 이벤트 구동형 프로그래밍 모델이라는 것을 활용한다.


목록 1. jQuery로 클라이언트측에서 이벤트 구동형 프로그래밍
				
// jQuery code on the client-side showing how Event-Driven programming works

// When a button is pressed, an Event occurs - deal with it
// directly right here in an anonymous function, where all the
// necessary variables are present and can be referenced directly
$("#myButton").click(function(){
     if ($("#myTextField").val() != $(this).val())
         alert("Field must match button text");
});

서버측은 실제로 클라이언트측과 다르지 않다. 사실이다. 눌러야 하는 단추도 없고 입력하는 텍스트 필드도 없지만, 더 상위 레벨에서 이벤트가 진행 중이다. 하나의 연결이 작성되었다 — 이벤트이다! 데이터가 연결을 통해 수신된다 — 이벤트이다! 데이터가 연결을 통해 오는 것이 중지된다 — 이벤트이다!

이러한 유형의 설정이 Node에 이상적인 이유는 무엇인가? JavaScript는 익명의 함수와 클로저를 허용하고, 그리고 더 중요하게도 구문이 코드를 해 본 적이 있는 거의 모든 사람에게 익숙하므로 이벤트 구동형 프로그래밍에 훌륭한 언어이다. 이벤트가 발생할 때 호출되는 콜백 함수는 이벤트를 캡처하는 동일한 지점에서 쓰여질 수 있다. 코드하기에 간편하고 유지보수하기에도 간편하다. 복잡한 오브젝트 지향 프레임워크가 없고, 인터페이스도 없으며, 과도한 아키텍팅(over-architecting)이 없다. 이벤트를 청취하고 콜백 함수를 쓰기만 하면 모든 것이 처리된다!


예제 Node 애플리케이션

마침내 일부 코드를 살펴보자! 논의한 모든 것들을 한데 묶어서 첫 번째 Node 애플리케이션을 작성해보자. Node가 높은 트래픽 애플리케이션을 처리하는 데 이상적이라는 것을 확인했으므로 최대 속도를 위해 제작된 매우 간단한 웹 애플리케이션을 작성해보자. "상사"로부터 아래로 전달된 샘플 애플리케이션에 대한 스펙이 여기 나와 있다. 무작위 숫자 생성기 RESTful API를 작성한다. 애플리케이션은 하나의 입력, "숫자"라는 하나의 매개변수를 취해야 한다. 그러면 해당 애플리케이션은 0과 이 매개변수 사이의 무작위 숫자를 리턴하고, 생성된 숫자를 호출자에게 리턴할 것이다. 그리고, "상사"가 엄청나게 인기 있는 애플리케이션이 되도록 기대하고 있으므로 이는 50000명의 동시 사용자를 처리해야 한다. 다음 코드를 살펴보자.


목록 2. Node 무작위 숫자 생성기
				
// these modules need to be imported in order to use them.
// Node has several modules.  They are like any #include
// or import statement in other languages
var http = require("http");
var url = require("url");

// The most important line in any Node file.  This function
// does the actual process of creating the server.  Technically,
// Node tells the underlying operating system that whenever a
// connection is made, this particular callback function should be
// executed.  Since we're creating a web service with REST API,
// we want an HTTP server, which requires the http variable
// we created in the lines above.
// Finally, you can see that the callback method receives a 'request'
// and 'response' object automatically.  This should be familiar
// to any PHP or Java programmer.
http.createServer(function(request, response) {

     // The response needs to handle all the headers, and the return codes
     // These types of things are handled automatically in server programs
     // like Apache and Tomcat, but Node requires everything to be done yourself
     response.writeHead(200, {"Content-Type": "text/plain"});

     // Here is some unique-looking code.  This is how Node retrives
     // parameters passed in from client requests.  The url module
     // handles all these functions.  The parse function
     // deconstructs the URL, and places the query key-values in the
     // query object.  We can find the value for the "number" key
     // by referencing it directly - the beauty of JavaScript.
     var params = url.parse(request.url, true).query;
     var input = params.number;

     // These are the generic JavaScript methods that will create
     // our random number that gets passed back to the caller
     var numInput = new Number(input);
     var numOutput = new Number(Math.random() * numInput).toFixed(0);
     
     // Write the random number to response
     response.write(numOutput);
     
     // Node requires us to explicitly end this connection.  This is because
     // Node allows you to keep a connection open and pass data back and forth,
     // though that advanced topic isn't discussed in this article.
     response.end();

   // When we create the server, we have to explicitly connect the HTTP server to
   // a port.  Standard HTTP port is 80, so we'll connect it to that one.
}).listen(80);

// Output a String to the console once the server starts up, letting us know everything
// starts up correctly
console.log("Random Number Generator Running...");

이 애플리케이션 시작하기

"random.js"라는 파일로 위의 코드를 넣는다. 이제 이 애플리케이션을 시작하여 실행하기 위해(그러므로 HTTP 서버를 작성하고 포트 80에서 연결을 청취함) 명령 프롬프트에서 다음 명령을 간단히 실행한다. % node random.js 서버를 시작하여 실행하는 중임을 인식할 때 다음과 같이 표시될 것이다.

root@ubuntu:/home/moila/ws/mike# node random.js
Random Number Generator Running...

이 애플리케이션에 액세스하기

애플리케이션이 시작되어 실행 중이다. Node가 현재 어느 연결이나 청취하고 있으므로 애플리케이션을 테스트해보자. 간단한 RESTful API를 작성했으므로, 웹 브라우저를 사용하여 애플리케이션에 액세스할 수 있다. 다음 주소를 입력하자(이전 단계를 완료하도록 한다). http://localhost/?number=27

브라우저 창이 0과 27사이의 무작위 숫자로 변경될 것이다. 브라우저에서 다시 로드하기를 누르면 또 다른 무작위 숫자가 나타날 것이다. 이렇게만 하면 된다. 첫 번째 Node 애플리케이션이 나왔다.


Node가 무엇에 유용한가?

자, Node에 대해 모두 읽고 나서 "Node란 무엇인가?"라는 질문에 응답할 수 있지만, "Node를 무엇에 대해 사용해야 하는가?"라는 의문을 가질 수 있다. Node가 정말로 유용한 것이 있기 때문에 이는 물어볼 만한 중요한 질문이다.

유용한 것

지금까지 살펴본 것처럼 Node는 대량의 트래픽과 서버측 논리를 예상하는 상황에 극도로 우수하게 설계되었고, 필요한 처리는 클라이언트에 응답하기 전에 반드시 규모가 클 필요는 없다. 여기에 Node가 탁월한 훌륭한 예제가 나와 있다.

  • RESTful API

    RESTful API를 제공하는 웹 서비스는 몇 가지 매개변수에서 취하고 이를 해석하여 응답과 함께 묶고 응답(대개 상대적으로 적은 양의 텍스트)을 사용자에게 다시 보낸다. 이는 Node에 이상적인 상황이다. 왜냐하면 이는 수 만개의 연결을 처리하도록 제작될 수 있기 때문이다. 이는 또한 대용량의 논리를 요구하지 않고, 기본적으로 데이터베이스로부터 값을 찾아 응답과 함께 종합한다. 응답이 소규모의 텍스트이므로, 수신 요청은 소규모의 텍스트이고, 트래픽 볼륨은 높지 않고, 하나의 머신이 가장 바쁜 회사의 API의 API 요청조차 처리할 가능성이 높다.

  • Twitter 큐

    트윗을 수신하고 데이터베이스로 이를 써야 하는 Twitter와 같은 회사에 대해 생각해 보자. 그야말로 초당 수 천개의 트윗이 들어오고 데이터베이스는 최대 사용 시간 동안 필요한 쓰기의 수를 거의 유지할 수 없다. Node는 이러한 문제점에 솔루션에서 중요한 구성요소가 된다. 확인한 대로 Node는 수 만개의 수신 트윗을 처리할 수 있다. 그러면 이는 인메모리 큐잉 메커니즘(예를 들어, memcached)으로 이를 빠르고 간편하게 쓸 수 있으며, 여기에서부터 또 다른 별도의 프로세스가 해당 데이터베이스로 이를 쓸 수 있다. 여기에서 Node의 역할은 트윗을 빠르게 수집하고 정보를 쓸 책임이 있는 다른 프로세스로 전달하는 것이다. 또 다른 설계를 상상해보자 — DB 자체로 쓰기를 처리하기 위해 노력하는 정상 PHP 서버 — 모든 트윗은 DB 호출이 차단되었으므로 DB에 쓰인 대로 약간의 지연이 발생할 것이다. 이러한 설계를 갖춘 머신은 데이터베이스 대기 시간으로 인해 초당 2000개의 수신 트윗만 처리할 수 있다. 초당 백 만개의 트윗이고 500개의 서버를 말하는 것이다. 그 대신에 Node는 모든 연결을 처리하고 차단하지 않아 이에 발생할 수 있는 가능한 많은 트윗을 캡처하기 위해 사용한다. 한 개의 노드 머신은 초당 50000개의 트윗을 처리할 수 있으며, 20개의 서버만 말하는 것이다.

  • 비디오 게임 통계

    Call of Duty 온라인과 같은 게임을 해본 적이 있다면, 게임 통계를 살펴볼 때 주로 통계의 레벨을 제작하기 위해 게임에 대해 엄청난 정보를 추적해야 한다는 생각이 즉시 떠오른다. 그러면 어느 시점에나 게임을 하는 수 백만의 사람들을 고려하면, 매우 빠르게 생성되는 수많은 정보가 있음을 깨닫는다. 게임으로부터 생성되는 데이터를 캡처할 수 있고, 이에 통합의 최소량을 수행한 다음에 데이터베이스로 쓰기 위해 이를 큐할 수 있기 때문에 Node는 이 시나리오에 대해 훌륭한 솔루션이다. 게임에서 사람들이 얼마나 많은 총알을 발사하는지 추적하는 데 전체 서버가 전념하는 것은 우스워 보일 수 있다. 이는 Apache와 같은 서버를 사용한 경우에 유용한 한계가 될 수 있지만 Node를 실행 중인 서버로 작업할 수 있는 것과 같이 게임에서부터 거의 모든 통계를 추적하는 데 하나의 서버가 전념할 수 있었다면 덜 우스워 보일 것이다.


Node 모듈

이 기사에서 원래는 계획된 논의가 아니었지만 대중적인 요청으로 인해 Node Modules과 Node Package Manager의 간략한 소개를 포함하도록 늘렸다. Apache로 작업하는 것에 익숙해지면서 성장한 사람들처럼 독자는 모듈을 설치하여 Node의 기능을 확장할 수 있다. 하지만, Node로 사용할 수 있는 모듈이 해당 제품을 엄청나게 향상시키기 때문에, 누구나 몇 가지 모듈을 설치하지 않고 Node를 사용할 가능성은 낮다. 이는 모듈이 전체 제품의 필수적인 부분이 되기까지 훌륭해진 이유이다.

참고자료에서 필자는 모듈 페이지로 링크를 제공하며, 여기에 모든 가능한 모듈이 나열되고 다운로드 가능하다. 기회를 빠르게 추출하기 위해 이는 사용 가능한 수많은 모듈 가운데 동적으로 작성된 페이지(PHP 등)를 쓰기 위한 모듈, MySQL로 간편하게 작업하기 위한 모듈, WebSockets를 돕기 위한 모듈 및 텍스트와 매개변수 구문 분석을 지원하기 위한 모듈을 포함한다. 필자는 모듈의 세부사항을 다루지 않을 것이다. 다시 말하지만, 이 기사는 Node를 심화하여 추구해야 할 만한 것인지 이해하는 데 도움을 주는 개요 기사에 불과하기 때문에, 독자가 이를 심도있게 알아보려고 선택하는 경우 당연히 사용 가능한 모듈로 작업해야 할 것이다.

추가적으로, Node는 Node Package Module을 갖추고 있으며, 이는 사용 중인 Node 모듈을 설치하고 관리하는 내장형 방식이다. 이는 자동으로 종속 항목을 처리하므로 설치하려는 어느 모듈이나 모든 필수 조각으로 제대로 설치하는 것이 보장될 수 있다. 자체적인 모듈에 관여하여 쓰려고 선택하는 경우 이는 Node 커뮤니티로 자체적인 모듈을 게시하는 방법으로서 역할을 담당한다. Node 설치를 중단하는 것에 대해 걱정하지 않고 Node의 기능을 간편하게 확장하는 방법으로서 NPM을 고려해보자. 다시 말하지만, Node를 심도있게 추구하기 위해 선택하는 경우 NPM은 Node 솔루션의 필수적 부분이 될 것이다.


결론

편집자의 참고

이 기사의 초기 발표된 버전으로 인해 이 기사가 표현한 다양한 관점에 대해 커뮤니티에서 많은 논의가 생성되었다. 그 이후로 작성자는 이러한 생각을 염두에 두고 이 기사를 개정했다. 이러한 종류의 동료 검토와 논의는 오프 소스 영역의 필수적인 부분이다. 건설적인 조언을 제공한 사람들한테 감사한다.

모든 오픈 소스 프로젝트와 마찬가지로 Node.js는 계속 진화할 것이고 개발자들은 한계의 숫자를 막론하고 이를 극복하기 위해 새로운 자원과 기술을 발견할 것이다. 언제나처럼 독자들이 스스로를 위해 기술을 시도해 보기 바란다.

"Node.js란?"이라는 이 기사의 초반부에서 독자가 가졌던 많은 의문들에 대해 이 기사를 읽은 후에 독자 스스로 모두 답할 수 있어야 한다. 독자는 Node.js가 무엇인지에 대해 몇 가지 분명하고 간결한 문장으로 설명할 수 있어야 한다. 그렇게 수행할 수 있다면, 거의 다른 모든 프로그래머들보다 앞서는 것이다. Node에 대해 필자와 대화했던 많은 사람들이 Node가 정확하게 수행하는 내용에 대해 혼란스러워했다. 당연히 이들은 Apache 사고방식을 가지고 있다 —서버가 HTML 파일을 놓는 애플리케이션이고 모두 작동한다는 것이다. 대부분의 프로그래머가 Apache와 Apache가 작업하는 것에 익숙하기 때문에, Node를 설명하는 가장 간편한 방법은 Apache와 비교하는 것이다. Node는 Apache가 할 수 있는 어느 작업이나 할 수 있는(일부 모듈을 사용하여) 프로그램이지만, 빌드할 수 있는 확장 가능한 JavaScript 플랫폼이 되어 훨씬 더 많은 작업을 할 수도 있다.

이 기사에서 Node가 고도로 확장 가능한 서버를 제공하는 목표를 달성하는 방법을 확인했다. 이는 Google, V8 엔진으로부터 엄청나게 빠른 JavaScript 엔진을 사용한다. 이는 코드를 최소화하고 읽기 간편하게 유지하도록 이벤트 구동형 설계를 사용한다. 이러한 모든 요인들로 인해 Node가 원하는 목표를 만들어낸다 — 이는 엄청나게 확장 가능한 솔루션을 쓰기에 상대적으로 간편하다.

Node가 무엇인지에 대해 이해하는 것이 중요한 것처럼 무엇이 아닌지에 대해 이해하는 것도 중요하다. Node는 즉시 PHP 웹 애플리케이션을 더 확장 가능하게 만들 Apache의 대체물에 불과하지 않다. 그것은 전혀 사실이 아니다. 지금은 Node의 수명 중에서 여전히 초기 단계이지만, 엄청나게 급격히 성장하고 있으며 해당 커뮤니티가 매우 적극적으로 관여하고, 작성되는 훌륭한 모듈이 매우 많고 이렇게 성장하는 제품은 독자의 비즈니스에 1년 내에 나타날 수 있다.


참고자료

교육

제품 및 기술 얻기

토론

필자소개

Mike Abernethy

In his 13 years in technology, Michael Abernethy has worked with a wide variety of technologies and a wide variety of clients. He currently works as a freelance programmer specializing in Java high availability and jQuery. His focus nowadays is on Rich Internet Applications and making them both more complex and simpler at the same time. When he's not working at his computer, he can be found on the golf course, or more accurately in the bushes, looking for his ball.

Posted by 1010
98..Etc/node.js2012. 3. 10. 12:18
반응형
Posted by 1010
54.iBATIS, MyBatis/iBatis2012. 3. 5. 19:51
반응형

DECLARE
    BEGIN
     UPDATE table_a SET 
            mdf_dt = SYSDATE
      WHERE  gds_ctf_no = #gds_ctf_no#
    ;
     UPDATE table_b SET 
            mdf_dt = SYSDATE
      WHERE  gds_ctf_no = #gds_ctf_no#
    ;
    END; 
Posted by 1010
반응형
이클립스 + 톰캣 + 스프링 MVC + maven 개발환경 구축 - 1장 - http://springmvc.egloos.com/429363
이클립스 + 톰캣 + 스프링 MVC + maven 개발환경 구축 - 2장 - http://springmvc.egloos.com/429570
이클립스 + 톰캣 + 스프링 MVC + maven 개발환경 구축 - 3장 - http://springmvc.egloos.com/429779
이클립스에서 SpringMVC 테스트(JUnit) 환경 구축하기 - http://springmvc.egloos.com/438345


출처 : http://springmvc.egloos.com/429363
Posted by 1010
53.jasper&ireport2012. 2. 6. 18:20
반응형

jreports.pdf


Posted by 1010
53.jasper&ireport2012. 2. 6. 18:16
반응형

JasperReports Ultimate Guide - Sample Reference - Schema Reference - Configuration Reference - API (Javadoc)

JasperReports - Data Source Sample (version 4.5.0)


Shows how custom or JavaBean-based data source implementations could be used to fill reports.

Download All Sample Source Files
Browse Sample Source Files on SVN


Main Features in This Sample

Data Sources

Custom Data Source

JavaBean Data Sources

TableModel Data Source


top

Data Sources Documented by Sanda Zaharia


Description / Goal
How to fill reports using data source objects.

Since
0.1.0

Other Samples
/demo/samples/csvdatasource
/demo/samples/xlsdatasource
/demo/samples/xmldatasource


Data Sources

Data sources are structured data containers used when filling generated reports. Compiled
JasperReport objects are now prepared to encapsulate their dynamic part of data within the generated report template.
The filling process relies on expression evaluations, variable calculations and successive iterations through the records of the supplied data source object. Every report section is filled step-by-step.
Usually, data are loaded into data source objects. The engine expects to receive either a
JRDataSource object as the data source of the report that it has to fill, or a java.sql.Connection when the report data is found in a relational database.
The
JRDataSource interface is very simple. Only two methods should implemented here:

public boolean next() throws JRException;
- called on the data source object by the reporting engine when iterating through the data at report-filling time
public Object getFieldValue(JRField jrField) throws JRException;
- provides the value for each report field in the current data source record
It is important to notice that the only way to retrieve data from the data source is by using the report fields. As a structured object, a data source object is more like a table with columns and rows containing data in the table cells. The rows of this table are the records through which the reporting engine iterates when filling the report and each column should be mapped to a report field, so that we can make use of the data source content in the report expressions. There are several default implementations of the JRDataSource interface, depending on the way the records in the data source are acquired.

Rewindable Data Sources

The JRRewindableDataSource is an extension of the JRDataSource interface, to which it adds the possibility of moving the record pointer back before the first virtual record. It adds only one method, called moveFirst(), to the interface.
Rewindable data sources are useful when working with subreports placed inside a band that is not allowed to split due to the isSplitAllowed="false" setting and there is not enough space on the current page for the subreport to be rendered.
All built-in data source implementations listed below are rewindable except for the JRResultSetDataSource, which does not support moving the record pointer back. This is a problem only if this data source is used to manually wrap a java.sql.ResultSet before passing it to the subreport. It is not a problem if the SQL query resides in the subreport template because the engine will reexecute it when restarting the subreport on the next page.

Data Source Implementations
JDBC data sources: the JRResultSetDataSource class
- Wraps a java.sql.ResultSet object. Represents the most commonly used data source implementations when report data are extracted from a relational database. If a java.sql.Connection is passed to the engine instead, it executes first the related query and stores the returned java.sql.ResultSet object in a JRResultSetDataSource instance.
JavaBean data sources: JRBeanArrayDataSource and JRBeanCollectionDataSource
- Represent implementations that can wrap collections or arrays of JavaBean objects. Each object inside the array or the collection will be seen as one record in this type of data source. The mapping between a particular JavaBean property and the corresponding report field is made by naming conventions. The name of the report field must be the same as the name of the JavaBean property as specified by the JavaBeans specifications.
Map-based data sources: JRMapArrayDataSource and JRMapCollectionDataSource
- These implementations are useful if the parent application already stores the reporting data available in-memory as java.util.Map objects. Each Map object in the wrapped array or collection is considered a virtual record in the data source, and the value of each report field is extracted from the map using the report field name as the key
TableModel data sources: the JRTableModelDataSource class
- Wraps a javax.swing.table.TableModel object. Columns in the wrapped TableModel object can be accessed either by their names or by their 0-based indexes.
XML data sources: the JRXmlDataSource class
- A data source implementation based on DOM, which uses XPath expressions to select data from the XML document. Records in the XML data source are represented by node elements selected through the XPath expression. Field values are retrieved from each record using the XPath expression provided by the field description (<fieldDescription> element in JRXML).
CSV data sources: the JRCsvDataSource class
- Represents an implementation for data sources which retrieve their data from structured text files, usually CSVs. Field values are retrieved using their column index.
XLS data sources: the JRXlsDataSource class
- Represents an implementation for data sources which retrieve their data from Excel documents (workbooks). Report-field mapping for this data source implementation is also based on the field column index.
Empty data sources: the JREmptyDataSource class
- Simulates a data source with a given number of virtual empty records inside. It is is used by the UI tools to offer basic report preview functionality, or in special report templates, or for testing and debugging purposes.
Data Source Providers

When creating a report template using GUI tools, a special tool for customizing the report's data source is needed. The JasperReports library comes with the JRDataSourceProvider interface that allows to create and dispose of data source objects. This is the standard way to plug custom data sources into a design tool.
A custom implementation of this interface should implement the following methods that allow creating and disposing of data source objects and also methods for listing the available report fields inside the data source if possible:
  • public boolean supportsGetFieldsOperation();
  • public JRField[] getFields(JasperReport report) throws JRException, UnsupportedOperationException;
  • public JRDataSource create(JasperReport report) throws JRException;
  • public void dispose(JRDataSource dataSource) throws JRException;

top

Custom Data Source Documented by Sanda Zaharia


Description / Goal
How to implement a custom data source from scratch.

Since
0.1.0


Custom Data Sources

The
datasource sample shows how to implement some of the data sources enumerated in the Data Source Implementations section. Using the same report template, it could be filled with data provided by any of these data sources, depending on the fill argument used with the ant command:
  • if the argument is fill1 then data will be extracted from the CustomDataSource object.
  • if the argument is fill2 then data will be extracted from the CustomTableModel object.
  • if the argument is fill3 then data will be extracted from the CustomBeanFactory object as JavaBean array.
  • if the argument is fill4 then data will be extracted from the CustomBeanFactory object as JavaBean Collection.
When the argument is fill1 the data source is created from scratch. It contains an array of Object arrays, representing records of data, and a record index:
 private Object[][] data =
  {
   {"Berne", new Integer(22), "Bill Ott", "250 - 20th Ave."},
   {"Berne", new Integer(9), "James Schneider", "277 Seventh Av."},
   {"Boston", new Integer(32), "Michael Ott", "339 College Av."},
   {"Boston", new Integer(23), "Julia Heiniger", "358 College Av."},
   {"Chicago", new Integer(39), "Mary Karsen", "202 College Av."},
   {"Chicago", new Integer(35), "George Karsen", "412 College Av."},
   {"Chicago", new Integer(11), "Julia White", "412 Upland Pl."},
   {"Dallas", new Integer(47), "Janet Fuller", "445 Upland Pl."},
   {"Dallas", new Integer(43), "Susanne Smith", "2 Upland Pl."},
   {"Dallas", new Integer(40), "Susanne Miller", "440 - 20th Ave."},
   {"Dallas", new Integer(36), "John Steel", "276 Upland Pl."},
   {"Dallas", new Integer(37), "Michael Clancy", "19 Seventh Av."},
   {"Dallas", new Integer(19), "Susanne Heiniger", "86 - 20th Ave."},
   {"Dallas", new Integer(10), "Anne Fuller", "135 Upland Pl."},
   {"Dallas", new Integer(4), "Sylvia Ringer", "365 College Av."},
   {"Dallas", new Integer(0), "Laura Steel", "429 Seventh Av."},
   {"Lyon", new Integer(38), "Andrew Heiniger", "347 College Av."},
   {"Lyon", new Integer(28), "Susanne White", "74 - 20th Ave."},
   {"Lyon", new Integer(17), "Laura Ott", "443 Seventh Av."},
   {"Lyon", new Integer(2), "Anne Miller", "20 Upland Pl."},
   {"New York", new Integer(46), "Andrew May", "172 Seventh Av."},
   {"New York", new Integer(44), "Sylvia Ott", "361 College Av."},
   {"New York", new Integer(41), "Bill King", "546 College Av."},
   {"Oslo", new Integer(45), "Janet May", "396 Seventh Av."},
   {"Oslo", new Integer(42), "Robert Ott", "503 Seventh Av."},
   {"Paris", new Integer(25), "Sylvia Steel", "269 College Av."},
   {"Paris", new Integer(18), "Sylvia Fuller", "158 - 20th Ave."},
   {"Paris", new Integer(5), "Laura Miller", "294 Seventh Av."},
   {"San Francisco", new Integer(48), "Robert White", "549 Seventh Av."},
   {"San Francisco", new Integer(7), "James Peterson", "231 Upland Pl."}
  };
  
  private int index = -1;
The next() and getFieldValue(JRField) are implemented in order to make possible iteration through data records and field values retrieving for a given record. Field names are assumed to be: the_city, id, name and street, in this order (see the /src/CustomDataSource.java source file).
 public boolean next() throws JRException
 {
  index++;
  return (index < data.length);
 }

 public Object getFieldValue(JRField field) throws JRException
 {
  Object value = null;
  String fieldName = field.getName();

  if ("the_city".equals(fieldName))
  {
   value = data[index][0];
  }
  else if ("id".equals(fieldName))
  {
   value = data[index][1];
  }
  else if ("name".equals(fieldName))
  {
   value = data[index][2];
  }
  else if ("street".equals(fieldName))
  {
   value = data[index][3];
  }

  return value;
 }
At fill time a CustomDataSource object is passed as argument to the fillReportToFile() method in the JasperFillManager class (see the the /src/DataSourceApp.java file): Let's take a look at related methods in the /src/DataSourceApp.java file:
 public void fill1() throws JRException
 {
  long start = System.currentTimeMillis();
  //Preparing parameters
  Map parameters = new HashMap();
  parameters.put("ReportTitle", "Address Report");
  parameters.put("DataFile", "CustomDataSource.java");

  JasperFillManager.fillReportToFile("build/reports/DataSourceReport.jasper", 
    parameters, new CustomDataSource());
  System.err.println("Filling time : " + (System.currentTimeMillis() - start));
 }
In order to figure out more on custom data sources behavior, just test this sample by running from the command line the ant clean javac compile fill1 view command. It will generate the sample report in the /build/reports directory, filling it with data extracted from the CustomDataSource object.

top

JavaBean Data Sources Documented by Sanda Zaharia


Description / Goal
How to fill reports with collections or arrays of JavaBean objects.

Since
0.1.0


JavaBean Data Sources

There are two data source implementations that can wrap collections or arrays of JavaBean objects. Both implementations rely on Java reflection to retrieve report field data from the JavaBean objects wrapped inside the data sources. These data sources can be used to generate reports using data already available in-memory in the form of EJBs, Hibernate, JDO objects, or even POJOs.
The
JRBeanArrayDataSource is for wrapping an array of JavaBean objects to use for filling a report with data, and the JRBeanCollectionDataSource is for wrapping a collection of JavaBeans. Each object inside the array or the collection will be seen as one record in this type of data source.
The mapping between a particular JavaBean property and the corresponding report field is made by naming conventions. The name of the report field must be the same as the name of the JavaBean property as specified by the JavaBeans specifications. For instance, to retrieve the value of a report field named
address, the program will try to call through reflection a method called getAddress() on the current JavaBean object.
Nested JavaBeans properties can be also accessed in a JavaBean data source. For example, if the current JavaBean object inside the data source is of type
Product and contains nested supplier information accessible by calling the getSupplier() method, which returns a Supplier object. In this case, to access the address property inside the Supplier object, a report field named supplier.address is required.
For backward-compatibility reasons, the current implementations still look into the field’s description first, to locate the the JavaBean property. If there is no description, then the report field name is used instead. If this default behavior is not desirable, especially if the field description is already used for other purposes, you can use special data source constructors that receive a flag called
isUseFieldDescription to suppress this behavior.
A special field mapping can be used to access the current JavaBean object itself. Thus, when a field uses
_THIS as description or name, the data source will return the current JavaBean object as field value.

JavaBean Data Sources Example

In our concrete example a factory class is used to provide JavaBean data sources either as JavaBean arrays or as JavaBean collections. The JavaBean is defined in the /src/CustomBean.java file. It contains 4 accessible properties, and a supplementary
getMe() method which returns a reference to the object itself:
public class CustomBean
{
 private String city;
 private Integer id;
 private String name;
 private String street;

 public CustomBean(
  String pcity,
  Integer pid,
  String pname,
  String pstreet
  )
 {
  city = pcity;
  id = pid;
  name = pname;
  street = pstreet;
 }

 public CustomBean getMe()
 {
  return this;
 }

 public String getCity()
 {
  return city;
 }

 public Integer getId()
 {
  return id;
 }

 public String getName()
 {
  return name;
 }

 public String getStreet()
 {
  return street;
 }
}
Note that one of the CustomBean properties is named city. In the report template there is no corresponding field named city. A field named the_city exists instead. In this case, the field mapping is done through the <fieldDescription/> as described in the JavaBean Data Sources section. The CustomBean object is reffered to as me, with the associated getter getMe() method:

<field name="the_city" class="java.lang.String">
<fieldDescription><![CDATA[me.city]]></fieldDescription>
</field>


The factory class is defined in the /src/CustomBeanFactory.java file. It contains an array of CustomBean objects and two getter methods:
public class CustomBeanFactory
{
 private static CustomBean[] data =
  {
   new CustomBean("Berne", new Integer(9), "James Schneider", "277 Seventh Av."),
   new CustomBean("Berne", new Integer(22), "Bill Ott", "250 - 20th Ave."),
   new CustomBean("Boston", new Integer(23), "Julia Heiniger", "358 College Av."),
   new CustomBean("Boston", new Integer(32), "Michael Ott", "339 College Av."),
   new CustomBean("Chicago", new Integer(39), "Mary Karsen", "202 College Av."),
   new CustomBean("Chicago", new Integer(35), "George Karsen", "412 College Av."),
   new CustomBean("Chicago", new Integer(11), "Julia White", "412 Upland Pl."),
   new CustomBean("Dallas", new Integer(47), "Janet Fuller", "445 Upland Pl."),
   new CustomBean("Dallas", new Integer(43), "Susanne Smith", "2 Upland Pl."),
   new CustomBean("Dallas", new Integer(40), "Susanne Miller", "440 - 20th Ave."),
   new CustomBean("Dallas", new Integer(36), "John Steel", "276 Upland Pl."),
   new CustomBean("Dallas", new Integer(37), "Michael Clancy", "19 Seventh Av."),
   new CustomBean("Dallas", new Integer(19), "Susanne Heiniger", "86 - 20th Ave."),
   new CustomBean("Dallas", new Integer(10), "Anne Fuller", "135 Upland Pl."),
   new CustomBean("Dallas", new Integer(4), "Sylvia Ringer", "365 College Av."),
   new CustomBean("Dallas", new Integer(0), "Laura Steel", "429 Seventh Av."),
   new CustomBean("Lyon", new Integer(38), "Andrew Heiniger", "347 College Av."),
   new CustomBean("Lyon", new Integer(28), "Susanne White", "74 - 20th Ave."),
   new CustomBean("Lyon", new Integer(17), "Laura Ott", "443 Seventh Av."),
   new CustomBean("Lyon", new Integer(2), "Anne Miller", "20 Upland Pl."),
   new CustomBean("New York", new Integer(46), "Andrew May", "172 Seventh Av."),
   new CustomBean("New York", new Integer(44), "Sylvia Ott", "361 College Av."),
   new CustomBean("New York", new Integer(41), "Bill King", "546 College Av."),
   new CustomBean("Oslo", new Integer(45), "Janet May", "396 Seventh Av."),
   new CustomBean("Oslo", new Integer(42), "Robert Ott", "503 Seventh Av."),
   new CustomBean("Paris", new Integer(25), "Sylvia Steel", "269 College Av."),
   new CustomBean("Paris", new Integer(18), "Sylvia Fuller", "158 - 20th Ave."),
   new CustomBean("Paris", new Integer(5), "Laura Miller", "294 Seventh Av."),
   new CustomBean("San Francisco", new Integer(48), "Robert White", "549 Seventh Av."),
   new CustomBean("San Francisco", new Integer(7), "James Peterson", "231 Upland Pl.")
  };  
		
 public static Object[] getBeanArray()
 {
  return data;
 }

 public static Collection getBeanCollection()
 {
  return Arrays.asList(data);
 }
}
Using the same report template, it could be filled with data provided either as CustomBean array or as CustomBean Collection, depending on the fill argument used with the ant command:
  • if the argument is fill3 then data will be extracted as JavaBean array, using the getBeanArray() method. At fill time, a JRBeanArrayDataSource object is passed as argument to the fillReportToFile() method in the JasperFillManager class.
  • if the argument is fill4 then data will be extracted as JavaBean Collection (java.util.List), using the getBeanCollection() method. At fill time, a JRBeanCollectionDataSource object is passed as argument to the fillReportToFile() method in the JasperFillManager class.
Let's take a look at related report filling methods in the /src/DataSourceApp.java file:
 public void fill3() throws JRException
 {
  long start = System.currentTimeMillis();
  //Preparing parameters
  Map parameters = new HashMap();
  parameters.put("ReportTitle", "Address Report");
  parameters.put("DataFile", "CustomBeanFactory.java - Bean Array");

  JasperFillManager.fillReportToFile("build/reports/DataSourceReport.jasper", 
    parameters, new JRBeanArrayDataSource(CustomBeanFactory.getBeanArray()));
  System.err.println("Filling time : " + (System.currentTimeMillis() - start));
 }

 public void fill4() throws JRException
 {
  long start = System.currentTimeMillis();
  //Preparing parameters
  Map parameters = new HashMap();
  parameters.put("ReportTitle", "Address Report");
  parameters.put("DataFile", "CustomBeanFactory.java - Bean Collection");

  JasperFillManager.fillReportToFile("build/reports/DataSourceReport.jasper", 
    parameters, new JRBeanCollectionDataSource(CustomBeanFactory.getBeanCollection()));
  System.err.println("Filling time : " + (System.currentTimeMillis() - start));
 }
In order to figure out more on JavaBean data sources behavior, just test this sample by running from the command line the ant clean javac compile fill3 view command and then ant clean javac compile fill4 view. It will generate the sample report filling it with data extracted from a JRBeanArrayDataSource data source, and then the same report will be generated with data extracted from a JRBeanCollectionDataSource data source.

top

TableModel Data Source Documented by Sanda Zaharia


Description / Goal
How to wrap a custom TableModel implementation into a report data source.

Since
0.3.3


TableModel Data Sources

In some Swing-based desktop client applications, the reporting data might already be available in the form of a
javax.swing.table.TableModel implementation used for rendering javax.swing.JTable components on various forms. JasperReports can generate reports using this kind of data if a given TableModel object is wrapped in a JRTableModelDataSource instance before being passed as the data source for the report-filling process.
There are two ways to use this type of data source. Normally, to retrieve data from it, one must declare a report field for each column in the
TableModel object bearing the same name as the column it maps. Sometimes it is not possible or desirable to use the column name, however, because the report field name and columns could still be bound to report fields using their zero-based index instead of their names.
For instance, if is known that a particular column is the third column in the table model object (index=2), then one could name the corresponding field "COLUMN_2" and use the column data without problems.
An example of
TableModel data source implementation is provided in the following section.

TableModel Data Source Example

In our example the
TableModel data source is implemented in the /src/CustomTableModel.java file. It contains an array of column names and an array of Object arrays, representing records of data in the data source. Column names are identical to their related field names in the report template: the_city, id, name and street. Methods required by the javax.swing.table.AbstractTableModel parent class are also implemented.
 public class CustomTableModel extends AbstractTableModel
 {
  private String[] columnNames = {"the_city", "id", "name", "street"};

  private Object[][] data =
  {
   {"Berne", new Integer(22), "Bill Ott", "250 - 20th Ave."},
   {"Berne", new Integer(9), "James Schneider", "277 Seventh Av."},
   {"Boston", new Integer(32), "Michael Ott", "339 College Av."},
   {"Boston", new Integer(23), "Julia Heiniger", "358 College Av."},
   {"Chicago", new Integer(39), "Mary Karsen", "202 College Av."},
   {"Chicago", new Integer(35), "George Karsen", "412 College Av."},
   {"Chicago", new Integer(11), "Julia White", "412 Upland Pl."},
   {"Dallas", new Integer(47), "Janet Fuller", "445 Upland Pl."},
   {"Dallas", new Integer(43), "Susanne Smith", "2 Upland Pl."},
   {"Dallas", new Integer(40), "Susanne Miller", "440 - 20th Ave."},
   {"Dallas", new Integer(36), "John Steel", "276 Upland Pl."},
   {"Dallas", new Integer(37), "Michael Clancy", "19 Seventh Av."},
   {"Dallas", new Integer(19), "Susanne Heiniger", "86 - 20th Ave."},
   {"Dallas", new Integer(10), "Anne Fuller", "135 Upland Pl."},
   {"Dallas", new Integer(4), "Sylvia Ringer", "365 College Av."},
   {"Dallas", new Integer(0), "Laura Steel", "429 Seventh Av."},
   {"Lyon", new Integer(38), "Andrew Heiniger", "347 College Av."},
   {"Lyon", new Integer(28), "Susanne White", "74 - 20th Ave."},
   {"Lyon", new Integer(17), "Laura Ott", "443 Seventh Av."},
   {"Lyon", new Integer(2), "Anne Miller", "20 Upland Pl."},
   {"New York", new Integer(46), "Andrew May", "172 Seventh Av."},
   {"New York", new Integer(44), "Sylvia Ott", "361 College Av."},
   {"New York", new Integer(41), "Bill King", "546 College Av."},
   {"Oslo", new Integer(45), "Janet May", "396 Seventh Av."},
   {"Oslo", new Integer(42), "Robert Ott", "503 Seventh Av."},
   {"Paris", new Integer(25), "Sylvia Steel", "269 College Av."},
   {"Paris", new Integer(18), "Sylvia Fuller", "158 - 20th Ave."},
   {"Paris", new Integer(5), "Laura Miller", "294 Seventh Av."},
   {"San Francisco", new Integer(48), "Robert White", "549 Seventh Av."},
   {"San Francisco", new Integer(7), "James Peterson", "231 Upland Pl."}
  };

  public CustomTableModel()
  {
  }

  public int getColumnCount()
  {
   return this.columnNames.length;
  }

  public String getColumnName(int columnIndex)
  {
   return this.columnNames[columnIndex];
  }

  public int getRowCount()
  {
   return this.data.length;
  }

  public Object getValueAt(int rowIndex, int columnIndex)
  {
   return this.data[rowIndex][columnIndex];
  }
 }
When the ant command is used with the fill2 argument, at fill time a JRTableModelDataSource object is passed as argument to the fillReportToFile() method in the JasperFillManager class (see the /src/DataSourceApp.java file):
 public void fill2() throws JRException
 {
  long start = System.currentTimeMillis();
  //Preparing parameters
  Map parameters = new HashMap();
  parameters.put("ReportTitle", "Address Report");
  parameters.put("DataFile", "CustomTableModel.java");

  JasperFillManager.fillReportToFile("build/reports/DataSourceReport.jasper", 
    parameters, new JRTableModelDataSource(new CustomTableModel()));
  System.err.println("Filling time : " + (System.currentTimeMillis() - start));
 }
Running the Sample

Running the sample requires the Apache Ant library. Make sure that ant is already installed on your system (version 1.5 or later).
In a command prompt/terminal window set the current folder to demo/samples/datasource within the JasperReports source project and run the > ant test view command.
It will generate all supported document types containing the sample report in the demo/samples/datasource/build/reports directory.
Then the report will open in the JasperReports internal viewer.



© 2001-2010 Jaspersoft Corporation www.jaspersoft.com
Posted by 1010
53.jasper&ireport2012. 2. 6. 18:10
반응형

public static void main(String[] args) {
        Map map = new RenderReportBean().execute("northwind", "OrdersReport");
 
    }
 
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public Map execute(String sourceFileId, String templateId, Integer[] formats) {
        Map params = new HashMap();
        Document document;
        Map<Integer, Boolean> renderedSuccessList = new HashMap<Integer, Boolean>();
        try {
 
            document = JRXmlUtils.parse(JRLoader.getLocationInputStream(sourceFileId + ".xml"));
 
            params.put(JRXPathQueryExecuterFactory.PARAMETER_XML_DATA_DOCUMENT, document);
            params.put(JRXPathQueryExecuterFactory.XML_DATE_PATTERN, "yyyy-MM-dd");
            params.put(JRXPathQueryExecuterFactory.XML_NUMBER_PATTERN, "#,##0.##");
            params.put(JRXPathQueryExecuterFactory.XML_LOCALE, Locale.ENGLISH);
            params.put(JRParameter.REPORT_LOCALE, Locale.US);
 
            JasperCompileManager.compileReportToFile(templateId + ".jrxml", templateId + ".jasper");
 
            JasperFillManager.fillReportToFile(templateId + ".jasper", params);
 
            JasperExportManager.exportReportToPdfFile(templateId + ".jrprint", sourceFileId + ".pdf");
 
 
        } catch (Exception e) {
            e.printStackTrace();
            return renderedSuccessList;
        }
        return renderedSuccessList;
    }
Posted by 1010
53.jasper&ireport2012. 2. 2. 14:16
반응형

Simple Guide To Sub-reports in JasperReports / iReport

Reporting tools… why is it so hard??

It seems like it’s practically a requirement that all business reporting tools be difficult to learn, use and work with. JasperReports / iReport is no different. Don’t get me wrong it’s a good solution to a certain kind of problem (and it’s free and open source which doesn’t hurt), but the iReport UI is (and I’ll try to be kind) utilitarian at best.

Anyhow, to do any non-trivial report with iReport, you’ll probably need to use sub-reports, which are not very clearly documented as to how the hell they work.

I’ll be talking strictly about Java-bean collection data sources for this article, so you will need to translate if you are doing direct SQL queries or something else.

The Java-bean data source is nice because we can utilise our existing domain layer in order to create our report, rather than replicating the same logistics in SQL (or worse – stored procedures) and thereby having two places to update when requirements change.

To easily understand how sub-reports work, we need to understand how JasperReports works in general.

JasperReports are stored in XML files (JRXML) – if you’ve created any report you’d be familiar with these files. These XML files are translated to Java source code by JasperReports, and then compiled into regular Java CLASS files, which are executable by the Jasper engine. You could say that Jasper compiles the JRXML files into Java, and then Java will compile these into byte code.

When you execute a report you are essentially executing Java code. Keep this in mind when filling out expression fields in your report, and things will start to make more sense.

Generally you use a sub-report in a situation where you have a two or more child lists of data relating to a single parent element. A common use case would be a report with multiple details bands of different types. I say “different types”, because if you have nested children that relate to the same data set, then generally you can achieve formatting using groups with breaking on certain fields in the data set. Things get complicated though where you have one big report, which has multiple unrelated data sets inside it.

To avoid getting too meta – here’s a concrete example…

This report has a single main detail band (contact details – first and last names) and two sub-detail bands for each contact – addresses and phone numbers.

In Jasper we need to use two sub-reports to implement this. But before we get too far, let’s look at how we would create Javabeans to store this data.

The addresses:

package com.visural.report;

public class AddressBean {

private String type;
private String address;

public String getAddress() {
return address;
}

public void setAddress(String address) {
this.address = address;
}

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}
}

The phone numbers:

package com.visural.report;

public class PhoneBean {

private String type;
private String number;

public String getNumber() {
return number;
}

public void setNumber(String number) {
this.number = number;
}

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}
}

And the contact (parent) bean:

package com.visural.report;

import java.util.List;

public class ContactBean {

private String firstName;
private String lastName;
private List addresses;
private List phones;

public List getAddresses() {
return addresses;
}

public void setAddresses(List addresses) {
this.addresses = addresses;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public List getPhones() {
return phones;
}

public void setPhones(List phones) {
this.phones = phones;
}
}

Finally, we need a test data source to use in developing our report. Here’s the factory for the report pictured earlier…

package com.visural.report;

import java.util.Arrays;
import java.util.List;

public class ContactFactory {

public static List create() {
ContactBean stub = new ContactBean();
stub
.setFirstName("John");
stub
.setLastName("Smith");

AddressBean address1 = new AddressBean();
address1
.setType("Home");
address1
.setAddress("123 Fake St\nFaketown\nFK 12345");
AddressBean address2 = new AddressBean();
address2
.setType("Work");
address2
.setAddress("321 Bogus St\nFaketown\nFK 12345");
stub
.setAddresses(Arrays.asList(address1, address2));

PhoneBean phone1 = new PhoneBean();
phone1
.setType("Home");
phone1
.setNumber("03 9876 1234");
PhoneBean phone2 = new PhoneBean();
phone2
.setType("Work");
phone2
.setNumber("03 1234 9876");
PhoneBean phone3 = new PhoneBean();
phone3
.setType("Mobile");
phone3
.setNumber("0432 123 456");
stub
.setPhones(Arrays.asList(phone1, phone2, phone3));

return Arrays.asList(stub);
}
}

The thing to notice here is that we have modelled the Javabeans exactly as we would if they were being used for some other purpose, i.e. we haven’t done anything special to make them usable in JasperReports / iReport.

In Jasper we configure a Javabeans data source that is created from a Collection, using our ContactFactory.create() method. We then add fields as follows, and create our report layout:

Note that the field names correspond to the Javabean property names.

Now for the important part. We then need to set the data source on the sub-report’s properties:

So we can just use an “data source expression” as our connection for the sub-report, and for the expression we create a data source on the fly using our collection of java beans from our current data source’s “addresses” and “phones” fields. “new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource(datasource.getPhones())” is the Java code we would write if we were to create a Javabean data source in our regular Java code. JasperReports will replace $F{phones} with “datasource.getPhones()” (or its equivalent) as part of it’s JRXML to Java compilation process.

The rest is simple; our sub-reports define fields that match the AddressBean and PhoneBean properties:

With all that in mind, it really is a case of “it’s simple when you know how”, but be that as it may, I couldn’t find a concise description of how to do this in my googling. Hopefully this post will fill that gap. Perhaps everyone is still writing SQL-based reports against a single database? :) I don’t know, but using Javabeans is a nice flexible alternative to use SQL-based reports that gives you a lot of options in the long term.

If you’re still confused you can download the above code, and the JRXML reports in a Netbeans 6 project here.

Also, try one of these books. Jasper & iReport’s documentation is pretty thin online, so having a reference book can be handy –

Posted by 1010
반응형
JAVA는 컴파일된 클래스들을 JAR로 묶어서 배포할 수 있게 하고 있다. cmd에서 java 명령어를 통해서도 JAR를 만들 수 있지만 이클립스에서도 JAR를 만들 수 있다.



프로젝트를 JAR로 export하는 방법

  1. File -> Export 에서 JAVA -> JAR file을 선택

  2. 왼쪽 창에서 JAR로 만들 프로젝트를 선택

  3. 중간의 JAR file: 에서 JAR 의 이름과 위치를 선택

  4. next, next 후 아래의 Main class:에서 JAR를 실행시 호출할 메인 클래스를 지정한다.

  5. finish를 누르면 앞에서 지정한 위치에 JAR 파일이 생성된다.



배포하는 쪽의 라이브러리 환경과 실행할 쪽의 라이브러리 환경이 같은 경우만 위 방법을 사용할 수 있다.
만약 외부 라이브러리 JAR파일등을 eclipse에서 추가해서 프로그램을 작성하고 위 방법으로 JAR를 만들면 외부 라이브러리는 새로 만든 JAR 파일에 포함되지 않는다.

따라서 배포를 한 후, 실행하는 환경에서 해당 외부라이브러리가 설치되지 않았다면 실행할 수 없다.
이 경우 내가 사용한 라이브러리들을 JAR에 포함시켜야 한다.

eclipse에서 외부 라이브러리를 포함한 JAR파일 생성은 아래를 참고.
외부 라이브러리를 포함한 JAR파일 만들기



JAR를 실행하는 방법은 아래를 참고.

JAR 실행방법

[펌]http://veenvalu.tistory.com/1


Posted by 1010
반응형

Simple이란?

Simple은 XML의 직렬화 및 역직렬화 프로세스를 단순화하는 데 사용되는 Java 프레임워크이다. 이름에서 알 수 있듯이 Simple을 사용하는 개발자는 POJO(plain old Java object)를 XML 문서로 변환하는 직렬화 프로세스를 단순화할 수 있다. Simple은 그 반대의 기능도 제공한다. 즉, XML 문서를 POJO로 변환할 수 있으며 이 프로세스를 역직렬화라고 한다.

Simple은 그 이름에 걸맞게 어노테이션을 사용하여 직렬화 또는 역직렬화 프로세스를 수행한다. POJO는 해당 XML 문서의 표시 방법에 따라 어노테이트된다. 일부 필드는 속성으로 어노테이트되고 다른 필드는 요소로 어노테이트된다. 클래스는 일반적으로 루트 요소로 어노테이트된다. 직렬화 프로세스 동안 어노테이션을 해석하고 해당 XML 문서를 생성하는 지루한 프로세스는 프레임워크에 의해 자동으로 처리된다. 또한 어노테이션은 XML 문서가 POJO로 변환되는 역직렬화 프로세스 동안에도 해석된다.

Simple을 사용하면 여러 가지 장점을 얻을 수 있다. 첫 번째 장점은 애플리케이션을 빠르게 개발할 수 있다는 것이다. Simple은 매우 단순하므로 과도한 학습 곡선 또는 개발 오버헤드 없이도 XML 직렬화 및 역직렬화를 사용하는 강력한 애플리케이션을 빠르게 구현할 수 있다.

Simple의 다음 장점은 구성이 필요하지 않다는 것이다. 앞에서 언급한 대로 Simple은 어노테이션을 사용한다. 이러한 어노테이션은 일반적으로 이러한 특성을 가진 프레임워크에 사용되는 XML 기반 구성 파일 대신 사용된다.

마지막으로 Simple을 사용하는 애플리케이션의 풋프린트에 최소한의 공간만 추가된다는 장점이 있다. 즉, 239KB에 불과한 JAR(Java Archive) 파일만 추가된다. 또한 Simple은 다른 프레임워크와 마찬가지로 다른 JAR 파일을 사용하지 않는다.

Simple 다운로드하기

Simple을 사용하려면 먼저 참고자료에 나열되어 있는 Simple 웹 사이트로 이동하여 아카이브를 다운로드해야 한다. 하지만 이 프로세스와 관련하여 좋은 소식과 나쁜 소식이 있다. 좋은 소식은 아카이브라 무료라는 것이고 나쁜 소식은 아카이브가 .tar.gz 형식이라는 것이다. 따라서 Microsoft® Windows® 기본 아카이브 추출기로는 이 아카이브를 열 수가 없기 때문에 WinZip 또는 유사한 아카이브 유틸리티가 필요하다.

파일을 추출한 후 jar 디렉토리를 보면 하나의 JAR 파일(simple-xml-2.1.4.jar)이 있다. 이 파일은 컴파일 시간 및 런타임에 클래스 경로에 있어야 하는 JAR 파일이다.

직렬화하기

오브젝트를 XML 문서로 직렬화하는 작업은 매우 간단하다. 다음 두 단계만 수행하면 된다.

  1. 적절한 어노테이션을 사용하여 POJO를 작성한다.
  2. 직렬화 프로세스를 실제로 수행하는 몇 줄의 코드를 작성한다.

이 기사에서는 필자의 기사에서 자주 사용되는 테마인 루어를 다시 한번 테마로 사용할 것이며 Listing 1이 바로 루어에 대한 정보를 나타내는 POJO이다.


Listing 1. Lure 클래스
@Root
public class Lure {

     @Attribute
     private String type;
	
     @Element
     private String company;
	
     @Element
     private int quantityInStock;
	
     @Element
     private String model;

     public String getType() {
		return type;
     }

     public void setType(String type) {
          this.type = type;
     }

     public String getCompany() {
          return company;
     }

     public void setCompany(String company) {
          this.company = company;
     }

     public int getQuantityInStock() {
          return quantityInStock;
     }

     public void setQuantityInStock(int quantityInStock) {
          this.quantityInStock = quantityInStock;
     }

     public String getModel() {
          return model;
     }

     public void setModel(String model) {
          this.model = model;
     }
}

이 POJO에는 복잡한 내용이 하나도 없다. 처음 봤을 때 어노테이션 부분이 익숙하지 않을 수도 있겠지만 이 또한 의도적인 것이다. Simple 프레임워크가 그 이름에 걸맞다고 한 필자의 말을 떠올려 보라.

@Root 어노테이션은 XML 문서의 루트 요소를 설명한다. 모든 XML 문서에는 루트 요소가 필요하므로 이 어노테이션을 반드시 포함시켜야 한다.

type 필드 위의 @Attribute 어노테이션은 해당 필드를 속성으로 식별한다. 이 속성은 루트 요소에 속성으로 추가된다.

마지막으로 남아 있는 @Element 어노테이션은 company, quantityInStockmodel이라는 세 필드의 바로 위에 사용된다. 이러한 필드는 XML 문서 내의 요소를 나타낸다.

POJO의 나머지 부분은 JavaBean 표준에 따라 접근자와 변경자로 구성되어 있다.

이제 POJO가 완료되었으므로 직렬화 코드를 작성할 차례이다. Listing 2에서 이 직렬화 코드를 볼 수 있다.


Listing 2. LureExample 클래스
public static void main(String[] args) {
     try {
          Serializer serializer = new Persister();
          Lure lure = new Lure();
          lure.setCompany("Donzai");
          lure.setModel("Marlin Buster");
          lure.setQuantityInStock(23);
          lure.setType("Trolling");
		
          File result = new File("lure.xml");
          serializer.write(lure, result);
     } catch (Exception e) {
          e.printStackTrace();
     }
}

이 코드에서는 가장 먼저 Persister 오브젝트를 인스턴스화한다. 이 클래스는 Simple 프레임워크의 일부이고 Serializer 인터페이스를 구현한다.

그런 다음 Lure 오브젝트를 인스턴스화하고 필드를 적절히 설정한다. 여기에서는 루어를 제조하는 회사의 이름이 Donzai이고 모델 이름이 Marlin Buster이다. 재고량은 23개이다. 마지막으로 루어의 유형은 Trolling이다.

그런 다음 XML 문서가 될 파일의 이름을 사용하여 File 오브젝트를 인스턴스화한다. 이 경우에는 파일 이름이 lure.xml이다.

마지막으로 직렬 변환기를 호출하여 파일을 작성한다. write() 메소드에 두 개의 매개변수가 제공된다. 첫 번째 매개변수는 POJO이고 두 번째 매개변수는 File 오브젝트이다.

이제 이 코드를 실행할 수 있다. Listing 2는 Java 애플리케이션이므로 자주 사용하는 IDE(Integrated Development Environment)를 사용하여 코드를 실행할 수 있다. simple-xml-2.1.4.jar이 클래스 경로에 있는지 확인한다. Eclipse를 사용하는 경우에는 파일을 마우스 오른쪽 단추로 클릭하고 Run As를 선택한 다음 표시되는 메뉴에서 Java Application을 선택하면 된다.

애플리케이션이 정상적으로 작동했다면 Listing 3과 같은 결과 XML 문서가 생성되어야 한다. (당연히 정상적으로 작동되어야 하며 정말 간단한 작업이다.)


Listing 3. LureExample 출력
<lure type="Trolling">
   <company>Donzai</company>
   <quantityInStock>23</quantityInStock>
   <model>Marlin Buster</model>
</lure>

Listing 3에서는 두 가지 사항에 주목해야 한다. 첫 번째는 루어 유형이 루트 요소의 속성이라는 것이다. 이는 @Element가 아닌 @Attribute를 사용하여 POJO의 type 필드를 어노테이트했기 때문에 완벽하게 작동한다.

결과 XML과 관련하여 또 하나 중요한 점은 요소 이름이 JavaBean 표준을 따른다는 것이다. 예를 들어, 루트 요소는 lure이고 클래스 이름은 Lure이다. 세 개의 하위 요소 이름도 해당 필드 이름과 완벽하게 일치한다. 다시 한번 말해서, 이 방법을 사용하면 루트 요소 이름과 하위 요소 이름이 서로 다른 패턴을 따르지 않아도 되기 때문에 이는 매우 실용적인 방법이다.

역직렬화하기

오브젝트를 직렬화하는 작업이 매우 쉬웠던 것처럼 역직렬화하는 방법도 매우 쉽다.

역직렬화는 XML 문서를 POJO로 변환하는 프로세스이다. 한 가지 좋은 점은 조금 전에 작성한 XML 문서를 역직렬화 작업에 사용할 수 있다는 것이다.

Listing 4에서는 역직렬화 코드를 보여 준다.


Listing 4. LureExample2 클래스
public static void main(String[] args) {
     try {
          Serializer serializer = new Persister();
          File source = new File("lure.xml");
          Lure lure = serializer.read(Lure.class, source);

          System.out.println(lure.getCompany());
          System.out.println(lure.getModel());
          System.out.println(lure.getQuantityInStock());
          System.out.println(lure.getType());
     } catch (Exception e) {
          e.printStackTrace();
     }
}

먼저 Serializer 인터페이스를 구현하는 Persister 오브젝트를 인스턴스화한다.

File 오브젝트를 인스턴스화하는 행도 익숙해 보이겠지만 이 경우에는 명확한 차이가 있다. Listing 3에서는 존재하지 않는 파일에 대한 File 오브젝트를 인스턴스화했지만 여기에서는 파일이 존재하고 있는 것으로 가정하고 있다. (실제로도 파일이 있어야 한다.)

그런 다음 Serializer 오브젝트의 read 메소드를 호출하여 POJO를 인스턴스화한다. read 메소드는 두 개의 매개변수를 사용한다. 하는 POJO 클래스이고 다른 하나는 데이터가 포함된 XML 파일을 나타내는 File 오브젝트이다.

마지막으로 모든 정보가 올바르게 읽혔는지 확인하기 위해 POJO의 모든 정보를 출력한다.

이 코드를 실행하면 Listing 5와 같은 출력이 표시되어야 한다.


Listing 5. LureExample2 출력
Donzai
Marlin Buster
23
Trolling

전체 트리 직렬화

지금까지 직렬화 및 역직렬화했던 XML 문서는 상당히 단순했다.

하지만 대부분의 XML 문서는 훨씬 더 복잡하다. 일반적으로 이러한 문서에는 중첩 요소뿐만 아니라 여러 개의 하위 요소를 가지고 있는 일대다 반복 요소가 여러 계층으로 포함되어 있다.

다행스럽게도 Simple은 그 이름에 걸맞게 복잡한 문서도 쉽게 처리할 수 있다. POJO 내에서 POJO를 중첩하는 것처럼 간단하게 처리할 수 있다. Listing 6을 살펴보자.


Listing 6. AdvancedLure 클래스
@Attribute
private String type;

@Element
private String company;
	
@Element
private int quantityInStock;
	
@Element
private String model;
	
@Element
private ConfigurationScheme configurationScheme;

Listing 6AdvancedLure 클래스는 Listing 1Lure 클래스와 매우 유사하다. 한 가지 차이점은 configurationScheme라는 또 하나의 필드가 포함되어 있다는 것이다. 구성 스키마는 Listing 7에서 설명하는 또 다른 POJO에 의해 표시된다.


Listing 7. ConfigurationScheme 클래스
@Root
public class ConfigurationScheme {
	
@Element
private String color;
	
@Element
private int size;

여기에서는 간단하게 설명하기 위해 접근자와 변경자를 생략했다.

Listing 7에서는 익숙한 어노테이션을 볼 수 있다. 이러한 어노테이션은 Listing 1에서 사용했던 것과 같은 어노테이션이다.

이제 Listing 8과 같은 결과를 얻을 수 있다.


Listing 8. LureExample3 클래스
public static void main(String[] args) {
     try {
          Serializer serializer = new Persister();
          AdvancedLure lure = new AdvancedLure();
          lure.setCompany("Donzai");
          lure.setModel("Marlin Buster");
          lure.setQuantityInStock(23);
          lure.setType("Trolling");
			
          ConfigurationScheme configurationScheme = new ConfigurationScheme();
          configurationScheme.setColor("Blue");
          configurationScheme.setSize(3);
          lure.setConfigurationScheme(configurationScheme);
			
          File result = new File("advancedlure.xml");
          serializer.write(lure, result);
     } catch (Exception e) {
          e.printStackTrace();
     }
}

Listing 2와 비교했을 때 Listing 8의 큰 차이점은 ConfigurationScheme 오브젝트를 인스턴스화한 다음 AdvancedLure 오브젝트의 해당 필드를 설정한다는 것이다.

이 코드를 실행하면 Listing 9와 같은 출력이 표시되어야 한다.


Listing 9. LureExample3 출력
<advancedLure type="Trolling">
   <company>Donzai</company>
   <quantityInStock>23</quantityInStock>
   <model>Marlin Buster</model>
   <configurationScheme>
      <color>Blue</color>
      <size>3</size>
   </configurationScheme>
</advancedLure>

이 출력을 보면 중첩 요소가 예상대로 정확히 직렬화되었다는 것을 알 수 있다.

열거

XML 문서에는 특정 요소의 열거가 자주 사용된다. 즉, 동일한 요소 이름이 하위 또는 속성 데이터만 변경된 채로 반복해서 자주 사용된다. 다행히도 Simple은 이 상황을 잘 처리할 수 있다.

이 기능을 확인하기 위해 먼저 Inventory라는 새 클래스를 작성한다. 이 클래스에는 재고품이 보관되어 있는 창고의 이름과 해당 재고 창고에서 찾을 수 있는 루어의 목록이 있다(Listing 10 참조).


Listing 10. Inventory 클래스
@Root
public class Inventory {
	
     @ElementList
     private List<AdvancedLure> lures;
	
     @Attribute
     private String warehouse;

이 Listing에서는 @ElementList라는 새 어노테이션을 사용하고 있다. 이 어노테이션은 해당 List 오브젝트가 XML 요소의 열거를 나타낸다는 의미를 지닌다.

이 POJO의 직렬화를 보여 주기 위해 사용된 코드는 더 간단한 POJO(예: Listing 2에서 직렬화했던 POJO)를 직렬화하는 데 사용했던 코드와 마찬가지로 쉽게 이해할 수 있다. Listing 11을 살펴보자.


Listing 11. LureExample4 클래스
Serializer serializer = new Persister();

AdvancedLure lure = new AdvancedLure();
lure.setCompany("Donzai");
lure.setModel("Marlin Buster");
lure.setQuantityInStock(23);
lure.setType("Trolling");
			
ConfigurationScheme configurationScheme = new ConfigurationScheme();
configurationScheme.setColor("Blue");
configurationScheme.setSize(3);
lure.setConfigurationScheme(configurationScheme);
			
			
AdvancedLure lure2 = new AdvancedLure();
lure2.setCompany("Ziggi");
lure2.setModel("Tuna Finder");
lure2.setQuantityInStock(44);
lure2.setType("Trolling");
		
ConfigurationScheme configurationScheme2 = new ConfigurationScheme();
configurationScheme2.setColor("Red");
configurationScheme2.setSize(5);
lure2.setConfigurationScheme(configurationScheme2);
			
List<AdvancedLure> lures = new ArrayList<AdvancedLure>();
lures.add(lure);
lures.add(lure2);
			
Inventory inventory = new Inventory();
inventory.setLures(lures);
inventory.setWarehouse("Midwest");
			
File result = new File("inventory.xml");

serializer.write(inventory, result);

이 코드를 실행하면 inventory.xml이라는 XML 파일이 작성된다. 이 파일의 내용은 Listing 12와 같다.


Listing 12. LureExample4 출력
<inventory warehouse="Midwest">
   <lures>
      <advancedLure type="Trolling">
         <company>Donzai</company>
         <quantityInStock>23</quantityInStock>
         <model>Marlin Buster</model>
         <configurationScheme>
            <color>Blue</color>
            <size>3</size>
         </configurationScheme>
      </advancedLure>
      <advancedLure type="Trolling">
         <company>Ziggi</company>
         <quantityInStock>44</quantityInStock>
         <model>Tuna Finder</model>
         <configurationScheme>
            <color>Red</color>
            <size>5</size>
         </configurationScheme>
      </advancedLure>
   </lures>
</inventory>

이 Listing을 보면 Listing 11에서 인스턴스화하고 작성했던 POJO와 출력이 완전히 같다는 것을 알 수 있다. 두 개의 advancedLure 요소가 있고 각 요소에는 해당 POJO를 채우는 데 사용했던 데이터가 있다. 여기에서도 중첩이 적절히 사용되고 있다.

생성자

코드에서 변경되지 않는 POJO를 사용할 수 있다. 이 경우 setter 메소드를 사용하여 필드 속성을 수정하는 대신 생성자를 사용하여 이러한 값을 설정할 수 있다. Simple은 이 상황을 잘 처리할 수 있다.

이 경우에는 필드 이름 위가 아닌 생성자 매개변수 내에서 어노테이션을 지정한다. 해당 접근자 메소드 위에도 어노테이션이 필요하다. Listing 13을 살펴보자.


Listing 13. Inventory2 클래스
public Inventory2(@ElementList(name="lures") List<AdvancedLure> lures,
 @Attribute(name="warehouse") String warehouse) {
     this.lures = lures;
     this.warehouse = warehouse;
}

@ElementList(name="lures")
public List<AdvancedLure> getLures() {
     return lures;
}

@Attribute(name="warehouse")
public String getWarehouse() {
     return warehouse;
}

어노테이션을 생성자 매개변수의 일부로 지정할 경우에는 매개변수에 해당하는 필드 이름도 지정해야 한다. 첫 번째 매개변수에 대한 필드 이름은 lures이고 두 번째 매개변수에 대한 필드 이름은 warehouse이다.

그런 다음 접근자 메소드 위에 일치하는 어노테이션 및 필드 이름을 제공한다. lures에 대한 getter 바로 위에서 생성자에 사용된 어노테이션과 완전히 일치하는 해당 어노테이션을 볼 수 있다. 이와 마찬가지로 warehouse에 대한 getter 위의 어노테이션도 해당 어노테이션과 완전히 일치한다.

이 코드를 실행하기 위해 먼저 Listing 11을 약간 수정하여 Listing 14의 코드를 포함시킨다.


Listing 14. LureExample5 클래스
Inventory2 inventory = new Inventory2(lures,"MidWest");

여기에서는 Listing 11에서 사용했던 setter 메소드 대신 Listing 14의 코드를 사용하며 나머지 부분은 모두 동일하다.

템플리트 필터

XML 문서를 역직렬화할 때 템플리트 필터 또는 기본값을 사용할 수 있다는 점은 Simple의 또 다른 주요 기능이다.

이제 원래의 lure.xml로 돌아가서 Listing 15처럼 약간만 수정해 보자.


Listing 15. Lure2.xml 문서
<lure type="Trolling">
   <company>${lure.company}</company>
   <quantityInStock>23</quantityInStock>
   <model>Marlin Buster</model>
</lure>

이 문서의 company 요소에는 실제 회사의 이름 대신 Apache Ant 유형의 변수 선언이 포함되어 있으며 변수의 이름은 lure.company이다.

템플리트 필터를 사용하면 런타임에 변수 선언을 실제 값으로 대체하여 설정할 수 있다. 이를 수행하는 쉬운 방법으로는 변수 이름과 해당 값을 연결하는 Map 오브젝트를 사용하는 것이다. 그런 다음 Map 오브젝트를 사용하여 Simple 프레임워크에서 Filter 오브젝트를 생성한다. 그런 다음 Filter 오브젝트를 사용하여 Persister 오브젝트를 생성한다. Listing 16을 살펴보자.


Listing 16. LureExample6 클래스
Map<String,String> map = new HashMap<String,String>();
map.put("lure.company", "Monmouth");
Filter filter = new MapFilter(map);
			
Serializer serializer = new Persister(filter);
File source = new File("lure2.xml");

Lure lure = serializer.read(Lure.class, source);

System.out.println(lure.getCompany());
System.out.println(lure.getModel());
System.out.println(lure.getQuantityInStock());
System.out.println(lure.getType());

Listing 16Listing 2와 크게 다르지 않다. 주요 차이점은 String 값을 String 키에 연결하는 HashMap이 인스턴스화된다는 것이다. 이 경우 String 키는 예상대로 Listing 15에서 사용했던 변수 이름인 lure.company이다. 여기에서는 앞에서 보았던 XML 문서에 있던 값인 Donzai대신 Monmouth라는 값을 이 키에 지정한다.

이 코드를 실행하면 Listing 17과 같은 출력이 표시되어야 한다.


Listing 17. LureExample6 출력
Monmouth
Marlin Buster
23
Trolling

이 출력을 보면 템플리트 필터가 변수 이름 lure.companyMap 오브젝트에 있는 해당 키 이름에 연결된 실제 값으로 대체했다는 것을 알 수 있다. 이 출력은 예상과 정확히 일치한다.

결론

지금까지 살펴보았듯이 Simple은 강력한 XML 직렬화 및 역직렬화 프레임워크이며 사용하기도 쉽고, 구성도 필요하지 않기 때문에 빠른 개발이 가능하다.

Simple에는 여러 가지 강력한 기능이 있지만 여기에서는 지면의 제약으로 인해 일부 기능만을 살펴보았다. 소프트웨어 개발 작업 중에 XML 직렬화 및 역직렬화가 필요한 개발자라면 Simple을 사용해 보기를 적극 권장한다.



다운로드 하십시오

설명 이름 크기 다운로드 방식
Source code for the examples used in this article Simple.zip 5KB HTTP

다운로드 방식에 대한 정보

Posted by 1010
반응형

오래전부터 XML을 변환하는 데 있어서 XStream을 많이 사용했을 겁니다. 이것을 사용하면 아주 편하게 XML을 제어롤 하게 됩니다.(object를 xml로 or xml을 object로) 그래서 SOAP 인터페이스나 다양한 OPEN API나 멀티미디어 디바이스와의 연동 등에 많이 사용하곤 합니다.

아래의 샘플을 올려놓을테니 한번 실행해 보시고 사용법을 익힌다음 자기의 것으로 만들어 개발에 생산성을 높이는데 일조를 하시면 되겠죠. ^^

1. IXmlRule.java
package com.mimul.xstream;

public interface IXmlRule
{
public String toXML();

}

2. BaseRule.java
package com.mimul.xstream;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.Annotations;

import java.io.Serializable;
import java.lang.reflect.Field;


public class BaseRule implements Serializable {

/**
* XML 문자열로 변환
*/
protected String toXML() {
XStream xstream = new XStream();
Annotations.configureAliases(xstream, getClass());
Field[] fields = getClass().getDeclaredFields();
for (Field f : fields) {
Annotations.configureAliases(xstream, f.getType());
}
String xmlString = xstream.toXML(this);
xstream = null;
return xmlString;
}

/**
* XML 데이터로부터 Rule Build
*/
public static IXmlRule fromXML(String xmlString, Class clazz) {
XStream xstream = new XStream();
Annotations.configureAliases(xstream, clazz);
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
Annotations.configureAliases(xstream, f.getType());
}
IXmlRule rule = (IXmlRule) xstream.fromXML(xmlString);
xstream = null;
return rule;
}
}

3. Member.java
package com.mimul.xstream;

import com.thoughtworks.xstream.annotations.XStreamAlias;

@XStreamAlias("xstream.Member")
public class Member {

private String accountNo;
private String password;


public String getAccountNo() {
return accountNo;
}

public void setAccountNo(String accountNo) {
this.accountNo = accountNo;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}
}

4. PersonRule.java
package com.mimul.xstream;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamImplicit;

import java.util.ArrayList;
import java.util.List;


@XStreamAlias("Person")
public class PersonRule extends BaseRule implements IXmlRule
{
private static final long serialVersionUID = 1L;

public String toXML() {
return super.toXML();
}

private String name;
private int age;
private String occupation;

@XStreamImplicit(itemFieldName = "members")
private List<Member> members;


public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getOccupation() {
return occupation;
}

public void setOccupation(String occupation) {
this.occupation = occupation;
}

public List<Member> getMembers() {
return members;
}

public void setMembers(List<Member> members) {
this.members = members;
}

public static void main(String args[])
{
PersonRule person = null;
List<Member> members = null;
Member member = null;

try {
person = new PersonRule();
person.setName("미물");
person.setAge(32);
person.setOccupation("Consultant");

members = new ArrayList<Member>(3);
member = new Member();
member.setAccountNo("mimul");
member.setPassword("mimuladmim");
members.add(member);

member = new Member();
member.setAccountNo("pepsi");
member.setPassword("pepsiadmin");
members.add(member);

member = new Member();
member.setAccountNo("scott");
member.setPassword("tigerda");
members.add(member);

person.setMembers(members);

// Object에서 XML 생성
String xmlString = person.toXML();
System.out.println("XML : " + xmlString);

// XML파일 Object 매핑
PersonRule personRule = (PersonRule) BaseRule.fromXML(xmlString, PersonRule.class);

System.out.println(personRule.getName());
System.out.println(personRule.getAge());
System.out.println(personRule.getOccupation());

for (Member mem : personRule.getMembers()) {
System.out.println(mem.getAccountNo());
System.out.println(mem.getPassword());
}
} catch (Exception e) {
System.out.println(e);
person = null;
members = null;
}
}
}

5. 실행 화면

Xstream
6. JSON 변환 방법을 알려면 여기를 가시면 됩니다.

출처 : http://mimul.com/pebble/default/2007/11/08/1194530400000.html
Posted by 1010
반응형
String t_xmlStr =           
   "<root>" +           
   "<item value=\"돈까스\">" +
   "<item value=\"순대국\">" +
   "<item value=\"짜장면\">" +
   "</item></item></item></root>";
   
  DocumentBuilderFactory t_dbf = null;       
  DocumentBuilder t_db = null;       
  Document t_doc = null;       
  NodeList t_nodes = null;       
  Node t_node = null;       
  Element t_element = null;       
  InputSource t_is = new InputSource();        
  try{           
   t_dbf = DocumentBuilderFactory.newInstance();           
   t_db = t_dbf.newDocumentBuilder();           
   t_is = new InputSource();           
   t_is.setCharacterStream(new StringReader(t_xmlStr));           
   t_doc = (Document) t_db.parse(t_is);           
   t_nodes = t_doc.getElementsByTagName("item");            
   for (int i = 0, t_len = t_nodes.getLength(); i < t_len; i ++){              
    t_element = (Element)t_nodes.item(i);                
    System.out.println(t_element.getAttribute("value"));   
    collection.add(new personVO(t_element.getAttribute("value"), t_element.getAttribute("value"), t_element.getAttribute("value")));
   }       
  }catch (Exception e){           
   e.printStackTrace();       
  }
Posted by 1010
01.JAVA/Java2012. 1. 27. 14:50
반응형

jar 파일 생성 시 MANIFEST.MF 작성

JAVA 2009/03/05 08:56
파일 위치 및 명령어 실행 위치 현황
D:\Java_EXE \
└Genealogy2 \ ←명령어 실행 위치
└data
└lib ← swt.jar 위치
META-INF (folder)
└src ← 실행 파일 위치(package)

● META-INF 폴더는 root 폴더 바로 아래에 만든다.
( src 등 기타 위치에 생성하는 건 의미없다.
eclipse에서 export를 통해 jar를 만들 때 root 폴더가 아닌 곳에 만든 manifest.mf를 참조할 경우
eclipse가 root 폴더 아래 새로 만들기 때문에 실행 파일 설정이 정상적으로 이뤄지지 않는다. )

root\META-INF 밑에 MANIFEST.MF 만들어서 아래 내용 추가하고, Export 할 때 manifest.mf를 추가해 준다. (eclipse에서 작업해야 Resource is out of sync ~~~ 안 뜬다. 뜨면 한 번 열어서 읽어 준다.)

MANIFEST.MF 파일 내용
Manifest-Version: 0.1
Class-Path: lib/swt.jar
Main-Class: src.ManageGenealogy


Class-Path: lib/swt.jar ← jar 파일 내부 폴더에 둔다.
그 외 참조할 class가 있으면 그 위치를 적어준다. 구분자는 ' '
이 예제의 경우, swt.jar 를 제외한 모든 class가 메인 클래스와 같은 src 하부에 있어서 추가없음.
Class-Path는 72자까지만 됨.
Class-Path는 외부 경로(local)만 가능함. Jar 내부나, Internet 등으로 접근하는 Jar는 참조할 수 없음.
(-> 내가 만든 jar 안에 내가 참조할 외부 jar를 넣고, Class-Path에 잡아주어도 참조하지 못한다.
참조하려면 1. 참조할 jar를 풀어서 내 jar 안에 넣고, sealed 처리하던가
2. 외부에 참조할 jar를 위치시키고 class-path에 경로를 잡아준다.

Main-Class: src.ManageGenealogy ← 실행 파일 경로 및 파일 명
jar 파일을 실행 가능하게 만든다.
실행 명령어 : java -jar Genealogy.jar

※ 주의사항 :
1. MANIFEST.MF 내에서 다른 class, directory, jar를 참조할 때는 경로 정보를 입력할 때 '/'를 사용한다.
(경우에 따라서 '\'를 쓰게 되는 경우도 있으니 아래 Exception 발생 시 경로를 수정해 볼 것.
Exception in thread "main" java.lang.NoClassDefFoundError: aaa/bbb/ccc )
2. 각 'attirbute :' 다음에 공백 한 칸 둘 것. (ex 'Class-Path: ')
3. Main-Class attribute 다음에 carrage return(엔터) 하나 둘 것. 안 그러면 실행 시 main class를 인식 못 함.

참조 : http://www.ibm.com/developerworks/kr/library/j-jar/index.html
http://java.sun.com/docs/books/tutorial/deployment/jar/basicsindex.html
http://blog.naver.com/echris7?Redirect=Log&logNo=140012585340
관련 글 : http://digicom.tistory.com/165
---------------------------------------------------------------------------------------------------

...


Posted by 1010
반응형
:http://xstream.codehaus.org/tutorial.html <- 참조

Serializing an object to XML

Let's create an instance of Person and populate its fields:

Person joe = new Person("Joe", "Walnes");
joe.setPhone(new PhoneNumber(123, "1234-456"));
joe.setFax(new PhoneNumber(123, "9999-999"));

Now, to convert it to XML, all you have to do is make a simple call to XStream:

String xml = xstream.toXML(joe);

The resulting XML looks like this:

<person>
  <firstname>Joe</firstname>
  <lastname>Walnes</lastname>
  <phone>
    <code>123</code>
    <number>1234-456</number>
  </phone>
  <fax>
    <code>123</code>
    <number>9999-999</number>
  </fax>
</person>

It's that simple. Look at how clean the XML is.

Posted by 1010
반응형

ThoughtWorks에서 만든 Xstream을 활용한다.
Xstream 최대의 장점은 초 간단...
얼마나 간단하면 튜토리얼이 Two Minute Tutorial 이다.
클래스 패스에 xstream-xxx.jar를 넣고.. 다음 코드를 실행하면..
XStream xstream = new XStream();
Person joe = new Person();
joe.setAge(30);
joe.setName("Joe");
joe.setPhone(new PhoneNumber(123, "1234-456"));
joe.setFax(new PhoneNumber(123, "9999-999"));
String xml = xstream.toXML(joe);
System.out.println(xml);
출력 내용은.. 간단하기 이를데 없다.. 만족.. ^^
<object.Person>
<name>Joe</name>
<age>30</age>
<fax>
<code>123</code>
<number>9999-999</number>
</fax>
<phone>
<code>123</code>
<number>1234-456</number>
</phone>
</object.Person>
object.Person은 좀 보기 싫어.. 별칭(alias)를 준다.
XStream xstream = new XStream();
xstream.alias("person", Person.class);
Person joe = new Person();
joe.setAge(30);
joe.setName("Joe");
joe.setPhone(new PhoneNumber(123, "1234-456"));
joe.setFax(new PhoneNumber(123, "9999-999"));
String xml = xstream.toXML(joe);
System.out.println(xml);
그럼.. 출력은 내 스타일(?)로 변모...
<person>
<name>Joe</name>
<age>30</age>
<fax>
<code>123</code>
<number>9999-999</number>
</fax>
<phone>
<code>123</code>
<number>1234-456</number>
</phone>
</person>
null값을 갖는 속성은 어찌 되는가?
XStream xstream = new XStream();
xstream.alias("person", Person.class);
Person joe = new Person();
// joe.setAge(30);
joe.setName("Joe");
joe.setPhone(new PhoneNumber(123, "1234-456"));
joe.setFax(new PhoneNumber(123, "9999-999"));
출력이 안되는군.
<person>
<name>Joe</name>
<fax>
<code>123</code>
<number>9999-999</number>
</fax>
<phone>
<code>123</code>
<number>1234-456</number>
</phone>
</person>
XML을 자바 객체로..
XStream xstream = new XStream();
xstream.alias("person", Person.class);
String xml =
"<person>" +
"<name>Joe</name>" +
"<fax>" +
"<code>123</code>" +
"<number>9999-999</number>" +
"</fax>" +
"<phone>" +
"<code>123</code>" +
"<number>1234-456</number>" +
"</phone>" +
"</person>" ;
Person joe = (Person)xstream.fromXML(xml);
alias 처리를 포함해도 세 문장이면 되는구만.
단.. 자바 객체 변환(Deserializing)시에는 xpp.jar(xstream zip 파일의 lib에 있음)가 필요하다.
Posted by 1010
반응형

JAXB를 활용한 Java 객체의 XML 자동 변환

Using JAXB for XML data binding

자바 SE 6에서 JAXB(Java Architecture for XML Binding)를 사용하여 JAVA -> XML 변환하는 테스트 샘플을 만들어 보았습니다. 물론 XStream으로도 가능합니다.

1. JAXB란?
JAXB를 사용하면 XML과 자바 간에 쉽게 앞뒤로 이동할 수 있습니다. JAXB 구현은 XML 스키마를 받아 해당 스키마에 매핑되는 자바 클래스를 생성하는 스키마 컴파일러를 제공합니다. XML 문서의 데이터는 JAXB의 바인딩 런타임 프레임워크를 통해, 스키마 컴파일러가 생성한 클래스에 자동으로 바인딩될 수 있습니다. 이 작업을 언마샬링(Unmarshalling)이라고 합니다. 언마샬링되면 필요에 따라 콘텐츠를 Java로 조작하거나 수정할 수 있습니다. JAXB는 자바 개체에서 XML 인스턴스 문서로 데이터를 쓸(마샬링할) 수도 있습니다.

2. 샘플 소스
*. Person bean 객체
package client;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "person")
public class Person
{
private String firstName;
private String lastName;
private Family family;

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public Family getFamily() {
return family;
}

public void setFamily(Family family) {
this.family = family;
}
}

*. Family bean 객체
package client;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;

public class Family
{
private String description;
@XmlElementWrapper(name = "persons")
@XmlElement
private List<Person> members = new ArrayList<Person>();


public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public List<Person> getMembers() {
return members;
}
}

*. Java객체를 Xml로 변환하는 클라이언트 샘플
package client;

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

public class JAXBClient
{
public static void main(String[] args) {
JAXBContext context = null;
List<Person> list = null;
Person person1 = null;
Person person2 = null;
Family family = null;
Marshaller marshaller = null;

try {
context = JAXBContext.newInstance(Person.class);
list = new ArrayList<Person>();

person1 = new Person();
family = new Family();

family.setDescription("Family Mimul");
person1.setFirstName("IlDong");
person1.setLastName("Hong");
person1.setFamily(family);
list.add(person1);

person2 = new Person();
person2.setFirstName("LeeDong");
person2.setLastName("Hong");
person2.setFamily(family);
list.add(person2);

// Marshal 객체를 XML로 변환
// Unmarshal the objects from XML

marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_ENCODING, "utf-8");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
Boolean.TRUE);

marshaller.marshal(person2, System.out);

} catch (JAXBException e) {
e.printStackTrace();
}
}
}


3. 실행 결과
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<person>
<family>
<persons/>
<description>Family Mimul</description>
</family>
<firstName>LeeDong</firstName>
<lastName>Hong</lastName>
</person>
Posted by 1010
반응형

How to create XML file in Java – (JDOM Parser)
Published: August 4, 2011 , Updated: August 4, 2011 , Author: mkyong

In this example, we show you how to use JDOM parser to create document, element and attribute in a XML file.

1. XML File

At the end of this example, following XML file will be created.

File : file.xml

<?xml version="1.0" encoding="UTF-8"?>
<company>
  <staff id="1">
    <firstname>yong</firstname>
    <lastname>mook kim</lastname>
    <nickname>mkyong</nickname>
    <salary>199999</salary>
  </staff>
  <staff id="2">
    <firstname>low</firstname>
    <lastname>yin fong</lastname>
    <nickname>fong fong</nickname>
    <salary>188888</salary>
  </staff>
</company>

3. JDOM Example

JDOM example to create above XML file.

import java.io.FileWriter;
import java.io.IOException;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
 
public class WriteXMLFile {
	public static void main(String[] args) {
 
	  try {
 
		Element company = new Element("company");
		Document doc = new Document(company);
		doc.setRootElement(company);
 
		Element staff = new Element("staff");
		staff.setAttribute(new Attribute("id", "1"));
		staff.addContent(new Element("firstname").setText("yong"));
		staff.addContent(new Element("lastname").setText("mook kim"));
		staff.addContent(new Element("nickname").setText("mkyong"));
		staff.addContent(new Element("salary").setText("199999"));
 
		doc.getRootElement().addContent(staff);
 
		Element staff2 = new Element("staff");
		staff2.setAttribute(new Attribute("id", "2"));
		staff2.addContent(new Element("firstname").setText("low"));
		staff2.addContent(new Element("lastname").setText("yin fong"));
		staff2.addContent(new Element("nickname").setText("fong fong"));
		staff2.addContent(new Element("salary").setText("188888"));
 
		doc.getRootElement().addContent(staff2);
 
		// new XMLOutputter().output(doc, System.out);
		XMLOutputter xmlOutput = new XMLOutputter();
 
		// display nice nice
		xmlOutput.setFormat(Format.getPrettyFormat());
		xmlOutput.output(doc, new FileWriter("c:\\file.xml"));
 
		System.out.println("File Saved!");
	  } catch (IOException io) {
		System.out.println(io.getMessage());
	  }
	}
}
Posted by 1010
반응형
How to modify XML file in Java – (JDOM Parser)
Published: April 3, 2010 , Updated: August 4, 2011 , Author: mkyong

JDOM XML parser example to modify an existing XML file :

  1. Add a new element
  2. Update existing element attribute
  3. Update existing element value
  4. Delete existing element

1. XML File

See before and after XML file.

File : file.xml – Original XML file.

<?xml version="1.0" encoding="UTF-8"?>
<company>
  <staff id="1">
    <firstname>yong</firstname>
    <lastname>mook kim</lastname>
    <nickname>mkyong</nickname>
    <salary>5000</salary>
  </staff>
</company>

Later, update above XML file via JDOM XML Parser.

  1. Add a new “age” element under staff
  2. Update the staff attribute id = 2
  3. Update salary value to 7000
  4. Delete “firstname” element under staff

File : file.xml – Newly modified XML file.

<?xml version="1.0" encoding="UTF-8"?>
<company>
  <staff id="2">
    <lastname>mook kim</lastname>
    <nickname>mkyong</nickname>
    <salary>7000</salary>
    <age>28</age>
  </staff>
</company>

2. JDOM Example

JDOM parser to update or modify an existing XML file.

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
 
public class ModifyXMLFile {
	public static void main(String[] args) {
 
	  try {
 
		SAXBuilder builder = new SAXBuilder();
		File xmlFile = new File("c:\\file.xml");
 
		Document doc = (Document) builder.build(xmlFile);
		Element rootNode = doc.getRootElement();
 
		// update staff id attribute
		Element staff = rootNode.getChild("staff");
		staff.getAttribute("id").setValue("2");
 
		// add new age element
		Element age = new Element("age").setText("28");
		staff.addContent(age);
 
		// update salary value
		staff.getChild("salary").setText("7000");
 
		// remove firstname element
		staff.removeChild("firstname");
 
		XMLOutputter xmlOutput = new XMLOutputter();
 
		// display nice nice
		xmlOutput.setFormat(Format.getPrettyFormat());
		xmlOutput.output(doc, new FileWriter("c:\\file.xml"));
 
		// xmlOutput.output(doc, System.out);
 
		System.out.println("File updated!");
	  } catch (IOException io) {
		io.printStackTrace();
	  } catch (JDOMException e) {
		e.printStackTrace();
	  }
	}
}

Posted by 1010
반응형

How to read XML file in Java – (JDOM Parser)
Published: December 21, 2009 , Updated: August 4, 2011 , Author: mkyong

JDOM is, quite simply, a Java representation of an XML document. JDOM provides a way to represent that document for easy and efficient reading, manipulation, and writing. It has a straightforward API, is a lightweight and fast, and is optimized for the Java programmer. It’s an alternative to DOM and SAX, although it integrates well with both DOM and SAX.

JDOM, Java XML parser, is more user friendly in the way of accessing the XML document.

In this example, we show you how to use JDOM to read a XML file, and print out each element orderly.

1. Download the JDOM library

JDOM is not like SAX or DOM, which bundled in JDK. To use JDOM, you need to download the library manually.

Get JDOM from JDOM official site or declares following dependency if you are using Maven.

    <dependency>
	<groupId>jdom</groupId>
	<artifactId>jdom</artifactId>
	<version>1.1</version>
    </dependency>

2. XML File

XML file as following

<?xml version="1.0"?>
<company>
	<staff>
		<firstname>yong</firstname>
		<lastname>mook kim</lastname>
		<nickname>mkyong</nickname>
		<salary>100000</salary>
	</staff>
	<staff>
		<firstname>low</firstname>
		<lastname>yin fong</lastname>
		<nickname>fong fong</nickname>
		<salary>200000</salary>
	</staff>
</company>

3. Java File

Use JDOM parser to parse above XML file.

import java.io.File;
import java.io.IOException;
import java.util.List;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
 
public class ReadXMLFile {
	public static void main(String[] args) {
 
	  SAXBuilder builder = new SAXBuilder();
	  File xmlFile = new File("c:\\file.xml");
 
	  try {
 
		Document document = (Document) builder.build(xmlFile);
		Element rootNode = document.getRootElement();
		List list = rootNode.getChildren("staff");
 
		for (int i = 0; i < list.size(); i++) {
 
		   Element node = (Element) list.get(i);
 
		   System.out.println("First Name : " + node.getChildText("firstname"));
		   System.out.println("Last Name : " + node.getChildText("lastname"));
		   System.out.println("Nick Name : " + node.getChildText("nickname"));
		   System.out.println("Salary : " + node.getChildText("salary"));
 
		}
 
	  } catch (IOException io) {
		System.out.println(io.getMessage());
	  } catch (JDOMException jdomex) {
		System.out.println(jdomex.getMessage());
	  }
	}
}

Output

First Name : yong
Last Name : mook kim
Nick Name : mkyong
Salary : 100000
First Name : low
Last Name : yin fong
Nick Name : fong fong
Salary : 200000
Posted by 1010
53.jasper&ireport2012. 1. 25. 13:22
반응형

JavaBeans as datasource in JasperReports

JasperReports is very flexible report generation tool on both beginner as well as enterprise level. It supports many data access mechanisms for retrieving data and rendering to the report like SQL, EJBQL, HSQL, XML, JavaBeans, XPath etc. But here our main focus is on the usage of JavaBeans.

I have divided the whole task of report generation into certain activities as shown below:
1. Create a simple Java Class (JavaBean) with properties and their accessors and mutators.
2. Design a report either manually or you can use IDE like iReports for that, I have used iReports.
3. Compile the report using Java and run it to test whether its working or not.

We will start with step 1:
Create a simple Java Class thats a simple POJO(Plain Old Java Object) its contains the data for the report. You can take any entity for that, I am here taking a simple entity Student and creating a Java file shown below with the name Student.java.

package beansforjasper;

public class Student
{
private String name;
private String roll_no;
private String fathers_name;
private String studying_in;

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRoll_no() {
return roll_no;
}
public void setRoll_no(String roll_no) {
this.roll_no = roll_no;
}
public String getFathers_name() {
return fathers_name;
}
public void setFathers_name(String fathers_name) {
this.fathers_name = fathers_name;
}
public String getStudying_in() {
return studying_in;
}
public void setStudying_in(String studying_in) {
this.studying_in = studying_in;
}
}

In addition to the above code we have to add a static method that returns a collection. This will be used as datasource for report. I have made a simple static method as follows:


public static Collection getStudentList()
{
Vector students = new Vector();
try
{
Student student = new Student();
student.setRoll_no("101");
student.setName("Steve");
student.setFathers_name("Jack");
student.setStudying_in("I-A");
students.add(student);
student = new Student();
student.setRoll_no("102");
student.setName("Mark");
student.setFathers_name("Henry");
student.setStudying_in("I-A");
students.add(student);
}
catch(Exception ex)
{
System.out.println(ex);
}
return students;
}


Thats all for as far as datasource for report is concerned.


Step 2 (The iReports part):
Create a new report in iReports as show in diagram 1.

Diagram 1

Now create a new datasource by clicking on "Report Datasources" button on toolbar. You will see a window showing the tabular representation of the all existing datasources. Now click on "New" button and you will see datasource types as shown in Diagram 2 below:

Diagram 2

Now select JavaBean set datasource and click on the "Next" button. This will take you to a new window, that will ask you for name, fully qualified class name of the factory class that will generate set and of course the static method thats going to return either Collection or Array of JavaBeans. Be care full to select the radio button specific to the return type of your static method. This is shown in Diagram 3 below:

Diagram 3

After doing all this work when you click on "Test" button an error will be generated, this is mainly because the class path is not set for our "Student.class" file. To set classpath follow steps below:
1. Goto Tools(Menu)>>Options
2. Select iReport tab and then select "Classpath" tab now click on "Add Folder" if you have only class file and add directory containing it else "Add JAR" if you have distributable jar file.

After the classpath is set Now its time to add data fields so that these can be used in our report.
In order to do that Right click the Report Node(Root Node) in the "Report Inspector" and choose "Edit Query" from popup menu. A window will appear choose "JavaBean Datasource" tab in that window as shown below:

Diagram 4

Provide the fully qualified class name of the JavaBean and click on "Read Attributes" you will see all the fields that this class contains. Select the fields that you want to make available for the report and then click on "Add Selected Fields".

I have created a simple design just to show you how easy it is to create reports with iReport. My sample is shown as Diagram 5.

Diagram 5


This is actually an attemp to show how JavaBeans can be used as datasource for the JasperReports.
Here I have used iReport 3.7.2.

On clicking the preview its generates preview as as shown below in Diagram 6.

Diagram 6

Step 3(Compilation and Test using Java)
To test this demo using a Java program we can use the following code:


public static void main(String[] str)
{
try
{
JasperReport jasperReport = null;
JasperPrint jasperPrint = null;
JasperDesign jasperDesign = null;
Map parameters = new HashMap();
jasperDesign = JRXmlLoader.load("<Path of Report>");
jasperReport = JasperCompileManager.compileReport(jasperDesign);
jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, new JRBeanCollectionDataSource(beansforjasper.Student.getStudentList()));
JasperExportManager.exportReportToPdfFile(jasperPrint,"StudentInfo.pdf");
JasperViewer.viewReport(jasperPrint);
}
catch(Exception ex)
{
System.out.println("EXCEPTION: "+ex);
}
}


This will generate a "StudentInfo.pdf" file and will invoke Jasper report viewer that will show you the generated report.

Remember to put the dependencies at the classpath while running the above program.
Posted by 1010
53.jasper&ireport2012. 1. 19. 16:18
53.jasper&ireport2012. 1. 19. 16:17
반응형

4 Connections and Datasources

Data to print can be retrived in several ways from different places like a database or a XML file. This data is presented to JasperReports always in form of records using a special interface called JRDataSource. JasperReports comes with a good set of implementations of this interface to wrap JDBC ResultSets, TableModels, Collections, Vectors and Arrays of objects, etc... But not always a JRDataSource is needed to supply data to the report in order to fill it. In fact JasperReports can execute yourself sql queries using a given opened Connection to a database, and use the result to fill the report. How we'll see, this features will be very useful and easy to use.

4.1 Types of datasource

iReport supports JDBC connections and 4 types of datasource (that can be used to wrap any kind of custom datasource).
  • Empty data source (JREmptyDatasource): is a special datasource used to fill report that don't expose any records. This datasource is used when you press the button to "run" a report.
  • XML DataSource (not yet implemented): is a datasource capable to wrap an XML file and normalize its content.
    Fig.4.1: XML datasource definition.
    The only informations needed to create this type of datasource are a name (for the datasource) and the name of the XML file.







  • JavaBeans Set Datasource (not yet implemented): is a datasource capable to wrap a Collection or an Array of JavaBeans.
    Fig.4.2: JavaBeans Set datasource definition.
    How all the rest of datasources used by iReport and presented here, this datasource need a spacial factory class that provides a static method to generate a collection or an array of JavaBeans (alias a set of Objects).
    To create this datasource you need a name for the datasource, the name of a class that will provide the static method to call to retrive the Array/Collection of Objects and the name of this method that will have a definition like this:

    public static Collection createMyCollection()
    or
    public static Object[] createMyArray()

    Remember to set the type of result (Collection or Array).

  • Custom Datasource: this type of datasource is generic. iReport don't know how the JRDataSource is implemented by this particular connection but it's not important.
    Fig.4.3: Custom JRDatasource definition.
    This datasource need a spacial factory class that provides a static method that return a JRDataSource.
    To create this datasource you need a name for the datasource, the name of a class that will provide the static method to call to retrive the JRDataSource and the name of this method that will have a definition like this:

    public static JRDataSource createMyJRDataSource()


An example of implementation of a custom datasource is provided at the end of this chapter.



4.2 Setting up a JDBC connection

To set up a JDBC connection we need a running JDBC capable DBMS (I like MySQL), an appropriate JDBC driver to access it, a database and a valid account. Are you ready? Let's go!
Select the menu Datasources > Connection/Datasources. Will appeare the frame with the list of datasources and JDBC connections that you have defined. Please note that you can define how many datasources and connecgtions you want but you can, for now, use only one at time. We'll see how set the "Active connection". Press the "New" button.
Fig.4.4: JDBC connection definition frame.
In the new frame, write a connection name (i.e. "My First JDBC connection"), select the right JDBC driver, you can specify one writing it directly or use one already present in the list. Please note that this drivers are not shipped with iReport (except MySQL driver), be sure that the driver that you want use is in the classpath. Putting a jar in the lib directory of iReport can be a good idea, but the jars present in this directory are added to the CLASSPATH only when iReport start. For now it's not possible change the classpath of iReport 2 dinamically.
Before write the URL, write the database name, then press the button "Wizard". In this way, if iReport recognize the driver, it will suggest a URL to use with.
Set the username and the password, then test the connection pressing the Test button.
Fig.4.5: The connection is OK.
If all it's OK, a dialog box (Fig. 4.5) will inform you of the test success.
Many software use a very similar way to setting up a JDBC connection. You can refer to the specific JDBC driver documentation to know all options offered by the driver and the exact syntax of the URL.
All most used DBMS have a JDBC driver. If you need to access a database via ODBC on a Win32 system, you can use the JDBC-ODBC brigde, a special JDBC driver developed by Sun Inc.. But I suggest to verify first the presence of a JDBC driver.

iReport for default don't store connection passwords. If you want store it, you must first check the "Save password" checkbox. Press the "Save" button to definitly store the connection in the iReport connections pool.


4.3 Setting up a custom datasource

I will not bore to you with other basic slight notions on which button you must press in order to execute what is written on it...
If you have not, read the previous paragraph that explains where put hands to create a new datasource/connection. You only should to kwnow that you can choose the type of your datasource selecting it by the combobox in the connection frame.
When you have filled all fields, test it with the test button.


In this session we have created a simple report, saved as XML file, compiled as jasper file, filled with an "EmptyDataSource" end exported in PDF.


4.4 Implementing a new custom datasource

This topic is more a JasperReports releated argument, than an iReport feature explanation. But I think that can be useful know how you can develope your custom data driver (alias JRDataSource).
We will write a very simple JRDataSource that retrive fields from a CSV file. A CSV file is a text file that contains a set row. Any row contains a cartain number of fields separated by a special character (i.e. teh semicolon ';').
What must do our datasource is retrive this rows and return the right value to JasperReport when it ask for a fields (or column). What we have to do is implement this very simple interface:

package dori.jasper.engine;

public interface JRDataSource
{
public boolean next() throws JRException;
public Object getFieldValue(JRField jrField) throws JRException;
}

A JRField is a vary simple class to. It contains the name of the field (a String), and the java Class that represents the type of this field. In our case all fields are of type String, but we can choose to use as field name (alias the column name) the values of the first row of our cvs file or a generic name as COLUMN_1, COLUMN_2, ... This is the same way used by JasperReport in implementation of the TableModel wrapper datasource, that can indifferently use as column name the value of the column header (if present) or the special name COLUMN_<n> with n in the set {0,1,2,3,...,k}.
We'll use fixed names to refer columns in our datasource (COLUMN_1, COLUMN_2, ...).
This is the code:

1   
2   
3   import java.io.*;
4   import java.util.*;
5   
6   public class JRCSVDataSource implements dori.jasper.engine.JRDataSource {
7       
8       String row = "";
9       LineNumberReader lineNumberReader;
10      
11      /** Creates a new instance of JRCVSDataSource */
12      public JRCSVDataSource(String cvsFile) {
13          try {
14              lineNumberReader = new LineNumberReader( new FileReader(cvsFile));
15          } catch (Exception ex) { }
16      }
17      
18      public Object getFieldValue(dori.jasper.engine.JRField jRField) throws dori.jasper.engine.JRException {
19          String field = jRField.getName();
20          int fieldPosition = Integer.parseInt(field.substring(7)); // Strip COLUMN_ 
21          StringTokenizer st = new StringTokenizer(row,";");
22          while (st.hasMoreTokens())
23          {
24              fieldPosition--; // The column is not 0 indexed.
25              String token = st.nextToken();
26              if (fieldPosition == 0) return token;
27          }
28          return null; // Column not found...
29      }
30      
31      public boolean next() throws dori.jasper.engine.JRException {
32          try {
33              row = lineNumberReader.readLine();
34              if (row.length()>0) return true;
35          } catch (Exception ex) { }
36          return false;
37      }   
38  }
How you can see, only 38 lines of code... It's time to test it...
We'll write a little "JRDataSourcFactory" in order to use it with iReport. This factory will instance a JRCSVDataSource and will return it with the static method: getTheDatasource()
1   package it.businesslogic.ireport.connection;
2   
3   public class CSVDatasourceTestFactory {
4       
5       public dori.jasper.engine.JRDataSource getTheDatasource( )
6       {
7           return new JRCSVDataSource("test.csv");
8       }
9   }
10  
Open iReport, create a new custom JRDataSource connection and fill all fields as in Fig. 4.6, test and save the connection.
Fig.4.6: The new CSV datasource connection.

Now go to Build > Set active connection and select our new connection ("CSV Datasource (test.csv)")
Fig.4.7: Set the active connection.
This is the result. We'll soon learn how to create the trial report used to test our datasource.
Fig.4.8: The result print.
Posted by 1010
53.jasper&ireport2012. 1. 19. 15:29
반응형
Posted by 1010
53.jasper&ireport2012. 1. 19. 15:22
반응형
Posted by 1010
53.jasper&ireport2012. 1. 19. 15:15
반응형

Jaspersoft iReport: How to pass a parameter to a sub-dataset


Jaspersoft iReport: How to pass a parameter to a sub-dataset

Let’s say our main report is grouped by continent and the details band holds sales figures for each country. We would like to add now a pie chart to the group footer to visualize the share by product by continent.


Imagine our main report query is:

SELECT
product_sales.`continent` AS product_sales_continent,
product_sales.`city` AS product_sales_city,
product_sales.`product` AS product_sales_product,
product_sales.`sales` AS product_sales_sales
FROM
`product_sales` product_sales
ORDER BY
1, 2, 3

To add a sub-dataset right click on the report root element and choose New Dataset:
Follow the wizard instructions and insert a query. In our imaginary case it is something like this:

SELECT
product_sales.`product` AS product_sales_product,
SUM(product_sales.`sales`) AS product_sales_sales
FROM
`product_sales` product_sales
GROUP BY 1
ORDER BY 1

You must have noticed that there is something missing: This is of course not our final query, we want to restrict the results by continent. In order to do that, we have to first pass the parameter to the sub-dataset.

Now let’s have a look at how this is done:
  1. Create the parameter within the sub-dataset: Give it a name in the properties panel and make sure that the parameter class is the same as for the parameter that you want to pass from the main query. Also, untick Use as a prompt:
  2. Now add a chart to the design area. Right click on it and choose Chart Data:
  3. Specify all the standard settings for the chart (Connection etc), then click on Parameters and Add. From the top pull down menu Dataset parameter name choose the sub-dataset parameter we just created before. Click on the button next to Value expression: You can now choose from the parameters, fields and variables of the main dataset. In our case, we just choose the continent field:
    Apply, Click Apply, OK, and Close.
  4. Now we can finally change our SQL query in a way that it looks like we originally intended it to be. Therefore, right click on the dataset and choose Edit Query:
    Now add a WHERE clause to the query like this one:WHERE
    product_sales.`continent`=

    From the right hand side, you can
    drag over the parameter. It should then look like this:OK.


For your reference, please find the whole last SQL query below:
SELECT
product_sales.`product` AS product_sales_product,
SUM(product_sales.`sales`) AS product_sales_sales
FROM
`product_sales` product_sales
WHERE
product_sales.`continent`=$P{CONTINENT_CHART}

GROUP BY 1
ORDER BY 1

Now everything will be working as intended. The parameter will now be passed from the main report to the chart (which is kind of a hidden sub-report). This method works for Lists, Tables and Crosstabs as well.

Posted by 1010