Использование Facebook Graph API в Java

Добрый день, Хаброжители!

Сегодня я расскажу Вам историю собственного велосипеда.
Передо мной стала задача работы с Facebook Graph API в Java, меня интересовали 3 функции: логин, получение информации о пользователе, публикация сообщения на стене.
Работающей библиотеки на Java я не нашёл (или плохо искал), поэтому пришлось изобретать собственный велосипед.
Прочитав о Graph API я начал искать библиотеки, которые мне помогут в укрощении данной API,
пару минут помучив Google я нашёл open-source библиотеку HtmlUnit.

Итак, приступим. Что нам понадобиться для того, чтобы залогиниться на Facebook под своим аккаунтом:

1) Нам необходимо создать приложения в Facebook, App ID которого мы будем использоваться для логина и получения AccessToken.
2) HtmlUnit, для заполнения форм.

Создание приложения на Facebook


Проходим по ссылке и нажимаем на кнопку "Создать новое приложение".
Заполняем поле "App Display Name", соглашаемся с "политикой конфиденциальности платформы" и жмём кнопку "Продолжить".
В загрузившейся странице нажимаем "Сохранить изменения" и сохраняем у себя App ID.

Далее переходим к написанию Java приложения


public class Facebook {
	/* App ID */
	private static final String API_KEY = "1";
	/* Ссылка на страницу, куда перенаправят нас при удачном логине. */
	private static final String REDIRECT_URL = "https://www.facebook.com/connect/login_success.html";
	
	/* ID логин формы. */
	private static final String LOGIN_FORM_ID = "login_form";
	/* Имя e-mail формы. */
	private static final String INPUT_EMAIL_NAME = "email";
	/* Имя password формы. */
	private static final String INPUT_PASSWORD_NAME = "pass";
	/* Имя кнопки "Войти". */
	private static final String INPUT_LOGIN_NAME = "login";
	
	/* Имя формы управления правами приложения. */
	private static final String ACCESS_FORM_ID = "uiserver_form";
	/* Имя кнопки "Разрешить". */
	private static final String INPUT_ALLOW_NAME = "grant_clicked";
	
	/* Ссылка на Graph API. */
	private static final String GRAPH_URL = "https://graph.facebook.com/";
	
	/* HtmlUnit Веб-клиент. */
	private WebClient webClient;
	/* Полученный AccessToken. */
	private String accessToken;
	
	
	public Facebook() {
		initWebClient();
	}
	
	/**
	 * Логинимся в Facebook используя данные email и password.
	 */
	public void login(String email, String password) {
		try {
			/* Получаем логин форму. */
			HtmlForm loginForm = getForm(LOGIN_FORM_ID);
			if (loginForm != null) {
				/* Заполняем поле email. */
				loginForm.getInputByName(INPUT_EMAIL_NAME).setValueAttribute(email);
				/* Заполняем поле password. */
				loginForm.getInputByName(INPUT_PASSWORD_NAME).setValueAttribute(password);
				/* Нажимаем кнопку "Войти" и получаем страницу, на которую нас перенаправит Facebook. */
				HtmlPage page = loginForm.getInputByName(INPUT_LOGIN_NAME).click();
				/* Получаем форму управления правами приложения. */
				HtmlForm accessForm = getForm(page, ACCESS_FORM_ID);
				if (accessForm != null) {
					/* Нажимаем на кнопку "Разрешить" и получаем страницу, на которую нас перенаправит Facebook. */
					page = accessForm.getInputByName(INPUT_ALLOW_NAME).click();
				}
				/* Проверяем, увеналась ли удачей наша попытка логина. */
				if (page.getBody().getTextContent().trim().equalsIgnoreCase("success")) {
					/* Извлекаем AccessToken. */
					getAccessToken(page.getUrl());
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public String getAccessToken() {
		return this.accessToken;
	}
	
	/**
	 * Получаем информацию о пользователе.
	 */
	public String getUserInfo(String id) {
		/* Генерируем ссылку запроса. */
		String requestURL = GRAPH_URL + id + "?access_token=" + accessToken;
		/* Посылаем запрос. */
		return sendRequest(requestURL);
	}
	
	/**
	 * Публикуем сообщения на стене пользователя.
	 */
	public String writeInWall(String id, String msg) {
		/* Генерируем ссылку публикации. */
		String requestURL = GRAPH_URL + id + "?access_token=" + accessToken + "&message=" + encodeMsg(msg);
		/* Публикуем сообщение на стене пользователя. */
		return publish(requestURL);
	}
	
	/**
	 * Инициализируем WebClient.
	 */
	private void initWebClient() {
		webClient = new WebClient();
		/* Отключаем CSS. */
		webClient.setCssEnabled(false);
		/* Отключаем JavaScript. */
		webClient.setJavaScriptEnabled(false);
	}
	
	/**
	 * Получаем форму по formID.
	 */
	private HtmlForm getForm(String formID) {
		HtmlForm form = null;
		
		try {
			HtmlPage page = webClient.getPage(getLoginURL());
			form = getForm(page, formID);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return form;
	}
	
	/**
	 * Получаем форму по formID со страницы page.
	 */
	private HtmlForm getForm(HtmlPage page, String formID) {
		HtmlForm form = null;
		
		List<HtmlForm> forms = page.getForms();
		
		for (HtmlForm tForm : forms) {
			if (tForm.getId().equalsIgnoreCase(formID)) {
				form = tForm;
				break;
			}
		}
		
		return form;
	}
	
	/**
	 * Извлекаем AccessToken из полученной ссылки link.
	 */
	private void getAccessToken(URL link) {
		String ref = link.getRef();
		String token = "access_token=";
		String expires = "&expires";
		
		int startIndex = ref.indexOf(token);
		int endIndex = ref.indexOf(expires);
		
		if (startIndex != -1 && endIndex != -1) {
			accessToken = ref.substring(startIndex + token.length(), endIndex);
		}
	}
	
	/**
	 * Посылаем запрос.
	 */
	private String sendRequest(String request) {
		String result = null;
		
		try {
			HttpGet get = new HttpGet(request);
			DefaultHttpClient client = new DefaultHttpClient();
			HttpResponse response = client.execute(get);
			result = EntityUtils.toString(response.getEntity());
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return result;
	}
	
	/**
	 * Посылаем post запрос.
	 */
	private String publish(String request) {
		String result = null;
		
		try {
			HttpPost post = new HttpPost(request);
			DefaultHttpClient client = new DefaultHttpClient();
			HttpResponse response = client.execute(post);
			result = EntityUtils.toString(response.getEntity());
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return result;
	}
	
	/* Кодируем текст сообщения. */
	private String encodeMsg(String msg) {
		try {
			msg = URLEncoder.encode(msg, HTTP.UTF_8);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return msg;
	}
	
	/* Формируем ссылку логина. */
	private String getLoginURL() {
		return "https://www.facebook.com/dialog/oauth?client_id=" + API_KEY + "&redirect_uri=" + REDIRECT_URL + "&scope=" + getPermissions() + "&response_type=token";
	}
	
	/* Формируем перечень прав приложения. */
	private String getPermissions() {
		StringBuilder permissions = new StringBuilder();
		
		permissions.append("read_stream,");
		permissions.append("user_birthday,");
		permissions.append("user_religion_politics,");
		permissions.append("user_relationships,");
		permissions.append("user_relationship_details,");
		permissions.append("user_hometown,");
		permissions.append("user_location,");
		permissions.append("user_likes,");
		permissions.append("user_activities,");
		permissions.append("user_interests,");
		permissions.append("user_education_history,");
		permissions.append("user_work_history,");
		permissions.append("user_online_presence,");
		permissions.append("user_website,");
		permissions.append("user_groups,");
		permissions.append("user_events,");
		permissions.append("user_photos,");
		permissions.append("user_videos,");
		permissions.append("user_photo_video_tags,");
		permissions.append("user_notes,");
		permissions.append("user_about_me,");
		permissions.append("user_status,");
		permissions.append("friends_birthday,");
		permissions.append("friends_religion_politics,");
		permissions.append("friends_relationships,");
		permissions.append("friends_relationship_details,");
		permissions.append("friends_hometown,");
		permissions.append("friends_location,");
		permissions.append("friends_likes,");
		permissions.append("friends_activities,");
		permissions.append("friends_interests,");
		permissions.append("friends_education_history,");
		permissions.append("friends_work_history,");
		permissions.append("friends_online_presence,");
		permissions.append("friends_website,");
		permissions.append("friends_groups,");
		permissions.append("friends_events,");
		permissions.append("friends_photos,");
		permissions.append("friends_videos,");
		permissions.append("friends_photo_video_tags,");
		permissions.append("friends_notes,");
		permissions.append("friends_about_me,");
		permissions.append("friends_status,");
		permissions.append("publish_stream,");
		permissions.append("create_event,");
		permissions.append("rsvp_event,");
		permissions.append("sms,");
		permissions.append("offline_access,");
		permissions.append("publish_checkins,");
		permissions.append("manage_friendlists,");
		permissions.append("manage_pages");
	
		return permissions.toString();
	}
}


Проверяем, что у нас получилось.

public class Test {
	public static void main(String[] args) {
		Facebook facebook = new Facebook();
                /* Логинимся. */
		facebook.login("email", "pass");
                /* Получаем пользовательскую информацию. */
		System.out.println(facebook.getUserInfo("me/feed"));
                /* Публикуем на стене. */
		System.out.println(facebook.writeInWall("me/feed", "Проверка!"));
	}
}


Заходим на свою страницу и видим следующее:


P.S.
Выслушаю и приму на заметку любую критику. Буду очень рад, если кому-то поможет данная статья.
  • +3
  • 11,4k
  • 7
Поделиться публикацией
Комментарии 7
    0
    А теперь встречаем «Require me to enter a security code each time an unrecognized computer or device tries to access my account» [ www.facebook.com/settings?tab=security§ion=approvals&t ]. Будет Ой? ;)
      0
      Да, если включить эту опцию, то будет ой. :)
      0
      Spring social еще есть.

      PS Кстати, оберните ваши исходники в
      <source lang="java">
      , тогда они красиво покрасятся
        0
        Насчёт Spring social знаю, но, к сожалению, я ещё в стадии изучения Spring.
        Исходники обвернуты в
        , но, почему-то, не подсвечиваются. :\
          0
          Это приколы, появившиеся после обновления хабра — хабраподсветка слетела, как и некоторые другие старые фичи.
          0
          Google -> «facebook java api» -> forum -> «This project has been abandoned?» -> restfb.com (A Lightweight Java Facebook Graph API and Old REST)
          И там ближе к середине страницы короткий и простой пример «Publishing a Message and Event».

          В самом гугловском поиске сей апи не в самом верху :)

          А HtmlUnit несколько для других целей, да ;)
            0
            Спасибо, буду знать.
            На тот момент, когда я изобретал этот велосипед, restfb был заброшен. :)

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

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