From 1a28953bf4cd9fe5977bd50123cad57e87b67c10 Mon Sep 17 00:00:00 2001 From: ChiHoc Date: Mon, 30 Oct 2017 11:32:42 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=BF=E7=94=A8swing=E4=BB=A3=E6=9B=BF?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E4=BA=8C=E7=BB=B4=E7=A0=81=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/zhouyafeng/itchat4j/Wechat.java | 4 +- .../itchat4j/controller/LoginController.java | 19 +-- .../itchat4j/service/ILoginService.java | 3 +- .../service/impl/LoginServiceImpl.java | 81 +++++---- .../itchat4j/utils/tools/QRCodeTools.java | 158 ++++++++++++++++++ .../itchat4j/demo/demo1/MyTest.java | 15 +- .../itchat4j/demo/demo2/TulingRobot.java | 2 +- .../itchat4j/demo/demo3/PicYourFriends.java | 3 +- .../itchat4j/demo/unuseful/UnusefulDemo.java | 2 +- 9 files changed, 234 insertions(+), 53 deletions(-) create mode 100644 src/main/java/cn/zhouyafeng/itchat4j/utils/tools/QRCodeTools.java diff --git a/src/main/java/cn/zhouyafeng/itchat4j/Wechat.java b/src/main/java/cn/zhouyafeng/itchat4j/Wechat.java index baf4ee2..ff37148 100644 --- a/src/main/java/cn/zhouyafeng/itchat4j/Wechat.java +++ b/src/main/java/cn/zhouyafeng/itchat4j/Wechat.java @@ -11,13 +11,13 @@ public class Wechat { private static final Logger LOG = LoggerFactory.getLogger(Wechat.class); private IMsgHandlerFace msgHandler; - public Wechat(IMsgHandlerFace msgHandler, String qrPath) { + public Wechat(IMsgHandlerFace msgHandler) { System.setProperty("jsse.enableSNIExtension", "false"); // 防止SSL错误 this.msgHandler = msgHandler; // 登陆 LoginController login = new LoginController(); - login.login(qrPath); + login.login(); } public void start() { diff --git a/src/main/java/cn/zhouyafeng/itchat4j/controller/LoginController.java b/src/main/java/cn/zhouyafeng/itchat4j/controller/LoginController.java index 11545dd..8f6d364 100644 --- a/src/main/java/cn/zhouyafeng/itchat4j/controller/LoginController.java +++ b/src/main/java/cn/zhouyafeng/itchat4j/controller/LoginController.java @@ -13,7 +13,7 @@ /** * 登陆控制器 - * + * * @author https://github.com/yaphone * @date 创建时间:2017年5月13日 下午12:56:07 * @version 1.0 @@ -24,25 +24,22 @@ public class LoginController { private ILoginService loginService = new LoginServiceImpl(); private static Core core = Core.getInstance(); - public void login(String qrPath) { + public void login() { if (core.isAlive()) { // 已登陆 LOG.info("itchat4j已登陆"); return; } while (true) { for (int count = 0; count < 10; count++) { - LOG.info("获取UUID"); + LOG.info("1. 获取微信UUID"); while (loginService.getUuid() == null) { - LOG.info("1. 获取微信UUID"); - while (loginService.getUuid() == null) { - LOG.warn("1.1. 获取微信UUID失败,两秒后重新获取"); - SleepUtils.sleep(2000); - } + LOG.warn("1.1. 获取微信UUID失败,两秒后重新获取"); + SleepUtils.sleep(2000); } LOG.info("2. 获取登陆二维码图片"); - if (loginService.getQR(qrPath)) { + if (loginService.getQR()) { break; - } else if (count == 10) { + } else if (count == 9) { LOG.error("2.2. 获取登陆二维码图片失败,系统退出"); System.exit(0); } @@ -51,7 +48,7 @@ public void login(String qrPath) { if (!core.isAlive()) { loginService.login(); core.setAlive(true); - LOG.info(("登陆成功")); + LOG.info(("4. 登陆成功")); break; } LOG.info("4. 登陆超时,请重新扫描二维码图片"); diff --git a/src/main/java/cn/zhouyafeng/itchat4j/service/ILoginService.java b/src/main/java/cn/zhouyafeng/itchat4j/service/ILoginService.java index d902f77..13975a8 100644 --- a/src/main/java/cn/zhouyafeng/itchat4j/service/ILoginService.java +++ b/src/main/java/cn/zhouyafeng/itchat4j/service/ILoginService.java @@ -34,10 +34,9 @@ public interface ILoginService { * * @author https://github.com/yaphone * @date 2017年5月13日 上午12:13:51 - * @param qrPath * @return */ - boolean getQR(String qrPath); + boolean getQR(); /** * web初始化 diff --git a/src/main/java/cn/zhouyafeng/itchat4j/service/impl/LoginServiceImpl.java b/src/main/java/cn/zhouyafeng/itchat4j/service/impl/LoginServiceImpl.java index c68e7fb..057e2c4 100644 --- a/src/main/java/cn/zhouyafeng/itchat4j/service/impl/LoginServiceImpl.java +++ b/src/main/java/cn/zhouyafeng/itchat4j/service/impl/LoginServiceImpl.java @@ -1,7 +1,17 @@ package cn.zhouyafeng.itchat4j.service.impl; +import cn.zhouyafeng.itchat4j.utils.tools.QRCodeTools; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Date; @@ -13,6 +23,10 @@ import java.util.Random; import java.util.regex.Matcher; +import javax.imageio.ImageIO; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLabel; import org.apache.http.Consts; import org.apache.http.HttpEntity; import org.apache.http.message.BasicNameValuePair; @@ -44,7 +58,7 @@ /** * 登陆服务实现类 - * + * * @author https://github.com/yaphone * @date 创建时间:2017年5月13日 上午12:09:35 * @version 1.0 @@ -68,14 +82,15 @@ public boolean login() { boolean isLogin = false; // 组装参数和URL List params = new ArrayList(); - params.add(new BasicNameValuePair(LoginParaEnum.LOGIN_ICON.para(), LoginParaEnum.LOGIN_ICON.value())); - params.add(new BasicNameValuePair(LoginParaEnum.UUID.para(), core.getUuid())); - params.add(new BasicNameValuePair(LoginParaEnum.TIP.para(), LoginParaEnum.TIP.value())); // long time = 4000; while (!isLogin) { // SleepUtils.sleep(time += 1000); long millis = System.currentTimeMillis(); + params.clear(); + params.add(new BasicNameValuePair(LoginParaEnum.LOGIN_ICON.para(), LoginParaEnum.LOGIN_ICON.value())); + params.add(new BasicNameValuePair(LoginParaEnum.UUID.para(), core.getUuid())); + params.add(new BasicNameValuePair(LoginParaEnum.TIP.para(), LoginParaEnum.TIP.value())); params.add(new BasicNameValuePair(LoginParaEnum.R.para(), String.valueOf(millis / 1579L))); params.add(new BasicNameValuePair(LoginParaEnum._.para(), String.valueOf(millis))); HttpEntity entity = httpClient.doGet(URLEnum.LOGIN_URL.getUrl(), params, true, null); @@ -85,13 +100,21 @@ public boolean login() { String status = checklogin(result); if (ResultEnum.SUCCESS.getCode().equals(status)) { + QRCodeTools.dismissLoginCode(); processLoginInfo(result); // 处理结果 isLogin = true; core.setAlive(isLogin); break; } if (ResultEnum.WAIT_CONFIRM.getCode().equals(status)) { - LOG.info("请点击微信确认按钮,进行登陆"); + LOG.info("3.1 请点击微信确认按钮,进行登陆"); + String regEx = "window.userAvatar = 'data:img/jpg;base64,([^']+)';"; + Matcher matcher = CommonTools.getMatcher(regEx, result); + if ( matcher.find() && matcher.groupCount() == 2 ) { + BasicNameValuePair pair = new BasicNameValuePair(matcher.group(1), matcher.group(2)); + QRCodeTools.showLoginAvatar(pair.getValue()); + } + QRCodeTools.showLoginAvatar(checkAvatar(result)); } } catch (Exception e) { @@ -129,28 +152,16 @@ public String getUuid() { } @Override - public boolean getQR(String qrPath) { - qrPath = qrPath + File.separator + "QR.jpg"; + public boolean getQR() { String qrUrl = URLEnum.QRCODE_URL.getUrl() + core.getUuid(); HttpEntity entity = myHttpClient.doGet(qrUrl, null, true, null); try { - OutputStream out = new FileOutputStream(qrPath); byte[] bytes = EntityUtils.toByteArray(entity); - out.write(bytes); - out.flush(); - out.close(); - try { - CommonTools.printQr(qrPath); // 打开登陆二维码图片 - } catch (Exception e) { - LOG.info(e.getMessage()); - } - + return QRCodeTools.showLoginCode(bytes); } catch (Exception e) { LOG.info(e.getMessage()); return false; } - - return true; } @Override @@ -446,12 +457,26 @@ public String checklogin(String result) { return null; } + /** + * 检查头像 + * + * @param result + * @return + */ + public String checkAvatar(String result) { + String regEx = "window.userAvatar = 'data:img/jpg;base64,([^']+)';"; + Matcher matcher = CommonTools.getMatcher(regEx, result); + if (matcher.find()) { + return matcher.group(1); + } + return null; + } + /** * 处理登陆信息 * * @author https://github.com/yaphone * @date 2017年4月9日 下午12:16:26 - * @param result */ private void processLoginInfo(String loginContent) { String regEx = "window.redirect_uri=\"(\\S+)\";"; @@ -522,7 +547,7 @@ private Map> getPossibleUrlMap() { Map> possibleUrlMap = new HashMap>(); possibleUrlMap.put("wx.qq.com", new ArrayList() { /** - * + * */ private static final long serialVersionUID = 1L; @@ -534,7 +559,7 @@ private Map> getPossibleUrlMap() { possibleUrlMap.put("wx2.qq.com", new ArrayList() { /** - * + * */ private static final long serialVersionUID = 1L; @@ -545,7 +570,7 @@ private Map> getPossibleUrlMap() { }); possibleUrlMap.put("wx8.qq.com", new ArrayList() { /** - * + * */ private static final long serialVersionUID = 1L; @@ -557,7 +582,7 @@ private Map> getPossibleUrlMap() { possibleUrlMap.put("web2.wechat.com", new ArrayList() { /** - * + * */ private static final long serialVersionUID = 1L; @@ -568,7 +593,7 @@ private Map> getPossibleUrlMap() { }); possibleUrlMap.put("wechat.com", new ArrayList() { /** - * + * */ private static final long serialVersionUID = 1L; @@ -582,7 +607,7 @@ private Map> getPossibleUrlMap() { /** * 同步消息 sync the messages - * + * * @author https://github.com/yaphone * @date 2017年5月12日 上午12:24:55 * @return @@ -627,11 +652,11 @@ private JSONObject webWxSync() { /** * 检查是否有新消息 check whether there's a message - * + * * @author https://github.com/yaphone * @date 2017年4月16日 上午11:11:34 * @return - * + * */ private Map syncCheck() { Map resultMap = new HashMap(); diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/tools/QRCodeTools.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/tools/QRCodeTools.java new file mode 100644 index 0000000..5865bc7 --- /dev/null +++ b/src/main/java/cn/zhouyafeng/itchat4j/utils/tools/QRCodeTools.java @@ -0,0 +1,158 @@ +package cn.zhouyafeng.itchat4j.utils.tools; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import javax.imageio.ImageIO; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.WindowConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sun.misc.BASE64Decoder; + +public class QRCodeTools { + + private static Logger logger = LoggerFactory.getLogger(QRCodeTools.class); + private static JFrame frameInstance; + private static int FRAME_WIDTH = 300; + private static int FRAME_HEIGHT = 400; + + /** + * 获取JFrame单例 + * + * @return + */ + public static JFrame getFrameInstance() { + synchronized (JFrame.class) { + if ( frameInstance == null ) { + frameInstance = new JFrame(); + frameInstance.getContentPane().setBackground(Color.WHITE); + frameInstance.setResizable(false); + frameInstance.setLayout(null); + frameInstance.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + frameInstance.setSize(FRAME_WIDTH, FRAME_HEIGHT); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + frameInstance.setLocation( + dim.width / 2 - FRAME_WIDTH / 2, dim.height / 2 - FRAME_HEIGHT / 2); + frameInstance.setVisible(true); + } + } + return frameInstance; + } + + /** + * 显示登录二维码 + * + * @return + */ + public static boolean showLoginCode( byte[] bytes ) { + + int CODE_WIDTH = 190; + int CODE_HEIGHT = 190; + int CODE_MARGIN_TOP = 40; + + BufferedImage resizedImg; + InputStream inputStream = new ByteArrayInputStream(bytes); + try { + resizedImg = new BufferedImage(CODE_WIDTH, CODE_HEIGHT, BufferedImage.TYPE_INT_RGB); + Graphics2D graphics2D = resizedImg.createGraphics(); + graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + graphics2D.drawImage(ImageIO.read(inputStream), 0, 0, CODE_WIDTH, CODE_HEIGHT, null); + graphics2D.dispose(); + } catch (IOException e) { + logger.info(e.getMessage()); + return false; + } + JLabel codeLabel = new JLabel(); + codeLabel.setIcon(new ImageIcon(resizedImg)); + codeLabel.setSize(CODE_WIDTH, CODE_HEIGHT); + codeLabel.setLocation(( FRAME_WIDTH - CODE_WIDTH ) / 2, CODE_MARGIN_TOP); + + JLabel tipsLabel = new JLabel("扫码登录微信"); + tipsLabel.setFont(new Font("Dialog", Font.PLAIN, 20)); + tipsLabel.setSize(FRAME_WIDTH, 20); + tipsLabel.setHorizontalAlignment(JLabel.CENTER); + tipsLabel.setLocation(0, CODE_MARGIN_TOP * 2 + CODE_HEIGHT); + + JFrame frame = getFrameInstance(); + frame.getContentPane().removeAll(); + frame.getContentPane().repaint(); + + frame.getContentPane().add(codeLabel); + frame.getContentPane().add(tipsLabel); + + frame.validate(); + return true; + } + + /** + * 显示登录头像 + */ + public static void showLoginAvatar( String imageBase64Data ) { + + int AVATAR_WIDTH = 100; + int AVATAR_HEIGHT = 100; + int CODE_MARGIN_TOP = 78; + + BufferedImage resizedImg; + BASE64Decoder decoder = new BASE64Decoder(); + try { + byte[] imageByte = decoder.decodeBuffer(imageBase64Data); + InputStream inputStream = new ByteArrayInputStream(imageByte); + resizedImg = new BufferedImage(AVATAR_WIDTH, AVATAR_HEIGHT, BufferedImage.TYPE_INT_RGB); + Graphics2D graphics2D = resizedImg.createGraphics(); + graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + graphics2D.drawImage(ImageIO.read(inputStream), 0, 0, AVATAR_WIDTH, AVATAR_HEIGHT, null); + graphics2D.dispose(); + } catch (IOException e) { + logger.info(e.getMessage()); + return; + } + JLabel codeLabel = new JLabel(); + codeLabel.setIcon(new ImageIcon(resizedImg)); + codeLabel.setSize(AVATAR_WIDTH, AVATAR_HEIGHT); + codeLabel.setLocation(( FRAME_WIDTH - AVATAR_HEIGHT ) / 2, CODE_MARGIN_TOP); + + JLabel tipsLabel = new JLabel("扫描成功"); + tipsLabel.setFont(new Font("Dialog", Font.PLAIN, 20)); + tipsLabel.setForeground(new Color(0x26AB28)); + tipsLabel.setSize(FRAME_WIDTH, 20); + tipsLabel.setHorizontalAlignment(JLabel.CENTER); + tipsLabel.setLocation(0, CODE_MARGIN_TOP + AVATAR_HEIGHT + 30); + + JLabel subTipsLabel = new JLabel("请在手机微信中点击登录"); + subTipsLabel.setFont(new Font("Dialog", Font.PLAIN, 14)); + subTipsLabel.setForeground(new Color(0x888888)); + subTipsLabel.setSize(FRAME_WIDTH, 20); + subTipsLabel.setHorizontalAlignment(JLabel.CENTER); + subTipsLabel.setLocation(0, CODE_MARGIN_TOP + AVATAR_HEIGHT + 60); + + JFrame frame = getFrameInstance(); + frame.getContentPane().removeAll(); + frame.getContentPane().repaint(); + + frame.getContentPane().add(codeLabel); + frame.getContentPane().add(tipsLabel); + frame.getContentPane().add(subTipsLabel); + } + + /** + * 清除JFrame + */ + public static void dismissLoginCode() { + if ( frameInstance != null ) { + frameInstance.setVisible(false); + frameInstance.dispose(); + frameInstance = null; + } + } +} diff --git a/src/test/java/cn/zhouyafeng/itchat4j/demo/demo1/MyTest.java b/src/test/java/cn/zhouyafeng/itchat4j/demo/demo1/MyTest.java index d587969..17f5635 100644 --- a/src/test/java/cn/zhouyafeng/itchat4j/demo/demo1/MyTest.java +++ b/src/test/java/cn/zhouyafeng/itchat4j/demo/demo1/MyTest.java @@ -2,19 +2,22 @@ import cn.zhouyafeng.itchat4j.Wechat; import cn.zhouyafeng.itchat4j.face.IMsgHandlerFace; +import cn.zhouyafeng.itchat4j.utils.enums.ResultEnum; +import cn.zhouyafeng.itchat4j.utils.tools.CommonTools; +import cn.zhouyafeng.itchat4j.utils.tools.QRCodeTools; +import java.util.regex.Matcher; +import org.apache.http.message.BasicNameValuePair; /** - * * @author https://github.com/yaphone - * @date 创建时间:2017年4月28日 上午12:44:10 * @version 1.0 - * + * @date 创建时间:2017年4月28日 上午12:44:10 */ public class MyTest { - public static void main(String[] args) { - String qrPath = "D://itchat4j//login"; // 保存登陆二维码图片的路径,这里需要在本地新建目录 + + public static void main( String[] args ) { IMsgHandlerFace msgHandler = new SimpleDemo(); // 实现IMsgHandlerFace接口的类 - Wechat wechat = new Wechat(msgHandler, qrPath); // 【注入】 + Wechat wechat = new Wechat(msgHandler); // 【注入】 wechat.start(); // 启动服务,会在qrPath下生成一张二维码图片,扫描即可登陆,注意,二维码图片如果超过一定时间未扫描会过期,过期时会自动更新,所以你可能需要重新打开图片 } } diff --git a/src/test/java/cn/zhouyafeng/itchat4j/demo/demo2/TulingRobot.java b/src/test/java/cn/zhouyafeng/itchat4j/demo/demo2/TulingRobot.java index 1fa6cc6..6fdfb58 100644 --- a/src/test/java/cn/zhouyafeng/itchat4j/demo/demo2/TulingRobot.java +++ b/src/test/java/cn/zhouyafeng/itchat4j/demo/demo2/TulingRobot.java @@ -81,7 +81,7 @@ public String viedoMsgHandle(BaseMsg msg) { public static void main(String[] args) { IMsgHandlerFace msgHandler = new TulingRobot(); - Wechat wechat = new Wechat(msgHandler, "D://itchat4j/login"); + Wechat wechat = new Wechat(msgHandler); wechat.start(); } diff --git a/src/test/java/cn/zhouyafeng/itchat4j/demo/demo3/PicYourFriends.java b/src/test/java/cn/zhouyafeng/itchat4j/demo/demo3/PicYourFriends.java index 50e23a1..9c86bff 100644 --- a/src/test/java/cn/zhouyafeng/itchat4j/demo/demo3/PicYourFriends.java +++ b/src/test/java/cn/zhouyafeng/itchat4j/demo/demo3/PicYourFriends.java @@ -99,9 +99,8 @@ public void sysMsgHandle(BaseMsg msg) { } public static void main(String[] args) { - String qrPath = "D://itchat4j//login"; // 保存登陆二维码图片的路径,这里需要在本地新建目录 IMsgHandlerFace msgHandler = new PicYourFriends(); // 实现IMsgHandlerFace接口的类 - Wechat wechat = new Wechat(msgHandler, qrPath); // 【注入】 + Wechat wechat = new Wechat(msgHandler); // 【注入】 wechat.start(); // 启动服务,会在qrPath下生成一张二维码图片,扫描即可登陆,注意,二维码图片如果超过一定时间未扫描会过期,过期时会自动更新,所以你可能需要重新打开图片 } diff --git a/src/test/java/cn/zhouyafeng/itchat4j/demo/unuseful/UnusefulDemo.java b/src/test/java/cn/zhouyafeng/itchat4j/demo/unuseful/UnusefulDemo.java index fe1625d..ceac859 100644 --- a/src/test/java/cn/zhouyafeng/itchat4j/demo/unuseful/UnusefulDemo.java +++ b/src/test/java/cn/zhouyafeng/itchat4j/demo/unuseful/UnusefulDemo.java @@ -63,7 +63,7 @@ public String nameCardMsgHandle(BaseMsg msg) { public static void main(String[] args) { IMsgHandlerFace msgHandler = new UnusefulDemo(); - Wechat wechat = new Wechat(msgHandler, "D://itchat4j/login"); + Wechat wechat = new Wechat(msgHandler); wechat.start(); }