タイトルからも分かる通り、SNS内から、Twitterを通じて発言できるようにしてみました。さらに、Ajaxのライブラリとして、DWR2を採用。同ライブラリは元々Springとの連携も考慮されているので、比較的連携は簡単でした。
また、Twitterのライブラリとしてfaff.jpの作成者でもあるHaruyoshiさんから「Twitter4J」が便利だと聞いて採用しました。Javaオブジェクトで操作が出来るため、自分でXMLなどの面倒なパースをしなくて済むのが一番の大きな点です。
JavaでTwitterと連携したいのであれば、一番簡単なんじゃないかと思います。注意として、ライブラリを最新版(2.0.8)にしないと、Twitter側のAPIとの絡みでExceptionは発生します。なので、使用する際は、最新版を利用してください。
まぁ、今回の連携について、コードを残しておきますので、何かの役に立てばと思います。
DWR2+Spring2の連携により、dwr.xmlの記述が必要なくなり、applicationContext.xmlに記述するだけでよくなり、Springに慣れている人は設定しやすいと思います。
自分メモですが、今回のタグは「MileStone_008」にDWR2+Spring2の連動までの確認を含めたソースをコミットしています。
広告
■applicationContext.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | < ?xml version="1.0" encoding="UTF-8"?> <beans default-lazy-init="false" xmlns="https://www.springframework.org/schema/beans" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:dwr="https://www.directwebremoting.org/schema/spring-dwr" xmlns:aop="https://www.springframework.org/schema/aop" xmlns:tx="https://www.springframework.org/schema/tx" xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-2.0.xsd https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-2.0.xsd https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd https://www.directwebremoting.org/schema/spring-dwr https://www.directwebremoting.org/schema/spring-dwr-2.0.xsd"> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:database.properties </value> </list> </property> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="transactionAttributeSource" class="org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource"> <property name="properties"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="delete*">PROPAGATION_REQUIRED</prop> <!-- <prop key="*">PROPAGATION_REQUIRED,readOnly --> </props> </property> </bean> <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager" ref="transactionManager"></property> <property name="transactionAttributeSource" ref="transactionAttributeSource"></property> </bean> <bean id="beanNameAutoProxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="interceptorNames"> <list> <value>transactionInterceptor</value> </list> </property> <property name="beanNames"> <list> <value>*Service</value> </list> </property> </bean> <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> <property name="configLocation" value="classpath:sqlMapConfig.xml"></property> <property name="dataSource" ref="dataSource"></property> </bean> <!-- Model --> <bean id="loginModel" class="org.fukata.jc_front.model.LoginModel"> </bean> <!-- Dao --> <bean id="customerDao" class="org.fukata.jc_front.dao.impl.CustomerDaoImpl"> <property name="sqlMapClient" ref="sqlMapClient"></property> </bean> <bean id="communityDao" class="org.fukata.jc_front.dao.impl.CommunityDaoImpl"> <property name="sqlMapClient" ref="sqlMapClient"></property> </bean> <bean id="informationDao" class="org.fukata.jc_front.dao.impl.InformationDaoImpl"> <property name="sqlMapClient" ref="sqlMapClient"></property> </bean> <!-- Service --> <bean id="customerService" class="org.fukata.jc_front.service.impl.CustomerServiceImpl"> <property name="customerDao" ref="customerDao"></property> <property name="communityDao" ref="communityDao"></property> </bean> <bean id="informationService" class="org.fukata.jc_front.service.impl.InformationServiceImpl"> <property name="informationDao" ref="informationDao"></property> </bean> <bean id="twitterService" class="org.fukata.jc_front.service.impl.TwitterServiceImpl"> </bean> <!-- Action --> <bean id="loginAction" class="org.fukata.jc_front.action.LoginAction" scope="prototype"> </bean> <bean id="loginWithValidationAction" class="org.fukata.jc_front.action.LoginWithValidationAction" scope="prototype"> <property name="loginModel" ref="loginModel"></property> <property name="customerService" ref="customerService"></property> </bean> <bean id="indexAction" class="org.fukata.jc_front.action.IndexAction" scope="prototype"> <property name="customerService" ref="customerService"></property> <property name="informationService" ref="informationService"></property> </bean> <bean id="logoutAction" class="org.fukata.jc_front.action.LogoutAction" scope="prototype"> <property name="customerService" ref="customerService"></property> </bean> <!-- DWR Manager --> <dwr :configuration> </dwr><dwr :convert type="bean" class="org.fukata.jc_front.dwr.bean.TwitterBean"></dwr> <dwr :convert type="bean" class="twitter4j.Status"></dwr> <dwr :convert type="bean" class="twitter4j.User"></dwr> <bean id="twitterManager" class="org.fukata.jc_front.dwr.manager.TwitterManager"> <property name="customerService" ref="customerService"></property> <property name="twitterService" ref="twitterService"></property> <dwr :remote javascript="TwitterManager"> </dwr><dwr :include method="echo"></dwr> <dwr :include method="getFriendsTimeline"></dwr> <dwr :include method="setCustomerService"></dwr> <dwr :include method="setTwitterService"></dwr> </bean> <!-- Interceptor --> <bean id="loginInterceptor" class="org.fukata.jc_front.interceptor.LoginInterceptor" scope="prototype"> <property name="customerService" ref="customerService"></property> </bean> <!-- Advice --> <aop :config> </aop><aop :advisor pointcut="execution(* org.fukata.jc_front.service.*Service.*(..))" advice-ref="loggingAdvice"></aop> <bean id="loggingAdvice" class="org.fukata.jc_common.advice.LoggingAdvice" scope="prototype"> </bean> </beans> |
■web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | < !DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "https://java.sun.com/dtd/web-app_2_3.dtd" > <web -app> <display -name>jc-front</display> <!-- Setting for Spring2 listner. --> <context -param> <param -name/>contextConfigLocation <param -value/>/WEB-INF/applicationContext.xml </context> <filter> </filter><filter -name>jc-front</filter> <filter -class>org.apache.struts2.dispatcher.FilterDispatcher</filter> <init -param> <param -name/>actionPackages <param -value/>org.fukata.jc_front.action </init> <filter -mapping> </filter><filter -name>jc-front</filter> <url -pattern>/*</url> <listener> </listener><listener -class>org.springframework.web.context.ContextLoaderListener</listener> <!-- DWR --> <servlet> </servlet><servlet -name>dwr-invoker</servlet> <servlet -class>org.directwebremoting.spring.DwrSpringServlet</servlet> <init -param> <!-- (1)デバッグモードの有効化 --> <param -name/>debug <param -value/>true </init> <init -param> <param -name/>activeReverseAjaxEnabled <param -value/>true </init> <load -on-startup>1</load> <servlet -mapping> </servlet><servlet -name>dwr-invoker</servlet> <!-- (1)DwrServletからJavaScriptを自動生成するための設定 --> <url -pattern>/dwr/*</url> </web> |
■TwitterManager.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | package org.fukata.jc_front.dwr.manager; import java.util.List; import javax.servlet.http.HttpServletRequest; import org.directwebremoting.WebContext; import org.directwebremoting.WebContextFactory; import org.fukata.jc_common.utils.beanutils.JcBeanUtils; import org.fukata.jc_front.dto.CustomerDto; import org.fukata.jc_front.dto.SessionUserDto; import org.fukata.jc_front.dto.TwitterDto; import org.fukata.jc_front.dwr.bean.TwitterBean; import org.fukata.jc_front.service.CustomerService; import org.fukata.jc_front.service.TwitterService; import twitter4j.Status; public class TwitterManager { private CustomerService customerService; private TwitterService twitterService; /** * 発言用メソッド * @param status */ public TwitterBean echo(String status) { WebContext dwrContext = WebContextFactory.get(); HttpServletRequest request = dwrContext .getHttpServletRequest(); TwitterDto twitterDto = generateTwitterDto(request); // status twitterDto.setStatus(status); Status updateStatus = this.twitterService.updateStatus(twitterDto); // beanの生成 TwitterBean bean = new TwitterBean(); bean.setLatestStatus(updateStatus); return bean; } private TwitterDto generateTwitterDto(HttpServletRequest request) { SessionUserDto sessionUserDto = this.customerService.getSessionUserDto(request); CustomerDto customerDto = this.customerService.selectByCustomerId(sessionUserDto.getCustomerId()); TwitterDto twitterDto = new TwitterDto(); JcBeanUtils.copyProperties(twitterDto, customerDto); return twitterDto; } /** * フレンドタイムライン取得用メソッド * @param value */ public TwitterBean getFriendsTimeline() { WebContext dwrContext = WebContextFactory.get(); HttpServletRequest request = dwrContext .getHttpServletRequest(); TwitterDto twitterDto = generateTwitterDto(request); List<status> friendsTimeline = this.twitterService.getFriendsTimeline(twitterDto); // beanの生成 TwitterBean bean = new TwitterBean(); bean.setFriendsTimeline(friendsTimeline); return bean; } public CustomerService getCustomerService() { return customerService; } public void setCustomerService(CustomerService customerService) { this.customerService = customerService; } public TwitterService getTwitterService() { return twitterService; } public void setTwitterService(TwitterService twitterService) { this.twitterService = twitterService; } } </status> |
■TwitterBean.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | package org.fukata.jc_front.dwr.bean; import java.io.Serializable; import java.util.List; import twitter4j.Status; public class TwitterBean implements Serializable { private Status latestStatus; private List<status> friendsTimeline; public Status getLatestStatus() { return latestStatus; } public void setLatestStatus(Status latestStatus) { this.latestStatus = latestStatus; } public List</status><status> getFriendsTimeline() { return friendsTimeline; } public void setFriendsTimeline(List</status><status> friendsTimeline) { this.friendsTimeline = friendsTimeline; } } </status> |
■twitter.js(jquery.jsに依存しています)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | // 発言用 function echo() { // HTMLからデータを取得 var status = dwr.util.getValue("twitter_status"); // 入力値が空の場合は発言しない。 if (status.trim=="") { return false; } // リモートオブジェクトの実行(第二引数はコールバック関数) TwitterManager.echo(status, _echo); return false; } // 発言用コールバック function _echo(twitterBean) { // 入力値の初期化 dwr.util.setValue("twitter_status", ""); } // 返信 function reply(to) { var status = dwr.util.getValue("twitter_status"); status = '@' + to + " " + status; dwr.util.setValue("twitter_status", status); } // 初期ロード時実行用 function init() { dwr.engine.setActiveReverseAjax(true); getFriendsTimeline(); } // フレンドタイムライン取得用 function getFriendsTimeline() { TwitterManager.getFriendsTimeline({ callback: _getFriendsTimeline }); } // フレンドタイムライン取得用コールバック function _getFriendsTimeline(twitterBean) { var options = {}; options.escapeHtml = false; // 初期化 dwr.util.setValue("twitter_timeline", "", options); var html = ""; for (var i = 0; i < twitterBean.friendsTimeline.length; i++) { var status = twitterBean.friendsTimeline[i]; var _html = ""; _html += '<div class="timeline_row clearfix">'; _html += '<div class="twitter_img">'; _html += '<img src="https://fukata.org/2009/07/19/jc-dwr2-spring2-and-twitter4j/" width="48" height="48"/>'; _html += '</div>'; _html += '<div class="twitter_message">'; _html += status.user.screenName + "<br />"; _html += status.text; _html += '</div>'; _html += '<div class="twitter_action">'; _html += '<a href="javascript:reply(\''+status.user.screenName+'\')"></a>'; _html += '</div>'; _html += ''; html += _html; dwr.util.setValue("twitter_timeline", html, options); } // ポーリング setTimeout(getFriendsTimeline, 60000); } $(document).ready(init); |