【基于若依实现的证书生成系统】SpringBoot+vue

技术栈:

SpingBoot+Vue+ElementUI+canvas工具

绘图工具:

HTML5 <canvas> 元素用于图形的绘制,通过脚本 (通常是JavaScript)来完成.

<canvas> 标签只是图形容器,您必须使用脚本来绘制图形。

你可以通过多种方法使用 canvas 绘制路径,盒、圆、字符以及添加图像。

canvas

这个技术目前应该算是主流的

效果生成

可以实现自动生成图片根据对应的关键字

生成的证书如图

证书预览

使用ruoyi做后台系统,进行管理,实现权限,用户,和参数持久化,方便用户持久使用,基于若依实现的证书生成系统

参数设置

批量生成压缩

增加了遮罩层,

绘画渲染核心函数

这个图其实动态的,我们将需要动态变化的数据进行,动态传进去

方法实例如下:

artistName, 艺术家的名字

artworkName,艺术作品名

category,作品分类

remark,备注

size,大小

,pieces_time,时间

col,其他字段

5个参数,数据会动态渲染到程序界面上,数据很多许多画布需要一点点调整和计算,这里放在这儿给大家参考实现的证书生成系统

async  asyncreimg2(artistName, artworkName, category, remark, size ,pieces_time,col) {
      this.downloadUrl = "";
      const canvas = this.$refs["canvas"];
      const ctx = canvas.getContext('2d');

      // 清除主Canvas内容
      ctx.clearRect(0, 0, canvas.width, canvas.height);

      // 加载背景图片
      const backgroundImage = new Image();
      backgroundImage.src = require('@/assets/images/back2.jpg');

      await new Promise((resolve, reject) => {
        backgroundImage.onload = () => {
          resolve();
        };
        backgroundImage.onerror = (error) => {
          reject(error);
        };
      });

      const logo = new Image();
      logo.src = require('@/assets/images/11.png');

      await new Promise((resolve, reject) => {
        logo.onload = () => {
          resolve();
        };
        logo.onerror = (error) => {
          reject(error);
        };
      });

      const tile = new Image();
      tile.src = require("@/assets/images/title.png");

      await new Promise((resolve, reject) => {
        tile.onload = () => {
          resolve();
        };
        tile.onerror = (error) => {
          reject(error);
        };
      });

      /**########################### begin ########################*/
      // 绘制背景图片
      ctx.drawImage(backgroundImage, 0, 0, canvas.width, canvas.height);
      // 标题
      const certificateText = "艺术品溯源鉴真数字证书"
      // 设置字体样式,加粗
      ctx.font = "bold 160px 黑体"; // 修改这里的字体样式
      let letterSpacing = 10; // 修改这里的文字间距
      // 计算文本宽度
      let textWidth = ctx.measureText(certificateText).width;
      // 计算文本的 x 坐标,使其在 Canvas 中央水平方向居中
      let x = (canvas.width - textWidth - 110) / 2;
      const y = canvas.height / 7;
      for (const char of certificateText) {
        // 将文本渲染到Canvas上
        ctx.fillText(char, x, y);
        const charWidth = ctx.measureText(char).width; // 获取当前字符的宽度
        x = x + charWidth + letterSpacing; // 增加 x 坐标,加上字符宽度和间距
      }

      ctx.font = 'bold 90px "宋体"';
      let name = " " + artistName + " ";
      let title = "艺术家区块链艺术品溯源鉴真平台登记艺术家信"
      let title2 = "息及艺术品上链,特此颁发《艺术品溯源鉴真数字证书》。"
      //畅首才 艺术家区块链艺术品额源警真平台登记艺术家信
      let textWidth1 = ctx.measureText(title).width;
      let textWidth2 = ctx.measureText(name).width;
      let nx = (canvas.width - textWidth1 - textWidth2) / 2 + 100;
      let ny = canvas.height / 5 - 100;
      ctx.fillText(name, nx, ny);

      ctx.font = 'bold 80px "宋体"';
      nx = (canvas.width - textWidth1) / 2 + 300;
      ctx.fillText(title, nx, ny);

      //聪及艺术品上酷,特此颁发《全国需源要真数字证书》
      let textWidth3 = ctx.measureText(title2).width;
      nx = (canvas.width - textWidth3) / 2
      ny = ny + 150;
      ctx.fillText(title2, nx, ny);

      let nx_init = nx + 100
      //字体样式
      ctx.font = '80px "微软雅黑"';
      ctx.letterSpacing = 0; // 修改这里的文字间距
      //主题信息
      // 定义要显示的多行文本
      const text = "证   书   信   息"
      ny = ny + 200;
      let nx_t = (canvas.width - 1500) / 2;
      let nx_t1 = (canvas.width - ctx.measureText(text).width) / 2
      ctx.drawImage(tile, nx_t, ny - 100, 1500, 130)


      ctx.fillStyle = "white"; // 设置为白色
      ctx.fillText(text, nx_t1, ny-5.5);
      ctx.fillStyle = "black"; // 设置为黑色

      const text2 = "区块链地址:"
      ctx.font = '60px "楷体"';
      ny = ny + 150;
      ctx.fillText(text2, nx_init, ny);


      const randomNumber = Math.floor(Math.random() * 10000000); // 生成一个 0 到 99999999 的随机数
      let text21 = "#0" + randomNumber
      ctx.font = '80px "新宋体"';
      nx = nx_init + 360
      ctx.fillText(text21, nx, ny);

      const text3 = "数字签名:"
      ctx.font = '60px "楷体"';
      ny = ny + 110;
      ctx.fillText(text3, nx_init + 60, ny);

      let text31 = this.generateRandomString(40)
      ctx.font = '80px "新宋体"';
      nx = nx_init + 360
      ctx.fillText(text31, nx, ny);

      const text4 = this.generateRandomString(24)
      ny = ny + 100;
      ctx.fillText(text4, nx, ny);

      const text5 = "上链时间:"
      ctx.font = '60px "楷体"';
      ny = ny + 110;
      ctx.fillText(text5, nx_init + 60, ny);

      ctx.font = '80px "新宋体"';


      // 格式化为 "yyyy-M-d HH:mm:ss" 的字符串
      // 获取当前时间的 Date 对象
      const currentDate = new Date();

      // 提取年、月、日、小时、分钟和秒
      const year = currentDate.getFullYear();
      const month = currentDate.getMonth() + 1; // 月份从0开始,需要+1
      const day = currentDate.getDate();
      const hours = currentDate.getHours();
      const minutes = currentDate.getMinutes();
      const seconds = currentDate.getSeconds();

      // 格式化日期
      const formattedDate = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;

      let text51 = pieces_time
      nx = nx_init + 360
      ctx.fillText(text51, nx, ny);

      const text6 = "作   品   信   息"
      ctx.font = '80px "微软雅黑"';
      ny = ny + 200;
      ctx.drawImage(tile, nx_t, ny - 100, 1500, 130)
      ctx.fillStyle = "white"; // 设置为白色
      ctx.fillText(text6, nx_t1, ny-5);
      ctx.fillStyle = "black"; // 设置为黑色


      const text7 = "作品名称:"
      ny = ny + 150;
      ctx.font = '60px "楷体"';
      ctx.fillText(text7, nx_init + 60, ny);

      let text71 = artworkName
      ctx.font = '80px "新宋体"';
      nx = nx_init + 360
      ctx.fillText(text71, nx, ny);


      const text9 = "作品分类:"
      ctx.font = '60px "楷体"';
      ny = ny + 110;
      ctx.fillText(text9, nx_init + 60, ny);


      let text91 = category
      nx = nx_init + 360
      ctx.font = '80px "新宋体"';
      ctx.fillText(text91, nx, ny);

      let text10 = "作品尺寸:"
      ctx.font = '60px "楷体"';
      ny = ny + 110;
      ctx.fillText(text10, nx_init + 60, ny);

      const text101 = size
      ctx.font = '80px "新宋体"';
      nx = nx_init + 360
      ctx.fillText(text101, nx, ny);

      let text11 = "艺  术   家   信   息"
      ctx.font = '80px "微软雅黑"';
      ny = ny + 200;
      let nx_t2 = (canvas.width - ctx.measureText(text11).width) / 2
      ctx.drawImage(tile, nx_t, ny - 100, 1500, 130)
      ctx.fillStyle = "white"; // 设置为白色
      ctx.fillText(text11, nx_t2, ny-5);
      ctx.fillStyle = "black"; // 设置为黑色

      text11 = "艺术家姓名:"
      ny = ny + 150;
      ctx.font = '60px "楷体"';
      ctx.fillText(text11, nx_init, ny);

      text11 = artistName
      ctx.font = '80px "新宋体"';
      ctx.fillText(text11, nx_init + 360, ny);

      text11 = "艺术家公销:"
      ny = ny + 110;
      ctx.font = '60px "楷体"';
      ctx.fillText(text11, nx_init, ny);

      text11 = this.generateRandomString(40)
      ctx.font = '80px "新宋体"';
      ctx.fillText(text11, nx_init + 360, ny);

      text11 = this.generateRandomString(27)
      ny = ny + 100;
      ctx.fillText(text11, nx_init + 360, ny);

      text11 = "艺术家签名:"
      ctx.font = '60px "楷体"';
      ny = ny + 110;
      ctx.fillText(text11, nx_init, ny);

      text11 = this.generateRandomString(40)
      ctx.font = '80px "新宋体"';
      ctx.fillText(text11, nx_init + 360, ny);

      text11 = this.generateRandomString(10)
      ny = ny + 100;
      ctx.fillText(text11, nx_init + 360, ny);


      ctx.font = '100px "黑体"';
      let len = ctx.measureText("全国艺术家艺术品溯源鉴真平台").width+130;
      nx = (canvas.width - len) / 2

      // logo
      ctx.drawImage(logo, nx-30, ny + 100, 130, 130)



      ctx.fillText("全国艺术家艺术品溯源鉴真平台", nx+150, ny + 200)



      text11 = "上   链   方   信   息"
      ctx.font = '80px "微软雅黑"';
      ny = ny + 400;
      nx_t2 = (canvas.width - ctx.measureText(text11).width) / 2
      ctx.drawImage(tile, nx_t, ny - 100, 1500, 130)
      ctx.fillStyle = "white"; // 设置为白色
      ctx.fillText(text11, nx_t2, ny-5);
      ctx.fillStyle = "black"; // 设置为黑色

      text11 = "上链方名称:"
      ny = ny + 150;
      ctx.font = '60px "楷体"';
      ctx.fillText(text11, nx_init, ny);

      text11 = "北京松竹轩书画院"
      ctx.font = '80px "新宋体"';
      ctx.fillText(text11, nx_init + 360, ny);

      text11 = "上链方公钥:"
      ny = ny + 110;
      ctx.font = '60px "楷体"';
      ctx.fillText(text11, nx_init, ny);

      text11 = this.generateRandomString(40)
      ctx.font = '80px "新宋体"';
      ctx.fillText(text11, nx_init + 360, ny);

      text11 = this.generateRandomString(26)
      ny = ny + 100;
      ctx.fillText(text11, nx_init + 360, ny);

      text11 = "上链方签名:"
      ctx.font = '60px "楷体"';
      ny = ny + 110;
      ctx.fillText(text11, nx_init, ny);

      text11 = this.generateRandomString(40)
      ctx.font = '80px "新宋体"';
      ctx.fillText(text11, nx_init + 360, ny);

      text11 = this.generateRandomString(10)
      ny = ny + 100;
      ctx.fillText(text11, nx_init + 360, ny);


      //注意消息
      ctx.font = '50px "宋体"';
      text11 = "1、本 平 台 保 证 上 述 溯 源 信 息 的 溯 源 过 程 真 实 有 效。"
      ny = ny + 100;
      nx = nx_init + 130;
      ctx.fillText(text11, nx, ny);

      text11 = "2、证书持有人或相关签方私钥丢失或被盗引起信息不实由遗失方负责。"
      ny = ny + 80;
      ctx.fillText(text11, nx, ny);

      text11 = "3、 本  平  台  保  留  本  证  书  的  最  终  解  释  权 。"
      ny = ny + 80;
      ctx.fillText(text11, nx, ny);

      /**###################################end ******************************************/

压缩函数

基于若依实现的证书生成压缩文件的函数:

downloadimg(row){
      this.loading=true
      // 创建一个新的JSZip实例
      const JSZip = require("jszip");
      const zip = new JSZip();

      const id = row.id || this.ids
      getPieces(id).then( async response => {
        this.form = response.data;
        let res = response.data;
        await this.asyncreimg2(res.artistName, res.artworkName, res.category, "", res.size,res.piecesTime,res.col)
         let i = 0
        console.log(res.numbers)
        while (i<res.numbers) {
          try {
            const response = await getPieces(id);
            this.form = response.data;
            let res = response.data;

            // 使用 await 等待图像数据加载完成
            let img = await this.asyncreimg2(res.artistName, res.artworkName, res.category, "", res.size,res.piecesTime,res.col);

            // 将 res.size 中的 * 替换为 _
            res.size = res.size.replace(/\*/g, "_");

            // 将图像数据添加到压缩文件
            zip.file(res.col+res.artworkName+i+ res.artistName + res.size+ ".png", img.split(",")[1], { base64: true });
            i++
            console.log(i)
          } catch (error) {
            console.error("获取图像数据失败", error);
          }
        }

        // 生成压缩文件
        zip.generateAsync({ type: "blob" }).then((content) => {
          // 创建下载链接
          const a = document.createElement("a");
          a.href = URL.createObjectURL(content);
          a.download = res.artworkName + res.artistName + res.size + "images.zip";
          a.click();
          a.remove()
          console.log("download success")
          this.$modal.msgSuccess("下载成功");
        });
        this.loading=false
      });
    },

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
学生管理系统是一个常见的项目,可以使用Spring Boot作为后端框架,Vue作为前端框架,MySQL作为数据库。下面是一个简单的实现步骤: 1. 创建数据库表结构: - 学生表:包含学生的ID、姓名、年龄、性别等信息。 - 可以使用MySQL Workbench或者命令行创建表结构。 2. 创建Spring Boot项目: - 使用Spring Initializr创建一个新的Spring Boot项目,添加必要的依赖。 - 配置数据库连接信息,包括URL、用户名和密码等。 3. 创建学生实体类: - 在Spring Boot项目中创建一个学生实体类,包含与数据库表对应的属性。 4. 创建学生Controller: - 创建一个RESTful API的Controller类,处理学生相关的HTTP请求。 - 使用Spring注解标记Controller类和接口方法。 5. 创建学生Service: - 创建一个Service类,处理业务逻辑,例如增删改查学生信息。 - 使用@Autowired注解将Service类注入到Controller中。 6. 创建Vue前端项目: - 使用Vue CLI创建一个新的Vue项目,配置路由和组件等。 - 可以使用Element UI等UI库来美化界面。 7. 编写前端页面: - 创建学生列表、添加学生、编辑学生等页面,使用axios发送HTTP请求与后端交互。 8. 测试运行: - 启动Spring Boot项目和Vue项目,测试学生管理系统的功能。 这只是一个简单的实现示例,实际项目中可能还需要加入权限控制、分页查询、数据校验等功能。希望对你有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学长代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值