1. 概述
發佈到Reddit是一場投機行為。 一篇帖子可能大受歡迎並獲得大量關注,而另一篇可能更好的帖子卻一無所獲。因此,應密切關注這些帖子,並在它們缺乏足夠關注度時,迅速刪除並重新提交。
在本文中,我們將繼續研究Reddit案例,並實現一個有趣的特性——如果帖子沒有立即獲得足夠關注,則刪除並重新提交。
其簡單目標是允許用户配置多少個Reddit上的投票足以認為帖子獲得了足夠的關注,並將其保留一段時間內。
2. 更多 Reddit 權限
首先,我們需要從 Reddit API 請求額外的權限——具體來説,我們需要編輯帖子。
因此,我們將向 Reddit Resource 添加 “edit” 權限範圍:
@Bean
public OAuth2ProtectedResourceDetails reddit() {
AuthorizationCodeResourceDetails details =
new AuthorizationCodeResourceDetails();
details.setScope(Arrays.asList("identity", "read", "submit", "edit"));
...
}3. The Entity and the Repository
Now – let’s add the extra information in our Post entity:
@Entity
public class Post {
...
private String redditID;
private int noOfAttempts;
private int timeInterval;
private int minScoreRequired;
}字段:
- redditID:在 Reddit 上查看帖子得分和刪除帖子的使用標識符
- noOfAttempts:最大重提交次數(刪除帖子並重新提交)
- timeInterval:檢查帖子是否獲得足夠關注的時間間隔
- minScoreRequired:為了認為它足夠成功而保留的最低得分
接下來,讓我們為我們的 PostRepository 接口添加一些新的操作——以便在需要檢查時輕鬆檢索帖子:
public interface PostRepository extends JpaRepository<Post, Long> {
List<Post> findBySubmissionDateBeforeAndIsSent(Date date, boolean sent);
List<Post> findByUser(User user);
List<Post> findByRedditIDNotNullAndNoOfAttemptsGreaterThan(int attempts);
}4. 新定時任務
現在,讓我們將“重新提交任務”定義為新的定時任務,並將其添加到調度器中:
@Scheduled(fixedRate = 3 * 60 * 1000)
public void checkAndReSubmitPosts() {
List<Post> submitted =
postReopsitory.findByRedditIDNotNullAndNoOfAttemptsGreaterThan(0);
for (Post post : submitted) {
checkAndReSubmit(post);
}
}每隔幾分鐘,它會簡單地迭代所有仍在進行的帖子,如果它們沒有獲得足夠的關注度,就會刪除它們並重新提交。
以下是 checkAndReSubmit() 方法:
private void checkAndReSubmit(Post post) {
try {
checkAndReSubmitInternal(post);
} catch (final Exception e) {
logger.error("Error occurred while check post " + post.toString(), e);
}
}
private void checkAndReSubmitInternal(Post post) {
if (didIntervalPassed(post.getSubmissionDate(), post.getTimeInterval())) {
int score = getPostScore(post.getRedditID());
if (score < post.getMinScoreRequired()) {
deletePost(post.getRedditID());
resetPost(post);
} else {
post.setNoOfAttempts(0);
postReopsitory.save(post);
}
}
}
private boolean didIntervalPassed(Date submissonDate, int postInterval) {
long currentTime = new Date().getTime();
long interval = currentTime - submissonDate.getTime();
long intervalInMinutes = TimeUnit.MINUTES.convert(interval, TimeUnit.MILLISECONDS);
return intervalInMinutes > postInterval;
}
private void resetPost(Post post) {
long time = new Date().getTime();
time += TimeUnit.MILLISECONDS.convert(post.getTimeInterval(), TimeUnit.MINUTES);
post.setRedditID(null);
post.setSubmissionDate(new Date(time));
post.setSent(false);
post.setSubmissionResponse("Not sent yet");
postReopsitory.save(post);
}我們還需要在首次將其提交到 Reddit 時跟蹤 redditID:
private void submitPostInternal(Post post) {
...
JsonNode node = redditRestTemplate.postForObject(
"https://oauth.reddit.com/api/submit", param, JsonNode.class);
JsonNode errorNode = node.get("json").get("errors").get(0);
if (errorNode == null) {
post.setRedditID(node.get("json").get("data").get("id").asText());
post.setNoOfAttempts(post.getNoOfAttempts() - 1);
...
}這裏的邏輯非常簡單——我們只是保存 ID 並減少嘗試計數器。
5. 獲取 Reddit 帖子得分
現在,讓我們看看如何獲取 Reddit 帖子當前的得分:
private int getPostScore(String redditId) {
JsonNode node = redditRestTemplate.getForObject(
"https://oauth.reddit.com/api/info?id=t3_" + redditId, JsonNode.class);
int score = node.get("data").get("children").get(0).get("data").get("score").asInt();
return score;
}請注意:
- 在從Reddit檢索帖子信息時,我們需要“read”範圍
- 我們通過在Reddit ID中添加“t3_”來獲取帖子的全名
刪除 Reddit 帖子
接下來,讓我們看看如何通過其 ID 刪除 Reddit 帖子:
private void deletePost(String redditId) {
MultiValueMap<String, String> param = new LinkedMultiValueMap<String, String>();
param.add("id", "t3_" + redditId);
redditRestTemplate.postForObject(
"https://oauth.reddit.com/api/del.json", param, JsonNode.class);
}7. RedditController
現在 – 讓我們將新信息添加到控制器中:
@RequestMapping(value = "/schedule", method = RequestMethod.POST)
public String schedule(Model model,
@RequestParam Map<String, String> formParams) throws ParseException {
Post post = new Post();
post.setTitle(formParams.get("title"));
post.setSubreddit(formParams.get("sr"));
post.setUrl(formParams.get("url"));
post.setNoOfAttempts(Integer.parseInt(formParams.get("attempt")));
post.setTimeInterval(Integer.parseInt(formParams.get("interval")));
post.setMinScoreRequired(Integer.parseInt(formParams.get("score")));
....
}8. 用户界面 – 配置規則
最後,讓我們修改我們的非常簡單的日程表表單,以添加重新提交新設置:
<label class="col-sm-3">Resubmit Settings</label>
<label>Number of Attempts</label>
<select name="attempt">
<option value="0" selected>None</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
<label>Time interval</label>
<select name="interval">
<option value="0" selected >None</option>
<option value="45">45 minutes</option>
<option value="60">1 hour</option>
<option value="120">2 hours</option>
</select>
<label>Min score</label>
<input type="number"value="0" name="score" required/>9. 結論
我們正在不斷改進這個簡單應用的功能——現在我們可以將內容發佈到Reddit,並且—如果發佈內容沒有迅速獲得足夠的關注—系統可以刪除該內容並重新發布,以提高其表現的機會。