QQ扫码登录实现与原理
生活随笔
收集整理的這篇文章主要介紹了
QQ扫码登录实现与原理
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
二維碼
掃碼原理
實(shí)現(xiàn)代碼
工具類
1
import com.google.zxing.LuminanceSource;import java.awt.*;import java.awt.geom.AffineTransform;import java.awt.image.BufferedImage;public class BufferedImageLuminanceSource extends LuminanceSource {private final BufferedImage image;private final int left;private final int top;public BufferedImageLuminanceSource(BufferedImage image) {this(image, 0, 0, image.getWidth(), image.getHeight());}public BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width, int height) {super(width, height);int sourceWidth = image.getWidth();int sourceHeight = image.getHeight();if (left + width > sourceWidth || top + height > sourceHeight) {throw new IllegalArgumentException("Crop rectangle does not fit within image data.");}for (int y = top; y < top + height; y++) {for (int x = left; x < left + width; x++) {if ((image.getRGB(x, y) & 0xFF000000) == 0) {image.setRGB(x, y, 0xFFFFFFFF); // = white}}}this.image = new BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE_BYTE_GRAY);this.image.getGraphics().drawImage(image, 0, 0, null);this.left = left;this.top = top;}public byte[] getRow(int y, byte[] row) {if (y < 0 || y >= getHeight()) {throw new IllegalArgumentException("Requested row is outside the image: " + y);}int width = getWidth();if (row == null || row.length < width) {row = new byte[width];}image.getRaster().getDataElements(left, top + y, width, 1, row);return row;}public byte[] getMatrix() {int width = getWidth();int height = getHeight();int area = width * height;byte[] matrix = new byte[area];image.getRaster().getDataElements(left, top, width, height, matrix);return matrix;}public boolean isCropSupported() {return true;}public LuminanceSource crop(int left, int top, int width, int height) {return new BufferedImageLuminanceSource(image, this.left + left, this.top + top, width, height);}public boolean isRotateSupported() {return true;}public LuminanceSource rotateCounterClockwise() {int sourceWidth = image.getWidth();int sourceHeight = image.getHeight();AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth);BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, BufferedImage.TYPE_BYTE_GRAY);Graphics2D g = rotatedImage.createGraphics();g.drawImage(image, transform, null);g.dispose();int width = getWidth();return new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth - (left + width), getHeight(), width);}}2
import com.google.zxing.*;import com.google.zxing.common.BitMatrix;import com.google.zxing.common.HybridBinarizer;import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;import javax.imageio.ImageIO;import java.awt.*;import java.awt.geom.RoundRectangle2D;import java.awt.image.BufferedImage;import java.io.File;import java.io.OutputStream;import java.util.Hashtable;public class QRCodeUtil {private static final String CHARSET = "utf-8";private static final String FORMAT_NAME = "JPG";// 二維碼尺寸private static final int QRCODE_SIZE = 300;// LOGO寬度private static final int WIDTH = 60;// LOGO高度private static final int HEIGHT = 60;public static BufferedImage createImage(String content, String imgPath, boolean needCompress) throws Exception {Hashtable hints = new Hashtable();hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);hints.put(EncodeHintType.CHARACTER_SET, CHARSET);hints.put(EncodeHintType.MARGIN, 1);BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE,hints);int width = bitMatrix.getWidth();int height = bitMatrix.getHeight();BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);for (int x = 0; x < width; x++) {for (int y = 0; y < height; y++) {image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);}}if (imgPath == null || "".equals(imgPath)) {return image;}// 插入圖片QRCodeUtil.insertImage(image, imgPath, needCompress);return image;}private static void insertImage(BufferedImage source, String imgPath, boolean needCompress) throws Exception {File file = new File(imgPath);if (!file.exists()) {System.err.println("" + imgPath + " 該文件不存在!");return;}Image src = ImageIO.read(new File(imgPath));int width = src.getWidth(null);int height = src.getHeight(null);if (needCompress) { // 壓縮LOGOif (width > WIDTH) {width = WIDTH;}if (height > HEIGHT) {height = HEIGHT;}Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);Graphics g = tag.getGraphics();g.drawImage(image, 0, 0, null); // 繪制縮小后的圖g.dispose();src = image;}// 插入LOGOGraphics2D graph = source.createGraphics();int x = (QRCODE_SIZE - width) / 2;int y = (QRCODE_SIZE - height) / 2;graph.drawImage(src, x, y, width, height, null);Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);graph.setStroke(new BasicStroke(3f));graph.draw(shape);graph.dispose();}public static void encode(String content, String imgPath, String destPath, boolean needCompress) throws Exception {BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);mkdirs(destPath);// String file = new Random().nextInt(99999999)+".jpg";// ImageIO.write(image, FORMAT_NAME, new File(destPath+"/"+file));ImageIO.write(image, FORMAT_NAME, new File(destPath));}public BufferedImage encode(String content, String imgPath, boolean needCompress) throws Exception {BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);return image;}public static void mkdirs(String destPath) {File file = new File(destPath);// 當(dāng)文件夾不存在時(shí),mkdirs會(huì)自動(dòng)創(chuàng)建多層目錄,區(qū)別于mkdir.(mkdir如果父目錄不存在則會(huì)拋出異常)if (!file.exists() && !file.isDirectory()) {file.mkdirs();}}public static void encode(String content, String imgPath, String destPath) throws Exception {QRCodeUtil.encode(content, imgPath, destPath, false);}// 被注釋的方法/** public static void encode(String content, String destPath, boolean* needCompress) throws Exception { QRCodeUtil.encode(content, null, destPath,* needCompress); }*/public static void encode(String content, String destPath) throws Exception {QRCodeUtil.encode(content, null, destPath, false);}public static void encode(String content, String imgPath, OutputStream output, boolean needCompress)throws Exception {BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);ImageIO.write(image, FORMAT_NAME, output);}public static void encode(String content, OutputStream output) throws Exception {QRCodeUtil.encode(content, null, output, false);}public static String decode(File file) throws Exception {BufferedImage image;image = ImageIO.read(file);if (image == null) {return null;}BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));Result result;Hashtable hints = new Hashtable();hints.put(DecodeHintType.CHARACTER_SET, CHARSET);result = new MultiFormatReader().decode(bitmap, hints);String resultStr = result.getText();return resultStr;}public static String decode(String path) throws Exception {return QRCodeUtil.decode(new File(path));}}3
@Componentpublic class RedisUtils {@Autowiredprivate StringRedisTemplate stringRedisTemplate;public void set(String key, Object object, Long time) {// 讓該方法能夠支持多種數(shù)據(jù)類型存放if (object instanceof String) {setString(key, object);}// 如果存放時(shí)Set類型if (object instanceof Set) {setSet(key, object);}// 設(shè)置有效期if (time != null) {stringRedisTemplate.expire(key, time, TimeUnit.SECONDS);}}public void setString(String key, Object object) {String value = (String) object;// 存放string類型stringRedisTemplate.opsForValue().set(key, value);}public void setSet(String key, Object object) {Set<String> valueSet = (Set<String>) object;for (String string : valueSet) {stringRedisTemplate.opsForSet().add(key, string);}}public String getString(String key) {return stringRedisTemplate.opsForValue().get(key);}public boolean delete(String key) {return stringRedisTemplate.delete(key);}}pom 多加如下依賴
<dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.3.0</version></dependency><!-- 集成redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!--freemarker--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency>yml
server:servlet:context-path: /port: 8088 spring:application:name: utilsredis:database: 0host: 127.0.0.1port: 6379password: rootfreemarker:allow-request-override: falsecache: falsecheck-template-location: truecharset: UTF-8content-type: text/html; charset=utf-8expose-request-attributes: falseexpose-session-attributes: falseexpose-spring-macro-helpers: falsesuffix: .ftltemplate-loader-path: classpath:/templates #token更新地址,此地址需要外網(wǎng)地址才行,使用natapp穿透下 https://blog.csdn.net/qq_40673786/article/details/90298955 baseImgUrl: http://xdc5z3.natappfree.cc/updateTokenState?token= #二維碼log圖片地址 bgImgPath: F:/a.jpgQRCodeController
@Controller public class QRCodeController {@Autowiredprivate RedisUtils redisUtils;@Value("${baseImgUrl}")private String baseImgUrl;@Value("${bgImgPath}")private String bgImgPath;//生成token地址@RequestMapping(value = "/generateCode")@ResponseBodypublic String generateCode() throws Exception {// 1.生成token令牌String token = UUID.randomUUID().toString().replace("-", "");// 2.存入到redis中redisUtils.setString(token, "0");// 3.生成圖形驗(yàn)證碼 在驗(yàn)證碼中傳遞該參數(shù)String codeText = baseImgUrl + token;String destPath = "F:/code/" + token + ".png";// 4.將二維碼寫入到本地文件中QRCodeUtil.encode(codeText, bgImgPath, destPath, true);return token;}//獲取生成的二維碼圖片@RequestMapping(value = "/getCodeImg", produces = MediaType.IMAGE_JPEG_VALUE)@ResponseBodypublic byte[] getCodeImg(String token) throws IOException {File file = new File("F:/code/" + token + ".png");FileInputStream inputStream = new FileInputStream(file);byte[] bytes = new byte[inputStream.available()];inputStream.read(bytes, 0, inputStream.available());return bytes;}//跳到掃碼頁@RequestMapping("/")public String index(String token, HttpServletRequest request) {request.setAttribute("token", token);return "index";}//掃描二維碼時(shí)調(diào)用此接口,二維碼內(nèi)容即此接口地址@RequestMapping("/updateTokenState")@ResponseBodypublic String updateTokenState(String token) {if (StringUtils.isEmpty(token)) {return "掃碼登陸失敗!";}// 將token狀態(tài)改為1redisUtils.setString(token, "1");return "掃碼登陸成功!";}//前端檢測redistoken是否被更改,即是否已經(jīng)掃過碼了@RequestMapping("/checkToken")@ResponseBodypublic boolean checkToken(String token) {if (StringUtils.isEmpty(token)) {return false;}String redisValue = redisUtils.getString(token);if (StringUtils.isEmpty(redisValue)) {return false;}if (!redisValue.equals("1")) {return false;}return true;}//掃過碼之后要跳轉(zhuǎn)的地址@ResponseBody@RequestMapping("/sweepCode")public String sweepCode() {return "掃碼登錄成功!";} }App
@SpringBootApplication public class App {public static void main(String[] args) {SpringApplication.run(App.class, args);} }index.ftl 此ftl在resources/templates文件夾下
<h1>掃一下該二維碼,實(shí)現(xiàn)掃碼登陸</h1><img src="getCodeImg?token=${token}"> <script src="http://code.jquery.com/jquery-latest.js"></script> <script>function checkToken() {// alert('1000');$.ajax({url: "checkToken?token=${token}",dataType: "json",type: "get",async: "false",success: function (data) {if (data == true) {window.location.href = '/sweepCode';}},error: function () {}});}setInterval(checkToken, 2000);</script>測試 前提 1、啟動(dòng)redis 2、生成外網(wǎng)地址
第一步
http://localhost:8088/generateCode 生成token
第二步
http://localhost:8088/?token=上述生成的token
查看生成到本地F://code/下的的二維碼
http://localhost:8088/getCodeImg?token=上述生成的token
思想來源
www.mayikt.com/
總結(jié)
以上是生活随笔為你收集整理的QQ扫码登录实现与原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: html设置一个搜索引擎,零基础打造一款
- 下一篇: bigworld引擎