본문 바로가기

닷컴's_열공/JAVA

RSS Writer 컴포넌트 만들기 - 자바

 

그럼, 이번 시간에는 지난 시간에 이어서(사실은 별개적인 내용으로 볼 수도 있습니다만) Rss 작성기를 만들어 보도록 하겠습니다. 클래스의 설계구조는 아마도 다들 비슷하지 않을까 싶네요. 저의 경우는 일반 문자열 결합을 통해서 XML 파일을 생성하는 것 보다는(비록 그것이 성능면에서 상대적으로 낫다해도) XmlTextWriter 클래스를 사용해서 좀 더 확실하게 XML 파일을 작성하는 쪽으로 방향을 잡았습니다. 여러분도 그렇게 방향을 잡으신 것이라면, "우리는 친구~~~" 인 것입니당당당.. 샤바방~~

저는 기본적으로 개발자가 RSS로 작성하고 싶은 항목들을 일단 RssWriter 메모리 상에 적재한 다음에, 특정 메서드를 호출하면 그때까지 메모리에 쌓여있던 모든 데이터를 RSS로 좌악~ 만들어서 출력해주는 식으로 동작하게 만들려 합니다.

출력의 형태는 2가지를 생각하고 있는데요. 하나는 Response 응답 그 자체이구요. 다른 하나는 XML 파일로써 서버에 생성되게 할까 합니다. 두 가지 형태 모두 매우 자주 사용되는 형식이니까요 ^^

RssWriter 클래스는 기존 RssChannel 클래스와 RssItems 클래스도 사용합니다. 그들의 개체 인스턴스를 만들어서, RSS로 작성하고자 하는 데이터를 일단 메모리 상의 그 개체들에다가 적재시킬 것이니까요. ^^

말보다 직접 보면서 설명드리는 것이 이해하기에 나을 듯 합니다. 다음 클래스 시그너처들을 한번 봐주시겠어요? 실제 구현부는 생략했구요(이건 잠시 뒤에 보여드리겠습니다) 골격만 일단 같이 확인해 보겠습니다.

    public class RssWriter
    {
        RssChannel channel;
        RssItems rssItems;

        public RssWriter()

        public RssChannel Channel
        public RssItems Items

        public void SaveToResponse(System.IO.Stream stream)
        public void SaveToFile(string path)

        public void AddChannel(string title, Uri link, string description...)
        public void AddItem(string author, string category, string title...)

        private XmlTextWriter WriteChannel(XmlTextWriter writer, RssChannel channel)
        private XmlTextWriter WriteItem(XmlTextWriter writer, RssItem item)
        private XmlTextWriter WriteFooter(XmlTextWriter writer)
    }

클래스에서는 보시다시피 필드로써 하나의 RssChannel 개체와 RssItems 컬렉션 클래스를 정의하고 있습니다. 그리고, 이 개체들의 초기화는 생성자에서 해 주고 있구요(그 코드는 여기서는 보이지 않지만요~). 그리고, 이 각각의 개체에 접근할 수 있도록 하기 위해서, Channel과 Items 라는 공개 속성을 노출시키고 있습니다. 해서, RssWriter 사용자는 이 속성들을 통해서 각각의 개체에 접근할 수가 있는 것이지요. RSS용 데이터를 작성하기 위해서는 공개 메서드인 AddChannel과 AddItem을 사용할 수 있습니다. 이 메서드들은 개발자가 인자로 지정한 데이터를 가지고, 메모리 상의 RssChannel 개체와 RssItems 컬렉션 클래스에 데이터를 적재하는 역할을 하게 됩니다.

만일, 개발자가 필요한 모든 데이터를 AddChannel과 AddItem 메서드를 이용해서 적재했다면, 작업을 완료하기 위해서 SaveToResponse 메서드나 SaveToFile 메서드를 호출할 수 있습니다. 이 메서드는 내부적으로, WriteChannel, WriteItem, WriteFooter라는 전용 메서드를 호출하는데요. 이 각각의 Write 메서드들은 메모리상에 존재하는 데이터들을 실제 XmlTextWriter 개체로 작성하는 역할을 수행합니다.

두 메서드(SaveToResponse와 SaveToFile)의 차이점이라면, 전자는 Response 개체로 데이터를 내려보내고, 후자는 실제 파일로써 로컬 디렉터리에 XML 파일을 생성한다는 것이 차이입니다.

대략적인 구성이 이해가 되시는지요? 크게 어렵지는 않으시죠?? 물론, 뭐~ 이러한 구성이 가장 올바른 구성이라고 말할 수는 없을 것입니다. 목적에 따라 구성은 달라질 수 있죠. 하지만, 제 생각에는 이러한 형태가 가장 일반적인 형태가 아닌가 싶네요. ^^;;

그럼, 이제 설명드린 내용을 참고하시면서 구체적인 코드를 한번 보실까요?

using System;
using System.Collections;
using System.ComponentModel;
using System.IO;
using System.Xml;
using System.Text;

    public class RssWriter
    {
        RssChannel channel;
        RssItems rssItems;

        public RssWriter()
        {
            channel = new RssChannel();
            rssItems = new RssItems();
        }

        public RssChannel Channel
        {
            get    {    return channel;    }
            set    {    channel = value;    }
        }

        public RssItems Items
        {
            get    {    return rssItems;    }
            set    {    rssItems = value;    }
        }

        public void SaveToResponse(Stream stream)
        {
            XmlTextWriter writer = new XmlTextWriter(stream, Encoding.GetEncoding(949));
            WriteChannel(writer, channel);

            foreach(RssItem item in rssItems)
                WriteItem(writer, item);

            WriteFooter(writer);

            writer.Flush();
            writer.Close();
        }

        public void SaveToFile(string path)
        {
            XmlTextWriter writer = new XmlTextWriter(path, Encoding.GetEncoding(949));
            WriteChannel(writer, channel);

            foreach(RssItem item in rssItems)
            {
                WriteItem(writer, item);
            }

            WriteFooter(writer);

            writer.Flush();
            writer.Close();
        }

        public void AddChannel(string title, Uri link, string description, string language, string copyright, DateTime lastBuildDate)
        {
            channel.Title = title;
            channel.Link = link;
            channel.Description = description;
            channel.Language = language;
            channel.Copyright = copyright;
            channel.LastBuildDate = lastBuildDate;
        }

        public void AddItem(string author, string category, string title, Uri link, DateTime pubdate, string description)
        {
            RssItem item;

            item.Author = author;
            item.Category = category;
            item.Title = title;
            item.Link = link;
            item.Pubdate = pubdate;
            item.Description = description;

            rssItems.Add(item);
        }

        private XmlTextWriter WriteChannel(XmlTextWriter writer, RssChannel channel)
        {
            writer.WriteStartDocument();
            writer.WriteComment("RSS generated by TaeyoNet RssGen v1.0 on " + DateTime.Now.ToString("r"));
            writer.WriteStartElement("rss");
            writer.WriteAttributeString("version","2.0");

            writer.WriteStartElement("channel");
            writer.WriteElementString("title", channel.Title);
            writer.WriteElementString("link", channel.Link.ToString());
            writer.WriteElementString("language", channel.Language);
            writer.WriteElementString("description", channel.Description);
            writer.WriteElementString("copyright", channel.Copyright);
            writer.WriteElementString("lastBuildDate", channel.LastBuildDate.ToString("r"));

            return writer;
        }

        private XmlTextWriter WriteItem(XmlTextWriter writer, RssItem item)
        {
            writer.WriteStartElement("item");
            writer.WriteElementString("author", item.Author);
            writer.WriteElementString("category", item.Category);
            writer.WriteElementString("title", item.Title);
            writer.WriteElementString("link", item.Link.ToString());
            writer.WriteElementString("pubDate", item.Pubdate.ToString("r"));
            writer.WriteElementString("description", item.Description);

            writer.WriteEndElement();
            return writer;
        }

        private XmlTextWriter WriteFooter(XmlTextWriter writer)
        {
            writer.WriteEndElement();
            writer.WriteEndElement();
            writer.WriteEndDocument();

            return writer;
        }
}

소스에서 크게 어려운 부분은 없지 않나 하는 생각입니다만... 어떠세요? 만일, 소스가 어렵게 느껴지신다면, 그것은 아마도 XmlTextWriter 클래스의 사용법에 익숙하지 못해서 그런 것이 아닐까 싶네요 ^^. XmlTextWriter 클래스에 대해서 더 많은 것을 알고 싶으시다면, MSDN을 참고해 주세요. XmlTextWriter 클래스의 멤버들 중 WriteStartElement, WriteElementString, WriteEndElement 메서드들을 집중적으로 살펴보시면 될 것 같습니다. ^^ (클릭! XmlTextWriter 클래스)

자~ 이제 클래스가 완성되었으면 컴파일 및 빌드를 해 봐야겠죠? 오타가 없다면 문제없이 빌드될 것입니다. 이 RssWriter 클래스는 기존의 RssReader 클래스와 같은 네임스페이스인 TaeyoWebLib안에 속할 것입니다. 강좌대로 따라오셨다면, 이미 그렇게 되어져 있겠죠?

좋습니다. 빌드를 해서 DLL이 만들어 졌다면, 이제 이 클래스를 한번 사용해 보도록 하겠습니다. 새롭게 테스트를 위한 웹 폼 페이지를 하나 만들어 보도록 하겠습니다. 저는 RssWriterTest.aspx 라는 이름의 aspx 페이지를 만들어 보았습니다.

물론, 기존 RssReader때와 마찬가지로, 현재의 웹 프로젝트는 TaeyoWebLib.dll을 프로젝트에서 참조하고 있어야 하고, using TaeyoWebLib를 통해서 네임스페이스가 임포트되어 있어야 할 것입니다. 아마도 전 강좌에서 그렇게 해 두셨을테니 이번의 경우는 네임스페이스만 임포트하시면 될 것 같네요 ^^

그렇다면, 이제 RssWriterTest.aspx 페이지의 Page_Load 이벤트 처리기 구역을 작성해 볼까요? 저의경우는 다음과 같이 간단하게만 해보았습니다

    private void Page_Load(object sender, System.EventArgs e)
    {
        RssWriter wr = new RssWriter();

        wr.Channel.Title = "Taeyo 사이트 최근 강좌 목록";
        wr.Channel.Link = new Uri("http://www.taeyo.net");
        wr.Channel.LastBuildDate = DateTime.Now;

        RssItem item;
        item.Author = "김태영";
        item.Category = "닷넷";
        item.Link = new Uri("http://www.taeyo.net/Lecture/NET/RssEx02.asp");
        item.Title = "RSS Reader 컴포넌트 만들기";
        item.Pubdate = DateTime.Now;
        item.Description = "자세한 설명은 링크를 통해서 확인하세요";
        wr.Items.Add(item);

        item.Author = "김태영";
        item.Category = "닷넷";
        item.Link = new Uri("http://www.taeyo.net/Lecture/NET/RssEx01.asp");
        item.Title = "RSS란?";
        item.Pubdate = DateTime.Now;
        item.Description = "자세한 설명은 링크를 통해서 확인하세요";
        wr.Items.Add(item);

        wr.SaveToResponse(Response.OutputStream);
        Response.ContentType = "text/xml";
        Response.End();
    }

혹은, 메서드를 이용해서 다음과 같이 간단하게 작성할 수도 있습니다.

    private void Page_Load(object sender, System.EventArgs e)
    {
        RssWriter wr = new RssWriter();

        wr.AddChannel("Taeyo 사이트 최근 강좌 목록", new Uri("http://www.taeyo.net"),
                "태오 사이트 최근강좌의 목록입니다", "ko-KO", "태오사이트", DateTime.Now);

        wr.AddItem("김태영", "닷넷", "RSS Reader 컴포넌트 만들기",
                new Uri("http://www.taeyo.net/Lecture/NET/RssEx02.asp"), DateTime.Now,
                "자세한 설명은 링크를 통해서 확인하세요");
        wr.AddItem("김태영", "닷넷", "RSS란?",
                new Uri("http://www.taeyo.net/Lecture/NET/RssEx01.asp"), DateTime.Now,
                "자세한 설명은 링크를 통해서 확인하세요");

        wr.SaveToResponse(Response.OutputStream);
        Response.ContentType = "text/xml";
        Response.End();
    }

위의 두 소스는 다음과 같이 정확하게 동일한 결과를 만들어내게 됩니다. 그리고, 그 결과화면은 다음과 같을 것입니다!!

멋지죠?

이제 여러분은 데이터베이스로부터 데이터를 가져와서 RssWriter를 이용해서 RSS를 꾸밀 수도 있고, 아니면, 위에서 한 것처럼 수동으로 데이터를 채워넣어서 RSS를 구성할 수도 있을 것입니다. 주로, 데이터베이스에서 데이터를 가져와서 동적으로 RSS를 꾸미는 경우가 더 많겠지만 말이죠~~

이로써 3회에 걸쳐서 RSS 컴포넌트 만들기를 같이 해 보았는데요. 전에도 말씀드렸다시피, 이것은 심플 버전에 불과합니다 여러분의 상황과 요구조건에 따라 이 컴포넌트는 더더욱 많은 기능으로 무장될 수도 있을 겁니다. 그것은 이제부터 여러분이 하셔야 하는 부분이 되겠죠?

태오닷넷 사이트로의 업그레이드 작업과 Microsoft 세미나 준비등의 여러 바쁜 일과로 인해서 (밤에는 애기가 울구.. ㅠㅠ) 강좌가 자주 업데이트 되지 못한 점 대단히 죄송스럽게 생각합니다.