diff --git a/src/main/java/org/springframework/social/weibo/api/CommentOperations.java b/src/main/java/org/springframework/social/weibo/api/CommentOperations.java index 92deaa1..de62135 100644 --- a/src/main/java/org/springframework/social/weibo/api/CommentOperations.java +++ b/src/main/java/org/springframework/social/weibo/api/CommentOperations.java @@ -19,6 +19,11 @@ public interface CommentOperations { + Comment createComment(long id, String comment); + + Comment createComment(long id, String comment, + boolean commentFromExternalSource); + CursoredList getCommentsByMe(); CursoredList getCommentsByMe(int pageSize, int pageNumber); diff --git a/src/main/java/org/springframework/social/weibo/api/impl/CommentTemplate.java b/src/main/java/org/springframework/social/weibo/api/impl/CommentTemplate.java index 294ece5..afe16fc 100644 --- a/src/main/java/org/springframework/social/weibo/api/impl/CommentTemplate.java +++ b/src/main/java/org/springframework/social/weibo/api/impl/CommentTemplate.java @@ -26,6 +26,8 @@ import org.springframework.social.weibo.api.CursoredList; import org.springframework.social.weibo.api.SourceFilterType; import org.springframework.social.weibo.util.StringUtils; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; class CommentTemplate extends AbstractWeiboOperations implements @@ -36,6 +38,25 @@ protected CommentTemplate(ObjectMapper objectMapper, super(objectMapper, restTemplate, isAuthorized); } + @Override + public Comment createComment(long id, String comment) { + return createComment(id, comment, false); + } + + @Override + public Comment createComment(long id, String comment, + boolean commentFromExternalSource) { + requireAuthorization(); + MultiValueMap request = new LinkedMultiValueMap( + 3); + request.add("id", String.valueOf(id)); + request.add("comment", comment); + request.add("comment_ori", + StringUtils.booleanToString(commentFromExternalSource)); + return restTemplate.postForObject(buildUri("comments/create.json"), + request, Comment.class); + } + @Override public CursoredList getCommentsByMe() { requireAuthorization(); @@ -116,8 +137,7 @@ public List getCommentsOnStatuses(List ids) { requireAuthorization(); URI uri = buildUri("comments/show_batch.json", "cids", StringUtils.join(ids)); - JsonNode dataNode = restTemplate.getForObject( - uri, JsonNode.class); + JsonNode dataNode = restTemplate.getForObject(uri, JsonNode.class); return deserializeDataList(dataNode, Comment.class); } diff --git a/src/main/java/org/springframework/social/weibo/api/impl/TimelineTemplate.java b/src/main/java/org/springframework/social/weibo/api/impl/TimelineTemplate.java index 930f82b..a560c15 100644 --- a/src/main/java/org/springframework/social/weibo/api/impl/TimelineTemplate.java +++ b/src/main/java/org/springframework/social/weibo/api/impl/TimelineTemplate.java @@ -26,6 +26,7 @@ import org.springframework.social.weibo.api.Status; import org.springframework.social.weibo.api.StatusContentType; import org.springframework.social.weibo.api.TimelineOperations; +import org.springframework.social.weibo.util.StringUtils; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; @@ -33,10 +34,6 @@ public class TimelineTemplate extends AbstractWeiboOperations implements TimelineOperations { - private static String booleanToString(boolean value) { - return value ? "1" : "0"; - } - protected TimelineTemplate(ObjectMapper objectMapper, RestTemplate restTemplate, boolean isAuthorized) { super(objectMapper, restTemplate, isAuthorized); @@ -56,17 +53,22 @@ private CursoredList fetchStatusList(String url, long sinceId, long maxId, int pageSize, int pageNumber, boolean onlyApplicationStatus, StatusContentType statusContentType) { requireAuthorization(); - JsonNode dataNode = restTemplate.getForObject( - uriBuilder(url) - .queryParam("since_id", String.valueOf(sinceId)) - .queryParam("max_id", String.valueOf(maxId)) - .queryParam("count", String.valueOf(pageSize)) - .queryParam("page", String.valueOf(pageNumber)) - .queryParam("base_app", - booleanToString(onlyApplicationStatus)) - .queryParam("feature", - String.valueOf(statusContentType.ordinal())) - .build(), JsonNode.class); + JsonNode dataNode = restTemplate + .getForObject( + uriBuilder(url) + .queryParam("since_id", String.valueOf(sinceId)) + .queryParam("max_id", String.valueOf(maxId)) + .queryParam("count", String.valueOf(pageSize)) + .queryParam("page", String.valueOf(pageNumber)) + .queryParam( + "base_app", + StringUtils + .booleanToString(onlyApplicationStatus)) + .queryParam( + "feature", + String.valueOf(statusContentType + .ordinal())).build(), + JsonNode.class); return deserializeCursoredList(dataNode, Status.class, "statuses"); } @@ -116,8 +118,10 @@ public List getDailyHotComments(int pageSize, .getForObject( uriBuilder("statuses/hot/comments_daily.json") .queryParam("count", String.valueOf(pageSize)) - .queryParam("base_app", - booleanToString(onlyApplicationStatus)) + .queryParam( + "base_app", + StringUtils + .booleanToString(onlyApplicationStatus)) .build(), JsonNode.class); return deserializeDataList(dataNode, Status.class); } @@ -138,8 +142,10 @@ public List getDailyHotRepost(int pageSize, .getForObject( uriBuilder("statuses/hot/repost_daily.json") .queryParam("count", String.valueOf(pageSize)) - .queryParam("base_app", - booleanToString(onlyApplicationStatus)) + .queryParam( + "base_app", + StringUtils + .booleanToString(onlyApplicationStatus)) .build(), JsonNode.class); return deserializeDataList(dataNode, Status.class); } @@ -231,8 +237,8 @@ public CursoredList getMentions(long sinceId, long maxId, .queryParam("filter_by_source", String.valueOf(sourceFilterType.ordinal())) .queryParam("filter_by_type", - booleanToString(createdInWeibo)).build(), - JsonNode.class); + StringUtils.booleanToString(createdInWeibo)) + .build(), JsonNode.class); return deserializeCursoredList(dataNode, Status.class, "statuses"); } @@ -257,8 +263,10 @@ public CursoredList getPublicTimeline(int pageSize, int pageNumber, uriBuilder("statuses/public_timeline.json") .queryParam("count", String.valueOf(pageSize)) .queryParam("page", String.valueOf(pageNumber)) - .queryParam("base_app", - booleanToString(onlyApplicationStatus)) + .queryParam( + "base_app", + StringUtils + .booleanToString(onlyApplicationStatus)) .build(), JsonNode.class); return deserializeCursoredList(dataNode, Status.class, "statuses"); } @@ -359,18 +367,23 @@ public CursoredList getUserTimeline(long uid, long sinceId, long maxId, int pageSize, int pageNumber, boolean onlyApplicationStatus, StatusContentType statusContentType) { requireAuthorization(); - JsonNode dataNode = restTemplate.getForObject( - uriBuilder("statuses/user_timeline.json") - .queryParam("uid", String.valueOf(uid)) - .queryParam("since_id", String.valueOf(sinceId)) - .queryParam("max_id", String.valueOf(maxId)) - .queryParam("count", String.valueOf(pageSize)) - .queryParam("page", String.valueOf(pageNumber)) - .queryParam("base_app", - booleanToString(onlyApplicationStatus)) - .queryParam("feature", - String.valueOf(statusContentType.ordinal())) - .build(), JsonNode.class); + JsonNode dataNode = restTemplate + .getForObject( + uriBuilder("statuses/user_timeline.json") + .queryParam("uid", String.valueOf(uid)) + .queryParam("since_id", String.valueOf(sinceId)) + .queryParam("max_id", String.valueOf(maxId)) + .queryParam("count", String.valueOf(pageSize)) + .queryParam("page", String.valueOf(pageNumber)) + .queryParam( + "base_app", + StringUtils + .booleanToString(onlyApplicationStatus)) + .queryParam( + "feature", + String.valueOf(statusContentType + .ordinal())).build(), + JsonNode.class); return deserializeCursoredList(dataNode, Status.class, "statuses"); } @@ -390,8 +403,10 @@ public List getWeeklyHotComments(int pageSize, .getForObject( uriBuilder("statuses/hot/comments_weekly.json") .queryParam("count", String.valueOf(pageSize)) - .queryParam("base_app", - booleanToString(onlyApplicationStatus)) + .queryParam( + "base_app", + StringUtils + .booleanToString(onlyApplicationStatus)) .build(), JsonNode.class); return deserializeDataList(dataNode, Status.class); } @@ -412,8 +427,10 @@ public List getWeeklyHotRepost(int pageSize, .getForObject( uriBuilder("statuses/hot/repost_weekly.json") .queryParam("count", String.valueOf(pageSize)) - .queryParam("base_app", - booleanToString(onlyApplicationStatus)) + .queryParam( + "base_app", + StringUtils + .booleanToString(onlyApplicationStatus)) .build(), JsonNode.class); return deserializeDataList(dataNode, Status.class); } diff --git a/src/main/java/org/springframework/social/weibo/util/StringUtils.java b/src/main/java/org/springframework/social/weibo/util/StringUtils.java index bef5b9c..88b149b 100644 --- a/src/main/java/org/springframework/social/weibo/util/StringUtils.java +++ b/src/main/java/org/springframework/social/weibo/util/StringUtils.java @@ -36,4 +36,8 @@ public static String join(Iterable iterable) { return stringBuilder.toString(); } + public static String booleanToString(boolean value) { + return value ? "1" : "0"; + } + } diff --git a/src/test/java/org/springframework/social/weibo/api/impl/CommentTemplateTest.java b/src/test/java/org/springframework/social/weibo/api/impl/CommentTemplateTest.java index de24a5f..88a4e6a 100644 --- a/src/test/java/org/springframework/social/weibo/api/impl/CommentTemplateTest.java +++ b/src/test/java/org/springframework/social/weibo/api/impl/CommentTemplateTest.java @@ -18,6 +18,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.springframework.http.HttpMethod.GET; +import static org.springframework.http.HttpMethod.POST; +import static org.springframework.social.test.client.RequestMatchers.body; import static org.springframework.social.test.client.RequestMatchers.method; import static org.springframework.social.test.client.RequestMatchers.requestTo; import static org.springframework.social.test.client.ResponseCreators.withResponse; @@ -260,4 +262,17 @@ public void testGetCommentsOnStatuses() { verifyComment(comments.iterator().next()); assertEquals(2, comments.size()); } + + @Test + public void testCreateComment() { + mockServer + .expect(requestTo("https://api.weibo.com/2/comments/create.json")) + .andExpect(method(POST)) + .andExpect( + body("id=1&comment=%E6%88%91%E5%96%9C%E6%AC%A2%E4%BD%A0%E5%81%9A%E7%9A%84&comment_ori=0")) + .andRespond( + withResponse(jsonResource("comment"), responseHeaders)); + Comment comment = commentTemplate.createComment(1, "我喜欢你做的"); + verifyComment(comment); + } } diff --git a/src/test/java/org/springframework/social/weibo/util/StringUtilsTest.java b/src/test/java/org/springframework/social/weibo/util/StringUtilsTest.java index 4b24b22..96cf439 100644 --- a/src/test/java/org/springframework/social/weibo/util/StringUtilsTest.java +++ b/src/test/java/org/springframework/social/weibo/util/StringUtilsTest.java @@ -34,4 +34,10 @@ public void testJoinArray() { assertEquals("1,2,3", StringUtils.join(Arrays.asList(1L, 2L, 3L))); } + @Test + public void testBooleanToString() { + assertEquals("1", StringUtils.booleanToString(true)); + assertEquals("0", StringUtils.booleanToString(false)); + } + } diff --git a/src/test/resources/json/comment.json b/src/test/resources/json/comment.json new file mode 100644 index 0000000..b158660 --- /dev/null +++ b/src/test/resources/json/comment.json @@ -0,0 +1,81 @@ +{ + "created_at" : "Wed Jun 01 00:50:25 +0800 2011", + "id" : 12438492184, + "text" : "我喜欢你做的", + "source" : "新浪微博", + "mid" : "202110601896455629", + "user" : { + "id" : 1404376560, + "screen_name" : "zaku", + "name" : "zaku", + "province" : "11", + "city" : "5", + "location" : "北京 朝阳区", + "description" : "人生五十年,乃如梦如幻;有生斯有死,壮士复何憾。", + "url" : "http://blog.sina.com.cn/zaku", + "profile_image_url" : "http://tp1.sinaimg.cn/1404376560/50/0/1", + "domain" : "zaku", + "gender" : "m", + "followers_count" : 1204, + "friends_count" : 447, + "statuses_count" : 2908, + "favourites_count" : 0, + "created_at" : "Fri Aug 28 00:00:00 +0800 2009", + "following" : false, + "allow_all_act_msg" : false, + "remark" : "", + "geo_enabled" : true, + "verified" : false, + "allow_all_comment" : true, + "avatar_large" : "http://tp1.sinaimg.cn/1404376560/180/0/1", + "verified_reason" : "", + "follow_me" : false, + "online_status" : 0, + "bi_followers_count" : 215 + }, + "status" : { + "created_at" : "Tue May 31 17:46:55 +0800 2011", + "id" : 11488058246, + "text" : "求关注。", + "source" : "新浪微博", + "favorited" : false, + "truncated" : false, + "in_reply_to_status_id" : "", + "in_reply_to_user_id" : "", + "in_reply_to_screen_name" : "", + "geo" : null, + "mid" : "5612814510546515491", + "reposts_count" : 8, + "comments_count" : 9, + "annotations" : [], + "user" : { + "id" : 1404376560, + "screen_name" : "zaku", + "name" : "zaku", + "province" : "11", + "city" : "5", + "location" : "北京 朝阳区", + "description" : "人生五十年,乃如梦如幻;有生斯有死,壮士复何憾。", + "url" : "http://blog.sina.com.cn/zaku", + "profile_image_url" : "http://tp1.sinaimg.cn/1404376560/50/0/1", + "domain" : "zaku", + "gender" : "m", + "followers_count" : 1204, + "friends_count" : 447, + "statuses_count" : 2908, + "favourites_count" : 0, + "created_at" : "Fri Aug 28 00:00:00 +0800 2009", + "following" : false, + "allow_all_act_msg" : false, + "remark" : "", + "geo_enabled" : true, + "verified" : false, + "allow_all_comment" : true, + "avatar_large" : "http://tp1.sinaimg.cn/1404376560/180/0/1", + "verified_reason" : "", + "follow_me" : false, + "online_status" : 0, + "bi_followers_count" : 215 + } + } +} \ No newline at end of file