zoukankan      html  css  js  c++  java
  • iQQ 学习笔记2 :借助新浪微博输入验证码、远程控制退出

    iQQ 学习笔记声明
    本文仅供学习研究使用,不得用于任何非法及侵权用途。
    转贴请注明原发位置: http://xuekaiyuan.com/forum.php?mod=viewthread&tid=5
    讨论请加QQ群:306320259


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


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

    package test_2;
    
    import java.util.logging.Logger;
    
    import iqq.im.QQClient;
    import iqq.im.QQException;
    import iqq.im.QQNotifyListener;
    import iqq.im.WebQQClient;
    import iqq.im.actor.ThreadActorDispatcher;
    import iqq.im.bean.QQMsg;
    import iqq.im.bean.QQStatus;
    import iqq.im.bean.content.ContentItem;
    import iqq.im.bean.content.TextItem;
    import iqq.im.event.QQActionEvent;
    import iqq.im.event.QQActionFuture;
    import iqq.im.event.QQNotifyEvent;
    import iqq.im.event.QQNotifyEventArgs;
    import iqq.im.event.QQActionEvent.Type;
    
    public class Test_2 {
    	private static final String username = "**********";
    	private static final String password = "**********";
    	private static final Logger logger = java.util.logging.Logger.getLogger("");
    	private static QQClient client;
    	public static void main(String[] args) {
    		client = new WebQQClient(username, password, new QQNotifyListener() {
    			@Override
    			public void onNotifyEvent(QQNotifyEvent event) {
    				if (event.getType() == QQNotifyEvent.Type.CHAT_MSG) {
    					if (event.getTarget() instanceof QQMsg) {
    						QQMsg msg = (QQMsg) event.getTarget();
    						for (ContentItem contentItem : msg.getContentList()) {
    							if (contentItem instanceof TextItem) {
    								TextItem textItem = (TextItem) contentItem;
    								logger.info(textItem.getContent());
    								if (textItem.getContent().startsWith("logout ")) {
    									client.logout(null);
    								}									
    							}
    						}
    					}
    				} else if (event.getType() == QQNotifyEvent.Type.CAPACHA_VERIFY) {
    					if (event.getTarget() instanceof QQNotifyEventArgs.ImageVerify) {
    						QQNotifyEventArgs.ImageVerify imageVerify = (QQNotifyEventArgs.ImageVerify) event.getTarget();
    						String code = ImageVerifyQuestioners.ImageVeiryQuestion(imageVerify);
    						client.submitVerify(code, event);
    					} else {
    						logger.info(event.getTarget().getClass().getName());
    					}
    				} else {
    					logger.info("TODO QQNotifyEvent: " + event.getType() + ", " + event.getTarget());
    				}
    			}
    		}, new ThreadActorDispatcher());
    		QQActionFuture future = client.login(QQStatus.ONLINE, null);
    		try {
    			QQActionEvent event = future.waitFinalEvent();
    			if (event.getType() == Type.EVT_OK) {
    				client.beginPollMsg();
    			}
    		} catch (QQException e) {
    			e.printStackTrace();
    		}
    	}
    }

    为了便于实现多种图片验证码的输入方式,设计一个图片验证码接口。

    package test_2;
    
    import iqq.im.event.QQNotifyEventArgs.ImageVerify;
    
    public abstract class ImageVerifyQuestioner {
    	private ImageVerify imageVerify;
    	private String Code;
    	public ImageVerifyQuestioner(ImageVerify imageVerify) {
    		this.imageVerify = imageVerify;
    		this.Code = "";
    	}
    	protected final ImageVerify getImageVerify() {
    		return imageVerify;
    	}
    	public final String getCode() {
    		return Code;
    	}
    	protected final void setCode(String code) {
    		Code = code;
    	}
    	public abstract void loop ();
    }

    通过一个调度程序管理多种图片验证码的输入方式,当一种输入方式获取验证码时,其他输入方式退出。

    package test_2;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import iqq.im.event.QQNotifyEventArgs.ImageVerify;
    
    public class ImageVerifyQuestioners {
    	public static String ImageVeiryQuestion (ImageVerify imageVerify) {
    		String code = "";
    		List<ImageVerifyQuestioner> imageVerifyQuestionerList = new ArrayList<ImageVerifyQuestioner>();
    		imageVerifyQuestionerList.add(new ImageVerifyConsoleQuestioner(imageVerify));
    		imageVerifyQuestionerList.add(new ImageVerifyWeiboQuestioner(imageVerify));
    		boolean alive = true;
    		while (alive) {
    			for(ImageVerifyQuestioner imageVerifyQuestioner : imageVerifyQuestionerList) {
    				if (true == alive) {
    					imageVerifyQuestioner.loop();
    					if (imageVerifyQuestioner.getCode() != "") {
    						code = imageVerifyQuestioner.getCode();
    						alive = false;
    					}					
    				}
    			}
    			try {
    				Thread.sleep(100);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    		return code;
    	}
    }

    保持原有的命令行交互输入图片验证码的输入方式。

    /**
     * 
     */
    package test_2;
    
    import java.io.File;
    import java.io.IOException;
    import javax.imageio.ImageIO;
    
    import iqq.im.event.QQNotifyEventArgs.ImageVerify;
    
    public class ImageVerifyConsoleQuestioner extends ImageVerifyQuestioner {
    	private boolean isPrompt;
    	private StringBuilder codeStringBuilder = new StringBuilder();
    	public ImageVerifyConsoleQuestioner(ImageVerify imageVerify) {
    		super(imageVerify);
    	}
    	private void prompt () {
    		try {
    			ImageIO.write(this.getImageVerify().image, "png", new File("verify.png"));
    			System.out.println(this.getImageVerify().reason);
    			System.out.print("请输入在项目根目录下 verify.png 图片里面的验证码: ");
    			isPrompt = true;
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    	private void read () {
    		try {
    			int available = System.in.available();
    			if (0 < available) {
    				int inChar = System.in.read();
    				switch (Character.getType(inChar)) {
    				case Character.UPPERCASE_LETTER:
    				case Character.LOWERCASE_LETTER:
    				case Character.DECIMAL_DIGIT_NUMBER:
    					codeStringBuilder.append((char) inChar);
    					break;
    				case Character.CONTROL:
    					this.setCode(codeStringBuilder.toString());
    					break;
    				}
    			}
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    	@Override
    	public void loop() {
    		if (false == this.isPrompt) {
    			this.prompt();
    		}
    		if (this.getCode() == "") {
    			this.read();					
    		}		
    	}
    }

    新增通过新浪微博输入图片验证码的输入方式,其中的accessTokenFile的值应替换为保存新浪微博Access Token的路径。

    /**
     * 
     */
    package test_2;
    
    import java.io.BufferedReader;
    import java.io.ByteArrayOutputStream;
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLConnection;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.logging.Logger;
    
    import javax.imageio.ImageIO;
    import javax.net.ssl.HttpsURLConnection;
    
    import org.json.JSONObject;
    
    import iqq.im.event.QQNotifyEventArgs.ImageVerify;
    
    public class ImageVerifyWeiboQuestioner extends ImageVerifyQuestioner {
    	private static final String accessTokenFile = "**********";
    	private static final Logger logger = java.util.logging.Logger.getLogger("");
    	private String accessToken;
    	private long weiboId;
    	private long lastCheckTime;
    	public ImageVerifyWeiboQuestioner(ImageVerify imageVerify) {
    		super(imageVerify);
    	}
    	private void readAccessToken () {
    		FileReader fileReaderAccessToken;
    		try {
    			fileReaderAccessToken = new FileReader(accessTokenFile);
    			BufferedReader bufferedReaderAccessToken = new BufferedReader(fileReaderAccessToken);
    			accessToken = bufferedReaderAccessToken.readLine();
    			bufferedReaderAccessToken.close();
    			fileReaderAccessToken.close();
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    	private void uploadVerifyImage () {
    		try {
    			//Status
    			StringBuilder statusStringBuilder = new StringBuilder();
    			statusStringBuilder.append("请@胡争辉 输入验证码 ");
    			statusStringBuilder.append((new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(new Date())); 
    			//URL
    			StringBuilder urlStringBuilder = new StringBuilder();
    			urlStringBuilder.append("https://api.weibo.com/2/statuses/upload.json?access_token=");
    			urlStringBuilder.append(accessToken);
    			URL url = new URL(urlStringBuilder.toString());
    			URLConnection urlConnection =url.openConnection();
    			if (urlConnection instanceof HttpsURLConnection) {
    				String BOUNDARY = "---------------------------" + String.valueOf(System.currentTimeMillis());
    				ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    				byteArrayOutputStream.write(("--" + BOUNDARY + "\r\n").getBytes());
    				byteArrayOutputStream.write(("Content-Disposition: form-data; name=\"pic\"; filename=\"verifyimage.png\"\r\n").getBytes());
    				byteArrayOutputStream.write(("Content-Type: image/png\r\n").getBytes());
    				byteArrayOutputStream.write(("\r\n").getBytes());
    				ImageIO.write(this.getImageVerify().image, "png", byteArrayOutputStream);
    				byteArrayOutputStream.write(("\r\n").getBytes());
    				byteArrayOutputStream.write(("--" + BOUNDARY + "\r\n").getBytes());
    				byteArrayOutputStream.write(("Content-Disposition: form-data; name=\"status\"\r\n").getBytes());
    				byteArrayOutputStream.write(("\r\n").getBytes());
    				byteArrayOutputStream.write(statusStringBuilder.toString().getBytes());
    				byteArrayOutputStream.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes());
    				HttpsURLConnection httpsURLConnection = (HttpsURLConnection) urlConnection;
    				httpsURLConnection.setRequestMethod("POST");
    				httpsURLConnection.addRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
    				httpsURLConnection.setDoOutput(true);
    				httpsURLConnection.setDoInput(true);
    				OutputStream outputStream = httpsURLConnection.getOutputStream();
    				outputStream.write(byteArrayOutputStream.toByteArray());
    				outputStream.flush();
    				outputStream.close();
    				StringBuilder response = new StringBuilder();
    				InputStreamReader inputStreamReader = new InputStreamReader(httpsURLConnection.getInputStream());
    				int readChar = inputStreamReader.read();
    				while (-1 != readChar) {
    					response.append((char) readChar);
    					readChar = inputStreamReader.read();
    				}
    				inputStreamReader.close();
    				httpsURLConnection.disconnect();
    				logger.info(response.toString());
    				JSONObject responseJson = new JSONObject(response.toString());
    				this.weiboId = responseJson.getLong("id"); 
    				logger.info("Weibo Id = " + String.valueOf(this.weiboId));
    			}
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		
    	}
    	private void checkComment () {
    		try {
    			StringBuilder commentStringBuilder = new StringBuilder();
    			commentStringBuilder.append("https://api.weibo.com/2/comments/show.json?filter_by_author=1&access_token=");
    			commentStringBuilder.append(accessToken);
    			commentStringBuilder.append("&id=");
    			commentStringBuilder.append(weiboId);
    			URL comment = new URL(commentStringBuilder.toString());
    			URLConnection commentConnection = comment.openConnection();
    			if (commentConnection instanceof HttpsURLConnection) {
    				HttpsURLConnection commentHttpsURLConnection = (HttpsURLConnection) commentConnection;
    				commentHttpsURLConnection.setDoInput(true);
    				InputStreamReader commentStreamReader = new InputStreamReader(commentHttpsURLConnection.getInputStream());
    				StringBuilder commentResponse = new StringBuilder();
    				int commentChar = commentStreamReader.read();
    				while (-1 != commentChar) {
    					commentResponse.append((char) commentChar);
    					commentChar = commentStreamReader.read();
    				}
    				commentStreamReader.close();
    				commentHttpsURLConnection.disconnect();
    				JSONObject commentsJson = new JSONObject(commentResponse.toString());
    				int total_number = commentsJson.getInt("total_number");
    				logger.info("total_number = " + String.valueOf(total_number));
    				if (0 < total_number) {
    					JSONObject commentJson = commentsJson.getJSONArray("comments").getJSONObject(0);
    					logger.info("text=" + commentJson.getString("text"));
    					this.setCode(commentJson.getString("text"));
    				}
    				
    			}
    		} catch (MalformedURLException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    	@Override
    	public void loop () {
    		if (null == accessToken) {
    			this.readAccessToken();
    		}
    		if ((null != accessToken) && (0 == weiboId)) {
    			this.uploadVerifyImage();
    			lastCheckTime = System.currentTimeMillis();
    		}
    		if ((0 < weiboId) && (this.getCode() == "") && (10000 < System.currentTimeMillis() - lastCheckTime)) {
    			this.checkComment();
    			lastCheckTime = System.currentTimeMillis();
    		}
    	}
    }

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

  • 相关阅读:
    js
    DOM
    css
    html
    java虚拟机
    java并发
    java容器
    java基础
    计算机网络面试题
    计算机操作系统-设备管理
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3113109.html
Copyright © 2011-2022 走看看