'Java'에 해당되는 글 26건

  1. 2012.05.24 Java Servlet과 jQuery를 이용한 환율정보(from 네이버) 가져오기 6
  2. 2011.11.24 Java 에서 문자열 비교할때 equals() 말고 == (비교연산자) 로 비교하기 1
  3. 2011.11.24 Java에서 파일로 부터 데이터 읽어서 정렬(bubble sort)하기
  4. 2011.11.23 xpath 를 이용, java 에서 xml 문서 쉽게 파싱하기 5
  5. 2011.11.16 재귀함수(Recursive funtion)을 이용한 특정 폴더 아래의 모든 파일정보 읽어서 출력하기

Java Servlet과 jQuery를 이용한 환율정보(from 네이버) 가져오기



요런걸 해도 되는진 모르긋지만 재미삼아서 한번 만들어 보았다.


환율정보를 가져오는 OpenAPI 를 한번 디벼 보았지만 별로 신통한게 없어서 네이버 메인 훌래쉬에서 땡겨다 쓰는 환율정보 XML 을 써보기로 했다.



네이버 메인화면 오른쪽에 보면 여러가지 정보를 제공하는 위젯 훌래쉬가 보인다.




위젯 훌래쉬 메뉴 중에 고맙게도 "환율" 이라는 메뉴가 있어서 한번 클릭해 보았다. 우리나라 통화를 기준으로 다른 여러나라들의 환율정보를 보여준다.


대부분의 훌래쉬는 데이터를 외부 url 에 있는 xml 파일같은걸로 땡겨오는데


네이버 메인 훌래쉬를 한번 분석해 보니깐 환율정보는 http://www.naver.com/include/timesquare/widget/exchange.xml 요기에서 땡겨오고 있었다.


넘어오는 xml 구조를 보기 위해서 죠 주소를 브라우져 주소창에 입력해 보았다. 하지만 찾을 수 없는 페이지라고만 딸랑 뜬다.



왜 그럴까 하고 고민하다 그냥 구글에게 물어보기로 하고 뽓 물어보니 HTTP 요청할때 헤더값중 이전에 머물렀던 URL 을 뜻하는 Referer 의 값이 naver.com 도메인에 속한 URL 이어야 한다는 것이였다.


역시 분명히 될것 같은데 안될때는 뻘짖하지 말고 구글에 물어보는게 제일 빠른것 같다.


그렇다면 요런식으로 Referer 헤더를 살 바꿔서 호출해야 한다. 인터넷에 있는 예제는 PHP 용 밖에 없는것 같다.

Java 로 할려면 요런 코드를 쓰면 된다.

URLConnection conn = new URL("http://www.naver.com/include/timesquare/widget/exchange.xml").openConnection();
conn.addRequestProperty("Referer", "http://www.naver.com");



Java 어플리케이션에서만 쓸려면 그냥 저렇게 xml 을 가져와서 xml 파싱후 원하는 데이터만 뽑아내서 쓰면 된다.


하지만 여기서 한걸음 더 나가 웹어플리케이션에서 데이터를 가져와서 html 로 보여주고 싶다. 


xml 가져와서 xml 문서를 리턴해주는 부분은 Java Servlet 으로 맹글고, jQuery ajax 요청으로 고 서블릿을 호출해서 데이터를 가져온 후 화면에 살 뿌려보자.



먼저 서블릿 소스

자기의 스타일에 맞게 바꿔 쓰면 된다. 말리진 않음.

package com.tistory.stove99;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CurrencyXmlServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

    public CurrencyXmlServlet() {
        super();
    }

	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		generateXML(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		generateXML(request, response);
	}
	
	private void generateXML(HttpServletRequest request, HttpServletResponse response){
		response.setContentType("text/xml");
		
		URLConnection conn = null;
		BufferedWriter bw = null;
		BufferedReader br = null;
		
		try{
			conn = new URL("http://www.naver.com/include/timesquare/widget/exchange.xml").openConnection();
			conn.addRequestProperty("Referer", "http://www.naver.com");
			
			br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
			bw = new BufferedWriter(response.getWriter());
			
			String line = null;
			while( (line=br.readLine())!=null ){
				bw.write(line);
			}
		}catch(Exception ex){
			
		}finally{
			try {bw.close();} catch (IOException e) {e.printStackTrace();}
		}
	}
}

web.xml 에 서블릿 맵핑

<servlet>
	<servlet-name>currencyServlet</servlet-name>
	<servlet-class>com.tistory.stove99.CurrencyXmlServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>currencyServlet</servlet-name>
	<url-pattern>/currency/xml</url-pattern>
</servlet-mapping>


만약 스프링 @MVC 로 하는 후로젝트라면 구찮게 저렇게 할 필요없이 딸랑 요런 메소드 하나면 위와 완전 똑같다.

@RequestMapping("/currency/xml")
@ResponseBody
public void currency(HttpServletResponse response) throws Exception{
	response.setContentType("text/xml");
	
	URLConnection conn;
	BufferedWriter bw;
	BufferedReader br;
	
	conn = new URL("http://www.naver.com/include/timesquare/widget/exchange.xml").openConnection();
	conn.addRequestProperty("Referer", "http://www.naver.com");
	
	br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
	bw = new BufferedWriter(response.getWriter());
	
	String line = null;
	while( (line=br.readLine())!=null ){
		bw.write(line);
	}
	
	bw.close();
}



이제 Servlet 을 다 했으니 쪽바로 땡겨오나 테스트를 해보자. 서버를 띄우고 주소창에 http://127.0.0.1:8080/currency/xml 을 뿍 입력해 보면


정상적으로 xml이 잘 뜬다. xml 태그들이 뜻하는거는 네이버 환율정보 화면을 비교해 보며 대충 때려 맞추길 바란다.






jQuery 를 이용한 데이터 파싱및 화면에 뿌리기 소스

<html>
<head>
	<script type="text/javascript" src="jquery-1.7.1.min.js"></script>
	
	<script>
		$(document).ready(function(){
			$.ajax({
				url : "/currency/xml",
				success : function(xml){
					xml = $(xml);
					
					xml.find("currency").each(function(){
						var tr = $("<tr><td/><td/><td/><td/></tr>");
						tr.find("td:eq(0)").text($(this).find("hname").text());
						tr.find("td:eq(1)").text($(this).find("standard").text());
						tr.find("td:eq(2)").text($(this).find("buy").text());
						tr.find("td:eq(3)").text($(this).find("sell").text());
						
						$("#currencyResult tbody").append(tr);
					});
				}
			});
		});
	</script>
</head>

<body>
	<table id="currencyResult" border="1">
		<colgroup>
			<col width="25%"/>
			<col width="25%"/>
			<col width="25%"/>
			<col width="25%"/>
		</colgroup>
		<thead>
			<tr>
				<th></th>
				<th>매매기준</th>
				<th>현찰살때</th>
				<th>현찰팔때</th>
			</tr>
		</thead>
		<tbody></tbody>
	</table>
</body>
</html>



출력 결과


Java 에서 문자열 비교할때 equals() 말고 == (비교연산자) 로 비교하기


왠지 도움이 될것 같다면 추천을 *(-_-)*


오늘 이클립스에서 작업하다 스트링 객체 다음에 . 을 찍고 뭐 쓸만한게 없나 문득 살펴봤다.

왠지 늘 쓰던거만 쓰면 재미없지 않은가! 뭐 재미진 메소드가 없나 하는 요런 마음?


고러던 와중 그동안 즌혀 관심 1g 조차 없었던 intern() 이라는 메소드가 보였다.

이클립에서 뽓 튀어 나오는 설명을 대충 쪽 읽어보니 == 으로 스트링이 똑같은지 비교를 해주게 하는것 같았다.



뭐! 요런게 있었던 말이가! 하면서 요즘 나온 JAVA7 에 새로 추가된 메소드 인가 하고 API 를 찾아보니 JDK 1.3 부터도 있었던 메소드였다 -_-;;

아무튼 요 메소드를 쓸 일은 거의 1% 미만이지만 왠지 재미진것 같으니깐 알아는 둬야지

대충 요딴식으로 사용한다.
String a = new String("3269");
String b = new String("3269");

System.out.println(a == b);    // false

System.out.println(a.intern() == b);    // false

System.out.println(a.intern() == b.intern());    // true



음 막상 코드를 작성하고 나서 보니 "3269".equals(a); 가 훨씬 더 좋구나 라고 생각이 든다 -_-;  분명히 무슨 용도가 있기 때문에 맹근 메소드일껀데 아직까진 그 용도가 잘 파악이 안된다.


※ 비교연산자는 == 요것만 되는것 같다 < , > 요런건 안됨. 컴파일 에러남 

Java에서 파일로 부터 데이터 읽어서 정렬(bubble sort)하기


왠지 도움이 될것 같다면 추천을 *(-_-)*


학교에서 내주는 숙제용 소스코드이다.

자바 기본 라이브러리로 있는 ArrayList 와 Collections.sort() 를 이용하면

임시 배열에 읽었다가 복사하고 꾸리한 버블정렬을 할 필요없이 간결한 코드를 맹글 수 있지만, 이건 숙제용이니깐~

그래도 약간 배울만한 점은 Scanner 클래스의 새로운 발견이랄까?

Scanner 는 주로 System.in 에서 사용자로 부터 뭔가를 입력받는 용도로 많이들 쓸 건데,

여기서는 File 에서 데이터를 읽는 용도로 썼다. InputStream 이나 Reader 계열로 뭔가를 읽는 코드보다 간결해서 좋은것 같다.

요거는 앞으로 Stream 에서 뭔가를 읽고 싶을때 어째 잘 써먹도록 해야 겠다. 




소스코드
import java.io.File;
import java.util.Scanner;

public class FileSort {
	public static void main(String[] args) throws Exception {
		Scanner scan = new Scanner(new File("c:\\numbers.dat"));

		float[] arr = new float[100];
		int cnt = 0;

		// numbers.dat 파일읽기
		while (scan.hasNext()) {
			arr[cnt++] = scan.nextFloat();
		}

		// 읽혀진 숫자 갯수만큼 배열을 생성해서 복사
		float[] numbers = new float[cnt];
		System.arraycopy(arr, 0, numbers, 0, cnt);

		// 버블정렬
		bubbleSort(numbers);

		// 배열 출력
		for (float num : numbers) {
			System.out.println(num);
		}
	}

	// 내림차순 버블 소트
	public static void bubbleSort(float[] arr) {
		int n = arr.length;
		for (int pass = 1; pass < n; pass++) {
			for (int i = 0; i < n - pass; i++) {
				if (arr[i] < arr[i + 1]) {
					float temp = arr[i];
					arr[i] = arr[i + 1];
					arr[i + 1] = temp;
				}
			}
		}
	}
}


내림차순으로 바꾸고 싶을때는 if (arr[i] < arr[i + 1]) 요기에서 요렇게 부등호 방향만 바꿔주면 된다. if (arr[i] > arr[i + 1]) {


사용된 numbers.dat 파일


xpath 를 이용, java 에서 xml 문서 쉽게 파싱하기

xpath 를 이용할수 있다는 걸 알기전에는 무식하게도 Document 클래스의 getElementById() 나 getElementsByTagName() 메소드를 이용해서 

상당히 무식하게 난해한 코드로 xml 을 파싱하곤 했었다 -_-



어느날 문득 xpath 에 대해서 살짝 알게되고 나서 부터는 전에 쓰던 방법에 비해서는 아주 간결하고 이해하기 쉬운 코드로 xml 에서 원하는 데이터를 땡겨다 쓰는게 훨씬 수월해 졌다.




※ xpath 문법에 대해서 왠만한걸 쉽게 파악하기 위해서는 요 사이트에 가면 된다.

http://www.zvon.org/xxl/XPathTutorial/General/examples.html

요기 가서 보면 알겠지만 쉽게 쉽게 설명되있다.

xpath 만 어느정도 쓸 수 있으면 xml 에서 원하는 데이터를 땡겨오는건 매우 쉬워지니 살짝 한번 연구해 보는걸 추천한다.





xpath를 이용해서 xml 에서 원하는 데이터를 파싱하는 예제코드를 작성해 보았다.

xpath 를 사용하기 위해서 별다로 다른 라이브러리를 classpath 에 추가 안해도 된다.




예제 코드에서 사용된 xml
<root>
	<row>
		<col1 id="c1">값1</col1>
		<col2 id="c2" val="val2">값2</col2>
	</row>
	<row>
		<col1 id="c3">값3</col1>
		<col2 id="c4">값4</col2>
	</row>
</root>



예제 코드는 다음과 같다.
import java.io.StringReader;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;


public class XPathTest{
	public static void main(String[] args) throws Exception {
		String xml = "<root><row><col1 id='c1'>값1</col1><col2 id='c2' val='val2'>값2</col2></row>" + 
                             "<row><col1 id='c3'>값3</col1><col2 id='c4'>값4</col2></row></root>";
		
		// XML Document 객체 생성
		InputSource is = new InputSource(new StringReader(xml));
		Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);

		// 인터넷 상의 XML 문서는 요렇게 생성하면 편리함.
		//Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder()
		//                               .parse("http://www.example.com/test.xml");
		
		
		
		// xpath 생성
		XPath xpath = XPathFactory.newInstance().newXPath();
		

		
		
		// NodeList 가져오기 : row 아래에 있는 모든 col1 을 선택
		NodeList cols = (NodeList)xpath.evaluate("//row/col1", document, XPathConstants.NODESET);
		for( int idx=0; idx<cols.getLength(); idx++ ){
			System.out.println(cols.item(idx).getTextContent());
		}
		// 값1   값3  이 출력됨
		
		
		
		
		
		// id 가 c2 인 Node의 val attribute 값 가져오기
		Node col2 = (Node)xpath.evaluate("//*[@id='c2']", document, XPathConstants.NODE);
		System.out.println(col2.getAttributes().getNamedItem("val").getTextContent());
		// val2 출력
		
		
		
		
		
		// id 가 c3 인 Node 의 value 값 가져오기
		System.out.println(xpath.evaluate("//*[@id='c3']", document, XPathConstants.STRING));
		// 값3 출력
	}
}


전에 getElementById(), getElementsByTagName() 요걸 쓰던 코드에 비하면 코드도 쉽게 읽히고 심플하기도 서울역에 그지없다.

앞으로 xml 파싱할때는 xpath 를 주로 써야겠다.



※ evalueate() 메소드 맨 끝에 들어가는 파라메터로

XPathConstants.NODESET
XPathConstants.NODE
XPathConstants.BOOLEAN
XPathConstants.NUMBER


재귀함수(Recursive funtion)을 이용한 특정 폴더 아래의 모든 파일정보 읽어서 출력하기


왠지 도움이 될것 같다면 추천을 *(-_-)*


이런건 학교 뎅길때 숙제로 많이 하던것이다.

복잡해 보이는 문제도 이빠이 작은 부분으로 쪼개서 생각하고 고걸 recursive funtion 화 시키면 쉽게! 심플하게! 문제를 해결할 수 있다.



요 문제의 경우, 작게 쪼개서 생각할만한 부분은

어떤 디렉토리가 있으면 그 디렉토리 안에 있는 디렉토리들과 파일들을 출력할래염!!! 이다.

디렉토리의 디렉토리 안에 있는 또 다른디렉토리와 또 그 많은 파일을의 출력에 대해서는 생각하지 않는다.

어떤 디렉토리가 있으면 그 디렉토리 안에 있는 디렉토리들과 파일들을 출력할래염!!!에 대해서 recursive function 을 맹글면 된다.



어렴풋이 생각나는 학창시절의 배움을 더듬어 보면 그냥 쌩으로 for 문을 써서 하는게 속도면에서는 훨씬 빠르다.(그런데 코드는 훨씬 복잡해질것이다.)

하지만 요즘 컴퓨터는 그때의 컴퓨터가 아니다. 나는 컴퓨터를 믿는다. *(-_-)*



성능이 매우매우매우매우매우 중요할 때에는 recursive function 을 쓰면 안되겠지만 그럴 경우가 아니면야 가독성 있는 코딩을 할 수 있는 방법이 훨씬 좋다고 생각한다.




잡소리는 고만하고, source!
package com.tistory.stove99;

import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

public class FileListExporter {
	private StringBuffer sb = new StringBuffer();
	private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

	String targetDir; // 리스팅할 대상 디렉토리
	File outputFile;  // 결과를 출력할 파일

	public FileListExporter(String targetDir, File outputFile) {
		this.targetDir = targetDir;
		this.outputFile = outputFile;
	}

	public void export() {
		// StringBuffer 로 파일정보 싹 읽어 들이기
		traversDir(new File(targetDir), 0);

		// 파일로 출력
		PrintWriter pw = null;
		try {
			pw = new PrintWriter(outputFile);
			pw.append(sb);
			pw.flush();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} finally {
			if (pw != null)
				pw.close();
		}
	}

	// recursive funtion
	private void traversDir(File dir, final int level) {
		dir.listFiles(new FileFilter() {

			public boolean accept(File file) {
				String modified = sdf.format(new Date(file.lastModified()));

				// 탭처리 해서 트리처럼 보이게 하기
				for (int idx = 0; idx < level; idx++) sb.append("\t");

				if (file.isDirectory()) {
					sb.append(String.format("%-35s <dir> %s", file.getName(), modified))
						.append("\r\n");
					traversDir(file, level + 1);
				} else {
					sb.append(String.format("%-35s %d %s", file.getName(), file.length(), modified))
						.append("\r\n");
				}

				return false;
			}

		});
	}

	// test
	public static void main(String[] args) {
		new FileListExporter("C:\\Program Files", new File("c:\\list.txt")).export();
		System.out.println("export end");
	}
}


파일 출력하는것 때문에 코드가 약간 길어지긴 했는데 딱 보면 코드가 그렇게 길지도 않다. 요런 짧으면서도 이해가 뽓 잘되는 코드를 맹글수 있다는게 recursive funtion의 매력인것 같다 *(-_-)*

요걸 뽓 실행해 보면 C 드라이브에 요런 list.txt 파일이 생성된다.


 
prev 1 2 3 4 5 6 next