当前位置:首页 » 《资源分享》 » 正文

基于Spring Boot+区块链技术的农产品溯源平台设计与实现(前端VUE)

26 人参与  2024年09月24日 18:40  分类 : 《资源分享》  评论

点击全文阅读


目 录
1 绪论 1
1.1 系统研究背景 1
1.2 系统开发的目的与意义 1
1.3 国内外研究现状 2
2 系统开发平台及使用技术 2
2.1 系统开发平台 2
2.2 系统相关技术介绍 3
2.2.1 Spring Boot 3
2.2.2 Mybatis 3
2.2.3 FastDFS 3
2.2.4 Redis 4
2.2.5 区块链技术 4
2.2.6 Hyperledger Fabric 4
3 需求分析 5
3.1 系统应用需求 5
3.2 平台业务流程设计 5
3.3 可行性分析 7
3.3.1 技术可行性 7
3.3.2 经济可行性 7
3.3.3 操作可行性 8
4 系统设计 8
4.1 系统项目架构 8
4.2 系统功能模块设计 9
4.3 数据库设计 10
4.3.1 数据库E-R图 10
4.3.2 数据库表结构 11
4.4 Fabric区块链设计 15
4.4.1 区块链设计 15
4.4.2 智能合约设计 15
4.4.3 系统内部溯源流程设计 18
5 系统实现 19
5.1 Fabric区块链网络搭建 19
5.2 用户登录 22
5.3 系统管理模块实现 23
5.3.1 用户管理 23
5.3.2 角色管理 24
5.3.3 日志管理 25
5.4 农作物管理模块实现 27
5.4.1 农作物信息管理 27
5.4.2 农作物生长记录管理 28
5.5 农产品加工模块实现 29
5.6 质量检测模块实现 30
5.7 运输管理模块实现 31
5.8 农产品溯源模块实现 32
6 系统测试 33
6.1 系统管理模块测试 33
6.2 农作物管理模块测试 34
6.3 农产品加工模块测试 35
6.4 运输管理模块测试 36
6.5 农产品溯源模块测试 37
7 总结与展望 37
参考文献 39
致谢 40
4 系统设计
4.1 系统项目架构
本系统使用了基于Spring Boot的权限管理系统,若依管理系统进行辅助开发,实现了前后端分离的开发模式。系统前端采用了Vue框架技术进行开发,系统后端的区块链相关功能模块方面使用node.js进行开发,基础数据管理方面使用Spring Boot整合Mybatis,数据库使用开源的Mysql数据库,为了方便一些中小文件的存储,选择在服务器部署FastDFS文件服务来存储图片信息,图片路径及相关信息存储在Mysql数据库里。区块链技术使用Hyperledger Fabric,智能合约采用Golang语言编写。部署区块链的服务器运行环境为Centos7操作系统,需要先安装curl,docker,docker-compose,Golang,Python,node.js。结合农产品的生产过程及溯源的要求,系统总体架构图如图3所示。
本系统逻辑架构设计一共分为五层。持久层采用Fabric部署区块链服务器来存放溯源数据,并使用智能合约和Fabric的共识机制对溯源的数据进行验证、更新,把溯源关键数据上传至区块链网络中。Mysql数据库存放基础数据,包括用户数据、日志数据以及一些不需要上传至区块链的农作物管理数据。本平台使用FastDFS来存储图片等小文件,并将路径存储在Mysql数据库里。业务层主要负责整个溯源系统的农产品溯源数据采集、溯源信息查询、用户信息的增删改查等业务功能,为企业、消费者提供操作支持以及可靠的溯源信息。控制层负责接受前端发出的页面请求,调用业务层的方法处理数据,最后把返回的数据打包发送给前端页面。

<template>  <div class="login">    <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">      <h3 class="title">区块链防伪溯源平台</h3>      <el-form-item prop="username">        <el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号">          <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />        </el-input>      </el-form-item>      <el-form-item prop="password">        <el-input          v-model="loginForm.password"          type="password"          auto-complete="off"          placeholder="密码"          @keyup.enter.native="handleLogin"        >          <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />        </el-input>      </el-form-item>      <el-form-item prop="code">        <el-input          v-model="loginForm.code"          auto-complete="off"          placeholder="验证码"          style="width: 63%"          @keyup.enter.native="handleLogin"        >          <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />        </el-input>        <div class="login-code">          <img :src="codeUrl" @click="getCode" class="login-code-img"/>        </div>      </el-form-item>      <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>      <el-form-item style="width:100%;">        <el-button          :loading="loading"          size="medium"          type="primary"          style="width:100%;"          @click.native.prevent="handleLogin"        >          <span v-if="!loading">登 录</span>          <span v-else>登 录 中...</span>        </el-button>      </el-form-item>      <el-form-item style="width:100%;">        <el-button          size="medium"          type="success"          style="width:100%;"          @click.native.prevent="roTrace"        >          <span >消费者溯源</span>        </el-button>      </el-form-item>    </el-form>    <!--  底部  -->    <el-dialog      title="农产品溯源"      :visible.sync="drawer"      width="95%">      <el-divider content-position="left">农产品溯源</el-divider>      <div>        <Trace></Trace>      </div>    </el-dialog>  </div></template><script>import { getCodeImg } from "@/api/login";import Cookies from "js-cookie";import { encrypt, decrypt } from '@/utils/jsencrypt'import Trace from './Trace.vue'export default {  name: "Login",  data() {    return {      codeUrl: "",      cookiePassword: "",      loginForm: {        username: "admin",        password: "admin123",        rememberMe: false,        code: "",        uuid: ""      },      loginRules: {        username: [          { required: true, trigger: "blur", message: "用户名不能为空" }        ],        password: [          { required: true, trigger: "blur", message: "密码不能为空" }        ],        code: [{ required: true, trigger: "change", message: "验证码不能为空" }]      },      loading: false,      redirect: undefined,      drawer:false,    };  },  components:{    Trace  },  watch: {    $route: {      handler: function(route) {        this.redirect = route.query && route.query.redirect;      },      immediate: true    }  },  created() {    this.getCode();    this.getCookie();  },  methods: {    roTrace(){      this.drawer = true    },    getCode() {      getCodeImg().then(res => {        this.codeUrl = "data:image/gif;base64," + res.img;        this.loginForm.uuid = res.uuid;      });    },    getCookie() {      const username = Cookies.get("username");      const password = Cookies.get("password");      const rememberMe = Cookies.get('rememberMe')      this.loginForm = {        username: username === undefined ? this.loginForm.username : username,        password: password === undefined ? this.loginForm.password : decrypt(password),        rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)      };    },    handleLogin() {      this.$refs.loginForm.validate(valid => {        if (valid) {          this.loading = true;          if (this.loginForm.rememberMe) {            Cookies.set("username", this.loginForm.username, { expires: 30 });            Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 });            Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 });          } else {            Cookies.remove("username");            Cookies.remove("password");            Cookies.remove('rememberMe');          }          this.$store            .dispatch("Login", this.loginForm)            .then(() => {              this.$router.push({ path: this.redirect || "/" });            })            .catch(() => {              this.loading = false;              this.getCode();            });        }      });    }  }};</script><style rel="stylesheet/scss" lang="scss">.login {  display: flex;  justify-content: center;  align-items: center;  height: 100%;  background-image: url("../assets/image/login-background.jpg");  background-size: cover;}.title {  margin: 0px auto 30px auto;  text-align: center;  color: #707070;}.login-form {  border-radius: 6px;  background: #ffffff;  width: 400px;  padding: 25px 25px 5px 25px;  .el-input {    height: 38px;    input {      height: 38px;    }  }  .input-icon {    height: 39px;    width: 14px;    margin-left: 2px;  }}.login-tip {  font-size: 13px;  text-align: center;  color: #bfbfbf;}.login-code {  width: 33%;  height: 38px;  float: right;  img {    cursor: pointer;    vertical-align: middle;  }}.el-login-footer {  height: 40px;  line-height: 40px;  position: fixed;  bottom: 0;  width: 100%;  text-align: center;  color: #fff;  font-family: Arial;  font-size: 12px;  letter-spacing: 1px;}.login-code-img {  height: 38px;}</style>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


点击全文阅读


本文链接:http://zhangshiyu.com/post/164146.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1