找了很多资料,七七八八都试了一遍,最终写出来了这个功能。
菜鸟一枚,此文只为做笔记。
简单的一个生成二维码,通过网页确认登录,实现二维码页面跳转到主页面。
有三个servlet:
CodeServlet.java 干2件事
a:生成随机的uuid,是一个唯一标识,该标识贯穿整个流程
b:生成二维码图片,二维码信息:http://xx.xx.xx.xx:8080/xxxx/login.jsp?uuid= xxxx
LongConnectionCheckServlet.java
进行长连接轮询操作,参数为uuid,查找loginMap中是否有此uuid,如果有则停止轮询,loginMap中remove这个uuid
PhoneLoginServlet.java 干2件事
a:检测登录,查看是否有此uuid
b:登录成功后将登录信息插入到loginMap中去,uuid为key
-------- Servlet 需要配置web.xml --------
UserLoginInfoVO.java
用户登录信息存储用户名密码(其他的还可以加,我只写了简单的)
LoginUser.java
用HashMap存用户登录信息
TwoDimensionCode.java
最关键的生成二维码的类,实现QRCodeImage,需要QRCode.jar包
QRCode.jar下载地址:http://vdisk.weibo.com/s/A25JOYrYFK9xO
UserLoginInfoVO.java
public class UserLoginInfoVO {
private String userName;
private String userPass;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPass() {
return userPass;
}
public void setUserPass(String userPass) {
this.userPass = userPass;
}
}
LoginUser.java
import java.util.HashMap;
public class LoginUser {
private static HashMap<String, UserLoginInfoVO> loginMap = new HashMap<String, UserLoginInfoVO>();
private static UserLoginInfoVO userLoginInfoVO;
public static UserLoginInfoVO getVO() {
if (userLoginInfoVO == null) {
userLoginInfoVO = new UserLoginInfoVO();
}
return userLoginInfoVO;
}
public static HashMap<String, UserLoginInfoVO> getLoginMap() {
return loginMap;
}
}
TwoDimensionCode.java
import java.awt.Color;
import java.awt.Graphics2D;
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 {
/**
* 生成二维码(QRCode)图片
*
* @param content
* 存储内容
* @param imgPath
* 图片路径
* @param imgType
* 图片类型
* @param output
* 输出流
* @param size
* 二维码尺寸
*/
public void encoderQRCode(String content, String imgPath) {
this.encoderQRCode(content, imgPath, "png", 7);
}
public void encoderQRCode(String content, OutputStream output) {
this.encoderQRCode(content, output, "png", 7);
}
public void encoderQRCode(String content, String imgPath, String imgType) {
this.encoderQRCode(content, imgPath, imgType, 7);
}
public void encoderQRCode(String content, OutputStream output, String imgType) {
this.encoderQRCode(content, output, imgType, 7);
}
public void encoderQRCode(String content, String imgPath, String imgType, int size) {
try {
BufferedImage bufImg = this.qRCodeCommon(content, imgType, size);
File imgFile = new File(imgPath);
if (!imgFile.exists()) {
imgFile.mkdirs();
}
// 生成二维码QRCode图片
ImageIO.write(bufImg, imgType, imgFile);
} catch (Exception e) {
e.printStackTrace();
}
}
public void encoderQRCode(String content, OutputStream output, String imgType, int size) {
try {
BufferedImage bufImg = this.qRCodeCommon(content, imgType, size);
// 生成二维码QRCode图片
ImageIO.write(bufImg, imgType, output);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 生成二维码(QRCode)图片的公共方法
*
* @return BufferedImage
*/
private BufferedImage qRCodeCommon(String content, String imgType, int size) {
BufferedImage bufImg = null;
try {
Qrcode qrcode = new Qrcode();
// 设置二维码排错率,可选L(7%)、M(15%)、Q(25%)、H(30%),排错率越高可存储的信息越少,但对二维码清晰度的要求越小
qrcode.setQrcodeErrorCorrect('M');
qrcode.setQrcodeEncodeMode('B');
// 设置设置二维码尺寸,取值范围1-40,值越大尺寸越大,可存储的信息越大
qrcode.setQrcodeVersion(size);
// 获得内容的字节数组,设置编码格式
byte[] contentBytes = content.getBytes("utf-8");
// 图片尺寸
int imgSize = 67 + 12 * (size - 1);
// BufferedImage.TYPE_INT_RGB表示一个图像,该图像具有整数像素的 8 位 RGB 颜色
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);
// 设置偏移量,不设置可能导致解析出错
int pixoff = 2;
// 输出内容> 二维码
if (contentBytes.length > 0 && contentBytes.length < 800) {
// calQrcode()让字符串生成二维码。
boolean[][] codeOut = qrcode.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 * 3 + pixoff, i * 3 + pixoff, 3, 3);
}
}
}
} else {
throw new Exception("QRCode content bytes length = " + contentBytes.length + " not in [0, 800].");
}
gs.dispose();
bufImg.flush();
} catch (Exception e) {
e.printStackTrace();
}
return bufImg;
}
}
CodeServlet.java
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.dsjstudio.loanfront.useras.utils.TwoDimensionCode;
public class CodeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
// 生成唯一ID
int uuid = (int) (Math.random() * 100000);
// 二维码内容
String content = "http://localhost:8080/xxxx/index.jsp?uuid=" + uuid;
// 生成二维码
String imgName = "image_" + uuid + ".png";
String imgPath = "D:/images/" + imgName;
TwoDimensionCode handler = new TwoDimensionCode();
handler.encoderQRCode(content, imgPath, "png");
System.out.println(content);
// 生成的图片访问地址
String qrCodeImg = "http://localhost:8080/images/" + imgName;
String jsonStr = "{\"uuid\":" + uuid + ",\"qrCodeImg\":\"" + qrCodeImg + "\"}";
out.print(jsonStr);
out.flush();
out.close();
}
}
LongConnectionCheckServlet.java
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.dsjstudio.loanfront.useras.controller.user.controller.LoginUser;
import com.dsjstudio.loanfront.useras.controller.user.vo.UserLoginInfoVO;
public class LongConnectionCheckServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String uuid = request.getParameter("uuid");
String jsonStr = "";
System.out.println("in");
System.out.println("uuid:" + uuid);
long inTime = new Date().getTime();
Boolean bool = true;
while (bool) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 检测登录
UserLoginInfoVO userVo = LoginUser.getLoginMap().get(uuid);
System.out.println("userVo:" + userVo);
if (userVo != null) {
bool = false;
jsonStr = "{\"uname\":\"" + userVo.getUserName() + "\"}";
LoginUser.getLoginMap().remove(uuid);
} else {
if (new Date().getTime() - inTime > 5000) {
bool = false;
}
}
}
System.out.println("login ok : " + jsonStr);
PrintWriter out = response.getWriter();
out.print(jsonStr);
out.flush();
out.close();
}
}
PhoneLoginServlet.java
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.dsjstudio.loanfront.useras.controller.user.controller.LoginUser;
import com.dsjstudio.loanfront.useras.controller.user.vo.UserLoginInfoVO;
public class PhoneLoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String uuid = request.getParameter("uuid");
String uname = request.getParameter("uname");
String upwd = request.getParameter("upwd");
System.out.println(uuid);
System.out.println(uname);
System.out.println(upwd);
// TODO 验证登录
boolean bool = true;
if (bool) {
// 将登陆信息存入map
UserLoginInfoVO userVo = LoginUser.getLoginMap().get(uuid);
if (userVo == null) {
userVo = new UserLoginInfoVO();
userVo.setUserName(uname);
userVo.setUserPass(upwd);
LoginUser.getLoginMap().put(uuid, userVo);
}
}
PrintWriter out = response.getWriter();
out.print(bool);
out.flush();
out.close();
}
}
两个jsp页面:
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
var uuid;
//alert("1");
$.get("/dsjstudio-loan-user-as/CodeServlet", function(data, status) {
var obj = eval("(" + data + ")");
//alert("2");
//存储UUID
uuid = obj.uuid;
//显示二维码
$("#QrCodeImg").attr("src", obj.qrCodeImg);
// alert(obj.qrCodeImg);
//开始验证登录
validateLogin();
});
function validateLogin(){
$.get("/dsjstudio-loan-user-as/LongConnectionCheckServlet?uuid=" + uuid , function(data, status) {
if(data == ""){
validateLogin();
}else{
var obj = eval("(" + data + ")");
alert("欢迎您回家:" + obj.uname);
window.location.href='http://www.baidu.com';
}
});
}
});
</script>
</head>
<body>
<h1>哥么敢不敢扫一下!</h1>
<div id="divCon">
<img src="" id="QrCodeImg" />
</div>
</body>
</html>
login.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>点确认吧小伙子</title>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
//登录
function login()
$.post("/dsjstudio-loan-user-as/PhoneLoginServlet", {
uuid : $.getUrlParam('uuid'),
uname:$("#login_name").val(),
upwd:$("#login_psw").val()
}, function(data, status) {
if(data == ""){
alert("登录失败");
}else{
alert("登录成功");
}
});
}
//获取网页参数
(function($){
$.getUrlParam = function(name){
//这个正则是寻找&+url参数名字=值+&
var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
//这里是开始匹配,找到了返回对应url值,没找到返回null。
var r = window.location.search.substr(1).match(reg);
if (r!=null) return unescape(r[2]); return null;
}
})(jQuery);
</script>
</head>
<body>
<div>
<p>
<span>名称:</span>
<input type="text" id="login_name" value="lingzi">
</p>
<p>
<span>密码:</span>
<input type="password" id="login_psw" value="xxxxxxxxx">
</p>
<div>
<a href="javascript:login()">登录</a>
</div>
</div>
</body>
</html>
因为连的是本地的tomcat,所以是直接电脑上操作,二维码出来,有一个uuid打印在Console上,复制粘贴到网址上
实现效果图:
Console上uuid打印出来62951
点击登录
返回index.jsp页面查看,成功~点击确认跳转页面啦~
web.xml配置
<servlet>
<description></description>
<display-name>长连接检查登录状态</display-name>
<servlet-name>LongConnectionCheckServlet</servlet-name>
<servlet-class>com.dsjstudio.loanfront.useras.controller.user.servlet.LongConnectionCheckServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LongConnectionCheckServlet</servlet-name>
<url-pattern>/LongConnectionCheckServlet</url-pattern>
</servlet-mapping>
<servlet>
<description>获取二维码图片以及uuid</description>
<display-name>CodeServlet</display-name>
<servlet-name>CodeServlet</servlet-name>
<servlet-class>com.dsjstudio.loanfront.useras.controller.user.servlet.CodeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CodeServlet</servlet-name>
<url-pattern>/CodeServlet</url-pattern>
</servlet-mapping>
<servlet>
<description>手机扫描二维码之后进行登录</description>
<display-name>PhoneLoginServlet</display-name>
<servlet-name>PhoneLoginServlet</servlet-name>
<servlet-class>com.dsjstudio.loanfront.useras.controller.user.servlet.PhoneLoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PhoneLoginServlet</servlet-name>
<url-pattern>/PhoneLoginServlet</url-pattern>
</servlet-mapping>