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格式的圖片(data:image/gif;base64,xxxx) <br> * eg: <code> * <img alt="" src="data:image/gif;base64,xxxx"> * </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(); } }