Общее·количество·просмотров·страницы

Java Dev Notes - разработка на Java (а также на JavaScript/Python/Flex и др), факты, события из АйТи

вторник, 29 сентября 2009 г.

Кеширование новостей - запись данных в файл, кодировки, локи на файл

Итак, есть задача - сделать кеширование новостей на сервере. Сейчас у нас новости тянутся с блогпота - читается фид блога (формат Atom), и затем они транслируются на сайте.

Кешируем следующим образом: сохраняем XML контент в файл на сервере. Стратегия обновления файла: если дата создания файл отличается от сегодняшней, то тащим новости с блогспота. Если же дата такая же, то не трогаем файл. Т.е. если у нас нет запросов к сайту, то файл с фидами не обновляется. Если запросы есть, то он обновляется раз в сутки.

Можно было конечно не заморачиваться с этим, и сделать попроще: используя cron раз в сутки запускать программку, которая пишет фиды с блогспота в файл. Соответственно, в java-программке не надо ничего писать, а просто лишь читать файл с сервера.

Итак, код чтения файла:

ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
 
String filename = "newsfeed.xml";
String realPath = getServletContext().getRealPath(filename);
updateNewsFile(realPath);
 
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(realPath)));
 
String s;
StringBuilder result = new StringBuilder();
while ((s = in.readLine()) != null) {
result.append(s);
}
in.close();
ModelAndView mv = new ModelAndView(this.view);
mv.addObject("feed", result.toString());
return mv;
}

Раз мы в коде видим ModelAndView - то ясно, что используется Spring MVC. Функция updateNewsFile(realPath) проверяет файл с фидами, и если его дата не равно сегодняшней, или файл вообще отсутствует, тащит фиды с блогспота, и пишет их в файл. Вот и ее код:

 
private static void updateNewsFile(String realPath) throws Exception {
Calendar today = Calendar.getInstance();
Calendar fileTime = Calendar.getInstance();
File file = new File(realPath);
boolean fileExists = true;
 
try {
fileTime.setTimeInMillis(file.lastModified());
} catch (Exception e) {
fileExists = false;
}
 
// if file doesn't exist or isn't up-to-date, refresh it
if (
!fileExists ||
(
today.get(Calendar.YEAR) != fileTime.get(Calendar.YEAR) ||
today.get(Calendar.MONTH) != fileTime.get(Calendar.MONTH) ||
today.get(Calendar.DATE) != fileTime.get(Calendar.DATE))
)
{
URL feed = new URL("http://jdevnotes.blogspot.com/feeds/posts/default");
BufferedReader in = new BufferedReader(new InputStreamReader(feed.openStream(), "utf-8"));
StringBuilder sb = new StringBuilder();
String s;
while ((s = in.readLine()) != null) Х
sb.append(s);
}
in.close();
writeContentToFile(realPath, sb.toString());
}
}


Функция writeContentToFile лочит файл и записывает в него содержимое фиды. Используется Java NIO. Пример использования я посмотрел вот по этой ссылке. Вот код функции:

private static void writeContentToFile(String path, String content) throws Exception {
FileOutputStream fos = null;
FileLock lock = null;
try {
fos = new FileOutputStream(path);
FileChannel fileChannel = fos.getChannel();
lock = fileChannel.tryLock();
if (lock != null) {
fos.write(content.getBytes());
}
} finally {
if (lock != null) {
lock.release();
}
fos.close();
}
}


Код простой и сам-себя-объясняет, т.е. self-explanatory =). Но есть одно "но". В примере используется RandomAccessFile. Сначала и я его использовал.

Это такой класс, который записывает строку как String, а не как байты. С этого я получил расход времени на задачу плюс 2.5 часа сверх обычного ;-) Уж как только я не "трахался" с этим - указывал явно кодировки при записи, явно при чтении, при записи и при чтении, и т.д., и т.п. Пока наконец не догадался заменить RandomAccessFile на FileOutputStream - после этого все заработало с первого раза.

Такие дела =)

Комментариев нет:

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

Постоянные читатели