SpringMVC生成二维码并成功实现LOGO图片与底部文字的插入(使用AJAX)

本篇将主要介绍如何生成一个既含LOGO又含底部文字的二维码.

先展示一下最终成果图,如下:

好,现在来说一说具体的实现思路.

第一步,实现LOGO图片的上传:

①LOGO文件选择框改变事件触发后,将文件传输到后台

②后台存储后,将文件于服务器端的实际存储地址返回个前端

③前端将文件地址进行存储

第二步,实现二维码的生成:

①生成二维码按钮点击事件触发后,将“二维码信息”、“LOGO地址”、“底部字符”一并传递到后台

②后台检验“LOGO地址”和“底部字符”是否存在,存在则插入二维码一并生成

第三步,前端进行二维码的展示

①前端AJAX的success回调函数中,获取到二维码的Base64字符串

②将此Base64字符串直接放入图片展示区域<img>标签的src属性中即可正确显示创造的二维码


现在来看具体的实现代码(实现代码中有大量的代码注释供理解所用):

1. 首先引入文件上传、二维码生成以及JSONObject对象所依赖的包

    <!-- 文件上传 -->
    <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.3</version>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.5</version>
    </dependency>

    <!-- 二维码生成 -->
    <!-- https://mvnrepository.com/artifact/com.google.zxing/core -->
    <dependency>
      <groupId>com.google.zxing</groupId>
      <artifactId>core</artifactId>
      <version>3.3.0</version>
    </dependency>

    <!-- JSONObject对象依赖 -->
    <!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->
    <dependency>
      <groupId>net.sf.json-lib</groupId>
      <artifactId>json-lib</artifactId>
      <version>2.4</version>
    </dependency>

2.在applicationContext.xml中,配置文件解析器,如下图:

    <!-- 文件解析器 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 设置上传文件的最大尺寸为1MB -->
        <property name="maxUploadSize" value="1048576" />
        <!-- 字符编码 -->
        <property name="defaultEncoding" value="UTF-8" />
    </bean>

3.创建文件上传的控制器FileController,并写好LOGO图片上传的方法.

/**
 * TODO
 *
 * @author ShangHai
 * @date 2019/12/02 16:40
 */
@Controller
@RequestMapping(value= "/file")
public class FileController {

     /**
     * 此方法用于将用户上传的图片保存在指定位置
     * @param file 用户上传的LOGO图片
     * @return
     */
    @ResponseBody
    @RequestMapping(value= "/loGoUpload",produces = {"text/html;charset=UTF-8"})
    public String loGoUpload(@RequestParam(value = "file",required = false)MultipartFile file){
        JSONObject jsonObject = new JSONObject();
        try{
            //再次判断文件是否为空
            if(file.isEmpty()){
                jsonObject.put("status","fail");
                jsonObject.put("msg","上传的文件为空,请重新选择");
                return jsonObject.toString();
            }
            //声明图片存放路径
            String path = "G:"+File.separator+"study"+File.separator+"upload";

            //获取上传文件名
            String fileName = file.getOriginalFilename();
            //获取文件的类型
            String fileType = fileName.substring(fileName.lastIndexOf("."));
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmm");
            //对上传的图片进行重命名:命名规则为 "随机的UUID + 年月日时分"
            String newFileName = UUID.randomUUID()+"-"+sdf.format(new Date())+fileType;
            //实例化此路径
            File targetFile = new File(path+File.separator+newFileName);
            if(!targetFile.exists()){
                //文件若不存在,则进行创建
                //若文件所属的父目录均不存在时,mkdirs方法会连父目录一起创建
                targetFile.mkdirs();
            }
            //拷贝
            file.transferTo(targetFile);
            jsonObject.put("status","ok");
            jsonObject.put("msg","文件上传成功");
            //注意此处!!将图片在服务器上的实际存储地址传给前端   
            jsonObject.put("logoPath",""+path+File.separator+newFileName);
        }catch(Exception e){
            jsonObject.put("status","error");
            jsonObject.put("msg","发生了未知的错误,请联系管理员");
        }
        return jsonObject.toString();
    }

}

ps:需要将图片的实际地址传递给前端

            //注意此处!!将图片在服务器上的实际存储地址传给前端   
            jsonObject.put("logoPath",""+path+File.separator+newFileName);

4.创建一个二维码生成的工具类,QRCodeUtil.

/**
 * TODO
 *
 * @author ShangHai
 * @date 2019/12/04 22:08
 */
public class QRCodeUtil {

    /**
     * 生成二维码图片并返回
     * @param content 二维码存储的内容
     * @param width   指定二维码的宽度
     * @param height  指定二维码的高度
     * @return
     * @throws Exception
     */
    public static BufferedImage createQrCodeImage(String content,int width,int height) throws Exception{
        Hashtable hints = new Hashtable();
        //指定纠错等级
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        //生成二维码矩阵
        BitMatrix bitMatrix =
                new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
        //获取矩阵宽度、高度,生成二维码图片
        BufferedImage image = new BufferedImage(bitMatrix.getWidth(),bitMatrix.getHeight(),BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        return image;
    }

    /**
     * 往二维码中插入一个LOGO,也可以在底部插入一行字符
     * @param image 需要插入LOGO的二维码
     * @param logoPath  LOGO的路径
     * @param showBottomText  底部需要显示的字符
     * @return
     * @throws IOException
     */
    public static BufferedImage megerLoGo(BufferedImage image,String logoPath,String showBottomText) throws IOException{
        Graphics2D gs = image.createGraphics();

        //1.加入LOGO水印效果
        if(logoPath!=null && !"".equals(logoPath)){
            //1.1 载入LOGO图片
            BufferedImage logoImage = ImageIO.read(new File(logoPath));
            //1.2 考虑到LOGO图片将插入到二维码中间,建议大小不要超过二维码的1/5
            int width = image.getWidth()/4;
            int height = image.getHeight()/4;
            //1.3 LOGO居中显示
            int x = (image.getWidth() - width)/2;
            int y = (image.getHeight() - height)/2;
            gs.drawImage(logoImage,x,y,width,height,null);
            logoImage.flush();
        }

        //2.二维码图片底部插入文字
        if(showBottomText!=null && !"".equals(showBottomText)){
            //2.1 设置字体样式
            Font font = new Font("微软雅黑", Font.PLAIN, 14);
            gs.setColor(Color.BLACK);
            gs.setFont(font);
            //2.2 字体显示位置
            int x = (image.getWidth() - getWatermarkLength(showBottomText, gs))/2;
            int y = image.getHeight()-10;
            gs.drawString(showBottomText, x, y);
        }
        //销毁图形界面资源
        gs.dispose();
        return image;
    }

    /**
     * 将图片转换成base64的字符串并返回
     * @param image 需要进行转换的图片
     * @return
     * @throws Exception
     */
    public static String imageToBase64(BufferedImage image) throws Exception{
        String base64 = "data:image/jpg;base64,";
        //新建字符数组输出流
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        //利用ImageIO类提供的write方法,将图片以jpg的数据模式写入字符数组输出流
        ImageIO.write(image,"jpg",os);
        //从流中获取数据数组
        byte[] bytes = os.toByteArray();
        //将数据数组转换成base64字符串
        base64 += new BASE64Encoder().encode(bytes);
        return base64;
    }

    /**
     * 获取水印字体的长度
     * @param fontString
     * @param gs
     * @return
     */
    public static int getWatermarkLength(String fontString,Graphics2D gs){
        return gs.getFontMetrics(gs.getFont()).charsWidth(fontString.toCharArray(),0,fontString.length());
    }

}

5.创建条码生成控制器CodeController.

/**
 * TODO
 *
 * @author ShangHai
 * @date 2019/12/04 22:16
 */
@Controller
@RequestMapping(value= "/code")
public class CodeController {
    /**
     * 根据用户输入的内容生成二维码,并将二维码转换为base64字符串并返回
     * @param content 二维码存储的信息
     * @param logoPath LOGO的存储地址
     * @param bottomText 底部字符
     * @return
     */
    @ResponseBody
    @RequestMapping(value= "/getQrCodeBase64",produces = {"text/html;charset=utf-8"})
    public String getQrCodeBase64(String content,String logoPath,String bottomText){
        JSONObject jsonObject = new JSONObject();
        try {
            //获取二维码图片
            BufferedImage image = QRCodeUtil.createQrCodeImage(content,200,200);
            //往二维码图片插入LOGO及字符
            image = QRCodeUtil.megerLoGo(image,logoPath,bottomText);
            //二维码图片转base64字符串
            String base64 = QRCodeUtil.imageToBase64(image);
            jsonObject.put("status","ok");
            //将得到的base64字符串放入jsonObject对象中,方便转换成json数据
            jsonObject.put("base64",base64);
        } catch (Exception e) {
            jsonObject.put("status","fail");
            jsonObject.put("base64","");
            e.printStackTrace();
        }
        return jsonObject.toString();
    }

}

至此,后台的处理方法均已完善.

6.创建前端展示界面QRCode_Base64.jsp.

    <style type="text/css">
        *{margin: 0;padding: 0;list-style: none;}
        .container{width: 360px;height: 430px;margin: auto;margin-top: 100px;
            box-shadow: 0 0 20px black;overflow: hidden;}
        .container .title{width: 100%;height: 50px;outline: 1px solid black;
            text-align: center;font-weight: bold;font-size: 18px;line-height: 50px;}
        .container .code_content{width: 100%;height: 35px;outline: 1px solid silver;
            line-height: 35px;padding-left: 10px;}
        .container .logo_upload{width: 100%;height: 35px;outline: 1px solid silver;
            line-height: 35px;padding-left: 10px;}
        .container .bottom_text{width: 100%;height: 35px;outline: 1px solid silver;
            line-height: 35px;padding-left: 10px;}
        .container .operation{width: 100%;height: 35px;outline: 1px solid silver;
            line-height: 35px;padding-left: 10px;}
        .container .img_show{width: 100%;height: 200px;text-align: center;}
        .container .img_show div{font-size: 14px;font-weight: bold;margin-top: 10px;}
    </style>

<body>

<div class="container">
    <div class="title">二维码生成器</div>
    <div class="code_content">
        二维码信息输入:
        <input type="text" id="codeContent" name="codeContent">
    </div>
    <div class="logo_upload">
        嵌入LOGO:
        <input type="file" id="logoImg" name="logoImg">
        <input type="hidden" id="logoPath" name="logoPath">
    </div>
    <div class="bottom_text">
        底部字符输入:
        <input type="text" id="bottomText" name="bottomText">
    </div>
    <div class="operation">
        操作:
        <button id="submitBtn" name="submitBtn">生成二维码</button>
    </div>
    <div class="img_show">
        <div>二维码的显示区域</div>
        <center>
            <img id="imgShow" name="imgShow" style="display: none;">
        </center>
    </div>
</div>

</body>

7.LOGO文件框改变事件绑定的JQuery逻辑代码:

            //LOGO图片文件上传
            $("#logoImg").change(function () {
                //初始化:LOGO图片上传后保存的位置
                $("#logoPath").val("");
                //获取图片的路径
                var filePath = $("#logoImg").val();
                if(filePath == ""){
                    alert("请选择一张图片");
                    $("#logoImg").val("");
                    return ;
                }
                //截取图片文件类型
                var fileType = filePath.substring(filePath.lastIndexOf("."));
                if(fileType!=".jpg" && fileType!=".png" && fileType!=".bmp" && fileType!=".gif"){
                    alert("请选择一张图片");
                    $("#logoImg").val("");
                    return ;
                }
                //生成FormData,用于装上传的图片文件
                var formData = new FormData();
                formData.append("file",$('#logoImg')[0].files[0]);

                // 通过ajax技术上传图片文件,
                // 成功上传后,获取图片保存的路径,并存于页面的隐藏域中
                $.ajax({
                    url: '/file/loGoUpload',    //图片上传的控制层映射
                    dataType: 'json',   //返回值类型为json
                    data: formData,
                    type: 'POST',
                    processData: false, //使数据不做处理
                    contentType: false, //不要设置Content-Type请求头
                    success: function (data) {  //data为返回的json数据
                        if(data.status == 'ok'){
                            alert('图片上传成功!');
                            //关键点:将图片上传成功后保存的实际地址记录下来
                            $("#logoPath").val(data.logoPath);
                        } else {
                            alert('图片上传失败!');
                        }
                    },error: function () {
                        alert('ajax请求失败');
                    }
                });
            });

生成二维码按钮点击事件绑定的JQuery逻辑代码:

            //获取二维码图片
            $("#submitBtn").click(function () {
                //初始化:将图片展示区域隐藏、src清空
                $("#imgShow").css("display","none");
                $("#imgShow").attr("src","");
                //获取输入的二维码内容
                var content = $("#codeContent").val();
                //LOGO图片的存放路径
                var logoPath = $("#logoPath").val();
                //底部字符
                var bottomText = $("#bottomText").val();

                if(content == ""){
                    alert("请输入二维码需要存储的内容");
                    $("#codeContent").focus();
                    return ;
                }

                //通过ajax技术访问后台,获取返回的base64字符串.
                //成功获取后,将base64字符串直接放入img标签的src属性中即可
                $.ajax({
                    url: "/code/getQrCodeBase64",    //二维码生成的映射路径
                    data: {                        
                        content: content,    //二维码内容
                        logoPath: logoPath,    //LOGO图片存储地址
                        bottomText: bottomText    //底部字符
                    },
                    type: 'POST',
                    dataType: 'json',    //返回数据类型为json类型
                    success: function (data) {    //请求成功回调函数
                        if(data.status == "ok"){
                            alert("获取成功");
                            //图片展示区域显示并将base64字符串放入src中即可
                            $("#imgShow").css("display","block");
                            $("#imgShow").attr("src",data.base64);
                        } else {
                            alert("获取失败");
                            $("#codeContent").val("");
                            $("#codeContent").focus();
                        }
                    },error: function () {    //请求失败回调函数
                        alert("ajax请求失败");
                    }
                });
            });

至此,整个二维码生成器便实现了.

以下是QRCode_Base64.jsp页面所有的代码:

<%--
  Created by IntelliJ IDEA.
  User: ShangHai
  Date: 2019/12/04
  Time: 22:24
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>QRCode_Base64</title>
    <style type="text/css">
        *{margin: 0;padding: 0;list-style: none;}
        .container{width: 360px;height: 430px;margin: auto;margin-top: 100px;
            box-shadow: 0 0 20px black;overflow: hidden;}
        .container .title{width: 100%;height: 50px;outline: 1px solid black;
            text-align: center;font-weight: bold;font-size: 18px;line-height: 50px;}
        .container .code_content{width: 100%;height: 35px;outline: 1px solid silver;
            line-height: 35px;padding-left: 10px;}
        .container .logo_upload{width: 100%;height: 35px;outline: 1px solid silver;
            line-height: 35px;padding-left: 10px;}
        .container .bottom_text{width: 100%;height: 35px;outline: 1px solid silver;
            line-height: 35px;padding-left: 10px;}
        .container .operation{width: 100%;height: 35px;outline: 1px solid silver;
            line-height: 35px;padding-left: 10px;}
        .container .img_show{width: 100%;height: 200px;text-align: center;}
        .container .img_show div{font-size: 14px;font-weight: bold;margin-top: 10px;}
    </style>
    <script src="${pageContext.request.contextPath}/lib/jquery-2.1.1.min.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            //让二维码信息输入框获取焦点
            $("#codeContent").focus();

            //LOGO图片文件上传
            $("#logoImg").change(function () {
                //初始化:LOGO图片上传后保存的位置
                $("#logoPath").val("");
                //获取图片的路径
                var filePath = $("#logoImg").val();
                if(filePath == ""){
                    alert("请选择一张图片");
                    $("#logoImg").val("");
                    return ;
                }
                //截取图片文件类型
                var fileType = filePath.substring(filePath.lastIndexOf("."));
                if(fileType!=".jpg" && fileType!=".png" && fileType!=".bmp" && fileType!=".gif"){
                    alert("请选择一张图片");
                    $("#logoImg").val("");
                    return ;
                }
                //生成FormData,用于装上传的图片文件
                var formData = new FormData();
                formData.append("file",$('#logoImg')[0].files[0]);

                // 通过ajax技术上传图片文件,
                // 成功上传后,获取图片保存的路径,并存于页面的隐藏域中
                $.ajax({
                    url: '/file/loGoUpload',    //图片上传的控制层映射
                    dataType: 'json',   //返回值类型为json
                    data: formData,
                    type: 'POST',
                    processData: false, //使数据不做处理
                    contentType: false, //不要设置Content-Type请求头
                    success: function (data) {  //data为返回的json数据
                        if(data.status == 'ok'){
                            alert('图片上传成功!');
                            //关键点:将图片上传成功后保存的实际地址记录下来
                            $("#logoPath").val(data.logoPath);
                        } else {
                            alert('图片上传失败!');
                        }
                    },error: function () {
                        alert('ajax请求失败');
                    }
                });
            });

            //获取二维码图片
            $("#submitBtn").click(function () {
                //初始化:将图片展示区域隐藏、src清空
                $("#imgShow").css("display","none");
                $("#imgShow").attr("src","");
                //获取输入的二维码内容
                var content = $("#codeContent").val();
                //LOGO图片的存放路径
                var logoPath = $("#logoPath").val();
                //底部字符
                var bottomText = $("#bottomText").val();

                if(content == ""){
                    alert("请输入二维码需要存储的内容");
                    $("#codeContent").focus();
                    return ;
                }

                //通过ajax技术访问后台,获取返回的base64字符串.
                //成功获取后,将base64字符串直接放入img标签的src属性中即可
                $.ajax({
                    url: "/code/getQrCodeBase64",
                    data: {
                        content: content,
                        logoPath: logoPath,
                        bottomText: bottomText
                    },
                    type: 'POST',
                    dataType: 'json',
                    success: function (data) {
                        if(data.status == "ok"){
                            alert("获取成功");
                            //图片展示区域显示并将base64字符串放入src中即可
                            $("#imgShow").css("display","block");
                            $("#imgShow").attr("src",data.base64);
                        } else {
                            alert("获取失败");
                            $("#codeContent").val("");
                            $("#codeContent").focus();
                        }
                    },error: function () {
                        alert("ajax请求失败");
                    }
                });
            });
        });
    </script>
</head>
<body>

<div class="container">
    <div class="title">二维码生成器</div>
    <div class="code_content">
        二维码信息输入:
        <input type="text" id="codeContent" name="codeContent">
    </div>
    <div class="logo_upload">
        嵌入LOGO:
        <input type="file" id="logoImg" name="logoImg">
        <input type="hidden" id="logoPath" name="logoPath">
    </div>
    <div class="bottom_text">
        底部字符输入:
        <input type="text" id="bottomText" name="bottomText">
    </div>
    <div class="operation">
        操作:
        <button id="submitBtn" name="submitBtn">生成二维码</button>
    </div>
    <div class="img_show">
        <div>二维码的显示区域</div>
        <center>
            <img id="imgShow" name="imgShow" style="display: none;">
        </center>
    </div>
</div>

</body>
</html>

即可进行测试!

第一种情况:既不插入LOGO图片,也不插入底部字符.

第二种情况:仅插入LOGO图片,不插入底部字符.

选择一张LOGO图片:

然后点击"生成二维码"按钮

第三种情况:既插入LOGO图片,又插入底部字符.

选择一张LOGO图片,同上.然后输入一串底部字符

没有任何问题,完美实现!

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值