最近公司的app上線了,在推廣APP的時候出現了一個問題,因為Android和IOS的下載地址不一樣,那么在推廣的時候就要推廣兩個二維碼,這樣比較麻煩,如何簡化我們的推廣,讓IOS用戶掃描二維碼的時候自動跳轉到蘋果應用市場,讓Android用戶掃描二維碼的時候自動跳轉到安卓應用市場呢。這時候我百度了一下,發現市面上確實有一些這樣的網站幫助我們合成二維碼,但是在使用這些二維碼的時候,我發現了一些問題,因為這些網站把自己的短網址放到了二維碼中,在用戶使用QQ掃描二維碼的時候,QQ自動屏蔽了這個短網址,這樣就無法跳轉到指定的下載頁面了。
於是,我決定自己用java搭建一個屬於自己APP二維碼合成網站。我的思路是這樣的:
1、用戶在前台表單提交APP的IOS和Android下載地址。
2、后台接收IOS和Android下載地址然后生成一個UUID,把這三個信息存儲在數據庫中。
3、定義一個@RequestMapping地址,通過地址中傳遞的UUID,在數據庫中查詢到IOS和Android
4、把當前服務器的網址+@RequestMapping地址+UUID合成二維碼返回給前端顯示
5、用戶掃描的二維碼實際上是訪問了我們事先定義的@RequestMapping地址,通過用戶的http請求,我們可以獲取到用戶的手機操作系統是IOS還是Android,這樣就可以跳轉到指定的地址了。
項目選型,我使用Spring SpringMVC MyBatis現在最流行的框架,然后用maven搭建項目,在二維碼的生成和解析的時候,使用google的zxing jar。
添加的依賴pom.xml

<?xml version="1.0"?> <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.jiafuwei.spring</groupId> <artifactId>spring-parent</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <groupId>com.jiafuwei.spring</groupId> <artifactId>spring-mvc-web</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>spring-mvc-web Maven Webapp</name> <url>http://maven.apache.org</url> <properties> <spring.version>4.2.7.RELEASE</spring.version> <jackson.version>2.6.7</jackson.version> <!-- mybatis版本號 --> <mybatis.version>3.2.6</mybatis.version> <!-- freemarker模板包版本 --> <freemarker.version>2.3.23</freemarker.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <!-- freemarker依賴 --> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>${freemarker.version}</version> </dependency> <!-- spring mvc 框架 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <!-- 導入Mysql數據庫鏈接jar包 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.4</version> </dependency> <!-- mybatis核心包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>${mybatis.version}</version> </dependency> <!-- mybatis/spring包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.2.2</version> </dependency> <!-- 上傳組件包 --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.9</version> </dependency> <!-- servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <!-- jsp/jstl/core 頁面標簽 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> <!-- SLF4J API --> <!-- SLF4J 是一個日志抽象層,允許你使用任何一個日志系統,並且可以隨時切換還不需要動到已經寫好的程序 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.22</version> </dependency> <!-- Log4j 日志系統(最常用) --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.22</version> </dependency> <!-- jackson --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- 二維碼 --> <dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId> <version>3.0.0</version> </dependency> <!-- swagger2整合springmvc快速生成rest風格接口文檔 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.5.0</version> </dependency> </dependencies> <build> <finalName>spring-mvc-web</finalName> </build> </project>
二維碼生成、解析工具類ZXingCodeUtil.java

package com.jiafuwei.spring.util; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletRequest; import com.google.zxing.BarcodeFormat; import com.google.zxing.Binarizer; import com.google.zxing.BinaryBitmap; import com.google.zxing.DecodeHintType; import com.google.zxing.EncodeHintType; import com.google.zxing.LuminanceSource; import com.google.zxing.MultiFormatReader; import com.google.zxing.MultiFormatWriter; import com.google.zxing.NotFoundException; import com.google.zxing.Result; import com.google.zxing.WriterException; import com.google.zxing.client.j2se.BufferedImageLuminanceSource; import com.google.zxing.common.BitMatrix; import com.google.zxing.common.HybridBinarizer; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; /** * @Description: (二維碼生成工具類) * @author jiafuwei * @date:2017-03-01 下午05:27:13 */ public class ZXingCodeUtil { private static final int QRCOLOR = 0xFF000000; //默認是黑色 private static final int BGWHITE = 0xFFFFFFFF; //背景顏色 public static void main(String[] args) throws WriterException{ try { //getLogoQRCode("https://www.baidu.com/", null, "跳轉到百度的二維碼"); //getQRCode("https://www.baidu.com/", null, "跳轉到百度的二維碼"); } catch (Exception e) { e.printStackTrace(); } } /** * 二維碼解析 * @param file 二維碼圖片文件 * @return 解析結果 */ public static String parseQRCode(File file) { BufferedImage image; try { image = ImageIO.read(file); LuminanceSource source = new BufferedImageLuminanceSource(image); Binarizer binarizer = new HybridBinarizer(source); BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer); Map<DecodeHintType, Object> hints = new HashMap<DecodeHintType, Object>(); hints.put(DecodeHintType.CHARACTER_SET, "UTF-8"); Result result = new MultiFormatReader().decode(binaryBitmap, hints);// 對圖像進行解碼 return result.getText(); } catch (IOException e) { e.printStackTrace(); return null; } catch (NotFoundException e) { e.printStackTrace(); return null; } } /** * 生成不帶logo的二維碼 * @param qrUrl 鏈接地址 * @param request 請求 * @param productName 二維碼名稱 * @param file 上傳路徑+文件名 * @return */ public static String getQRCode(String qrUrl,HttpServletRequest request,String productName,File file ) { // String filePath = request.getSession().getServletContext().getRealPath("/") + "resources/images/logoImages/llhlogo.png"; //filePath是二維碼logo的路徑,但是實際中我們是放在項目的某個路徑下面的,所以路徑用上面的,把下面的注釋就好 String content = qrUrl; try { ZXingCodeUtil zp = new ZXingCodeUtil(); BufferedImage image = zp.getQR_CODEBufferedImage(content, BarcodeFormat.QR_CODE, 400, 400, zp.getDecodeHintType()); image.flush(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.flush(); ImageIO.write(image, "png", baos); //二維碼生成的路徑,但是實際項目中,我們是把這生成的二維碼顯示到界面上的,因此下面的折行代碼可以注釋掉 //可以看到這個方法最終返回的是這個二維碼的imageBase64字符串 //前端用 <img src="data:image/png;base64,${imageBase64QRCode}"/> 其中${imageBase64QRCode}對應二維碼的imageBase64字符串 //new File("E:/" + new Date().getTime() + "test.png") //判斷目標文件所在的目錄是否存在 if(!file.getParentFile().exists()) { //如果目標文件所在的目錄不存在,則創建父目錄 System.out.println("目標文件所在目錄不存在,准備創建它!"); if(!file.getParentFile().mkdirs()) { System.out.println("創建目標文件所在目錄失敗!"); } } ImageIO.write(image, "png", file); String imageBase64QRCode = new sun.misc.BASE64Encoder().encodeBuffer(baos.toByteArray()); baos.close(); return imageBase64QRCode; } catch (Exception e){ e.printStackTrace(); } return null; } /** * 生成帶logo的二維碼圖片 * @param qrUrl 鏈接地址 * @param request 請求 * @param productName 二維碼名稱 * @param logoFile logo文件 * @param createFile 生成的文件路徑 * @return */ public static String getLogoQRCode(String qrUrl,HttpServletRequest request,String productName,File logoFile,File createFile) { // String filePath = request.getSession().getServletContext().getRealPath("/") + "resources/images/logoImages/llhlogo.png"; //filePath是二維碼logo的路徑,但是實際中我們是放在項目的某個路徑下面的,所以路徑用上面的,把下面的注釋就好 String content = qrUrl; try{ ZXingCodeUtil zp = new ZXingCodeUtil(); BufferedImage bim = zp.getQR_CODEBufferedImage(content, BarcodeFormat.QR_CODE, 400, 400, zp.getDecodeHintType()); return zp.addLogo_QRCode(bim, logoFile , new LogoConfig(), productName, createFile); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 給二維碼圖片添加Logo * * @param qrPic * @param logoPic */ public String addLogo_QRCode(BufferedImage bim, File logoPic, LogoConfig logoConfig, String productName, File createFile) { try { /** * 讀取二維碼圖片,並構建繪圖對象 */ BufferedImage image = bim; Graphics2D g = image.createGraphics(); /** * 讀取Logo圖片 */ BufferedImage logo = ImageIO.read(logoPic); /** * 設置logo的大小,本人設置為二維碼圖片的20%,因為過大會蓋掉二維碼 */ int widthLogo = logo.getWidth(null)>image.getWidth()*3/10?(image.getWidth()*3/10):logo.getWidth(null), heightLogo = logo.getHeight(null)>image.getHeight()*3/10?(image.getHeight()*3/10):logo.getWidth(null); /** * logo放在中心 */ int x = (image.getWidth() - widthLogo) / 2; int y = (image.getHeight() - heightLogo) / 2; /** * logo放在右下角 * int x = (image.getWidth() - widthLogo); * int y = (image.getHeight() - heightLogo); */ //開始繪制圖片 g.drawImage(logo, x, y, widthLogo, heightLogo, null); // g.drawRoundRect(x, y, widthLogo, heightLogo, 15, 15); // g.setStroke(new BasicStroke(logoConfig.getBorder())); // g.setColor(logoConfig.getBorderColor()); // g.drawRect(x, y, widthLogo, heightLogo); g.dispose(); //把商品名稱添加上去,商品名稱不要太長哦,這里最多支持兩行。太長就會自動截取啦 if (productName != null && !productName.equals("")) { //新的圖片,把帶logo的二維碼下面加上文字 BufferedImage outImage = new BufferedImage(400, 445, BufferedImage.TYPE_4BYTE_ABGR); Graphics2D outg = outImage.createGraphics(); //畫二維碼到新的面板 outg.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null); //畫文字到新的面板 outg.setColor(Color.BLACK); outg.setFont(new Font("宋體",Font.BOLD,30)); //字體、字型、字號 int strWidth = outg.getFontMetrics().stringWidth(productName); if (strWidth > 399) { // //長度過長就截取前面部分 // outg.drawString(productName, 0, image.getHeight() + (outImage.getHeight() - image.getHeight())/2 + 5 ); //畫文字 //長度過長就換行 String productName1 = productName.substring(0, productName.length()/2); String productName2 = productName.substring(productName.length()/2, productName.length()); int strWidth1 = outg.getFontMetrics().stringWidth(productName1); int strWidth2 = outg.getFontMetrics().stringWidth(productName2); outg.drawString(productName1, 200 - strWidth1/2, image.getHeight() + (outImage.getHeight() - image.getHeight())/2 + 12 ); BufferedImage outImage2 = new BufferedImage(400, 485, BufferedImage.TYPE_4BYTE_ABGR); Graphics2D outg2 = outImage2.createGraphics(); outg2.drawImage(outImage, 0, 0, outImage.getWidth(), outImage.getHeight(), null); outg2.setColor(Color.BLACK); outg2.setFont(new Font("宋體",Font.BOLD,30)); //字體、字型、字號 outg2.drawString(productName2, 200 - strWidth2/2, outImage.getHeight() + (outImage2.getHeight() - outImage.getHeight())/2 + 5 ); outg2.dispose(); outImage2.flush(); outImage = outImage2; }else { outg.drawString(productName, 200 - strWidth/2 , image.getHeight() + (outImage.getHeight() - image.getHeight())/2 + 12 ); //畫文字 } outg.dispose(); outImage.flush(); image = outImage; } logo.flush(); image.flush(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.flush(); ImageIO.write(image, "png", baos); //二維碼生成的路徑,但是實際項目中,我們是把這生成的二維碼顯示到界面上的,因此下面的折行代碼可以注釋掉 //可以看到這個方法最終返回的是這個二維碼的imageBase64字符串 //前端用 <img src="data:image/png;base64,${imageBase64QRCode}"/> 其中${imageBase64QRCode}對應二維碼的imageBase64字符串 if(!createFile.getParentFile().exists()) { //如果目標文件所在的目錄不存在,則創建父目錄 System.out.println("目標文件所在目錄不存在,准備創建它!"); if(!createFile.getParentFile().mkdirs()) { System.out.println("創建目標文件所在目錄失敗!"); } } ImageIO.write(image, "png", createFile); String imageBase64QRCode = new sun.misc.BASE64Encoder().encodeBuffer(baos.toByteArray()); baos.close(); return imageBase64QRCode; } catch (Exception e){ e.printStackTrace(); } return null; } /** * 構建初始化二維碼 * * @param bm * @return */ public BufferedImage fileToBufferedImage(BitMatrix bm){ BufferedImage image = null; try { int w = bm.getWidth(), h = bm.getHeight(); image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { image.setRGB(x, y, bm.get(x, y) ? 0xFF000000 : 0xFFCCDDEE); } } } catch (Exception e){ e.printStackTrace(); } return image; } /** * 生成二維碼bufferedImage圖片 * * @param content * 編碼內容 * @param barcodeFormat * 編碼類型 * @param width * 圖片寬度 * @param height * 圖片高度 * @param hints * 設置參數 * @return */ public BufferedImage getQR_CODEBufferedImage(String content, BarcodeFormat barcodeFormat, int width, int height, Map<EncodeHintType, ?> hints) { MultiFormatWriter multiFormatWriter = null; BitMatrix bm = null; BufferedImage image = null; try{ multiFormatWriter = new MultiFormatWriter(); // 參數順序分別為:編碼內容,編碼類型,生成圖片寬度,生成圖片高度,設置參數 bm = multiFormatWriter.encode(content, barcodeFormat, width, height, hints); int w = bm.getWidth(); int h = bm.getHeight(); image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); // 開始利用二維碼數據創建Bitmap圖片,分別設為黑(0xFFFFFFFF)白(0xFF000000)兩色 for (int x = 0; x < w; x++){ for (int y = 0; y < h; y++) { image.setRGB(x, y, bm.get(x, y) ? QRCOLOR : BGWHITE); } } } catch (WriterException e){ e.printStackTrace(); } return image; } /** * 設置二維碼的格式參數 * * @return */ public Map<EncodeHintType, Object> getDecodeHintType() { // 用於設置QR二維碼參數 Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>(); // 設置QR二維碼的糾錯級別(H為最高級別)具體級別信息 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // 設置編碼方式 hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); hints.put(EncodeHintType.MARGIN, 0); hints.put(EncodeHintType.MAX_SIZE, 350); hints.put(EncodeHintType.MIN_SIZE, 100); return hints; } } class LogoConfig { // logo默認邊框顏色 public static final Color DEFAULT_BORDERCOLOR = Color.WHITE; // logo默認邊框寬度 public static final int DEFAULT_BORDER = 2; // logo大小默認為照片的1/5 public static final int DEFAULT_LOGOPART = 5; private final int border = DEFAULT_BORDER; private final Color borderColor; private final int logoPart; /** * Creates a default config with on color {@link #BLACK} and off color * {@link #WHITE}, generating normal black-on-white barcodes. */ public LogoConfig(){ this(DEFAULT_BORDERCOLOR, DEFAULT_LOGOPART); } public LogoConfig(Color borderColor, int logoPart){ this.borderColor = borderColor; this.logoPart = logoPart; } public Color getBorderColor() { return borderColor; } public int getBorder(){ return border; } public int getLogoPart() { return logoPart; } }
8位短uuid生成工具類

package com.jiafuwei.spring.util; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.UUID; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletRequest; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatWriter; import com.google.zxing.WriterException; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; /** * @Description: 短uuid生成 * @author jiafuwei * @date:2017-03-02 下午05:27:13 */ public class UuidUtil { public static void main(String[] args) throws WriterException{ String uuid = generateShortUuid(); System.out.println(uuid); } public static String[] chars = new String[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" }; public static String generateShortUuid() { StringBuffer shortBuffer = new StringBuffer(); String uuid = UUID.randomUUID().toString().replace("-", ""); for (int i = 0; i < 8; i++) { String str = uuid.substring(i * 4, i * 4 + 4); int x = Integer.parseInt(str, 16); shortBuffer.append(chars[x % 0x3E]); } return shortBuffer.toString(); } }
核心控制器

package com.jiafuwei.spring.controller; import java.io.BufferedInputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.Date; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.commons.CommonsMultipartFile; import com.jiafuwei.spring.po.JsonResult; import com.jiafuwei.spring.po.QRCode; import com.jiafuwei.spring.service.IQRCodeService; import com.jiafuwei.spring.util.UuidUtil; import com.jiafuwei.spring.util.ZXingCodeUtil; @Controller public class UploadController { final Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private IQRCodeService qRCodeService; /* * 通過流的方式上傳文件 * @RequestParam("file") 將name=file控件得到的文件封裝成CommonsMultipartFile 對象 */ @RequestMapping("fileUpload") public String fileUpload(@RequestParam("file") CommonsMultipartFile file,HttpServletRequest request, ModelMap model) throws IOException { //用來檢測程序運行時間 long startTime=System.currentTimeMillis(); String path = request.getSession().getServletContext().getRealPath("upload"); String fileName = file.getOriginalFilename(); System.out.println("fileName:"+fileName); File targetFile = new File(path, fileName); if(!targetFile.exists()){ targetFile.mkdirs(); } file.transferTo(targetFile); model.addAttribute("fileUrl", request.getContextPath()+"/upload/"+fileName); long endTime=System.currentTimeMillis(); System.out.println("方法一的運行時間:"+String.valueOf(endTime-startTime)+"ms"); return "/result"; } @RequestMapping("fileUploadLogo") @ResponseBody public String fileUploadLogo(@RequestParam("file") CommonsMultipartFile file,HttpServletRequest request, ModelMap model) throws IOException { //用來檢測程序運行時間 long startTime=System.currentTimeMillis(); String path = request.getSession().getServletContext().getRealPath("upload"); String fileName = file.getOriginalFilename(); System.out.println("fileName:"+fileName); File targetFile = new File(path, fileName); if(!targetFile.exists()){ targetFile.mkdirs(); } file.transferTo(targetFile); model.addAttribute("fileUrl", request.getContextPath()+"/upload/"+fileName); long endTime=System.currentTimeMillis(); System.out.println("方法一的運行時間:"+String.valueOf(endTime-startTime)+"ms"); return "result"; } /** * APP 合成二維碼生成 * @param request * @param model * @return * @throws IOException */ @RequestMapping("synthesisQRCode") @ResponseBody public JsonResult SynthesisQRCode(HttpServletRequest request, @RequestParam(value="file",required=false) CommonsMultipartFile logoFile, @RequestParam(value="ios_url",required=true) String ios_url, @RequestParam(value="android_url",required=true) String android_url, ModelMap model) throws IOException { logger.info("SynthesisQRCode - {}", "開始了"); logger.info("path - {}", request.getSession().getServletContext().getRealPath("/")); StringBuffer url = request.getRequestURL(); String tempContextUrl = url.delete(url.length() - request.getRequestURI().length(), url.length()).append(request.getContextPath()).append("/").toString(); logger.info("tempContextUrl - {}", tempContextUrl); String key_id = UuidUtil.generateShortUuid(); QRCode qRCode = new QRCode(); qRCode.setAndroid_url(android_url); qRCode.setIos_url(ios_url); qRCode.setKey_id(key_id); int intInsert = qRCodeService.insert(qRCode); String path = request.getSession().getServletContext().getRealPath("upload"); String fileName = new Date().getTime() + "qrcode.png"; File createFile = new File(path+"/"+fileName); //訪問路徑 服務器地址+ findAppUrl + key_id String urltxt = tempContextUrl+"findAppUrl/"+key_id; logger.info("urltxt - {}", urltxt); //生成二維碼 String imageBase64QRCode = ""; if(logoFile != null){ String logoFileName = logoFile.getOriginalFilename(); File targetFile = new File(path, logoFileName); if(!targetFile.exists()){ targetFile.mkdirs(); } logoFile.transferTo(targetFile); imageBase64QRCode = ZXingCodeUtil.getLogoQRCode(urltxt, request, "", targetFile, createFile); //刪除上傳的logo targetFile.delete(); }else{ imageBase64QRCode = ZXingCodeUtil.getQRCode(urltxt, request, "", createFile); } //二維碼地址 String qrcode_path = tempContextUrl+"upload/"+fileName; JsonResult jsonResult = new JsonResult(); Map data = new HashMap<String, String>(); data.put("recreateFlag", "0"); data.put("qrcode_path", qrcode_path); data.put("accessKey", "13598992"); data.put("shortUrl", urltxt); jsonResult.setData(data); jsonResult.setMeg("生成成功"); jsonResult.setRes(1); return jsonResult; } /** * url鏈接或者文本生成二維碼 * @param request * @param model * @return * @throws IOException */ @RequestMapping("urlQRCode") @ResponseBody public JsonResult UrlQRCode(HttpServletRequest request,ModelMap model, @RequestParam(value="file",required=false) CommonsMultipartFile logoFile, @RequestParam(value="urltxt",required=false) String urltxt) throws IOException { logger.info("UrlQRCode - {}", "開始了"); logger.info("頁面傳遞的文本內容- {}", urltxt); StringBuffer url = request.getRequestURL(); String tempContextUrl = url.delete(url.length() - request.getRequestURI().length(), url.length()).append(request.getContextPath()).append("/").toString(); String path = request.getSession().getServletContext().getRealPath("upload"); String fileName = new Date().getTime() + "url.png"; File createFile = new File(path+"/"+fileName); //生成二維碼 String imageBase64QRCode = ""; if(logoFile != null){ String logoFileName = logoFile.getOriginalFilename(); File targetFile = new File(path, logoFileName); if(!targetFile.exists()){ targetFile.mkdirs(); } logoFile.transferTo(targetFile); imageBase64QRCode = ZXingCodeUtil.getLogoQRCode(urltxt, request, "", targetFile, createFile); //刪除上傳的logo targetFile.delete(); }else{ imageBase64QRCode = ZXingCodeUtil.getQRCode(urltxt, request, "", createFile); } //二維碼地址 String qrcode_path = tempContextUrl+"upload/"+fileName; JsonResult jsonResult = new JsonResult(); Map data = new HashMap<String, String>(); data.put("qrcode_path", qrcode_path); data.put("qrcode", imageBase64QRCode); jsonResult.setData(data); jsonResult.setMeg("生成成功"); jsonResult.setRes(1); return jsonResult; } /** * 二維碼下載 * @param qrcode_path * @param request * @param response * @throws IOException */ @RequestMapping("/download") public void downloadFile(@RequestParam(value="qrcode_path",required=true) String qrcode_path, HttpServletRequest request, HttpServletResponse response) throws IOException { String destUrl = qrcode_path; // 建立鏈接 URL url = new URL(destUrl); HttpURLConnection httpUrl = (HttpURLConnection) url.openConnection(); // 連接指定的資源 httpUrl.connect(); // 獲取網絡輸入流 BufferedInputStream bis = new BufferedInputStream(httpUrl.getInputStream()); response.setContentType("application/x-msdownload"); response.setHeader("Content-Disposition", "attachment; filename="+java.net.URLEncoder.encode(new Date().getTime()+"url.png","UTF-8")); OutputStream out = response.getOutputStream(); byte[] buf = new byte[1024]; if (destUrl != null) { BufferedInputStream br = bis; int len = 0; while ((len = br.read(buf)) > 0){ out.write(buf, 0, len); } br.close(); } out.flush(); out.close(); } /** * 二維碼解析 * @param request * @param model * @return * @throws IOException */ @RequestMapping("parseQRCode") @ResponseBody public JsonResult ParseQRCode(HttpServletRequest request,ModelMap model, @RequestParam(value="file",required=false) CommonsMultipartFile logoFile) throws IOException { logger.info("ParseQRCode - {}", "開始了"); StringBuffer url = request.getRequestURL(); String tempContextUrl = url.delete(url.length() - request.getRequestURI().length(), url.length()).append(request.getContextPath()).append("/").toString(); String path = request.getSession().getServletContext().getRealPath("upload"); String logoFileName = logoFile.getOriginalFilename(); File targetFile = new File(path, logoFileName); if(!targetFile.exists()){ targetFile.mkdirs(); } logoFile.transferTo(targetFile); String text = ZXingCodeUtil.parseQRCode(targetFile); targetFile.delete(); logger.info("解析結果 - {}", text); JsonResult jsonResult = new JsonResult(); Map data = new HashMap<String, String>(); data.put("text", text); jsonResult.setData(data); jsonResult.setMeg("生成成功"); jsonResult.setRes(1); return jsonResult; } }
最后搭建完成的項目如下:
一、APP二維碼合並,用蘋果手機掃描自動打開App Store頁面下載APP,用安卓手機掃碼自動打開應用頁面下載APP。
二、網址生成二維碼
三、生成的二維碼識別