iQQ 学习笔记2 :借助新浪微博输入验证码、远程控制退出

来源:互联网 发布:中小学信息化数据库 编辑:程序博客网 时间:2024/04/30 18:16
iQQ 学习笔记2说明 :借助新浪微博输入验证码、远程控制退出
在第1个案例中实现了iQQ的登录、验证码和收消息,其中有两处需要人工参与,第一处是需要打开验证码图片,然后输入验证码,第二处是退出程序需要强制退出。验证码暂时还不能自动识别,不过可以改进交互方式,本例中将借助新浪微博实现显示验证码图片和输入验证码。退出程序改成收到QQ消息后按消息内容操作。

iQQ 学习笔记2程序 :借助新浪微博输入验证码、远程控制退出
这是主程序,其中的username常量的值应替换为QQ号,password常量的值应替换为该QQ号对应的QQ密码。
  1. package test_2;

  2. import java.util.logging.Logger;

  3. import iqq.im.QQClient;
  4. import iqq.im.QQException;
  5. import iqq.im.QQNotifyListener;
  6. import iqq.im.WebQQClient;
  7. import iqq.im.actor.ThreadActorDispatcher;
  8. import iqq.im.bean.QQMsg;
  9. import iqq.im.bean.QQStatus;
  10. import iqq.im.bean.content.ContentItem;
  11. import iqq.im.bean.content.TextItem;
  12. import iqq.im.event.QQActionEvent;
  13. import iqq.im.event.QQActionFuture;
  14. import iqq.im.event.QQNotifyEvent;
  15. import iqq.im.event.QQNotifyEventArgs;
  16. import iqq.im.event.QQActionEvent.Type;

  17. public class Test_2 {
  18.         private static final String username = "**********";
  19.         private static final String password = "**********";
  20.         private static final Logger logger = java.util.logging.Logger.getLogger("");
  21.         private static QQClient client;
  22.         public static void main(String[] args) {
  23.                 client = new WebQQClient(username, password, new QQNotifyListener() {
  24.                         @Override
  25.                         public void onNotifyEvent(QQNotifyEvent event) {
  26.                                 if (event.getType() == QQNotifyEvent.Type.CHAT_MSG) {
  27.                                         if (event.getTarget() instanceof QQMsg) {
  28.                                                 QQMsg msg = (QQMsg) event.getTarget();
  29.                                                 for (ContentItem contentItem : msg.getContentList()) {
  30.                                                         if (contentItem instanceof TextItem) {
  31.                                                                 TextItem textItem = (TextItem) contentItem;
  32.                                                                 logger.info(textItem.getContent());
  33.                                                                 if (textItem.getContent().startsWith("logout ")) {
  34.                                                                         client.logout(null);
  35.                                                                 }                                                                        
  36.                                                         }
  37.                                                 }
  38.                                         }
  39.                                 } else if (event.getType() == QQNotifyEvent.Type.CAPACHA_VERIFY) {
  40.                                         if (event.getTarget() instanceof QQNotifyEventArgs.ImageVerify) {
  41.                                                 QQNotifyEventArgs.ImageVerify imageVerify = (QQNotifyEventArgs.ImageVerify) event.getTarget();
  42.                                                 String code = ImageVerifyQuestioners.ImageVeiryQuestion(imageVerify);
  43.                                                 client.submitVerify(code, event);
  44.                                         } else {
  45.                                                 logger.info(event.getTarget().getClass().getName());
  46.                                         }
  47.                                 } else {
  48.                                         logger.info("TODO QQNotifyEvent: " + event.getType() + ", " + event.getTarget());
  49.                                 }
  50.                         }
  51.                 }, new ThreadActorDispatcher());
  52.                 QQActionFuture future = client.login(QQStatus.ONLINE, null);
  53.                 try {
  54.                         QQActionEvent event = future.waitFinalEvent();
  55.                         if (event.getType() == Type.EVT_OK) {
  56.                                 client.beginPollMsg();
  57.                         }
  58.                 } catch (QQException e) {
  59.                         e.printStackTrace();
  60.                 }
  61.         }
  62. }
复制代码
为了便于实现多种图片验证码的输入方式,设计一个图片验证码接口。
  1. package test_2;

  2. import iqq.im.event.QQNotifyEventArgs.ImageVerify;

  3. public abstract class ImageVerifyQuestioner {
  4.         private ImageVerify imageVerify;
  5.         private String Code;
  6.         public ImageVerifyQuestioner(ImageVerify imageVerify) {
  7.                 this.imageVerify = imageVerify;
  8.                 this.Code = "";
  9.         }
  10.         protected final ImageVerify getImageVerify() {
  11.                 return imageVerify;
  12.         }
  13.         public final String getCode() {
  14.                 return Code;
  15.         }
  16.         protected final void setCode(String code) {
  17.                 Code = code;
  18.         }
  19.         public abstract void loop ();
  20. }
复制代码
通过一个调度程序管理多种图片验证码的输入方式,当一种输入方式获取验证码时,其他输入方式退出。
  1. package test_2;

  2. import java.util.ArrayList;
  3. import java.util.List;

  4. import iqq.im.event.QQNotifyEventArgs.ImageVerify;

  5. public class ImageVerifyQuestioners {
  6.         public static String ImageVeiryQuestion (ImageVerify imageVerify) {
  7.                 String code = "";
  8.                 List<ImageVerifyQuestioner> imageVerifyQuestionerList = new ArrayList<ImageVerifyQuestioner>();
  9.                 imageVerifyQuestionerList.add(new ImageVerifyConsoleQuestioner(imageVerify));
  10.                 imageVerifyQuestionerList.add(new ImageVerifyWeiboQuestioner(imageVerify));
  11.                 boolean alive = true;
  12.                 while (alive) {
  13.                         for(ImageVerifyQuestioner imageVerifyQuestioner : imageVerifyQuestionerList) {
  14.                                 if (true == alive) {
  15.                                         imageVerifyQuestioner.loop();
  16.                                         if (imageVerifyQuestioner.getCode() != "") {
  17.                                                 code = imageVerifyQuestioner.getCode();
  18.                                                 alive = false;
  19.                                         }                                        
  20.                                 }
  21.                         }
  22.                         try {
  23.                                 Thread.sleep(100);
  24.                         } catch (InterruptedException e) {
  25.                                 e.printStackTrace();
  26.                         }
  27.                 }
  28.                 return code;
  29.         }
  30. }
复制代码
保持原有的命令行交互输入图片验证码的输入方式。
  1. /**

  2. */
  3. package test_2;

  4. import java.io.File;
  5. import java.io.IOException;
  6. import javax.imageio.ImageIO;

  7. import iqq.im.event.QQNotifyEventArgs.ImageVerify;

  8. public class ImageVerifyConsoleQuestioner extends ImageVerifyQuestioner {
  9.         private boolean isPrompt;
  10.         private StringBuilder codeStringBuilder = new StringBuilder();
  11.         public ImageVerifyConsoleQuestioner(ImageVerify imageVerify) {
  12.                 super(imageVerify);
  13.         }
  14.         private void prompt () {
  15.                 try {
  16.                         ImageIO.write(this.getImageVerify().image, "png", new File("verify.png"));
  17.                         System.out.println(this.getImageVerify().reason);
  18.                         System.out.print("请输入在项目根目录下 verify.png 图片里面的验证码: ");
  19.                         isPrompt = true;
  20.                 } catch (IOException e) {
  21.                         e.printStackTrace();
  22.                 }
  23.         }
  24.         private void read () {
  25.                 try {
  26.                         int available = System.in.available();
  27.                         if (0 < available) {
  28.                                 int inChar = System.in.read();
  29.                                 switch (Character.getType(inChar)) {
  30.                                 case Character.UPPERCASE_LETTER:
  31.                                 case Character.LOWERCASE_LETTER:
  32.                                 case Character.DECIMAL_DIGIT_NUMBER:
  33.                                         codeStringBuilder.append((char) inChar);
  34.                                         break;
  35.                                 case Character.CONTROL:
  36.                                         this.setCode(codeStringBuilder.toString());
  37.                                         break;
  38.                                 }
  39.                         }
  40.                 } catch (IOException e) {
  41.                         e.printStackTrace();
  42.                 }
  43.         }
  44.         @Override
  45.         public void loop() {
  46.                 if (false == this.isPrompt) {
  47.                         this.prompt();
  48.                 }
  49.                 if (this.getCode() == "") {
  50.                         this.read();                                        
  51.                 }                
  52.         }
  53. }
复制代码
新增通过新浪微博输入图片验证码的输入方式,其中的accessTokenFile的值应替换为保存新浪微博Access Token的路径。
  1. /**

  2. */
  3. package test_2;

  4. import java.io.BufferedReader;
  5. import java.io.ByteArrayOutputStream;
  6. import java.io.FileNotFoundException;
  7. import java.io.FileReader;
  8. import java.io.IOException;
  9. import java.io.InputStreamReader;
  10. import java.io.OutputStream;
  11. import java.net.MalformedURLException;
  12. import java.net.URL;
  13. import java.net.URLConnection;
  14. import java.text.SimpleDateFormat;
  15. import java.util.Date;
  16. import java.util.logging.Logger;

  17. import javax.imageio.ImageIO;
  18. import javax.net.ssl.HttpsURLConnection;

  19. import org.json.JSONObject;

  20. import iqq.im.event.QQNotifyEventArgs.ImageVerify;

  21. public class ImageVerifyWeiboQuestioner extends ImageVerifyQuestioner {
  22.         private static final String accessTokenFile = "**********";
  23.         private static final Logger logger = java.util.logging.Logger.getLogger("");
  24.         private String accessToken;
  25.         private long weiboId;
  26.         private long lastCheckTime;
  27.         public ImageVerifyWeiboQuestioner(ImageVerify imageVerify) {
  28.                 super(imageVerify);
  29.         }
  30.         private void readAccessToken () {
  31.                 FileReader fileReaderAccessToken;
  32.                 try {
  33.                         fileReaderAccessToken = new FileReader(accessTokenFile);
  34.                         BufferedReader bufferedReaderAccessToken = new BufferedReader(fileReaderAccessToken);
  35.                         accessToken = bufferedReaderAccessToken.readLine();
  36.                         bufferedReaderAccessToken.close();
  37.                         fileReaderAccessToken.close();
  38.                 } catch (FileNotFoundException e) {
  39.                         e.printStackTrace();
  40.                 } catch (IOException e) {
  41.                         e.printStackTrace();
  42.                 }
  43.         }
  44.         private void uploadVerifyImage () {
  45.                 try {
  46.                         //Status
  47.                         StringBuilder statusStringBuilder = new StringBuilder();
  48.                         statusStringBuilder.append("请@胡争辉 输入验证码 ");
  49.                         statusStringBuilder.append((new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(new Date())); 
  50.                         //URL
  51.                         StringBuilder urlStringBuilder = new StringBuilder();
  52.                         urlStringBuilder.append("https://api.weibo.com/2/statuses/upload.json?access_token=");
  53.                         urlStringBuilder.append(accessToken);
  54.                         URL url = new URL(urlStringBuilder.toString());
  55.                         URLConnection urlConnection =url.openConnection();
  56.                         if (urlConnection instanceof HttpsURLConnection) {
  57.                                 String BOUNDARY = "---------------------------" + String.valueOf(System.currentTimeMillis());
  58.                                 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
  59.                                 byteArrayOutputStream.write(("--" + BOUNDARY + "\r\n").getBytes());
  60.                                 byteArrayOutputStream.write(("Content-Disposition: form-data; name=\"pic\"; filename=\"verifyimage.png\"\r\n").getBytes());
  61.                                 byteArrayOutputStream.write(("Content-Type: image/png\r\n").getBytes());
  62.                                 byteArrayOutputStream.write(("\r\n").getBytes());
  63.                                 ImageIO.write(this.getImageVerify().image, "png", byteArrayOutputStream);
  64.                                 byteArrayOutputStream.write(("\r\n").getBytes());
  65.                                 byteArrayOutputStream.write(("--" + BOUNDARY + "\r\n").getBytes());
  66.                                 byteArrayOutputStream.write(("Content-Disposition: form-data; name=\"status\"\r\n").getBytes());
  67.                                 byteArrayOutputStream.write(("\r\n").getBytes());
  68.                                 byteArrayOutputStream.write(statusStringBuilder.toString().getBytes());
  69.                                 byteArrayOutputStream.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes());
  70.                                 HttpsURLConnection httpsURLConnection = (HttpsURLConnection) urlConnection;
  71.                                 httpsURLConnection.setRequestMethod("POST");
  72.                                 httpsURLConnection.addRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
  73.                                 httpsURLConnection.setDoOutput(true);
  74.                                 httpsURLConnection.setDoInput(true);
  75.                                 OutputStream outputStream = httpsURLConnection.getOutputStream();
  76.                                 outputStream.write(byteArrayOutputStream.toByteArray());
  77.                                 outputStream.flush();
  78.                                 outputStream.close();
  79.                                 StringBuilder response = new StringBuilder();
  80.                                 InputStreamReader inputStreamReader = new InputStreamReader(httpsURLConnection.getInputStream());
  81.                                 int readChar = inputStreamReader.read();
  82.                                 while (-1 != readChar) {
  83.                                         response.append((char) readChar);
  84.                                         readChar = inputStreamReader.read();
  85.                                 }
  86.                                 inputStreamReader.close();
  87.                                 httpsURLConnection.disconnect();
  88.                                 logger.info(response.toString());
  89.                                 JSONObject responseJson = new JSONObject(response.toString());
  90.                                 this.weiboId = responseJson.getLong("id"); 
  91.                                 logger.info("Weibo Id = " + String.valueOf(this.weiboId));
  92.                         }
  93.                 } catch (FileNotFoundException e) {
  94.                         e.printStackTrace();
  95.                 } catch (IOException e) {
  96.                         e.printStackTrace();
  97.                 }
  98.                 
  99.         }
  100.         private void checkComment () {
  101.                 try {
  102.                         StringBuilder commentStringBuilder = new StringBuilder();
  103.                         commentStringBuilder.append("https://api.weibo.com/2/comments/show.json?filter_by_author=1&access_token=");
  104.                         commentStringBuilder.append(accessToken);
  105.                         commentStringBuilder.append("&id=");
  106.                         commentStringBuilder.append(weiboId);
  107.                         URL comment = new URL(commentStringBuilder.toString());
  108.                         URLConnection commentConnection = comment.openConnection();
  109.                         if (commentConnection instanceof HttpsURLConnection) {
  110.                                 HttpsURLConnection commentHttpsURLConnection = (HttpsURLConnection) commentConnection;
  111.                                 commentHttpsURLConnection.setDoInput(true);
  112.                                 InputStreamReader commentStreamReader = new InputStreamReader(commentHttpsURLConnection.getInputStream());
  113.                                 StringBuilder commentResponse = new StringBuilder();
  114.                                 int commentChar = commentStreamReader.read();
  115.                                 while (-1 != commentChar) {
  116.                                         commentResponse.append((char) commentChar);
  117.                                         commentChar = commentStreamReader.read();
  118.                                 }
  119.                                 commentStreamReader.close();
  120.                                 commentHttpsURLConnection.disconnect();
  121.                                 JSONObject commentsJson = new JSONObject(commentResponse.toString());
  122.                                 int total_number = commentsJson.getInt("total_number");
  123.                                 logger.info("total_number = " + String.valueOf(total_number));
  124.                                 if (0 < total_number) {
  125.                                         JSONObject commentJson = commentsJson.getJSONArray("comments").getJSONObject(0);
  126.                                         logger.info("text=" + commentJson.getString("text"));
  127.                                         this.setCode(commentJson.getString("text"));
  128.                                 }
  129.                                 
  130.                         }
  131.                 } catch (MalformedURLException e) {
  132.                         e.printStackTrace();
  133.                 } catch (IOException e) {
  134.                         e.printStackTrace();
  135.                 }
  136.         }
  137.         @Override
  138.         public void loop () {
  139.                 if (null == accessToken) {
  140.                         this.readAccessToken();
  141.                 }
  142.                 if ((null != accessToken) && (0 == weiboId)) {
  143.                         this.uploadVerifyImage();
  144.                         lastCheckTime = System.currentTimeMillis();
  145.                 }
  146.                 if ((0 < weiboId) && (this.getCode() == "") && (10000 < System.currentTimeMillis() - lastCheckTime)) {
  147.                         this.checkComment();
  148.                         lastCheckTime = System.currentTimeMillis();
  149.                 }
  150.         }
  151. }
复制代码

iQQ 学习笔记2测试 :借助新浪微博输入验证码、远程控制退出
测试本程序需要注册两个QQ号,并互相加为好友。保持一个QQ使用客户端登录,另一个QQ的QQ号和密码填写在程序中。
需要注册一个新浪微博APP帐号,需要注册两个新浪微博帐号,其中一个通过该新浪微博APP验证后保存Access Token,设定这两个帐号互相关注。
运行程序后不仅出现命令行提示,还将用一个新浪微博帐号发一条微博,另一个新浪微博帐号会显示该条微博,微博上包含有验证码图片,用另一个新浪微博帐号回复该条微博,内容为验证码图片上的文字。
在QQ上可以看到该QQ上线,如果输入logout,QQ将下线,程序自动退出。
0 0