Repository: belerweb/social-sdk Branch: master Commit: 797b15bd70f0 Files: 114 Total size: 384.3 KB Directory structure: gitextract_ctatj41d/ ├── .gitignore ├── README.md ├── eclipse-java-google-style.xml ├── pom.xml └── src/ ├── main/ │ └── java/ │ └── com/ │ └── belerweb/ │ └── social/ │ ├── API.java │ ├── SDK.java │ ├── bean/ │ │ ├── Error.java │ │ ├── Gender.java │ │ ├── JsonBean.java │ │ ├── OnlineStatus.java │ │ └── Result.java │ ├── captcha/ │ │ ├── api/ │ │ │ └── Yundama.java │ │ └── bean/ │ │ └── YundamaType.java │ ├── exception/ │ │ └── SocialException.java │ ├── http/ │ │ ├── Http.java │ │ └── HttpException.java │ ├── mail/ │ │ └── api/ │ │ └── POP3.java │ ├── qq/ │ │ ├── connect/ │ │ │ ├── api/ │ │ │ │ ├── OAuth2.java │ │ │ │ ├── QQConnect.java │ │ │ │ ├── QZone.java │ │ │ │ ├── User.java │ │ │ │ └── Weibo.java │ │ │ └── bean/ │ │ │ ├── AccessToken.java │ │ │ ├── Album.java │ │ │ ├── AlbumPrivilege.java │ │ │ ├── Company.java │ │ │ ├── Display.java │ │ │ ├── Education.java │ │ │ ├── FanList.java │ │ │ ├── Gut.java │ │ │ ├── IdolList.java │ │ │ ├── Image.java │ │ │ ├── Music.java │ │ │ ├── NewT.java │ │ │ ├── OpenID.java │ │ │ ├── Photo.java │ │ │ ├── PicUploadResult.java │ │ │ ├── RepostList.java │ │ │ ├── Scope.java │ │ │ ├── SendPrivate.java │ │ │ ├── Tag.java │ │ │ ├── TenpayAddress.java │ │ │ ├── TweetInfo.java │ │ │ ├── User.java │ │ │ ├── Video.java │ │ │ └── WeiboUser.java │ │ ├── mail/ │ │ │ ├── api/ │ │ │ │ └── Contact.java │ │ │ └── bean/ │ │ │ ├── Address.java │ │ │ ├── Email.java │ │ │ ├── Group.java │ │ │ ├── Org.java │ │ │ ├── Tel.java │ │ │ ├── User.java │ │ │ └── ValidationCode.java │ │ ├── qzone/ │ │ │ └── api/ │ │ │ └── Visitor.java │ │ └── t/ │ │ └── api/ │ │ ├── OAuth2.java │ │ └── QQT.java │ ├── weibo/ │ │ ├── api/ │ │ │ ├── OAuth2.java │ │ │ ├── User.java │ │ │ └── Weibo.java │ │ └── bean/ │ │ ├── AccessToken.java │ │ ├── Comment.java │ │ ├── Display.java │ │ ├── Geo.java │ │ ├── Privacy.java │ │ ├── Remind.java │ │ ├── Scope.java │ │ ├── Status.java │ │ ├── TokenInfo.java │ │ ├── UrlShort.java │ │ ├── User.java │ │ ├── UserCounts.java │ │ └── Visible.java │ └── weixin/ │ ├── api/ │ │ ├── Group.java │ │ ├── Media.java │ │ ├── Menu.java │ │ ├── OAuth2.java │ │ ├── User.java │ │ └── Weixin.java │ └── bean/ │ ├── AccessToken.java │ ├── ApiTicket.java │ ├── Article.java │ ├── EventType.java │ ├── GetFollowersResult.java │ ├── Group.java │ ├── JSApiTicket.java │ ├── Media.java │ ├── MediaType.java │ ├── Menu.java │ ├── MenuType.java │ ├── Message.java │ ├── MsgType.java │ ├── QRCreation.java │ ├── QRTicket.java │ ├── QRType.java │ ├── Scope.java │ ├── User.java │ ├── Variable.java │ └── VoiceType.java └── test/ ├── java/ │ └── com/ │ └── belerweb/ │ └── social/ │ ├── SDKTest.java │ ├── TestConfig.java │ ├── captcha/ │ │ └── api/ │ │ └── YundamaTest.java │ ├── mail/ │ │ └── api/ │ │ └── POP3Test.java │ ├── qq/ │ │ └── connect/ │ │ └── api/ │ │ ├── OAuth2Test.java │ │ └── UserTest.java │ ├── weibo/ │ │ └── api/ │ │ ├── OAuth2Test.java │ │ └── UserTest.java │ └── weixin/ │ └── api/ │ ├── GroupTest.java │ ├── MediaTest.java │ ├── MenuTest.java │ ├── OAuth2Test.java │ ├── UserTest.java │ └── WeixinTest.java └── resources/ └── logback.xml ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Eclipse .externalToolBuilders/ .settings/ bin/ tmp/ .metadata .gradle *.tmp *.bak *.swp *~.nib local.properties .loadpath .project .classpath # IntelliJ IDES .idea/ out/ .idea_modules/ *.iml *.ipr *.ids *.iws # OSX # Icon must end with two \r Icon ._* .DS_Store .AppleDouble .LSOverride .DocumentRevisions-V100 .fseventsd .Spotlight-V100 .TemporaryItems .Trashes .VolumeIcon.icns .AppleDB .AppleDesktop Network Trash Folder Temporary Items .apdisk # Windows $RECYCLE.BIN/ Thumbs.db ehthumbs.db Desktop.ini *.lnk # Linux *~ .directory .Trash-* # Maven target/ pom.xml.tag pom.xml.releaseBackup pom.xml.versionsBackup pom.xml.next release.properties dependency-reduced-pom.xml buildNumber.properties .mvn/timing.properties # frontend-maven-plugin node bower_components node_modules etc ================================================ FILE: README.md ================================================ social-sdk ========== social-sdk是一个集成[新浪微博开放平台][1]、[QQ互联][2]、[腾讯微博开发平台][3]、[微信公众平台][4]等社交平台的接口的Java库。 其实在开始这个项目之前,各个平台都已经提供相应的Java SDK,有官方的、也有非官方的开源项目,如如新浪微博开放平台有[weibo4j][5]。我也一直在使用这些项目。但是在使用过程中越到的问题越来越多,越来越麻烦,如: - 这些SDK都是提供一个ZIP包,不适合Maven或Ivy管理的项目。 - 各个SDK都引入了开源公共类库,确改了包名,造成类库过多、混乱。 - SDK更新超级慢,跟不上平台上接口的变更。 - 没有交流环境,遇到BUG找不到资料,找不到沟通的地方,需要自己去琢磨源代码。 - ...... 因此,自己开发一个,尝试尽可能多的集成社交平台。 **因为我并没有在项目中使用到那么多社交平台,所以有的社交平台没有可供测试的应用信息(通常叫做AppKey和AppSecret)。所以非常希望有资源的朋友共享测试帐号。** 已实现 --- - QQ相关 - 通过QQ邮箱获取联系人,支持验证码自动登录 - 获取QZone访客记录,支持验证码自动登录 - 新浪微博 - 新浪微博登录 - 获取新浪微博用户信息 - QQ帐号/QQ互联 - 支持http://wiki.connect.qq.com 列出的API - 腾讯微博(未测试) - 腾讯微博登录(未测试) - 获取腾讯微博用户信息(未测试) - [微信帐号](../../wiki/微信API) - [获取access_token](../../wiki/微信API#获取access token) - [获取jsapi_ticket](../../wiki/微信API#获取jsapi_ticket) - jsapi签名 - 上传下载多媒体文件 - 接受消息/事件推送/位置信息 - 验证消息真实性 - 发送被动响应信息 - 发送客服消息 - 发送模板消息 - 分组管理 - 获取用户基本信息 - 获取关注者列表 - 网页授权获取用户基本信息 - 自定义菜单 - 生成带参数的二维码接口 计划开发 ---- - 更多的接口 - 支持更多的平台 下载 -- 推荐使用Maven下载。social-sdk已发布到Maven中央库。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ com.belerweb social-sdk 0.0.5 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 参与 -- 交流:GitHub上留言或加入QQ群(328171904) 共享代码:Fork项目并提交Pull Requests 提交BUG:直接在GitHub上提交 其他:欢迎任何形式的贡献,文档、经验、意见... 链接 -- [1]: [2]: [3]: [4]: [5]: [6]: [7]: [8]: ================================================ FILE: eclipse-java-google-style.xml ================================================ ================================================ FILE: pom.xml ================================================ 4.0.0 org.sonatype.oss oss-parent 7 com.belerweb social-sdk 0.0.6-SNAPSHOT jar social-sdk All in one sdk, include weibo, qq connect, t.qq.com ... https://github.com/belerweb/social-sdk BSD http://opensource.org/licenses/bsd-license.html repo scm:git:https://github.com/belerweb/social-sdk.git scm:git:https://github.com/belerweb/social-sdk.git https://github.com/belerweb/social-sdk.git Github Issue https://github.com/belerweb/social-sdk/issues belerweb Tangjun He belerweb@gmail.com https://github.com/belerweb UTF-8 1.5 ${maven.compiler.source} 2.6 org.json json 20131018 org.apache.httpcomponents httpmime 4.3.1 commons-lang commons-lang 2.6 commons-io commons-io 2.4 commons-net commons-net 3.3 org.jsoup jsoup 1.7.3 org.slf4j slf4j-api 1.7.5 ch.qos.logback logback-classic 1.0.13 test junit junit 4.11 test com.googlecode.maven-java-formatter-plugin maven-java-formatter-plugin 0.4 ${maven.compiler.source} ${maven.compiler.source} ${maven.compiler.source} ${project.basedir}/eclipse-java-google-style.xml LF format org.eclipse.m2e lifecycle-mapping 1.0.0 com.googlecode.maven-java-formatter-plugin maven-java-formatter-plugin [0.4] format true org.apache.maven.plugins maven-enforcer-plugin [1.0,) enforce ================================================ FILE: src/main/java/com/belerweb/social/API.java ================================================ package com.belerweb.social; import com.belerweb.social.qq.connect.api.QQConnect; import com.belerweb.social.qq.t.api.QQT; import com.belerweb.social.weibo.api.Weibo; import com.belerweb.social.weixin.api.Weixin; public abstract class API { protected Weibo weibo; protected Weixin weixin; protected QQConnect connect; protected QQT t; protected API(Weibo weibo) { this.weibo = weibo; } protected API(Weixin weixin) { this.weixin = weixin; } protected API(QQConnect connect) { this.connect = connect; } protected API(QQT t) { this.t = t; } } ================================================ FILE: src/main/java/com/belerweb/social/SDK.java ================================================ package com.belerweb.social; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpEntity; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; import org.json.JSONArray; import org.json.JSONObject; import com.belerweb.social.bean.Error; import com.belerweb.social.bean.Result; import com.belerweb.social.exception.SocialException; import com.belerweb.social.http.Http; import com.belerweb.social.http.HttpException; public abstract class SDK { private final Charset defaultCharset; public SDK() { this(null); } public SDK(Charset defaultCharset) { this.defaultCharset = defaultCharset; } public String get(String url, List params) { try { Http.setDefaultCharset(defaultCharset); return Http.get(url, params); } catch (HttpException e) { throw new SocialException(e); } } public String get(String url) { return get(url, null); } public String post(String url, HttpEntity postBody) { try { Http.setDefaultCharset(defaultCharset); return Http.post(url, postBody); } catch (HttpException e) { throw new SocialException(e); } } public String post(String url, List params) { try { Http.setDefaultCharset(defaultCharset); return Http.post(url, params, "UTF-8"); } catch (HttpException e) { throw new SocialException(e); } } public String post(String url) { return post(url, (HttpEntity) null); } public void addParameter(List params, String name, Object value) { if (value == null) { throw new SocialException("Parameter " + name + " must not be null."); } params.add(new BasicNameValuePair(name, value.toString())); } public void addNotNullParameter(List params, String name, Object value) { if (value != null) { params.add(new BasicNameValuePair(name, value.toString())); } } public void addTrueParameter(List params, String name, Boolean value) { if (Boolean.TRUE.equals(value)) { params.add(new BasicNameValuePair(name, value.toString())); } } /** * 经纬度转换为地址 * * @param lon 经度 * @param lat 纬度 */ public Result lonLatToAddress(Double lon, Double lat) { List params = new ArrayList(); addParameter(params, "sensor", "false"); addParameter(params, "language", "zh"); addParameter(params, "latlng", lat + "," + lon); String json = get("https://maps.googleapis.com/maps/api/geocode/json", params); JSONObject jsonObject = new JSONObject(json); if (!"OK".equals(jsonObject.getString("status"))) { Error error = new Error(); error.setErrorCode(jsonObject.getString("status")); error.setError(jsonObject.optString("error_message")); return new Result(error); } JSONArray results = jsonObject.getJSONArray("results"); if (results.length() == 0) { return new Result(StringUtils.EMPTY); } return new Result(results.getJSONObject(0).getString("formatted_address")); } } ================================================ FILE: src/main/java/com/belerweb/social/bean/Error.java ================================================ package com.belerweb.social.bean; import org.json.JSONObject; public final class Error extends JsonBean { private String request; private String errorCode; private String error; public Error() {} public Error(String code, String message) { this.errorCode = code; this.error = message; } private Error(JSONObject jsonObject) { super(jsonObject); } public String getRequest() { return request; } public void setRequest(String request) { this.request = request; } public String getErrorCode() { return errorCode; } public void setErrorCode(String errorCode) { this.errorCode = errorCode; } public String getError() { return error; } public void setError(String error) { this.error = error; } @Override public String toString() { return errorCode + ":" + error + "(" + request + ")"; } public static Error parse(JSONObject jsonObject) { String errorCode = jsonObject.optString("error_code", null); if (errorCode != null) {// 微博 String request = jsonObject.optString("request", null); String error = jsonObject.optString("error", null); Error er = new Error(jsonObject); er.setRequest(request); er.setErrorCode(errorCode); er.setError(error); return er; } errorCode = jsonObject.optString("error", null); if (errorCode != null) {// QQ互联 String error = jsonObject.optString("error_description", null); Error er = new Error(jsonObject); er.setErrorCode(errorCode); er.setError(error); return er; } Integer ret = Result.parseInteger(jsonObject.opt("ret")); if (ret != null && ret != 0) {// QQ互联 String msg = jsonObject.optString("msg", null); Error er = new Error(jsonObject); er.setErrorCode(ret.toString()); er.setError(msg); return er; } ret = Result.parseInteger(jsonObject.opt("errcode")); if (ret != null && ret != 0) {// 微信 String error = jsonObject.optString("errmsg", null); Error er = new Error(jsonObject); er.setErrorCode(ret.toString()); er.setError(error); return er; } return null; } } ================================================ FILE: src/main/java/com/belerweb/social/bean/Gender.java ================================================ package com.belerweb.social.bean; public enum Gender { MALE(1, "m", "男", "Male"), FEMALE(0, "f", "女", "Female"), UNKNOWN(-1, "n", "未知", "Unknown"); int intValue; String code; String zhValue; String enValue; private Gender(int intValue, String code, String zhValue, String enValue) { this.intValue = intValue; this.code = code; this.zhValue = zhValue; this.enValue = zhValue; } public int value() { return intValue; } public String code() { return code; } public String text() { return zhValue; } public String enText() { return enValue; } @Override public String toString() { return zhValue; } public static Gender parse(Integer val) { if (val == null) { return null; } if (new Integer(1).equals(val)) { return MALE; } if (new Integer(0).equals(val) || new Integer(2).equals(val)) { // FIXME 微信2代表女性,0表示未知。暂且把微信的未知看作女性,如同新浪微博用户没有设置性别的时候会返回男性一样 return FEMALE; } return UNKNOWN; } public static Gender parse(String val) { if (val == null) { return null; } if ("男".equals(val) || "m".equalsIgnoreCase(val) || "male".equalsIgnoreCase(val) || "b".equalsIgnoreCase(val) || "boy".equalsIgnoreCase(val)) { return MALE; } if ("女".equals(val) || "f".equalsIgnoreCase(val) || "female".equalsIgnoreCase(val) || "g".equalsIgnoreCase(val) || "girl".equalsIgnoreCase(val)) { return FEMALE; } return UNKNOWN; } } ================================================ FILE: src/main/java/com/belerweb/social/bean/JsonBean.java ================================================ package com.belerweb.social.bean; import org.json.JSONObject; public abstract class JsonBean { private JSONObject jsonObject; protected JsonBean() {} protected JsonBean(JSONObject jsonObject) { this.jsonObject = jsonObject; } public JSONObject getJsonObject() { return jsonObject; } } ================================================ FILE: src/main/java/com/belerweb/social/bean/OnlineStatus.java ================================================ package com.belerweb.social.bean; public enum OnlineStatus { ONLINE(1, "在线", "online"), OFFLINE(0, "不在线", "offline"); private int status; private String text; private String enText; private OnlineStatus(int status, String text, String enText) { this.status = status; this.text = text; this.enText = enText; } public boolean online() { return status == 1; } public int status() { return status; } public String text() { return text; } public String enText() { return enText; } @Override public String toString() { return super.toString(); } public static OnlineStatus parse(Integer val) { if (val == null) { return null; } if (new Integer(1).equals(val)) { return ONLINE; } return OFFLINE; } public static OnlineStatus parse(String val) { if (val == null) { return null; } if ("在线".equals(val) || "online".equalsIgnoreCase(val)) { return ONLINE; } return OFFLINE; } } ================================================ FILE: src/main/java/com/belerweb/social/bean/Result.java ================================================ package com.belerweb.social.bean; import java.lang.reflect.Method; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import org.json.JSONArray; import org.json.JSONObject; import com.belerweb.social.exception.SocialException; public class Result { private Error error; private T result; private List results; public Result(Error error) { this.error = error; } public Result(T result) { this.result = result; } public Result(List results) { this.results = results; } public boolean success() { return error == null; } public Error getError() { return error; } public T getResult() { return result; } public List getResults() { return results; } public static Result parse(String json, Class resultType) { try { if (json.matches("^\\s*\\[.*$")) { return new Result(parse(new JSONArray(json), resultType)); } else { return parse(new JSONObject(json), resultType); } } catch (Exception e) { throw new SocialException(e); } } @SuppressWarnings("unchecked") public static Result parse(JSONObject jsonObject, Class resultType) { try { Error error = Error.parse(jsonObject); if (error == null) { Method parse = resultType.getMethod("parse", JSONObject.class); T obj = (T) parse.invoke(null, jsonObject); return new Result(obj); } return new Result(error); } catch (Exception e) { throw new SocialException(e); } } @SuppressWarnings("unchecked") public static List parse(JSONArray jsonArray, Class resultType) { List list = new ArrayList(); if (jsonArray == null) { return list; } try { for (int i = 0; i < jsonArray.length(); i++) { if (resultType.isAssignableFrom(String.class)) { list.add((T) toString(jsonArray.get(i))); } else if (resultType.isAssignableFrom(Integer.class)) { list.add((T) parseInteger(jsonArray.get(i))); } else if (resultType.isAssignableFrom(Long.class)) { list.add((T) parseLong(jsonArray.get(i))); } else if (resultType.isAssignableFrom(Double.class)) { list.add((T) parseDouble(jsonArray.get(i))); } else { Method parse = resultType.getMethod("parse", JSONObject.class); list.add((T) parse.invoke(null, jsonArray.getJSONObject(i))); } } return list; } catch (Exception e) { throw new SocialException(e); } } public static String toString(Object obj) { if (obj == null) { return null; } return obj.toString(); } public static Long parseLong(Object obj) { if (obj == null) { return null; } Long result = null; if (obj instanceof Number) { result = ((Number) obj).longValue(); } else if (obj instanceof String) { result = Long.valueOf((String) obj); } return result; } public static Integer parseInteger(Object obj) { if (obj == null) { return null; } Integer result = null; if (obj instanceof Number) { result = ((Number) obj).intValue(); } else if (obj instanceof String) { result = Integer.valueOf((String) obj); } return result; } public static Double parseDouble(Object obj) { if (obj == null) { return null; } Double result = null; if (obj instanceof Number) { result = ((Number) obj).doubleValue(); } else if (obj instanceof String) { result = Double.valueOf((String) obj); } return result; } public static Boolean parseBoolean(Object obj) { if (obj == null) { return null; } Boolean result = null; if (obj instanceof Boolean) { result = (Boolean) obj; } else if (obj instanceof Integer) { result = ((Integer) obj).intValue() == 1; } else if (obj instanceof String) { result = Boolean.valueOf(obj.toString()); } return result; } public static Date parseDate(Object obj, String pattern, Locale locale) { if (obj == null) { return null; } Date result = null; if (obj instanceof Date) { result = new Date(((Date) obj).getTime()); } else if (obj instanceof String) { try { SimpleDateFormat format = new SimpleDateFormat(pattern, locale); result = format.parse((String) obj); } catch (ParseException e) { throw new SocialException(e); } } return result; } public static Date parseTimeSeconds(Object obj) { Integer seconds = Result.parseInteger(obj); if (seconds == null || seconds == 0) { return null; } return new Date(seconds * 1000); } } ================================================ FILE: src/main/java/com/belerweb/social/captcha/api/Yundama.java ================================================ package com.belerweb.social.captcha.api; import java.io.IOException; import org.apache.commons.io.IOUtils; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.json.JSONObject; import com.belerweb.social.bean.Error; import com.belerweb.social.bean.Result; import com.belerweb.social.captcha.bean.YundamaType; import com.belerweb.social.exception.SocialException; import com.belerweb.social.http.Http; import com.belerweb.social.http.HttpException; public class Yundama { private String appId = "85"; private String appKey = "19fcd07d8de9c03b8cebec5d8bfe7d8e"; private String username; private String password; public Yundama(String username, String password) { this.username = username; this.password = password; } public Result decode(byte[] img, YundamaType type) { HttpPost request = new HttpPost("http://api.yundama.com/api.php?method=upload"); MultipartEntityBuilder builder = MultipartEntityBuilder.create() .addBinaryBody("file", img, ContentType.create("image/png"), "code.png") .addTextBody("username", username).addTextBody("password", password) .addTextBody("codetype", type.getType().toString()).addTextBody("appid", appId) .addTextBody("appkey", appKey).addTextBody("timeout", "60"); request.setEntity(builder.build()); try { HttpResponse response = Http.CLIENT.execute(request); String json = IOUtils.toString(response.getEntity().getContent()); request.releaseConnection(); JSONObject jsonObject = new JSONObject(json); Integer ret = Result.parseInteger(jsonObject.get("ret")); if (ret == 0) { String url = "http://api.yundama.com/api.php?method=result&cid=" + Result.toString(jsonObject.get("cid")); long start = System.currentTimeMillis(); while (true) { jsonObject = new JSONObject(Http.get(url)); if (Result.parseInteger(jsonObject.get("ret")) == 0) { return new Result(Result.toString(jsonObject.get("text"))); } if (System.currentTimeMillis() - start > 10000) { return new Result(new Error("TIMEOUT", "验证码识别超时。")); } try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } } } Error error = new Error(); error.setErrorCode(ret.toString()); return new Result(error); } catch (ClientProtocolException e) { throw new SocialException(e); } catch (HttpException e) { throw new SocialException(e); } catch (IOException e) { throw new SocialException(e); } } } ================================================ FILE: src/main/java/com/belerweb/social/captcha/bean/YundamaType.java ================================================ package com.belerweb.social.captcha.bean; public enum YundamaType { /** * 不定长英文数字 2.5题分一个字符(按文本长度收费) */ ALPHANUMERIC(1000), /** * 1位英文数字 7题分 */ ALPHANUMERIC1(1001), /** * 2位英文数字 8题分 */ ALPHANUMERIC2(1002), /** * 3位英文数字 9题分 */ ALPHANUMERIC3(1003), /** * 4位英文数字 10题分 */ ALPHANUMERIC4(1004), /** * 5位英文数字 12题分 */ ALPHANUMERIC5(1005), /** * 6位英文数字 15题分 */ ALPHANUMERIC6(1006), /** * 7位英文数字 17题分 */ ALPHANUMERIC7(1007), /** * 8位英文数字 20题分 */ ALPHANUMERIC8(1008), /** * 9位英文数字 22题分 */ ALPHANUMERIC9(1009), /** * 10位英文数字 25题分 */ ALPHANUMERIC10(1010), /** * 11位英文数字 27题分 */ ALPHANUMERIC11(1011), /** * 12位英文数字 30题分 */ ALPHANUMERIC12(1012), /** * 13位英文数字 32题分 */ ALPHANUMERIC13(1013), /** * 14位英文数字 35题分 */ ALPHANUMERIC14(1014), /** * 15位英文数字 37题分 */ ALPHANUMERIC15(1015), /** * 16位英文数字 40题分 */ ALPHANUMERIC16(1016), /** * 17位英文数字 42题分 */ ALPHANUMERIC17(1017), /** * 18位英文数字 45题分 */ ALPHANUMERIC18(1018), /** * 19位英文数字 47题分 */ ALPHANUMERIC19(1019), /** * 20位英文数字 50题分 */ ALPHANUMERIC20(1020), /** * 2位纯汉字 20题分 */ CHINESE2(2002), /** * 4位纯汉字 40题分 */ CHINESE4(2004), /** * 4位纯英文 10题分 */ ALPHABETIC4(3004), /** * 5位纯英文 12题分 */ ALPHABETIC5(3005), /** * 6位纯英文 15题分 */ ALPHABETIC6(3006), /** * 4位纯数字 10题分 */ NUMERIC4(4004), /** * 5位纯数字 12题分 */ NUMERIC5(4005); Integer type; YundamaType(Integer type) { this.type = type; } public Integer getType() { return type; } } ================================================ FILE: src/main/java/com/belerweb/social/exception/SocialException.java ================================================ package com.belerweb.social.exception; public class SocialException extends RuntimeException { private static final long serialVersionUID = 3536584215181288508L; public SocialException(Exception exception) { super(exception); } public SocialException(String message) { super(message); } } ================================================ FILE: src/main/java/com/belerweb/social/http/Http.java ================================================ package com.belerweb.social.http; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import javax.net.ssl.SSLContext; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.RandomUtils; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.conn.ssl.SSLContexts; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.entity.ContentType; import org.apache.http.impl.client.HttpClientBuilder; public final class Http { private static final String[] AGENTS = new String[] { "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1664.3 Safari/537.36", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11", "Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11", "Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11", "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; WOW64; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; Media Center PC 5.0; .NET CLR 3.5.21022; GreenBrowser)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; GreenBrowser)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.5.30729; InfoPath.2; .NET CLR 3.0.30729; GreenBrowser)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; OfficeLiveConnector.1.4; OfficeLivePatch.1.3; GreenBrowser)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; GTB6; .NET CLR 2.0.50727; GreenBrowser)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; GTB6; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 1.1.4322; GreenBrowser)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; GTB6.3; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 1.1.4322; GreenBrowser)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; GTB0.0; InfoPath.1; GreenBrowser)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 4.0.20506; GreenBrowser)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 1.1.4322; InfoPath.2; GreenBrowser)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322; GreenBrowser)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.04506.30; GreenBrowser)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; InfoPath.2; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; GreenBrowser)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 4.0; .NET CLR 2.0.50727; InfoPath.1; GreenBrowser)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; GreenBrowser)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; GreenBrowser)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 1.1.4322; GreenBrowser)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 1.1.4322; GreenBrowser)", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.62 Safari/537.36"}; public static final HttpClient CLIENT = newClient(); private static final ThreadLocal defaultCharset = new ThreadLocal(); private static Charset getDefaultCharset() { return defaultCharset.get(); } /** * Sets the default charset for reading the response, which is used while the server side does not * provided the encoding or charset. If {@code null} is set, the {@link Charset#defaultCharset()} * will be used to read the response. Note, this is a {@link ThreadLocal} variable. * * @param charset the charset. * @see #responseToString(HttpResponse) */ public static void setDefaultCharset(Charset charset) { defaultCharset.set(charset); } public static String get(String uri, List params) throws HttpException { String url = uri; if (params != null) { String param = StringUtils.join(params, "&"); if (url.contains("?")) { url = url + "&" + param; } else { url = url + "?" + param; } } return get(url); } public static String get(String uri, Header... headers) throws HttpException { HttpGet request = new HttpGet(uri); if (headers != null) { for (Header header : headers) { request.addHeader(header); } } return execute(request); } public static String post(String uri, HttpEntity postBody, Header... headers) throws HttpException { HttpPost request = new HttpPost(uri); if (postBody != null) { request.setEntity(postBody); } if (headers != null) { for (Header header : headers) { request.addHeader(header); } } return execute(request); } public static String post(String uri, List params, String charset, Header... headers) throws HttpException { HttpPost request = new HttpPost(uri); if (params != null) { List parameters = new ArrayList(); parameters.addAll(params); try { HttpEntity entity = new UrlEncodedFormEntity(parameters, charset); request.setEntity(entity); } catch (UnsupportedEncodingException e) { throw new HttpException(e); } } if (headers != null) { for (Header header : headers) { request.addHeader(header); } } return execute(request); } public static String post(String uri) throws HttpException { return post(uri, (HttpEntity) null); } private static String execute(HttpRequestBase request) throws HttpException { try { HttpResponse response = CLIENT.execute(request); // StatusLine status = response.getStatusLine(); return responseToString(response); // if (status.getStatusCode() != HttpStatus.SC_OK) { // throw new HttpException(status.getStatusCode() + ":" + status.getReasonPhrase() + "\r\n" // + result); // } } catch (ClientProtocolException e) { throw new HttpException(e); } catch (IOException e) { throw new HttpException(e); } finally { request.releaseConnection(); } } public static boolean isRequestSuccess(HttpResponse response) throws HttpException { return response.getStatusLine() != null && response.getStatusLine().getStatusCode() == HttpStatus.SC_OK; } public static String responseToString(HttpResponse response) throws HttpException { HttpEntity entity = response.getEntity(); String result = null; if (entity != null) { Charset charset = null; Header encoding = entity.getContentEncoding(); if (encoding == null) { ContentType contentType = ContentType.get(entity); if (contentType != null) { charset = contentType.getCharset(); } } else { charset = Charset.forName(encoding.getValue()); } if (charset == null) { charset = getDefaultCharset(); } try { result = IOUtils.toString(entity.getContent(), charset); } catch (Exception e) { throw new HttpException(e); } return result; } else { throw new HttpException("No response entity."); } } public static String randomAgent() { return AGENTS[RandomUtils.nextInt(AGENTS.length)]; } public static HttpClient newClient() { SSLContext sslContext = SSLContexts.createDefault(); try { sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() { public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }).build(); } catch (Exception e) { e.printStackTrace(); } return HttpClientBuilder .create() .setSslcontext(sslContext) .setMaxConnPerRoute(50) .setMaxConnTotal(200) .setUserAgent(Http.randomAgent()) .setDefaultRequestConfig( RequestConfig.custom().setConnectTimeout(30000).setSocketTimeout(30000) .setConnectionRequestTimeout(30000).build()).build(); } } ================================================ FILE: src/main/java/com/belerweb/social/http/HttpException.java ================================================ package com.belerweb.social.http; public class HttpException extends Exception { private static final long serialVersionUID = -7528165403129614352L; public HttpException(Exception exception) { super(exception); } public HttpException(String message) { super(message); } } ================================================ FILE: src/main/java/com/belerweb/social/mail/api/POP3.java ================================================ package com.belerweb.social.mail.api; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.Reader; import java.net.SocketException; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.net.pop3.POP3Client; import org.apache.commons.net.pop3.POP3MessageInfo; import org.apache.commons.net.pop3.POP3SClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.belerweb.social.exception.SocialException; /** * POP3 邮件工具 */ public class POP3 { private static final Logger LOGGER = LoggerFactory.getLogger(POP3.class); private String username; private String password; private String host; private int port; private POP3Client client; public POP3(String username, String password, String host) { this(username, password, host, org.apache.commons.net.pop3.POP3.DEFAULT_PORT, false); } public POP3(String username, String password, String host, int port, boolean ssl) { this.username = username; this.password = password; this.host = host; this.port = port; if (ssl) { this.client = new POP3SClient("SSL", true); } else { this.client = new POP3Client(); } this.client.setDefaultTimeout(300000); } private boolean login() throws SocketException, IOException { client.connect(host, port); return client.login(username, password); } /** * 检查用户信息是否正确 */ public boolean test() throws SocialException { try { return login(); } catch (SocketException e) { e.printStackTrace(); throw new SocialException(e); } catch (IOException e) { e.printStackTrace(); throw new SocialException(e); } finally { try { this.client.disconnect(); } catch (IOException e) { e.printStackTrace(); } } } /** * 下载所有电子邮件到指定目录 */ public void download(File dir) throws SocialException { if (!dir.isDirectory() || !dir.canWrite()) { throw new SocialException("The specified directory is unavailable."); } try { if (login()) { POP3MessageInfo[] messages = client.listUniqueIdentifiers(); if (messages == null) { LOGGER.debug("Could not retrieve message list."); throw new SocialException("Could not retrieve message list."); } else { for (POP3MessageInfo message : messages) { File eml = new File(dir, username + "@" + host + "/" + message.identifier + ".eml"); try { Reader reader = client.retrieveMessage(message.number); if (reader == null) { LOGGER.debug("Could not retrieve message."); continue; } if (eml.exists() && ((message.size > 0 && eml.length() == message.size) || eml.length() > 1000)) { LOGGER.debug("Message {} exist, skip download.", message.identifier); continue; } eml.getParentFile().mkdirs(); LOGGER.debug("Downloading {} ...", message.identifier); IOUtils.copy(reader, new FileOutputStream(eml));; LOGGER.debug("Downloaded {} ...", message.identifier); } catch (Exception e) { try { FileUtils.forceDelete(eml); } catch (Exception exception) { e.printStackTrace(); } } } } } } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { client.disconnect(); } catch (IOException e) { e.printStackTrace(); } } } /** * 下载所有电子邮件到指定目录 */ public void download(String dir) { download(new File(dir)); } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/api/OAuth2.java ================================================ package com.belerweb.social.qq.connect.api; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.apache.http.NameValuePair; import org.json.JSONObject; import com.belerweb.social.API; import com.belerweb.social.bean.Result; import com.belerweb.social.qq.connect.bean.AccessToken; import com.belerweb.social.qq.connect.bean.Display; import com.belerweb.social.qq.connect.bean.Gut; import com.belerweb.social.qq.connect.bean.OpenID; import com.belerweb.social.qq.connect.bean.Scope; public final class OAuth2 extends API { OAuth2(QQConnect connect) { super(connect); } /** * 获取Authorization Code * * @see OAuth2#authorize(Boolean) */ public String authorize() { return authorize(false); } /** * 获取Authorization Code * * @see OAuth2#authorize(String, Boolean) */ public String authorize(String redirectUri) { return authorize(redirectUri, false); } /** * 获取Authorization Code * * 从 {@link QQConnect} 从获取clientId,redirectUri,responseType为code,state使用authorize,scope使用 * {@link Scope#ALL},其余参数默认 * * @see OAuth2#authorize(String, String, String, String, Scope[], Display, Gut, Boolean) */ public String authorize(Boolean wap) { return authorize(connect.getRedirectUri(), wap); } /** * 获取Authorization Code * * 从 {@link QQConnect} 从获取clientId,responseType为code,state使用authorize,scope使用 {@link Scope#ALL} * ,其余参数默认 * * @see OAuth2#authorize(String, String, String, String, Scope[], Display, Gut, Boolean) */ public String authorize(String redirectUri, Boolean wap) { return authorize(connect.getClientId(), redirectUri, "code", "authorize", Scope.ALL, null, null, wap); } /** * 获取Authorization Code * * 文档地址:http://wiki.connect.qq.com/使用authorization_code获取access_token * * @param clientId 必须,申请QQ登录成功后,分配给应用的appid。 * @param redirectUri 必须,成功授权后的回调地址,必须是注册appid时填写的主域名下的地址,建议设置为网站首页或网站的用户中心。注意需要将url进行URLEncode。 * @param responseType 必须,授权类型,此值固定为“code”。 * @param state 必须,client端的状态值。用于第三方应用防止CSRF攻击,成功授权后回调时会原样带回。请务必严格按照流程检查用户与state参数状态的绑定。 * @param scope 可选,请求用户授权时向用户显示的可进行授权的列表 * @param display 可选,仅PC网站接入时使用。用于展示的样式。不传则默认展示为PC下的样式。如果传入“mobile”,则展示为mobile端下的样式。 * @param gut 仅WAP网站接入时使用。QQ登录页面版本(1:wml版本; 2:xhtml版本),默认值为1。 * @param wap 是否使wap版,默认为false */ public String authorize(String clientId, String redirectUri, String responseType, String state, Scope[] scope, Display display, Gut gut, Boolean wap) { List params = new ArrayList(); connect.addParameter(params, "response_type", responseType); connect.addParameter(params, "client_id", clientId); connect.addParameter(params, "redirect_uri", redirectUri); connect.addParameter(params, "state", state); if (scope != null) { connect.addParameter(params, "scope", StringUtils.join(scope, ",")); } if (Display.MOBILE.equals(display)) { connect.addParameter(params, "display", "mobile"); } if (Gut.XHTML.equals(gut)) { connect.addParameter(params, "g_ut", gut.toString()); } String url = "https://graph.qq.com/oauth2.0/authorize?"; if (Boolean.TRUE.equals(wap)) { url = "https://graph.z.qq.com/moc2/authorize?"; } return url + StringUtils.join(params, "&"); } /** * 通过Authorization Code获取Access Token,此接口适用于PC网站。 * * 从 {@link QQConnect} 从获取clientId,clientSecret,redirectUri,grantType为authorization_code * * @see OAuth2#accessToken(String, String, String, String, String, Boolean) */ public Result accessToken(String code) { return accessToken(code, connect.getRedirectUri()); } /** * 通过Authorization Code获取Access Token,此接口适用于PC网站。 * * 从 {@link QQConnect} 从获取clientId,clientSecret,grantType为authorization_code * * @see OAuth2#accessToken(String, String, String, String, String, Boolean) */ public Result accessToken(String code, String redirectUri) { return accessToken(code, redirectUri, null); } /** * 通过Authorization Code获取Access Token * * 从 {@link QQConnect} 从获取clientId,clientSecret,redirectUri,grantType为authorization_code * * @see OAuth2#accessToken(String, String, String, String, String, Boolean) */ public Result accessToken(String code, Boolean wap) { return accessToken(code, connect.getRedirectUri(), wap); } /** * 通过Authorization Code获取Access Token * * 从 {@link QQConnect} 从获取clientId,clientSecret,grantType为authorization_code * * @see OAuth2#accessToken(String, String, String, String, String, Boolean) */ public Result accessToken(String code, String redirectUri, Boolean wap) { return accessToken(connect.getClientId(), connect.getClientSecret(), "authorization_code", code, redirectUri, wap); } /** * 通过Authorization Code获取Access Token * * 文档地址:http://wiki.connect.qq.com/使用authorization_code获取access_token * * @param clientId 申请QQ登录成功后,分配给网站的appid。 * @param clientSecret 申请QQ登录成功后,分配给网站的appkey。 * @param grantType 授权类型,在本步骤中,此值为“authorization_code”。 * @param code 上一步返回的authorization code。如果用户成功登录并授权,则会跳转到指定的回调地址,并在URL中带上Authorization * Code。注意此code会在10分钟内过期。 * @param redirectUri 与上面一步中传入的redirect_uri保持一致。 * @param wap 是否使wap版,默认为false */ public Result accessToken(String clientId, String clientSecret, String grantType, String code, String redirectUri, Boolean wap) { List params = new ArrayList(); connect.addParameter(params, "client_id", clientId); connect.addParameter(params, "client_secret", clientSecret); connect.addParameter(params, "grant_type", grantType); connect.addParameter(params, "code", code); connect.addParameter(params, "redirect_uri", redirectUri); String url = "https://graph.qq.com/oauth2.0/token"; if (Boolean.TRUE.equals(wap)) { url = "https://graph.z.qq.com/moc2/token"; } String result = connect.get(url, params).trim(); return parseAccessTokenResult(result); } /** * 权限自动续期,获取Access Token,此方法适用于PC网站。 * * 从 {@link QQConnect}中获取 clientId, clientSecret * * @see OAuth2#refreshAccessToken(String, String, String, String, Boolean) * @param refreshToken {@link AccessToken}中的refresToken。 */ public Result refreshAccessToken(String refreshToken) { return refreshAccessToken(connect.getClientId(), connect.getClientSecret(), refreshToken); } /** * 权限自动续期,获取Access Token,此方法适用于PC网站。 * * @see OAuth2#refreshAccessToken(String, String, String, String, Boolean) * @param refreshToken {@link AccessToken}中的refresToken。 */ public Result refreshAccessToken(String clientId, String clientSecret, String refreshToken) { return refreshAccessToken(clientId, clientSecret, "refresh_token", refreshToken, null); } /** * 权限自动续期,获取Access Token * * 从 {@link QQConnect}中获取 clientId, clientSecret * * @see OAuth2#refreshAccessToken(String, String, String, String, Boolean) * @param refreshToken {@link AccessToken}中的refresToken。 * @param wap 是否使wap版,默认为false */ public Result refreshAccessToken(String refreshToken, Boolean wap) { return refreshAccessToken(connect.getClientId(), connect.getClientSecret(), refreshToken, wap); } /** * 权限自动续期,获取Access Token * * @see OAuth2#refreshAccessToken(String, String, String, String, Boolean) * @param refreshToken {@link AccessToken}中的refresToken。 * @param wap 是否使wap版,默认为false */ public Result refreshAccessToken(String clientId, String clientSecret, String refreshToken, Boolean wap) { return refreshAccessToken(clientId, clientSecret, "refresh_token", refreshToken, wap); } /** * 权限自动续期,获取Access Token * * 文档地址:http://wiki.connect.qq.com/使用authorization_code获取access_token * * @param clientId 申请QQ登录成功后,分配给网站的appid。 * @param clientSecret 申请QQ登录成功后,分配给网站的appkey。 * @param grantType 授权类型,在本步骤中,此值为“refresh_token”。 * @param refresToken {@link AccessToken}中的refresToken。 * @param wap 是否使wap版,默认为false */ public Result refreshAccessToken(String clientId, String clientSecret, String grantType, String refreshToken, Boolean wap) { List params = new ArrayList(); connect.addParameter(params, "client_id", clientId); connect.addParameter(params, "client_secret", clientSecret); connect.addParameter(params, "grant_type", grantType); connect.addParameter(params, "refresh_token", refreshToken); String url = "https://graph.qq.com/oauth2.0/token"; if (Boolean.TRUE.equals(wap)) { url = "https://graph.z.qq.com/moc2/token"; } String result = connect.get(url, params); return parseAccessTokenResult(result); } /** * 获取用户OpenID,此接口适用于PC网站访问 * * 文档地址:http://wiki.connect.qq.com/获取用户openid_oauth2-0 * * @param accessToken 授权令牌 */ public Result openId(String accessToken) { return openId(accessToken, null); } /** * 获取用户OpenID * * 文档地址:http://wiki.connect.qq.com/获取用户openid_oauth2-0 * * @param accessToken 授权令牌 * @param wap 是否使wap网站访问 */ public Result openId(String accessToken, Boolean wap) { List params = new ArrayList(); connect.addParameter(params, "access_token", accessToken); String url = "https://graph.qq.com/oauth2.0/me"; if (Boolean.TRUE.equals(wap)) { url = "https://graph.z.qq.com/moc2/me"; } String result = connect.get(url, params).trim(); JSONObject jsonObject; if (result.startsWith("callback")) {// PC网站的正确返回结果 jsonObject = new JSONObject(result.substring(result.indexOf("{"), result.lastIndexOf("}") + 1)); } else {// WAP网站返回结果或错误信息 jsonObject = new JSONObject(); String[] results = result.split("\\&"); for (String param : results) { String[] keyValue = param.split("\\="); jsonObject.put(keyValue[0], keyValue.length > 0 ? keyValue[1] : null); } String errorCode = jsonObject.optString("code", null); if (errorCode != null) { jsonObject.put("ret", errorCode);// To match Error.parse() } } return Result.parse(jsonObject, OpenID.class); } private Result parseAccessTokenResult(String result) { JSONObject jsonObject; if (result.startsWith("callback")) {// 错误信息 // callback({"error":100021,"error_description":"get access token error"}); jsonObject = new JSONObject(result.substring(result.indexOf("{"), result.lastIndexOf("}") + 1)); return Result.parse(jsonObject, AccessToken.class); } else {// 正确结果 jsonObject = new JSONObject(); String[] results = result.split("\\&"); for (String param : results) { String[] keyValue = param.split("\\="); jsonObject.put(keyValue[0], keyValue.length > 0 ? keyValue[1] : null); } String errorCode = jsonObject.optString("code", null); if (errorCode != null) { jsonObject.put("ret", errorCode);// To match Error.parse() } } return Result.parse(jsonObject, AccessToken.class); } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/api/QQConnect.java ================================================ package com.belerweb.social.qq.connect.api; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Locale; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.json.JSONObject; import com.belerweb.social.SDK; import com.belerweb.social.bean.Error; import com.belerweb.social.bean.Result; import com.belerweb.social.exception.SocialException; import com.belerweb.social.http.Http; import com.belerweb.social.qq.connect.bean.NewT; import com.belerweb.social.qq.connect.bean.TenpayAddress; public final class QQConnect extends SDK { private String clientId; private String clientSecret; private String redirectUri; private OAuth2 oAuth2; private User user; public QQConnect(String clientId, String clientSecret) { this.clientId = clientId; this.clientSecret = clientSecret; } public QQConnect(String clientId, String clientSecret, String redirectUri) { this(clientId, clientSecret); this.redirectUri = redirectUri; } /** * 收听腾讯微博上的用户。 * * 文档地址:http://wiki.connect.qq.com/add_idol * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openId 用户的ID,与QQ号码一一对应。 * @param name 要收听的用户的账户名列表。最多30个。 */ public Result addIdol(String accessToken, String openId, List name) { return addIdol(accessToken, openId, name, null); } /** * 收听腾讯微博上的用户。 * * 文档地址:http://wiki.connect.qq.com/add_idol * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openId 用户的ID,与QQ号码一一对应。 * @param name 要收听的用户的账户名列表。最多30个。 * @param fopenids 要收听的用户的openid列表。最多30个。 name和fopenids至少选一个,若同时存在则以name值为主。 */ public Result addIdol(String accessToken, String openId, List name, List fopenids) { return addIdol(accessToken, getClientId(), openId, name, fopenids); } /** * 收听腾讯微博上的用户。 * * 文档地址:http://wiki.connect.qq.com/add_idol * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param oauthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param openId 用户的ID,与QQ号码一一对应。 * @param name 要收听的用户的账户名列表。最多30个。 * @param fopenids 要收听的用户的openid列表。最多30个。 name和fopenids至少选一个,若同时存在则以name值为主。 */ public Result addIdol(String accessToken, String oauthConsumerKey, String openId, List name, List fopenids) { List params = new ArrayList(); addParameter(params, "access_token", accessToken); addParameter(params, "oauth_consumer_key", oauthConsumerKey); addParameter(params, "openid", openId); if (name != null && !name.isEmpty()) { addParameter(params, "name", StringUtils.join(name, ",")); } if (fopenids != null && !fopenids.isEmpty()) { addParameter(params, "fopenids", StringUtils.join(fopenids, "_")); } addParameter(params, "format", "json"); return Result.parse(post("https://graph.qq.com/relation/add_idol", params), Error.class); } /** * 取消收听腾讯微博上的用户。 * * 文档地址:http://wiki.connect.qq.com/del_idol * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openId 用户的ID,与QQ号码一一对应。 * @param name 要取消收听的用户的账户名。 可选,name和fopenid至少选一个,若同时存在则以name值为主。 */ public Result delIdol(String accessToken, String openId, String name) { return delIdol(accessToken, openId, name, null); } /** * 取消收听腾讯微博上的用户。 * * 文档地址:http://wiki.connect.qq.com/del_idol * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openId 用户的ID,与QQ号码一一对应。 * @param name 要取消收听的用户的账户名。 可选,name和fopenid至少选一个,若同时存在则以name值为主。 * @param fopenid 要取消收听的用户的openid。可选,name和fopenid至少选一个,若同时存在则以name值为主。 */ public Result delIdol(String accessToken, String openId, String name, String fopenid) { return delIdol(accessToken, getClientId(), openId, name, fopenid); } /** * 取消收听腾讯微博上的用户。 * * 文档地址:http://wiki.connect.qq.com/del_idol * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param oauthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param openId 用户的ID,与QQ号码一一对应。 * @param name 要取消收听的用户的账户名。 可选,name和fopenid至少选一个,若同时存在则以name值为主。 * @param fopenid 要取消收听的用户的openid。可选,name和fopenid至少选一个,若同时存在则以name值为主。 */ public Result delIdol(String accessToken, String oauthConsumerKey, String openId, String name, String fopenid) { List params = new ArrayList(); addParameter(params, "access_token", accessToken); addParameter(params, "oauth_consumer_key", oauthConsumerKey); addParameter(params, "openid", openId); addNotNullParameter(params, "name", name); addNotNullParameter(params, "fopenid", fopenid); addParameter(params, "format", "json"); return Result.parse(post("https://graph.qq.com/relation/del_idol", params), Error.class); } /** * 登录用户发表一篇新日志。 * * 文档地址:http://wiki.connect.qq.com/add_one_blog * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openId 用户的ID,与QQ号码一一对应。 * @param title 日志标题(纯文本,最大长度128个字节,utf-8编码)。 * @param content 文章内容(html数据,最大长度100*1024个字节,utf-8编码). */ public Result addOneBlog(String accessToken, String openId, String title, String content) { return addOneBlog(accessToken, getClientId(), openId, title, content); } /** * 登录用户发表一篇新日志。 * * 文档地址:http://wiki.connect.qq.com/add_one_blog * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param oauthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param openId 用户的ID,与QQ号码一一对应。 * @param title 日志标题(纯文本,最大长度128个字节,utf-8编码)。 * @param content 文章内容(html数据,最大长度100*1024个字节,utf-8编码). */ public Result addOneBlog(String accessToken, String oauthConsumerKey, String openId, String title, String content) { List params = new ArrayList(); addParameter(params, "access_token", accessToken); addParameter(params, "oauth_consumer_key", oauthConsumerKey); addParameter(params, "openid", openId); addParameter(params, "title", title); addParameter(params, "content", content); addParameter(params, "format", "json"); return Result.parse(post("https://graph.qq.com/blog/add_one_blog", params), Error.class); } /** * 发表一条微博信息(纯文本)到腾讯微博平台上。注意连续两次发布的微博内容不可以重复。 * * 文档地址:http://wiki.connect.qq.com/add_t * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openId 用户的ID,与QQ号码一一对应。 * @param content * 表示要发表的微博内容。必须为UTF-8编码,最长为140个汉字,也就是420字节。如果微博内容中有URL,后台会自动将该URL转换为短URL,每个URL折算成11个字节。 * 若在此处@好友,需正确填写好友的微博账号,而非昵称。 */ public Result addT(String accessToken, String openId, String content) { return addT(accessToken, getClientId(), openId, content); } /** * 发表一条微博信息(纯文本)到腾讯微博平台上。注意连续两次发布的微博内容不可以重复。 * * 文档地址:http://wiki.connect.qq.com/add_t * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param oauthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param openId 用户的ID,与QQ号码一一对应。 * @param content * 表示要发表的微博内容。必须为UTF-8编码,最长为140个汉字,也就是420字节。如果微博内容中有URL,后台会自动将该URL转换为短URL,每个URL折算成11个字节。 * 若在此处@好友,需正确填写好友的微博账号,而非昵称。 */ public Result addT(String accessToken, String oauthConsumerKey, String openId, String content) { return addT(accessToken, oauthConsumerKey, openId, content, null, null, null, true, true); } /** * 发表一条微博信息(纯文本)到腾讯微博平台上。注意连续两次发布的微博内容不可以重复。 * * 文档地址:http://wiki.connect.qq.com/add_t * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param oauthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param openId 用户的ID,与QQ号码一一对应。 * @param content * 表示要发表的微博内容。必须为UTF-8编码,最长为140个汉字,也就是420字节。如果微博内容中有URL,后台会自动将该URL转换为短URL,每个URL折算成11个字节。 * 若在此处@好友,需正确填写好友的微博账号,而非昵称。 * @param clientIp 用户ip。必须正确填写用户侧真实ip,不能为内网ip及以127或255开头的ip,以分析用户所在地。 * @param lon 用户所在地理位置的经度。为实数,最多支持10位有效数字。有效范围:-180.0到+180.0,+表示东经,默认为0.0。 * @param lat 用户所在地理位置的纬度。为实数,最多支持10位有效数字。有效范围:-90.0到+90.0,+表示北纬,默认为0.0。 * @param sync 标识是否将发布的微博同步到QQ空间(0:同步; 1:不同步;),默认为0。该参数只支持OAuth1.0,OAuth2.0暂不支持。 * @param compatible 容错标志,支持按位操作,默认为0。0x20:微博内容长度超过140字则报错;0:以上错误均做容错处理,即发表普通微博。 */ public Result addT(String accessToken, String oauthConsumerKey, String openId, String content, String clientIp, Double lon, Double lat, Boolean sync, Boolean compatible) { List params = new ArrayList(); addParameter(params, "access_token", accessToken); addParameter(params, "oauth_consumer_key", oauthConsumerKey); addParameter(params, "openid", openId); addParameter(params, "content", content); addNotNullParameter(params, "clientip", clientIp); addNotNullParameter(params, "lon", lon); addNotNullParameter(params, "lat", lat); if (sync != null) { addParameter(params, "syncflag", sync ? "0" : "1"); } if (compatible != null) { addParameter(params, "compatibleflag", compatible ? "0" : "0x20"); } addParameter(params, "format", "json"); JSONObject jsonObject = new JSONObject(post("https://graph.qq.com/t/add_t", params)); Error error = Error.parse(jsonObject); if (error != null) { return new Result(error); } return Result.parse(jsonObject.getJSONObject("data"), NewT.class); } /** * 根据微博ID删除指定微博。 * * 文档地址:http://wiki.connect.qq.com/del_t * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openId 用户的ID,与QQ号码一一对应。 * @param id 微博消息的ID,用来唯一标识一条微博消息。 */ public Result delT(String accessToken, String openId, String id) { return delT(accessToken, getClientId(), openId, id); } /** * 上传一张图片,并发布一条消息到腾讯微博平台上。 * * 文档地址:http://wiki.connect.qq.com/add_pic_t * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openId 用户的ID,与QQ号码一一对应。 * @param content * 表示要发表的微博内容。必须为UTF-8编码,最长为140个汉字,也就是420字节。如果微博内容中有URL,后台会自动将该URL转换为短URL,每个URL折算成11个字节。 * 若在此处@好友,需正确填写好友的微博账号,而非昵称。 * @param pic * 要上传的图片的文件名以及图片的内容(在发送请求时,图片内容以二进制数据流的形式发送,见下面的请求示例)。图片仅支持gif、jpeg、jpg、png、bmp及ico格式(所有图片都会重新压缩 * ,gif被重新压缩后不会再有动画效果),图片size小于4M。 */ public Result addPicT(String accessToken, String openId, String content, byte[] pic) { return addPicT(accessToken, getClientId(), openId, content, pic); } /** * 上传一张图片,并发布一条消息到腾讯微博平台上。 * * 文档地址:http://wiki.connect.qq.com/add_pic_t * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param oauthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param openId 用户的ID,与QQ号码一一对应。 * @param content * 表示要发表的微博内容。必须为UTF-8编码,最长为140个汉字,也就是420字节。如果微博内容中有URL,后台会自动将该URL转换为短URL,每个URL折算成11个字节。 * 若在此处@好友,需正确填写好友的微博账号,而非昵称。 * @param pic * 要上传的图片的文件名以及图片的内容(在发送请求时,图片内容以二进制数据流的形式发送,见下面的请求示例)。图片仅支持gif、jpeg、jpg、png、bmp及ico格式(所有图片都会重新压缩 * ,gif被重新压缩后不会再有动画效果),图片size小于4M。 */ public Result addPicT(String accessToken, String oauthConsumerKey, String openId, String content, byte[] pic) { return addPicT(accessToken, oauthConsumerKey, openId, content, pic, null, null, null, true, true); } /** * 上传一张图片,并发布一条消息到腾讯微博平台上。 * * 文档地址:http://wiki.connect.qq.com/add_pic_t * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param oauthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param openId 用户的ID,与QQ号码一一对应。 * @param content * 表示要发表的微博内容。必须为UTF-8编码,最长为140个汉字,也就是420字节。如果微博内容中有URL,后台会自动将该URL转换为短URL,每个URL折算成11个字节。 * 若在此处@好友,需正确填写好友的微博账号,而非昵称。 * @param pic * 要上传的图片的文件名以及图片的内容(在发送请求时,图片内容以二进制数据流的形式发送,见下面的请求示例)。图片仅支持gif、jpeg、jpg、png、bmp及ico格式(所有图片都会重新压缩 * ,gif被重新压缩后不会再有动画效果),图片size小于4M。 * @param clientIp 用户ip。必须正确填写用户侧真实ip,不能为内网ip及以127或255开头的ip,以分析用户所在地。 * @param lon 用户所在地理位置的经度。为实数,最多支持10位有效数字。有效范围:-180.0到+180.0,+表示东经,默认为0.0。 * @param lat 用户所在地理位置的纬度。为实数,最多支持10位有效数字。有效范围:-90.0到+90.0,+表示北纬,默认为0.0。 * @param sync 标识是否将发布的微博同步到QQ空间(0:同步; 1:不同步;),默认为0。该参数只支持OAuth1.0,OAuth2.0暂不支持。 * @param compatible 容错标志,支持按位操作,默认为0。0x20:微博内容长度超过140字则报错;0:以上错误均做容错处理,即发表普通微博。 */ public Result addPicT(String accessToken, String oauthConsumerKey, String openId, String content, byte[] pic, String clientIp, Double lon, Double lat, Boolean sync, Boolean compatible) { HttpPost request = new HttpPost("https://graph.qq.com/t/add_pic_t"); MultipartEntityBuilder builder = MultipartEntityBuilder.create().addBinaryBody("pic", pic); List params = new ArrayList(); addParameter(params, "access_token", accessToken); addParameter(params, "oauth_consumer_key", oauthConsumerKey); addParameter(params, "openid", openId); addParameter(params, "content", content); addNotNullParameter(params, "clientip", clientIp); addNotNullParameter(params, "lon", lon); addNotNullParameter(params, "lat", lat); if (sync != null) { addParameter(params, "syncflag", sync ? "0" : "1"); } if (compatible != null) { addParameter(params, "compatibleflag", compatible ? "0" : "0x20"); } addParameter(params, "format", "json"); for (NameValuePair nameValuePair : params) { builder.addTextBody(nameValuePair.getName(), nameValuePair.getValue()); } request.setEntity(builder.build()); try { HttpResponse response = Http.CLIENT.execute(request); String json = IOUtils.toString(response.getEntity().getContent()); JSONObject jsonObject = new JSONObject(json); Error error = Error.parse(jsonObject); if (error != null) { return new Result(error); } return Result.parse(jsonObject.getJSONObject("data"), NewT.class); } catch (ClientProtocolException e) { throw new SocialException(e); } catch (IOException e) { throw new SocialException(e); } finally { request.releaseConnection(); } } /** * 根据微博ID删除指定微博。 * * 文档地址:http://wiki.connect.qq.com/del_t * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param oauthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param openId 用户的ID,与QQ号码一一对应。 * @param id 微博消息的ID,用来唯一标识一条微博消息。 */ public Result delT(String accessToken, String oauthConsumerKey, String openId, String id) { List params = new ArrayList(); addParameter(params, "access_token", accessToken); addParameter(params, "oauth_consumer_key", oauthConsumerKey); addParameter(params, "openid", openId); addParameter(params, "id", id); addParameter(params, "format", "json"); return Result.parse(post("https://graph.qq.com/t/del_t", params), Error.class); } /** * 获取财付通用户的收货地址。一个用户可能设置了多条收货地址信息。查询的用户必须为财付通用户,否则查询将返回失败。 * * 文档地址:http://wiki.connect.qq.com/get_tenpay_addr * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openId 用户的ID,与QQ号码一一对应。 */ public Result> getTenpayAddr(String accessToken, String openId) { return getTenpayAddr(accessToken, getClientId(), openId, 0, Integer.MAX_VALUE); } /** * 获取财付通用户的收货地址。一个用户可能设置了多条收货地址信息。查询的用户必须为财付通用户,否则查询将返回失败。 * * 文档地址:http://wiki.connect.qq.com/get_tenpay_addr * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openId 用户的ID,与QQ号码一一对应。 * @param offset * 表示查询收货地址的偏移量,一般情况下offset可以不传值或传入0,表示从第一条开始读取。offset参数是为一种特殊情况准备的,即该收货人有很多条收获地址,需要分页展示, * 则offset可设置为该页显示的条数。例如如果offset为10,则会跳过第10条收货地址,从第11条收货地址开始读取。 * @param limit 表示查询收货地址的返回限制数(即最多期望返回几个收货地址)。limit不传默认按照5来处理。 */ public Result> getTenpayAddr(String accessToken, String openId, Integer offset, Integer limit) { return getTenpayAddr(accessToken, getClientId(), openId, offset, limit); } /** * 获取财付通用户的收货地址。一个用户可能设置了多条收货地址信息。查询的用户必须为财付通用户,否则查询将返回失败。 * * 文档地址:http://wiki.connect.qq.com/get_tenpay_addr * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param oauthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param openId 用户的ID,与QQ号码一一对应。 * @param offset * 表示查询收货地址的偏移量,一般情况下offset可以不传值或传入0,表示从第一条开始读取。offset参数是为一种特殊情况准备的,即该收货人有很多条收获地址,需要分页展示, * 则offset可设置为该页显示的条数。例如如果offset为10,则会跳过第10条收货地址,从第11条收货地址开始读取。 * @param limit 表示查询收货地址的返回限制数(即最多期望返回几个收货地址)。limit不传默认按照5来处理。 */ public Result> getTenpayAddr(String accessToken, String oauthConsumerKey, String openId, Integer offset, Integer limit) { List params = new ArrayList(); addParameter(params, "access_token", accessToken); addParameter(params, "oauth_consumer_key", oauthConsumerKey); addParameter(params, "openid", openId); addParameter(params, "offset", offset == null ? "0" : offset); addParameter(params, "limit", limit == null ? "5" : limit); addParameter(params, "ver", "1"); addParameter(params, "format", "json"); JSONObject jsonObject = new JSONObject(post("https://graph.qq.com/cft_info/get_tenpay_addr", params)); Error error = Error.parse(jsonObject); if (error != null) { return new Result>(error); } List addresses = new ArrayList(); Integer total = Result.parseInteger(jsonObject.get("ret_num")); for (int i = 0; i < total; i++) { Integer index = Result.parseInteger(jsonObject.opt("Findex_" + i)); if (index == null) { break; } TenpayAddress address = new TenpayAddress(); address.setTotal(total); address.setIndex(index); address.setRegionId(Result.parseInteger(jsonObject.opt("FRegionId_" + i))); address.setStreet(jsonObject.optString("Faddrstreet_" + i)); address.setZipcode(Result.toString(jsonObject.opt("Fzipcode_" + i))); address.setMobile(Result.toString(jsonObject.opt("Fmobile_" + i))); address.setTel(Result.toString(jsonObject.opt("Ftel_" + i))); address.setName(Result.toString(jsonObject.opt("Fname_" + i))); address.setCreated(Result.parseDate(jsonObject.opt("Fcreate_time_" + i), "yyyy-MM-dd HH:mm:ss", Locale.CHINA)); address.setModified(Result.parseDate(jsonObject.opt("Fmod_time_" + i), "yyyy-MM-dd HH:mm:ss", Locale.CHINA)); address.setLastUsed(Result.parseDate(jsonObject.opt("Flastuse_time_" + i), "yyyy-MM-dd HH:mm:ss", Locale.CHINA)); address.setUsedCount(Result.parseInteger(jsonObject.opt("FUsedCount_" + i))); } return new Result>(addresses); } public OAuth2 getOAuth2() { if (oAuth2 == null) { oAuth2 = new OAuth2(this); } return oAuth2; } public User getUser() { if (user == null) { user = new User(this); } return user; } public String getClientId() { return clientId; } public void setClientId(String clientId) { this.clientId = clientId; } public String getClientSecret() { return clientSecret; } public void setClientSecret(String clientSecret) { this.clientSecret = clientSecret; } public String getRedirectUri() { return redirectUri; } public void setRedirectUri(String redirectUri) { this.redirectUri = redirectUri; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/api/QZone.java ================================================ package com.belerweb.social.qq.connect.api; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.commons.io.IOUtils; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.json.JSONArray; import org.json.JSONObject; import com.belerweb.social.API; import com.belerweb.social.bean.Error; import com.belerweb.social.bean.Result; import com.belerweb.social.exception.SocialException; import com.belerweb.social.http.Http; import com.belerweb.social.qq.connect.bean.Album; import com.belerweb.social.qq.connect.bean.AlbumPrivilege; import com.belerweb.social.qq.connect.bean.Photo; import com.belerweb.social.qq.connect.bean.PicUploadResult; /** * QZone API,相册,日志... */ public final class QZone extends API { protected QZone(QQConnect connect) { super(connect); } /** * 获取登录用户的相册列表。 * * 文档地址:http://wiki.connect.qq.com/list_album * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 */ public Result listAlbum(String accessToken, String openid) { return listAlbum(connect.getClientId(), accessToken, openid); } /** * 获取登录用户的相册列表。 * * 文档地址:http://wiki.connect.qq.com/list_album * * @param oAuthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 */ public Result listAlbum(String oAuthConsumerKey, String accessToken, String openid) { List params = new ArrayList(); connect.addParameter(params, "oauth_consumer_key", oAuthConsumerKey); connect.addParameter(params, "access_token", accessToken); connect.addParameter(params, "openid", openid); connect.addParameter(params, "format", "json"); String json = connect.get("https://graph.qq.com/photo/list_album", params); JSONObject jsonObject = new JSONObject(json); Error error = Error.parse(jsonObject); if (error != null) { return new Result(error); } List results = new ArrayList(); JSONArray jsonArray = jsonObject.getJSONArray("album"); for (int i = 0; i < jsonArray.length(); i++) { results.add(Album.parse(jsonArray.getJSONObject(i))); } return new Result(results); } /** * 登录用户创建一个公共相册。注:每个用户最多可创建10个相册。 * * 文档地址:http://wiki.connect.qq.com/add_album * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 * @param albumName 相册名,不能超过30个字符。 */ public Result addAlbum(String accessToken, String openid, String albumName) { return addAlbum(connect.getClientId(), accessToken, openid, albumName, null, null, null, null); } /** * 登录用户创建相册。注:每个用户最多可创建10个相册。 * * 文档地址:http://wiki.connect.qq.com/add_album * * @param oAuthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 * @param albumName 相册名,不能超过30个字符。 * @param albumDesc 相册描述,不能超过200个字符。 * @param privilege 用户的ID,与QQ号码一一对应。 相册权限, * * 其取值含义为: 1=公开;3=只主人可见; 4=QQ好友可见; 5=问答加密。 * * 不传则相册默认为公开权限。 * * 如果priv取值为5,即相册是问答加密的,则必须包含问题和答案两个参数: * * -question: 问题,不能超过30个字符。 * * -answer: 答案,不能超过30个字符。 */ public Result addAlbum(String oAuthConsumerKey, String accessToken, String openid, String albumName, String albumDesc, AlbumPrivilege privilege, String question, String answer) { List params = new ArrayList(); connect.addParameter(params, "oauth_consumer_key", oAuthConsumerKey); connect.addParameter(params, "access_token", accessToken); connect.addParameter(params, "openid", openid); connect.addParameter(params, "format", "json"); connect.addParameter(params, "albumname", albumName); connect.addNotNullParameter(params, "albumdesc", albumDesc); connect.addNotNullParameter(params, "priv", privilege); if (privilege == AlbumPrivilege.QUESTION) { connect.addParameter(params, "question", question); connect.addParameter(params, "answer", answer); } String json = connect.post("https://graph.qq.com/photo/add_album", params); return Result.parse(json, Album.class); } /** * 登录用户上传照片,支持单张上传和批量上传。 * * 文档地址:http://wiki.connect.qq.com/upload_pic * * @param oAuthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 * @param title 照片的命名,必须以.jpg, .gif, .png, .jpeg, .bmp此类后缀结尾。 * @param picture * @param photoDesc 照片描述,注意照片描述不能超过200个字符。 * @param albumId 相册id。可不填,不填时则根据“mobile”标识选择默认上传的相册。 * @param mobile * 标志位,0表示PC,1表示手机。用于当不传相册id时(即albumid为空时)控制是否传到手机相册。(1)如果传1,则当albumid为空时,图片会上传到手机相册;(2) * 如果不传或传0,则当albumid为空时,图片会上传到贴图相册; * @param lon 照片拍摄时的地理位置的经度。请使用原始数据(纯经纬度,0-360)。 * @param lat 照片拍摄时的地理位置的纬度。请使用原始数据(纯经纬度,0-360)。 * @param needFeed 标识上传照片时是否要发feed(0:不发feed; 1:发feed)。如果不填则默认为发feed。 * @param successNum 批量上传照片时,已成功上传的张数,指明上传完成情况。单张上传时可以不填,不填则默认为0。 * @param picNum * 批量上传照片的总张数,如果不填则默认为1。如果picnum=1,为单张上传,发送单张上传feed;如果picnum>1,为批量上传,发送批量上传feed。批量上传方式: * picnum为一次上传照片的张数 * ,successnum初始值为0,每调用一次照片上传接口后递增其值。信息中心中的feed表现形式:批量上传时最新的7张在feed中展示。其中最新上传的一张图片展示为大图 * ,剩下的六张按从新到旧的顺序展示为小图,其他图片不在feed中展示。 */ public Result uploadPic(String oAuthConsumerKey, String accessToken, String openid, String title, byte[] picture, String photoDesc, String albumId, Boolean mobile, Double lon, Double lat, Boolean needFeed, Integer successNum, Integer picNum) { HttpPost request = new HttpPost("https://graph.qq.com/photo/upload_pic"); MultipartEntityBuilder builder = MultipartEntityBuilder.create().addBinaryBody("picture", picture, ContentType.create("image/" + title.substring(title.lastIndexOf(".") + 1)), title); builder.addTextBody("oauth_consumer_key", oAuthConsumerKey); builder.addTextBody("access_token", accessToken); builder.addTextBody("openid", openid); builder.addTextBody("format", "json"); builder.addTextBody("title", title); if (photoDesc != null) { builder.addTextBody("photodesc", photoDesc); } if (albumId != null) { builder.addTextBody("albumid", albumId); } if (Boolean.TRUE.equals(mobile)) { builder.addTextBody("mobile", "1"); } if (lon != null) { builder.addTextBody("x", lon.toString()); } if (lat != null) { builder.addTextBody("y", lat.toString()); } if (Boolean.FALSE.equals(needFeed)) { builder.addTextBody("needfeed", "0"); } if (successNum != null) { builder.addTextBody("successnum", successNum.toString()); } if (picNum != null) { builder.addTextBody("picnum", picNum.toString()); } request.setEntity(builder.build()); try { HttpResponse response = Http.CLIENT.execute(request); String json = IOUtils.toString(response.getEntity().getContent()); return Result.parse(json, PicUploadResult.class); } catch (ClientProtocolException e) { throw new SocialException(e); } catch (IOException e) { throw new SocialException(e); } finally { request.releaseConnection(); } } /** * 获取登录用户的照片列表。 * * 文档地址:http://wiki.connect.qq.com/list_photo * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 * @param albumId 表示要获取的照片列表所在的相册ID。 */ public Result listPhoto(String accessToken, String openid, String albumId) { return listPhoto(connect.getClientId(), accessToken, openid, albumId); } /** * 获取登录用户的照片列表。 * * 文档地址:http://wiki.connect.qq.com/list_photo * * @param oAuthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 * @param albumId 表示要获取的照片列表所在的相册ID。 */ public Result listPhoto(String oAuthConsumerKey, String accessToken, String openid, String albumId) { List params = new ArrayList(); connect.addParameter(params, "oauth_consumer_key", oAuthConsumerKey); connect.addParameter(params, "access_token", accessToken); connect.addParameter(params, "openid", openid); connect.addParameter(params, "format", "json"); connect.addParameter(params, "albumid", albumId); String json = connect.get("https://graph.qq.com/photo/list_photo", params); JSONObject jsonObject = new JSONObject(json); Error error = Error.parse(jsonObject); if (error != null) { return new Result(error); } List results = new ArrayList(); JSONArray jsonArray = jsonObject.getJSONArray("photos"); for (int i = 0; i < jsonArray.length(); i++) { results.add(Photo.parse(jsonArray.getJSONObject(i))); } return new Result(results); } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/api/User.java ================================================ package com.belerweb.social.qq.connect.api; import java.util.ArrayList; import java.util.List; import org.apache.http.NameValuePair; import com.belerweb.social.API; import com.belerweb.social.bean.Result; /** * 访问用户资料 */ public final class User extends API { protected User(QQConnect connect) { super(connect); } /** * 获取登录用户在QQ空间的信息,包括昵称、头像、性别及黄钻信息(包括黄钻等级、是否年费黄钻等)。此接口仅支持网站调用 * * 文档地址:http://wiki.connect.qq.com/get_user_info * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 * 可通过调用https://graph.qq.com/oauth2.0/me?access_token=YOUR_ACCESS_TOKEN 来获取。 */ public Result getUserInfo(String accessToken, String openid) { return getUserInfo(accessToken, connect.getClientId(), openid); } /** * 获取登录用户在QQ空间的信息,包括昵称、头像、性别及黄钻信息(包括黄钻等级、是否年费黄钻等)。此接口仅支持网站调用 * * 文档地址:http://wiki.connect.qq.com/get_user_info * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param oAuthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param openid 用户的ID,与QQ号码一一对应。 * 可通过调用https://graph.qq.com/oauth2.0/me?access_token=YOUR_ACCESS_TOKEN 来获取。 */ public Result getUserInfo(String accessToken, String oAuthConsumerKey, String openid) { List params = new ArrayList(); connect.addParameter(params, "access_token", accessToken); connect.addParameter(params, "oauth_consumer_key", oAuthConsumerKey); connect.addParameter(params, "openid", openid); connect.addNotNullParameter(params, "format", "json"); String json = connect.get("https://graph.qq.com/user/get_user_info", params); return Result.parse(json, com.belerweb.social.qq.connect.bean.User.class); } /** * 获取移动端应用的登录用户在QQ空间的简单个人信息,包括昵称、头像和黄钻信息(包括黄钻等级、是否年费黄钻等),以及用户的QQ头像。 此接口仅支持移动端应用调用 * * 文档地址:http://wiki.connect.qq.com/get_simple_userinfo * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param oAuthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param openid 用户的ID,与QQ号码一一对应。 * 可通过调用https://graph.qq.com/oauth2.0/me?access_token=YOUR_ACCESS_TOKEN 来获取。 */ public Result getSimpleUserInfo(String accessToken, String oAuthConsumerKey, String openid) { List params = new ArrayList(); connect.addParameter(params, "access_token", accessToken); connect.addParameter(params, "oauth_consumer_key", oAuthConsumerKey); connect.addParameter(params, "openid", openid); connect.addNotNullParameter(params, "format", "json"); String json = connect.get("https://openmobile.qq.com/user/get_simple_userinfo", params); return Result.parse(json, com.belerweb.social.qq.connect.bean.User.class); } /** * 获取已登录用户的关于QQ会员业务的基本资料。 * * 基本资料包括以下信息:是否为“普通包月会员”,是否为“年费会员”,QQ会员等级信息,是否为“豪华版QQ会员”,是否为“钻皇会员”,是否为“SVIP”。 * * 文档地址:http://wiki.connect.qq.com/get_vip_info * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 */ public Result getVipInfo(String accessToken, String openid) { return getVipInfo(accessToken, connect.getClientId(), openid); } /** * 获取已登录用户的关于QQ会员业务的基本资料。 * * 基本资料包括以下信息:是否为“普通包月会员”,是否为“年费会员”,QQ会员等级信息,是否为“豪华版QQ会员”,是否为“钻皇会员”,是否为“SVIP”。 * * 文档地址:http://wiki.connect.qq.com/get_vip_info * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param oAuthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param openid 用户的ID,与QQ号码一一对应。 */ public Result getVipInfo(String accessToken, String oAuthConsumerKey, String openid) { List params = new ArrayList(); connect.addParameter(params, "access_token", accessToken); connect.addParameter(params, "oauth_consumer_key", oAuthConsumerKey); connect.addParameter(params, "openid", openid); connect.addParameter(params, "format", "json"); String json = connect.get("https://graph.qq.com/user/get_vip_info", params); return Result.parse(json, com.belerweb.social.qq.connect.bean.User.class); } /** * 获取已登录用户的关于QQ会员业务的详细资料。 * * 详细资料包括:用户会员的历史属性,用户会员特权的到期时间,用户最后一次充值会员业务的支付渠道,用户开通会员的主要驱动因素。 * * 文档地址:http://wiki.connect.qq.com/get_vip_rich_info * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 */ public Result getVipRichInfo(String accessToken, String openid) { return getVipRichInfo(connect.getClientId(), accessToken, openid); } /** * 获取已登录用户的关于QQ会员业务的详细资料。 * * 详细资料包括:用户会员的历史属性,用户会员特权的到期时间,用户最后一次充值会员业务的支付渠道,用户开通会员的主要驱动因素。 * * 文档地址:http://wiki.connect.qq.com/get_vip_rich_info * * @param oAuthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 */ public Result getVipRichInfo(String oAuthConsumerKey, String accessToken, String openid) { List params = new ArrayList(); connect.addParameter(params, "oauth_consumer_key", oAuthConsumerKey); connect.addParameter(params, "access_token", accessToken); connect.addParameter(params, "openid", openid); connect.addParameter(params, "format", "json"); String json = connect.get("https://graph.qq.com/user/get_vip_rich_info", params); return Result.parse(json, com.belerweb.social.qq.connect.bean.User.class); } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/api/Weibo.java ================================================ package com.belerweb.social.qq.connect.api; import java.util.ArrayList; import java.util.List; import org.apache.http.NameValuePair; import org.json.JSONObject; import com.belerweb.social.API; import com.belerweb.social.bean.Error; import com.belerweb.social.bean.Result; import com.belerweb.social.qq.connect.bean.FanList; import com.belerweb.social.qq.connect.bean.IdolList; import com.belerweb.social.qq.connect.bean.RepostList; import com.belerweb.social.qq.connect.bean.WeiboUser; /** * 腾讯微博API */ public final class Weibo extends API { protected Weibo(QQConnect connect) { super(connect); } /** * 获取腾讯微博登录用户的用户资料。 * * 文档地址:http://wiki.connect.qq.com/get_info * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 */ public Result getInfo(String accessToken, String openid) { return getInfo(connect.getClientId(), accessToken, openid); } /** * 获取腾讯微博登录用户的用户资料。 * * 文档地址:http://wiki.connect.qq.com/get_info * * @param oAuthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 */ public Result getInfo(String oAuthConsumerKey, String accessToken, String openid) { List params = new ArrayList(); connect.addParameter(params, "oauth_consumer_key", oAuthConsumerKey); connect.addParameter(params, "access_token", accessToken); connect.addParameter(params, "openid", openid); connect.addParameter(params, "format", "json"); String json = connect.get("https://graph.qq.com/user/get_info", params); JSONObject jsonObject = new JSONObject(json); Error error = Error.parse(jsonObject); if (error != null) { return new Result(error); } return Result.parse(jsonObject.getJSONObject("data"), WeiboUser.class); } /** * 获取腾讯微博其他用户详细信息。 * * 文档地址:http://wiki.connect.qq.com/get_other_info * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 * @param name 其他用户的账户名。可选,name和fopenid至少选一个,若同时存在则以name值为主。 */ public Result getOtherInfo(String accessToken, String openid, String name) { return getOtherInfo(connect.getClientId(), accessToken, openid, name, null); } /** * 获取腾讯微博其他用户详细信息。 * * 文档地址:http://wiki.connect.qq.com/get_other_info * * @param oAuthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 * @param name 其他用户的账户名。可选,name和fopenid至少选一个,若同时存在则以name值为主。 * @param fopenid 其他用户的账户名。可选,name和fopenid至少选一个,若同时存在则以name值为主。 */ public Result getOtherInfo(String oAuthConsumerKey, String accessToken, String openid, String name, String fopenid) { List params = new ArrayList(); connect.addParameter(params, "oauth_consumer_key", oAuthConsumerKey); connect.addParameter(params, "access_token", accessToken); connect.addParameter(params, "openid", openid); connect.addParameter(params, "format", "json"); connect.addNotNullParameter(params, "name", name); connect.addNotNullParameter(params, "fopenid", fopenid); String json = connect.get("https://graph.qq.com/user/get_other_info", params); JSONObject jsonObject = new JSONObject(json); Error error = Error.parse(jsonObject); if (error != null) { return new Result(error); } return Result.parse(jsonObject.getJSONObject("data"), WeiboUser.class); } /** * 获取登录用户的听众列表。 * * 文档地址:http://wiki.connect.qq.com/get_fanslist * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 * @param reqNum 必须。请求获取的听众个数。取值范围为1-30。 * @param startIndex 必须。请求获取听众列表的起始位置。第一页:0;继续向下翻页:reqnum*(page-1)。 */ public Result getFansList(String accessToken, String openid, int reqNum, int startIndex) { return getFansList(connect.getClientId(), accessToken, openid, reqNum, startIndex, null, null, null); } /** * 获取登录用户的听众列表。 * * 文档地址:http://wiki.connect.qq.com/get_fanslist * * @param oAuthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 * @param reqNum 必须。请求获取的听众个数。取值范围为1-30。 * @param startIndex 必须。请求获取听众列表的起始位置。第一页:0;继续向下翻页:reqnum*(page-1)。 * @param newMode * 获取听众信息的模式。获取听众信息的模式,默认值为0。0:旧模式,新添加的听众信息排在前面,最多只能拉取1000个听众的信息。1:新模式,可以拉取所有听众的信息,暂时不支持排序。 * @param install 判断获取的是安装应用的听众,还是未安装应用的听众。 0:不考虑该参数;1:获取已安装应用的听众信息;2:获取未安装应用的听众信息。 * @param sex 按性别过滤标识,默认为0。此参数当mode=0时使用,支持排序。 1:获取的是男性听众信息;2:获取的是女性听众信息;0:不进行性别过滤,获取所有听众信息。 */ public Result getFansList(String oAuthConsumerKey, String accessToken, String openid, int reqNum, int startIndex, Boolean newMode, Integer install, Integer sex) { List params = new ArrayList(); connect.addParameter(params, "oauth_consumer_key", oAuthConsumerKey); connect.addParameter(params, "access_token", accessToken); connect.addParameter(params, "openid", openid); connect.addParameter(params, "format", "json"); connect.addParameter(params, "reqnum", reqNum); connect.addParameter(params, "startindex", startIndex); if (Boolean.TRUE.equals(newMode)) { connect.addParameter(params, "mode", "1"); } connect.addNotNullParameter(params, "install", install); connect.addNotNullParameter(params, "sex", sex); String json = connect.get("https://graph.qq.com/relation/get_fanslist", params); JSONObject jsonObject = new JSONObject(json); Error error = Error.parse(jsonObject); if (error != null) { return new Result(error); } return Result.parse(jsonObject.getJSONObject("data"), FanList.class); } /** * 获取登录用户收听的人的列表。 * * 文档地址:http://wiki.connect.qq.com/get_idollist * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 * @param reqNum 必须。请求获取的听众个数。取值范围为1-30。 * @param startIndex 必须。请求获取听众列表的起始位置。第一页:0;继续向下翻页:reqnum*(page-1)。 */ public Result getIdolList(String accessToken, String openid, int reqNum, int startIndex) { return getIdolList(connect.getClientId(), accessToken, openid, reqNum, startIndex, null, null); } /** * 获取登录用户收听的人的列表。 * * 文档地址:http://wiki.connect.qq.com/get_idollist * * @param oAuthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 * @param reqNum 必须。请求获取的听众个数。取值范围为1-30。 * @param startIndex 必须。请求获取听众列表的起始位置。第一页:0;继续向下翻页:reqnum*(page-1)。 * @param newMode 获取收听的人的信息模式,默认为0。 * 0:旧模式,新添加的收听的人信息排在前面,最多只能拉取1000个收听的人的信息。1:新模式,最多可拉取10000个收听的人的信息,暂不支持排序。 * @param install 判断获取的是安装了应用的收听好友,还是未安装应用的收听好友。0:不考虑该参数;1:获取已安装应用的收听好友信息;2:获取未安装应用的收听好友信息。 */ public Result getIdolList(String oAuthConsumerKey, String accessToken, String openid, int reqNum, int startIndex, Boolean newMode, Integer install) { List params = new ArrayList(); connect.addParameter(params, "oauth_consumer_key", oAuthConsumerKey); connect.addParameter(params, "access_token", accessToken); connect.addParameter(params, "openid", openid); connect.addParameter(params, "format", "json"); connect.addParameter(params, "reqnum", reqNum); connect.addParameter(params, "startindex", startIndex); if (Boolean.TRUE.equals(newMode)) { connect.addParameter(params, "mode", "1"); } connect.addNotNullParameter(params, "install", install); String json = connect.get("https://graph.qq.com/relation/get_idollist", params); JSONObject jsonObject = new JSONObject(json); Error error = Error.parse(jsonObject); if (error != null) { return new Result(error); } return Result.parse(jsonObject.getJSONObject("data"), IdolList.class); } /** * 获取一条微博的转播或评论信息列表。 * * 文档地址:http://wiki.connect.qq.com/get_repost_list * * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 * @param reqNum 必须。请求获取的听众个数。取值范围为1-30。 * @param startIndex 必须。请求获取听众列表的起始位置。第一页:0;继续向下翻页:reqnum*(page-1)。 */ public Result getRepostList(String accessToken, String openid, int flag, String rootId, int pageFlag, int pageTime, int reqNum, String twitterId) { return getRepostList(connect.getClientId(), accessToken, openid, flag, rootId, pageFlag, pageTime, reqNum, twitterId); } /** * 获取一条微博的转播或评论信息列表。 * * 文档地址:http://wiki.connect.qq.com/get_repost_list * * @param oAuthConsumerKey 申请QQ登录成功后,分配给应用的appid * @param accessToken 可通过使用Authorization_Code获取Access_Token 或来获取。access_token有3个月有效期。 * @param openid 用户的ID,与QQ号码一一对应。 * @param flag 标识获取的是转播列表还是点评列表。0:获取转播列表;1:获取点评列表;2:转播列表和点评列表都获取。 * @param rootId 转发或点评的源微博的ID。 * @param pageFlag 分页标识。0:第一页;1:向下翻页;2:向上翻页。 * @param pageTime 分页标识。0:第一页;1:向下翻页;2:向上翻页。 * @param reqNum 每次请求记录的条数。取值为1-100条。 * @param twitterId 翻页时使用。第1-100条:0;继续向下翻页:上一次请求返回的最后一条记录id。 */ public Result getRepostList(String oAuthConsumerKey, String accessToken, String openid, int flag, String rootId, int pageFlag, int pageTime, int reqNum, String twitterId) { List params = new ArrayList(); connect.addParameter(params, "oauth_consumer_key", oAuthConsumerKey); connect.addParameter(params, "access_token", accessToken); connect.addParameter(params, "openid", openid); connect.addParameter(params, "format", "json"); connect.addParameter(params, "flag", flag); connect.addParameter(params, "rootid", rootId); connect.addParameter(params, "pageflag", pageFlag); connect.addParameter(params, "pagetime", pageTime); connect.addParameter(params, "reqnum", reqNum); connect.addParameter(params, "twitterid", twitterId); String json = connect.get("https://graph.qq.com/t/get_repost_list", params); JSONObject jsonObject = new JSONObject(json); Error error = Error.parse(jsonObject); if (error != null) { return new Result(error); } return Result.parse(jsonObject.getJSONObject("data"), RepostList.class); } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/AccessToken.java ================================================ package com.belerweb.social.qq.connect.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; public class AccessToken extends JsonBean { public AccessToken() {} private AccessToken(JSONObject jsonObject) { super(jsonObject); } private String token;// 授权令牌,Access_Token。 private Long expiresIn;// 该access token的有效期,单位为秒。 private String refreshToken;// 在授权自动续期步骤中,获取新的Access_Token时需要提供的参数。 /** * 授权令牌,Access_Token。 */ public String getToken() { return token; } public void setToken(String token) { this.token = token; } /** * 该access token的有效期,单位为秒。 */ public Long getExpiresIn() { return expiresIn; } public void setExpiresIn(Long expiresIn) { this.expiresIn = expiresIn; } /** * 在授权自动续期步骤中,获取新的Access_Token时需要提供的参数。 */ public String getRefreshToken() { return refreshToken; } public void setRefreshToken(String refreshToken) { this.refreshToken = refreshToken; } public static AccessToken parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } AccessToken obj = new AccessToken(jsonObject); obj.token = jsonObject.getString("access_token"); obj.expiresIn = Result.parseLong(jsonObject.opt("expires_in")); obj.refreshToken = Result.toString(jsonObject.opt("refresh_token")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/Album.java ================================================ package com.belerweb.social.qq.connect.bean; import java.util.Date; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; public class Album extends JsonBean { public Album() {} private Album(JSONObject jsonObject) { super(jsonObject); } private String albumId; private String classId; private Date createTime; private String name; private String description; private String cover; private Integer picNum; public String getAlbumId() { return albumId; } public void setAlbumId(String albumId) { this.albumId = albumId; } public String getClassId() { return classId; } public void setClassId(String classId) { this.classId = classId; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getCover() { return cover; } public void setCover(String cover) { this.cover = cover; } public Integer getPicNum() { return picNum; } public void setPicNum(Integer picNum) { this.picNum = picNum; } public static Album parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } Album obj = new Album(jsonObject); obj.albumId = Result.toString(jsonObject.get("albumid")); obj.classId = Result.toString(jsonObject.opt("classid")); obj.createTime = Result.parseTimeSeconds(jsonObject.opt("createtime")); obj.name = Result.toString(jsonObject.opt("name")); obj.description = Result.toString(jsonObject.opt("desc")); obj.cover = Result.toString(jsonObject.opt("coverurl")); obj.picNum = Result.parseInteger(jsonObject.opt("picnum")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/AlbumPrivilege.java ================================================ package com.belerweb.social.qq.connect.bean; public enum AlbumPrivilege { PUBLIC(1), PRIVATE(3), FRIEND(4), QUESTION(5); private Integer value; private AlbumPrivilege(Integer value) { this.value = value; } public Integer value() { return value; } @Override public String toString() { return value.toString(); } public static AlbumPrivilege parse(Integer value) { if (value == null) { return null; } if (value == 1) { return PUBLIC; } if (value == 3) { return PRIVATE; } if (value == 4) { return FRIEND; } if (value == 5) { return QUESTION; } return null; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/Company.java ================================================ package com.belerweb.social.qq.connect.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; public class Company extends JsonBean { public Company() {} private Company(JSONObject jsonObject) { super(jsonObject); } private String id;// 公司id。 private String companyName;// 公司名称。 private String departmentName;// 部门名称。 private Integer beginYear;// 开始年。 private Integer endYear;// 结束年。 public String getId() { return id; } public void setId(String id) { this.id = id; } public String getCompanyName() { return companyName; } public void setCompanyName(String companyName) { this.companyName = companyName; } public String getDepartmentName() { return departmentName; } public void setDepartmentName(String departmentName) { this.departmentName = departmentName; } public Integer getBeginYear() { return beginYear; } public void setBeginYear(Integer beginYear) { this.beginYear = beginYear; } public Integer getEndYear() { return endYear; } public void setEndYear(Integer endYear) { this.endYear = endYear; } public static Company parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } Company obj = new Company(jsonObject); obj.id = Result.toString(jsonObject.get("id")); obj.companyName = Result.toString(jsonObject.opt("company_name")); obj.departmentName = Result.toString(jsonObject.opt("department_name")); obj.beginYear = Result.parseInteger(jsonObject.opt("begin_year")); obj.endYear = Result.parseInteger(jsonObject.opt("end_year")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/Display.java ================================================ package com.belerweb.social.qq.connect.bean; public enum Display { DEFAULT, MOBILE; } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/Education.java ================================================ package com.belerweb.social.qq.connect.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; public class Education extends JsonBean { public Education() {} private Education(JSONObject jsonObject) { super(jsonObject); } private String id;// 教育信息记录ID。 private Integer year;// 入学年。 private String schoolId;// 学校ID。学校ID与学校具体信息的对应关系请参见教育信息数据库。 private String departmentId;// 院系ID。院系ID与院系具体信息的对应关系请参见教育信息数据库。 private Integer level;// 学历级别。 public String getId() { return id; } public void setId(String id) { this.id = id; } public Integer getYear() { return year; } public void setYear(Integer year) { this.year = year; } public String getSchoolId() { return schoolId; } public void setSchoolId(String schoolId) { this.schoolId = schoolId; } public String getDepartmentId() { return departmentId; } public void setDepartmentId(String departmentId) { this.departmentId = departmentId; } public Integer getLevel() { return level; } public void setLevel(Integer level) { this.level = level; } public static Education parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } Education obj = new Education(jsonObject); obj.id = Result.toString(jsonObject.get("id")); obj.schoolId = Result.toString(jsonObject.opt("company_name")); obj.departmentId = Result.toString(jsonObject.opt("department_name")); obj.year = Result.parseInteger(jsonObject.opt("begin_year")); obj.level = Result.parseInteger(jsonObject.opt("end_year")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/FanList.java ================================================ package com.belerweb.social.qq.connect.bean; import java.util.Date; import java.util.List; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; public class FanList extends JsonBean { public FanList() {} private FanList(JSONObject jsonObject) { super(jsonObject); } private Date timestamp; private Boolean hasNext; private List fans; public Date getTimestamp() { return timestamp; } public void setTimestamp(Date timestamp) { this.timestamp = timestamp; } public Boolean getHasNext() { return hasNext; } public void setHasNext(Boolean hasNext) { this.hasNext = hasNext; } public List getFans() { return fans; } public void setFans(List fans) { this.fans = fans; } public static FanList parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } FanList obj = new FanList(jsonObject); obj.timestamp = Result.parseTimeSeconds(jsonObject.get("timestamp")); obj.hasNext = Result.parseBoolean(jsonObject.get("hasnext")); obj.fans = Result.parse(jsonObject.optJSONArray("info"), WeiboUser.class); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/Gut.java ================================================ package com.belerweb.social.qq.connect.bean; /** * QQ登录页面版本 */ public enum Gut { WML(1), XHTML(2); private int value; private Gut(int value) { this.value = value; } public int value() { return value; } @Override public String toString() { return String.valueOf(value); } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/IdolList.java ================================================ package com.belerweb.social.qq.connect.bean; import java.util.Date; import java.util.List; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; public class IdolList extends JsonBean { public IdolList() {} private IdolList(JSONObject jsonObject) { super(jsonObject); } private Date timestamp; private Boolean hasNext; private List fans; public Date getTimestamp() { return timestamp; } public void setTimestamp(Date timestamp) { this.timestamp = timestamp; } public Boolean getHasNext() { return hasNext; } public void setHasNext(Boolean hasNext) { this.hasNext = hasNext; } public List getFans() { return fans; } public void setFans(List fans) { this.fans = fans; } public static IdolList parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } IdolList obj = new IdolList(jsonObject); obj.timestamp = Result.parseTimeSeconds(jsonObject.get("timestamp")); obj.hasNext = Result.parseBoolean(jsonObject.get("hasnext")); obj.fans = Result.parse(jsonObject.optJSONArray("info"), WeiboUser.class); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/Image.java ================================================ package com.belerweb.social.qq.connect.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; public class Image extends JsonBean { public Image() {} private Image(JSONObject jsonObject) { super(jsonObject); } private String url; private Integer width; private Integer height; public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public Integer getWidth() { return width; } public void setWidth(Integer width) { this.width = width; } public Integer getHeight() { return height; } public void setHeight(Integer height) { this.height = height; } public static Image parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } Image obj = new Image(jsonObject); obj.url = Result.toString(jsonObject.opt("url")); obj.width = Result.parseInteger(jsonObject.opt("width")); obj.height = Result.parseInteger(jsonObject.opt("height")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/Music.java ================================================ package com.belerweb.social.qq.connect.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; public class Music extends JsonBean { public Music() {} private Music(JSONObject jsonObject) { super(jsonObject); } private String author;// 演唱者。 private String url;// 音频地址。 private String title;// 音频名字,歌名。 public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public static Music parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } Music obj = new Music(jsonObject); obj.author = Result.toString(jsonObject.opt("author")); obj.url = Result.toString(jsonObject.opt("url")); obj.title = Result.toString(jsonObject.opt("title")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/NewT.java ================================================ package com.belerweb.social.qq.connect.bean; import java.util.Date; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; /** * 新发布的微博的返回信息 */ public class NewT extends JsonBean { public NewT() {} private NewT(JSONObject jsonObject) { super(jsonObject); } private Long id;// 微博的ID,用来唯一标识一条微博。 private Date time;// 微博的发表时间。 private String imgUrl;// 图片分享后的url地址。 public Long getId() { return id; } public void setId(Long id) { this.id = id; } public Date getTime() { return time; } public void setTime(Date time) { this.time = time; } public String getImgUrl() { return imgUrl; } public void setImgUrl(String imgUrl) { this.imgUrl = imgUrl; } public static NewT parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } NewT obj = new NewT(jsonObject); obj.id = Result.parseLong(jsonObject.get("id")); obj.time = new Date(Result.parseLong(jsonObject.get("time")) * 1000); obj.imgUrl = jsonObject.optString("imgurl"); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/OpenID.java ================================================ package com.belerweb.social.qq.connect.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; public class OpenID extends JsonBean { public OpenID() {} private OpenID(JSONObject jsonObject) { super(jsonObject); } private String clientId; private String openId; // openid是此网站上唯一对应用户身份的标识,网站可将此ID进行存储便于用户下次登录时辨识其身份,或将其与用户在网站上的原有账号进行绑定。 /** * openid是此网站上唯一对应用户身份的标识,网站可将此ID进行存储便于用户下次登录时辨识其身份,或将其与用户在网站上的原有账号进行绑定。 */ public String getClientId() { return clientId; } public void setClientId(String clientId) { this.clientId = clientId; } public String getOpenId() { return openId; } public void setOpenId(String openId) { this.openId = openId; } public static OpenID parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } OpenID obj = new OpenID(jsonObject); obj.clientId = jsonObject.getString("client_id"); obj.openId = jsonObject.getString("openid"); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/Photo.java ================================================ package com.belerweb.social.qq.connect.bean; import java.util.Date; import java.util.Locale; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; public class Photo extends JsonBean { public Photo() {} private Photo(JSONObject jsonObject) { super(jsonObject); } private String sLoc; private String lLoc; private String name; private String description; private Date updatedTime; private Date uploadedTime; private String smallUrl; private Image largeImage; public String getsLoc() { return sLoc; } public void setsLoc(String sLoc) { this.sLoc = sLoc; } public String getlLoc() { return lLoc; } public void setlLoc(String lLoc) { this.lLoc = lLoc; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public Date getUpdatedTime() { return updatedTime; } public void setUpdatedTime(Date updatedTime) { this.updatedTime = updatedTime; } public Date getUploadedTime() { return uploadedTime; } public void setUploadedTime(Date uploadedTime) { this.uploadedTime = uploadedTime; } public String getSmallUrl() { return smallUrl; } public void setSmallUrl(String smallUrl) { this.smallUrl = smallUrl; } public Image getLargeImage() { return largeImage; } public void setLargeImage(Image largeImage) { this.largeImage = largeImage; } public static Photo parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } Photo obj = new Photo(jsonObject); obj.sLoc = Result.toString(jsonObject.opt("sloc")); obj.lLoc = Result.toString(jsonObject.opt("lloc")); obj.name = Result.toString(jsonObject.opt("name")); obj.description = Result.toString(jsonObject.opt("desc")); obj.updatedTime = Result.parseTimeSeconds(jsonObject.opt("updated_time")); obj.uploadedTime = Result.parseDate(jsonObject.opt("uploaded_time"), "yyyy-MM-dd HH:mm:ss", Locale.CHINA); obj.smallUrl = Result.toString(jsonObject.opt("small_url")); obj.largeImage = Image.parse(jsonObject.optJSONObject("large_image")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/PicUploadResult.java ================================================ package com.belerweb.social.qq.connect.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; public class PicUploadResult extends JsonBean { public PicUploadResult() {} private PicUploadResult(JSONObject jsonObject) { super(jsonObject); } private String albumId; private String lLoc; private String sLoc; private String largeUrl; private String smallUrl; private Integer width; private Integer height; public String getAlbumId() { return albumId; } public void setAlbumId(String albumId) { this.albumId = albumId; } public String getlLoc() { return lLoc; } public void setlLoc(String lLoc) { this.lLoc = lLoc; } public String getsLoc() { return sLoc; } public void setsLoc(String sLoc) { this.sLoc = sLoc; } public String getLargeUrl() { return largeUrl; } public void setLargeUrl(String largeUrl) { this.largeUrl = largeUrl; } public String getSmallUrl() { return smallUrl; } public void setSmallUrl(String smallUrl) { this.smallUrl = smallUrl; } public Integer getWidth() { return width; } public void setWidth(Integer width) { this.width = width; } public Integer getHeight() { return height; } public void setHeight(Integer height) { this.height = height; } public static PicUploadResult parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } PicUploadResult obj = new PicUploadResult(jsonObject); obj.albumId = Result.toString(jsonObject.opt("albumid")); obj.lLoc = Result.toString(jsonObject.opt("lloc")); obj.sLoc = Result.toString(jsonObject.opt("sloc")); obj.largeUrl = Result.toString(jsonObject.opt("large_url")); obj.smallUrl = Result.toString(jsonObject.opt("small_url")); obj.width = Result.parseInteger(jsonObject.opt("width")); obj.height = Result.parseInteger(jsonObject.opt("height")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/RepostList.java ================================================ package com.belerweb.social.qq.connect.bean; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; public class RepostList extends JsonBean { public RepostList() {} private RepostList(JSONObject jsonObject) { super(jsonObject); } private Date timestamp; private Boolean hasNext; private Integer totalNum; private List tweets; private Map nameNickMap = new HashMap(); public Date getTimestamp() { return timestamp; } public void setTimestamp(Date timestamp) { this.timestamp = timestamp; } public Boolean getHasNext() { return hasNext; } public void setHasNext(Boolean hasNext) { this.hasNext = hasNext; } public Integer getTotalNum() { return totalNum; } public void setTotalNum(Integer totalNum) { this.totalNum = totalNum; } public List getTweets() { return tweets; } public void setTweets(List tweets) { this.tweets = tweets; } public static RepostList parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } RepostList obj = new RepostList(jsonObject); obj.timestamp = Result.parseTimeSeconds(jsonObject.get("timestamp")); obj.hasNext = Result.parseBoolean(jsonObject.get("hasnext")); obj.totalNum = Result.parseInteger(jsonObject.get("totalnum")); obj.tweets = Result.parse(jsonObject.optJSONArray("info"), TweetInfo.class); JSONObject map = jsonObject.optJSONObject("user"); if (map != null) { Iterator keys = map.keys(); while (keys.hasNext()) { String key = keys.next().toString(); obj.nameNickMap.put(key, map.get(key).toString()); } } return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/Scope.java ================================================ package com.belerweb.social.qq.connect.bean; /** * 请求用户授权时向用户显示的可进行授权的列表。 */ public enum Scope { /** * do_like */ DO_LIKE("do_like"), /** * 获取登录用户的昵称、头像、性别 */ GET_USER_INFO("get_user_info"), /** * 获取登录用户的昵称、头像、性别 */ GET_SIMPLE_USERINFO("get_simple_userinfo"), /** * 获取QQ会员的基本信息 */ GET_VIP_INFO("get_vip_info"), /** * 获取QQ会员的高级信息 */ GET_VIP_RICH_INFO("get_vip_rich_info"), /** * 发表日志到QQ空间 */ ADD_ONE_BLOG("add_one_blog"), /** * 获取用户QQ空间相册列表 */ LIST_ALBUM("list_album"), /** * 上传一张照片到QQ空间相册 */ UPLOAD_PIC("upload_pic"), /** * 在用户的空间相册里,创建一个新的个人相册 */ ADD_ALBUM("add_album"), /** * 获取用户QQ空间相册中的照片列表 */ LIST_PHOTO("list_photo"), /** * 获取登录用户在腾讯微博详细资料 */ GET_INFO("get_info"), /** * 发表一条微博 */ ADD_T("add_t"), /** * 删除一条微博 */ DEL_T("del_t"), /** * 发表一条带图片的微博 */ ADD_PIC_T("add_pic_t"), /** * 获取单条微博的转发或点评列表 */ GET_REPOST_LIST("get_repost_list"), /** * 获取他人微博资料 */ GET_OTHER_INFO("get_other_info"), /** * 我的微博粉丝列表 */ GET_FANSLIST("get_fanslist"), /** * 我的微博偶像列表 */ GET_IDOLLIST("get_idollist"), /** * 收听某个微博用户 */ ADD_IDOL("add_idol"), /** * 取消收听某个微博用户 */ DEL_IDOL("del_idol"), /** * 在这个网站上将展现您财付通登记的收货地址 */ GET_TENPAY_ADDR("get_tenpay_addr"); private String scope; private Scope(String scope) { this.scope = scope; } public String value() { return scope; } @Override public String toString() { return scope; } public static final Scope[] ALL = new Scope[] {Scope.DO_LIKE, Scope.GET_USER_INFO, Scope.GET_SIMPLE_USERINFO, Scope.GET_VIP_INFO, Scope.GET_VIP_RICH_INFO, Scope.ADD_ONE_BLOG, Scope.LIST_ALBUM, Scope.UPLOAD_PIC, Scope.ADD_ALBUM, Scope.LIST_PHOTO, Scope.GET_INFO, Scope.ADD_T, Scope.DEL_T, Scope.ADD_PIC_T, Scope.GET_REPOST_LIST, Scope.GET_OTHER_INFO, Scope.GET_FANSLIST, Scope.GET_IDOLLIST, Scope.ADD_IDOL, Scope.DEL_IDOL, Scope.GET_TENPAY_ADDR,}; } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/SendPrivate.java ================================================ package com.belerweb.social.qq.connect.bean; public enum SendPrivate { IDOL(0), FRIEND(1), PUBLIC(2); private Integer value; private SendPrivate(Integer value) { this.value = value; } public Integer value() { return value; } @Override public String toString() { return value.toString(); } public static SendPrivate parse(Integer value) { if (value == null) { return null; } if (value == 0) { return IDOL; } if (value == 1) { return FRIEND; } if (value == 2) { return PUBLIC; } return null; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/Tag.java ================================================ package com.belerweb.social.qq.connect.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; public class Tag extends JsonBean { public Tag() {} private Tag(JSONObject jsonObject) { super(jsonObject); } private String id;// 个人标签id。 private String name;// 标签名。 public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public static Tag parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } Tag obj = new Tag(jsonObject); obj.id = Result.toString(jsonObject.get("id")); obj.name = Result.toString(jsonObject.opt("name")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/TenpayAddress.java ================================================ package com.belerweb.social.qq.connect.bean; import java.util.Date; /** * 财付通收货地址 */ public class TenpayAddress { private Integer index;// 收货信息的索引编号 private Integer regionId;// 收货信息的地区编号 private String street;// 收货信息的收货地址 private String zipcode;// 收货信息的邮编 private String mobile;// 收货信息的收货人移动电话 private String tel;// 收货信息的收货人固定电话 private String name;// 收货信息的收货人姓名 private Date created;// 收货信息的创建时间 private Date modified;// 收货信息上一次被修改的时间 private Date lastUsed;// 收货信息上一次被使用的时间 private Integer usedCount;// 收货信息被使用过的次数 private Integer total;// 该用户财付通收货地址的个数 public Integer getIndex() { return index; } public void setIndex(Integer index) { this.index = index; } public Integer getRegionId() { return regionId; } public void setRegionId(Integer regionId) { this.regionId = regionId; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } public String getZipcode() { return zipcode; } public void setZipcode(String zipcode) { this.zipcode = zipcode; } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile; } public String getTel() { return tel; } public void setTel(String tel) { this.tel = tel; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getCreated() { return created; } public void setCreated(Date created) { this.created = created; } public Date getModified() { return modified; } public void setModified(Date modified) { this.modified = modified; } public Date getLastUsed() { return lastUsed; } public void setLastUsed(Date lastUsed) { this.lastUsed = lastUsed; } public Integer getUsedCount() { return usedCount; } public void setUsedCount(Integer usedCount) { this.usedCount = usedCount; } public Integer getTotal() { return total; } public void setTotal(Integer total) { this.total = total; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/TweetInfo.java ================================================ package com.belerweb.social.qq.connect.bean; import java.util.Date; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; public class TweetInfo extends JsonBean { public TweetInfo() {} private TweetInfo(JSONObject jsonObject) { super(jsonObject); } private String id;// 微博唯一id。 private String countryCode;// 发表微博时所作的国家代码。 private String provinceCode;// 发表微博时所作的省份代码。 private String cityCode;// 发表微博时所作的城市代码。 private String emotionType;// 心情类型。 private String emotionUrl;// 心情图片url。 private String from;// 来源。 private String fromUrl;// 来源url。 private String image;// 图片url。 private String geo;// 地理位置信息。 private String location;// 发表者所在地。 private Double longitude;// 经度。 private Double latitude;// 纬度。 private Music music; private String origText;// 微博原始内容。 private Boolean self;// 是否自已发的的微博 private Integer status;// 表示微博的状态。0:正常;1:微博被系统删除;2:审核中;3;微博被用户删除;4:源微博被系统审核删除。 private String text;// 微博内容。 private Date timestamp;// 服务器时间戳,不能用于翻页。 private Integer type;// 表示微博的类型。1:原创发表;2:转播;3:私信;4:回复;5:没有内容的回复;6:提及;7:评论。 private Video video;// 视频信息。 private Integer count;// 转播次数。 private Integer mCount;// 评论数。 private Boolean isVip;// 用户是否为微博认证用户 public String getId() { return id; } public void setId(String id) { this.id = id; } public String getCountryCode() { return countryCode; } public void setCountryCode(String countryCode) { this.countryCode = countryCode; } public String getProvinceCode() { return provinceCode; } public void setProvinceCode(String provinceCode) { this.provinceCode = provinceCode; } public String getCityCode() { return cityCode; } public void setCityCode(String cityCode) { this.cityCode = cityCode; } public String getEmotionType() { return emotionType; } public void setEmotionType(String emotionType) { this.emotionType = emotionType; } public String getEmotionUrl() { return emotionUrl; } public void setEmotionUrl(String emotionUrl) { this.emotionUrl = emotionUrl; } public String getFrom() { return from; } public void setFrom(String from) { this.from = from; } public String getFromUrl() { return fromUrl; } public void setFromUrl(String fromUrl) { this.fromUrl = fromUrl; } public String getImage() { return image; } public void setImage(String image) { this.image = image; } public String getGeo() { return geo; } public void setGeo(String geo) { this.geo = geo; } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } public Double getLongitude() { return longitude; } public void setLongitude(Double longitude) { this.longitude = longitude; } public Double getLatitude() { return latitude; } public void setLatitude(Double latitude) { this.latitude = latitude; } public Music getMusic() { return music; } public void setMusic(Music music) { this.music = music; } public String getOrigText() { return origText; } public void setOrigText(String origText) { this.origText = origText; } public Boolean getSelf() { return self; } public void setSelf(Boolean self) { this.self = self; } public Integer getStatus() { return status; } public void setStatus(Integer status) { this.status = status; } public String getText() { return text; } public void setText(String text) { this.text = text; } public Date getTimestamp() { return timestamp; } public void setTimestamp(Date timestamp) { this.timestamp = timestamp; } public Integer getType() { return type; } public void setType(Integer type) { this.type = type; } public Video getVideo() { return video; } public void setVideo(Video video) { this.video = video; } public Integer getCount() { return count; } public void setCount(Integer count) { this.count = count; } public Integer getmCount() { return mCount; } public void setmCount(Integer mCount) { this.mCount = mCount; } public Boolean getIsVip() { return isVip; } public void setIsVip(Boolean isVip) { this.isVip = isVip; } public static TweetInfo parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } TweetInfo obj = new TweetInfo(jsonObject); obj.id = Result.toString(jsonObject.get("id")); obj.countryCode = Result.toString(jsonObject.opt("country_code")); obj.provinceCode = Result.toString(jsonObject.opt("province_code")); obj.cityCode = Result.toString(jsonObject.opt("city_code")); obj.emotionType = Result.toString(jsonObject.opt("emotiontype")); obj.emotionUrl = Result.toString(jsonObject.opt("emotionurl")); obj.from = Result.toString(jsonObject.opt("from")); obj.fromUrl = Result.toString(jsonObject.opt("fromurl")); obj.image = Result.toString(jsonObject.opt("image")); obj.geo = Result.toString(jsonObject.opt("geo")); obj.location = Result.toString(jsonObject.opt("location")); obj.longitude = Result.parseDouble(jsonObject.opt("longitude")); obj.latitude = Result.parseDouble(jsonObject.opt("latitude")); obj.music = Music.parse(jsonObject.optJSONObject("music")); obj.origText = Result.toString(jsonObject.opt("origtext")); obj.self = Result.parseBoolean(jsonObject.opt("self")); obj.status = Result.parseInteger(jsonObject.opt("status")); obj.text = Result.toString(jsonObject.opt("text")); obj.timestamp = Result.parseTimeSeconds(jsonObject.opt("timestamp")); obj.type = Result.parseInteger(jsonObject.opt("type")); obj.video = Video.parse(jsonObject.optJSONObject("video")); obj.count = Result.parseInteger(jsonObject.opt("count")); obj.mCount = Result.parseInteger(jsonObject.opt("mcount")); obj.isVip = Result.parseBoolean(jsonObject.opt("isvip")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/User.java ================================================ package com.belerweb.social.qq.connect.bean; import java.util.Date; import org.json.JSONObject; import com.belerweb.social.bean.Gender; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; public class User extends JsonBean { public User() {} private User(JSONObject jsonObject) { super(jsonObject); } private String nickname;// 用户在QQ空间的昵称。 private String figureUrl;// 大小为30×30像素的QQ空间头像URL。 private String figureUrl1;// 大小为50×50像素的QQ空间头像URL。 private String figureUrl2;// 大小为100×100像素的QQ空间头像URL。 private String figureUrlQQ1;// 大小为40×40像素的QQ头像URL。 40x40像素则是一定会有。 private String figureUrlQQ2;// 大小为100×100像素的QQ头像URL。需要注意,不是所有的用户都拥有QQ的100x100的头像。 private Gender gender;// 性别。 如果获取不到则默认返回"男" private Boolean isYellowVip;// 标识用户是否为黄钻用户 private Boolean vip;// 标识用户是否为黄钻用户 private Integer yellowVipLevel;// 黄钻等级 private Integer level;// 黄钻等级 private Boolean isYellowYearVip;// 标识是否为年费黄钻用户 private Boolean isQQVip;// 标识是否QQ会员 private Integer qqVipLevel;// QQ会员等级 private Boolean isQQYearVip;// 标识是否为年费QQ会员 private Boolean isLost; private Date qqVipStart;// QQ会员最后一次充值时间 private Date qqVipEnd;// QQ会员期限 private Integer qqVipPayway;// QQ会员充值方式 private Date qqYearVipStart;// QQ年费会员最后一次充值时间 private Date qqYearVipEnd;// QQ年费会员期限 private Integer qqYearVipPayway;// QQ年费会员充值方式 private Date qqZuanhuangStart;// QQ钻皇最后一次充值时间 private Date qqZuanhuangEnd;// QQ钻皇期限 private Integer qqZuanhuangPayway;// QQ钻皇充值方式 private Date qqHaohuaStart;// 豪华版QQ会员最后一次充值时间 private Date qqHaohuaEnd;// 豪华版QQ会员期限 private Integer qqHaohuaPayway;// 豪华版QQ会员充值方式 private Date qqSvipStart;// QQ SVIP最后一次充值时间,预留字段,当前信息无效 private Date qqSvipEnd;// QQ SVIP期限,预留字段,当前信息无效 private Integer qqSvipPayway;// QQ SVIP充值方式,预留字段,当前信息无效 private Date historyPayTime;// 非会员历史充值时间,仅在用户是非会员时信息有效 private Date historyEndTime;// 非会员历史充值到期时间,仅在用户是非会员时信息有效 /** * 用户在QQ空间的昵称。 */ public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } /** * 大小为30×30像素的QQ空间头像URL。 */ public String getFigureUrl() { return figureUrl; } public void setFigureUrl(String figureUrl) { this.figureUrl = figureUrl; } /** * 大小为50×50像素的QQ空间头像URL。 */ public String getFigureUrl1() { return figureUrl1; } public void setFigureUrl1(String figureUrl1) { this.figureUrl1 = figureUrl1; } /** * 大小为100×100像素的QQ空间头像URL。 */ public String getFigureUrl2() { return figureUrl2; } public void setFigureUrl2(String figureUrl2) { this.figureUrl2 = figureUrl2; } /** * 大小为40×40像素的QQ头像URL。 40x40像素则是一定会有。 */ public String getFigureUrlQQ1() { return figureUrlQQ1; } public void setFigureUrlQQ1(String figureUrlQQ1) { this.figureUrlQQ1 = figureUrlQQ1; } /** * 大小为100×100像素的QQ头像URL。需要注意,不是所有的用户都拥有QQ的100x100的头像。 */ public String getFigureUrlQQ2() { return figureUrlQQ2; } public void setFigureUrlQQ2(String figureUrlQQ2) { this.figureUrlQQ2 = figureUrlQQ2; } /** * 性别。 如果获取不到则默认返回"男" */ public Gender getGender() { return gender; } public void setGender(Gender gender) { this.gender = gender; } /** * 标识用户是否为黄钻用户 */ public Boolean getIsYellowVip() { return isYellowVip; } public void setIsYellowVip(Boolean isYellowVip) { this.isYellowVip = isYellowVip; } /** * 标识用户是否为黄钻用户 */ public Boolean getVip() { return vip; } public void setVip(Boolean vip) { this.vip = vip; } /** * 黄钻等级 */ public Integer getYellowVipLevel() { return yellowVipLevel; } public void setYellowVipLevel(Integer yellowVipLevel) { this.yellowVipLevel = yellowVipLevel; } /** * 黄钻等级 */ public Integer getLevel() { return level; } public void setLevel(Integer level) { this.level = level; } /** * 标识是否为年费黄钻用户 */ public Boolean getIsYellowYearVip() { return isYellowYearVip; } public void setIsYellowYearVip(Boolean isYellowYearVip) { this.isYellowYearVip = isYellowYearVip; } /** * 标识是否QQ会员 */ public Boolean getIsQQVip() { return isQQVip; } public void setIsQQVip(Boolean isQQVip) { this.isQQVip = isQQVip; } /** * QQ会员等级 */ public Integer getQqVipLevel() { return qqVipLevel; } public void setQqVipLevel(Integer qqVipLevel) { this.qqVipLevel = qqVipLevel; } /** * 是否是QQ年费会员 */ public Boolean getIsQQYearVip() { return isQQYearVip; } public void setIsQQYearVip(Boolean isQQYearVip) { this.isQQYearVip = isQQYearVip; } public Boolean getIsLost() { return isLost; } public void setIsLost(Boolean isLost) { this.isLost = isLost; } /** * QQ会员最后一次充值时间 */ public Date getQqVipStart() { return qqVipStart; } public void setQqVipStart(Date qqVipStart) { this.qqVipStart = qqVipStart; } /** * QQ会员期限 */ public Date getQqVipEnd() { return qqVipEnd; } public void setQqVipEnd(Date qqVipEnd) { this.qqVipEnd = qqVipEnd; } /** * QQ会员充值方式 */ public Integer getQqVipPayway() { return qqVipPayway; } public void setQqVipPayway(Integer qqVipPayway) { this.qqVipPayway = qqVipPayway; } /** * QQ年费会员最后一次充值时间 */ public Date getQqYearVipStart() { return qqYearVipStart; } public void setQqYearVipStart(Date qqYearVipStart) { this.qqYearVipStart = qqYearVipStart; } /** * QQ年费会员期限 */ public Date getQqYearVipEnd() { return qqYearVipEnd; } public void setQqYearVipEnd(Date qqYearVipEnd) { this.qqYearVipEnd = qqYearVipEnd; } /** * QQ年费会员充值方式 */ public Integer getQqYearVipPayway() { return qqYearVipPayway; } public void setQqYearVipPayway(Integer qqYearVipPayway) { this.qqYearVipPayway = qqYearVipPayway; } /** * QQ钻皇最后一次充值时间 */ public Date getQqZuanhuangStart() { return qqZuanhuangStart; } public void setQqZuanhuangStart(Date qqZuanhuangStart) { this.qqZuanhuangStart = qqZuanhuangStart; } /** * QQ钻皇期限 */ public Date getQqZuanhuangEnd() { return qqZuanhuangEnd; } public void setQqZuanhuangEnd(Date qqZuanhuangEnd) { this.qqZuanhuangEnd = qqZuanhuangEnd; } /** * QQ钻皇充值方式 */ public Integer getQqZuanhuangPayway() { return qqZuanhuangPayway; } public void setQqZuanhuangPayway(Integer qqZuanhuangPayway) { this.qqZuanhuangPayway = qqZuanhuangPayway; } /** * 豪华版QQ会员最后一次充值时间 */ public Date getQqHaohuaStart() { return qqHaohuaStart; } public void setQqHaohuaStart(Date qqHaohuaStart) { this.qqHaohuaStart = qqHaohuaStart; } /** * 豪华版QQ会员期限 */ public Date getQqHaohuaEnd() { return qqHaohuaEnd; } public void setQqHaohuaEnd(Date qqHaohuaEnd) { this.qqHaohuaEnd = qqHaohuaEnd; } /** * 豪华版QQ会员充值方式 */ public Integer getQqHaohuaPayway() { return qqHaohuaPayway; } public void setQqHaohuaPayway(Integer qqHaohuaPayway) { this.qqHaohuaPayway = qqHaohuaPayway; } /** * QQ SVIP最后一次充值时间,预留字段,当前信息无效 */ public Date getQqSvipStart() { return qqSvipStart; } public void setQqSvipStart(Date qqSvipStart) { this.qqSvipStart = qqSvipStart; } /** * QQ SVIP期限,预留字段,当前信息无效 */ public Date getQqSvipEnd() { return qqSvipEnd; } public void setQqSvipEnd(Date qqSvipEnd) { this.qqSvipEnd = qqSvipEnd; } /** * QQ SVIP充值方式,预留字段,当前信息无效 */ public Integer getQqSvipPayway() { return qqSvipPayway; } public void setQqSvipPayway(Integer qqSvipPayway) { this.qqSvipPayway = qqSvipPayway; } /** * 非会员历史充值时间,仅在用户是非会员时信息有效 */ public Date getHistoryPayTime() { return historyPayTime; } public void setHistoryPayTime(Date historyPayTime) { this.historyPayTime = historyPayTime; } /** * 非会员历史充值到期时间,仅在用户是非会员时信息有效 */ public Date getHistoryEndTime() { return historyEndTime; } public void setHistoryEndTime(Date historyEndTime) { this.historyEndTime = historyEndTime; } public static User parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } User obj = new User(jsonObject); obj.nickname = Result.toString(jsonObject.opt("nickname")); obj.figureUrl = Result.toString(jsonObject.opt("figureurl")); obj.figureUrl1 = Result.toString(jsonObject.opt("figureurl_1")); obj.figureUrl2 = Result.toString(jsonObject.opt("figureurl_2")); obj.figureUrlQQ1 = Result.toString(jsonObject.opt("figureurl_qq_1")); obj.figureUrlQQ2 = Result.toString(jsonObject.opt("figureurl_qq_2")); obj.gender = Gender.parse(jsonObject.optString("gender", null)); obj.isYellowVip = Result.parseBoolean(jsonObject.opt("is_yellow_vip")); obj.vip = Result.parseBoolean(jsonObject.opt("vip")); obj.yellowVipLevel = Result.parseInteger(jsonObject.opt("yellow_vip_level")); obj.level = Result.parseInteger(jsonObject.opt("level")); obj.isYellowYearVip = Result.parseBoolean(jsonObject.opt("is_yellow_year_vip")); obj.isQQVip = Result.parseBoolean(jsonObject.opt("is_qq_vip")); obj.qqVipLevel = Result.parseInteger(jsonObject.opt("qq_vip_level")); obj.isQQYearVip = Result.parseBoolean(jsonObject.opt("is_qq_year_vip")); obj.isLost = Result.parseBoolean(jsonObject.opt("is_lost")); obj.qqVipStart = Result.parseTimeSeconds(jsonObject.opt("qq_vip_start")); obj.qqVipEnd = Result.parseTimeSeconds(jsonObject.opt("qq_vip_end")); obj.qqVipPayway = Result.parseInteger(jsonObject.opt("qq_vip_payway")); obj.qqYearVipStart = Result.parseTimeSeconds(jsonObject.opt("qq_year_vip_start")); obj.qqYearVipEnd = Result.parseTimeSeconds(jsonObject.opt("qq_year_vip_end")); obj.qqYearVipPayway = Result.parseInteger(jsonObject.opt("qq_year_vip_payway")); obj.qqZuanhuangStart = Result.parseTimeSeconds(jsonObject.opt("qq_zuanhuang_start")); obj.qqZuanhuangEnd = Result.parseTimeSeconds(jsonObject.opt("qq_zuanhuang_end")); obj.qqZuanhuangPayway = Result.parseInteger(jsonObject.opt("qq_zuanhuang_payway")); obj.qqHaohuaStart = Result.parseTimeSeconds(jsonObject.opt("qq_haohua_start")); obj.qqHaohuaEnd = Result.parseTimeSeconds(jsonObject.opt("qq_haohua_end")); obj.qqHaohuaPayway = Result.parseInteger(jsonObject.opt("qq_haohua_payway")); obj.qqSvipStart = Result.parseTimeSeconds(jsonObject.opt("qq_svip_start")); obj.qqSvipEnd = Result.parseTimeSeconds(jsonObject.opt("qq_svip_end")); obj.qqSvipPayway = Result.parseInteger(jsonObject.opt("qq_svip_payway")); obj.historyPayTime = Result.parseTimeSeconds(jsonObject.opt("history_pay_time")); obj.historyEndTime = Result.parseTimeSeconds(jsonObject.opt("history_end_time")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/Video.java ================================================ package com.belerweb.social.qq.connect.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; public class Video extends JsonBean { public Video() {} private Video(JSONObject jsonObject) { super(jsonObject); } private String picUrl;// 缩略图。 private String player;// 播放器地址。 private String realUrl;// 视频原地址。 private String shortUrl;// 视频的短url。 private String title;// 视频标题。 public String getPicUrl() { return picUrl; } public void setPicUrl(String picUrl) { this.picUrl = picUrl; } public String getPlayer() { return player; } public void setPlayer(String player) { this.player = player; } public String getRealUrl() { return realUrl; } public void setRealUrl(String realUrl) { this.realUrl = realUrl; } public String getShortUrl() { return shortUrl; } public void setShortUrl(String shortUrl) { this.shortUrl = shortUrl; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public static Video parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } Video obj = new Video(jsonObject); obj.picUrl = Result.toString(jsonObject.opt("picurl")); obj.player = Result.toString(jsonObject.opt("player")); obj.realUrl = Result.toString(jsonObject.opt("realurl")); obj.shortUrl = Result.toString(jsonObject.opt("shorturl")); obj.title = Result.toString(jsonObject.opt("title")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/connect/bean/WeiboUser.java ================================================ package com.belerweb.social.qq.connect.bean; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import org.json.JSONArray; import org.json.JSONObject; import com.belerweb.social.bean.Gender; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; public class WeiboUser extends JsonBean { public WeiboUser() {} private WeiboUser(JSONObject jsonObject) { super(jsonObject); } private String openId;// 登录用户的唯一ID,与name一一对应。 private String name;// 登录用户的帐号名 private String nick;// 登录用户昵称。 private Date regTime;// 登录注册时间。 private Date birth; private String countryCode; private String provinceCode; private String cityCode; private List companies; private List educations; private Integer fansNum;// 登录用户听众数。 private Integer favNum;// 登录用户收藏数。 private String head; private String homeCountryCode;// 登录用户家乡所在国家代码。 private String homeProvinceCode;// 登录用户家乡所在省份代码。 private String homeCityCode;// 登录用户家乡所在城市代码。 private String hometownCode;// 登录用户家乡所在城镇代码。 private String homepage;// 个人主页。 private Integer idolNum;// 登录用户收听的人数。 private String industryCode;// 行业ID。 private String introduction;// 登录用户的个人介绍。 private Boolean isEnt;// 登录用户是否为企业机构 private Boolean isMyBlack;// 是否在当前用户的黑名单中 private Boolean isMyFans;// 是否是当前用户的听众 private Boolean isMyIdol;// 是否是当前用户的偶像 private Boolean isRealName;// 登录用户是否实名认证 private Boolean isVip;// 登录用户是否为微博认证用户 private String location;// 登录用户所在地。 private Integer mutualFansNum;// 登录用户的互听好友数 private SendPrivate sendPrivate;// 是否允许所有人给当前用户发私信。 private Gender gender; private List tags; private List tweets; private Integer tweetNum; private String verifyInfo; private Integer exp; private Integer level; private String seqId; public String getOpenId() { return openId; } public void setOpenId(String openId) { this.openId = openId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getNick() { return nick; } public void setNick(String nick) { this.nick = nick; } public Date getRegTime() { return regTime; } public void setRegTime(Date regTime) { this.regTime = regTime; } public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } public String getCountryCode() { return countryCode; } public void setCountryCode(String countryCode) { this.countryCode = countryCode; } public String getProvinceCode() { return provinceCode; } public void setProvinceCode(String provinceCode) { this.provinceCode = provinceCode; } public String getCityCode() { return cityCode; } public void setCityCode(String cityCode) { this.cityCode = cityCode; } public List getCompanies() { return companies; } public void setCompanies(List companies) { this.companies = companies; } public List getEducations() { return educations; } public void setEducations(List educations) { this.educations = educations; } public Integer getFansNum() { return fansNum; } public void setFansNum(Integer fansNum) { this.fansNum = fansNum; } public Integer getFavNum() { return favNum; } public void setFavNum(Integer favNum) { this.favNum = favNum; } public String getHead() { return head; } public void setHead(String head) { this.head = head; } public String getHomeCountryCode() { return homeCountryCode; } public void setHomeCountryCode(String homeCountryCode) { this.homeCountryCode = homeCountryCode; } public String getHomeProvinceCode() { return homeProvinceCode; } public void setHomeProvinceCode(String homeProvinceCode) { this.homeProvinceCode = homeProvinceCode; } public String getHomeCityCode() { return homeCityCode; } public void setHomeCityCode(String homeCityCode) { this.homeCityCode = homeCityCode; } public String getHometownCode() { return hometownCode; } public void setHometownCode(String hometownCode) { this.hometownCode = hometownCode; } public String getHomepage() { return homepage; } public void setHomepage(String homepage) { this.homepage = homepage; } public Integer getIdolNum() { return idolNum; } public void setIdolNum(Integer idolNum) { this.idolNum = idolNum; } public String getIndustryCode() { return industryCode; } public void setIndustryCode(String industryCode) { this.industryCode = industryCode; } public String getIntroduction() { return introduction; } public void setIntroduction(String introduction) { this.introduction = introduction; } public Boolean getIsEnt() { return isEnt; } public void setIsEnt(Boolean isEnt) { this.isEnt = isEnt; } public Boolean getIsMyBlack() { return isMyBlack; } public void setIsMyBlack(Boolean isMyBlack) { this.isMyBlack = isMyBlack; } public Boolean getIsMyFans() { return isMyFans; } public void setIsMyFans(Boolean isMyFans) { this.isMyFans = isMyFans; } public Boolean getIsMyIdol() { return isMyIdol; } public void setIsMyIdol(Boolean isMyIdol) { this.isMyIdol = isMyIdol; } public Boolean getIsRealName() { return isRealName; } public void setIsRealName(Boolean isRealName) { this.isRealName = isRealName; } public Boolean getIsVip() { return isVip; } public void setIsVip(Boolean isVip) { this.isVip = isVip; } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } public Integer getMutualFansNum() { return mutualFansNum; } public void setMutualFansNum(Integer mutualFansNum) { this.mutualFansNum = mutualFansNum; } public SendPrivate getSendPrivate() { return sendPrivate; } public void setSendPrivate(SendPrivate sendPrivate) { this.sendPrivate = sendPrivate; } public Gender getGender() { return gender; } public void setGender(Gender gender) { this.gender = gender; } public List getTags() { return tags; } public void setTags(List tags) { this.tags = tags; } public List getTweets() { return tweets; } public void setTweets(List tweets) { this.tweets = tweets; } public Integer getTweetNum() { return tweetNum; } public void setTweetNum(Integer tweetNum) { this.tweetNum = tweetNum; } public String getVerifyInfo() { return verifyInfo; } public void setVerifyInfo(String verifyInfo) { this.verifyInfo = verifyInfo; } public Integer getExp() { return exp; } public void setExp(Integer exp) { this.exp = exp; } public Integer getLevel() { return level; } public void setLevel(Integer level) { this.level = level; } public String getSeqId() { return seqId; } public void setSeqId(String seqId) { this.seqId = seqId; } public static WeiboUser parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } WeiboUser obj = new WeiboUser(jsonObject); obj.openId = Result.toString(jsonObject.get("openid")); obj.name = Result.toString(jsonObject.opt("name")); obj.nick = Result.toString(jsonObject.opt("nick")); obj.regTime = Result.parseTimeSeconds(jsonObject.opt("regtime")); Object year = jsonObject.get("birth_year"); Object month = jsonObject.get("birth_month"); Object day = jsonObject.get("birth_day"); obj.birth = Result.parseDate(year.toString() + month.toString() + day.toString(), "yyyy-MM-dd", Locale.CHINA); obj.countryCode = Result.toString(jsonObject.opt("country_code")); obj.provinceCode = Result.toString(jsonObject.opt("province_code")); obj.cityCode = Result.toString(jsonObject.opt("city_code")); JSONArray jsonArray = jsonObject.optJSONArray("comp"); if (jsonArray != null) { List companies = new ArrayList(); for (int i = 0; i < jsonArray.length(); i++) { companies.add(Company.parse(jsonArray.optJSONObject(i))); } obj.companies = companies; } jsonArray = jsonObject.optJSONArray("edu"); if (jsonArray != null) { List educations = new ArrayList(); for (int i = 0; i < jsonArray.length(); i++) { educations.add(Education.parse(jsonArray.optJSONObject(i))); } obj.educations = educations; } obj.fansNum = Result.parseInteger(jsonObject.opt("fansnum")); obj.favNum = Result.parseInteger(jsonObject.opt("favnum")); obj.head = Result.toString(jsonObject.opt("head")); obj.homeCountryCode = Result.toString(jsonObject.opt("homecountry_code")); obj.homeProvinceCode = Result.toString(jsonObject.opt("homeprovince_code")); obj.homeCityCode = Result.toString(jsonObject.opt("homecity_code")); obj.hometownCode = Result.toString(jsonObject.opt("hometown_code")); obj.homepage = Result.toString(jsonObject.opt("homepage")); obj.idolNum = Result.parseInteger(jsonObject.opt("idolnum")); obj.industryCode = Result.toString(jsonObject.opt("industry_code")); obj.introduction = Result.toString(jsonObject.opt("introduction")); obj.isEnt = Result.parseBoolean(jsonObject.opt("isent")); obj.isMyBlack = Result.parseBoolean(jsonObject.opt("ismyblack")); obj.isMyFans = Result.parseBoolean(jsonObject.opt("ismyfans")); obj.isMyIdol = Result.parseBoolean(jsonObject.opt("isMyIdol")); obj.isRealName = Result.parseBoolean(jsonObject.opt("isrealname")); obj.isVip = Result.parseBoolean(jsonObject.opt("isvip")); obj.location = Result.toString(jsonObject.opt("location")); obj.mutualFansNum = Result.parseInteger(jsonObject.opt("mutual_fans_num")); obj.sendPrivate = SendPrivate.parse(Result.parseInteger(jsonObject.opt("send_private_flag"))); obj.gender = Gender.parse(Result.parseInteger(jsonObject.opt("sex"))); jsonArray = jsonObject.optJSONArray("tag"); if (jsonArray != null) { List tags = new ArrayList(); for (int i = 0; i < jsonArray.length(); i++) { tags.add(Tag.parse(jsonArray.optJSONObject(i))); } obj.tags = tags; } jsonArray = jsonObject.optJSONArray("tweetinfo"); if (jsonArray == null) { jsonArray = jsonObject.optJSONArray("tweet"); } if (jsonArray != null) { List tweets = new ArrayList(); for (int i = 0; i < jsonArray.length(); i++) { tweets.add(TweetInfo.parse(jsonArray.optJSONObject(i))); } obj.tweets = tweets; } obj.tweetNum = Result.parseInteger(jsonObject.opt("tweetnum")); obj.verifyInfo = Result.toString(jsonObject.opt("verifyinfo")); obj.exp = Result.parseInteger(jsonObject.opt("exp")); obj.level = Result.parseInteger(jsonObject.opt("level")); obj.seqId = Result.toString(jsonObject.opt("seqid")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/mail/api/Contact.java ================================================ package com.belerweb.social.qq.mail.api; import java.io.IOException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.script.Bindings; import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.RandomStringUtils; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.NameValuePair; import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicNameValuePair; import org.jsoup.Jsoup; import org.jsoup.nodes.DataNode; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import com.belerweb.social.captcha.api.Yundama; import com.belerweb.social.captcha.bean.YundamaType; import com.belerweb.social.exception.SocialException; import com.belerweb.social.http.Http; import com.belerweb.social.qq.mail.bean.Group; import com.belerweb.social.qq.mail.bean.User; import com.belerweb.social.qq.mail.bean.ValidationCode; /** * 获取QQ邮箱联系人 */ public class Contact { private static final Pattern PATTERN = Pattern.compile("sid=([0-9a-zA-Z-_]+)[&\"]"); private HttpClient http; private String email; private String password; private Yundama yundama; private String sid; /** * 创建一个QQ邮箱联系人API * * @param email QQ邮箱地址 * @param password QQ邮箱密码 */ public Contact(String email, String password, Yundama yundama) { this.email = email; this.password = password; this.yundama = yundama; http = Http.newClient(); } private List get(Group group) throws SocialException { HttpGet request = new HttpGet("http://mail.qq.com/cgi-bin/laddr_list?sid=" + sid + "&operate=view&t=contact&view=" + group.getType() + (group.getId() != null ? ("&groupid=" + group.getId()) : "&loc=frame_html,,,23")); request.addHeader(new BasicHeader("Referer", "http://mail.qq.com/cgi-bin/laddr_list?operate=view&t=contact&view=normal&loc=frame_html,,,23&sid=" + sid)); request.addHeader(new BasicHeader("Accept-Language", "zh-cn,zh")); request .addHeader(new BasicHeader("Referer", "http://mail.qq.com/cgi-bin/frame_html?sid=" + sid)); try { HttpResponse response = http.execute(request); StatusLine statusLine = response.getStatusLine(); if (statusLine == null || statusLine.getStatusCode() != HttpStatus.SC_OK || response.getEntity() == null) { throw new SocialException(String.valueOf(statusLine)); } String result = IOUtils.toString(response.getEntity().getContent(), "GB18030"); request.releaseConnection(); List groups = null; Document doc = Jsoup.parse(result); Elements scripts = doc.select("script"); for (Element el : scripts) { for (DataNode node : el.dataNodes()) { String script = node.getWholeData().trim(); if (script.startsWith("var goListData")) { ScriptEngine engine = new ScriptEngineManager().getEngineByName("javascript"); List users = new ArrayList(); Bindings bindings = engine.createBindings(); bindings.put("users", users); script = script + "(function(){for(var i in goListData.oList){var o=goListData.oList[i];var u=new com.belerweb.social.qq.mail.bean.User();u.setId(o.sId);u.setType(o.sItemType);u.setLevel(o.sLevel);u.setName(o.oName.length?o.oName[0].sVal:'');u.setFamilyName((o.oFamilyName&&o.oFamilyName.length)?o.oFamilyName[0].sVal:'');u.setGivenName((o.oGivenName&&o.oGivenName.length)?o.oGivenName[0].sVal:'');u.setCustom((o.oCustom&&o.oCustom.length)?o.oCustom[0].sVal:'');u.setNickName((o.oQQNickName&&o.oQQNickName.length)?o.oQQNickName[0].sVal:'');u.setRelate((o.oRelate&&o.oRelate.length)?o.oRelate[0].sVal:'');u.setUrl((o.oUrl&&o.oUrl.length)?o.oUrl[0].sVal:'');u.setDate((o.oDate&&o.oDate.length)?o.oDate[0].sVal:'');u.setBirthday((o.oBirthday&&o.oBirthday.length)?o.oBirthday[0].sVal:'');u.setIm((o.oIM&&o.oIM.length)?o.oIM[0].sVal:'');u.setNote((o.oNote&&o.oNote.length)?o.oNote[0].sVal:'');var es=new java.util.ArrayList();for(var j in o.oEmail){var obj=o.oEmail[j];var e=new com.belerweb.social.qq.mail.bean.Email();e.setEmail(obj.sVal);e.setLabel(obj.sLabel?obj.sLabel:'');e.setType(obj.sType?obj.sType:'');es.add(e)}u.setEmails(es);var ts=new java.util.ArrayList();for(var j in o.oTel){var obj=o.oTel[j];var t=new com.belerweb.social.qq.mail.bean.Tel();t.setNum(obj.sVal);t.setLabel(obj.sLabel?obj.sLabel:'');t.setType(obj.sType?obj.sType:'');ts.add(t)}u.setTels(ts);if(o.oOrg&&o.oOrg.length){var org=new com.belerweb.social.qq.mail.bean.Org();org.setOrg1(o.oOrg[0].sOrg1);org.setOrg2(o.oOrg[0].sOrg2);org.setTitle(o.oOrg[0].sTitle);u.setOrg(org)}if(o.oAdr&&o.oAdr.length){var adr=new com.belerweb.social.qq.mail.bean.Address();adr.setLabel(o.oAdr[0].sLabel);adr.setType(o.oAdr[0].sType);adr.setCountry(o.oAdr[0].sCountry);adr.setProvince(o.oAdr[0].sProvince);adr.setCity(o.oAdr[0].sCity);adr.setStreet(o.oAdr[0].sStreet);adr.setPostcode(o.oAdr[0].sPostcode);u.setAddress(adr)}users.add(u)}})();"; if (group.getId() == null) { groups = new ArrayList(); bindings.put("groups", groups); script = script + "(function(){for(var k in goGroupData){for(var i in goGroupData[k].oList){var obj=goGroupData[k].oList[i];var g=new com.belerweb.social.qq.mail.bean.Group();g.setId(obj.sId);g.setType(obj.sSubType);g.setName(obj.sName);groups.add(g);}}})();"; } engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE); engine.eval(script); group.setUsers(users); } } } return groups; } catch (ClientProtocolException e) { throw new SocialException(e); } catch (IOException e) { throw new SocialException(e); } catch (ScriptException e) { throw new SocialException(e); } } /** * 按分组获取所有QQ邮箱中的联系人,包括QQ联系人 */ public List get() throws SocialException { List result = new ArrayList(); login(); Group group = new Group(); group.setType("normal"); group.setName("全部"); group.setOwner(email); List groups = get(group); result.add(group); for (Group group2 : groups) { get(group2); group2.setOwner(email); result.add(group2); } return result; } /** * QQ邮箱登录,如果登录成功则返回sid,登录失败抛出异常 */ public String login() throws SocialException { ValidationCode validationCode = check(); String vc = validationCode.getCode(); if (validationCode.need()) { vc = yundama.decode(getValidationCode(), YundamaType.ALPHABETIC4).getResult(); } try { String code = DigestUtils.md5Hex(password).toUpperCase(); byte[] byte1 = Hex.decodeHex(code.toCharArray()); byte[] byte2 = Hex.decodeHex(validationCode.getUid().toCharArray()); byte[] bytes = new byte[byte1.length + byte2.length]; System.arraycopy(byte1, 0, bytes, 0, byte1.length); System.arraycopy(byte2, 0, bytes, byte1.length, byte2.length); code = DigestUtils.md5Hex(bytes).toUpperCase(); code = DigestUtils.md5Hex(code + vc.toUpperCase()).toUpperCase(); List params = new ArrayList(); params.add(new BasicNameValuePair("aid", "522005705")); params.add(new BasicNameValuePair("ptlang", "2052")); params.add(new BasicNameValuePair("js_type", "2")); params.add(new BasicNameValuePair("js_ver", "10009")); params.add(new BasicNameValuePair("fp", "loginerroralert")); params.add(new BasicNameValuePair("wording", "快速登录")); params.add(new BasicNameValuePair("mibao_css", "m_ptmail")); params.add(new BasicNameValuePair("u1", URLEncoder.encode( "https://mail.qq.com/cgi-bin/login?vt=passport&vm=wpt&ft=ptlogin&lang=cn&ss=&validcnt=&clientaddr=" + email, "UTF-8"))); params.add(new BasicNameValuePair("css", "https://mail.qq.com/zh_CN/htmledition/style/fast_login181b91.css")); params.add(new BasicNameValuePair("daid", "4")); params.add(new BasicNameValuePair("dummy", "")); params.add(new BasicNameValuePair("from_ui", "1")); params.add(new BasicNameValuePair("g", "1")); params.add(new BasicNameValuePair("h", "1")); params.add(new BasicNameValuePair("ptredirect", "1")); params.add(new BasicNameValuePair("t", "1")); params.add(new BasicNameValuePair("action", "4-20-" + RandomStringUtils.randomNumeric(5))); params.add(new BasicNameValuePair("p", code)); params.add(new BasicNameValuePair("u", email)); params.add(new BasicNameValuePair("u_domain", email.substring(email.indexOf("@")))); params.add(new BasicNameValuePair("uin", email.substring(0, email.indexOf("@")))); params.add(new BasicNameValuePair("verifycode", vc)); HttpGet request = new HttpGet("https://ssl.ptlogin2.qq.com/login?" + StringUtils.join(params, "&")); request .addHeader(new BasicHeader("Referer", "https://mail.qq.com/cgi-bin/loginpage?lang=cn")); request.addHeader(new BasicHeader("Accept-Language", "zh-cn,zh")); HttpResponse response = http.execute(request); StatusLine statusLine = response.getStatusLine(); if (statusLine == null || statusLine.getStatusCode() != HttpStatus.SC_OK || response.getEntity() == null) { throw new SocialException(String.valueOf(statusLine)); } String result = IOUtils.toString(response.getEntity().getContent()); request.releaseConnection(); String[] str = result.substring(7, result.length() - 1).split(","); if (!"0".equals(str[0].trim().substring(1, str[0].length() - 1))) { throw new SocialException(str[4]); } request = new HttpGet(str[2].trim().substring(1, str[2].length() - 1)); response = http.execute(request); statusLine = response.getStatusLine(); if (statusLine == null || statusLine.getStatusCode() != HttpStatus.SC_OK || response.getEntity() == null) { throw new SocialException(String.valueOf(statusLine)); } result = IOUtils.toString(response.getEntity().getContent(), "GB18030"); request.releaseConnection(); Matcher matcher = PATTERN.matcher(result); if (matcher.find()) { this.sid = matcher.group(1); } else { if (!result.contains("看不清")) { Document doc = Jsoup.parse(result); Elements scripts = doc.select("script"); boolean status = false; for (Element el : scripts) { for (DataNode node : el.dataNodes()) { String script = node.getWholeData().trim(); if (script.startsWith("var urlHead")) { ScriptEngine engine = new ScriptEngineManager().getEngineByName("javascript"); script = script.replace("window.location.replace(targetUrl);", ""); try { engine.eval(script); String url = engine.get("targetUrl").toString(); request = new HttpGet(url); response = http.execute(request); result = IOUtils.toString(response.getEntity().getContent(), "GB18030"); status = true; } catch (Exception e) { e.printStackTrace(); } } } } if (!status) { // throw new SocialException("没有获取到sid"); } } vc = yundama.decode(getValidationCode2(), YundamaType.ALPHABETIC4).getResult(); params = new ArrayList(); params.add(new BasicNameValuePair("btlogin", "登录")); params.add(new BasicNameValuePair("delegate_url", "")); params.add(new BasicNameValuePair("sid", "")); params.add(new BasicNameValuePair("uin", email.substring(0, email.indexOf("@")))); params.add(new BasicNameValuePair("verifycode", vc)); params.add(new BasicNameValuePair("vt", "passport")); HttpPost post = new HttpPost("https://mail.qq.com/cgi-bin/login?sid="); post.setConfig(RequestConfig.custom().setRedirectsEnabled(false) .setRelativeRedirectsAllowed(false).setCircularRedirectsAllowed(false).build()); post.setEntity(new UrlEncodedFormEntity(params)); response = http.execute(post); try { result = IOUtils.toString(response.getEntity().getContent(), "GB18030"); matcher = PATTERN.matcher(result); if (matcher.find()) { this.sid = matcher.group(1); } else { matcher = PATTERN.matcher(response.getFirstHeader("Location").getValue()); if (matcher.find()) { this.sid = matcher.group(1); } else { throw new SocialException("没有获取到sid"); } } } catch (Exception e) { throw new SocialException("没有获取到sid"); } } return this.sid; } catch (DecoderException e) { throw new SocialException(e); } catch (ClientProtocolException e) { throw new SocialException(e); } catch (IOException e) { throw new SocialException(e); } } /** * 检查QQ邮箱登录是否需要验证码 */ public ValidationCode check() throws SocialException { List params = new ArrayList(); params.add(new BasicNameValuePair("appid", "522005705")); params.add(new BasicNameValuePair("ptlang", "2052")); params.add(new BasicNameValuePair("js_type", "2")); params.add(new BasicNameValuePair("js_ver", "10009")); params.add(new BasicNameValuePair("r", String.valueOf(Math.random()))); params.add(new BasicNameValuePair("uin", email)); HttpGet request = new HttpGet("https://ssl.ptlogin2.qq.com/check?" + StringUtils.join(params, "&")); request.addHeader(new BasicHeader("Referer", "https://mail.qq.com/cgi-bin/loginpage?lang=cn")); request.addHeader(new BasicHeader("Accept-Language", "zh-cn,zh")); try { HttpResponse response = http.execute(request); StatusLine statusLine = response.getStatusLine(); if (statusLine == null || statusLine.getStatusCode() != HttpStatus.SC_OK || response.getEntity() == null) { throw new SocialException(String.valueOf(statusLine)); } String result = IOUtils.toString(response.getEntity().getContent()); request.releaseConnection(); return new ValidationCode(result); } catch (ClientProtocolException e) { throw new SocialException(e); } catch (IOException e) { throw new SocialException(e); } } /** * 获取验证码 */ public byte[] getValidationCode() throws SocialException { List params = new ArrayList(); params.add(new BasicNameValuePair("aid", "522005705")); params.add(new BasicNameValuePair("r", String.valueOf(Math.random()))); params.add(new BasicNameValuePair("uin", email)); HttpGet request = new HttpGet("https://ssl.captcha.qq.com/getimage?" + StringUtils.join(params, "&")); request.addHeader(new BasicHeader("Referer", "https://mail.qq.com/cgi-bin/loginpage?lang=cn")); request.addHeader(new BasicHeader("Accept-Language", "zh-cn,zh")); try { HttpResponse response = http.execute(request); StatusLine statusLine = response.getStatusLine(); if (statusLine == null || statusLine.getStatusCode() != HttpStatus.SC_OK || response.getEntity() == null) { throw new SocialException(String.valueOf(statusLine)); } byte[] result = IOUtils.toByteArray(response.getEntity().getContent()); request.releaseConnection(); return result; } catch (ClientProtocolException e) { throw new SocialException(e); } catch (IOException e) { throw new SocialException(e); } } /** * 获取验证码2 */ public byte[] getValidationCode2() throws SocialException { List params = new ArrayList(); params.add(new BasicNameValuePair("aid", "23000101")); params.add(new BasicNameValuePair("f", "html")); params.add(new BasicNameValuePair("ck", "1")); params.add(new BasicNameValuePair("r", String.valueOf(Math.random()))); HttpGet request = new HttpGet("https://mail.qq.com/cgi-bin/getverifyimage?" + StringUtils.join(params, "&")); request.addHeader(new BasicHeader("Referer", " https://mail.qq.com/cgi-bin/loginpage?errtype=3")); request.addHeader(new BasicHeader("Accept-Language", "zh-cn,zh")); try { HttpResponse response = http.execute(request); StatusLine statusLine = response.getStatusLine(); if (statusLine == null || statusLine.getStatusCode() != HttpStatus.SC_OK || response.getEntity() == null) { throw new SocialException(String.valueOf(statusLine)); } byte[] result = IOUtils.toByteArray(response.getEntity().getContent()); request.releaseConnection(); return result; } catch (ClientProtocolException e) { throw new SocialException(e); } catch (IOException e) { throw new SocialException(e); } } } ================================================ FILE: src/main/java/com/belerweb/social/qq/mail/bean/Address.java ================================================ package com.belerweb.social.qq.mail.bean; public class Address { private String label; private String type; private String country; private String province; private String city; private String street; private String postcode; public String getLabel() { return label; } public void setLabel(String label) { this.label = label; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getProvince() { return province; } public void setProvince(String province) { this.province = province; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } public String getPostcode() { return postcode; } public void setPostcode(String postcode) { this.postcode = postcode; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/mail/bean/Email.java ================================================ package com.belerweb.social.qq.mail.bean; public class Email { private String label; private String type; private String email; public String getLabel() { return label; } public void setLabel(String label) { this.label = label; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/mail/bean/Group.java ================================================ package com.belerweb.social.qq.mail.bean; import java.util.List; public class Group { private String id; private String type; private String name; private List users; private String owner; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List getUsers() { return users; } public void setUsers(List users) { this.users = users; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/mail/bean/Org.java ================================================ package com.belerweb.social.qq.mail.bean; public class Org { private String org1; private String org2; private String title; public String getOrg1() { return org1; } public void setOrg1(String org1) { this.org1 = org1; } public String getOrg2() { return org2; } public void setOrg2(String org2) { this.org2 = org2; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/mail/bean/Tel.java ================================================ package com.belerweb.social.qq.mail.bean; public class Tel { private String label; private String type; private String num; public String getLabel() { return label; } public void setLabel(String label) { this.label = label; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getNum() { return num; } public void setNum(String num) { this.num = num; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/mail/bean/User.java ================================================ package com.belerweb.social.qq.mail.bean; import java.util.List; public class User { private String id; private String level; private String type; private String name; private String nickName; private String familyName; private String givenName; private String relate; private String url; private String date; private String birthday; private String im; private String custom; private String note; private Address address; private Org org; private List emails; private List tels; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getLevel() { return level; } public void setLevel(String level) { this.level = level; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getNickName() { return nickName; } public void setNickName(String nickName) { this.nickName = nickName; } public String getFamilyName() { return familyName; } public void setFamilyName(String familyName) { this.familyName = familyName; } public String getGivenName() { return givenName; } public void setGivenName(String givenName) { this.givenName = givenName; } public String getRelate() { return relate; } public void setRelate(String relate) { this.relate = relate; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } public String getBirthday() { return birthday; } public void setBirthday(String birthday) { this.birthday = birthday; } public String getIm() { return im; } public void setIm(String im) { this.im = im; } public String getCustom() { return custom; } public void setCustom(String custom) { this.custom = custom; } public String getNote() { return note; } public void setNote(String note) { this.note = note; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public Org getOrg() { return org; } public void setOrg(Org org) { this.org = org; } public List getEmails() { return emails; } public void setEmails(List emails) { this.emails = emails; } public List getTels() { return tels; } public void setTels(List tels) { this.tels = tels; } } ================================================ FILE: src/main/java/com/belerweb/social/qq/mail/bean/ValidationCode.java ================================================ package com.belerweb.social.qq.mail.bean; public class ValidationCode { private String status; private String code; private String uid; public ValidationCode() {} public ValidationCode(String response) { String[] str = response.substring(13, response.length() - 2).split(","); status = str[0].trim().substring(1, str[0].length() - 1); code = str[1].trim().substring(1, str[1].length() - 1); uid = str[2].trim().substring(1, str[2].length() - 1).replaceAll("\\\\x", ""); } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getUid() { return uid; } public void setUid(String uid) { this.uid = uid; } public boolean need() { return !"0".equals(status); } } ================================================ FILE: src/main/java/com/belerweb/social/qq/qzone/api/Visitor.java ================================================ package com.belerweb.social.qq.qzone.api; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicNameValuePair; import org.json.JSONObject; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.belerweb.social.captcha.api.Yundama; import com.belerweb.social.captcha.bean.YundamaType; import com.belerweb.social.exception.SocialException; import com.belerweb.social.http.Http; import com.belerweb.social.http.HttpException; import com.belerweb.social.qq.mail.bean.ValidationCode; public class Visitor { private static final Logger LOGGER = LoggerFactory.getLogger(Visitor.class); private String qq; private String password; private Yundama yundama; private HttpClient http; private String loginUi; private String loginSig; private String skey; private boolean session; public Visitor(String qq, String password, Yundama yundama) { this.qq = qq; this.password = password; this.yundama = yundama; this.http = Http.newClient(); } private void openLogin() throws ClientProtocolException, IOException, HttpException { String uri = "http://user.qzone.qq.com/" + qq + "/friendvisitor"; HttpResponse response = http.execute(new HttpGet(uri)); if (!Http.isRequestSuccess(response)) { throw new SocialException("Step 1, open login ui failed."); } Document doc = Jsoup.parse(Http.responseToString(response)); loginUi = doc.select("#login_frame").get(0).attr("src"); HttpGet request = new HttpGet(loginUi); request.addHeader(new BasicHeader("Referer", uri)); response = http.execute(request); if (!Http.isRequestSuccess(response)) { throw new SocialException("Step 2, open login ui failed."); } doc = Jsoup.parse(Http.responseToString(response)); Matcher matcher = Pattern.compile("login_sig\\s*:\\s*[\"']([^\"']+)[\"']").matcher( doc.select("script").get(0).html()); if (!matcher.find()) { throw new SocialException("Step 3, login page isn't contain login_sig."); } loginSig = matcher.group(1); } private ValidationCode loginCheck() throws ClientProtocolException, IOException, HttpException { List params = new ArrayList(); params.add(new BasicNameValuePair("regmaster", "")); params.add(new BasicNameValuePair("uin", qq)); params.add(new BasicNameValuePair("appid", "549000912")); params.add(new BasicNameValuePair("js_ver", "10064")); params.add(new BasicNameValuePair("js_type", "1")); params.add(new BasicNameValuePair("login_sig", loginSig)); params .add(new BasicNameValuePair("u1", "http://qzs.qq.com/qzone/v5/loginsucc.html?para=reload")); params.add(new BasicNameValuePair("r", String.valueOf(Math.random()))); HttpGet request = new HttpGet("http://check.ptlogin2.qq.com/check?" + StringUtils.join(params, "&")); request.addHeader(new BasicHeader("Referer", loginUi)); request.addHeader(new BasicHeader("Accept-Language", "zh-cn,zh")); HttpResponse response = http.execute(request); if (!Http.isRequestSuccess(response)) { throw new SocialException("Step 4, check if validation code failed."); } return new ValidationCode(Http.responseToString(response)); } private byte[] getValidationCode() throws ClientProtocolException, IOException, HttpException { List params = new ArrayList(); params.add(new BasicNameValuePair("uin", qq)); params.add(new BasicNameValuePair("aid", "549000912")); params.add(new BasicNameValuePair(String.valueOf(Math.random()), "")); HttpGet request = new HttpGet("http://captcha.qq.com/getimage?" + StringUtils.join(params, "&")); request.addHeader(new BasicHeader("Referer", loginUi)); request.addHeader(new BasicHeader("Accept-Language", "zh-cn,zh")); HttpResponse response = http.execute(request); if (!Http.isRequestSuccess(response)) { throw new SocialException("Step 5, get validation code image failed."); } return IOUtils.toByteArray(response.getEntity().getContent()); } private void login() throws ClientProtocolException, IOException, DecoderException, HttpException { openLogin(); ValidationCode validationCode = loginCheck(); String code = validationCode.getCode(); if (validationCode.need()) { LOGGER.debug("Qzone visitor need validation code."); code = yundama.decode(getValidationCode(), YundamaType.ALPHANUMERIC).getResult(); LOGGER.debug("Qzone visitor validation code is {}.", code); } String p = DigestUtils.md5Hex(password).toUpperCase(); byte[] byte1 = Hex.decodeHex(p.toCharArray()); byte[] byte2 = Hex.decodeHex(validationCode.getUid().toCharArray()); byte[] bytes = new byte[byte1.length + byte2.length]; System.arraycopy(byte1, 0, bytes, 0, byte1.length); System.arraycopy(byte2, 0, bytes, byte1.length, byte2.length); p = DigestUtils.md5Hex(bytes).toUpperCase(); p = DigestUtils.md5Hex(p + code.toUpperCase()).toUpperCase(); List params = new ArrayList(); params.add(new BasicNameValuePair("u", qq)); params.add(new BasicNameValuePair("p", p)); params.add(new BasicNameValuePair("verifycode", code)); params.add(new BasicNameValuePair("aid", "549000912")); params.add(new BasicNameValuePair("u1", "http%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dreload")); params.add(new BasicNameValuePair("h", "1")); params.add(new BasicNameValuePair("ptredirect", "0")); params.add(new BasicNameValuePair("ptlang", "2052")); params.add(new BasicNameValuePair("from_ui", "1")); params.add(new BasicNameValuePair("dump", "")); params.add(new BasicNameValuePair("low_login_enable", "0")); params.add(new BasicNameValuePair("regmaster", "")); params.add(new BasicNameValuePair("fp", "loginerroralert")); params.add(new BasicNameValuePair("action", "2-22-1389885147889")); params.add(new BasicNameValuePair("mibao_css", "")); params.add(new BasicNameValuePair("t", "1")); params.add(new BasicNameValuePair("g", "1")); params.add(new BasicNameValuePair("js_ver", "10064")); params.add(new BasicNameValuePair("js_type", "1")); params.add(new BasicNameValuePair("login_sig", loginSig)); params.add(new BasicNameValuePair("pt_rsa", "0")); HttpGet request = new HttpGet("http://ptlogin2.qq.com/login?" + StringUtils.join(params, "&")); request.addHeader(new BasicHeader("Referer", loginUi)); request.addHeader(new BasicHeader("Accept-Language", "zh-cn,zh")); HttpResponse response = http.execute(request); if (!Http.isRequestSuccess(response)) { throw new SocialException("Step 6, login failed."); } LOGGER.debug("Qzone visitor login end."); String html = Http.responseToString(response); if (!html.contains("登录成功")) { throw new SocialException("Step 7, login failed."); } for (Header header : response.getHeaders("Set-Cookie")) { Matcher matcher = Pattern.compile("skey=([^;]+);").matcher(header.getValue()); if (matcher.find()) { skey = matcher.group(1); session = true; LOGGER.debug("Qzone visitor login success."); } } if (!session) { throw new SocialException("Step 8, get skey failed."); } } public JSONObject getSimple() throws SocialException { LOGGER.debug("Qzone visitor getSimple begin."); try { if (!session) { LOGGER.debug("Qzone visitor need login."); login(); } else { LOGGER.debug("Qzone in session."); } long gtk = 5381; for (int i = 0, len = skey.length(); i < len; ++i) { gtk += (gtk << 5) + skey.charAt(i); } gtk = gtk & 2147483647; List params = new ArrayList(); params.add(new BasicNameValuePair("uin", qq)); params.add(new BasicNameValuePair("mask", "2")); params.add(new BasicNameValuePair("clear", "1")); params.add(new BasicNameValuePair("mod", "8")); params.add(new BasicNameValuePair("fupdate", "1")); params.add(new BasicNameValuePair("random", String.valueOf(Math.random()))); params.add(new BasicNameValuePair("g_tk", String.valueOf(gtk))); HttpGet request = new HttpGet("http://g.qzone.qq.com/cgi-bin/friendshow/cgi_get_visitor_simple?" + StringUtils.join(params, "&")); request.addHeader(new BasicHeader("Referer", "http://ctc.qzs.qq.com/qzone/v8/pages/visitors/refuse.html")); request.addHeader(new BasicHeader("Accept-Language", "zh-cn,zh")); HttpResponse response = http.execute(request); if (!Http.isRequestSuccess(response)) { throw new SocialException("Step 9, get visitor simple failed."); } LOGGER.debug("Qzone visitor getSimple end."); String html = Http.responseToString(response); JSONObject json = new JSONObject(html.substring(html.indexOf("{"), html.lastIndexOf("}") + 1)); if (json.getInt("code") != 0) { LOGGER.debug("Qzone visitor getSimple error: {}", html); session = false; http = Http.newClient(); loginUi = null; loginSig = null; skey = null; return getSimple(); } LOGGER.debug("Qzone visitor getSimple success."); return json; } catch (ClientProtocolException e) { throw new SocialException(e); } catch (IOException e) { throw new SocialException(e); } catch (HttpException e) { throw new SocialException(e); } catch (DecoderException e) { throw new SocialException(e); } } } ================================================ FILE: src/main/java/com/belerweb/social/qq/t/api/OAuth2.java ================================================ package com.belerweb.social.qq.t.api; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.apache.http.NameValuePair; import com.belerweb.social.API; public final class OAuth2 extends API { OAuth2(QQT t) { super(t); } /** * 获取Authorization Code * * 从 {@link QQT} 从获取clientId,redirectUri,responseType为code ,其余参数默认 * * @see OAuth2#authorize(String, String, String, String, String, Boolean) */ public String authorize() { return authorize(t.getRedirectUri()); } /** * 获取Authorization Code * * 从 {@link QQT} 从获取clientId,responseType为code ,其余参数默认 * * @see OAuth2#authorize(String, String, String, String, String, Boolean) */ public String authorize(String redirectUri) { return authorize(t.getClientId(), redirectUri, "code", null, null, null); } /** * 获取Authorization Code * * 文档地址:http://wiki.t.qq.com/使用authorization_code获取access_token * * @param clientId 必须,申请应用时分配的app_key * @param redirectUri 必须,授权回调地址,必须和应用注册的地址一致(地址长度上限为256个字节) * @param responseType 必须,授权类型,为code * @param wap * 主要用于指定手机授权页的版本,无此参数默认显示pc授权页面。wap=1时,跳转到wap1.0的授权页。wap=2时,跳转到wap2.0的授权页。不带本参数时,手机访问默认跳到wap2 * .0的授权页 * @param state * 用于保持请求和回调的状态,授权请求成功后原样带回给第三方。该参数用于防止csrf攻击(跨站请求伪造攻击),强烈建议第三方带上该参数。参数设置建议为简单随机数+session的方式 * @param forceLogin 针对pc授权页。forcelogin=true,强制弹出登录授权页面 * forcelogin=false,用户已经登录并且已经授权第三方应用,则不再弹出授权页面 默认为forcelogin=true */ public String authorize(String clientId, String redirectUri, String responseType, String wap, String state, Boolean forceLogin) { List params = new ArrayList(); t.addParameter(params, "client_id", clientId); t.addParameter(params, "redirect_uri", redirectUri); t.addParameter(params, "response_type", responseType); t.addNotNullParameter(params, "wap", wap); t.addNotNullParameter(params, "state", state); t.addTrueParameter(params, "forcelogin", forceLogin); return "https://open.t.qq.com/cgi-bin/oauth2/authorize?" + StringUtils.join(params, "&"); } } ================================================ FILE: src/main/java/com/belerweb/social/qq/t/api/QQT.java ================================================ package com.belerweb.social.qq.t.api; import com.belerweb.social.SDK; public final class QQT extends SDK { private String clientId; private String clientSecret; private String redirectUri; public QQT(String clientId, String clientSecret) { this.clientId = clientId; this.clientSecret = clientSecret; } public QQT(String clientId, String clientSecret, String redirectUri) { this(clientId, clientSecret); this.redirectUri = redirectUri; } public String getClientId() { return clientId; } public void setClientId(String clientId) { this.clientId = clientId; } public String getClientSecret() { return clientSecret; } public void setClientSecret(String clientSecret) { this.clientSecret = clientSecret; } public String getRedirectUri() { return redirectUri; } public void setRedirectUri(String redirectUri) { this.redirectUri = redirectUri; } } ================================================ FILE: src/main/java/com/belerweb/social/weibo/api/OAuth2.java ================================================ package com.belerweb.social.weibo.api; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.apache.http.NameValuePair; import org.json.JSONObject; import com.belerweb.social.API; import com.belerweb.social.bean.Error; import com.belerweb.social.bean.Result; import com.belerweb.social.exception.SocialException; import com.belerweb.social.weibo.bean.AccessToken; import com.belerweb.social.weibo.bean.Display; import com.belerweb.social.weibo.bean.Scope; import com.belerweb.social.weibo.bean.TokenInfo; public final class OAuth2 extends API { OAuth2(Weibo weibo) { super(weibo); } /** * OAuth2的authorize接口 * * 从 {@link Weibo} 从获取clientId,redirectUri,scope 使用 {@link Scope#ALL},其余参数默认 * * @see OAuth2#authorize(String, String, Scope[], String, Display, Boolean, String) */ public String authorize() { return authorize(weibo.getRedirectUri()); } /** * OAuth2的authorize接口 * * 从 {@link Weibo} 从获取clientId,scope 使用 {@link Scope#ALL},其余参数默认 * * @see OAuth2#authorize(String, String, Scope[], String, Display, Boolean, String) * * @param redirectUri 授权回调地址,站外应用需与设置的回调地址一致,站内应用需填写canvas page的地址。 */ public String authorize(String redirectUri) { return authorize(weibo.getClientId(), redirectUri, new Scope[] {Scope.ALL}, null, null, null, null); } /** * OAuth2的authorize接口 * * 文档地址:http://open.weibo.com/wiki/Oauth2/authorize * * @param clientId 申请应用时分配的AppKey。 * @param redirectUri 授权回调地址,站外应用需与设置的回调地址一致,站内应用需填写canvas page的地址。 * @param scope 申请scope权限所需参数,可一次申请多个scope权限,用逗号分隔。使用文档 * @param state 用于保持请求和回调的状态,在回调时,会在Query * Parameter中回传该参数。开发者可以用这个参数验证请求有效性,也可以记录用户请求授权页前的位置。这个参数可用于防止跨站请求伪造(CSRF)攻击 * @param display 授权页面的终端类型,取值见下面的说明。 * @param forceLogin 是否强制用户重新登录,true:是,false:否。默认false。 * @param language 授权页语言,缺省为中文简体版,en为英文版。 */ public String authorize(String clientId, String redirectUri, Scope[] scope, String state, Display display, Boolean forceLogin, String language) { List params = new ArrayList(); weibo.addParameter(params, "client_id", clientId); weibo.addParameter(params, "redirect_uri", redirectUri); if (scope != null) { weibo.addParameter(params, "scope", StringUtils.join(scope, ",")); } weibo.addNotNullParameter(params, "state", state); weibo.addNotNullParameter(params, "display", display); weibo.addTrueParameter(params, "forcelogin", forceLogin); weibo.addNotNullParameter(params, "language", language); return "https://api.weibo.com/oauth2/authorize?" + StringUtils.join(params, "&"); } /** * 从 {@link Weibo} 从获取clientId,clientSecret,grantType,redirectUri 使用 authorization_code * * @see OAuth2#accessToken(String, String, String, String, String) */ public Result accessToken(String code) { return accessToken(code, weibo.getRedirectUri()); } /** * 从 {@link Weibo} 从获取clientId,clientSecret,grantType 使用 authorization_code * * @see OAuth2#accessToken(String, String, String, String, String) */ public Result accessToken(String code, String redirectUri) { return accessToken(weibo.getClientId(), weibo.getClientSecret(), "authorization_code", code, redirectUri); } /** * OAuth2的access_token接口 * * 文档地址:http://open.weibo.com/wiki/OAuth2/access_token * * @param clientId 申请应用时分配的AppKey。 * @param clientSecret 申请应用时分配的AppSecret。 * @param grantType 请求的类型,填写authorization_code * @param code grant_type为authorization_code时,调用authorize获得的code值。 * @param redirectUri grant_type为authorization_code时,回调地址,需需与注册应用里的回调地址一致。 */ public Result accessToken(String clientId, String clientSecret, String grantType, String code, String redirectUri) { List params = new ArrayList(); weibo.addParameter(params, "client_id", clientId); weibo.addParameter(params, "client_secret", clientSecret); weibo.addParameter(params, "grant_type", grantType); if ("authorization_code".equals(grantType)) { weibo.addParameter(params, "code", code); weibo.addParameter(params, "redirect_uri", redirectUri); } String result = weibo.post("https://api.weibo.com/oauth2/access_token", params); return Result.parse(result, AccessToken.class); } /** * 查询用户access_token的授权相关信息,包括授权时间,过期时间和scope权限。 * * 文档地址:http://open.weibo.com/wiki/Oauth2/get_token_info * * @param accessToken 用户授权时生成的access_token。 */ public Result getTokenInfo(String accessToken) { List params = new ArrayList(); weibo.addParameter(params, "access_token", accessToken); String result = weibo.post("https://api.weibo.com/oauth2/get_token_info", params); return Result.parse(result, TokenInfo.class); } /** * 用于OAuth1.0 access token 更换至 OAuth2.0 access * token,帮助开发者使用新版接口和OAuth2.0时平滑迁移用户。详细的OAuth1.0调用方式和SDK资源参见:http://open.weibo.com/wiki/Oauth * * 文档地址:http://open.weibo.com/wiki/Oauth2/get_oauth2_token * * @param oauthConsumerKey 创建应用时生成的APP KEY。 * @param oauthToken oauth的token。 * @param oauthSignatureMethod 签名方法,建议使用“HMAC-SHA1”。 * @param oauthTimestamp 生成Base String时的时间戳。 * @param oauthNonce 单次值,一个随机字符串,防止重复攻击。该参数只支持ASCII码的字符串。 * @param oauthVersion OAuth协议版本。填写“1.0”。 * @param oauthSignature 签名值,是由根据上面的几个参数生成的 Base String经HMAC-SHA1算法计算得出。 */ public void getOAuth2Token(String oauthConsumerKey, String oauthToken, String oauthSignatureMethod, Long oauthTimestamp, String oauthNonce, String oauthVersion, String oauthSignature) { throw new SocialException("方法还未实现..."); } /** * 授权回收接口,帮助开发者主动取消用户的授权。 * * 文档地址:http://open.weibo.com/wiki/Oauth2/revokeoauth2 * * @param accessToken 用户授权应用的access_token */ public Result revokeOAuth2(String accessToken) { List params = new ArrayList(); weibo.addParameter(params, "access_token", accessToken); String json = weibo.post("https://api.weibo.com/oauth2/revokeoauth2", params); JSONObject jsonObject = new JSONObject(json); Error error = Error.parse(jsonObject); if (error == null) { return new Result(Result.parseBoolean(jsonObject.get("result"))); } return new Result(error); } } ================================================ FILE: src/main/java/com/belerweb/social/weibo/api/User.java ================================================ package com.belerweb.social.weibo.api; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.apache.http.NameValuePair; import com.belerweb.social.API; import com.belerweb.social.bean.Result; import com.belerweb.social.exception.SocialException; import com.belerweb.social.weibo.bean.UserCounts; /** * 读取用户信息接口 */ public final class User extends API { protected User(Weibo weibo) { super(weibo); } /** * 获取用户信息/根据用户ID获取用户信息 * * 访问级别:普通接口 * * 频次限制:是 * * 文档地址:https://api.weibo.com/2/users/show.json * * @param source 采用OAuth授权方式不需要此参数,其他授权方式为必填参数,数值为应用的AppKey。 * @param accessToken 采用OAuth授权方式为必填参数,其他授权方式不需要此参数,OAuth授权后获得。 * @param uid 需要查询的用户ID。 * @param screename 需要查询的用户昵称。 * * 参数uid与screen_name二者必选其一,且只能选其一 */ public Result show(String source, String accessToken, String uid, String screenName) { List params = new ArrayList(); weibo.addNotNullParameter(params, "source", source); weibo.addNotNullParameter(params, "access_token", accessToken); weibo.addNotNullParameter(params, "uid", uid); weibo.addNotNullParameter(params, "screen_name", screenName); String json = weibo.get("https://api.weibo.com/2/users/show.json", params); return Result.parse(json, com.belerweb.social.weibo.bean.User.class); } /** * 通过个性域名获取用户信息/通过个性化域名获取用户资料以及用户最新的一条微博 * * 访问级别:普通接口 * * 频次限制:是 * * 文档地址:https://api.weibo.com/2/users/domain_show.json * * @param source 采用OAuth授权方式不需要此参数,其他授权方式为必填参数,数值为应用的AppKey。 * @param accessToken 采用OAuth授权方式为必填参数,其他授权方式不需要此参数,OAuth授权后获得。 * @param domain 需要查询的个性化域名。 */ public Result domainShow(String source, String accessToken, String domain) { List params = new ArrayList(); weibo.addNotNullParameter(params, "source", source); weibo.addNotNullParameter(params, "access_token", accessToken); weibo.addParameter(params, "domain", domain); String json = weibo.get("https://api.weibo.com/2/users/domain_show.json", params); return Result.parse(json, com.belerweb.social.weibo.bean.User.class); } /** * 批量获取用户的粉丝数、关注数、微博数 * * 访问级别:普通接口 * * 频次限制:是 * * 文档地址:https://api.weibo.com/2/users/counts.json * * @param source 采用OAuth授权方式不需要此参数,其他授权方式为必填参数,数值为应用的AppKey。 * @param accessToken 采用OAuth授权方式为必填参数,其他授权方式不需要此参数,OAuth授权后获得。 * @param uids 需要获取数据的用户UID,最多不超过100个。 */ public Result counts(String source, String accessToken, List uids) { if (uids == null || uids.size() > 100) { throw new SocialException("需要获取数据的用户UID,必须且最多不超过100个"); } List params = new ArrayList(); weibo.addNotNullParameter(params, "source", source); weibo.addNotNullParameter(params, "access_token", accessToken); weibo.addParameter(params, "uids", StringUtils.join(uids, ",")); String result = weibo.get("https://api.weibo.com/2/users/counts.json", params); return Result.parse(result, UserCounts.class); } } ================================================ FILE: src/main/java/com/belerweb/social/weibo/api/Weibo.java ================================================ package com.belerweb.social.weibo.api; import com.belerweb.social.SDK; public final class Weibo extends SDK { private String clientId; private String clientSecret; private String redirectUri; private OAuth2 oAuth2; private User user; public Weibo(String clientId, String clientSecret) { this.clientId = clientId; this.clientSecret = clientSecret; } public Weibo(String clientId, String clientSecret, String redirectUri) { this(clientId, clientSecret); this.redirectUri = redirectUri; } public OAuth2 getOAuth2() { if (oAuth2 == null) { oAuth2 = new OAuth2(this); } return oAuth2; } public User getUser() { if (user == null) { user = new User(this); } return user; } public String getClientId() { return clientId; } public void setClientId(String clientId) { this.clientId = clientId; } public String getClientSecret() { return clientSecret; } public void setClientSecret(String clientSecret) { this.clientSecret = clientSecret; } public String getRedirectUri() { return redirectUri; } public void setRedirectUri(String redirectUri) { this.redirectUri = redirectUri; } } ================================================ FILE: src/main/java/com/belerweb/social/weibo/bean/AccessToken.java ================================================ package com.belerweb.social.weibo.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; public class AccessToken extends JsonBean { public AccessToken() {} private AccessToken(JSONObject jsonObject) { super(jsonObject); } private String token;// 用于调用access_token,接口获取授权后的access token。 private Long expiresIn;// access_token的生命周期,单位是秒数。 private Long remindIn;// access_token的生命周期(该参数即将废弃,开发者请使用expires_in)。 private String uid;// 当前授权用户的UID。 /** * 用于调用access_token,接口获取授权后的access token。 */ public String getToken() { return token; } public void setToken(String token) { this.token = token; } /** * access_token的生命周期,单位是秒数。 */ public Long getExpiresIn() { return expiresIn; } public void setExpiresIn(Long expiresIn) { this.expiresIn = expiresIn; } /** * access_token的生命周期(该参数即将废弃,开发者请使用expires_in)。 */ public Long getRemindIn() { return remindIn; } public void setRemindIn(Long remindIn) { this.remindIn = remindIn; } /** * 当前授权用户的UID。 */ public String getUid() { return uid; } public void setUid(String uid) { this.uid = uid; } public static AccessToken parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } AccessToken obj = new AccessToken(jsonObject); obj.token = jsonObject.getString("access_token"); obj.expiresIn = Result.parseLong(jsonObject.opt("expires_in")); obj.remindIn = Result.parseLong(jsonObject.opt("remind_in")); obj.uid = Result.toString(jsonObject.get("uid")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weibo/bean/Comment.java ================================================ package com.belerweb.social.weibo.bean; import java.util.Date; import java.util.Locale; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; /** * 评论 * * 文档地址:http://open.weibo.com/wiki/常见返回对象数据结构#.E8.AF.84.E8.AE.BA.EF.BC.88comment.EF.BC.89 */ public class Comment extends JsonBean { public Comment() {} private Comment(JSONObject jsonObject) { super(jsonObject); } private String id;// 评论的ID private String mid;// 评论的MID private String idstr;// 字符串型的评论ID private Date createdAt;// 评论创建时间 private String text;// 评论的内容 private String source;// 评论的来源 private User user;// 评论作者的用户信息字段 private Status status;// 评论的微博信息字段 private Comment replyComment;// 评论来源评论,当本评论属于对另一评论的回复时返回此字段 /** * 评论的ID */ public String getId() { return id; } public void setId(String id) { this.id = id; } /** * 评论的MID */ public String getMid() { return mid; } public void setMid(String mid) { this.mid = mid; } /** * 字符串型的评论ID */ public String getIdstr() { return idstr; } public void setIdstr(String idstr) { this.idstr = idstr; } /** * 评论创建时间 */ public Date getCreatedAt() { return createdAt; } public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; } /** * 评论的内容 */ public String getText() { return text; } public void setText(String text) { this.text = text; } /** * 评论的来源 */ public String getSource() { return source; } public void setSource(String source) { this.source = source; } /** * 评论作者的用户信息字段 */ public User getUser() { return user; } public void setUser(User user) { this.user = user; } /** * 评论的微博信息字段 */ public Status getStatus() { return status; } public void setStatus(Status status) { this.status = status; } /** * 评论来源评论,当本评论属于对另一评论的回复时返回此字段 */ public Comment getReplyComment() { return replyComment; } public void setReplyComment(Comment replyComment) { this.replyComment = replyComment; } public static Comment parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } Comment obj = new Comment(jsonObject); obj.id = Result.toString(jsonObject.get("id")); obj.mid = Result.toString(jsonObject.opt("mid")); obj.idstr = Result.toString(jsonObject.opt("idstr")); obj.createdAt = Result .parseDate(jsonObject.opt("created_at"), "EEE MMM dd HH:mm:ss Z yyyy", Locale.ENGLISH); obj.text = Result.toString(jsonObject.get("text")); obj.source = Result.toString(jsonObject.opt("source")); obj.user = User.parse(jsonObject.optJSONObject("user")); obj.status = Status.parse(jsonObject); obj.replyComment = Comment.parse(jsonObject.optJSONObject("reply_comment")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weibo/bean/Display.java ================================================ package com.belerweb.social.weibo.bean; /** * 授权页面的终端类型 */ public enum Display { /** * 默认的授权页面,适用于web浏览器。 */ DEFAULT("default"), /** * 移动终端的授权页面,适用于支持html5的手机。注:使用此版授权页请用 https://open.weibo.cn/oauth2/authorize 授权接口 */ MOBILE("mobile"), /** * wap版授权页面,适用于非智能手机。 */ WAP("wap"), /** * 客户端版本授权页面,适用于PC桌面应用。 */ CLIENT("client"), /** * 默认的站内应用授权页,授权后不返回access_token,只刷新站内应用父框架。 */ APPONWEIBO("apponweibo"); private String display; private Display(String display) { this.display = display; } public String value() { return display; } @Override public String toString() { return display; } } ================================================ FILE: src/main/java/com/belerweb/social/weibo/bean/Geo.java ================================================ package com.belerweb.social.weibo.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; /** * 地理信息 * * 文档地址:http://open.weibo.com/wiki/常见返回对象数据结构#.E5.9C.B0.E7.90.86.E4.BF.A1.E6.81.AF.EF.BC.88geo.EF.BC * .89 */ public class Geo extends JsonBean { public Geo() {} private Geo(JSONObject jsonObject) { super(jsonObject); } private Double longitude;// 经度坐标 private Double latitude;// 维度坐标 private String city;// 所在城市的城市代码 private String province;// 所在省份的省份代码 private String cityName;// 所在城市的城市名称 private String provinceName;// 所在省份的省份名称 private String address;// 所在的实际地址,可以为空 private String pinyin;// 地址的汉语拼音,不是所有情况都会返回该字段 private String more;// 更多信息,不是所有情况都会返回该字段 /** * 经度坐标 */ public Double getLongitude() { return longitude; } public void setLongitude(Double longitude) { this.longitude = longitude; } /** * 维度坐标 */ public Double getLatitude() { return latitude; } public void setLatitude(Double latitude) { this.latitude = latitude; } /** * 所在城市的城市代码 */ public String getCity() { return city; } public void setCity(String city) { this.city = city; } /** * 所在省份的省份代码 */ public String getProvince() { return province; } public void setProvince(String province) { this.province = province; } /** * 所在城市的城市名称 */ public String getCityName() { return cityName; } public void setCityName(String cityName) { this.cityName = cityName; } /** * 所在省份的省份名称 */ public String getProvinceName() { return provinceName; } public void setProvinceName(String provinceName) { this.provinceName = provinceName; } /** * 所在的实际地址,可以为空 */ public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } /** * 地址的汉语拼音,不是所有情况都会返回该字段 */ public String getPinyin() { return pinyin; } public void setPinyin(String pinyin) { this.pinyin = pinyin; } /** * 更多信息,不是所有情况都会返回该字段 */ public String getMore() { return more; } public void setMore(String more) { this.more = more; } public static Geo parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } Geo obj = new Geo(jsonObject); obj.longitude = Result.parseDouble(jsonObject.get("longitude")); obj.latitude = Result.parseDouble(jsonObject.get("latitude")); obj.city = Result.toString(jsonObject.opt("city")); obj.province = Result.toString(jsonObject.opt("province")); obj.cityName = Result.toString(jsonObject.opt("city_name")); obj.provinceName = Result.toString(jsonObject.opt("province_name")); obj.address = Result.toString(jsonObject.opt("address")); obj.pinyin = Result.toString(jsonObject.opt("pinyin")); obj.more = Result.toString(jsonObject.opt("more")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weibo/bean/Privacy.java ================================================ package com.belerweb.social.weibo.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; /** * 隐私设置 */ public class Privacy extends JsonBean { public Privacy() {} private Privacy(JSONObject jsonObject) { super(jsonObject); } private Integer comment;// 是否可以评论我的微博,0:所有人、1:关注的人、2:可信用户 private Integer geo;// 是否开启地理信息,0:不开启、1:开启 private Integer message;// 是否可以给我发私信,0:所有人、1:我关注的人、2:可信用户 private Integer realname;// 是否可以通过真名搜索到我,0:不可以、1:可以 private Integer badge;// 勋章是否可见,0:不可见、1:可见 private Integer mobile;// 是否可以通过手机号码搜索到我,0:不可以、1:可以 private Integer webim;// 是否开启webim, 0:不开启、1:开启 /** * 是否可以评论我的微博,0:所有人、1:关注的人、2:可信用户 */ public Integer getComment() { return comment; } public void setComment(Integer comment) { this.comment = comment; } /** * 是否开启地理信息,0:不开启、1:开启 */ public Integer getGeo() { return geo; } public void setGeo(Integer geo) { this.geo = geo; } /** * 是否可以给我发私信,0:所有人、1:我关注的人、2:可信用户 */ public Integer getMessage() { return message; } public void setMessage(Integer message) { this.message = message; } /** * 是否可以通过真名搜索到我,0:不可以、1:可以 */ public Integer getRealname() { return realname; } public void setRealname(Integer realname) { this.realname = realname; } /** * 勋章是否可见,0:不可见、1:可见 */ public Integer getBadge() { return badge; } public void setBadge(Integer badge) { this.badge = badge; } /** * 是否可以通过手机号码搜索到我,0:不可以、1:可以 */ public Integer getMobile() { return mobile; } public void setMobile(Integer mobile) { this.mobile = mobile; } /** * 是否开启webim, 0:不开启、1:开启 */ public Integer getWebim() { return webim; } public void setWebim(Integer webim) { this.webim = webim; } public static Privacy parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } Privacy obj = new Privacy(jsonObject); obj.comment = Result.parseInteger(jsonObject.opt("comment")); obj.geo = Result.parseInteger(jsonObject.opt("geo")); obj.message = Result.parseInteger(jsonObject.opt("message")); obj.realname = Result.parseInteger(jsonObject.opt("realname")); obj.badge = Result.parseInteger(jsonObject.opt("badge")); obj.mobile = Result.parseInteger(jsonObject.opt("mobile")); obj.webim = Result.parseInteger(jsonObject.opt("webim")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weibo/bean/Remind.java ================================================ package com.belerweb.social.weibo.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; /** * 消息未读数 */ public class Remind extends JsonBean { public Remind() {} private Remind(JSONObject jsonObject) { super(jsonObject); } private Integer status;// 新微博未读数 private Integer follower;// 新粉丝数 private Integer cmt;// 新评论数 private Integer dm;// 新私信数 private Integer mentionStatus;// 新提及我的微博数 private Integer mentionCmt;// 新提及我的评论数 private Integer group;// 微群消息未读数 private Integer privateGroup;// 私有微群消息未读数 private Integer notice;// 新通知未读数 private Integer invite;// 新邀请未读数 private Integer badge;// 新勋章数 private Integer photo;// 相册消息未读数 private Integer msgbox;// 消息未读数 /** * 新微博未读数 */ public Integer getStatus() { return status; } public void setStatus(Integer status) { this.status = status; } /** * 新粉丝数 */ public Integer getFollower() { return follower; } public void setFollower(Integer follower) { this.follower = follower; } /** * 新评论数 */ public Integer getCmt() { return cmt; } public void setCmt(Integer cmt) { this.cmt = cmt; } /** * 新私信数 */ public Integer getDm() { return dm; } public void setDm(Integer dm) { this.dm = dm; } /** * 新提及我的微博数 */ public Integer getMentionStatus() { return mentionStatus; } public void setMentionStatus(Integer mentionStatus) { this.mentionStatus = mentionStatus; } /** * 新提及我的评论数 */ public Integer getMentionCmt() { return mentionCmt; } public void setMentionCmt(Integer mentionCmt) { this.mentionCmt = mentionCmt; } /** * 微群消息未读数 */ public Integer getGroup() { return group; } public void setGroup(Integer group) { this.group = group; } /** * 私有微群消息未读数 */ public Integer getPrivateGroup() { return privateGroup; } public void setPrivateGroup(Integer privateGroup) { this.privateGroup = privateGroup; } /** * 新通知未读数 */ public Integer getNotice() { return notice; } public void setNotice(Integer notice) { this.notice = notice; } /** * 新邀请未读数 */ public Integer getInvite() { return invite; } public void setInvite(Integer invite) { this.invite = invite; } /** * 新勋章数 */ public Integer getBadge() { return badge; } public void setBadge(Integer badge) { this.badge = badge; } /** * 相册消息未读数 */ public Integer getPhoto() { return photo; } public void setPhoto(Integer photo) { this.photo = photo; } /** * 消息未读数 */ public Integer getMsgbox() { return msgbox; } public void setMsgbox(Integer msgbox) { this.msgbox = msgbox; } public static Remind parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } Remind obj = new Remind(jsonObject); obj.status = Result.parseInteger(jsonObject.opt("status")); obj.follower = Result.parseInteger(jsonObject.opt("follower")); obj.cmt = Result.parseInteger(jsonObject.opt("cmt")); obj.dm = Result.parseInteger(jsonObject.opt("dm")); obj.mentionStatus = Result.parseInteger(jsonObject.opt("mention_status")); obj.mentionCmt = Result.parseInteger(jsonObject.opt("mention_cmt")); obj.group = Result.parseInteger(jsonObject.opt("group")); obj.privateGroup = Result.parseInteger(jsonObject.opt("private_group")); obj.notice = Result.parseInteger(jsonObject.opt("notice")); obj.invite = Result.parseInteger(jsonObject.opt("invite")); obj.badge = Result.parseInteger(jsonObject.opt("badge")); obj.photo = Result.parseInteger(jsonObject.opt("photo")); obj.msgbox = Result.parseInteger(jsonObject.opt("msgbox")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weibo/bean/Scope.java ================================================ package com.belerweb.social.weibo.bean; /** * scope是OAuth2.0授权机制中authorize接口的一个参数 * * 通过scope,平台将开放更多的微博核心功能给开发者,同时也加强用户隐私保护,提升了用户体验,用户在新OAuth2.0授权页中有权利选择赋予应用的功能。 */ public enum Scope { /** * 请求下列所有scope权限 */ ALL("all"), /** * 用户的联系邮箱 */ EMAIL("email"), /** * 私信发送接口 */ DIRECT_MESSAGES_WRITE("direct_messages_write"), /** * 私信读取接口 */ DIRECT_MESSAGES_READ("direct_messages_read"), /** * 邀请发送接口 */ INVITATION_WRITE("invitation_write"), /** * 好友分组读取接口组 */ FRIENDSHIPS_GROUPS_READ("friendships_groups_read"), /** * 好友分组写入接口组 */ FRIENDSHIPS_GROUPS_WRITE("friendships_groups_write"), /** * 定向微博读取接口组 */ STATUSES_TO_ME_READ("statuses_to_me_read"), /** * 关注应用官方微博,该参数不对应具体接口,只需在应用控制台填写官方帐号即可(默认值是应用开发者帐号) */ FOLLOW_APP_OFFICIAL_MICROBLOG("follow_app_official_microblog"); private String scope; private Scope(String scope) { this.scope = scope; } public String value() { return scope; } @Override public String toString() { return scope; } } ================================================ FILE: src/main/java/com/belerweb/social/weibo/bean/Status.java ================================================ package com.belerweb.social.weibo.bean; import java.util.Date; import java.util.List; import java.util.Locale; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; /** * 微博 * * 文档地址:http://open.weibo.com/wiki/常见返回对象数据结构#.E5.BE.AE.E5.8D.9A.EF.BC.88status.EF.BC.89 */ public class Status extends JsonBean { public Status() {} private Status(JSONObject jsonObject) { super(jsonObject); } private String id;// 微博ID private String mid;// 微博MID private String idstr;// 字符串型的微博ID private Date createdAt;// 微博创建时间 private String text;// 微博信息内容 private String source;// 微博来源 private Boolean favorited;// 是否已收藏 private Boolean truncated;// 是否被截断 private String inReplyToStatusId;// (暂未支持)回复ID private String inReplyToUserId;// 暂未支持)回复人UID private String inReplyToScreenName;// 暂未支持)回复人昵称 private String thumbnailPic;// 缩略图片地址,没有时不返回此字段 private String bmiddlePic;// 中等尺寸图片地址,没有时不返回此字段 private String originalPic;// 原始图片地址,没有时不返回此字段 private Geo geo;// 地理信息字段 private User user;// 微博作者的用户信息字段 private Status retweetedStatus;// 被转发的原微博信息字段,当该微博为转发微博时返回 private Integer repostsCount;// 转发数 private Integer commentsCount;// 评论数 private Integer attitudesCount;// 表态数 private Integer mlevel;// 暂未支持 private Visible visible;// 微博的可见性及指定可见分组信息 private List picUrls;// 微博配图地址。多图时返回多图链接。无配图返回“[]” private List ad;// 微博流内的推广微博ID /** * 微博ID */ public String getId() { return id; } public void setId(String id) { this.id = id; } /** * 微博MID */ public String getMid() { return mid; } public void setMid(String mid) { this.mid = mid; } /** * 字符串型的微博ID */ public String getIdstr() { return idstr; } public void setIdstr(String idstr) { this.idstr = idstr; } /** * 微博创建时间 */ public Date getCreatedAt() { return createdAt; } public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; } /** * 微博信息内容 */ public String getText() { return text; } public void setText(String text) { this.text = text; } /** * 微博来源 */ public String getSource() { return source; } public void setSource(String source) { this.source = source; } /** * 是否已收藏 */ public Boolean getFavorited() { return favorited; } public void setFavorited(Boolean favorited) { this.favorited = favorited; } /** * 是否被截断 */ public Boolean getTruncated() { return truncated; } public void setTruncated(Boolean truncated) { this.truncated = truncated; } /** * (暂未支持)回复ID */ public String getInReplyToStatusId() { return inReplyToStatusId; } public void setInReplyToStatusId(String inReplyToStatusId) { this.inReplyToStatusId = inReplyToStatusId; } /** * (暂未支持)回复人UID */ public String getInReplyToUserId() { return inReplyToUserId; } public void setInReplyToUserId(String inReplyToUserId) { this.inReplyToUserId = inReplyToUserId; } /** * (暂未支持)回复人昵称 */ public String getInReplyToScreenName() { return inReplyToScreenName; } public void setInReplyToScreenName(String inReplyToScreenName) { this.inReplyToScreenName = inReplyToScreenName; } /** * 缩略图片地址,没有时不返回此字段 */ public String getThumbnailPic() { return thumbnailPic; } public void setThumbnailPic(String thumbnailPic) { this.thumbnailPic = thumbnailPic; } /** * 中等尺寸图片地址,没有时不返回此字段 */ public String getBmiddlePic() { return bmiddlePic; } public void setBmiddlePic(String bmiddlePic) { this.bmiddlePic = bmiddlePic; } /** * 原始图片地址,没有时不返回此字段 */ public String getOriginalPic() { return originalPic; } public void setOriginalPic(String originalPic) { this.originalPic = originalPic; } /** * 地理信息字段 */ public Geo getGeo() { return geo; } public void setGeo(Geo geo) { this.geo = geo; } /** * 微博作者的用户信息字段 */ public User getUser() { return user; } public void setUser(User user) { this.user = user; } /** * 被转发的原微博信息字段,当该微博为转发微博时返回 */ public Status getRetweetedStatus() { return retweetedStatus; } public void setRetweetedStatus(Status retweetedStatus) { this.retweetedStatus = retweetedStatus; } /** * 转发数 */ public Integer getRepostsCount() { return repostsCount; } public void setRepostsCount(Integer repostsCount) { this.repostsCount = repostsCount; } /** * 评论数 */ public Integer getCommentsCount() { return commentsCount; } public void setCommentsCount(Integer commentsCount) { this.commentsCount = commentsCount; } /** * 表态数 */ public Integer getAttitudesCount() { return attitudesCount; } public void setAttitudesCount(Integer attitudesCount) { this.attitudesCount = attitudesCount; } /** * 暂未支持 */ public Integer getMlevel() { return mlevel; } public void setMlevel(Integer mlevel) { this.mlevel = mlevel; } /** * 微博的可见性及指定可见分组信息 */ public Visible getVisible() { return visible; } public void setVisible(Visible visible) { this.visible = visible; } /** * 微博配图地址。多图时返回多图链接。无配图返回“[]” */ public List getPicUrls() { return picUrls; } public void setPicUrls(List picUrls) { this.picUrls = picUrls; } /** * 微博流内的推广微博ID */ public List getAd() { return ad; } public void setAd(List ad) { this.ad = ad; } public static Status parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } Status obj = new Status(jsonObject); obj.id = Result.toString(jsonObject.get("id")); obj.mid = Result.toString(jsonObject.opt("mid")); obj.idstr = Result.toString(jsonObject.opt("idstr")); obj.createdAt = Result .parseDate(jsonObject.opt("created_at"), "EEE MMM dd HH:mm:ss Z yyyy", Locale.ENGLISH); obj.text = Result.toString(jsonObject.get("text")); obj.source = Result.toString(jsonObject.opt("source")); obj.favorited = Result.parseBoolean(jsonObject.opt("favorited")); obj.truncated = Result.parseBoolean(jsonObject.opt("truncated")); obj.inReplyToStatusId = Result.toString(jsonObject.opt("in_reply_to_status_id")); obj.inReplyToUserId = Result.toString(jsonObject.opt("in_reply_to_user_id")); obj.inReplyToScreenName = Result.toString(jsonObject.opt("in_reply_to_screen_name")); obj.thumbnailPic = Result.toString(jsonObject.opt("thumbnail_pic")); obj.bmiddlePic = Result.toString(jsonObject.opt("bmiddle_pic")); obj.originalPic = Result.toString(jsonObject.opt("original_pic")); obj.geo = Geo.parse(jsonObject.optJSONObject("geo")); obj.user = User.parse(jsonObject.optJSONObject("user")); obj.retweetedStatus = Status.parse(jsonObject.optJSONObject("retweeted_status")); obj.repostsCount = Result.parseInteger(jsonObject.opt("reposts_count")); obj.commentsCount = Result.parseInteger(jsonObject.opt("comments_count")); obj.attitudesCount = Result.parseInteger(jsonObject.opt("attitudes_count")); obj.mlevel = Result.parseInteger(jsonObject.opt("mlevel")); obj.visible = Visible.parse(jsonObject.optJSONObject("visible")); obj.picUrls = Result.parse(jsonObject.optJSONArray("pic_urls"), String.class); obj.ad = Result.parse(jsonObject.optJSONArray("ad"), String.class); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weibo/bean/TokenInfo.java ================================================ package com.belerweb.social.weibo.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; public class TokenInfo extends JsonBean { public TokenInfo() {} private TokenInfo(JSONObject jsonObject) { super(jsonObject); } private String uid; private String appkey;// access_token所属的应用appkey。 private String scope;// 用户授权的scope权限。 private Long createAt;// access_token的创建时间,从1970年到创建时间的秒数。 private Long expireIn;// access_token的剩余时间,单位是秒数。 /** * 授权用户的uid。 */ public String getUid() { return uid; } public void setUid(String uid) { this.uid = uid; } /** * access_token所属的应用appkey。 */ public String getAppkey() { return appkey; } public void setAppkey(String appkey) { this.appkey = appkey; } /** * 用户授权的scope权限。 */ public String getScope() { return scope; } public void setScope(String scope) { this.scope = scope; } /** * access_token的创建时间,从1970年到创建时间的秒数。 */ public Long getCreateAt() { return createAt; } public void setCreateAt(Long createAt) { this.createAt = createAt; } /** * access_token的剩余时间,单位是秒数。 */ public Long getExpireIn() { return expireIn; } public void setExpireIn(Long expireIn) { this.expireIn = expireIn; } public static TokenInfo parse(JSONObject jsonObject) { TokenInfo obj = new TokenInfo(jsonObject); obj.uid = Result.toString(jsonObject.get("uid")); obj.appkey = Result.toString(jsonObject.opt("appkey")); obj.scope = Result.toString(jsonObject.opt("scope")); obj.createAt = Result.parseLong(jsonObject.opt("create_at")); obj.expireIn = Result.parseLong(jsonObject.opt("expire_in")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weibo/bean/UrlShort.java ================================================ package com.belerweb.social.weibo.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; /** * 短链 */ public class UrlShort extends JsonBean { public UrlShort() {} private UrlShort(JSONObject jsonObject) { super(jsonObject); } private String urlShort;// 短链接 private String urlLong;// 原始长链接 private Integer type;// 链接的类型,0:普通网页、1:视频、2:音乐、3:活动、5、投票 private Boolean result;// 短链的可用状态,true:可用、false:不可用。 /** * 短链接 */ public String getUrlShort() { return urlShort; } public void setUrlShort(String urlShort) { this.urlShort = urlShort; } /** * 原始长链接 */ public String getUrlLong() { return urlLong; } public void setUrlLong(String urlLong) { this.urlLong = urlLong; } /** * 链接的类型,0:普通网页、1:视频、2:音乐、3:活动、5、投票 */ public Integer getType() { return type; } public void setType(Integer type) { this.type = type; } /** * 短链的可用状态,true:可用、false:不可用。 */ public Boolean getResult() { return result; } public void setResult(Boolean result) { this.result = result; } public static UrlShort parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } UrlShort obj = new UrlShort(jsonObject); obj.urlShort = Result.toString(jsonObject.opt("url_short")); obj.urlLong = Result.toString(jsonObject.opt("url_long")); obj.type = Result.parseInteger(jsonObject.opt("type")); obj.result = Result.parseBoolean(jsonObject.opt("result")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weibo/bean/User.java ================================================ package com.belerweb.social.weibo.bean; import java.util.Date; import java.util.Locale; import org.json.JSONObject; import com.belerweb.social.bean.Gender; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.OnlineStatus; import com.belerweb.social.bean.Result; /** * 用户 * * 文档地址:http://open.weibo.com/wiki/常见返回对象数据结构#.E7.94.A8.E6.88.B7.EF.BC.88user.EF.BC.89 */ public class User extends JsonBean { public User() {} private User(JSONObject jsonObject) { super(jsonObject); } private String id;// 用户UID private String idstr;// 字符串型的用户UID private String screenName;// 用户昵称 private String name;// screenName private Integer province;// 用户所在省级ID private Integer city;// 用户所在城市ID private String location;// 用户所在地 private String description;// 用户个人描述 private String url;// 用户博客地址 private String profileImageUrl;// 用户头像地址,50×50像素 private String profileUrl;// 用户的微博统一URL地址 private String domain;// 用户的个性化域名 private String weihao;// 用户的微号 private Gender gender;// 性别 private Integer followersCount;// 粉丝数 private Integer friendsCount;// 关注数 private Integer statusesCount;// 微博数 private Integer favouritesCount;// 收藏数 private Date createdAt;// 用户创建(注册)时间 private Boolean following;// 暂未支持 private Boolean allowAllActMsg;// 是否允许所有人给我发私信 private Boolean geoEnabled;// 是否允许标识用户的地理位置 private Boolean verified;// 是否是微博认证用户,即加V用户 private Integer verifiedType;// 暂未支持 private String remark;// 用户备注信息,只有在查询用户关系时才返回此字段 private Status status;// 用户的最近一条微博信息字段 详细 private Boolean allowAllComment;// 是否允许所有人对我的微博进行评论 private String avatarLarge;// 用户大头像地址 private String verifiedReason;// 认证原因 private Boolean followMe;// 该用户是否关注当前登录用户 private OnlineStatus onlineStatus;// 用户的在线状态 private Integer biFollowersCount;// 用户的互粉数 private String lang;// 用户当前的语言版本,zh-cn:简体中文,zh-tw:繁体中文,en:英语 /** * 用户UID */ public String getId() { return id; } public void setId(String id) { this.id = id; } /** * 字符串型的用户UID */ public String getIdstr() { return idstr; } public void setIdstr(String idstr) { this.idstr = idstr; } /** * 用户昵称 */ public String getScreenName() { return screenName; } public void setScreenName(String screenName) { this.screenName = screenName; } /** * 友好显示名称 */ public String getName() { return name; } public void setName(String name) { this.name = name; } /** * 用户所在省级ID */ public Integer getProvince() { return province; } public void setProvince(Integer province) { this.province = province; } /** * 用户所在城市ID */ public Integer getCity() { return city; } public void setCity(Integer city) { this.city = city; } /** * 用户所在地 */ public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } /** * 用户个人描述 */ public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } /** * 用户博客地址 */ public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } /** * 用户头像地址,50×50像素 */ public String getProfileImageUrl() { return profileImageUrl; } public void setProfileImageUrl(String profileImageUrl) { this.profileImageUrl = profileImageUrl; } /** * 用户的微博统一URL地址 */ public String getProfileUrl() { return profileUrl; } public void setProfileUrl(String profileUrl) { this.profileUrl = profileUrl; } /** * 用户的个性化域名 */ public String getDomain() { return domain; } public void setDomain(String domain) { this.domain = domain; } /** * 用户的微号 */ public String getWeihao() { return weihao; } public void setWeihao(String weihao) { this.weihao = weihao; } /** * 性别 */ public Gender getGender() { return gender; } public void setGender(Gender gender) { this.gender = gender; } /** * 粉丝数 */ public Integer getFollowersCount() { return followersCount; } public void setFollowersCount(Integer followersCount) { this.followersCount = followersCount; } /** * 关注数 */ public Integer getFriendsCount() { return friendsCount; } public void setFriendsCount(Integer friendsCount) { this.friendsCount = friendsCount; } /** * 微博数 */ public Integer getStatusesCount() { return statusesCount; } public void setStatusesCount(Integer statusesCount) { this.statusesCount = statusesCount; } /** * 收藏数 */ public Integer getFavouritesCount() { return favouritesCount; } public void setFavouritesCount(Integer favouritesCount) { this.favouritesCount = favouritesCount; } /** * 用户创建(注册)时间 */ public Date getCreatedAt() { return createdAt; } public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; } /** * 暂未支持 */ public Boolean getFollowing() { return following; } public void setFollowing(Boolean following) { this.following = following; } /** * 是否允许所有人给我发私信 */ public Boolean getAllowAllActMsg() { return allowAllActMsg; } public void setAllowAllActMsg(Boolean allowAllActMsg) { this.allowAllActMsg = allowAllActMsg; } /** * 是否允许标识用户的地理位置 */ public Boolean getGeoEnabled() { return geoEnabled; } public void setGeoEnabled(Boolean geoEnabled) { this.geoEnabled = geoEnabled; } /** * 是否是微博认证用户,即加V用户 */ public Boolean getVerified() { return verified; } public void setVerified(Boolean verified) { this.verified = verified; } /** * 暂未支持 */ public Integer getVerifiedType() { return verifiedType; } public void setVerifiedType(Integer verifiedType) { this.verifiedType = verifiedType; } /** * 用户备注信息,只有在查询用户关系时才返回此字段 */ public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } /** * 用户的最近一条微博信息字段 详细 */ public Status getStatus() { return status; } public void setStatus(Status status) { this.status = status; } /** * 是否允许所有人对我的微博进行评论 */ public Boolean getAllowAllComment() { return allowAllComment; } public void setAllowAllComment(Boolean allowAllComment) { this.allowAllComment = allowAllComment; } /** * 用户大头像地址 */ public String getAvatarLarge() { return avatarLarge; } public void setAvatarLarge(String avatarLarge) { this.avatarLarge = avatarLarge; } /** * 认证原因 */ public String getVerifiedReason() { return verifiedReason; } public void setVerifiedReason(String verifiedReason) { this.verifiedReason = verifiedReason; } /** * 该用户是否关注当前登录用户 */ public Boolean getFollowMe() { return followMe; } public void setFollowMe(Boolean followMe) { this.followMe = followMe; } /** * 用户的在线状态 */ public OnlineStatus getOnlineStatus() { return onlineStatus; } public void setOnlineStatus(OnlineStatus onlineStatus) { this.onlineStatus = onlineStatus; } /** * 用户的互粉数 */ public Integer getBiFollowersCount() { return biFollowersCount; } public void setBiFollowersCount(Integer biFollowersCount) { this.biFollowersCount = biFollowersCount; } /** * 用户当前的语言版本,zh-cn:简体中文,zh-tw:繁体中文,en:英语 */ public String getLang() { return lang; } public void setLang(String lang) { this.lang = lang; } public static User parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } User obj = new User(jsonObject); obj.id = Result.toString(jsonObject.get("id")); obj.idstr = Result.toString(jsonObject.opt("idstr")); obj.screenName = Result.toString(jsonObject.opt("screen_name")); obj.name = Result.toString(jsonObject.opt("name")); obj.province = Result.parseInteger(jsonObject.opt("province")); obj.city = Result.parseInteger(jsonObject.opt("city")); obj.location = Result.toString(jsonObject.opt("location")); obj.description = Result.toString(jsonObject.opt("description")); obj.url = Result.toString(jsonObject.opt("url")); obj.profileImageUrl = Result.toString(jsonObject.opt("profile_image_url")); obj.profileUrl = Result.toString(jsonObject.opt("profile_url")); obj.domain = Result.toString(jsonObject.opt("domain")); obj.weihao = Result.toString(jsonObject.opt("weihao")); obj.gender = Gender.parse(jsonObject.optString("gender", null)); obj.followersCount = Result.parseInteger(jsonObject.opt("followers_count")); obj.friendsCount = Result.parseInteger(jsonObject.opt("friends_count")); obj.statusesCount = Result.parseInteger(jsonObject.opt("statuses_count")); obj.favouritesCount = Result.parseInteger(jsonObject.opt("favourites_count")); obj.createdAt = Result .parseDate(jsonObject.opt("created_at"), "EEE MMM dd HH:mm:ss Z yyyy", Locale.ENGLISH); obj.following = Result.parseBoolean(jsonObject.opt("following")); obj.allowAllActMsg = Result.parseBoolean(jsonObject.opt("allow_all_act_msg")); obj.geoEnabled = Result.parseBoolean(jsonObject.opt("geo_enabled")); obj.verified = Result.parseBoolean(jsonObject.opt("verified")); obj.verifiedType = Result.parseInteger(jsonObject.opt("verified_type")); obj.remark = Result.toString(jsonObject.opt("remark")); obj.status = Status.parse(jsonObject.optJSONObject("status")); obj.allowAllComment = Result.parseBoolean(jsonObject.opt("allow_all_comment")); obj.avatarLarge = Result.toString(jsonObject.opt("avatar_large")); obj.verifiedReason = Result.toString(jsonObject.opt("verified_reason")); obj.followMe = Result.parseBoolean(jsonObject.opt("follow_me")); obj.onlineStatus = OnlineStatus.parse(Result.parseInteger(jsonObject.optString("online_status"))); obj.biFollowersCount = Result.parseInteger(jsonObject.opt("bi_followers_count")); obj.lang = Result.toString(jsonObject.opt("lang")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weibo/bean/UserCounts.java ================================================ package com.belerweb.social.weibo.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; /** * 用户的粉丝数、关注数、微博数 */ public class UserCounts extends JsonBean { public UserCounts() {} private UserCounts(JSONObject jsonObject) { super(jsonObject); } private String id;// 微博ID private Integer followersCount;// 粉丝数 private Integer friendsCount;// 关注数 private Integer statusesCount;// 微博数 private Integer privateFriendsCount;// 暂未支持 /** * 微博ID */ public String getId() { return id; } public void setId(String id) { this.id = id; } /** * 粉丝数 */ public Integer getFollowersCount() { return followersCount; } public void setFollowersCount(Integer followersCount) { this.followersCount = followersCount; } /** * 关注数 */ public Integer getFriendsCount() { return friendsCount; } public void setFriendsCount(Integer friendsCount) { this.friendsCount = friendsCount; } /** * 微博数 */ public Integer getStatusesCount() { return statusesCount; } public void setStatusesCount(Integer statusesCount) { this.statusesCount = statusesCount; } /** * 暂未支持 */ public Integer getPrivateFriendsCount() { return privateFriendsCount; } public void setPrivateFriendsCount(Integer privateFriendsCount) { this.privateFriendsCount = privateFriendsCount; } public static UserCounts parse(JSONObject jsonObject) { UserCounts obj = new UserCounts(jsonObject); obj.id = Result.toString(jsonObject.get("id")); obj.followersCount = Result.parseInteger(jsonObject.opt("followers_count")); obj.friendsCount = Result.parseInteger(jsonObject.opt("friends_count")); obj.statusesCount = Result.parseInteger(jsonObject.opt("statuses_count")); obj.privateFriendsCount = Result.parseInteger(jsonObject.opt("private_friends_count")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weibo/bean/Visible.java ================================================ package com.belerweb.social.weibo.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; /** * 微博的可见性及指定可见分组信息 */ public class Visible extends JsonBean { public Visible() {} private Visible(JSONObject jsonObject) { super(jsonObject); } private Integer type;// 0:普通微博,1:私密微博,3:指定分组微博,4:密友微博 private Integer listId;// 分组的组号 /** * 0:普通微博,1:私密微博,3:指定分组微博,4:密友微博 */ public Integer getType() { return type; } public void setType(Integer type) { this.type = type; } /** * 分组的组号 */ public Integer getListId() { return listId; } public void setListId(Integer listId) { this.listId = listId; } public static Visible parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } Visible obj = new Visible(jsonObject); obj.type = Result.parseInteger(jsonObject.opt("type")); obj.listId = Result.parseInteger(jsonObject.opt("list_id")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/api/Group.java ================================================ package com.belerweb.social.weixin.api; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; import org.apache.http.NameValuePair; import org.apache.http.entity.StringEntity; import org.json.JSONObject; import com.belerweb.social.API; import com.belerweb.social.bean.Error; import com.belerweb.social.bean.Result; import com.belerweb.social.exception.SocialException; /** * 分组管理接口 * * 文档地址:http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口 */ public class Group extends API { protected Group(Weixin weixin) { super(weixin); } /** * 查询分组 */ public Result> get() { return get(weixin.getAccessToken().getToken()); } /** * 查询分组 * * @param accessToken 调用接口凭证 */ public Result> get(String accessToken) { List params = new ArrayList(); weixin.addParameter(params, "access_token", accessToken); String json = weixin.get("https://api.weixin.qq.com/cgi-bin/groups/get", params); JSONObject jsonObject = new JSONObject(json); Error error = Error.parse(jsonObject); if (error == null) { List groups = Result.parse(jsonObject.getJSONArray("groups"), com.belerweb.social.weixin.bean.Group.class); return new Result>(groups); } return new Result>(error); } /** * 创建分组 * * @param name 分组名字(30个字符以内) */ public Result create(String name) { return create(weixin.getAccessToken().getToken(), name); } /** * 创建分组 * * 一个公众账号,最多支持创建500个分组。 * * @param accessToken 调用接口凭证 * @param name 分组名字(30个字符以内) */ public Result create(String accessToken, String name) { JSONObject request = new JSONObject(); JSONObject group = new JSONObject(); group.put("name", name); request.put("group", group); try { String json = weixin.post( "https://api.weixin.qq.com/cgi-bin/groups/create?access_token=" + accessToken, new StringEntity(request.toString())); JSONObject jsonObject = new JSONObject(json); Error error = Error.parse(jsonObject); if (error != null) { return new Result(error); } return new Result( com.belerweb.social.weixin.bean.Group.parse(jsonObject.getJSONObject("group"))); } catch (UnsupportedEncodingException e) { throw new SocialException(e); } } /** * 修改分组名 * * @param id 分组id,由微信分配 * @param name 分组名字(30个字符以内) */ public Result update(String id, String name) { return update(weixin.getAccessToken().getToken(), id, name); } /** * 修改分组名 * * @param accessToken 调用接口凭证 * @param id 分组id,由微信分配 * @param name 分组名字(30个字符以内) */ public Result update(String accessToken, String id, String name) { JSONObject request = new JSONObject(); JSONObject group = new JSONObject(); group.put("id", id); group.put("name", name); request.put("group", group); try { String json = weixin.post( "https://api.weixin.qq.com/cgi-bin/groups/update?access_token=" + accessToken, new StringEntity(request.toString())); return Result.parse(json, Error.class); } catch (UnsupportedEncodingException e) { throw new SocialException(e); } } /** * 移动用户分组 * * @param openId 用户唯一标识符 * @param groupId 分组id */ public Result move(String openId, String groupId) { return move(weixin.getAccessToken().getToken(), openId, groupId); } /** * 移动用户分组 * * @param accessToken 调用接口凭证 * @param openId 用户唯一标识符 * @param groupId 分组id */ public Result move(String accessToken, String openId, String groupId) { JSONObject request = new JSONObject(); request.put("openid", openId); request.put("to_groupid", groupId); try { String json = weixin.post("https://api.weixin.qq.com/cgi-bin/groups/members/update?access_token=" + accessToken, new StringEntity(request.toString())); return Result.parse(json, Error.class); } catch (UnsupportedEncodingException e) { throw new SocialException(e); } } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/api/Media.java ================================================ package com.belerweb.social.weixin.api; import java.io.IOException; import org.apache.commons.io.IOUtils; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.json.JSONObject; import com.belerweb.social.API; import com.belerweb.social.bean.Error; import com.belerweb.social.bean.Result; import com.belerweb.social.exception.SocialException; import com.belerweb.social.http.Http; import com.belerweb.social.weixin.bean.MediaType; /** * 上传下载多媒体文件 * * 文档地址:http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件 * * 公众号在使用接口时,对多媒体文件、多媒体消息的获取和调用等操作,是通过media_id来进行的。通过本接口,公众号可以上传或下载多媒体文件。但请注意,每个多媒体文件(media_id)会在上传、 * 用户发送到微信服务器3天后自动删除,以节省服务器资源。 * */ public class Media extends API { protected Media(Weixin weixin) { super(weixin); } /** * 上传多媒体文件,将把上传成功后的mediaId设置回传入的media中 * * @param type 媒体文件类型 * @param media form-data中媒体文件标识,有filename、filelength、content-type等信息 */ public Result upload(MediaType type, com.belerweb.social.weixin.bean.Media media) { return upload(weixin.getAccessToken().getToken(), type, media); } /** * 上传多媒体文件,将把上传成功后的mediaId设置回传入的media中 * * 图片(image): 256K,支持JPG格式 * * 语音(voice):256K,播放长度不超过60s,支持AMR与MP3格式 * * 视频(video):2MB,支持MP4格式 * * 缩略图(thumb):64KB,支持JPG格式 * * @param accessToken 调用接口凭证 * @param type 媒体文件类型 * @param media form-data中媒体文件标识,有filename、filelength、content-type等信息 */ public Result upload(String accessToken, MediaType type, com.belerweb.social.weixin.bean.Media media) { String url = "http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token=" + accessToken + "&type=" + type.value(); HttpPost request = new HttpPost(url); MultipartEntityBuilder builder = MultipartEntityBuilder.create().addBinaryBody("media", media.getContent(), ContentType.create(media.getContentType()), media.getName()); request.setEntity(builder.build()); try { HttpResponse response = Http.CLIENT.execute(request); String json = IOUtils.toString(response.getEntity().getContent()); JSONObject jsonObject = new JSONObject(json); Error error = Error.parse(jsonObject); if (error != null) { return new Result(error); } media.setId(jsonObject.getString("media_id")); return new Result(media); } catch (ClientProtocolException e) { throw new SocialException(e); } catch (IOException e) { throw new SocialException(e); } } /** * 下载多媒体文件 * * @param mediaId 媒体文件ID */ public Result get(String mediaId) { return get(weixin.getAccessToken().getToken(), mediaId); } /** * 下载多媒体文件 * * 公众号可调用本接口来获取多媒体文件。请注意,调用该接口需http协议。 * * @param accessToken 调用接口凭证 * @param mediaId 媒体文件ID */ public Result get(String accessToken, String mediaId) { String url = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=" + accessToken + "&media_id=" + mediaId; try { HttpResponse response = Http.CLIENT.execute(new HttpGet(url)); Header disposition = response.getFirstHeader("Content-disposition"); HttpEntity entity = response.getEntity(); if (disposition == null) { return new Result(Error.parse(new JSONObject(IOUtils .toString(entity.getContent())))); } String fileName = disposition.getValue(); fileName = fileName.substring(fileName.indexOf("\"") + 1, fileName.lastIndexOf("\"")); com.belerweb.social.weixin.bean.Media media = new com.belerweb.social.weixin.bean.Media(); media.setId(mediaId); media.setName(fileName); media.setContentType(entity.getContentType().getValue()); media.setContent(IOUtils.toByteArray(entity.getContent())); return new Result(media); } catch (ClientProtocolException e) { throw new SocialException(e); } catch (IOException e) { throw new SocialException(e); } } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/api/Menu.java ================================================ package com.belerweb.social.weixin.api; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; import org.apache.http.NameValuePair; import org.apache.http.entity.StringEntity; import org.json.JSONArray; import org.json.JSONObject; import com.belerweb.social.API; import com.belerweb.social.bean.Error; import com.belerweb.social.bean.Result; import com.belerweb.social.exception.SocialException; import com.belerweb.social.weixin.bean.MenuType; /** * 自定义菜单接口 * * 文档地址:http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单创建接口 */ public class Menu extends API { protected Menu(Weixin weixin) { super(weixin); } /** * 自定义菜单创建接口 * * @param menus 菜单 */ public Result create(List menus) { return create(weixin.getAccessToken().getToken(), menus); } /** * 自定义菜单创建接口 *

* 注意:只有菜单类型为 MenuType.VIEW 时才需要url属性,其它情况都是使用key *

* * @param accessToken 调用接口凭证 * @param menus 菜单 */ public Result create(String accessToken, List menus) { JSONArray menuArray = new JSONArray(); for (com.belerweb.social.weixin.bean.Menu menu : menus) { JSONObject obj = new JSONObject(); MenuType type = menu.getType(); obj.put("name", menu.getName()); if (type != null) { obj.put("type", type.value()); if (type == MenuType.VIEW) { obj.put("url", menu.getUrl()); } else { obj.put("key", menu.getKey()); } } List subs = menu.getSubs(); if (subs != null) { JSONArray _menuArray = new JSONArray(); for (com.belerweb.social.weixin.bean.Menu _menu : subs) { JSONObject _obj = new JSONObject(); MenuType _type = _menu.getType(); _obj.put("name", _menu.getName()); if (_type != null) { _obj.put("type", _type.value()); if (_type == MenuType.VIEW) { _obj.put("url", _menu.getUrl()); } else { _obj.put("key", _menu.getKey()); } } _menuArray.put(_obj); } obj.put("sub_button", _menuArray); } menuArray.put(obj); } JSONObject request = new JSONObject(); request.put("button", menuArray); try { String json = weixin.post("https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + accessToken, new StringEntity(request.toString(), "UTF-8")); return Result.parse(json, Error.class); } catch (UnsupportedEncodingException e) { throw new SocialException(e); } } /** * 自定义菜单查询接口 */ public Result> get() { return get(weixin.getAccessToken().getToken()); } /** * 自定义菜单查询接口 * * @param accessToken 调用接口凭证 */ public Result> get(String accessToken) { List params = new ArrayList(); weixin.addParameter(params, "access_token", accessToken); String json = weixin.get("https://api.weixin.qq.com/cgi-bin/menu/get", params); JSONObject jsonObject = new JSONObject(json); Error error = Error.parse(jsonObject); if (error != null) { return new Result>(error); } List menus = new ArrayList(); JSONObject menu = jsonObject.optJSONObject("menu"); if (menu != null) { menus = Result.parse(menu.optJSONArray("button"), com.belerweb.social.weixin.bean.Menu.class); } return new Result>(menus); } /** * 自定义菜单删除接口 */ public Result delete() { return delete(weixin.getAccessToken().getToken()); } /** * 自定义菜单删除接口 * * @param accessToken 调用接口凭证 */ public Result delete(String accessToken) { List params = new ArrayList(); weixin.addParameter(params, "access_token", accessToken); String json = weixin.get("https://api.weixin.qq.com/cgi-bin/menu/delete", params); return Result.parse(json, Error.class); } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/api/OAuth2.java ================================================ package com.belerweb.social.weixin.api; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.apache.http.NameValuePair; import com.belerweb.social.API; import com.belerweb.social.bean.Result; import com.belerweb.social.weixin.bean.AccessToken; import com.belerweb.social.weixin.bean.Scope; public final class OAuth2 extends API { OAuth2(Weixin weixin) { super(weixin); } /** * 获取Authorization Code * * 从 {@link Weixin} 从获取clientId,redirectUri,responseType为code ,其余参数默认 * * @see OAuth2#authorize(String, String, String, String, String, Boolean) */ public String authorize() { return authorize(false); } /** * 获取Authorization Code * * 从 {@link Weixin} 从获取clientId,redirectUri,responseType为code ,其余参数默认 * * @see OAuth2#authorize(String, String, String, String, String, Boolean) */ public String authorize(Boolean wechatRedirect) { return authorize(weixin.getRedirectUri(), wechatRedirect); } /** * 获取Authorization Code * * 从 {@link Weixin} 从获取clientId,responseType为code ,scope为snsapi_userinfo,其余参数默认 * * @see OAuth2#authorize(String, String, String, String, String, Boolean) */ public String authorize(String redirectUri) { return authorize(redirectUri, false); } /** * 获取Authorization Code * * 从 {@link Weixin} 从获取clientId,responseType为code ,scope为snsapi_userinfo,其余参数默认 * * @see OAuth2#authorize(String, String, String, String, String, Boolean) */ public String authorize(String redirectUri, Boolean wechatRedirect) { return authorize(weixin.getAppId(), redirectUri, "code", Scope.SNSAPI_USERINFO, null, wechatRedirect); } /** * 获取Authorization Code * * 文档地址:http://mp.weixin.qq.com/wiki/index.php?title=网页授权获取用户基本信息 * * @param appId 必须,公众号的唯一标识 * @param redirectUri 必须,授权后重定向的回调链接地址 * @param responseType 必须,返回类型,请填写code * @param scope 必须,应用授权作用域 * @param state 重定向后会带上state参数,开发者可以填写任意参数值 * @param wechatRedirect 直接在微信打开链接,可以不填此参数。做页面302重定向时候,必须带此参数 */ public String authorize(String appId, String redirectUri, String responseType, Scope scope, String state, Boolean wechatRedirect) { List params = new ArrayList(); weixin.addParameter(params, "appid", appId); weixin.addParameter(params, "redirect_uri", redirectUri); weixin.addParameter(params, "response_type", responseType); weixin.addParameter(params, "scope", scope); weixin.addNotNullParameter(params, "state", state); String result = "https://open.weixin.qq.com/connect/oauth2/authorize?" + StringUtils.join(params, "&"); if (Boolean.TRUE.equals(wechatRedirect)) { result = result + "#wechat_redirect"; } return result; } /** * 获取网站应用登录的Authorization Code,调用顺序如下: * *
   *    Weixin weixin = new Weixin(weixinAppId, weixinAppSecret);
   *    weixin.setRedirectUri(weixinAppRedirect);
   *    weixin.getOAuth2().authorizeLogin(state);        
   * 
* *

* 文档地址:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify * =1&id=open1419316505&token=&lang=zh_CN * * @param state 重定向后会带上state参数,开发者可以填写任意参数值 */ public String authorizeLogin(String state) { List params = new ArrayList(); weixin.addParameter(params, "appid", weixin.getAppId()); String redirect_uri = ""; try { redirect_uri = URLEncoder.encode(weixin.getRedirectUri(), "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } weixin.addParameter(params, "redirect_uri", redirect_uri); weixin.addParameter(params, "response_type", "code"); weixin.addParameter(params, "scope", Scope.SNSAPI_LOGIN); weixin.addNotNullParameter(params, "state", state); String result = "https://open.weixin.qq.com/connect/qrconnect?" + StringUtils.join(params, "&") + "#wechat_redirect"; return result; } /** * 通过code换取网页授权access_token。从{@link Weixin}中获取appId和secret。 * * @param code 填写第一步获取的code参数 */ public Result accessToken(String code) { return accessToken(weixin.getAppId(), weixin.getSecret(), code); } /** * 通过code换取网页授权access_token。grantType值为authorization_code。 * * @param appId 公众号的唯一标识 * @param secret 公众号的appsecret * @param code 填写第一步获取的code参数 */ public Result accessToken(String appId, String secret, String code) { return accessToken(appId, secret, code, "authorization_code"); } /** * 通过code换取网页授权access_token * * @param appId 公众号的唯一标识 * @param secret 公众号的appsecret * @param code 填写第一步获取的code参数 * @param grantType 填写为authorization_code */ public Result accessToken(String appId, String secret, String code, String grantType) { List params = new ArrayList(); weixin.addParameter(params, "appid", appId); weixin.addParameter(params, "secret", secret); weixin.addParameter(params, "code", code); weixin.addParameter(params, "grant_type", grantType); // String result = weixin.post("https://api.weixin.qq.com/sns/oauth2/access_token", params); String result = weixin.get("https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appId + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code"); return Result.parse(result, AccessToken.class); } /** * 刷新access_token(如果需要)。从{@link Weixin}中获取appId * * @param refreshToken 填写通过access_token获取到的refresh_token参数 */ public Result refreshAccessToken(String refreshToken) { return refreshAccessToken(weixin.getAppId(), "refresh_token", refreshToken); } /** * 刷新access_token(如果需要) * * @param appId 公众号的唯一标识 * @param refreshToken 填写通过access_token获取到的refresh_token参数 */ public Result refreshAccessToken(String appId, String refreshToken) { return refreshAccessToken(appId, "refresh_token", refreshToken); } /** * 刷新access_token(如果需要) * * @param appId 公众号的唯一标识 * @param grantType 填写为refresh_token * @param refreshToken 填写通过access_token获取到的refresh_token参数 */ public Result refreshAccessToken(String appId, String grantType, String refreshToken) { List params = new ArrayList(); weixin.addParameter(params, "appid", appId); weixin.addParameter(params, "grant_type", grantType); weixin.addParameter(params, "refresh_token", refreshToken); String result = weixin.get("https://api.weixin.qq.com/sns/oauth2/refresh_token", params); return Result.parse(result, AccessToken.class); } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/api/User.java ================================================ package com.belerweb.social.weixin.api; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.apache.http.NameValuePair; import com.belerweb.social.API; import com.belerweb.social.bean.Result; import com.belerweb.social.weixin.bean.GetFollowersResult; /** * 网页授权获取用户基本信息 * * 如果用户在微信中(Web微信除外)访问公众号的第三方网页,公众号开发者可以通过此接口获取当前用户基本信息(包括昵称、性别、城市、国家)。利用用户信息,可以实现体验优化、用户来源统计、帐号绑定、 * 用户身份鉴权等功能 * 。请注意,“获取用户基本信息接口是在用户和公众号产生消息交互时,才能根据用户OpenID获取用户基本信息,而网页授权的方式获取用户基本信息,则无需消息交互,只是用户进入到公众号的网页 * ,就可弹出请求用户授权的界面,用户授权后,就可获得其基本信息(此过程甚至不需要用户已经关注公众号。)” * * 本接口是通过OAuth2.0来完成网页授权的,是安全可靠的,关于OAuth2.0的详细介绍,可以参考OAuth2.0协议标准。在微信公众号请求用户网页授权之前, * 开发者需要先到公众平台网站中配置授权回调域名。 */ public class User extends API { protected User(Weixin weixin) { super(weixin); } /** * 拉取用户信息(需scope为 snsapi_userinfo)。适用于网页授权的用户。 * * 如果网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_token和openid拉取用户信息了。 * * @param accessToken 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同 * @param openId 用户的唯一标识 */ public Result snsapiUserInfo(String accessToken, String openId) { List params = new ArrayList(); weixin.addParameter(params, "access_token", accessToken); weixin.addParameter(params, "openid", openId); String json = weixin.get("https://api.weixin.qq.com/sns/userinfo", params); return Result.parse(json, com.belerweb.social.weixin.bean.User.class); } /** * 获取用户基本信息,适用于已关注公众帐号的用户。 * * 在关注者与公众号产生消息交互后,公众号可获得关注者的OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的。对于不同公众号,同一用户的openid不同)。 * 公众号可通过本接口来根据OpenID获取用户基本信息,包括昵称、头像、性别、所在城市、语言和关注时间。 * * @param accessToken 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同 * @param openId 用户的唯一标识 */ public Result userInfo(String accessToken, String openId) { List params = new ArrayList(); weixin.addParameter(params, "access_token", accessToken); weixin.addParameter(params, "openid", openId); String json = weixin.get("https://api.weixin.qq.com/cgi-bin/user/info", params); return Result.parse(json, com.belerweb.social.weixin.bean.User.class); } /** * 获取所欲关注者列表,包含用户详细信息,该接口采用循环多次获取用户详细信息的方式。如果关注者太多可能会很慢。还会超过微信API调用次数限制。请谨慎调用。建议只在第一次同步关注着信息时调用。 */ public Result> getFollowUsers() { return getFollowUsers(weixin.getAccessToken().getToken()); } /** * 获取所欲关注者列表,包含用户详细信息,该接口采用循环多次获取用户详细信息的方式。如果关注者太多可能会很慢。还会超过微信API调用次数限制。请谨慎调用。建议只在第一次同步关注着信息时调用。 * * @param accessToken 调用接口凭证 */ public Result> getFollowUsers(String accessToken) { List users = new ArrayList(); Result followersResult = getFollowers(accessToken); if (followersResult.success()) { for (String openId : followersResult.getResult().getOpenIds()) { Result userResult = userInfo(accessToken, openId); if (userResult.success()) { users.add(userResult.getResult()); } else { return new Result>(userResult.getError()); } } return new Result>(users); } return new Result>(followersResult.getError()); } /** * 获取所欲关注者列表 */ public Result getFollowers() { return getFollowers(weixin.getAccessToken().getToken()); } /** * 获取所欲关注者列表 * * @param accessToken 调用接口凭证 */ public Result getFollowers(String accessToken) { GetFollowersResult result = new GetFollowersResult(); List openIds = new ArrayList(); Result followers = getFollowers(accessToken, null); while (followers.success()) { for (String openId : followers.getResult().getOpenIds()) { openIds.add(openId); } String nextOpenid = followers.getResult().getNextOpenid(); if (StringUtils.isBlank(nextOpenid) || followers.getResult().getTotal() == openIds.size()) { break; } followers = getFollowers(accessToken, nextOpenid); } if (!followers.success()) { return new Result(followers.getError()); } result.setTotal(openIds.size()); result.setCount(openIds.size()); result.setOpenIds(openIds); return new Result(result); } /** * 获取关注者列表 * * 公众号可通过本接口来获取帐号的关注者列表,关注者列表由一串OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的)组成。一次拉取调用最多拉取10000个关注者的OpenID * ,可以通过多次拉取的方式来满足需求。 * * 文档地址:http://mp.weixin.qq.com/wiki/index.php?title=获取关注者列表 * * @param accessToken 调用接口凭证 * @param openId 第一个拉取的OPENID,不填默认从头开始拉取 */ public Result getFollowers(String accessToken, String openId) { List params = new ArrayList(); weixin.addParameter(params, "access_token", accessToken); weixin.addNotNullParameter(params, "next_openid", openId); String json = weixin.get("https://api.weixin.qq.com/cgi-bin/user/get", params); return Result.parse(json, GetFollowersResult.class); } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/api/Weixin.java ================================================ package com.belerweb.social.weixin.api; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang.StringUtils; import org.apache.http.NameValuePair; import org.apache.http.entity.StringEntity; import org.json.JSONObject; import com.belerweb.social.SDK; import com.belerweb.social.bean.Error; import com.belerweb.social.bean.Result; import com.belerweb.social.exception.SocialException; import com.belerweb.social.weixin.bean.AccessToken; import com.belerweb.social.weixin.bean.ApiTicket; import com.belerweb.social.weixin.bean.JSApiTicket; import com.belerweb.social.weixin.bean.Message; import com.belerweb.social.weixin.bean.QRCreation; import com.belerweb.social.weixin.bean.QRTicket; import com.belerweb.social.weixin.bean.QRType; /** * 微信SDK */ public final class Weixin extends SDK { private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); private String appId; private String secret; private String redirectUri; private String token; private OAuth2 oAuth2; private User user; private Group group; private Media media; private Menu menu; private AccessToken accessToken; private Date accessTokenTime; private JSApiTicket jsApiTicket; private Date jsApiTicketTime; private ApiTicket apiTicket; private Date apiTicketTime; /** * 只传入token实例化微信SDK,适合于只开发基于微信基础接口的被动接受消息类应用,如智能应答机器人。不推荐适用。 * * @param token 在公众平台网站的高级功能 – * 开发模式页,点击“成为开发者”按钮,填写URL和Token,其中URL是开发者用来接收微信服务器数据的接口URL。Token可由开发者可以任意填写 * ,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)。 */ public Weixin(String token) { super(DEFAULT_CHARSET); this.token = token; } /** * 通过appId和secret实例化微信SDK,适合于只开发基于微信高级接口的OAuth2应用,如客服功能。 * * @param appId 公众号的唯一标识 * @param secret 公众号的appsecret */ public Weixin(String appId, String secret) { super(DEFAULT_CHARSET); this.appId = appId; this.secret = secret; } /** * 通过token、appId和secret实例化微信SDK,支持微信基础和高级接口。推荐适用 * * @param appId 公众号的唯一标识 * @param secret 公众号的appsecret * @param token 在公众平台网站的高级功能 – * 开发模式页,点击“成为开发者”按钮,填写URL和Token,其中URL是开发者用来接收微信服务器数据的接口URL。Token可由开发者可以任意填写 * ,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)。 */ public Weixin(String appId, String secret, String token) { this(appId, secret); this.token = token; } public Weixin(String appid, String secret, String redirectUri, String token) { this(appid, secret, token); this.redirectUri = redirectUri; } /** * 验证消息真实性 * * 文档地址:http://mp.weixin.qq.com/wiki/index.php?title=验证消息真实性 * * @param signature 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 * @param timestamp 时间戳 * @param nonce 随机数 * @return 消息有效返回true,否则返回false */ public boolean validate(String signature, String timestamp, String nonce) { String[] chars = new String[] {token, timestamp, nonce,}; Arrays.sort(chars); String sha1 = DigestUtils.shaHex(StringUtils.join(chars)); if (sha1.equals(signature)) { return true; } return false; } /** * 签名传入的参数,按照字典顺序排序后连接起来sha1 文档地址:卡券扩展字段及签名生成算法 * * @param args * @return */ public String signature(String... args) { Arrays.sort(args); return DigestUtils.shaHex(StringUtils.join(args)); } /** * jsapi_ticket签名算法 * * 文档地址:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD.951- * JS-SDK.E4.BD.BF.E7.94.A8.E6.9D.83.E9.99.90.E7.AD.BE.E5.90.8D.E7.AE.97.E6.B3.95 * * @param url 网页的url地址不包括 {@code #} 后面的参数(不包含锚的值).但是包括所有的请求参数 * @param timestamp 时间戳 * @param nonce 随机数 * @return 返回签名后的字符串 */ public String jsapiSignature(String url, long timestamp, String nonce) { StringBuilder content = new StringBuilder(); content.append("jsapi_ticket=").append(getJsApiTicket().getTicket()); content.append("&noncestr=").append(nonce); content.append("×tamp=").append(timestamp); content.append("&url=").append(url); return DigestUtils.shaHex(content.toString()); } public String getAppId() { return appId; } public void setAppId(String appId) { this.appId = appId; } public String getSecret() { return secret; } public void setSecret(String secret) { this.secret = secret; } public String getRedirectUri() { return redirectUri; } public void setRedirectUri(String redirectUri) { this.redirectUri = redirectUri; } /** * 获取access token * * access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token。正常情况下access_token有效期为7200秒, * 重复获取将导致上次获取的access_token失效。 * * 公众号可以使用AppID和AppSecret调用本接口来获取access_token。AppID和AppSecret可在开发模式中获得(需要已经成为开发者,且帐号没有异常状态)。 */ public synchronized AccessToken getAccessToken() { if (accessToken == null || accessTokenTime == null || (new Date().getTime() - accessTokenTime.getTime()) / 1000 > accessToken.getExpiresIn()) { List params = new ArrayList(); addParameter(params, "appid", appId); addParameter(params, "secret", secret); addParameter(params, "grant_type", "client_credential"); String json = get("https://api.weixin.qq.com/cgi-bin/token?" + StringUtils.join(params, "&"), params); Result result = Result.parse(json, AccessToken.class); if (result.success()) { accessToken = result.getResult(); accessTokenTime = new Date(); } } return accessToken; } /** * api_ticket 是用于调用微信卡券JS API的临时票据,有效期为7200 秒,通过access_token 来获取。 * * 文档地址:获取api_ticket * * 由于获取api_ticket 的api 调用次数非常有限,频繁刷新api_ticket 会导致api调用受限,影响自身业务,开发者需在自己的服务存储与更新api_ticket。 */ public synchronized ApiTicket getApiTicket() { if (apiTicket == null || apiTicketTime == null || (new Date().getTime() - apiTicketTime.getTime()) / 1000 > apiTicket.getExpiresIn()) { List params = new ArrayList(); addParameter(params, "access_token", getAccessToken().getToken()); addParameter(params, "type", "wx_card"); String json = get("https://api.weixin.qq.com/cgi-bin/ticket/getticket?" + StringUtils.join(params, "&"), params); Result result = Result.parse(json, ApiTicket.class); if (result.success()) { apiTicket = result.getResult(); apiTicketTime = new Date(); } } return apiTicket; } /** * jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。 * * 文档地址:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD.951- * JS-SDK.E4.BD.BF.E7.94.A8.E6.9D.83.E9.99.90.E7.AD.BE.E5.90.8D.E7.AE.97.E6.B3.95 * * 由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。 */ public synchronized JSApiTicket getJsApiTicket() { if (jsApiTicket == null || jsApiTicketTime == null || (new Date().getTime() - jsApiTicketTime.getTime()) / 1000 > jsApiTicket.getExpiresIn()) { List params = new ArrayList(); addParameter(params, "access_token", getAccessToken().getToken()); addParameter(params, "type", "jsapi"); String json = get("https://api.weixin.qq.com/cgi-bin/ticket/getticket?" + StringUtils.join(params, "&"), params); Result result = Result.parse(json, JSApiTicket.class); if (result.success()) { jsApiTicket = result.getResult(); jsApiTicketTime = new Date(); } } return jsApiTicket; } /** * 自动获取accessToken并创建二维码ticket * * 每次创建二维码ticket需要提供一个开发者自行设定的参数(scene_id) * * 文档地址:http://mp.weixin.qq.com/wiki/index.php?title=生成带参数的二维码 * * @param type 二维码类型,QR_SCENE为临时,QR_LIMIT_SCENE为永久 * @param sceneId 场景值ID,临时二维码时为32位整型,永久二维码时最大值为1000 */ public Result createQR(QRType type, Integer sceneId) { return createQR(getAccessToken().getToken(), type, sceneId); } /** * 创建二维码ticket * * 每次创建二维码ticket需要提供一个开发者自行设定的参数(scene_id) * * 文档地址:http://mp.weixin.qq.com/wiki/index.php?title=生成带参数的二维码 * * @param accessToken access_token是公众号的全局唯一票据 * @param type 二维码类型,QR_SCENE为临时,QR_LIMIT_SCENE为永久 * @param sceneId 场景值ID,临时二维码时为32位整型,永久二维码时最大值为1000 */ public Result createQR(String accessToken, QRType type, Integer sceneId) { QRCreation request = new QRCreation(); request.setType(type); request.setSceneId(sceneId); try { String json = post("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + accessToken, new StringEntity(request.toString())); return Result.parse(json, QRTicket.class); } catch (UnsupportedEncodingException e) { throw new SocialException(e); } } /** * 发送客服消息 * * 当用户主动发消息给公众号的时候,微信将会把消息数据推送给开发者,开发者在一段时间内(目前为24小时)可以调用客服消息接口,通过POST一个JSON数据包来发送消息给普通用户, * 在24小时内不限制发送次数。此接口主要用于客服等有人工消息处理环节的功能,方便开发者为用户提供更加优质的服务。 * * 文档地址:http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息 * * @param message 消息 */ public Result sendCustomMessage(Message message) { return sendCustomMessage(getAccessToken().getToken(), message); } /** * 发送客服消息 * * 当用户主动发消息给公众号的时候,微信将会把消息数据推送给开发者,开发者在一段时间内(目前为24小时)可以调用客服消息接口,通过POST一个JSON数据包来发送消息给普通用户, * 在24小时内不限制发送次数。此接口主要用于客服等有人工消息处理环节的功能,方便开发者为用户提供更加优质的服务。 * * 文档地址:http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息 * * @param accessToken access_token是公众号的全局唯一票据 * @param message 消息 */ public Result sendCustomMessage(String accessToken, Message message) { try { // {"errcode":0,"errmsg":"ok"} // {"errcode":45015,"errmsg":"response out of time limit"} String json = post("https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + accessToken, new StringEntity(message.toJSON(), "UTF-8")); return new Result(Error.parse(new JSONObject(json))); } catch (UnsupportedEncodingException e) { throw new SocialException(e); } } /** * 发送模板消息 * *

* 为了保证用户不受到骚扰,在开发者出现需要主动提醒、通知用户时,才允许开发者在公众平台网站中模板消息库中选择模板,选择后获得模板ID,再根据模板ID向用户主动推送提醒、通知消息。 *

*

* 模板消息调用时主要需要模板ID和模板中各参数的赋值内容。请注意: *

    *
  1. 模板中参数内容必须以".DATA"结尾,否则视为保留字;
  2. *
  3. 模板保留符号"{{ }}"
  4. *
*

* 具体调用方法 *

* 第一步:获取模板ID
* 通过在模板消息功能的模板库中使用需要的模板,可以获得模板ID。 *

*

* 第二步:请求接口 *

* * 文档地址:https://mp.weixin.qq.com/advanced/tmplmsg?action=faq&lang=zh_CN * * @param message 消息 */ public Result sendTemplateMessage(Message message) { return sendTemplateMessage(getAccessToken().getToken(), message); } /** * 发送模板消息 * *

* 为了保证用户不受到骚扰,在开发者出现需要主动提醒、通知用户时,才允许开发者在公众平台网站中模板消息库中选择模板,选择后获得模板ID,再根据模板ID向用户主动推送提醒、通知消息。 *

*

* 模板消息调用时主要需要模板ID和模板中各参数的赋值内容。请注意: *

    *
  1. 模板中参数内容必须以".DATA"结尾,否则视为保留字;
  2. *
  3. 模板保留符号"{{ }}"
  4. *
*

* 具体调用方法 *

* 第一步:获取模板ID
* 通过在模板消息功能的模板库中使用需要的模板,可以获得模板ID。 *

*

* 第二步:请求接口 *

* * 文档地址:https://mp.weixin.qq.com/advanced/tmplmsg?action=faq&lang=zh_CN * * @param accessToken access_token是公众号的全局唯一票据 * @param message 消息 */ public Result sendTemplateMessage(String accessToken, Message message) { try { String json = post("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken, new StringEntity(message.toJSON(), "UTF-8")); return new Result(Error.parse(new JSONObject(json))); } catch (UnsupportedEncodingException e) { throw new SocialException(e); } } /** * 在公众平台网站的高级功能 – * 开发模式页,点击“成为开发者”按钮,填写URL和Token,其中URL是开发者用来接收微信服务器数据的接口URL。Token可由开发者可以任意填写,用作生成签名( * 该Token会和接口URL中包含的Token进行比对,从而验证安全性) */ public String getToken() { return token; } public void setToken(String token) { this.token = token; } public OAuth2 getOAuth2() { if (oAuth2 == null) { oAuth2 = new OAuth2(this); } return oAuth2; } public User getUser() { if (user == null) { user = new User(this); } return user; } public Group getGroup() { if (group == null) { group = new Group(this); } return group; } public Media getMedia() { if (media == null) { media = new Media(this); } return media; } public Menu getMenu() { if (menu == null) { menu = new Menu(this); } return menu; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/AccessToken.java ================================================ package com.belerweb.social.weixin.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; /** * 网页授权接口调用凭证 */ public class AccessToken extends JsonBean { public AccessToken() {} private AccessToken(JSONObject jsonObject) { super(jsonObject); } private String token;// 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同 private Long expiresIn;// access_token接口调用凭证超时时间,单位(秒) private String refreshToken;// 用户刷新access_token private String openId;// 用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID private Scope scope;// 用户授权的作用域,使用逗号(,)分隔 private String unionid;// 当且仅当该网站应用已获得该用户的userinfo授权时,才会出现该字段 /** * 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同 */ public String getToken() { return token; } public void setToken(String token) { this.token = token; } /** * access_token接口调用凭证超时时间,单位(秒) */ public Long getExpiresIn() { return expiresIn; } public void setExpiresIn(Long expiresIn) { this.expiresIn = expiresIn; } /** * 用户刷新access_token */ public String getRefreshToken() { return refreshToken; } public void setRefreshToken(String refreshToken) { this.refreshToken = refreshToken; } /** * 用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID */ public String getOpenId() { return openId; } public void setOpenId(String openId) { this.openId = openId; } /** * 用户授权的作用域,使用逗号(,)分隔 */ public Scope getScope() { return scope; } public void setScope(Scope scope) { this.scope = scope; } public String getUnionid() { return unionid; } public void setUnionid(String unionid) { this.unionid = unionid; } public static AccessToken parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } AccessToken obj = new AccessToken(jsonObject); obj.token = jsonObject.getString("access_token"); obj.openId = Result.toString(jsonObject.opt("openid")); obj.expiresIn = Result.parseLong(jsonObject.opt("expires_in")); obj.refreshToken = Result.toString(jsonObject.opt("refresh_token")); obj.scope = Scope.parse(jsonObject.opt("scope")); obj.unionid = Result.toString(jsonObject.opt("unionid")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/ApiTicket.java ================================================ package com.belerweb.social.weixin.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; /** * api_ticket 是用于调用微信卡券JS API的临时票据,有效期为7200 秒,通过access_token 来获取。 */ public class ApiTicket extends JsonBean { public ApiTicket() {} private ApiTicket(JSONObject jsonObject) { super(jsonObject); } private String ticket;// ticket是公众号用于调用微信卡券JS API的临时票据 private Long expiresIn;// api_ticket接口调用凭证超时时间,单位(秒) public String getTicket() { return ticket; } public void setTicket(String ticket) { this.ticket = ticket; } public Long getExpiresIn() { return expiresIn; } public void setExpiresIn(Long expiresIn) { this.expiresIn = expiresIn; } public static ApiTicket parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } ApiTicket obj = new ApiTicket(jsonObject); obj.ticket = jsonObject.getString("ticket"); obj.expiresIn = Result.parseLong(jsonObject.opt("expires_in")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/Article.java ================================================ package com.belerweb.social.weixin.bean; /** * 图文 */ public class Article { private String title;// 图文消息标题 private String description;// 图文消息描述 private String picUrl;// 图片链接,支持JPG、PNG格式,较好的效果为大图360*200,小图200*200 private String url;// 点击图文消息跳转链接 /** * 图文消息标题 */ public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } /** * 图文消息描述 */ public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } /** * 图片链接,支持JPG、PNG格式,较好的效果为大图360*200,小图200*200 */ public String getPicUrl() { return picUrl; } public void setPicUrl(String picUrl) { this.picUrl = picUrl; } /** * 点击图文消息跳转链接 */ public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/EventType.java ================================================ package com.belerweb.social.weixin.bean; /** * 事件类型 */ public enum EventType { /** * 订阅 */ SUBSCRIBE("subscribe"), /** * 取消订阅 */ UNSUBSCRIBE("unsubscribe"), /** * 扫描二维码:用户已关注时的事件推送 */ SCAN("SCAN"), /** * 上报地理位置事件 */ LOCATION("LOCATION"), /** * 点击链接事件 */ VIEW("VIEW"), /** * 自定义菜单事件 */ CLICK("CLICK"); private String type; private EventType(String type) { this.type = type; } public String value() { return type; } @Override public String toString() { return type; } public static EventType parse(Object val) { if (SUBSCRIBE.type.equals(val)) { return SUBSCRIBE; } if (UNSUBSCRIBE.type.equals(val)) { return UNSUBSCRIBE; } if (SCAN.type.equals(val)) { return SCAN; } if (LOCATION.type.equals(val)) { return LOCATION; } if (CLICK.type.equals(val)) { return CLICK; } if (VIEW.type.equals(val)) { return VIEW; } return null; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/GetFollowersResult.java ================================================ package com.belerweb.social.weixin.bean; import java.util.ArrayList; import java.util.List; import org.json.JSONArray; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; /** * 获取关注者列表结果 */ public class GetFollowersResult extends JsonBean { public GetFollowersResult() {} private GetFollowersResult(JSONObject jsonObject) { super(jsonObject); } private Integer total;// 关注该公众账号的总用户数 private Integer count;// 拉取的OPENID个数,最大值为10000 private List openIds;// OPENID的列表 private String nextOpenid;// 拉取列表的后一个用户的OPENID /** * 关注该公众账号的总用户数 */ public Integer getTotal() { return total; } public void setTotal(Integer total) { this.total = total; } /** * 拉取的OPENID个数,最大值为10000 */ public Integer getCount() { return count; } public void setCount(Integer count) { this.count = count; } /** * OPENID的列表 */ public List getOpenIds() { return openIds; } public void setOpenIds(List openIds) { this.openIds = openIds; } /** * 拉取列表的后一个用户的OPENID */ public String getNextOpenid() { return nextOpenid; } public void setNextOpenid(String nextOpenid) { this.nextOpenid = nextOpenid; } public static GetFollowersResult parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } GetFollowersResult obj = new GetFollowersResult(jsonObject); obj.total = Result.parseInteger(jsonObject.get("total")); obj.count = Result.parseInteger(jsonObject.get("count")); obj.nextOpenid = Result.toString(jsonObject.opt("next_openid")); JSONArray openIdArray = jsonObject.getJSONObject("data").getJSONArray("openid"); List openIds = new ArrayList(); for (int i = 0; i < openIdArray.length(); i++) { openIds.add(openIdArray.getString(i)); } obj.openIds = openIds; return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/Group.java ================================================ package com.belerweb.social.weixin.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; /** * 分组 */ public class Group extends JsonBean { public Group() {} private Group(JSONObject jsonObject) { super(jsonObject); } private String id;// 分组id,由微信分配 private String name;// 分组名字,UTF8编码 private Integer count;// 分组内用户数量 /** * 分组id,由微信分配 */ public String getId() { return id; } public void setId(String id) { this.id = id; } /** * 分组名字,UTF8编码 */ public String getName() { return name; } public void setName(String name) { this.name = name; } /** * 分组内用户数量 */ public Integer getCount() { return count; } public void setCount(Integer count) { this.count = count; } public static Group parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } Group obj = new Group(jsonObject); obj.id = Result.toString(jsonObject.get("id")); obj.name = Result.toString(jsonObject.get("name")); obj.count = Result.parseInteger(jsonObject.opt("count")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/JSApiTicket.java ================================================ package com.belerweb.social.weixin.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; /** * jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。 */ public class JSApiTicket extends JsonBean { public JSApiTicket() {} private JSApiTicket(JSONObject jsonObject) { super(jsonObject); } private String ticket;// ticket是公众号用于调用微信JS接口的临时票据 private Long expiresIn;// jsapi_ticket接口调用凭证超时时间,单位(秒) public String getTicket() { return ticket; } public void setTicket(String ticket) { this.ticket = ticket; } public Long getExpiresIn() { return expiresIn; } public void setExpiresIn(Long expiresIn) { this.expiresIn = expiresIn; } public static JSApiTicket parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } JSApiTicket obj = new JSApiTicket(jsonObject); obj.ticket = jsonObject.getString("ticket"); obj.expiresIn = Result.parseLong(jsonObject.opt("expires_in")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/Media.java ================================================ package com.belerweb.social.weixin.bean; /** * 媒体文件 */ public class Media { private String id; private String name; private String contentType; private byte[] content; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getContentType() { return contentType; } public void setContentType(String contentType) { this.contentType = contentType; } public byte[] getContent() { return content; } public void setContent(byte[] content) { this.content = content; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/MediaType.java ================================================ package com.belerweb.social.weixin.bean; /** * 媒体文件类型 */ public enum MediaType { /** * 图片 */ IMAGE("image"), /** * 语音 */ VOICE("voice"), /** * 语音 */ VOICE_AMR("voice"), /** * 语音 */ VOICE_MP3("voice"), /** * 视频 */ VIDEO("video"), /** * 缩略图 */ THUMB("thumb"); private String type; private MediaType(String type) { this.type = type; } public String value() { return type; } @Override public String toString() { return type; } public String contentType() { if (this == IMAGE || this == THUMB) { return "image/jpeg"; } if (this == VOICE || this == VOICE_AMR) { return "audio/amr"; } if (this == VOICE_MP3) { return "audio/mp3"; } if (this == VIDEO) { return "audio/mp4"; } return null; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/Menu.java ================================================ package com.belerweb.social.weixin.bean; import java.util.List; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; /** * 自定义菜单 */ public class Menu extends JsonBean { public Menu() {} private Menu(JSONObject jsonObject) { super(jsonObject); } private MenuType type; private String key; private String url; private String name; private List subs; public MenuType getType() { return type; } public void setType(MenuType type) { this.type = type; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List getSubs() { return subs; } public void setSubs(List subs) { this.subs = subs; } public static Menu parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } Menu obj = new Menu(jsonObject); obj.name = Result.toString(jsonObject.get("name")); obj.key = Result.toString(jsonObject.opt("key")); obj.url = Result.toString(jsonObject.opt("url")); obj.type = MenuType.parse(jsonObject.opt("type")); obj.subs = Result.parse(jsonObject.optJSONArray("sub_button"), Menu.class); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/MenuType.java ================================================ package com.belerweb.social.weixin.bean; /** * 自定义菜单类型 */ public enum MenuType { /** * 用户点击click类型按钮后,微信服务器会通过消息接口推送消息类型为event的结构给开发者(参考消息接口指南),并且带上按钮中开发者填写的key值, * 开发者可以通过自定义的key值与用户进行交互; */ CLICK("click"), /** * 用户点击view类型按钮后,微信客户端将会打开开发者在按钮中填写的url值 (即网页链接),达到打开网页的目的,建议与网页授权获取用户基本信息接口结合,获得用户的登入个人信息。 */ VIEW("view"), /** * 扫码推事件,用户点击按钮后,微信客户端将调起扫一扫工具,完成扫码操作后显示扫描结果(如果是URL,将进入URL),且会将扫码的结果传给开发者,开发者可以下发消息。 */ SCANCODE_PUSH("scancode_push"), /** * 扫码推事件且弹出“消息接收中”提示框,用户点击按钮后,微信客户端将调起扫一扫工具,完成扫码操作后,将扫码的结果传给开发者,同时收起扫一扫工具, * 然后弹出“消息接收中”提示框,随后可能会收到开发者下发的消息。 */ SCANCODE_WAITMSG("scancode_waitmsg"), /** * 弹出系统拍照发图,用户点击按钮后,微信客户端将调起系统相机,完成拍照操作后,会将拍摄的相片发送给开发者,并推送事件给开发者,同时收起系统相机,随后可能会收到开发者下发的消息。 */ PIC_SYSPHOTO("pic_sysphoto"), /** * 弹出拍照或者相册发图,用户点击按钮后,微信客户端将弹出选择器供用户选择“拍照”或者“从手机相册选择”。用户选择后即走其他两种流程。 */ PIC_PHOTO_OR_ALBUM("pic_photo_or_album"), /** * 弹出微信相册发图器,用户点击按钮后,微信客户端将调起微信相册,完成选择操作后,将选择的相片发送给开发者的服务器, 并推送事件给开发者,同时收起相册,随后可能会收到开发者下发的消息。 */ PIC_WEIXIN("pic_weixin"), /** * 弹出地理位置选择器,用户点击按钮后,微信客户端将调起地理位置选择工具,完成选择操作后,将选择的地理位置发送给开发者的服务器, 同时收起位置选择工具,随后可能会收到开发者下发的消息。 */ LOCATION_SELECT("location_select"), ; private String type; private MenuType(String type) { this.type = type; } public String value() { return type; } @Override public String toString() { return type; } public static MenuType parse(Object val) { if (CLICK.type.equals(val)) { return CLICK; } if (VIEW.type.equals(val)) { return VIEW; } return null; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/Message.java ================================================ package com.belerweb.social.weixin.bean; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.commons.lang.StringUtils; import org.json.JSONArray; import org.json.JSONObject; import org.json.XML; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; /** * 普通消息 */ public class Message extends JsonBean { public Message() {} public Message(MsgType msgType) { this.msgType = msgType; } private Message(JSONObject jsonObject) { super(jsonObject); } private Long msgId;// 消息id private String fromUser;// 发送方帐号(一个OpenID) private String toUser;// 开发者微信号 private Date createTime;// 消息创建时间 private MsgType msgType;// 消息类型 private String content;// 文本消息内容 private String mediaId;// 消息媒体id,可以调用多媒体文件下载接口拉取数据。 private String picUrl;// 图片链接 private VoiceType voiceType;// 语音格式 private String recognition;// 语音识别结果 private String thumbMediaId;// 视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。 private Double lon;// 地理位置经度 private Double lat;// 地理位置纬度 private Integer scale;// 地图缩放大小 private String label;// 地理位置信息 private String title;// 消息标题 private String description;// 消息描述 private String url;// 消息链接 private String musicUrl;// 音乐链接 private String hqMusicUrl;// 高质量音乐链接,WIFI环境优先使用该链接播放音乐 private EventType eventType;// 事件类型 private String eventKey;// 事件KEY值 private String ticket;// 二维码的ticket,可用来换取二维码图片 private Double precision;// 地理位置精度 private List
articles;// 多条图文消息信息,默认第一个item为大图 /** * 模板消息特有的属性 */ private String templateId;// 模板消息的id private String topColor;// 模板消息头部的颜色 eg:#FF0000 private List variables;// 模板消息的变量 /** * 消息id */ public Long getMsgId() { return msgId; } public void setMsgId(Long msgId) { this.msgId = msgId; } /** * 发送方帐号 */ public String getFromUser() { return fromUser; } public void setFromUser(String fromUser) { this.fromUser = fromUser; } /** * 接受方帐号 */ public String getToUser() { return toUser; } public void setToUser(String toUser) { this.toUser = toUser; } /** * 消息创建时间 */ public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } /** * 消息类型 */ public MsgType getMsgType() { return msgType; } public void setMsgType(MsgType msgType) { this.msgType = msgType; } /** * 文本消息内容 */ public String getContent() { return content; } public void setContent(String content) { this.content = content; } /** * 图片/语音/视频特有:消息媒体id,可以调用多媒体文件下载接口拉取数据。 */ public String getMediaId() { return mediaId; } public void setMediaId(String mediaId) { this.mediaId = mediaId; } /** * 图片消息特有:图片链接 */ public String getPicUrl() { return picUrl; } public void setPicUrl(String picUrl) { this.picUrl = picUrl; } /** * 语音消息特有:语音格式 */ public VoiceType getVoiceType() { return voiceType; } public void setVoiceType(VoiceType voiceType) { this.voiceType = voiceType; } /** * 语音消息特有: 语音识别结果,UTF8编码,只有在开启语音识别后才有此结果 */ public String getRecognition() { return recognition; } public void setRecognition(String recognition) { this.recognition = recognition; } /** * 视频消息/音乐消息特有:视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。 */ public String getThumbMediaId() { return thumbMediaId; } public void setThumbMediaId(String thumbMediaId) { this.thumbMediaId = thumbMediaId; } /** * 位置消息特有:地理位置经度 */ public Double getLon() { return lon; } public void setLon(Double lon) { this.lon = lon; } /** * 位置消息特有:地理位置纬度 */ public Double getLat() { return lat; } public void setLat(Double lat) { this.lat = lat; } /** * 位置消息特有: 地图缩放大小 */ public Integer getScale() { return scale; } public void setScale(Integer scale) { this.scale = scale; } /** * 位置消息特有: 地理位置信息 */ public String getLabel() { return label; } public void setLabel(String label) { this.label = label; } /** * 链接消息/音乐消息特有:消息标题 */ public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } /** * 链接消息/音乐消息特有:消息描述 */ public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } /** * 链接消息特有:消息链接 */ public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } /** * 音乐链接 */ public String getMusicUrl() { return musicUrl; } public void setMusicUrl(String musicUrl) { this.musicUrl = musicUrl; } /** * 高质量音乐链接,WIFI环境优先使用该链接播放音乐 */ public String getHqMusicUrl() { return hqMusicUrl; } public void setHqMusicUrl(String hqMusicUrl) { this.hqMusicUrl = hqMusicUrl; } /** * 事件特有:事件类型 */ public EventType getEventType() { return eventType; } public void setEventType(EventType eventType) { this.eventType = eventType; } /** * 事件KEY值,QR扫描/自定义菜单时特有 */ public String getEventKey() { return eventKey; } public void setEventKey(String eventKey) { this.eventKey = eventKey; } /** * 扫描二维码,用户已关注时的事件推送特有 *

* 二维码的ticket,可用来换取二维码图片 */ public String getTicket() { return ticket; } public void setTicket(String ticket) { this.ticket = ticket; } /** * 上报地理位置事件特有: 地理位置精度 */ public Double getPrecision() { return precision; } public void setPrecision(Double precision) { this.precision = precision; } /** * 多条图文消息信息,默认第一个item为大图 */ public List

getArticles() { return articles; } public void setArticles(List
articles) { this.articles = articles; } /** * 模板消息id */ public String getTemplateId() { return templateId; } public void setTemplateId(String templateId) { this.templateId = templateId; } /** * 模板消息头部颜色 */ public String getTopColor() { return topColor; } public void setTopColor(String topColor) { this.topColor = topColor; } /** * 模板消息变量 * * @return */ public List getVariables() { if (variables == null) { variables = new ArrayList(); } return variables; } public void setVariables(List variables) { this.variables = variables; } public Message addVariable(Variable variable) { getVariables().add(variable); return this; } /** * 将Message转换成XML格式,用于发送被动响应消息 */ public String toXML() { JSONObject obj = new JSONObject(); obj.put("MsgType", msgType.toString()); obj.put("ToUserName", toUser); obj.put("FromUserName", fromUser); obj.put("CreateTime", (Long) (createTime.getTime() / 1000)); if (msgType == MsgType.TEXT) { obj.put("Content", content); } if (msgType == MsgType.IMAGE) { JSONObject image = new JSONObject(); image.put("MediaId", mediaId); obj.put("Image", image); } if (msgType == MsgType.VOICE) { JSONObject voice = new JSONObject(); voice.put("MediaId", mediaId); obj.put("Voice", voice); } if (msgType == MsgType.VIDEO) { JSONObject video = new JSONObject(); video.put("MediaId", mediaId); video.put("ThumbMediaId", thumbMediaId); obj.put("Video", video); } if (msgType == MsgType.MUSIC) { JSONObject music = new JSONObject(); music.put("Title", title); music.put("Description", description); music.put("MusicURL", musicUrl); music.put("HQMusicUrl", hqMusicUrl); music.put("ThumbMediaId", thumbMediaId); obj.put("Music", music); } if (msgType == MsgType.NEWS) { obj.put("ArticleCount", articles.size()); JSONArray array = new JSONArray(); for (Article article : articles) { JSONObject itemWrapper = new JSONObject(); JSONObject item = new JSONObject(); item.put("Title", article.getTitle()); item.put("Description", article.getDescription()); item.put("PicUrl", article.getPicUrl()); item.put("Url", article.getUrl()); itemWrapper.put("item", item); array.put(itemWrapper); } obj.put("Articles", array); } return XML.toString(obj, "xml").replaceAll("", ""); } /** * 将Message转换成JSON格式,用于发送客服消息 */ public String toJSON() { JSONObject obj = new JSONObject(); obj.put("msgtype", msgType.toString()); obj.put("touser", toUser); if (msgType == MsgType.TEXT) { JSONObject text = new JSONObject(); text.put("content", content); obj.put("text", text); } if (msgType == MsgType.IMAGE) { JSONObject image = new JSONObject(); image.put("media_id", mediaId); obj.put("image", image); } if (msgType == MsgType.VOICE) { JSONObject voice = new JSONObject(); voice.put("media_id", mediaId); obj.put("voice", voice); } if (msgType == MsgType.VIDEO) { JSONObject video = new JSONObject(); video.put("media_id", mediaId); video.put("thumb_media_id", thumbMediaId); obj.put("video", video); } if (msgType == MsgType.MUSIC) { JSONObject music = new JSONObject(); music.put("title", title); music.put("description", description); music.put("musicurl", musicUrl); music.put("hqmusicurl", hqMusicUrl); music.put("thumb_media_id", thumbMediaId); obj.put("music", music); } if (msgType == MsgType.NEWS) { JSONObject news = new JSONObject(); JSONArray array = new JSONArray(); for (Article article : articles) { JSONObject item = new JSONObject(); item.put("title", article.getTitle()); item.put("description", article.getDescription()); item.put("picurl", article.getPicUrl()); item.put("url", article.getUrl()); array.put(item); } news.put("articles", array); obj.put("news", news); } if (msgType == MsgType.TEMPLATE) { obj.put("template_id", templateId); if (StringUtils.isNotBlank(topColor)) { obj.put("topcolor", topColor); } if (StringUtils.isNotBlank(url)) { obj.put("url", url); } JSONObject data = new JSONObject(); for (Variable var : variables) { JSONObject varJson = new JSONObject(); varJson.put("value", var.getValue()); if (StringUtils.isNotBlank(var.getColor())) { varJson.put("color", var.getColor()); } data.put(var.getName(), varJson); } obj.put("data", data); } return obj.toString(); } public static Message parse(String xml) { return parse(XML.toJSONObject(xml).getJSONObject("xml")); } public static Message parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } Message obj = new Message(jsonObject); obj.msgId = Result.parseLong(jsonObject.opt("MsgId")); MsgType type = MsgType.parse(jsonObject.get("MsgType")); obj.msgType = type; obj.createTime = new Date(Result.parseLong(jsonObject.get("CreateTime")) * 1000); obj.fromUser = Result.toString(jsonObject.get("FromUserName")); obj.toUser = Result.toString(jsonObject.get("ToUserName")); if (type == MsgType.TEXT) { obj.content = Result.toString(jsonObject.opt("Content")); } if (type == MsgType.IMAGE) { obj.mediaId = Result.toString(jsonObject.opt("MediaId")); obj.picUrl = Result.toString(jsonObject.opt("PicUrl")); } if (type == MsgType.VOICE) { obj.mediaId = Result.toString(jsonObject.opt("MediaId")); obj.voiceType = VoiceType.parse(jsonObject.opt("Format")); obj.recognition = Result.toString(jsonObject.opt("Recognition")); } if (type == MsgType.VIDEO) { obj.mediaId = Result.toString(jsonObject.opt("MediaId")); obj.thumbMediaId = Result.toString(jsonObject.opt("ThumbMediaId")); } if (type == MsgType.LOCATION) { obj.lon = Result.parseDouble(jsonObject.opt("Location_Y")); obj.lat = Result.parseDouble(jsonObject.opt("Location_X")); obj.scale = Result.parseInteger(jsonObject.opt("Scale")); obj.label = Result.toString(jsonObject.opt("Label")); } if (type == MsgType.LINK) { obj.title = Result.toString(jsonObject.opt("Title")); obj.description = Result.toString(jsonObject.opt("Description")); obj.url = Result.toString(jsonObject.opt("Url")); } if (type == MsgType.EVENT) { EventType eventType = EventType.parse(jsonObject.get("Event")); obj.eventType = eventType; if (eventType == EventType.SUBSCRIBE) { // Do nothing when direct follow // When scan QR to follow obj.eventKey = Result.toString(jsonObject.opt("EventKey")); obj.ticket = Result.toString(jsonObject.opt("Ticket")); } if (eventType == EventType.UNSUBSCRIBE) { // Do nothing } if (eventType == EventType.SCAN) { obj.eventKey = Result.toString(jsonObject.opt("EventKey")); obj.ticket = Result.toString(jsonObject.opt("Ticket")); } if (eventType == EventType.LOCATION) { obj.lon = Result.parseDouble(jsonObject.opt("Longitude")); obj.lat = Result.parseDouble(jsonObject.opt("Latitude")); } if (eventType == EventType.CLICK) { obj.eventKey = Result.toString(jsonObject.opt("EventKey")); } if (eventType == EventType.VIEW) { obj.eventKey = Result.toString(jsonObject.opt("EventKey")); obj.url = obj.eventKey; } } return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/MsgType.java ================================================ package com.belerweb.social.weixin.bean; /** * 普通消息 */ public enum MsgType { /** * 文本消息 */ TEXT("text"), /** * 图片消息 */ IMAGE("image"), /** * 语音消息 */ VOICE("voice"), /** * 视频消息 */ VIDEO("video"), /** * 视频消息 */ SHORTVIDEO("shortvideo"), /** * 音乐消息 */ MUSIC("music"), /** * 地理位置消息 */ LOCATION("location"), /** * 链接消息 */ LINK("link"), /** * 事件 */ EVENT("event"), /** * 图文消息 */ NEWS("news"), /** * 模板消息 */ TEMPLATE("template"), /** * 多客服接入 */ TRANSFER_CUSTOMER_SERVICE("transfer_customer_service"); private String type; private MsgType(String type) { this.type = type; } public String value() { return type; } @Override public String toString() { return type; } public static MsgType parse(Object val) { if (TEXT.type.equals(val)) { return TEXT; } if (IMAGE.type.equals(val)) { return IMAGE; } if (VOICE.type.equals(val)) { return VOICE; } if (VIDEO.type.equals(val)) { return VIDEO; } if (MUSIC.type.equals(val)) { return MUSIC; } if (LOCATION.type.equals(val)) { return LOCATION; } if (LINK.type.equals(val)) { return LINK; } if (EVENT.type.equals(val)) { return EVENT; } if (NEWS.type.equals(val)) { return NEWS; } if (TEMPLATE.type.equals(val)) { return TEMPLATE; } if (TRANSFER_CUSTOMER_SERVICE.type.equals(val)) { return TRANSFER_CUSTOMER_SERVICE; } return null; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/QRCreation.java ================================================ package com.belerweb.social.weixin.bean; import org.json.JSONObject; public class QRCreation { private QRType type;// 二维码类型,QR_SCENE为临时,QR_LIMIT_SCENE为永久 private Integer expireSeconds = 1800;// 该二维码有效时间,以秒为单位。 最大不超过1800。 private Integer sceneId;// 场景值ID,临时二维码时为32位整型,永久二维码时最大值为1000 public QRType getType() { return type; } public void setType(QRType type) { this.type = type; } public Integer getExpireSeconds() { return expireSeconds; } public void setExpireSeconds(Integer expireSeconds) { this.expireSeconds = expireSeconds; } public Integer getSceneId() { return sceneId; } public void setSceneId(Integer sceneId) { this.sceneId = sceneId; } @Override public String toString() { JSONObject obj = new JSONObject(); if (type == QRType.QR_SCENE) { obj.put("expire_seconds", expireSeconds); } obj.put("action_name", type.value()); JSONObject actionInfo = new JSONObject(); JSONObject scene = new JSONObject(); scene.put("scene_id", sceneId); actionInfo.put("scene", scene); obj.put("action_info", actionInfo); return obj.toString(); } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/QRTicket.java ================================================ package com.belerweb.social.weixin.bean; import org.json.JSONObject; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; /** * 二维码 Ticket */ public class QRTicket extends JsonBean { public QRTicket() {} private QRTicket(JSONObject jsonObject) { super(jsonObject); } private String ticket;// 获取的二维码ticket,凭借此ticket可以在有效时间内换取二维码。 private Integer expireSeconds = 604800;// 该二维码有效时间,以秒为单位。 最大不超过1800。 /** * 获取的二维码ticket,凭借此ticket可以在有效时间内换取二维码。 */ public String getTicket() { return ticket; } public void setTicket(String ticket) { this.ticket = ticket; } /** * 获取二维码ticket后,开发者可用ticket换取二维码图片。请注意,本接口无须登录态即可调用。 */ public String getQRUrl() { return "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + ticket; } /** * 该二维码有效时间,以秒为单位。 最大不超过1800。 */ public Integer getExpireSeconds() { return expireSeconds; } public void setExpireSeconds(Integer expireSeconds) { this.expireSeconds = expireSeconds; } public static QRTicket parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } QRTicket obj = new QRTicket(jsonObject); obj.ticket = jsonObject.getString("ticket"); obj.expireSeconds = Result.parseInteger(jsonObject.opt("expire_seconds")); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/QRType.java ================================================ package com.belerweb.social.weixin.bean; /** * 带参数的二维码类型 */ public enum QRType { /** * 临时二维码 */ QR_SCENE("QR_SCENE"), /** * 永久二维码 */ QR_LIMIT_SCENE("QR_LIMIT_SCENE"); private String type; private QRType(String type) { this.type = type; } public String value() { return type; } @Override public String toString() { return type; } public static QRType parse(Object val) { if (QR_LIMIT_SCENE.type.equals(val)) { return QR_LIMIT_SCENE; } if (QR_SCENE.type.equals(val)) { return QR_SCENE; } return null; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/Scope.java ================================================ package com.belerweb.social.weixin.bean; /** * 应用授权作用域 */ public enum Scope { /** * 不弹出授权页面,直接跳转,只能获取用户openid */ SNSAPI_BASE("snsapi_base"), /** * 网页应用目前仅填写snsapi_login即可 */ SNSAPI_LOGIN("snsapi_login"), /** * 弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息 */ SNSAPI_USERINFO("snsapi_userinfo"); private String scope; private Scope(String scope) { this.scope = scope; } public String value() { return scope; } @Override public String toString() { return scope; } public static Scope parse(Object val) { if (SNSAPI_BASE.scope.equals(val)) { return SNSAPI_BASE; } if (SNSAPI_USERINFO.scope.equals(val)) { return SNSAPI_USERINFO; } if (SNSAPI_LOGIN.scope.equals(val)) { return SNSAPI_LOGIN; } return null; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/User.java ================================================ package com.belerweb.social.weixin.bean; import java.util.Date; import java.util.List; import org.json.JSONObject; import com.belerweb.social.bean.Gender; import com.belerweb.social.bean.JsonBean; import com.belerweb.social.bean.Result; /** * 微信用户信息 */ public class User extends JsonBean { public User() {} private User(JSONObject jsonObject) { super(jsonObject); } private String openId;// 用户的唯一标识 private String unionID;// 同一用户,对同一个微信开放平台帐号下的不同应用,UnionID是相同的 private String nickname;// 用户昵称 private Gender gender;// 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知 private String province;// 用户个人资料填写的省份 private String city;// 普通用户个人资料填写的城市 private String country;// 国家,如中国为CN private List privilege; // 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom) private String language;// 用户的语言,简体中文为zh_CN private String headImgUrl;// 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空 private Boolean subscribe;// 用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。 private Date subscribeTime;// 用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间 /** * 用户的唯一标识 */ public String getOpenId() { return openId; } public void setOpenId(String openId) { this.openId = openId; } /** * 用户昵称 */ public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } /** * 用户的性别 */ public Gender getGender() { return gender; } public void setGender(Gender gender) { this.gender = gender; } /** * 用户个人资料填写的省份 */ public String getProvince() { return province; } public void setProvince(String province) { this.province = province; } /** * 普通用户个人资料填写的城市 */ public String getCity() { return city; } public void setCity(String city) { this.city = city; } /** * 国家,如中国为CN */ public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } /** * 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom) */ public List getPrivilege() { return privilege; } public void setPrivilege(List privilege) { this.privilege = privilege; } /** * 用户的语言,简体中文为zh_CN */ public String getLanguage() { return language; } public void setLanguage(String language) { this.language = language; } /** * 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空 */ public String getHeadImgUrl() { return headImgUrl; } public void setHeadImgUrl(String headImgUrl) { this.headImgUrl = headImgUrl; } /** * 用户是否订阅该公众号标识,false 表此用户没有关注该公众号,拉取不到其余信息。 */ public Boolean getSubscribe() { return subscribe; } public void setSubscribe(Boolean subscribe) { this.subscribe = subscribe; } /** * 用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间 */ public Date getSubscribeTime() { return subscribeTime; } public void setSubscribeTime(Date subscribeTime) { this.subscribeTime = subscribeTime; } /** * 公众号只有在被绑定到微信开放平台帐号下后,才会获取UnionID。只要是同一个微信开放平台帐号下的公众号,用户的UnionID是唯一的 * * @return the unionId */ public String getUnionID() { return unionID; } public void setUnionID(String unionID) { this.unionID = unionID; } public static User parse(JSONObject jsonObject) { if (jsonObject == null) { return null; } User obj = new User(jsonObject); obj.openId = Result.toString(jsonObject.get("openid")); if (jsonObject.has("unionid")) { obj.unionID = Result.toString(jsonObject.get("unionid")); } obj.nickname = Result.toString(jsonObject.opt("nickname")); obj.gender = Gender.parse(Result.parseInteger(jsonObject.opt("sex"))); obj.province = Result.toString(jsonObject.opt("province")); obj.city = Result.toString(jsonObject.opt("city")); obj.country = Result.toString(jsonObject.opt("country")); obj.language = Result.toString(jsonObject.opt("language")); obj.headImgUrl = Result.toString(jsonObject.opt("headimgurl")); obj.subscribe = Result.parseBoolean(jsonObject.opt("subscribe")); Long subscribeTime = Result.parseLong(jsonObject.opt("subscribe_time")); if (subscribeTime != null) { obj.subscribeTime = new Date(subscribeTime * 1000); } obj.privilege = Result.parse(jsonObject.optJSONArray("privilege"), String.class); return obj; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/Variable.java ================================================ package com.belerweb.social.weixin.bean; /** * 模板消息中的变量 * * @date Aug 28, 2014 */ public class Variable { private String name;// 变量名称 private String value;// 变量值 private String color;// 变量颜色值 eg:#FF0000 public Variable() {} public Variable(String name, String value) { this.name = name; this.value = value; } public Variable(String name, String value, String color) { this.name = name; this.value = value; this.color = color; } /** * 变量名称 */ public String getName() { return name; } public void setName(String name) { this.name = name; } /** * 变量值 */ public String getValue() { return value; } public void setValue(String value) { this.value = value; } /** * 变量颜色值 eg:#FF0000 */ public String getColor() { return color; } public void setColor(String color) { this.color = color; } } ================================================ FILE: src/main/java/com/belerweb/social/weixin/bean/VoiceType.java ================================================ package com.belerweb.social.weixin.bean; /** * 语音格式 */ public enum VoiceType { /** * amr */ AMR("amr"), /** * speex */ SPEEX("speex"); private String type; private VoiceType(String type) { this.type = type; } public String value() { return type; } @Override public String toString() { return type; } public static VoiceType parse(Object val) { if (AMR.type.equals(val)) { return AMR; } if (SPEEX.type.equals(val)) { return SPEEX; } return null; } } ================================================ FILE: src/test/java/com/belerweb/social/SDKTest.java ================================================ package com.belerweb.social; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.belerweb.social.bean.Result; public class SDKTest extends TestConfig { final static Logger logger = LoggerFactory.getLogger(SDKTest.class); @Test public void testLonLatToAddress() { Result result = weibo.lonLatToAddress(118.839485, 31.954561); Assert.assertTrue(result.success()); logger.info(result.getResult()); } } ================================================ FILE: src/test/java/com/belerweb/social/TestConfig.java ================================================ package com.belerweb.social; import org.junit.Before; import com.belerweb.social.qq.connect.api.QQConnect; import com.belerweb.social.weibo.api.Weibo; import com.belerweb.social.weixin.api.Weixin; public class TestConfig { protected Weibo weibo; protected QQConnect connect; protected Weixin weixin; @Before public void initialize() { String redirectUri = System.getProperty("redirect"); weibo = new Weibo(System.getProperty("weibo.id"), System.getProperty("weibo.secret"), redirectUri); connect = new QQConnect(System.getProperty("connect.id"), System.getProperty("connect.secret"), redirectUri); weixin = new Weixin(System.getProperty("weixin.id"), System.getProperty("weixin.secret"), redirectUri, System.getProperty("weixin.token")); } } ================================================ FILE: src/test/java/com/belerweb/social/captcha/api/YundamaTest.java ================================================ package com.belerweb.social.captcha.api; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.belerweb.social.bean.Result; import com.belerweb.social.captcha.bean.YundamaType; public class YundamaTest { final static Logger logger = LoggerFactory.getLogger(YundamaTest.class); @Test public void testDecode() { try { byte[] img = new byte[] {-1, -40, -1, -32, 0, 16, 74, 70, 73, 70, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, -1, -2, 0, 59, 67, 82, 69, 65, 84, 79, 82, 58, 32, 103, 100, 45, 106, 112, 101, 103, 32, 118, 49, 46, 48, 32, 40, 117, 115, 105, 110, 103, 32, 73, 74, 71, 32, 74, 80, 69, 71, 32, 118, 54, 50, 41, 44, 32, 113, 117, 97, 108, 105, 116, 121, 32, 61, 32, 56, 48, 10, -1, -37, 0, 67, 0, 6, 4, 5, 6, 5, 4, 6, 6, 5, 6, 7, 7, 6, 8, 10, 16, 10, 10, 9, 9, 10, 20, 14, 15, 12, 16, 23, 20, 24, 24, 23, 20, 22, 22, 26, 29, 37, 31, 26, 27, 35, 28, 22, 22, 32, 44, 32, 35, 38, 39, 41, 42, 41, 25, 31, 45, 48, 45, 40, 48, 37, 40, 41, 40, -1, -37, 0, 67, 1, 7, 7, 7, 10, 8, 10, 19, 10, 10, 19, 40, 26, 22, 26, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, -1, -64, 0, 17, 8, 0, 53, 0, -126, 3, 1, 34, 0, 2, 17, 1, 3, 17, 1, -1, -60, 0, 31, 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, -1, -60, 0, -75, 16, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125, 1, 2, 3, 0, 4, 17, 5, 18, 33, 49, 65, 6, 19, 81, 97, 7, 34, 113, 20, 50, -127, -111, -95, 8, 35, 66, -79, -63, 21, 82, -47, -16, 36, 51, 98, 114, -126, 9, 10, 22, 23, 24, 25, 26, 37, 38, 39, 40, 41, 42, 52, 53, 54, 55, 56, 57, 58, 67, 68, 69, 70, 71, 72, 73, 74, 83, 84, 85, 86, 87, 88, 89, 90, 99, 100, 101, 102, 103, 104, 105, 106, 115, 116, 117, 118, 119, 120, 121, 122, -125, -124, -123, -122, -121, -120, -119, -118, -110, -109, -108, -107, -106, -105, -104, -103, -102, -94, -93, -92, -91, -90, -89, -88, -87, -86, -78, -77, -76, -75, -74, -73, -72, -71, -70, -62, -61, -60, -59, -58, -57, -56, -55, -54, -46, -45, -44, -43, -42, -41, -40, -39, -38, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -1, -60, 0, 31, 1, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, -1, -60, 0, -75, 17, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 119, 0, 1, 2, 3, 17, 4, 5, 33, 49, 6, 18, 65, 81, 7, 97, 113, 19, 34, 50, -127, 8, 20, 66, -111, -95, -79, -63, 9, 35, 51, 82, -16, 21, 98, 114, -47, 10, 22, 36, 52, -31, 37, -15, 23, 24, 25, 26, 38, 39, 40, 41, 42, 53, 54, 55, 56, 57, 58, 67, 68, 69, 70, 71, 72, 73, 74, 83, 84, 85, 86, 87, 88, 89, 90, 99, 100, 101, 102, 103, 104, 105, 106, 115, 116, 117, 118, 119, 120, 121, 122, -126, -125, -124, -123, -122, -121, -120, -119, -118, -110, -109, -108, -107, -106, -105, -104, -103, -102, -94, -93, -92, -91, -90, -89, -88, -87, -86, -78, -77, -76, -75, -74, -73, -72, -71, -70, -62, -61, -60, -59, -58, -57, -56, -55, -54, -46, -45, -44, -43, -42, -41, -40, -39, -38, -30, -29, -28, -27, -26, -25, -24, -23, -22, -14, -13, -12, -11, -10, -9, -8, -7, -6, -1, -38, 0, 12, 3, 1, 0, 2, 17, 3, 17, 0, 63, 0, -6, 122, 40, -48, -58, -124, -94, -25, 3, -75, 59, -53, 79, -18, 47, -27, 68, 95, -22, -109, -3, -47, 89, -38, -34, -65, -91, 104, 104, -115, -86, -34, -59, 111, -65, -18, 43, 100, -77, 125, 20, 100, -97, -64, 87, 27, 113, -118, -69, 51, -47, 45, 77, 31, 45, 63, -72, -65, -107, 87, 75, -101, 39, 55, 1, 38, -74, 99, 110, 113, 48, 12, -89, -54, 56, -49, -51, -23, -57, 60, -43, 53, -15, 38, -109, -27, -93, -49, 120, -74, -117, 32, 5, 13, -30, 53, -74, -4, -25, -18, -7, -127, 115, -45, -73, -88, -11, 21, -105, -29, 41, 68, -63, 116, -69, 72, -82, 35, -44, 103, 97, 115, 109, 40, -120, -7, 50, 75, 24, 46, 17, -33, -95, 36, 70, 70, 15, 56, -26, -90, 83, -118, 87, 90, -125, 106, -38, 23, 116, 111, 17, -23, 90, -58, -87, 117, 97, 100, 36, 105, 109, -48, 72, 89, -94, 42, -110, 41, -29, 114, -109, -44, 103, -65, 126, -39, -83, -65, 45, 63, -72, -65, -107, 115, 66, -14, 23, -69, -46, 60, 65, 2, -19, -126, -14, 53, -76, -72, -36, 57, 77, -57, 41, -97, 117, -109, 40, 127, -33, -10, -82, -94, -118, 110, -21, 80, -120, -49, 45, 63, -72, -65, -107, 30, 92, 127, -36, 95, -54, -80, -4, 111, -30, 40, 124, 49, -31, -7, -17, -28, -38, -45, 125, -56, 35, 63, -57, 33, -24, 62, -99, -49, -80, -81, 5, -69, -15, 95, -119, -19, 116, -53, -72, 38, -71, -107, 23, 80, -105, -49, -106, 113, -9, -40, -107, 3, 104, 63, -62, 48, 7, 3, 29, 49, -46, -80, -60, 98, -31, 65, -14, -75, 114, 39, 81, 67, 67, -24, -85, 29, 67, 79, -65, -72, -70, -126, -50, 88, 102, -110, -43, -126, 77, -80, 100, 35, 30, -39, -23, -102, 124, 55, 118, 51, 94, -49, 103, 20, -42, -17, 117, 6, 60, -40, 65, 27, -45, 32, 17, -111, -41, -95, 21, -29, 127, 8, -68, 67, -89, -8, 107, -61, -102, -107, -34, -86, -14, 36, 50, -35, -92, 74, 81, 11, 124, -37, 9, -24, 62, -122, -71, 31, 19, -36, -22, 55, -66, 33, -44, 124, 73, -89, 71, 121, 21, -101, 92, -2, -26, -15, 85, -112, 1, -47, 112, -35, -114, 0, -84, 94, 57, 42, 113, -99, -82, -34, -21, -56, -105, 85, 36, -99, -113, -93, -76, -3, 67, 79, -44, 38, -69, -122, -46, 88, -92, -106, -42, 67, 20, -56, 7, 40, -61, -44, 127, 90, -69, -27, -89, -9, 23, -14, -81, 14, -75, -48, 124, 67, -32, -55, -93, -15, 118, -91, 121, 27, -17, -71, 67, 121, 20, 78, 92, -68, 114, 55, -52, 88, -114, 15, 36, 116, -49, 36, 30, -43, -18, 72, -54, -24, -84, -124, 50, -80, -56, 35, -95, 21, -45, 66, -85, -88, -102, -100, 108, -1, 0, 66, -31, 46, 109, -48, -98, 90, 127, 113, 127, 42, 60, -76, -2, -30, -2, 84, 75, 34, -59, 19, -55, 33, -38, -120, 11, 49, -12, 2, -71, -81, 10, -8, -25, 69, -15, 52, -83, 13, -116, -17, 29, -46, -25, -9, 19, -128, -82, -61, -43, 121, -63, -2, 117, -77, -108, 34, -44, 91, -43, -108, -38, 78, -57, 75, -27, -89, -9, 23, -14, -93, -53, 79, -18, 47, -27, 79, -94, -86, -56, 118, 51, 101, 24, -111, -64, -23, -109, 69, 18, -1, 0, -83, 127, -9, -115, 21, -54, -9, 48, 101, -8, -65, -43, 39, -5, -94, -71, 31, -120, 90, 71, -121, 111, 18, -46, -9, -60, 119, 109, 102, -48, 110, 72, 38, 89, 54, -112, -57, -98, -35, 72, -58, 107, -82, -117, -3, 82, 127, -70, 42, -114, -73, -94, -23, -6, -27, -76, 118, -6, -83, -78, -36, -61, 28, -126, 85, 70, 36, 0, -64, 17, -98, 15, -95, 53, -75, 72, 115, -61, -106, -55, -6, -101, 53, 117, 99, 58, 38, -77, -41, 60, 47, 34, 120, -122, 40, 93, 34, 13, 21, -30, -65, -35, 71, 78, 25, -77, -40, 127, 16, 62, -124, 26, -53, -70, -67, -42, 124, 38, -119, 36, -120, -6, -41, -121, -64, 31, -66, 78, 110, 109, -45, -43, -79, -60, -118, 7, 126, 15, -83, 107, -68, 81, -23, -2, 32, -14, -39, 7, -40, 117, 88, -4, -74, 83, -9, 68, -56, -68, 127, -33, 81, -126, 63, -19, -104, -11, -82, 67, 72, -101, 90, -16, -66, -83, 6, -115, -91, 105, -70, -122, -89, 100, -110, -55, 28, -86, -33, -22, -29, 78, 30, 54, 73, 27, 10, -89, 99, 96, -87, 56, -56, -29, 4, -42, 21, 27, -115, -81, -66, -41, 95, -27, -42, -28, 55, 99, 87, 69, -15, 14, -105, -30, 93, 87, 93, -16, -20, 66, 15, -78, -19, -13, 97, -106, -33, -27, -13, 85, -44, 23, 111, -9, -61, -79, 57, -9, -23, -112, 73, -22, -84, 110, -102, -30, 121, 18, 22, 73, 109, -96, -52, 79, 35, 49, 18, -7, -86, 112, 65, 93, -96, 99, 24, 57, -49, 57, -32, 99, 6, -71, -120, 124, 39, -94, -65, -118, 34, -15, 6, -127, 114, -79, -49, 108, -51, -10, -120, 44, -39, 25, 101, 37, 79, -54, 70, 112, -92, -28, 103, -41, -40, -13, 80, -4, 73, -42, 33, -16, -59, -101, -52, -6, 60, -105, -42, -38, -95, 49, 93, 50, 93, 60, 32, 16, -96, 0, 112, 15, 37, 65, 25, 24, 56, 90, 113, -100, -87, -63, -50, -91, -76, -4, -70, 127, -112, 38, -30, -81, 35, -109, -8, -121, 14, -79, -85, -8, -78, 73, 47, 108, 110, -96, -46, 116, -36, 44, 12, -56, 76, 110, 78, 62, 125, -61, -114, 78, 63, 32, 14, 14, 107, -100, -43, 116, -58, -44, -30, -119, 12, -62, 56, -112, -27, -126, -82, 114, 123, 119, -12, 53, -48, 104, 127, 18, 97, -79, -80, -74, -80, -47, 108, 45, -84, -83, -43, -10, 71, 109, 43, 73, 41, 66, -60, -110, 119, -110, 50, 55, 19, -12, -51, 95, -44, 124, 85, 107, -85, 94, -38, -40, 77, -31, 43, 61, 70, -13, 80, -3, -53, 73, -26, -124, 36, -32, 12, -18, -40, 89, 112, 57, -50, 114, 0, -21, -59, 121, -14, 84, -86, 94, 92, -38, -65, 95, -21, -16, 50, 124, -78, -42, -25, 5, -31, -97, 4, -34, 107, -79, -21, 50, 66, -52, 32, -45, -47, -10, 16, 63, -42, -54, 6, 66, 15, -64, 115, -8, 122, -41, -81, -39, 50, -8, -21, -31, 103, -105, -63, -71, -102, -37, -53, 62, -45, 39, 79, -90, 89, 65, -6, 26, -22, -12, 77, 38, -53, 68, -45, -46, -53, 76, -73, 91, 123, 100, 37, -126, 6, 45, -55, -28, -110, 79, 39, -15, -84, -33, 12, -23, 26, 95, -121, -82, -17, -84, 52, -21, -62, 101, -71, -112, -34, 53, -93, -54, -124, -60, 9, -63, 42, -96, 2, 23, -96, -25, 61, 7, 53, -41, 71, 9, -20, 116, -24, -43, -97, -24, 105, 26, 124, -70, 119, 42, -40, 104, -41, -73, -33, 14, 19, 71, -42, -111, 18, -11, -20, -52, 12, 3, 110, -38, 64, -62, 18, 125, 70, 20, -97, 122, -121, -31, 70, -84, -38, -89, -125, -83, -93, -100, -97, -75, 88, -109, 105, 40, 61, 65, 78, -97, -8, -18, 63, 28, -45, -17, -68, 65, 109, -31, -1, 0, 17, -35, -82, -83, 38, -91, 29, -108, -15, -122, 23, 87, 42, 62, -53, 27, 14, -111, -59, -75, 114, 88, -126, -60, -25, -97, -112, 117, -81, 62, 111, 29, -61, 101, -82, -33, -89, -127, 52, -85, 98, 110, -27, 18, 75, 37, -61, 74, -58, -23, -53, 0, 54, 71, -111, -80, -18, 118, -23, -44, 122, 98, -100, -86, -62, -108, -94, -17, -74, -115, 117, -14, 7, 37, 22, -114, -49, 93, -44, 53, 93, 123, 82, -46, -49, -125, 53, 80, 44, -29, -72, -110, -34, -10, 68, -117, 114, 33, 0, 18, 73, 35, 7, -125, -64, -11, 35, -16, 93, 95, 71, -16, -25, -107, -91, -92, 118, -112, -36, -53, 14, -96, -106, -119, 45, -76, -31, 36, 18, 96, -18, -13, 36, 95, -104, 17, -13, 49, 0, -28, -80, 94, -103, 53, 22, -67, -84, 78, -70, 77, -58, -116, -38, -2, -97, 109, -30, 123, -124, 12, -30, 103, 49, -57, 10, -74, 78, -60, 96, 49, -112, 14, 1, 63, 49, -21, -23, 89, 122, 111, -125, -91, -97, -62, 22, 26, 46, -93, 23, -40, -124, -38, -104, -107, -4, -87, 67, -18, 85, -124, -110, -54, -61, -5, -59, 78, 61, 51, -19, 74, 77, -54, 77, 37, 118, -2, -27, -27, -42, -34, 96, -11, 125, -49, 84, -94, -103, 18, 44, 81, -92, 104, 48, -86, 2, -114, 115, -64, -89, -41, -96, 108, 102, -53, -2, -75, -1, 0, -34, 52, 81, 47, -6, -41, -1, 0, 120, -47, 92, -113, 115, -99, -105, -30, -1, 0, 84, -97, -18, -118, 125, 50, 47, -11, 73, -2, -24, -89, -41, 82, -40, -35, 108, 114, -33, 17, 117, -69, 125, 3, 64, -114, -6, -22, -59, -81, 66, -36, -57, -78, 53, -112, -57, -75, -63, -36, 27, 112, 7, 24, -37, -8, -12, -17, 89, -66, 37, -15, 52, -10, -66, 30, -45, 124, 87, -91, -57, -10, -69, 22, 64, 46, 109, 89, -56, 93, -84, 70, 27, -72, 12, -82, 54, -25, 29, -49, -96, -82, -34, -30, 8, -82, 97, 104, -82, 34, 73, 98, 97, -122, 71, 80, -54, 126, -96, -41, 13, -84, -8, 91, 90, -5, 53, -26, -113, -96, 79, -89, 91, 104, 87, -123, -99, -60, -56, 89, -31, -35, -9, -111, 20, 113, -76, -100, -80, -12, -55, -58, 48, 43, -102, -76, 106, 43, -72, -11, 93, 55, -71, 18, 79, -96, -49, 27, -37, 107, 51, -35, -24, 122, -65, -124, 109, -103, 47, -90, 33, 39, -112, -100, 15, 44, -128, 85, 101, 29, 10, -11, -25, -73, 110, 72, -91, -15, -75, -89, -120, -11, -3, 30, 61, 20, -24, -42, -37, 110, 29, 5, -59, -22, 92, -87, 72, -80, -32, -18, 69, 108, 55, 65, -6, -111, -49, 90, -18, -32, 67, 28, 17, -93, 16, 74, -88, 82, 71, -80, -87, 42, -98, 29, 75, -102, -19, -21, -72, -36, 47, 127, 51, -25, -97, -120, -66, 1, -73, -16, -114, -109, 105, 119, 5, -20, -41, 50, 75, 55, -106, -37, -108, 40, 31, 41, 60, 99, -23, -21, 93, -73, -63, -81, 7, 73, -91, -37, 54, -75, -87, -57, -74, -10, -27, 49, 2, 48, -26, 56, -49, 115, -24, 79, -24, 62, -90, -69, -19, 99, 70, -77, -42, 13, -105, -37, -29, -13, 82, -42, 113, 112, -120, 126, -23, 96, -92, 12, -114, -29, -100, -29, -40, 86, -107, 99, 79, 3, 8, 85, -10, -117, 110, -120, -120, -46, 74, 87, 10, -32, 62, 40, -8, 107, 82, -44, 22, -33, 89, -16, -20, -78, -59, -85, 89, -93, 71, -120, -101, 107, -55, 27, 117, 10, 125, 70, 79, 29, -14, 123, -30, -69, -6, 43, -86, -83, 53, 86, 46, 44, -46, 81, -26, 86, 103, -119, -22, -87, -29, 95, 6, 94, 105, -59, -75, -69, -85, -69, 59, -26, -118, 57, 100, -108, -7, -62, 57, 59, -89, -49, -100, 117, 56, 35, 25, -4, 43, -47, 111, -76, 56, -19, -4, 69, 109, -86, 88, 104, 90, 108, -46, 41, 37, -26, 71, -14, 38, 70, 114, 124, -57, 32, 13, -78, 18, 49, -116, -112, 65, -49, 63, 55, 29, 13, -35, -76, 55, 112, 52, 55, 49, 44, -79, 49, 4, -85, 12, -116, -125, -112, 127, 2, 1, -87, -85, 40, 97, -108, 27, 87, -70, -23, -42, -33, 121, 42, 22, 57, -117, -65, 8, -39, -99, 38, -6, 61, 59, -3, 23, 83, -69, 83, -69, 80, 117, 18, 76, 92, -14, 73, 111, 126, -104, 24, 3, 60, 99, -118, -27, -84, 60, 31, 117, 7, -123, 109, -12, 75, -69, -119, -90, -113, -5, 95, 119, -38, 108, -33, -26, 84, -39, -126, -64, -13, -73, 15, -72, 28, -9, -51, 122, -123, 99, 39, -122, -12, -24, -75, -10, -42, 96, 73, -95, -67, 127, -11, -66, 84, -84, -87, 47, 24, -7, -108, 28, 31, -15, -26, -118, -104, 120, -74, -102, 94, 95, 32, 112, 76, -47, -45, -19, -123, -107, -123, -75, -86, -55, 36, -94, 8, -42, 48, -14, 28, -77, 109, 24, -53, 30, -28, -29, -102, -79, 69, 21, -48, -107, -76, 52, 51, 101, -1, 0, 90, -1, 0, -17, 26, 40, -105, -3, 107, -1, 0, -68, 104, -82, 87, -71, -50, -55, -110, -21, 106, -127, -77, -96, -57, 90, 119, -38, -1, 0, -40, -3, 104, -94, -85, -98, 69, 115, 48, -5, 95, -5, 31, -83, 31, 107, -1, 0, 99, -11, -94, -118, 61, -92, -125, -99, -121, -38, -1, 0, -40, -3, 104, -5, 95, -5, 31, -83, 20, 81, -19, 36, 28, -20, 62, -41, -2, -57, -21, 71, -38, -1, 0, -40, -3, 104, -94, -113, 105, 32, -25, 97, -10, -65, -10, 63, 90, 62, -41, -2, -57, -21, 69, 20, 123, 73, 7, 59, 15, -75, -1, 0, -79, -6, -47, -10, -65, -10, 63, 90, 40, -93, -38, 72, 57, -40, 125, -81, -3, -113, -42, -113, -75, -1, 0, -79, -6, -47, 69, 30, -46, 65, -50, -61, -19, 127, -20, 126, -76, 125, -81, -3, -113, -42, -118, 40, -10, -110, 14, 118, 86, 115, -71, -119, -11, 57, -94, -118, 42, 73, 63, -1, -39,}; Result result = new Yundama(System.getProperty("yundama.username"), System.getProperty("yundama.password")).decode(img, YundamaType.ALPHABETIC4); if (result.success()) { logger.info("Text:{}", result.getResult()); } else { logger.error("Error:{}", result.getError().getErrorCode()); } Assert.assertTrue("nkha".equalsIgnoreCase(result.getResult())); } catch (Exception e) { e.printStackTrace(); Assert.fail(e.getMessage()); } } } ================================================ FILE: src/test/java/com/belerweb/social/mail/api/POP3Test.java ================================================ package com.belerweb.social.mail.api; import org.junit.Test; import com.belerweb.social.mail.api.POP3; public class POP3Test { @Test public void testDownload() { String username = System.getProperty("pop3.username"); String password = System.getProperty("pop3.password"); String host = System.getProperty("pop3.host"); POP3 pop3 = new POP3(username, password, host, 995, true); pop3.download(System.getProperty("java.io.tmpdir")); } } ================================================ FILE: src/test/java/com/belerweb/social/qq/connect/api/OAuth2Test.java ================================================ package com.belerweb.social.qq.connect.api; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.belerweb.social.TestConfig; import com.belerweb.social.bean.Result; import com.belerweb.social.qq.connect.bean.AccessToken; import com.belerweb.social.qq.connect.bean.OpenID; public class OAuth2Test extends TestConfig { final static Logger logger = LoggerFactory.getLogger(OAuth2Test.class); @Test public void testAuthorize() { String url = connect.getOAuth2().authorize(); // 浏览器打开URL获取code用于下一步测试 logger.info(url); } @Test public void testAuthorizeWap() { String url = connect.getOAuth2().authorize(true); // 浏览器打开URL获取code用于下一步测试 logger.info(url); } @Test public void testAccessToken() { Result tokenResult = connect.getOAuth2().accessToken("code"); Assert.assertTrue(!tokenResult.success()); logger.info(tokenResult.getError().toString()); String code = System.getProperty("connect.code"); tokenResult = connect.getOAuth2().accessToken(code); Assert.assertTrue(tokenResult.success()); logger.info(tokenResult.getResult().getJsonObject().toString()); } @Test public void testAccessTokenWap() { Result tokenResult = connect.getOAuth2().accessToken("code", true); Assert.assertTrue(!tokenResult.success()); logger.info(tokenResult.getError().toString()); String code = System.getProperty("connect.code"); tokenResult = connect.getOAuth2().accessToken(code, true); Assert.assertTrue(tokenResult.success()); logger.info(tokenResult.getResult().getJsonObject().toString()); } @Test public void testOpenId() { String accessToken = System.getProperty("connect.token"); Result result = connect.getOAuth2().openId(accessToken); Assert.assertTrue(result.success()); logger.info(result.getResult().getJsonObject().toString()); } @Test public void testOpenIdWap() { String accessToken = System.getProperty("connect.token"); Result result = connect.getOAuth2().openId(accessToken, true); Assert.assertTrue(result.success()); logger.info(result.getResult().getJsonObject().toString()); } @Test public void testRefreshAccessToken() { String refreshToken = System.getProperty("connect.rtoken"); Result result = connect.getOAuth2().refreshAccessToken(refreshToken); Assert.assertTrue(result.success()); logger.info(result.getResult().getJsonObject().toString()); } @Test public void testRefreshAccessTokenWap() { String refreshToken = System.getProperty("connect.rtoken"); Result result = connect.getOAuth2().refreshAccessToken(refreshToken, true); Assert.assertTrue(result.success()); logger.info(result.getResult().getJsonObject().toString()); } } ================================================ FILE: src/test/java/com/belerweb/social/qq/connect/api/UserTest.java ================================================ package com.belerweb.social.qq.connect.api; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.belerweb.social.TestConfig; import com.belerweb.social.bean.Result; public class UserTest extends TestConfig { final static Logger logger = LoggerFactory.getLogger(UserTest.class); @Test public void testGetUserInfo() { String openId = System.getProperty("connect.openid"); String accessToken = System.getProperty("connect.token"); Result result = connect.getUser().getUserInfo(accessToken, openId); Assert.assertTrue(result.success()); logger.info(result.getResult().getJsonObject().toString()); } @Test public void testGetSimpleUserInfo() { String openId = System.getProperty("connect.openid"); String accessToken = System.getProperty("connect.token"); Result result = connect.getUser().getSimpleUserInfo(accessToken, connect.getClientId(), openId); Assert.assertTrue(result.success()); logger.info(result.getResult().getJsonObject().toString()); } } ================================================ FILE: src/test/java/com/belerweb/social/weibo/api/OAuth2Test.java ================================================ package com.belerweb.social.weibo.api; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.belerweb.social.TestConfig; import com.belerweb.social.bean.Result; import com.belerweb.social.weibo.bean.AccessToken; import com.belerweb.social.weibo.bean.TokenInfo; public class OAuth2Test extends TestConfig { final static Logger logger = LoggerFactory.getLogger(OAuth2Test.class); /** * 获取用于获取accessToken的code,此方法需要单独测试 */ @Test public void testAuthorize() { String url = weibo.getOAuth2().authorize(); // 浏览器打开URL获取code用于下一步测试 logger.info(url); } /** * 获取accessToken,此方法需要单独测试 */ @Test public void testAccessToken() { Result tokenResult = weibo.getOAuth2().accessToken("code"); Assert.assertTrue(!tokenResult.success()); logger.info(tokenResult.getError().toString()); String code = System.getProperty("weibo.code"); tokenResult = weibo.getOAuth2().accessToken(code); Assert.assertTrue(tokenResult.success()); logger.info(tokenResult.getResult().getJsonObject().toString()); } @Test public void testGetTokenInfo() { String accessToken = System.getProperty("weibo.token"); Result tokenResult = weibo.getOAuth2().getTokenInfo(accessToken); Assert.assertTrue(tokenResult.success()); logger.info(tokenResult.getResult().getJsonObject().toString()); } @Test public void testRevokeOAuth2() { String accessToken = System.getProperty("weibo.token"); Result tokenResult = weibo.getOAuth2().revokeOAuth2(accessToken); Assert.assertTrue(tokenResult.success()); Assert.assertTrue(tokenResult.getResult()); } } ================================================ FILE: src/test/java/com/belerweb/social/weibo/api/UserTest.java ================================================ package com.belerweb.social.weibo.api; import java.util.ArrayList; import java.util.List; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.belerweb.social.TestConfig; import com.belerweb.social.bean.Result; import com.belerweb.social.weibo.bean.UserCounts; public class UserTest extends TestConfig { final static Logger logger = LoggerFactory.getLogger(UserTest.class); @Test public void testShow() { String uid = System.getProperty("weibo.uid"); Result result = weibo.getUser().show(weibo.getClientId(), null, uid, null); Assert.assertTrue(result.success()); logger.info(result.getResult().getJsonObject().toString()); } @Test public void testDomainShow() { Result result = weibo.getUser().domainShow(weibo.getClientId(), null, "cqlybest"); Assert.assertTrue(result.success()); logger.info(result.getResult().getJsonObject().toString()); } @Test public void testCounts() { String accessToken = System.getProperty("weibo.token"); String uid = System.getProperty("weibo.uid"); List uids = new ArrayList(); uids.add(uid); Result result = weibo.getUser().counts(null, accessToken, uids); Assert.assertTrue(result.success()); List results = result.getResults(); for (UserCounts userCounts : results) { logger.info(userCounts.getJsonObject().toString()); } } } ================================================ FILE: src/test/java/com/belerweb/social/weixin/api/GroupTest.java ================================================ package com.belerweb.social.weixin.api; import java.util.List; import org.apache.commons.lang.RandomStringUtils; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.belerweb.social.TestConfig; import com.belerweb.social.bean.Error; import com.belerweb.social.bean.Result; import com.belerweb.social.weixin.bean.Group; public class GroupTest extends TestConfig { final static Logger logger = LoggerFactory.getLogger(GroupTest.class); @Test public void testCreate() { Result result = weixin.getGroup().create(RandomStringUtils.randomAlphabetic(6)); Assert.assertTrue(result.success()); logger.info(result.getResult().getJsonObject().toString()); } @Test public void testGet() { Result> result = weixin.getGroup().get(); Assert.assertTrue(result.success()); for (Group group : result.getResult()) { logger.info(group.getJsonObject().toString()); } } @Test public void testUpdate() { String id = System.getProperty("weixin.groupid"); Result result = weixin.getGroup().update(id, RandomStringUtils.randomAlphabetic(6)); Assert.assertTrue(result.success()); } @Test public void testMove() { String openId = System.getProperty("weixin.openid"); String groupId = System.getProperty("weixin.groupid"); Result result = weixin.getGroup().move(openId, groupId); Assert.assertTrue(result.success()); } } ================================================ FILE: src/test/java/com/belerweb/social/weixin/api/MediaTest.java ================================================ package com.belerweb.social.weixin.api; import java.io.File; import org.apache.commons.io.FileUtils; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.belerweb.social.TestConfig; import com.belerweb.social.bean.Result; import com.belerweb.social.weixin.bean.Media; import com.belerweb.social.weixin.bean.MediaType; public class MediaTest extends TestConfig { final static Logger logger = LoggerFactory.getLogger(MediaTest.class); @Test public void testUpload() throws Exception { File file = new File(System.getProperty("weixin.file")); Media media = new Media(); media.setName(file.getName()); media.setContentType(MediaType.VOICE_AMR.contentType()); media.setContent(FileUtils.readFileToByteArray(file)); Result result = weixin.getMedia().upload(MediaType.VOICE_AMR, media); Assert.assertTrue(result.success()); logger.info(result.getResult().getId()); } @Test public void testGet() throws Exception { String mediaId = System.getProperty("weixin.mediaid"); Result result = weixin.getMedia().get(mediaId); Assert.assertTrue(result.success()); logger.info(result.getResult().getContentType()); logger.info(result.getResult().getName()); } } ================================================ FILE: src/test/java/com/belerweb/social/weixin/api/MenuTest.java ================================================ package com.belerweb.social.weixin.api; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.RandomStringUtils; import org.junit.Assert; import org.junit.Test; import com.belerweb.social.TestConfig; import com.belerweb.social.bean.Error; import com.belerweb.social.bean.Result; import com.belerweb.social.weixin.bean.Menu; import com.belerweb.social.weixin.bean.MenuType; public class MenuTest extends TestConfig { @Test public void testGet() { Result> result = weixin.getMenu().get(); Assert.assertTrue(result.success()); } @Test public void testDelete() { Result result = weixin.getMenu().delete(); Assert.assertTrue(result.success()); } @Test public void testCreate() { List menus = new ArrayList(); Menu menu1 = new Menu(); menu1.setName(RandomStringUtils.randomAlphabetic(4)); List subs = new ArrayList(); Menu menu11 = new Menu(); menu11.setName(RandomStringUtils.randomAlphabetic(4)); menu11.setType(MenuType.CLICK); menu11.setKey(RandomStringUtils.randomAlphabetic(4)); subs.add(menu11); Menu menu22 = new Menu(); menu22.setName(RandomStringUtils.randomAlphabetic(4)); menu22.setType(MenuType.VIEW); menu22.setUrl("https://github.com/belerweb/"); subs.add(menu22); menu1.setSubs(subs); menus.add(menu1); Result result = weixin.getMenu().create(menus); Assert.assertTrue(result.success()); } @Test public void testCreate1() throws Exception { List menus = new ArrayList(); Menu menu1 = new Menu(); menu1.setName("普通菜单"); List subs1 = new ArrayList(); Menu menu11 = new Menu(); menu11.setName("点击事件"); menu11.setType(MenuType.CLICK); menu11.setKey("menu-click"); subs1.add(menu11); Menu menu12 = new Menu(); menu12.setName("跳转URL"); menu12.setType(MenuType.VIEW); menu12.setUrl("https://github.com/jdkcn"); subs1.add(menu12); menu1.setSubs(subs1); menus.add(menu1); Menu menu2 = new Menu(); menu2.setName("扫码"); List subs2 = new ArrayList(); Menu menu21 = new Menu(); menu21.setName("扫码推事件"); menu21.setType(MenuType.SCANCODE_PUSH); menu21.setKey("scancode_push"); subs2.add(menu21); Menu menu22 = new Menu(); menu22.setName("扫码带提示"); menu22.setType(MenuType.SCANCODE_WAITMSG); menu22.setKey("scancode_waitmsg"); subs2.add(menu22); Menu menu23 = new Menu(); menu23.setName("发送位置"); menu23.setType(MenuType.LOCATION_SELECT); menu23.setKey("location_select"); subs2.add(menu23); menu2.setSubs(subs2); menus.add(menu2); Menu menu3 = new Menu(); menu3.setName("发图"); List subs3 = new ArrayList(); Menu menu31 = new Menu(); menu31.setName("系统拍照发图"); menu31.setType(MenuType.PIC_SYSPHOTO); menu31.setKey("pic_sysphoto"); subs3.add(menu31); Menu menu32 = new Menu(); menu32.setName("拍照或者相册发图"); menu32.setType(MenuType.PIC_PHOTO_OR_ALBUM); menu32.setKey("pic_photo_or_album"); subs3.add(menu32); Menu menu33 = new Menu(); menu33.setName("微信相册发图"); menu33.setType(MenuType.PIC_WEIXIN); menu33.setKey("pic_weixin"); subs3.add(menu33); menu3.setSubs(subs3); menus.add(menu3); Result result = weixin.getMenu().create(menus); Assert.assertTrue(result.success()); } } ================================================ FILE: src/test/java/com/belerweb/social/weixin/api/OAuth2Test.java ================================================ package com.belerweb.social.weixin.api; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.belerweb.social.TestConfig; import com.belerweb.social.bean.Result; import com.belerweb.social.weixin.bean.AccessToken; public class OAuth2Test extends TestConfig { final static Logger logger = LoggerFactory.getLogger(OAuth2Test.class); @Test public void testAuthorize() { String url = weixin.getOAuth2().authorize(); // 浏览器不能访问,只能在微信客户端中访问 logger.info(url); } @Test public void testAccessToken() { Result tokenResult = weixin.getOAuth2().accessToken("code"); Assert.assertTrue(!tokenResult.success()); logger.info(tokenResult.getError().toString()); String code = System.getProperty("weixin.code"); tokenResult = weixin.getOAuth2().accessToken(code); Assert.assertTrue(tokenResult.success()); logger.info(tokenResult.getResult().getJsonObject().toString()); } @Test public void testRefreshAccessToken() { String refreshToken = System.getProperty("weixin.rtoken"); Result tokenResult = weixin.getOAuth2().refreshAccessToken(refreshToken); Assert.assertTrue(tokenResult.success()); System.out.print(tokenResult.getResult().getJsonObject()); } } ================================================ FILE: src/test/java/com/belerweb/social/weixin/api/UserTest.java ================================================ package com.belerweb.social.weixin.api; import java.util.List; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.belerweb.social.TestConfig; import com.belerweb.social.bean.Result; public class UserTest extends TestConfig { final static Logger logger = LoggerFactory.getLogger(UserTest.class); @Test public void testSnsapiUserInfo() { String accessToken = System.getProperty("weixin.atoken"); String openId = System.getProperty("weixin.openid"); Result result = weixin.getUser().snsapiUserInfo(accessToken, openId); Assert.assertTrue(result.success()); logger.info(result.getResult().getJsonObject().toString()); } @Test public void testUserInfo() { String openId = System.getProperty("weixin.openid"); Result result = weixin.getUser().userInfo(weixin.getAccessToken().getToken(), openId); Assert.assertTrue(result.success()); logger.info(result.getResult().getJsonObject().toString()); } @Test public void testGetFollowUsers() { Result> result = weixin.getUser().getFollowUsers(); Assert.assertTrue(result.success()); for (com.belerweb.social.weixin.bean.User user : result.getResult()) { logger.info(user.getJsonObject().toString()); } } } ================================================ FILE: src/test/java/com/belerweb/social/weixin/api/WeixinTest.java ================================================ package com.belerweb.social.weixin.api; import static org.junit.Assert.assertEquals; import java.util.Date; import org.apache.commons.lang.RandomStringUtils; import org.apache.commons.lang.time.DateFormatUtils; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.belerweb.social.TestConfig; import com.belerweb.social.bean.Result; import com.belerweb.social.weixin.bean.AccessToken; import com.belerweb.social.weixin.bean.ApiTicket; import com.belerweb.social.weixin.bean.JSApiTicket; import com.belerweb.social.weixin.bean.Message; import com.belerweb.social.weixin.bean.MsgType; import com.belerweb.social.weixin.bean.QRTicket; import com.belerweb.social.weixin.bean.QRType; import com.belerweb.social.weixin.bean.Variable; public class WeixinTest extends TestConfig { final static Logger logger = LoggerFactory.getLogger(WeixinTest.class); @Test public void testGetAccessToken() { AccessToken result = weixin.getAccessToken(); Assert.assertNotNull(result); logger.info(result.getJsonObject().toString()); } @Test public void testGetJSApiTicket() { JSApiTicket result = weixin.getJsApiTicket(); Assert.assertNotNull(result); logger.info(result.getJsonObject().toString()); } @Test public void testGetApiTicket() { ApiTicket result = weixin.getApiTicket(); Assert.assertNotNull(result); logger.info(result.getJsonObject().toString()); } @Test public void testSignature() throws Exception { Weixin wx = new Weixin(null); assertEquals("def42db04eb64f66c47a4e14fcc736156a704d8e", wx.signature("sduhi123", "wxd0f84fbc9396d6ae", "GROUPON", "E0o2-at6NcC2OsJiQTlwlKQmnidi_i9qnUG6I8wOFOOnPaK_fcjapbiBA15AUBXvkux2vvNsjYomRcbxXolfMw", "14300000000", "134234235235235")); } @Test public void testJsApiSignature() { String signature = weixin.jsapiSignature("http://openlaw.cn", new Date().getTime(), RandomStringUtils.randomAlphanumeric(16)); Assert.assertNotNull(signature); logger.info(signature); } @Test public void testCreateQR() { Result result = weixin.createQR(QRType.QR_SCENE, 0); Assert.assertTrue(result.success()); logger.info(result.getResult().getJsonObject().toString()); } @Test public void testCreateQR2() { Result result = weixin.createQR(QRType.QR_LIMIT_SCENE, 0); Assert.assertTrue(result.success()); logger.info(result.getResult().getJsonObject().toString()); logger.info(result.getResult().getQRUrl()); } @Test public void testSendCustomMessage() { Message message = new Message(MsgType.TEXT); message.setToUser(System.getProperty("weixin.openid")); message.setContent(new Date().toString()); Result result = weixin.sendCustomMessage(message); Assert.assertTrue(result.success()); } @Test public void testSendTemplateMessage() throws Exception { Message message = new Message(MsgType.TEMPLATE); message.setToUser(System.getProperty("weixin.openid")); message.setUrl("https://github.com/belerweb/social-sdk"); message.setTopColor("#459ae9"); message.setTemplateId(System.getProperty("weixin.templateid")); Variable var1 = new Variable("first", "您好,这是一个模板消息的测试"); Variable var2 = new Variable("schedule", "这是一个新的事件"); Variable var3 = new Variable("time", DateFormatUtils.format(new Date(), "yyyy年MM月dd日 HH:mm")); message.addVariable(var1).addVariable(var2).addVariable(var3); Result result = weixin.sendTemplateMessage(message); Assert.assertTrue(result.success()); } @Test public void testSendTemplateMessage1() throws Exception { Message message = new Message(MsgType.TEMPLATE); message.setToUser(System.getProperty("weixin.openid")); message.setUrl("http://openlaw.cn/judgement/4b47137610264874a4e41f3635b3fd83"); message.setTopColor("#459ae9"); message.setTemplateId(System.getProperty("weixin.templateid")); Variable var1 = new Variable("first", "高圆圆,您好!您关注的判决文书:\n龚喜琴与上海诺盛企业发展有限公司劳动合同纠纷一审民事判决书\n有新的回复。"); Variable var2 = new Variable("keyword1", "happyboy_1688"); Variable var3 = new Variable("keyword2", DateFormatUtils.format(new Date(), "yyyy年MM月dd日 HH:mm")); Variable var4 = new Variable( "keyword3", "本人参与庭审,有权发表意见:\n原告负责的项目她没本事拿下来,本人花了几个月把这项目做下来,老板为显示公平,却把一半提成给了原告,本人只拿一半帮原告挣钱但毫无怨言,这事大家都同意了,现在原告在法庭上反悔要本人的那一半,还好法官有眼,没给她.正义战胜邪恶! ", "#32a3cb"); message.addVariable(var1).addVariable(var2).addVariable(var3).addVariable(var4); Result result = weixin.sendTemplateMessage(message); Assert.assertTrue(result.success()); } } ================================================ FILE: src/test/resources/logback.xml ================================================ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n