java二维码生成 使用SSM框架 搭建属于自己的APP二维码合成、解析、下载

来源:互联网 发布:淘宝买快排警察找我 编辑:程序博客网 时间:2024/05/21 19:23

最近公司的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

[html] view plain copy
  1. <?xml version="1.0"?>  
  2. <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"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">  
  4.   <modelVersion>4.0.0</modelVersion>  
  5.   <parent>  
  6.     <groupId>com.jiafuwei.spring</groupId>  
  7.     <artifactId>spring-parent</artifactId>  
  8.     <version>0.0.1-SNAPSHOT</version>  
  9.   </parent>  
  10.     
  11.   <groupId>com.jiafuwei.spring</groupId>  
  12.   <artifactId>spring-mvc-web</artifactId>  
  13.   <version>0.0.1-SNAPSHOT</version>  
  14.   <packaging>war</packaging>  
  15.     
  16.   <name>spring-mvc-web Maven Webapp</name>  
  17.   <url>http://maven.apache.org</url>  
  18.     
  19.   <properties>  
  20.         <spring.version>4.2.7.RELEASE</spring.version>  
  21.         <jackson.version>2.6.7</jackson.version>  
  22.         <!-- mybatis版本号 -->    
  23.         <mybatis.version>3.2.6</mybatis.version>   
  24.         <!-- freemarker模板包版本 -->  
  25.         <freemarker.version>2.3.23</freemarker.version>   
  26.         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
  27.   </properties>  
  28.     
  29.     
  30.   <dependencies>  
  31.      <!-- freemarker依赖 -->  
  32.      <dependency>  
  33.        <groupId>org.freemarker</groupId>  
  34.        <artifactId>freemarker</artifactId>  
  35.        <version>${freemarker.version}</version>  
  36.      </dependency>  
  37.         
  38.     <!-- spring mvc 框架 -->  
  39.     <dependency>  
  40.         <groupId>org.springframework</groupId>  
  41.         <artifactId>spring-webmvc</artifactId>  
  42.         <version>${spring.version}</version>  
  43.     </dependency>  
  44.         
  45.         <dependency>    
  46.             <groupId>org.springframework</groupId>    
  47.             <artifactId>spring-jdbc</artifactId>    
  48.             <version>${spring.version}</version>    
  49.         </dependency>  
  50.           
  51.         <dependency>    
  52.             <groupId>org.springframework</groupId>    
  53.             <artifactId>spring-context-support</artifactId>    
  54.             <version>${spring.version}</version>    
  55.         </dependency>  
  56.           
  57.         <dependency>    
  58.             <groupId>org.springframework</groupId>    
  59.             <artifactId>spring-test</artifactId>    
  60.             <version>${spring.version}</version>    
  61.         </dependency>   
  62.           
  63.         <dependency>  
  64.             <groupId>c3p0</groupId>  
  65.             <artifactId>c3p0</artifactId>  
  66.              <version>0.9.1.2</version>  
  67.         </dependency>  
  68.           
  69.          <!-- 导入Mysql数据库链接jar包 -->    
  70.         <dependency>  
  71.             <groupId>mysql</groupId>  
  72.             <artifactId>mysql-connector-java</artifactId>  
  73.             <version>5.1.4</version>  
  74.         </dependency>   
  75.           
  76.         <!-- mybatis核心包 -->    
  77.         <dependency>    
  78.             <groupId>org.mybatis</groupId>    
  79.             <artifactId>mybatis</artifactId>    
  80.             <version>${mybatis.version}</version>    
  81.         </dependency>    
  82.         <!-- mybatis/spring包 -->    
  83.         <dependency>    
  84.             <groupId>org.mybatis</groupId>    
  85.             <artifactId>mybatis-spring</artifactId>    
  86.             <version>1.2.2</version>    
  87.         </dependency>   
  88.           
  89.          <!-- 上传组件包 -->    
  90.         <dependency>    
  91.             <groupId>commons-fileupload</groupId>    
  92.             <artifactId>commons-fileupload</artifactId>    
  93.             <version>1.3.1</version>    
  94.         </dependency>    
  95.         <dependency>    
  96.             <groupId>commons-io</groupId>    
  97.             <artifactId>commons-io</artifactId>    
  98.             <version>2.4</version>    
  99.         </dependency>    
  100.         <dependency>    
  101.             <groupId>commons-codec</groupId>    
  102.             <artifactId>commons-codec</artifactId>    
  103.             <version>1.9</version>    
  104.         </dependency>   
  105.       
  106.     <!-- servlet -->  
  107.     <dependency>  
  108.         <groupId>javax.servlet</groupId>  
  109.         <artifactId>servlet-api</artifactId>  
  110.         <version>2.5</version>  
  111.     </dependency>  
  112.       
  113.     <!-- jsp/jstl/core 页面标签 -->  
  114.     <dependency>  
  115.         <groupId>javax.servlet</groupId>  
  116.         <artifactId>jstl</artifactId>  
  117.         <version>1.2</version>  
  118.     </dependency>  
  119.     <dependency>  
  120.         <groupId>taglibs</groupId>  
  121.         <artifactId>standard</artifactId>  
  122.         <version>1.1.2</version>  
  123.     </dependency>  
  124.       
  125.     <!-- SLF4J API -->  
  126.     <!-- SLF4J 是一个日志抽象层,允许你使用任何一个日志系统,并且可以随时切换还不需要动到已经写好的程序 -->  
  127.     <dependency>  
  128.         <groupId>org.slf4j</groupId>  
  129.         <artifactId>slf4j-api</artifactId>  
  130.         <version>1.7.22</version>  
  131.     </dependency>  
  132.       
  133.     <!-- Log4j 日志系统(最常用) -->  
  134.     <dependency>  
  135.         <groupId>org.slf4j</groupId>  
  136.         <artifactId>slf4j-log4j12</artifactId>  
  137.         <version>1.7.22</version>  
  138.     </dependency>  
  139.       
  140.     <!-- jackson -->  
  141.     <dependency>  
  142.         <groupId>com.fasterxml.jackson.core</groupId>  
  143.         <artifactId>jackson-core</artifactId>  
  144.         <version>${jackson.version}</version>  
  145.     </dependency>  
  146.     <dependency>  
  147.         <groupId>com.fasterxml.jackson.core</groupId>  
  148.         <artifactId>jackson-annotations</artifactId>  
  149.         <version>${jackson.version}</version>  
  150.     </dependency>  
  151.     <dependency>  
  152.         <groupId>com.fasterxml.jackson.core</groupId>  
  153.         <artifactId>jackson-databind</artifactId>  
  154.         <version>${jackson.version}</version>  
  155.     </dependency>  
  156.         
  157.     <dependency>  
  158.       <groupId>junit</groupId>  
  159.       <artifactId>junit</artifactId>  
  160.       <version>3.8.1</version>  
  161.       <scope>test</scope>  
  162.     </dependency>  
  163.       
  164.     <!-- 二维码 -->  
  165.     <dependency>  
  166.         <groupId>com.google.zxing</groupId>  
  167.         <artifactId>core</artifactId>  
  168.         <version>3.1.0</version>  
  169.     </dependency>  
  170.       
  171.     <dependency>    
  172.         <groupId>com.google.zxing</groupId>    
  173.         <artifactId>javase</artifactId>    
  174.         <version>3.0.0</version>    
  175.     </dependency>   
  176.       
  177.        
  178.       
  179.     <!-- swagger2整合springmvc快速生成rest风格接口文档 -->  
  180.     <dependency>  
  181.         <groupId>io.springfox</groupId>  
  182.         <artifactId>springfox-swagger2</artifactId>  
  183.         <version>2.5.0</version>  
  184.     </dependency>  
  185.     <dependency>  
  186.         <groupId>io.springfox</groupId>  
  187.         <artifactId>springfox-swagger-ui</artifactId>  
  188.         <version>2.5.0</version>  
  189.     </dependency>  
  190.       
  191.   </dependencies>  
  192.     
  193.   <build>  
  194.     <finalName>spring-mvc-web</finalName>  
  195.   </build>  
  196. </project>  

二维码生成、解析工具类ZXingCodeUtil.java 

[java] view plain copy
  1. package com.jiafuwei.spring.util;  
  2.   
  3. import java.awt.Color;  
  4. import java.awt.Font;  
  5. import java.awt.Graphics2D;  
  6. import java.awt.image.BufferedImage;  
  7. import java.io.ByteArrayOutputStream;  
  8. import java.io.File;  
  9. import java.io.IOException;  
  10.   
  11. import java.util.HashMap;  
  12. import java.util.Map;  
  13. import javax.imageio.ImageIO;  
  14. import javax.servlet.http.HttpServletRequest;  
  15. import com.google.zxing.BarcodeFormat;  
  16. import com.google.zxing.Binarizer;  
  17. import com.google.zxing.BinaryBitmap;  
  18. import com.google.zxing.DecodeHintType;  
  19. import com.google.zxing.EncodeHintType;  
  20. import com.google.zxing.LuminanceSource;  
  21. import com.google.zxing.MultiFormatReader;  
  22. import com.google.zxing.MultiFormatWriter;  
  23. import com.google.zxing.NotFoundException;  
  24. import com.google.zxing.Result;  
  25. import com.google.zxing.WriterException;  
  26. import com.google.zxing.client.j2se.BufferedImageLuminanceSource;  
  27. import com.google.zxing.common.BitMatrix;  
  28. import com.google.zxing.common.HybridBinarizer;  
  29. import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;  
  30.   
  31.   
  32. /** 
  33.  * @Description: (二维码生成工具类) 
  34.  * @author jiafuwei 
  35.  * @date:2017-03-01 下午05:27:13 
  36.  */  
  37. public class ZXingCodeUtil {  
  38.     private static final int QRCOLOR = 0xFF000000;   //默认是黑色  
  39.     private static final int BGWHITE = 0xFFFFFFFF;   //背景颜色  
  40.   
  41.   
  42.     public static void main(String[] args) throws WriterException{    
  43.         try {    
  44.             //getLogoQRCode("https://www.baidu.com/", null, "跳转到百度的二维码");  
  45.             //getQRCode("https://www.baidu.com/", null, "跳转到百度的二维码");  
  46.               
  47.         }    
  48.         catch (Exception e)  {    
  49.             e.printStackTrace();    
  50.         }    
  51.     }    
  52.       
  53.     /** 
  54.      * 二维码解析 
  55.      * @param file 二维码图片文件 
  56.      * @return 解析结果 
  57.      */  
  58.     public static String parseQRCode(File file) {  
  59.         BufferedImage image;    
  60.         try {    
  61.             image = ImageIO.read(file);    
  62.             LuminanceSource source = new BufferedImageLuminanceSource(image);    
  63.             Binarizer binarizer = new HybridBinarizer(source);    
  64.             BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);    
  65.             Map<DecodeHintType, Object> hints = new HashMap<DecodeHintType, Object>();    
  66.             hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");    
  67.             Result result = new MultiFormatReader().decode(binaryBitmap, hints);// 对图像进行解码    
  68.             return result.getText();  
  69.         } catch (IOException e) {    
  70.             e.printStackTrace();   
  71.             return null;  
  72.         } catch (NotFoundException e) {    
  73.             e.printStackTrace();  
  74.             return null;  
  75.         }    
  76.     }  
  77.       
  78.       
  79.     /** 
  80.      * 生成不带logo的二维码 
  81.      * @param qrUrl 链接地址 
  82.      * @param request 请求 
  83.      * @param productName 二维码名称 
  84.      * @param file 上传路径+文件名 
  85.      * @return 
  86.      */  
  87.     public static String getQRCode(String qrUrl,HttpServletRequest request,String productName,File file ) {  
  88.         // String filePath = request.getSession().getServletContext().getRealPath("/") + "resources/images/logoImages/llhlogo.png";  
  89.         //filePath是二维码logo的路径,但是实际中我们是放在项目的某个路径下面的,所以路径用上面的,把下面的注释就好  
  90.           
  91.         String content = qrUrl;  
  92.         try {    
  93.             ZXingCodeUtil zp = new ZXingCodeUtil();  
  94.             BufferedImage image = zp.getQR_CODEBufferedImage(content, BarcodeFormat.QR_CODE, 400400, zp.getDecodeHintType());  
  95.             image.flush();  
  96.             ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  97.             baos.flush();  
  98.             ImageIO.write(image, "png", baos);  
  99.             //二维码生成的路径,但是实际项目中,我们是把这生成的二维码显示到界面上的,因此下面的折行代码可以注释掉  
  100.             //可以看到这个方法最终返回的是这个二维码的imageBase64字符串  
  101.             //前端用 <img src="data:image/png;base64,${imageBase64QRCode}"/> 其中${imageBase64QRCode}对应二维码的imageBase64字符串  
  102.             //new File("E:/" + new Date().getTime() + "test.png")  
  103.             //判断目标文件所在的目录是否存在    
  104.             if(!file.getParentFile().exists()) {    
  105.                 //如果目标文件所在的目录不存在,则创建父目录    
  106.                 System.out.println("目标文件所在目录不存在,准备创建它!");    
  107.                 if(!file.getParentFile().mkdirs()) {    
  108.                     System.out.println("创建目标文件所在目录失败!");    
  109.                 }    
  110.             }  
  111.             ImageIO.write(image, "png", file);   
  112.              
  113.             String imageBase64QRCode =  new sun.misc.BASE64Encoder().encodeBuffer(baos.toByteArray());  
  114.             baos.close();  
  115.             return imageBase64QRCode;  
  116.         }  
  117.         catch (Exception e){  
  118.             e.printStackTrace();  
  119.         }  
  120.         return null;  
  121.     }  
  122.   
  123.     /** 
  124.      * 生成带logo的二维码图片 
  125.      * @param qrUrl 链接地址 
  126.      * @param request 请求 
  127.      * @param productName 二维码名称 
  128.      * @param logoFile logo文件 
  129.      * @param createFile 生成的文件路径 
  130.      * @return 
  131.      */  
  132.     public static String getLogoQRCode(String qrUrl,HttpServletRequest request,String productName,File logoFile,File createFile) {  
  133.         // String filePath = request.getSession().getServletContext().getRealPath("/") + "resources/images/logoImages/llhlogo.png";  
  134.         //filePath是二维码logo的路径,但是实际中我们是放在项目的某个路径下面的,所以路径用上面的,把下面的注释就好  
  135.         String content = qrUrl;  
  136.         try{    
  137.             ZXingCodeUtil zp = new ZXingCodeUtil();  
  138.             BufferedImage bim = zp.getQR_CODEBufferedImage(content, BarcodeFormat.QR_CODE, 400400, zp.getDecodeHintType());  
  139.             return zp.addLogo_QRCode(bim, logoFile , new LogoConfig(), productName, createFile);  
  140.         }  
  141.         catch (Exception e) {  
  142.             e.printStackTrace();  
  143.         }  
  144.         return null;  
  145.     }  
  146.   
  147.     /** * 给二维码图片添加Logo * * @param qrPic * @param logoPic */  
  148.     public String addLogo_QRCode(BufferedImage bim, File logoPic, LogoConfig logoConfig, String productName, File createFile) {  
  149.         try {  
  150.             /** * 读取二维码图片,并构建绘图对象 */  
  151.             BufferedImage image = bim;  
  152.             Graphics2D g = image.createGraphics();  
  153.   
  154.             /** * 读取Logo图片 */  
  155.             BufferedImage logo = ImageIO.read(logoPic);  
  156.             /** * 设置logo的大小,本人设置为二维码图片的20%,因为过大会盖掉二维码 */  
  157.             int widthLogo = logo.getWidth(null)>image.getWidth()*3/10?(image.getWidth()*3/10):logo.getWidth(null),   
  158.                 heightLogo = logo.getHeight(null)>image.getHeight()*3/10?(image.getHeight()*3/10):logo.getWidth(null);  
  159.   
  160.             /** * logo放在中心 */  
  161.              int x = (image.getWidth() - widthLogo) / 2;  
  162.              int y = (image.getHeight() - heightLogo) / 2;  
  163.              /** * logo放在右下角 * int x = (image.getWidth() - widthLogo); * int y = (image.getHeight() - heightLogo); */  
  164.   
  165.             //开始绘制图片  
  166.             g.drawImage(logo, x, y, widthLogo, heightLogo, null);  
  167.             // g.drawRoundRect(x, y, widthLogo, heightLogo, 15, 15);  
  168.             // g.setStroke(new BasicStroke(logoConfig.getBorder()));  
  169.             // g.setColor(logoConfig.getBorderColor());  
  170.             // g.drawRect(x, y, widthLogo, heightLogo);  
  171.             g.dispose();  
  172.   
  173.             //把商品名称添加上去,商品名称不要太长哦,这里最多支持两行。太长就会自动截取啦  
  174.             if (productName != null && !productName.equals("")) {  
  175.                 //新的图片,把带logo的二维码下面加上文字  
  176.                 BufferedImage outImage = new BufferedImage(400445, BufferedImage.TYPE_4BYTE_ABGR);  
  177.                 Graphics2D outg = outImage.createGraphics();  
  178.                 //画二维码到新的面板  
  179.                 outg.drawImage(image, 00, image.getWidth(), image.getHeight(), null);  
  180.                 //画文字到新的面板  
  181.                 outg.setColor(Color.BLACK);   
  182.                 outg.setFont(new Font("宋体",Font.BOLD,30)); //字体、字型、字号   
  183.                 int strWidth = outg.getFontMetrics().stringWidth(productName);  
  184.                 if (strWidth > 399) {  
  185.                     // //长度过长就截取前面部分  
  186.                     // outg.drawString(productName, 0, image.getHeight() + (outImage.getHeight() - image.getHeight())/2 + 5 ); //画文字  
  187.                     //长度过长就换行  
  188.                     String productName1 = productName.substring(0, productName.length()/2);  
  189.                     String productName2 = productName.substring(productName.length()/2, productName.length());  
  190.                     int strWidth1 = outg.getFontMetrics().stringWidth(productName1);  
  191.                     int strWidth2 = outg.getFontMetrics().stringWidth(productName2);  
  192.                     outg.drawString(productName1, 200  - strWidth1/2, image.getHeight() + (outImage.getHeight() - image.getHeight())/2 + 12 );  
  193.                     BufferedImage outImage2 = new BufferedImage(400485, BufferedImage.TYPE_4BYTE_ABGR);  
  194.                     Graphics2D outg2 = outImage2.createGraphics();  
  195.                     outg2.drawImage(outImage, 00, outImage.getWidth(), outImage.getHeight(), null);  
  196.                     outg2.setColor(Color.BLACK);   
  197.                     outg2.setFont(new Font("宋体",Font.BOLD,30)); //字体、字型、字号   
  198.                     outg2.drawString(productName2, 200  - strWidth2/2, outImage.getHeight() + (outImage2.getHeight() - outImage.getHeight())/2 + 5 );  
  199.                     outg2.dispose();   
  200.                     outImage2.flush();  
  201.                     outImage = outImage2;  
  202.                 }else {  
  203.                     outg.drawString(productName, 200  - strWidth/2 , image.getHeight() + (outImage.getHeight() - image.getHeight())/2 + 12 ); //画文字   
  204.                 }  
  205.                 outg.dispose();   
  206.                 outImage.flush();  
  207.                 image = outImage;  
  208.             }  
  209.             logo.flush();  
  210.             image.flush();  
  211.             ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  212.             baos.flush();  
  213.             ImageIO.write(image, "png", baos);  
  214.   
  215.             //二维码生成的路径,但是实际项目中,我们是把这生成的二维码显示到界面上的,因此下面的折行代码可以注释掉  
  216.             //可以看到这个方法最终返回的是这个二维码的imageBase64字符串  
  217.             //前端用 <img src="data:image/png;base64,${imageBase64QRCode}"/> 其中${imageBase64QRCode}对应二维码的imageBase64字符串  
  218.             if(!createFile.getParentFile().exists()) {    
  219.                 //如果目标文件所在的目录不存在,则创建父目录    
  220.                 System.out.println("目标文件所在目录不存在,准备创建它!");    
  221.                 if(!createFile.getParentFile().mkdirs()) {    
  222.                     System.out.println("创建目标文件所在目录失败!");    
  223.                 }    
  224.             }  
  225.             ImageIO.write(image, "png", createFile);   
  226.              
  227.             String imageBase64QRCode =  new sun.misc.BASE64Encoder().encodeBuffer(baos.toByteArray());  
  228.             baos.close();  
  229.             return imageBase64QRCode;  
  230.         }  
  231.         catch (Exception e){  
  232.             e.printStackTrace();  
  233.         }  
  234.         return null;  
  235.     }  
  236.   
  237.   
  238.     /** * 构建初始化二维码 * * @param bm * @return */  
  239.     public BufferedImage fileToBufferedImage(BitMatrix bm){  
  240.         BufferedImage image = null;  
  241.         try  
  242.         {  
  243.             int w = bm.getWidth(), h = bm.getHeight();  
  244.             image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);  
  245.   
  246.             for (int x = 0; x < w; x++)  
  247.             {  
  248.                 for (int y = 0; y < h; y++)  
  249.                 {  
  250.                     image.setRGB(x, y, bm.get(x, y) ? 0xFF000000 : 0xFFCCDDEE);  
  251.                 }  
  252.             }  
  253.   
  254.         }  
  255.         catch (Exception e){  
  256.             e.printStackTrace();  
  257.         }  
  258.         return image;  
  259.     }  
  260.   
  261.     /** * 生成二维码bufferedImage图片 * * @param content * 编码内容 * @param barcodeFormat * 编码类型 * @param width * 图片宽度 * @param height * 图片高度 * @param hints * 设置参数 * @return */  
  262.     public BufferedImage getQR_CODEBufferedImage(String content, BarcodeFormat barcodeFormat, int width, int height, Map<EncodeHintType, ?> hints) {  
  263.         MultiFormatWriter multiFormatWriter = null;  
  264.         BitMatrix bm = null;  
  265.         BufferedImage image = null;  
  266.         try{  
  267.             multiFormatWriter = new MultiFormatWriter();  
  268.             // 参数顺序分别为:编码内容,编码类型,生成图片宽度,生成图片高度,设置参数  
  269.             bm = multiFormatWriter.encode(content, barcodeFormat, width, height, hints);  
  270.             int w = bm.getWidth();  
  271.             int h = bm.getHeight();  
  272.             image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);  
  273.   
  274.             // 开始利用二维码数据创建Bitmap图片,分别设为黑(0xFFFFFFFF)白(0xFF000000)两色  
  275.             for (int x = 0; x < w; x++){  
  276.                 for (int y = 0; y < h; y++) {  
  277.                     image.setRGB(x, y, bm.get(x, y) ? QRCOLOR : BGWHITE);  
  278.                 }  
  279.             }  
  280.         }  
  281.         catch (WriterException e){  
  282.             e.printStackTrace();  
  283.         }  
  284.         return image;  
  285.     }  
  286.   
  287.     /** * 设置二维码的格式参数 * * @return */  
  288.     public Map<EncodeHintType, Object> getDecodeHintType() {  
  289.         // 用于设置QR二维码参数  
  290.         Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();  
  291.         // 设置QR二维码的纠错级别(H为最高级别)具体级别信息  
  292.         hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);  
  293.         // 设置编码方式  
  294.         hints.put(EncodeHintType.CHARACTER_SET, "utf-8");  
  295.         hints.put(EncodeHintType.MARGIN, 0);  
  296.         hints.put(EncodeHintType.MAX_SIZE, 350);  
  297.         hints.put(EncodeHintType.MIN_SIZE, 100);  
  298.   
  299.         return hints;  
  300.     }  
  301. }  
  302.   
  303.     class LogoConfig {  
  304.         // logo默认边框颜色  
  305.         public static final Color DEFAULT_BORDERCOLOR = Color.WHITE;  
  306.         // logo默认边框宽度  
  307.         public static final int DEFAULT_BORDER = 2;  
  308.         // logo大小默认为照片的1/5  
  309.         public static final int DEFAULT_LOGOPART = 5;  
  310.   
  311.         private final int border = DEFAULT_BORDER;  
  312.         private final Color borderColor;  
  313.         private final int logoPart;  
  314.   
  315.         /** * Creates a default config with on color {@link #BLACK} and off color * {@link #WHITE}, generating normal black-on-white barcodes. */  
  316.         public LogoConfig(){  
  317.             this(DEFAULT_BORDERCOLOR, DEFAULT_LOGOPART);  
  318.         }  
  319.   
  320.         public LogoConfig(Color borderColor, int logoPart){  
  321.             this.borderColor = borderColor;  
  322.             this.logoPart = logoPart;  
  323.         }  
  324.   
  325.         public Color getBorderColor() {  
  326.             return borderColor;  
  327.         }  
  328.   
  329.         public int getBorder(){  
  330.             return border;  
  331.         }  
  332.   
  333.         public int getLogoPart() {  
  334.             return logoPart;  
  335.         }  
  336.     }  
 8位短uuid生成工具类

[java] view plain copy
  1. package com.jiafuwei.spring.util;  
  2.   
  3. import java.awt.Color;  
  4. import java.awt.Font;  
  5. import java.awt.Graphics2D;  
  6. import java.awt.image.BufferedImage;  
  7. import java.io.ByteArrayOutputStream;  
  8. import java.io.File;  
  9. import java.io.IOException;  
  10. import java.util.Date;  
  11. import java.util.HashMap;  
  12. import java.util.Map;  
  13. import java.util.UUID;  
  14.   
  15. import javax.imageio.ImageIO;  
  16. import javax.servlet.http.HttpServletRequest;  
  17. import com.google.zxing.BarcodeFormat;  
  18. import com.google.zxing.EncodeHintType;  
  19. import com.google.zxing.MultiFormatWriter;  
  20. import com.google.zxing.WriterException;  
  21. import com.google.zxing.common.BitMatrix;  
  22. import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;  
  23.   
  24.   
  25. /** 
  26.  * @Description: 短uuid生成 
  27.  * @author jiafuwei 
  28.  * @date:2017-03-02 下午05:27:13 
  29.  */  
  30. public class UuidUtil {  
  31.      
  32.   
  33.   
  34.     public static void main(String[] args) throws WriterException{    
  35.         String uuid = generateShortUuid();  
  36.         System.out.println(uuid);  
  37.     }    
  38.   
  39.     public static String[] chars = new String[] { "a""b""c""d""e""f",    
  40.         "g""h""i""j""k""l""m""n""o""p""q""r""s",    
  41.         "t""u""v""w""x""y""z""0""1""2""3""4""5",    
  42.         "6""7""8""9""A""B""C""D""E""F""G""H""I",    
  43.         "J""K""L""M""N""O""P""Q""R""S""T""U""V",    
  44.         "W""X""Y""Z" };    
  45.   
  46.   
  47.     public static String generateShortUuid() {    
  48.         StringBuffer shortBuffer = new StringBuffer();    
  49.         String uuid = UUID.randomUUID().toString().replace("-""");    
  50.         for (int i = 0; i < 8; i++) {    
  51.             String str = uuid.substring(i * 4, i * 4 + 4);    
  52.             int x = Integer.parseInt(str, 16);    
  53.             shortBuffer.append(chars[x % 0x3E]);    
  54.         }    
  55.         return shortBuffer.toString();    
  56.       
  57.     }    
  58.       
  59.       
  60.       
  61. }  
  62.   
  63.      

核心控制器

[java] view plain copy
  1. package com.jiafuwei.spring.controller;  
  2.   
  3. import java.io.BufferedInputStream;  
  4. import java.io.File;    
  5. import java.io.FileNotFoundException;  
  6. import java.io.FileOutputStream;  
  7. import java.io.IOException;  
  8. import java.io.InputStream;  
  9. import java.io.OutputStream;  
  10. import java.net.HttpURLConnection;  
  11. import java.net.URL;  
  12. import java.util.Date;    
  13. import java.util.HashMap;  
  14. import java.util.Map;  
  15.     
  16. import javax.servlet.http.HttpServletRequest;    
  17. import javax.servlet.http.HttpServletResponse;  
  18.     
  19. import org.slf4j.Logger;  
  20. import org.slf4j.LoggerFactory;  
  21. import org.springframework.beans.factory.annotation.Autowired;  
  22. import org.springframework.stereotype.Controller;    
  23. import org.springframework.ui.ModelMap;    
  24. import org.springframework.web.bind.annotation.RequestMapping;    
  25. import org.springframework.web.bind.annotation.RequestMethod;  
  26. import org.springframework.web.bind.annotation.RequestParam;    
  27. import org.springframework.web.bind.annotation.ResponseBody;  
  28. import org.springframework.web.multipart.MultipartFile;    
  29. import org.springframework.web.multipart.MultipartHttpServletRequest;  
  30. import org.springframework.web.multipart.commons.CommonsMultipartFile;  
  31.   
  32. import com.jiafuwei.spring.po.JsonResult;  
  33. import com.jiafuwei.spring.po.QRCode;  
  34. import com.jiafuwei.spring.service.IQRCodeService;  
  35. import com.jiafuwei.spring.util.UuidUtil;  
  36. import com.jiafuwei.spring.util.ZXingCodeUtil;  
  37.     
  38. @Controller    
  39. public class UploadController {    
  40.     final Logger logger = LoggerFactory.getLogger(getClass());  
  41.       
  42.     @Autowired  
  43.     private IQRCodeService qRCodeService;  
  44.    
  45.     /* 
  46.      * 通过流的方式上传文件 
  47.      * @RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象 
  48.      */  
  49.     @RequestMapping("fileUpload")  
  50.     public String  fileUpload(@RequestParam("file") CommonsMultipartFile file,HttpServletRequest request,  
  51.             ModelMap model) throws IOException {  
  52.            
  53.            
  54.         //用来检测程序运行时间  
  55.         long  startTime=System.currentTimeMillis();  
  56.         String path = request.getSession().getServletContext().getRealPath("upload");   
  57.         String fileName = file.getOriginalFilename();  
  58.         System.out.println("fileName:"+fileName);  
  59.           
  60.         File targetFile = new File(path, fileName);    
  61.         if(!targetFile.exists()){    
  62.             targetFile.mkdirs();    
  63.         }   
  64.         file.transferTo(targetFile);  
  65.           
  66.         model.addAttribute("fileUrl", request.getContextPath()+"/upload/"+fileName);    
  67.           
  68.          
  69.         long  endTime=System.currentTimeMillis();  
  70.         System.out.println("方法一的运行时间:"+String.valueOf(endTime-startTime)+"ms");  
  71.         return "/result";   
  72.     }  
  73.     
  74.       
  75.     @RequestMapping("fileUploadLogo")  
  76.     @ResponseBody  
  77.     public String  fileUploadLogo(@RequestParam("file") CommonsMultipartFile file,HttpServletRequest request,  
  78.             ModelMap model) throws IOException {  
  79.            
  80.            
  81.         //用来检测程序运行时间  
  82.         long  startTime=System.currentTimeMillis();  
  83.         String path = request.getSession().getServletContext().getRealPath("upload");   
  84.         String fileName = file.getOriginalFilename();  
  85.         System.out.println("fileName:"+fileName);  
  86.           
  87.         File targetFile = new File(path, fileName);    
  88.         if(!targetFile.exists()){    
  89.             targetFile.mkdirs();    
  90.         }   
  91.         file.transferTo(targetFile);  
  92.           
  93.         model.addAttribute("fileUrl", request.getContextPath()+"/upload/"+fileName);    
  94.           
  95.          
  96.         long  endTime=System.currentTimeMillis();  
  97.         System.out.println("方法一的运行时间:"+String.valueOf(endTime-startTime)+"ms");  
  98.         return "result";   
  99.     }  
  100.       
  101.     /** 
  102.      * APP 合成二维码生成 
  103.      * @param request 
  104.      * @param model 
  105.      * @return 
  106.      * @throws IOException 
  107.      */  
  108.     @RequestMapping("synthesisQRCode")  
  109.     @ResponseBody  
  110.     public JsonResult  SynthesisQRCode(HttpServletRequest request,  
  111.             @RequestParam(value="file",required=false) CommonsMultipartFile logoFile,  
  112.             @RequestParam(value="ios_url",required=true) String ios_url,  
  113.             @RequestParam(value="android_url",required=true) String android_url,  
  114.             ModelMap model) throws IOException {  
  115.           
  116.          logger.info("SynthesisQRCode - {}""开始了");  
  117.          logger.info("path - {}", request.getSession().getServletContext().getRealPath("/"));  
  118.            
  119.          StringBuffer url = request.getRequestURL();    
  120.          String tempContextUrl = url.delete(url.length() - request.getRequestURI().length(), url.length()).append(request.getContextPath()).append("/").toString();   
  121.          logger.info("tempContextUrl - {}", tempContextUrl);  
  122.            
  123.          String key_id = UuidUtil.generateShortUuid();  
  124.          QRCode qRCode = new QRCode();  
  125.          qRCode.setAndroid_url(android_url);  
  126.          qRCode.setIos_url(ios_url);  
  127.          qRCode.setKey_id(key_id);  
  128.          int intInsert = qRCodeService.insert(qRCode);  
  129.            
  130.          String path = request.getSession().getServletContext().getRealPath("upload");  
  131.          String fileName = new Date().getTime() + "qrcode.png";  
  132.          File createFile = new File(path+"/"+fileName);  
  133.            
  134.          //访问路径 服务器地址+ findAppUrl + key_id  
  135.          String urltxt = tempContextUrl+"findAppUrl/"+key_id;  
  136.          logger.info("urltxt - {}", urltxt);  
  137.            
  138.          //生成二维码  
  139.          String imageBase64QRCode = "";  
  140.          if(logoFile != null){  
  141.              String logoFileName = logoFile.getOriginalFilename();  
  142.              File targetFile = new File(path, logoFileName);    
  143.              if(!targetFile.exists()){    
  144.                  targetFile.mkdirs();    
  145.              }   
  146.              logoFile.transferTo(targetFile);  
  147.              imageBase64QRCode = ZXingCodeUtil.getLogoQRCode(urltxt, request, "", targetFile, createFile);  
  148.              //删除上传的logo  
  149.              targetFile.delete();  
  150.          }else{  
  151.              imageBase64QRCode = ZXingCodeUtil.getQRCode(urltxt, request, "", createFile);  
  152.          }  
  153.            
  154.          //二维码地址  
  155.          String qrcode_path = tempContextUrl+"upload/"+fileName;  
  156.            
  157.          JsonResult jsonResult = new JsonResult();  
  158.          Map data = new HashMap<String, String>();  
  159.          data.put("recreateFlag""0");  
  160.          data.put("qrcode_path", qrcode_path);  
  161.          data.put("accessKey""13598992");  
  162.          data.put("shortUrl", urltxt);  
  163.          jsonResult.setData(data);  
  164.          jsonResult.setMeg("生成成功");  
  165.          jsonResult.setRes(1);  
  166.        
  167.         return jsonResult;   
  168.     }  
  169.       
  170.     /** 
  171.      * url链接或者文本生成二维码 
  172.      * @param request 
  173.      * @param model 
  174.      * @return 
  175.      * @throws IOException 
  176.      */  
  177.     @RequestMapping("urlQRCode")  
  178.     @ResponseBody  
  179.     public JsonResult  UrlQRCode(HttpServletRequest request,ModelMap model,  
  180.             @RequestParam(value="file",required=false) CommonsMultipartFile logoFile,  
  181.             @RequestParam(value="urltxt",required=false) String urltxt) throws IOException {  
  182.           
  183.          logger.info("UrlQRCode - {}""开始了");  
  184.          logger.info("页面传递的文本内容- {}", urltxt);  
  185.            
  186.          StringBuffer url = request.getRequestURL();    
  187.          String tempContextUrl = url.delete(url.length() - request.getRequestURI().length(), url.length()).append(request.getContextPath()).append("/").toString();   
  188.            
  189.            
  190.          String path = request.getSession().getServletContext().getRealPath("upload");  
  191.          String fileName = new Date().getTime() + "url.png";  
  192.          File createFile = new File(path+"/"+fileName);  
  193.          //生成二维码  
  194.          String imageBase64QRCode = "";  
  195.          if(logoFile != null){  
  196.              String logoFileName = logoFile.getOriginalFilename();  
  197.              File targetFile = new File(path, logoFileName);    
  198.              if(!targetFile.exists()){    
  199.                  targetFile.mkdirs();    
  200.              }   
  201.              logoFile.transferTo(targetFile);  
  202.              imageBase64QRCode = ZXingCodeUtil.getLogoQRCode(urltxt, request, "", targetFile, createFile);  
  203.              //删除上传的logo  
  204.              targetFile.delete();  
  205.          }else{  
  206.              imageBase64QRCode = ZXingCodeUtil.getQRCode(urltxt, request, "", createFile);  
  207.          }  
  208.            
  209.          //二维码地址  
  210.          String qrcode_path = tempContextUrl+"upload/"+fileName;  
  211.            
  212.          JsonResult jsonResult = new JsonResult();  
  213.          Map data = new HashMap<String, String>();  
  214.          data.put("qrcode_path", qrcode_path);  
  215.          data.put("qrcode", imageBase64QRCode);  
  216.          jsonResult.setData(data);  
  217.          jsonResult.setMeg("生成成功");  
  218.          jsonResult.setRes(1);  
  219.        
  220.         return jsonResult;   
  221.     }  
  222.       
  223.     /** 
  224.      * 二维码下载 
  225.      * @param qrcode_path 
  226.      * @param request 
  227.      * @param response 
  228.      * @throws IOException 
  229.      */  
  230.     @RequestMapping("/download")    
  231.     public void downloadFile(@RequestParam(value="qrcode_path",required=true) String qrcode_path,  
  232.             HttpServletRequest request, HttpServletResponse response) throws IOException {      
  233.           
  234.         String destUrl = qrcode_path;  
  235.         // 建立链接      
  236.         URL url = new URL(destUrl);      
  237.         HttpURLConnection httpUrl = (HttpURLConnection) url.openConnection();      
  238.         // 连接指定的资源      
  239.         httpUrl.connect();      
  240.         // 获取网络输入流      
  241.         BufferedInputStream bis = new BufferedInputStream(httpUrl.getInputStream());      
  242.         
  243.         response.setContentType("application/x-msdownload");      
  244.         response.setHeader("Content-Disposition""attachment; filename="+java.net.URLEncoder.encode(new Date().getTime()+"url.png","UTF-8"));      
  245.         OutputStream out = response.getOutputStream();      
  246.         byte[] buf = new byte[1024];      
  247.         if (destUrl != null) {      
  248.             BufferedInputStream br = bis;      
  249.             int len = 0;      
  250.             while ((len = br.read(buf)) > 0){      
  251.                 out.write(buf, 0, len);      
  252.             }                     
  253.             br.close();      
  254.         }      
  255.         out.flush();      
  256.         out.close();      
  257.     }   
  258.       
  259.       
  260.     /** 
  261.      * 二维码解析 
  262.      * @param request 
  263.      * @param model 
  264.      * @return 
  265.      * @throws IOException 
  266.      */  
  267.     @RequestMapping("parseQRCode")  
  268.     @ResponseBody  
  269.     public JsonResult  ParseQRCode(HttpServletRequest request,ModelMap model,  
  270.             @RequestParam(value="file",required=false) CommonsMultipartFile logoFile) throws IOException {  
  271.           
  272.          logger.info("ParseQRCode - {}""开始了");  
  273.            
  274.          StringBuffer url = request.getRequestURL();    
  275.          String tempContextUrl = url.delete(url.length() - request.getRequestURI().length(), url.length()).append(request.getContextPath()).append("/").toString();   
  276.           
  277.          String path = request.getSession().getServletContext().getRealPath("upload");  
  278.            
  279.          String logoFileName = logoFile.getOriginalFilename();  
  280.          File targetFile = new File(path, logoFileName);    
  281.          if(!targetFile.exists()){    
  282.              targetFile.mkdirs();    
  283.          }   
  284.          logoFile.transferTo(targetFile);  
  285.            
  286.          String text = ZXingCodeUtil.parseQRCode(targetFile);  
  287.            
  288.          targetFile.delete();  
  289.            
  290.          logger.info("解析结果 - {}", text);  
  291.            
  292.          JsonResult jsonResult = new JsonResult();  
  293.          Map data = new HashMap<String, String>();  
  294.          data.put("text", text);  
  295.          jsonResult.setData(data);  
  296.          jsonResult.setMeg("生成成功");  
  297.          jsonResult.setRes(1);  
  298.        
  299.         return jsonResult;   
  300.     }  
  301. }   

   最后搭建完成的项目如下:

  一、APP二维码合并,用苹果手机扫描自动打开App Store页面下载APP,用安卓手机扫码自动打开应用页面下载APP。

  

    二、网址生成二维码

   三、生成的二维码识别

 

 

 

  项目源码 : https://github.com/jiafuweiJava/spring-integration

  演示地址:http://demo.jiafuwei.win:9191/

原文