VK notifer на java

в 16:40, , рубрики: 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);

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

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

Автор: matim


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js