VK notifer на java

Однажды мне довелось работать над проектом, заказчик которого поддерживал обратную связь исключительно с помощью социальной сети Вконтакте. Так как я — не особо активный пользователь данной социальной сети, то возникла проблема в плане скорости получения посланных мне сообщений. Так случилось, что я потянул поясницу и пару дней провел на койке. Так как делать лежа, причем с больной спиной, особо нечего, то я решил махом убить несколько проблем:
  • Скрасить время своей реабилитации
  • Решить проблему с доставкой сообщений
  • Попробовать себя в написании программ на java

Итоги получившейся java терапии под катом.

Хочется начать с того, что на java я никогда не программировал, поэтому я не претендую на гениальность своего приложения.
Поохав, устроившись поудобнее и пододвинув зарядку поближе, я начал свое первое приложение на этом чудесном языке.
Первое, что я решил сделать, это соорудить «каркас» для моего notifer'а. Все что мне было необходимо — это простое меню в трее, которое бы выдавало всплывающие сообщения.

//Создадим раскрывающееся меню
PopupMenu popup = new PopupMenu();
//Создадим элемент меню
MenuItem exitItem = new MenuItem("Выход");
//Добавим для него обработчик
exitItem.addActionListener(new ActionListener(){
	public void actionPerformed(ActionEvent e) {
		System.exit(0);
	}
});
//Добавим пункт в меню
popup.add(exitItem);
SystemTray systemTray = SystemTray.getSystemTray();
Image image = Toolkit.getDefaultToolkit().getImage("vk_icon.png");
TrayIcon trayIcon = new TrayIcon(image,"VKNotifer",popup);
trayIcon.setImageAutoSize(true);
//добавим иконку в трей
systemTray.add(trayIcon);
//тестовое сообщение
trayIcon.displayMessage("VKNotifer", "Текст",TrayIcon.MessageType.INFO);

Теперь главная задача — это получать список текущих сообщений. Для этой цели я воспользовался предоставленным api Вконтакте. С основной информацией по api можно ознакомиться здесь.
Первое что нужно сделать для того, чтобы иметь возможность использовать api, это создать приложение Вконтакте, после чего вы получите id своего приложения необходимый для получения token'а.
Второе действие для доступа к api — это получение самого token'а. Для этого необходимо в вашем приложении пройти следующие этапы:
  1. Авторизация
  2. Подтверждение запрашиваемых требований
  3. Непосредственно получение token'а

После этого, благодаря полученному token'у, вы сможете выполнять методы api. Процесс авторизации описан здесь
Для этих целей я создал класс VKapi, который будет иметь два метода: Получить token и получить список сообщений.
Метод первый — получение token'а:
HttpClient httpClient = new DefaultHttpClient();
// Делаем первый запрос
HttpPost post = new HttpPost("http://oauth.vk.com/authorize?" +
		"client_id="+client_id+
		"&scope="+scope+
		"&redirect_uri="+redirect_uri+
		"&display="+display+
		"&response_type="+response_type);
HttpResponse response;
response = httpClient.execute(post);
post.abort();
//Получаем редирект
String HeaderLocation = response.getFirstHeader("location").getValue();
URI RedirectUri = new URI(HeaderLocation);
//Для запроса авторизации необходимо два параметра полученных в первом запросе
//ip_h и to_h
String ip_h= RedirectUri.getQuery().split("&")[2].split("=")[1];
String to_h=RedirectUri.getQuery().split("&")[4].split("=")[1];
// Делаем запрос авторизации
post = new HttpPost("https://login.vk.com/?act=login&soft=1"+
		"&q=1"+
		"&ip_h="+ip_h+
		"&from_host=oauth.vk.com"+
		"&to="+to_h+
		"&expire=0"+
		"&email="+email+
		"&pass="+pass);
response = httpClient.execute(post);
post.abort();
// Получили редирект на подтверждение требований приложения
HeaderLocation = response.getFirstHeader("location").getValue();
post = new HttpPost(HeaderLocation);
// Проходим по нему
response = httpClient.execute(post);
post.abort();
// Теперь последний редирект на получение токена
HeaderLocation = response.getFirstHeader("location").getValue();
// Проходим по нему
post = new HttpPost(HeaderLocation);
response = httpClient.execute(post);
post.abort();
// Теперь в след редиректе необходимый токен
HeaderLocation = response.getFirstHeader("location").getValue();
// Просто спарсим его сплитами
access_token = HeaderLocation.split("#")[1].split("&")[0].split("=")[1];

Для получения списка сообщений api Вконтакте имеет метод messages.get
Метод второй — получение списка сообщений:
//формируем строку запроса
String url = "https://api.vk.com/method/"+
		"messages.get"+
		"?out=0"+
		"&access_token="+access_token
		;
String line = "";
try {
            URL url2 = new URL(url);
            BufferedReader reader = new BufferedReader(new InputStreamReader(url2.openStream()));
            line = reader.readLine();
            reader.close();

        } catch (MalformedURLException e) {
            // ...
        } catch (IOException e) {
            // ...
        }
return line;

Класс полностью:
public class VKapi {
	private String client_id = "2971510";
	private String scope = "messages";
	private String redirect_uri = "http://oauth.vk.com/blank.html";
	private String display = "popup";
	private String response_type = "token";
	private String access_token;
	private String email = "******";//тут должен быть прописан email
	private String pass = "******";//тут должен быть прописан пароль
	public void setConnection() throws IOException, URISyntaxException {
        //Ранее описанный код получения token'a
	}
	public String getNewMessage() throws ClientProtocolException, IOException, NoSuchAlgorithmException, URISyntaxException {
         //Ранее описанный код получения списка сообщений
	}
}

Все, что осталось, это создать экземпляр класса, получить token и в бесконечном цикле получать списки сообщений. Если вновь полученный список отличается от предыдущего, тогда выводим уведомление о новом сообщении.
В результате получаем:
public static void main(String[] args) throws IOException, URISyntaxException, AWTException, InterruptedException, NoSuchAlgorithmException {
	//Создадим раскрывающееся меню
	PopupMenu popup = new PopupMenu();
	//Создадим элемент меню
	MenuItem exitItem = new MenuItem("Выход");
	//Добавим для него обработчик
	exitItem.addActionListener(new ActionListener(){
		public void actionPerformed(ActionEvent e) {
			System.exit(0);
		}
	});
	//Добавим пункт в меню
	popup.add(exitItem);
	SystemTray systemTray = SystemTray.getSystemTray();
	//получим картинку
	Image image = Toolkit.getDefaultToolkit().getImage("vk_icon.png");
	TrayIcon trayIcon = new TrayIcon(image,"VKNotifer",popup);
	trayIcon.setImageAutoSize(true);
	//добавим иконку в трей
	systemTray.add(trayIcon);
	trayIcon.displayMessage("VKNotifer", "Соединяемся с сервером",TrayIcon.MessageType.INFO);
	//Создадим экземпляр класса ВКапи
	VKapi vkAPI = new VKapi();
	//Получим токен
	vkAPI.setConnection();
	trayIcon.displayMessage("VKNotifer", "Соединение установлено",TrayIcon.MessageType.INFO);
	//Бескоечный цикл
	String oldMessage = vkAPI.getNewMessage();
	String newMessage;
	int i = 0;
	for (;;){
		// Запросы на сервер можно подавать раз в 3 секунды
		Thread.sleep(3000); // ждем три секунды
		if (i == 15000){  // Если прошло 45 000 сек (Время взято с запасом, токен дается на день )
			vkAPI.setConnection(); // Обновляем токен
			Thread.sleep(3000);    // Запросы шлем только раз в три секунды
			i = 0;
		}
		//Здесь отработка 
		newMessage = vkAPI.getNewMessage();
		if (!newMessage.equals(oldMessage)) {
			oldMessage = newMessage;
			trayIcon.displayMessage("VKNotifer", "Получено новое сообщение",TrayIcon.MessageType.INFO);
			Tools.playDrum(Drum.d53_Ride_Bell, 127,0);
		}
		i++;
	}
}

Кроме всплывающего окна, также используется звуковое оповещение.
Tools.playDrum(Drum.d53_Ride_Bell, 127,0);

Для этого используется библиотека из этого топика

Я знаю, что это не идеальное исполнение, но самое главное — оно вполне решило мои проблемы. Спасибо за внимание.
Поделиться публикацией

Комментарии 13

    +4
    Делать для каждого заказчика персональный IM… да вы настоящий джедай!))
      +1
      Это лишь уведомитель. Но после написания этой статьи, я наткнулся на конкурс от Вконтакте на андроид мессаджер. Возможно он и перерастет в IM.
      0
      в бесконечном цикле получать списки сообщений. Если вновь полученный список отличается от предыдущего, тогда выводим уведомление о новом сообщении.

      Для этого придумали делегаты и события :)
        –1
        А по мне здесь как раз проще именно бесконечным циклом и не усложнять лишний раз… Задачи не те.
          0
          а если на телефоне с мобильным интернетом запускать будешь?
            +1
            Решение и не задумывалось для мобильных устройств.
        +2
        Используйте jabber клиент.
          +1
          Да это самый простой выход. Не спорю достаточно было в кипе включить плагин, но то, что сделал я, помогло мне скрасить время пребывания на постели, заодно попробовал что-нибудь в java наваять
            0
            Я бы вам советовал написать такой же нотифаер на джава с использованием джедайских техник паттернов и прочего ООП. Только тогда можно познать весь страх и ужас (как говорят мои друзья), или прелесть (как говорим мы с коллегами) Java.
              0
              Промахнулся, мой коммент вам чуть ниже.
          0
          Недавно, как раз, поступил на обучение в компанию, так что буду познавать.
            0
            Хочется начать с того, что на java я никогда не программировал, поэтому я не претендую на гениальность своего приложения.
            Поохав, устроившись поудобнее и пододвинув зарядку поближе, я начал свое первое приложение на этом чудесном языке.


            Спасибо за статью.
            А вы не могли бы чуть подробнее о том, что осталось между строк? В частности о литературе.
            Потому что сейчас я как раз на стадии «на java я никогда не программировал» и взглянув на ваш код, абсолютно не понимаю как с текущей стадии мне попасть на «начал свое первое приложение»)

            PS Только не советуйте Хорстманна и Корнелла, я уже их читаю.
              0
              Поставьте цель каким должно быть ваше приложение и идите в пучины google.com. Этот оракул даст вам все ответы, главное правильно спрашивайте его.

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое