最近我用springBoot开发了一个二手交易管理系统,分享一下实现方式~
最近把java升级到了java21的版本,就使用springboot框架写了一个二手交易平台来熟悉一下springBoot框架的语法。功能方面主要做了管理后台和手机用户端的功能。
管理系统后台的样式:
手机端:
主要做的功能有:
(1)平台管理端
· 用户管理
· 商品分类管理
· 二手商品管理
· 订单管理
· 管理员管理
· 资讯管理
(2)用户端
· 二手商品展示
· 分类筛选
· 商品详情
· 订单凭证与我的订单
· 联系卖家
· 资讯查看
· 我的发布
主要练习的后端技术是:springboot2.7 + mybatisplus
使用的数据库:mysql8.0
前端使用的 vue2 + Element UI
手机端使用的是 uni-app框架 也是可以打包小程序的!
node版本:16.20
后端管理员管理部分代码:
package com.jsonll.base.controller;
import com.jsonll.base.core.NoLogin;
import com.jsonll.base.core.R;
import com.jsonll.base.entity.Admin;
import com.jsonll.base.request.AdminRequest;
import com.jsonll.base.service.IAdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;/*** 管理员控制器*/
@RestController
@RequestMapping("/admin")
public class AdminController extends BaseController {@Autowiredprivate IAdminService iAdminService;/*** 管理员登录*/@PostMapping("/login")@NoLoginpublic R login(@RequestBody AdminRequest request) {return iAdminService.login(request);}/*** RESTful: 获取管理员列表(不分页)*/@GetMapping("")public R list() {// 直接使用 MyBatis-Plus 提供的 list 方法java.util.List<Admin> list = iAdminService.list();// 隐藏密码list.forEach(item -> item.setPassword(null));return R.successData(list);}/*** RESTful: 获取单个管理员详情*/@GetMapping("/{id}")public R get(@PathVariable Integer id) {Admin admin = iAdminService.getById(id);if (admin == null) {return R.error("管理员不存在");}admin.setPassword(null);return R.successData(admin);}/*** 获取管理员列表*/@GetMapping("/pageList")public R pageList(AdminRequest adminRequest) {return iAdminService.pageList(adminRequest);}/*** 添加管理员*/@PostMapping("")public R add(@RequestBody Admin admin) {return iAdminService.add(admin);}/*** 更新管理员信息*/@PutMapping("/{id}")public R updateAdmin(@PathVariable Integer id, @RequestBody Admin admin) {// 路径参数为准admin.setId(id);return iAdminService.updateAdmin(admin);}/*** 删除管理员*/@DeleteMapping("/{id}")public R deleteAdmin(@PathVariable Integer id) {return iAdminService.deleteAdmin(id);}/*** 获取当前登录用户信息*/@GetMapping("/userInfo")public R userInfo() {Integer userId = getLoginUserId();return iAdminService.userInfo(userId);}
}
package com.jsonll.base.service;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jsonll.base.core.R;
import com.jsonll.base.entity.Admin;
import com.jsonll.base.mapper.AdminMapper;
import com.jsonll.base.request.AdminRequest;
import com.jsonll.base.utils.JwtHelper;
import com.jsonll.base.utils.MD5;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;import java.util.List;/*** 管理员表 接口实现类*/
@Service
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements IAdminService {@Overridepublic R login(AdminRequest request) {// 参数校验if (StringUtils.isEmpty(request.getUsername()) || StringUtils.isEmpty(request.getPassword())) {return R.error("用户名或密码不能为空");}// 查询条件 示例LambdaQueryWrapper<Admin> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(Admin::getUsername, request.getUsername());Admin admin = getOne(queryWrapper);// 用户不存在if (admin == null) {return R.error( "用户名或密码错误");}// 密码校验String encryptedPassword = MD5.encoder(request.getPassword());if (!admin.getPassword().equals(encryptedPassword)) {return R.error( "用户名或密码错误");}// 生成tokenString token = JwtHelper.sign(admin.getId());// 给实体类字段赋值admin.setToken(token);return R.successData(admin);}@Overridepublic R userInfo(Integer userId) {//根据id查询示例Admin admin = getById(userId);if (admin == null) {return R.error("未查询到数据");}return R.successData(admin);}@Overridepublic R pageList(AdminRequest adminRequest) {//分页示例Page<Admin> page = new Page<>(adminRequest.getPageNum() == null ? 1 : adminRequest.getPageNum(), adminRequest.getPageSize() == null ? 10 : adminRequest.getPageSize());QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();//搜索条件 示例if(!StringUtils.isEmpty(adminRequest.getSearch())){queryWrapper.lambda().like(Admin::getUsername, adminRequest.getSearch());}page(page, queryWrapper.lambda().orderByDesc(Admin::getId));// 处理返回结果,隐藏密码List<Admin> records = page.getRecords();//列表回显 示例records.forEach(admin->{admin.setPassword(null);//列表实体类 回显示例admin.setEchoExample("回显示例");});return R.successData(page);}@Overridepublic R add(Admin admin) {// 参数校验if (StringUtils.isEmpty(admin.getUsername()) || StringUtils.isEmpty(admin.getPassword())) {return R.error("用户名或密码不能为空");}// where条件示例LambdaQueryWrapper<Admin> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(Admin::getUsername, admin.getUsername());if (count(queryWrapper) > 0) {return R.error( "用户名已存在");}// 设置默认值admin.setIsSuper(0); // 默认为普通管理员// 密码加密admin.setPassword(MD5.encoder(admin.getPassword()));// 保存管理员信息 示例save(admin);//无返回数据 示例return R.success();}@Overridepublic R updateAdmin(Admin admin) {// 参数校验if (admin.getId() == null) {return R.error( "管理员ID不能为空");}// 获取原管理员信息Admin existAdmin = getById(admin.getId());if (existAdmin == null) {return R.error("管理员不存在");}// 不允许修改超级管理员状态if (existAdmin.getIsSuper() == 1) {admin.setIsSuper(1);}// 如果修改了用户名,检查是否已存在if (!StringUtils.isEmpty(admin.getUsername()) && !admin.getUsername().equals(existAdmin.getUsername())) {LambdaQueryWrapper<Admin> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(Admin::getUsername, admin.getUsername());if (count(queryWrapper) > 0) {return R.error( "用户名已存在");}}// 如果密码为空,使用原密码if (StringUtils.isEmpty(admin.getPassword())) {admin.setPassword(existAdmin.getPassword());} else {// 密码加密admin.setPassword(MD5.encoder(admin.getPassword()));}// 根据id更新管理员信息 示例updateById(admin);return R.success();}@Overridepublic R deleteAdmin(Integer id) {// 参数校验if (id == null) {return R.error( "管理员ID不能为空");}// 获取管理员信息Admin admin = getById(id);if (admin == null) {return R.error("管理员不存在");}// 不允许删除超级管理员if (admin.getIsSuper() == 1) {return R.error( "不能删除超级管理员");}// 删除管理员 示例removeById(id);return R.success();}
}
手机端代码:
<template><view class="my-container"><!-- 用户信息区域 --><view class="user-info" v-if="isLogin"><view class="avatar-box"><image class="avatar" :src="userInfo.avatar || '/static/default-avatar.png'" mode="aspectFill"></image></view><view class="user-detail"><view class="nickname">{{userInfo.nickname || '未设置昵称'}}</view><view class="auth-status"><text :class="['auth-tag', userInfo.auth_status === 1 ? 'auth-yes' : 'auth-no']">{{userInfo.auth_status === 1 ? '已认证' : '未认证'}}</text></view></view></view><!-- 未登录状态 --><view class="user-info not-login" v-else @click="goToLogin"><view class="avatar-box"><image class="avatar" src="/static/default-avatar.png" mode="aspectFill"></image></view><view class="user-detail"><view class="nickname">点击登录</view></view></view><!-- 功能菜单 --><view class="menu-list"><view class="menu-group"><view class="menu-item" @click="handleMenuClick('myPublish')"><text class="iconfont icon-publish"></text><text class="menu-text">我的发布</text><text class="iconfont icon-right"></text></view><view class="menu-item" @click="handleMenuClick('myOrders')"><text class="iconfont icon-order"></text><text class="menu-text">我的订单</text><text class="iconfont icon-right"></text></view></view><view class="menu-group"><view class="menu-item" @click="handleMenuClick('news')"><text class="iconfont icon-news"></text><text class="menu-text">公告资讯</text><text class="iconfont icon-right"></text></view><view class="menu-item" @click="handleMenuClick('authenticate')" v-if="isLogin"><text class="iconfont icon-auth"></text><text class="menu-text">我的认证</text><text class="iconfont icon-right"></text></view></view><view class="menu-group" v-if="isLogin"><view class="menu-item" @click="handleMenuClick('logout')"><text class="iconfont icon-logout"></text><text class="menu-text">退出登录</text><text class="iconfont icon-right"></text></view></view><view class="menu-group" v-else><!-- <view class="menu-item" @click="handleMenuClick('register')"><text class="iconfont icon-register"></text><text class="menu-text">注册</text><text class="iconfont icon-right"></text></view> --><view class="menu-item" @click="handleMenuClick('login')"><text class="iconfont icon-login"></text><text class="menu-text">登录</text><text class="iconfont icon-right"></text></view></view></view></view>
</template><script>
import { getCurrentUser } from '@/api/user.js'export default {data() {return {isLogin: false,userInfo: {}}},onShow() {// 每次显示页面时检查登录状态this.checkLoginStatus()},onLoad() {// 页面加载时立即检查登录状态,如果未登录则跳转到登录页const token = uni.getStorageSync('token')if (!token) {uni.navigateTo({url: '/pages/login/login'})}},methods: {// 检查登录状态checkLoginStatus() {const token = uni.getStorageSync('token')if (token) {this.isLogin = truethis.getUserInfo()} else {this.isLogin = falsethis.userInfo = {}}},// 获取用户信息getUserInfo() {getCurrentUser().then(res => {if (res.code === 1000) {this.userInfo = res.data}}).catch(() => {this.isLogin = falsethis.userInfo = {}})},// 跳转到登录页goToLogin() {uni.navigateTo({url: '/pages/login/login'})},// 菜单点击处理handleMenuClick(type) {switch(type) {case 'myPublish':// 检查登录状态if (!this.isLogin) {uni.showToast({title: '请先登录',icon: 'none'})this.goToLogin()return}// 跳转到我的发布页面uni.navigateTo({url: '/pages/my/published'})breakcase 'myOrders':// 检查登录状态if (!this.isLogin) {uni.showToast({title: '请先登录',icon: 'none'})this.goToLogin()return}// 跳转到我的订单页面uni.navigateTo({url: '/pages/my/orders'})breakcase 'news':uni.navigateTo({url: '/pages/news/list'})breakcase 'authenticate':// 跳转到认证页面uni.navigateTo({url: '/pages/my/authenticate'})breakcase 'register':uni.showToast({title: '注册功能开发中',icon: 'none'})breakcase 'login':this.goToLogin()breakcase 'logout':this.handleLogout()break}},// 退出登录handleLogout() {uni.showModal({title: '提示',content: '确定要退出登录吗?',success: (res) => {if (res.confirm) {uni.removeStorageSync('token')this.isLogin = falsethis.userInfo = {}uni.showToast({title: '已退出登录',icon: 'success'})}}})}}
}
</script><style lang="scss">
.my-container {min-height: 100vh;background-color: #f5f5f5;.user-info {display: flex;align-items: center;padding: 30rpx;background-color: #ffffff;&.not-login {opacity: 0.8;}.avatar-box {width: 120rpx;height: 120rpx;border-radius: 50%;overflow: hidden;margin-right: 30rpx;.avatar {width: 100%;height: 100%;background-color: #eeeeee;}}.user-detail {flex: 1;.nickname {font-size: 32rpx;font-weight: bold;margin-bottom: 10rpx;}.auth-status {.auth-tag {display: inline-block;font-size: 24rpx;padding: 4rpx 12rpx;border-radius: 20rpx;&.auth-yes {background-color: #e6f7ff;color: #1890ff;}&.auth-no {background-color: #fff7e6;color: #fa8c16;}}}}}.menu-list {margin-top: 20rpx;.menu-group {background-color: #ffffff;margin-bottom: 20rpx;.menu-item {display: flex;align-items: center;padding: 30rpx;border-bottom: 1rpx solid #f0f0f0;&:last-child {border-bottom: none;}.iconfont {font-size: 40rpx;color: #666;margin-right: 20rpx;&.icon-right {margin-right: 0;margin-left: auto;font-size: 32rpx;color: #999;}}.menu-text {font-size: 28rpx;color: #333;}}}}
}
</style>
如果你刚开始学习Java,并且想通过实践提升自己,可以参考这篇文章,尝试模仿并独立完成一个类似的项目。
把项目部署了一个预览地址,方便大家参考。
https://test.wwwoop.com/?s=/er-shou-ping-tai-web&no=Second-hand-TP003&rand=0.6679227765871157