ToB企服应用市场:ToB评测及商务社交产业平台
标题:
基于Spring Boot+区块链技能的农产品溯源平台计划与实现(前端VUE)
[打印本页]
作者:
宝塔山
时间:
2024-10-6 00:48
标题:
基于Spring Boot+区块链技能的农产品溯源平台计划与实现(前端VUE)
目 录
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>
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4