1.简介
这是有关小型附属项目的第三篇也是最后一篇文章-该机器人自动在专用帐户上鸣叫来自各个Q&A StackExchange网站上的问题(文章末尾的完整列表)。
第一篇文章讨论了为StackExchange REST API构建一个简单的客户端 。 在第二篇文章中,我们使用Spring Social建立了与Twitter的交互。
本文将描述实现的最后一部分-负责Stackexchange客户端与TwitterTemplate之间的交互的部分。
2. Tweet Stackexchange服务
Stackexchange Client(公开原始问题)与TwitterTemplate (完全设置并可以鸣叫)之间的交互是一个非常简单的服务TweetStackexchangeService 。 由此发布的API是:
public void tweetTopQuestionBySite(String site, String twitterAccount){ ... }
public void tweetTopQuestionBySiteAndTag(String site, String twitterAccount, String tag){ ... }
功能很简单–这些API将继续(通过客户端)从Stackexchange REST API中读取“问题”,直到在该特定帐户上找到之前从未发过任何推文的为止。
找到该问题后,将通过与该帐户相对应的TwitterTemplate在Twitter上发布该消息,并将一个非常简单的Question实体保存在本地。 该实体仅存储问题的ID和已在其上发布的Twitter帐户。
例如以下问题: 在@RequestParam中绑定列表 已在SpringAtSO帐户上发布。
Question实体仅包含:
- 问题的编号 –在这种情况下为4596351
- 问题已在其上发布的Twitter帐户 – SpringAtSO
- 问题源自的Stackexcange网站 – stackoverflow
我们需要跟踪此信息,以便我们知道哪些问题已被发布,哪些问题尚未被发布。
3.调度程序
调度程序利用了Spring的调度任务功能-通过Java配置启用了这些功能:
@Configuration
@EnableScheduling
public class ContextConfig {
//
}
实际的调度程序相对简单:
@Component
@Profile(SpringProfileUtil.DEPLOYED)
public class TweetStackexchangeScheduler {
@Autowired
private TweetStackexchangeService service;
// API
@Scheduled(cron = "0 0 1,5 * * *")
public void tweetStackExchangeTopQuestion() throws JsonProcessingException, IOException {
service.tweetTopQuestionBySiteAndTag("StackOverflow", Tag.clojure.name(), "BestClojure", 1);
String randomSite = StackexchangeUtil.pickOne("SuperUser", "StackOverflow");
service.tweetTopQuestionBySiteAndTag(randomSite, Tag.bash.name(), "BestBash", 1);
}
}
上面配置了两个推文操作–来自StackOverflow问题的一个推文,在Best Of Clojure Twitter帐户上标有“ clojure”。
其他操作将推文标记为“ bash”的问题–由于这类问题实际上出现在Stackexchange网络上的多个站点上: StackOverflow , SuperUser和AskUbuntu ,因此首先有一个快速选择过程来选择这些站点之一,然后问题已发布。
最后, 计划cron作业每天在凌晨1点和凌晨5点运行 。
4.设定
这是一个宠物项目,它以一个非常简单的数据库结构开始 -现在仍然很简单,但情况更是如此。 因此,主要目标之一是能够轻松地更改数据库结构-当然,有几种用于数据库迁移的工具 ,但是对于这样一个简单的项目,它们全都过时了。
因此,我决定将设置数据保留为简单的文本格式 -将自动进行半自动更新。
安装程序有两个主要步骤:
- 检索每个Twitter帐户上的推文问题的ID,并将其存储在文本文件中
- 删除数据库架构并重新启动应用程序–这将再次创建架构,并将所有数据从文本文件设置回新数据库
4.1。 原始设置数据
使用JDBC检索现有数据库中数据的过程非常简单; 首先我们定义一个RowMapper:
class TweetRowMapper implements RowMapper<String> {
private Map<String, List<Long>> accountToQuestions;
public TweetRowMapper(Map<String, List<Long>> accountToQuestions) {
super();
this.accountToQuestions = accountToQuestions;
}
public String mapRow(ResultSet rs, int line) throws SQLException {
String questionIdAsString = rs.getString("question_id");
long questionId = Long.parseLong(questionIdAsString);
String account = rs.getString("account");
if (accountToQuestions.get(account) == null) {
accountToQuestions.put(account, Lists.<Long> newArrayList());
}
accountToQuestions.get(account).add(questionId);
return "";
}
}
这将为每个Twitter帐户建立一个问题列表。
接下来,我们将在一个简单的测试中使用它:
@Test
public void whenQuestionsAreRetrievedFromTheDB_thenNoExceptions() {
Map<String, List<Long>> accountToQuestionsMap = Maps.newHashMap();
jdbcTemplate.query
("SELECT * FROM question_tweet;", new TweetRowMapper(accountToQuestionsMap));
for (String accountName : accountToQuestionsMap.keySet()) {
System.out.println
(accountName + "=" + valuesAsCsv(accountToQuestionsMap.get(accountName)));
}
}
检索帐户问题后,测试将简单地列出问题; 例如:
SpringAtSO=3652090,1079114,5908466,...
4.2。 恢复设置数据
上一步生成的数据行存储在setup.properties文件中 ,该文件可用于Spring:
@Configuration
@PropertySource({ "classpath:setup.properties" })
public class PersistenceJPAConfig {
//
}
当应用程序启动时,将执行设置过程。 这个简单的过程使用Spring ApplicationListener,监听ContextRefreshedEvent :
@Component
public class StackexchangeSetup implements ApplicationListener<ContextRefreshedEvent> {
private boolean setupDone;
public void onApplicationEvent(ContextRefreshedEvent event) {
if (!setupDone) {
recreateAllQuestionsOnAllTwitterAccounts();
setupDone = true;
}
}
}
最后,从setup.properties文件中检索问题并重新创建:
private void recreateAllQuestionsOnTwitterAccount(String twitterAccount) {
String tweetedQuestions = env.getProperty(twitterAccount.name();
String[] questionIds = tweetedQuestions.split(",");
recreateQuestions(questionIds, twitterAccount);
}
void recreateQuestions(String[] questionIds, String twitterAccount) {
List<String> stackSitesForTwitterAccount = twitterAccountToStackSites(twitterAccount);
String site = stackSitesForTwitterAccount.get(0);
for (String questionId : questionIds) {
QuestionTweet questionTweet = new QuestionTweet(questionId, twitterAccount, site);
questionTweetDao.save(questionTweet);
}
}
这个简单的过程可以轻松地更新数据库结构-由于已完全擦除数据并完全重新创建了数据,因此无需进行任何实际的迁移 。
5.帐户完整清单
Twitter帐户的完整列表是:
- SpringAtSO –来自StackOverflow的Spring问题
- JavaTopSO –来自StackOverflow的Java问题
- RESTDaily –来自StackOverflow的REST问题
- BestJPA –来自StackOverflow的JPA问题
- BestMaven –来自StackOverflow的Maven问题
- BestGit –来自StackOverflow的Git问题
- AskUbuntuBest – AskUbuntu最佳总体问题(所有主题)
- ServerFaultBest – ServerFault最佳问题(所有主题)
- BestBash-来自StackOverflow,ServerFault和AskUbuntu的最佳Bash问题
- BestClojure –来自StackOverflow的Clojure问题
- BestScala –来自StackOverflow的Scala问题
- BestEclipse –来自StackOverflow的Eclipse问题
- jQueryDaily –来自StackOverflow的jQuery问题
- BestAlgorithms –来自StackOverflow的算法问题
这些帐户中的每个帐户每天都会创建2条推文,其特定主题的问题评分最高。
六,结论
第三篇文章完成了有关与StackOverflow和其他StackExchange网站集成以通过其REST API检索问题,以及与Twitter和Spring Social集成以发布这些问题的系列文章。 可能值得探索的潜在方向与Google Plus相同(可能使用Pages,而不是帐户)。
14这个项目的结果是Twitter帐户已启动并正在运行-专注于各种主题,并产生少量且希望高质量的内容(在评论中欢迎其他标记自己Twitter帐户的标记的想法)。
翻译自: https://www.javacodegeeks.com/2013/05/tweeting-stackexchange-questions-with-spring-social.html