package com.common.utils;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.junit.Assert;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
/**
* @author EX-CHENKEFENG001
*
* 微信验证、二维码生成工具类
*
*/
public class WechatValidateUtils {
private static final boolean NEEDCOMPRESS = false;
private static String LOGO_URL;
// LOGO宽度
private static final int WIDTH = 60;
// LOGO高度
private static final int HEIGHT = 60;
static{
LOGO_URL = PropertiesUtils.getProperty("context-ilife_core.properties", "pemobi.dmz.logo.url");
}
/**
* 生成二维码的工具类
*
* @param data
* 二维码中携带的数据
* @param width
* 二维码的宽度
* @param height
* 二维码的高度
* @return 返回base64格式的图片(https://img-blog.csdnimg.cn/2022010618054783822.gif) <br>
* eg: <code>
* <img alt="" src="https://img-blog.csdnimg.cn/2022010618054783822.gif">
* </code>
*/
public static String generateQRCode(String data, int width, int height,String isPicture) {
Assert.assertTrue("param data cannot empty.", data != null
&& data.trim().length() > 0);
Assert.assertTrue("param width and height must gt 0.", width > 0
&& height > 0);
ByteArrayOutputStream bos = null;
MultiFormatWriter formatWriter = new MultiFormatWriter();
Hashtable<EncodeHintType, Object> param = new Hashtable<EncodeHintType, Object>();
param.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.Q);
param.put(EncodeHintType.CHARACTER_SET, "utf-8");
param.put(EncodeHintType.MARGIN, 0);
try {
BitMatrix bitMatrix = formatWriter.encode(data,
BarcodeFormat.QR_CODE, width, height, param);
//1.1去白边
int[] rec = bitMatrix.getEnclosingRectangle();
int resWidth = rec[2] + 1;
int resHeight = rec[3] + 1;
BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);
resMatrix.clear();
for (int i = 0; i < resWidth; i++) {
for (int j = 0; j < resHeight; j++) {
if (bitMatrix.get(i + rec[0], j + rec[1])) {
resMatrix.set(i, j);
}
}
}
int width1 = resMatrix.getWidth();
int height1 = resMatrix.getHeight();
BufferedImage qrcode = new BufferedImage(width1, height1,
BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width1; x++) {
for (int y = 0; y < height1; y++) {
qrcode.setRGB(x, y, resMatrix.get(x, y) == true ?
Color.BLACK.getRGB():Color.WHITE.getRGB());
}
}
if(CommonUtil.isNotNull(LOGO_URL) && CommonUtil.isNotNull(isPicture)){
insertImage(width1,qrcode,LOGO_URL,NEEDCOMPRESS);
}
Logger.INFO("LOGO_URL------------------------"+LOGO_URL);
bos = new ByteArrayOutputStream();
ImageIO.write(qrcode, "png", bos);
String img = StringUtils.deleteWhitespace(Base64
.encodeBase64String(bos.toByteArray()));
return String.format("data:image/png;base64,%s", img);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
}
}
}
}
private static void insertImage(int QRCODE_SIZE,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 > 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;
}
// 插入LOGO
Graphics2D 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();
}
/**
* @param data
* 二维码携带的数据
* @param size
* 二维码的宽、高
* @return
* @see WechatValidateUtils#generateQRCode(String, int, int)
*/
public static String generateQRCode(String data, int size,String isPicture) {
return generateQRCode(data, size, size,isPicture);
}
/**
* 校验姓名是否合法
*
* @param name
* @return 验证通过true,否则false
*/
public static boolean validateName(String name) {
return StringUtils.isNotBlank(name);
}
/**
* 身份证号码校验
*
* @param idNo
* @return 验证通过 true,否则 false
*/
public static boolean validateIdNo(String idNo) {
if (StringUtils.isBlank(idNo)) {
return false;
}
String reg = "^(?:\\d{8}(?:0[1-9]|1[0-2])[0123]\\d{4}|\\d{6}(?:18|19|20)\\d{2}(?:0[1-9]|1[0-2])[0123]\\d{4}[0-9X])?$";
return idNo.matches(reg);
}
/**
* 校验手机号码是否合法
*
* @param mobile
* @return 校验通过true,否则false
*/
public static boolean validateMobile(String mobile) {
if (StringUtils.isBlank(mobile)) {
return false;
}
String reg = "^(13|14|15|17|18)[0-9]{9}$";
return mobile.matches(reg);
}
/**
* 根据身份证号码获取 性别,年龄
*
* @param idNo
* 身份证号码
* @return
*
* <code>
* sex: 'M|F',
* birth: Date,
* birthStr: String(yyyy-MM-dd),
* age: int
* </code>
*
*/
public static Map<String, Object> analyzeIdNo(String idNo, String format) {
if (StringUtils.isBlank(idNo)) {
return null;
}
Map<String, Object> result = new HashMap<String, Object>();
if (StringUtils.isBlank(format)) {
format = "yyyy-MM-dd";
}
DateFormat df = new SimpleDateFormat(format);
DateFormat parser = new SimpleDateFormat("yyyyMMdd");
String birthStr;
String sex;
switch (idNo.length()) {
case 18:
birthStr = idNo.substring(6, 14);
sex = (Integer.valueOf(idNo.substring(16, 17)) % 2) == 0 ? "F"
: "M";
break;
case 15:
birthStr = String.format("19%s", idNo.substring(6, 12));
sex = (Integer.valueOf(idNo.substring(14, 15)) % 2) == 0 ? "F"
: "M";
break;
default:
return null;
}
try {
Date birth = parser.parse(birthStr);
result.put("sex", sex);
result.put("birth", birth);
result.put("birthStr", df.format(birth));
result.put("age", DateUtil.calculateAgeInBirth(birth, new Date()));
return result;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String getSHA1(String openid, String timestamp, String nonce,
String key) {
String[] arr = new String[] { key, timestamp, nonce, openid };
Arrays.sort(arr);
StringBuilder content = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
content.append(arr[i]);
}
MessageDigest md = null;
String tmpStr = null;
try {
md = MessageDigest.getInstance("SHA-1");
// 将三个参数字符串拼接成一个字符串进行sha1加密
byte[] digest = md.digest(content.toString().getBytes());
tmpStr = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
content = null;
// 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
if(null == tmpStr) {
return null;
}
return tmpStr.toLowerCase();
}
/**
* 将字节数组转换为十六进制字符串
*
* @param byteArray
* @return
*/
private static String byteToStr(byte[] byteArray) {
String strDigest = "";
for (int i = 0; i < byteArray.length; i++) {
strDigest += byteToHexStr(byteArray[i]);
}
return strDigest;
}
/**
* 将字节转换为十六进制字符串
*
* @param mByte
* @return
*/
private static String byteToHexStr(byte mByte) {
char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
'B', 'C', 'D', 'E', 'F' };
char[] tempArr = new char[2];
tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
tempArr[1] = Digit[mByte & 0X0F];
String s = new String(tempArr);
return s;
}
/**
* 校验openid的合法性
*
* @param openid
* 授权返回的用户openid
* @param signature
* 授权后返回的加密串
* @param nonce
* 授权返回的随机数
* @param timestamp
* 授权返回的时间戳
* @return
*/
public static boolean validateOpenid(String openid, String signature,
String nonce, String timestamp) {
if (StringUtils.isBlank(openid)) {
return false;
}
String key = Configuration.getValue("wechat.paztcf.secret.key", "");
System.out.println("wechat.paztcf.secret.key--------" + key );
String signatureTemp = getSHA1(openid, timestamp, nonce, key);
if (StringUtils.isBlank(signature)) {
signature = "";
}
return signature.equalsIgnoreCase(signatureTemp);
}
/**
* 校验openid的合法性, 如果openid合法,则返回openid,否则返回null
*
* @param request
* @return
*/
public static String validateOpenid(HttpServletRequest request) {
HttpSession session = request.getSession();
String openid = (String) session.getAttribute("openid");
if (StringUtils.isNotBlank(openid)) {
return openid;
}
openid = request.getParameter("openid"); // 个人微信号
String signature = request.getParameter("signature"); // 签名串
String nonce = request.getParameter("nonce"); // 随机数
String timestamp = request.getParameter("timestamp"); // 时间戳
if (validateOpenid(openid, signature, nonce, timestamp)) {
session.setAttribute("openid", openid);
return openid;
}
return null;
}
/**
* 校验fid 与 sfid是否配对
*
* @param fid
* 分享人的openid
* @param sfid
* 分享人的加密后的openid
* @return
*/
public static boolean isLegalOpenId(String fid, String sfid) {
if (StringUtils.isBlank(fid) || StringUtils.isBlank(sfid)) {
return false;
}
String signature = secretOpenid(fid);
return sfid.equalsIgnoreCase(signature);
}
/**
* 对openid进行加密
*
* @param openid
* @return
*/
public static String secretOpenid(String openid) {
String key = Configuration.getValue("wechat.paztcf.secret.key", "");
return getSHA1(openid, "100", "100", key);
}
/**
* 微信环境不精准检测
*
* @param userAgent
* @return
*/
public static boolean isComeFromWechat(String userAgent) {
userAgent = userAgent.toLowerCase();
return userAgent.contains("micromessenger");
}
/**
* 微信环境不精准检测
*
* @param userAgent
* @return
*/
public static boolean isComeFromWechat(HttpServletRequest request) {
String userAgent = request.getHeader("User-Agent").toLowerCase();
;
return userAgent.contains("micromessenger");
}
/**
* 是否来自qq浏览器
*
* @param request
* @return
*/
public static boolean isComeFromQQ(HttpServletRequest request) {
String userAgent = request.getHeader("User-Agent").toLowerCase();
;
return userAgent.contains("qq");
}
/**
* 获取微信授权的url地址
*
* @param backUrl
* @return
*/
public static String getAuthorizeUrl(String backUrl) {
// 授权相关
String appid = Configuration.getValue("ucp.life.appid"); // 公众账号appId
String weappNo = Configuration.getValue("ucp.life.weappNo"); // 公众账号
String redirectServer = Configuration.getValue("ucp.ztkf.redirect.url"); // ucp回调服务器
String authorizeUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?"
+ "appid=%s&redirect_uri=%s&"
+ "response_type=code&scope=snsapi_base&state=sig#wechat_redirect"; // 微信授权的地址
try {
backUrl = URLEncoder.encode(backUrl, "utf-8"); // 对backUrl做编码
} catch (Exception e) {
e.printStackTrace();
}
String redirectUri = String.format("%s?weappNo=%s&backUrl=%s",
redirectServer, weappNo, backUrl); // ucp回调调转地址
try {
redirectUri = URLEncoder.encode(redirectUri, "utf-8"); // 对redirectUri做编码
} catch (Exception e) {
// nothing todo.
}
return String.format(authorizeUrl, appid, redirectUri);
}
public static void main(String[] args) throws Exception {
// 生成二维码
String url = "http://www.pingan.com/pa18shoplife/mobile/product/warminglife/quote.jsp?WT.mc_id=mobi07-pab-s102-ewm&eid=normal&appColumn=2A7010AC328C32F8E054002128BFD47A";
String src = generateQRCode(url,200,"1");
System.out.println(url.length());
String html = "<img src=\"" + src + "\">";
FileOutputStream ops = new FileOutputStream("D:\\QRCodeImage\\cecece.html");
org.apache.commons.io.IOUtils.write(html, ops, "utf-8");
ops.close();
}
}