0

Клиент для Blogger своими руками-3

В предыдущем посте я начал описывать создание программки, выдающей список постов данного блога. В прошлый раз задача оказалась решенной не до конца: написанная программка распечатывала неполный список. Прежде чем приступить к внесению изменений в смысловую часть программы (то есть перед тем, как добиваться от нее того, чего я хочу), я внесу некоторые изменения в процесс тестирования. В предыдущем варианте тест класса BlogEditor (функция main(String [])) находился в самом классе. Сейчас я решил, что мне будет удобнее разместить тесты в отдельном пакете, с названием test.
Имена тестовых пакетов будут повторять имена тестируемых, за исключением того, что тестовые пакеты будут начинаться со слова test, а тестирующие классы - со слова Test. Так, для пакета blogeditutil пакет тестов будет называться test.blogeditutil, а для класса BlogEditor тестирующий класс будет называться TestBlogEditor. Класс TestBlogEditor у меня будет содержать всего один метод - main(), тело которого я просто вырежу из исходного класса (из BlogEditor). Еще добавляю всякие внешние классы через директиву import, и конечно, добавляю тестируемый класс. В результате получается следующее:

package test.blogeditutil;
import com.google.gdata.client.*;
import com.google.gdata.data.*;
import com.google.gdata.util.*;
import java.io.*;
import javax.swing.*;
import java.util.*;
import blogeditutil.*;

class TestBlogEditor
{
public static void main(String args[]) throws IOException, ServiceException
{
BlogEditor bedit = new BlogEditor();
String blogname = JOptionPane.showInputDialog(null,
"For example, if blog addresss is lotrex.blogspot.com, input \"lotrex\"",
"Input name of blog");
System.out.println("Blog posts of " + blogname + ":");
List<Entry> postlist = bedit.getPostEntryList(blogname);
for(Entry p: postlist)
{
System.out.println("Post caption: " + p.getTitle().getPlainText());
System.out.println("Date and time: " + p.getPublished());
}
}
}

Этот текст сохраняю в файле TestBlogEditor.java. Было бы неплохо запускать тесты кучкой, и при этом видеть, какой тест не прошел. Я решил использовать для этого утилиту make. Создал в корневой директории моего проекта файл makefile со следующим содержимым:
JVM = java
JFLAGS = -cp .;.\gdata-core-1.0.jar -ea -esa
test:
$(JVM) $(JFLAGS) test.blogeditutil.TestBlogEditor >res.txt

Набираю в командной строке make, жму Enter, усе работает, как и раньше :)
Теперь можно возвращаться к самой программулине :)
Получить полный список постов довольно просто, для этого в тело метода getPostEntryList() достаточно вставить одну строку. Итак, изначально реализация метода getPostEntryList() выглядела следующим образом:

public List<Entry> getPostEntryList(String blogname)
throws IOException, ServiceException
{
String blog_id = getBloggerID("http://"+blogname+BLOGGER_SERVER);
if(blog_id == null)
throw new IOException("Can't get blogID for " + blogname+BLOGGER_SERVER);
//Запрос на получение постов:
Query query = new Query(new URL (BLOGGER_FEED + blog_id + POST_LOCATION));
return bservice.getFeed(query, Feed.class).getEntries();
}

Сначала создается объект класса запроса (класса Query), которому в качестве параметра передавался URL фида. После чего мы сразу обращались к серверу за данными. Но объекту класса Query можно задать кучу параметров, один из которых - максимальное количество результатов (считай-постов) в фиде. Если мы хотим сразу скачать всю ленту целиком, но не знаем, сколько в ней постов, то просто задаем в качестве максимального значения какое-нить число побольше. Новая реализация метода getPostEntryList() немногим отличается от старой:

private final int MAX_RESULTS = 10000000;
public List<Entry> getPostEntryList(String blogname)
throws IOException, ServiceException
{
String blog_id = getBloggerID("http://"+blogname+BLOGGER_SERVER);
if(blog_id == null)
throw new IOException("Can't get blogID for "+ blogname+BLOGGER_SERVER);
//Запрос на получение постов:
Query query = new Query(new URL (BLOGGER_FEED + blog_id + POST_LOCATION));
query.setMaxResults(MAX_RESULTS);
return bservice.getFeed(query, Feed.class).getEntries();
}

Сейчас результирующий список получился больше, чем в первый раз :) Во всяком случае, первый и последний посты в результирующем списке - те же самые, что и в блоге.
Помимо заголовков постов хотелось бы еще иметь возможность прочитать их содержимое. Содержимое поста (в виде текста) можно получить из того же источника, что его заголовок и дату публикации, ведь объект Entry по сути дела и есть сам пост. Немного модифицируем наш тест (файл TestBlogEditor.java):

class QueryBlogName
{
static String getBlogName()
{
return JOptionPane.showInputDialog(null,
"For example, if blog addresss is lotrex.blogspot.com, input \"lotrex\"",
"Input name of blog");
}
}

class TestBlogEditor
{
public static void main(String args[]) throws IOException, ServiceException
{
BlogEditor bedit = new BlogEditor();
String blogname = QueryBlogName.getBlogName();
List<Entry> postlist = bedit.getPostEntryList(blogname);
System.out.println("Blog posts of " + blogname + ":");
for(Entry p: postlist)
{
System.out.println("Post caption: " + p.getTitle().getPlainText());
System.out.println("Date and time: " + p.getPublished());
}
}
}
class TestBlogEditTextContent
{
public static void main(String args[]) throws IOException, ServiceException
{
BlogEditor bedit = new BlogEditor();
String blogname = QueryBlogName.getBlogName();
List<Entry> postlist = bedit.getPostEntryList(blogname);
System.out.println("Blog posts of " + blogname + ":");
for(Entry p: postlist)
{
System.out.println("-----------------------");
System.out.println("Post caption: " + p.getTitle().getPlainText());
System.out.println("Content:");
System.out.println(p.getPlainTextContent());
}
}
}

Теперь у меня есть 2 теста класса, которые выполняют разные действия. Добавлю в конец makefile еще одну строку, что бы он тоже выполнялся. Теперь содержимое makefile выглядит так:
JVM = java
JFLAGS = -cp .;.\gdata-core-1.0.jar -ea -esa
test:
$(JVM) $(JFLAGS) test.blogeditutil.TestBlogEditor >res.txt
$(JVM) $(JFLAGS) test.blogeditutil.TestBlogEditTextContent >rescontent.txt

Тест не работает! Почему-то матершина (т.е сообщения об ошибках) исходит из того места, где вызывается метод getPlainTextContent(). Как заставить этот метод работать правильно, я так и не понял. Заглянув в документацию мы увидим, что у класса Entry есть метод getTextContent(), который возвращает объект класса TextContent, у которого есть метод getContent(), возвращающий объект класса TextConstruct, у которого есть (наконец-то!!!) метод getPlainText(), который возвращает обычную строку:

String textcontent = p.getTextContent().getContent().getPlainText();

Несколько длинновато, но зато после замены вызова getPlainTextContent() на это длинное выражение все работает. Полученный результат вряд ли можно считать читабельным, он не содержит информации ни о ссылках, ни о разметке. Было бы неплохо получить html-представление постов, дабы потом их спокойно просматривать в браузере. Как оказалось, такая возможность есть, хотя о ней прямо ничего не сказано в документации на GData API. Как оказалось (по крайней мере, для случая, когда мы получаем фид постов), объект класса TextConstruct, который мы получим при вот таком вызове:

TextConstruct textconstr = p.getTextContent().getContent();

можно спокойно приводить к типу HtmlTextConstruct, из которого уже можно получить html-представление поста. Я создал новый класс под названием TestBlogEditHtmlContent, в котором и реализовал вывод содержимого постов в html-представлении. Он отличается от предыдущего тестового класса только телом цокла for, поэтому я приведу тут лишь это различие:

for(Entry p: postlist)
{
System.out.println("<h3>Post caption:<br>" +
p.getTitle().getPlainText() + "<br>");
System.out.println("Content:<br></h3>");
HtmlTextConstruct htmlconstr = (HtmlTextConstruct)(p.getTextContent().getContent());
System.out.println(htmlconstr.getHtml());
System.out.println("<br>----------------------- end of post.<br>");
}

Все это откомпилил, и в конец файла makefile вставил еще одну строчку:

$(JVM) $(JFLAGS) test.blogeditutil.TestBlogEditHtmlContent >res.html
Теперь мона открывать файл res.html в браузере и любоваться пейзажем :)))


0 коммент.:

Отправить комментарий