Post View

Spring에서 jdom을 이용한 RSS 출력하기

이번에는 블로그의 RSS(https://www.kurien.net/rss)를 만들어보았습니다.

RSS는 Rich Site Summary의 약자로 뉴스기사나 블로그의 컨텐츠만을 다로 모아서 보여주는 XML 형태의 포맷입니다.
RSS가 없으면 일부 검색엔진 측에서 글을 검색하는 경우 링크를 타고 이동하게 되는데, 이 과정에서 일부 글이 검색에서 누락되는 경우가 존재합니다.
하지만 RSS를 등록해두면 봇에게 글에 대한 정보를 더 상세히 전달할 수 있어 누락되는 현상이 개선된다고 합니다.
* 위 내용은 네이버의 Search Advisor에서 얻은 정보이므로 검색엔진에 따라 다를 수 있습니다.

비슷한 역할을 하는 Sitemap.xml이란 것도 존재하지만 아직 제작이 안되어있으므로 먼저 RSS를 출력하는 방법부터 알아보겠습니다.

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>사이트 이름</title>
    <link>http://www.example.com/</link>
    <description>사이트 설명</description>
    <item>
      <title>콘텐츠 게시글 1</title>
      <link>http://www.example.com/article-1.html</link>
      <description>글 내용 전체(또는 일부)</description>
      <pubDate>발행시간</pubDate>
      <guid>http://www.example.com/article-1.html</guid>
    </item>
    <item>
      <title>콘텐츠 게시글 2</title>
      <link>http://www.example.com/article-2.html</link>
      <description>글 내용 전체(또는 일부)</description>
      <pubDate>발행시간</pubDate>
      <guid>http://www.example.com/article-2.html</guid>
    </item>
  </channel>
</rss>

위의 코드는 네이버 Search Advisor에서 제공하는 RSS 예제입니다.
channel element 아래 있는 title, link, description element들은 홈페이지 자체의 정보를 나타내고, 그 아래 있는 item element에 있는 정보는 RSS를 통해 배포될 각 글들의 정보가 담기게 됩니다.

XML을 직접 만들어서 출력할 수도 있겠지만 매번 포스팅마다 수정할 수는 없는 노릇이니 자동으로 최신 글이 출력되도록 만들어봅시다!
먼저 pom.xml에 dependency를 추가합니다.

<!-- https://mvnrepository.com/artifact/org.jdom/jdom2 -->
<dependency>
    <groupId>org.jdom</groupId>
    <artifactId>jdom2</artifactId>
    <version>2.0.6</version>
</dependency>

gradle을 이용하시는 분은 https://mvnrepository.com/artifact/org.jdom/jdom2/2.0.6를 통해 gradle의 dependency 정보도 확인 가능합니다.

그럼 jdom을 사용해서 어떻게 처리하는지 보도록 하겠습니다.

@RequestMapping(value = "/rss", method = RequestMethod.GET, produces="application/xml;charset=utf-8")
public @ResponseBody String rss(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception {
	Criteria criteria = new Criteria(1, 500);

	List posts = postService.getList("N", criteria);

	SimpleDateFormat sdf = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.ENGLISH);

	Element root = new Element("rss");
	root.setAttribute(new Attribute("version", "2.0"));

	Element channel = new Element("channel");
	root.addContent(channel);

	channel.addContent(new Element("title").addContent(new CDATA("Kurien's Blog")));
	channel.addContent(new Element("link").setText("https://www.kurien.net/"));
	channel.addContent(new Element("description").addContent(new CDATA("Kurien's Blog는 프로그래밍과 개발 전반에 대한 내용을 다루는 블로그입니다.")));

	for(int i = 0; i < posts.size(); i++) {
		Element item = new Element("item");

		String link = "https://www.kurien.net/post/view/" + posts.get(i).getPostNo();

		item.addContent(new Element("title").addContent(new CDATA(posts.get(i).getPostSubject())));
		item.addContent(new Element("link").setText(link));
		item.addContent(new Element("description").addContent(new CDATA(posts.get(i).getPostContent())));
		item.addContent(new Element("pubDate").setText(sdf.format(posts.get(i).getPostWriteTime())));
		item.addContent(new Element("guid").setText(link));

		channel.addContent(item);
	}

	Document doc = new Document();
	doc.setRootElement(root);

	Format f = Format.getPrettyFormat();
	f.setEncoding("UTF-8");
	f.setLineSeparator("\r\n");

	XMLOutputter outputter = new XMLOutputter(f);

	return outputter.outputString(doc);
}

먼저 postService의 getList 메서드를 통해 포스팅을 가져옵니다.
네이버 Search Console의 내용 중에 "RSS 피드 용량이 10MB 이상 넘어가는 경우 제출 할 수 없습니다."라는 문구가 있으니 xml을 작성하신 뒤 다운로드 받아보시고 10MB가 넘어간다면 한번에 출력하는 글의 수를 줄여주셔야 합니다.

그 다음 Element root = new Element("rss");로 root element를 생성하고 root.setAttribute(new Attribute("version", "2.0"));로 element의 속성을 추가합니다.
이제 root 역할을 하는 rss element가 만들었으니 addContent 메서드를 이용해서 해당 element 내부에 channel을 넣고, channel 내부에 title, link, description element를 추가합니다.

마찬가지로 item element도 channel element에 추가를 해야합니다.
postService에서 가져온 포스팅을 반복문을 통해 item element 내부로 넣어주고 channel element에 추가합니다.
배포일자(pubDate)의 경우에는 "Tue, 14 Apr 2020 01:08:22 +0900" 형태로 출력해주어야 하므로 SimpleDateFormat을 이용해서 처리해줍니다.
이 때, Locale을 Locale.ENGLISH로 지정해주어야 요일이 영문으로 나타납니다.

element 추가가 완료되었다면 마지막으로 화면에 실제 출력할 Document 정보를 지정합니다.
getPrettyFormat 메서드를 통해 기본적인 Format을 받아온 뒤 인코딩과 라인 구분자를 세팅하고 XMLOuputter를 통해 String으로 출력합니다.

그리고 리턴되는 문자열은 @RequestBody로 선언하고, @RequestMapping에는 produces="application/xml;charset=utf-8"를 추가하여 xml 형태로 인식되도록 처리하였습니다.

이제 해당 페이지(https://www.kurien.net/rss)를 접속해보면 정상적으로 출력됩니다.

저는 작업 이후 바로 RSS 경로를 등록해서 현재는 정상처리 되고 있답니다.

해당 로직은 https://github.com/kurien92/kreBlog/commit/e0b90c7cd2187a85720cb5cd82c159e1ff0e84b5에서 추가적으로 확인하실 수 있습니다.

Comments