技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、Nodejs、Python、区块链等设计与开发。
主要内容:免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文降重、长期答辩答疑辅导、腾讯会议一对一专业讲解辅导答辩、模拟答辩演练、和理解代码逻辑思路。
🍅文末获取源码联系🍅
🍅文末获取源码联系🍅
🍅文末获取源码联系🍅
👇🏻 精彩专栏推荐订阅👇🏻 不然下次找不到哟
《区块链开发专栏》
《区块链系统学习案例专栏》⛺️心若有所向往,何惧道阻且长
一、运行环境与开发工具
1.1 环境要求
- Java: JDK 1.8 及以上
- Node.js: v12 及以上
- 前端开发工具:VSCode
- 后端开发工具: IntelliJ IDEA 等
- 区块链平台: FISCO BCOS
- 中间件: WeBASE-Front
1.2 技术版本
- Spring Boot: 2.6.13
- Vue.js: 2.6.14
- Element UI: 2.15.14
- Solidity: 0.4.25
- Maven: 3.6+
- npm: 6.0+
二、系统功能详解
本系统围绕商品全流程溯源,主要包括以下功能模块:
2.1 核心功能模块
用户管理模块
- 用户注册: 支持多角色注册(生产商、供应商、零售商)
- 用户登录: 基于区块链地址的登录验证
- 角色管理: 智能合约实现角色权限控制
- 用户注销: 支持撤销用户角色
商品溯源模块
- 生产信息录入: 生产商添加商品基本信息(溯源码、商品名称、生产时间、生产地址等)
- 供应信息录入: 供应商添加供应链信息(入库时间、质检情况、物流信息等)
- 零售信息录入: 零售商添加零售信息(入库时间、发货信息等)
- 溯源查询: 消费者通过溯源码查询商品完整流转信息
区块链存证模块
- 链上数据存储: 所有溯源信息写入区块链,确保不可篡改
- 区块信息查询: 查看每个环节的区块号、交易信息
- 节点状态监控: 实时查看区块链网络节点状态
- 系统统计: 查看交易总数、区块总数等统计信息
二维码溯源
- 二维码生成: 为每个商品生成唯一溯源二维码
- 扫码查询: 消费者扫描二维码即可查看溯源详情
- 时间线展示: 图形化展示商品流转全过程
2.2 系统角色
| 角色 | 代码 | 权限 | 功能 |
|---|---|---|---|
| 生产商 | 1 | 添加商品基本信息 | 创建溯源码、录入生产信息 |
| 供应商 | 2 | 添加供应链信息 | 录入仓储、质检、物流信息 |
| 零售商 | 3 | 添加零售信息 | 录入销售、配送信息 |
| 消费者 | 4 | 查询溯源信息 | 扫码或输入溯源码查询 |
三、技术栈
3.1 后端技术栈
Spring Boot 2.6.13 # 后端框架
Maven # 项目构建工具
Lombok # 简化Java代码
HttpClient 4.5.3 # HTTP客户端(与区块链通信)
Swagger2 3.0.0 # API文档生成
HuTool 5.8.11 # Java工具类库
3.2 前端技术栈
Vue.js 2.6.14 # 前端框架
Vue Router 3.5.1 # 路由管理
Vuex 3.6.2 # 状态管理
Element UI 2.15.14 # UI组件库
Axios 1.7.7 # HTTP请求库
QRCode 1.5.4 # 二维码生成
vue-json-pretty 1.9.5 # JSON展示组件
3.3 智能合约技术栈
Solidity 0.4.25 # 智能合约开发语言
FISCO BCOS # 区块链底层平台
WeBASE-Front # 区块链中间件
3.4 系统架构
前端(Vue) <--HTTP--> 后端(Spring Boot) <--HTTP--> WeBASE-Front <--RPC--> FISCO BCOS
四、功能页面展示



五、核心代码展示
5.1 智能合约代码
solidity
// SPDX-License-Identifier: MIT
pragma experimental ABIEncoderV2;
pragma solidity ^0.4.25;
import "./User.sol";
import "./ProductInfo.sol";
contract ProductTrace is User {
// 溯源码 -> ProductInfo
mapping(string => ProductInfo) productInfos;
string[] public traceCodes;
constructor(
address _producer,
address _supplier,
address _retailer
) public {
// 初始化用户角色
setUser(1, _producer);
setUser(2, _supplier);
setUser(3, _retailer);
}
// 生产商添加商品基本信息
function addProductBaseInfo(
string _traceCode,
string _productName,
string _producer,
uint256 _productionTime,
string _productionAddress
) public onlyProducer onlyValidTraceCode(_traceCode) {
// 创建新的ProductInfo实例
ProductInfo productInfo = new ProductInfo();
// 设置商品基本信息
productInfo.setProductBase(
msg.sender,
_productName,
_producer,
_productionTime,
_productionAddress
);
// 存储产品信息和溯源码
productInfos[_traceCode] = productInfo;
traceCodes.push(_traceCode);
}
// 供应商添加基本信息
function addSupplierInfo(
string _traceCode,
uint256 _storageTime,
string _qualityCheck,
string _shippingUnit,
string _receivingUnit,
string _receivingAddress
) public onlySupplier onlyExistingTraceCode(_traceCode) {
productInfos[_traceCode].setSupplierInfo(
msg.sender,
_storageTime,
_qualityCheck,
_shippingUnit,
_receivingUnit,
_receivingAddress
);
}
// 零售商添加基本信息
function addRetailerInfo(
string _traceCode,
uint256 _storageTime,
string _qualityCheck,
string _shippingUnit,
string _receivingUnit,
string _receivingAddress
) public onlyRetailer onlyExistingTraceCode(_traceCode) {
productInfos[_traceCode].setRetailerInfo(
msg.sender,
_storageTime,
_qualityCheck,
_shippingUnit,
_receivingUnit,
_receivingAddress
);
}
// 获取所有溯源码
function getAllTraceCodes() public view returns (string[]) {
return traceCodes;
}
}
5.2 后端控制器代码
java
@RestController
@Api(tags = "商品溯源接口")
public class ProductTraceController {
@Autowired
private HttpUtil httpUtil;
/**
* 生产商添加商品基本信息
*/
@PostMapping("/product/baseinfo")
@ApiOperation(value = "生产商添加商品基本信息")
public Result addProductBaseInfo(@RequestBody ProductBaseInfoRequest request) {
String address = AddressContext.getAddress();
httpUtil.sendTransaction(
address,
"addProductBaseInfo",
Arrays.asList(
request.getTraceCode(),
request.getProductName(),
request.getProducer(),
String.valueOf(request.getProductionTime()),
request.getProductionAddress()
)
);
return Result.success();
}
/**
* 获取完整的溯源信息
*/
@GetMapping("/trace/detail/{traceCode}")
@ApiOperation(value = "获取完整的溯源信息")
public Result getDetailTraceInfo(@PathVariable String traceCode) {
JSONObject result = new JSONObject();
result.set("traceCode", traceCode);
// 获取商品基本信息
JSONObject productBaseInfo = getProductBaseInfo(traceCode);
if(productBaseInfo == null){
throw new WeBaseFrontException("未找到该溯源信息");
}
result.set("productBaseInfo", productBaseInfo);
// 获取供应商信息
JSONObject supplierInfo = getSupplierInfo(traceCode);
result.set("supplierInfo", supplierInfo == null ? new JSONObject() : supplierInfo);
// 获取零售商信息
JSONObject retailerInfo = getRetailerInfo(traceCode);
result.set("retailerInfo", retailerInfo == null ? new JSONObject() : retailerInfo);
return Result.success(result);
}
/**
* 获取商品基本信息
*/
private JSONObject getProductBaseInfo(String traceCode) {
JSONArray result = httpUtil.call("getProductBaseInfo", Arrays.asList(traceCode));
if (result.size() == 1) {
return null;
}
JSONObject jsonObj = new JSONObject();
jsonObj.set("producerAddr", result.getStr(0));
jsonObj.set("productName", result.getStr(1));
jsonObj.set("producer", result.getStr(2));
jsonObj.set("productionTime", result.getLong(3));
jsonObj.set("productionAddress", result.getStr(4));
jsonObj.set("blockNumber", result.getLong(5));
jsonObj.set("traceCode", traceCode);
return jsonObj;
}
}
5.3 前端页面代码
vue
<template>
<div class="login-box">
<div class="login-container">
<div class="login-card">
<div class="login-header">
<img src="/logo.png" alt="logo" class="logo">
<h1 class="title">商品溯源平台</h1>
<p class="subtitle">登录账号</p>
</div>
<el-form :model="loginForm" :rules="rules" ref="loginForm" class="login-form">
<el-form-item prop="role" class="form-item">
<el-select v-model="loginForm.role" placeholder="选择用戶角色" class="role-select">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item prop="address" v-if="loginForm.role !== '4'" class="form-item">
<el-input v-model="loginForm.address" placeholder="输入用户地址" class="custom-input">
</el-input>
</el-form-item>
<div class="button-group">
<el-button role="primary" @click="submitForm('loginForm')" class="submit-btn">
登录
</el-button>
<el-button @click="goRegister" class="register-btn">
注册账号
</el-button>
</div>
</el-form>
</div>
</div>
</div>
</template>
<script>
import { localStorageService } from '@/utils/commonUtil';
export default {
name: 'login-view',
data() {
return {
loginForm: {
address: '',
role: ''
},
options: [
{ value: '1', label: '生产商' },
{ value: '2', label: '供应商' },
{ value: '3', label: '零售商' },
{ value: '4', label: '消费者' }
]
};
},
methods: {
async submitForm(formName) {
let { role } = this.loginForm;
// 消费者角色特殊处理
if (role === '4') {
const { data } = await this.$http.get('/getContractOwner');
this.loginForm.address = data.owner;
localStorageService.setItem('userInfo', this.loginForm);
this.$message.success('登录成功');
this.$router.push('/trace');
return;
}
// 其他角色正常登录
this.$refs[formName].validate(async (valid) => {
if (valid) {
const { code, mes } = await this.$http.post('/user/login', this.loginForm);
if (code == 200) {
this.$message.success('登录成功');
localStorageService.setItem('userInfo', this.loginForm);
this.$router.push('/trace');
} else {
this.$message.error(mes);
}
}
});
}
}
};
</script>