网站团购报名怎么做,做网站的平台,wordpress图片主题下载,做招聘网站需要什么人员一、前言 这几天在研究二维码的扫码登录。初来乍到#xff0c;还有好多东西不懂。在网上看到有人写了一些通过QRCode或者Zxing实现二维码的生成和解码。一时兴起#xff0c;决定自己亲手试一试。本人是通过QRCode实现的#xff0c;下面具体的说一下。 二、二维码原理 基础知… 一、前言 这几天在研究二维码的扫码登录。初来乍到还有好多东西不懂。在网上看到有人写了一些通过QRCode或者Zxing实现二维码的生成和解码。一时兴起决定自己亲手试一试。本人是通过QRCode实现的下面具体的说一下。 二、二维码原理 基础知识参考http://news.cnblogs.com/n/191671/ 很重要的一部分知识二维码一共有 40 个尺寸。官方叫版本 Version。Version 1 是 21 x 21 的矩阵Version 2 是 25 x 25 的矩阵Version 3 是 29 的尺寸每增加一个 version就会增加 4 的尺寸公式是(V-1)*4 21V是版本号 最高 Version 40(40-1)*421 177所以最高是 177 x 177 的正方形。 三、二维码生成和解码工具 1.效果如下图所示。 生成二维码不含有logo 生成二维码带有logo 对应的解码 工具很简单但是很实用。界面还可以美化功能还可以加强初心只是为了练习一下二维码的生成和解析。 2.二维码生成和解析的核心类 import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;import javax.imageio.ImageIO;import com.swetake.util.Qrcode;import jp.sourceforge.qrcode.QRCodeDecoder;
import jp.sourceforge.qrcode.exception.DecodingFailedException; public class TwoDimensionCode { //二维码 SIZEprivate static final int CODE_IMG_SIZE 235;// LOGO SIZE (为了插入图片的完整性我们选择在最中间插入而且长宽建议为整个二维码的1/7至1/4)private static final int INSERT_IMG_SIZE CODE_IMG_SIZE/5;/** * 生成二维码(QRCode)图片 * param content 存储内容 * param imgPath 二维码图片存储路径 * param imgType 图片类型 * param insertImgPath logo图片路径*/ public void encoderQRCode(String content, String imgPath, String imgType, String insertImgPath) { try { BufferedImage bufImg this.qRCodeCommon(content, imgType, insertImgPath); File imgFile new File(imgPath);if (!imgFile.exists()){imgFile.mkdirs();}// 生成二维码QRCode图片 ImageIO.write(bufImg, imgType, imgFile); } catch (Exception e) { e.printStackTrace(); } } /** * 生成二维码(QRCode)图片 * param content 存储内容 * param output 输出流 * param imgType 图片类型 */ public void encoderQRCode(String content, OutputStream output, String imgType) { try { BufferedImage bufImg this.qRCodeCommon(content, imgType, null); // 生成二维码QRCode图片 ImageIO.write(bufImg, imgType, output); } catch (Exception e) { e.printStackTrace(); } } /*** param content* param imgType* param size* param imgPath 嵌入图片的名称* return*/private BufferedImage qRCodeCommon(String content, String imgType, String imgPath){BufferedImage bufImg null; try { Qrcode qrcodeHandler new Qrcode(); // 设置二维码排错率可选L(7%)、M(15%)、Q(25%)、H(30%)排错率越高可存储的信息越少但对二维码清晰度的要求越小 qrcodeHandler.setQrcodeErrorCorrect(M); qrcodeHandler.setQrcodeEncodeMode(B); // 设置设置二维码尺寸取值范围1-40值越大尺寸越大可存储的信息越大 qrcodeHandler.setQrcodeVersion(15); // 获得内容的字节数组设置编码格式 byte[] contentBytes content.getBytes(utf-8); // 图片尺寸 int imgSize CODE_IMG_SIZE; bufImg new BufferedImage(imgSize, imgSize, BufferedImage.TYPE_INT_RGB); Graphics2D gs bufImg.createGraphics(); // 设置背景颜色 gs.setBackground(Color.WHITE); gs.clearRect(0, 0, imgSize, imgSize); // 设定图像颜色 BLACK gs.setColor(Color.BLACK); // 设置偏移量不设置可能导致解析出错 final int pixoff 2;final int sz 3;// 输出内容 二维码 if (contentBytes.length 0 contentBytes.length 800) { boolean[][] codeOut qrcodeHandler.calQrcode(contentBytes); for (int i 0; i codeOut.length; i) { for (int j 0; j codeOut.length; j) { if (codeOut[j][i]) { gs.fillRect(j * sz pixoff, i * sz pixoff, sz, sz); } } } } else { throw new Exception(QRCode content bytes length contentBytes.length not in [0, 800].); } //嵌入logoif(imgPath ! null)this.insertImage(bufImg, imgPath, true);gs.dispose(); bufImg.flush(); } catch (Exception e) { e.printStackTrace(); } return bufImg; }private 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) { // 压缩LOGO if (width INSERT_IMG_SIZE) { width INSERT_IMG_SIZE; } if (height INSERT_IMG_SIZE) { height INSERT_IMG_SIZE; } 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; } // 插入LOGO Graphics2D graph source.createGraphics(); int x (CODE_IMG_SIZE - width) / 2; int y (CODE_IMG_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(); } /** * 解析二维码QRCode * param imgPath 图片路径 * return */ public String decoderQRCode(String imgPath) { // QRCode 二维码图片的文件 File imageFile new File(imgPath); BufferedImage bufImg null; String content null; try { bufImg ImageIO.read(imageFile); QRCodeDecoder decoder new QRCodeDecoder(); content new String(decoder.decode(new TwoDimensionCodeImage(bufImg)), utf-8); } catch (IOException e) { System.out.println(Error: e.getMessage()); e.printStackTrace(); } catch (DecodingFailedException dfe) { System.out.println(Error: dfe.getMessage()); dfe.printStackTrace(); } return content; } /** * 解析二维码QRCode * param input 输入流 * return */ public String decoderQRCode(InputStream input) { BufferedImage bufImg null; String content null; try { bufImg ImageIO.read(input); QRCodeDecoder decoder new QRCodeDecoder(); content new String(decoder.decode(new TwoDimensionCodeImage(bufImg)), utf-8); } catch (IOException e) { System.out.println(Error: e.getMessage()); e.printStackTrace(); } catch (DecodingFailedException dfe) { System.out.println(Error: dfe.getMessage()); dfe.printStackTrace(); } return content; }
} View Code 3.具体注意的地方 //二维码 SIZE
private static final int CODE_IMG_SIZE 235;
// LOGO SIZE (为了插入图片的完整性我们选择在最中间插入而且长宽建议为整个二维码的1/7至1/4)
private static final int INSERT_IMG_SIZE CODE_IMG_SIZE/5; 对于二维码图片大小还是不会计算如果有人看到这里方便的话可以告诉小弟一声。我这里的这个值235是通过设定好QrcodeVersion(版本15)以及绘制图像时偏移量pixoff2和black区域的size3最终生成图片后将图片通过ps打开然后确定图片的尺寸信息。 还有就是中间的logo不要过大否则会导致QRCode解析出错但是手机扫码不一定会出错。感觉手机扫码解析比QRCode解析能力强。 Qrcode qrcodeHandler new Qrcode();
// 设置二维码排错率可选L(7%)、M(15%)、Q(25%)、H(30%)排错率越高可存储的信息越少但对二维码清晰度的要求越小
qrcodeHandler.setQrcodeErrorCorrect(M);
qrcodeHandler.setQrcodeEncodeMode(B);
// 设置设置二维码尺寸取值范围1-40值越大尺寸越大可存储的信息越大
qrcodeHandler.setQrcodeVersion(15); 一般设置version就好了网上好多都是7或者8我尝试下更大的值15的话二维码看起来很密集。 // 设置偏移量不设置可能导致解析出错
final int pixoff 2;
final int sz 3;
// 输出内容 二维码
if (contentBytes.length 0 contentBytes.length 800) { boolean[][] codeOut qrcodeHandler.calQrcode(contentBytes); for (int i 0; i codeOut.length; i) { for (int j 0; j codeOut.length; j) { if (codeOut[j][i]) { gs.fillRect(j * sz pixoff, i * sz pixoff, sz, sz); } } }
} 绘制black区域的时候要设置偏移量要不然可能导致二维码识别出错。 black区域的大小根据实际情况来就好。 四、二维码登录原理 1.原理图 按照自己的理解画的结合上图看一下代码吧。 2.GetQrCodeController.java /*** author hjzgg* 获取二维码图片*/
Controller
public class GetQrCodeController {RequestMapping(value/getTwoDemensionCode)ResponseBodypublic String getTwoDemensionCode(HttpServletRequest request){String uuid UUID.randomUUID().toString().substring(0, 8);String ip localhost;try {ip InetAddress.getLocalHost().getHostAddress();} catch (UnknownHostException e) {e.printStackTrace();}//二维码内容String content http:// ip :8080/yycc-portal/loginPage?uuid uuid;//生成二维码String imgName uuid _ (int) (new Date().getTime() / 1000) .png;String imgPath request.getServletContext().getRealPath(/) imgName;//String insertImgPath request.getServletContext().getRealPath(/)img/hjz.jpg;TwoDimensionCode handler new TwoDimensionCode();handler.encoderQRCode(content, imgPath, png, null);//生成的图片访问地址String qrCodeImg http:// ip :8080/yycc-portal/ imgName;JSONObject json new JSONObject();json.put(uuid, uuid);json.put(qrCodeImg, qrCodeImg);return json.toString();}
} 用户请求扫码方式登录后台生成二维码将uuid和二维码访问地址传给用户。 3.LongConnectionCheckController.java Controller
public class LongConnectionCheckController {private static final int LONG_TIME_WAIT 30000;//30sAutowiredprivate RedisTemplateString, Object redisTemplate;RequestMapping(value/longUserCheck)public String longUserCheck(String uuid){long inTime new Date().getTime();Boolean bool true;while (bool) {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}//检测登录UserVo userVo (UserVo) redisTemplate.opsForValue().get(uuid);System.out.println(LongConnectionCheckAction: userVo);if(userVo ! null){redisTemplate.delete(uuid);return forward:/loginTest?username userVo.getUsername() password userVo.getPassword();}else{if(new Date().getTime() - inTime LONG_TIME_WAIT){bool false;redisTemplate.delete(uuid);}}}return forward:/longConnectionFail;}RequestMapping(value/longConnectionFail)ResponseBodypublic String longConnectionFail(){JSONObject json new JSONObject();json.put(success, false);json.put(message, 长连接已断开!);return json.toString();}
} 用户获得uuid和二维码之后请求后台的长连接携带uuid不断检测uuid是否有对应的用户信息如果有则转到登录模块携带登录信息。 4.PhoneLoginController.java /*** author hjzgg* 手机登录验证*/
Controller
public class PhoneLoginController {Autowiredprivate RedisTemplateString, Object redisTemplate;RequestMapping(value/phoneLogin)public void phoneLogin(String uuid, String username, String password){UserVo user (UserVo) redisTemplate.opsForValue().get(uuid);if(user null) {user new UserVo(username, password);}System.out.println(user);redisTemplate.opsForValue().set(uuid, user);}RequestMapping(value/loginPage)public String loginPage(HttpServletRequest request, String uuid){request.setAttribute(uuid, uuid);return phone_login;}
} 用户通过手机扫码之后在手机端输入用户信息然后进行验证携带uuid后台更新uuid对应的用户信息以便长连接可以检测到用户登录信息。 五、源码下载 二维码登录例子以及二维码生成解析工具源码下载https://github.com/hjzgg/QRCodeLoginDemo 转载于:https://www.cnblogs.com/hujunzheng/p/5661443.html