项目编号:BS-SC-030
一,项目简介
新新商城,一款基于 Springboot+Vue 的电商项目,前后端分离项目。完整的实现了一个商城系统应有的基本功能,包括但不限于以下主要功能模块:
前端商城用户
- 用户注册登陆
- 商品信息分类和品牌浏览
- 全文搜索
- 添加购物车管理
- 在线购买商品:使用支付宝沙箱在线支付
- 个人信息管理
- 个人订单管理
- 在线退换货功能
- 退款功能
后台用户管理功能
- 商品分类管理
- 商品品牌管理
- 商品规格管理
- 商品采购管理
- 供应商管理
- 订单管理
- 退货退款管理
- 轮播图设置管理
- 用户管理
- 权限角色管理
- 个人信息管理
项目后台基于Springboot+MybatisPlus开发实现,前端使用VUE+Element开发实现,前后端分离开发,前端通过调用后台接口来进行相应的交互处理。
亮点技术:短信发送验证码、阿里云OSS云存储商品图片、邮箱自动发邮件验证操作权限,Shiro权限管理,数据加密处理,支付宝沙箱技术应用,Redis数据缓存处理。
项目功能完整,界面优雅大方,人机交互流畅,是一个难得的毕业设计作品。
二,环境介绍
语言环境:Java: jdk1.8
数据库:Mysql: mysql5.7 Redis:5.0.10
应用服务器:Tomcat: tomcat8.5.31
开发工具:IDEA或eclipse
技术应用:
后端技术
技术 |
说明 |
官网 |
SpringBoot |
容器+MVC框架 |
|
Shiro |
认证和授权框架 |
|
MyBatis |
ORM框架 |
|
MySQL |
数据库 |
|
Redis |
分布式缓存 |
|
Druid |
数据库连接池 |
前端技术
技术 |
说明 |
官网 |
Vue |
前端框架 |
|
Vue-router |
路由框架 |
|
Vuex |
全局状态管理框架 |
|
Element |
前端UI框架 |
|
Axios |
前端HTTP框架 |
|
vue-clipboard2 |
将内容复制到剪贴板 |
|
vuex-persistedstate |
vuex持久化 |
|
nprogress |
进度条控件 |
开发环境
工具 |
版本号 |
下载 |
JDK |
1.8 |
https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html |
Mysql |
5.7 |
|
Redis |
5.0.10 |
第三方技术
工具 |
官网 |
支付宝沙箱技术 |
|
OSS 存储 |
|
阿里云短信服务 |
|
QQ邮箱服务 |
三,系统展示
下面展示一下项目的主要核心功能:
前端用户操作
用户注册:会对邮箱发验证码验证,要求必须真实有效邮箱
用户登陆
首页
商品购买
购物车
结算付款
我的订单:可以申请退款、收货后可以申请退货等操作
后台管理用户功能
后台首页
商品管理:可以实现商品添加、编辑、删除、下架、查询等,另可以对商品分类、品牌、规则、采购信息进行管理,以及对供应商进行管理,不再一一展示。菜单上的功能都是齐全的。
订单管理:可以进行发货、退货、退款等相关操作
营销管理
主要对前端展示的广告轮播图进行管理
用户和权限管理:可以对管理员、顾客、角色进行管理操作
四,核心代码展示
package com.qiu.controller; import com.qiu.entity.Banner; import com.qiu.service.BannerService; import com.qiu.util.general.CommonResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; /** * @author ZNZ * @email 469603589@qq.com * @date 2022/12/31 16:23 * @description 商品类别 */ @CrossOrigin @RestController public class BannerController { @Autowired private BannerService bannerService; @RequestMapping(value = "/banner/add") public CommonResult addBanner(Banner banner) { if (bannerService.insertData(banner)) { return CommonResult.success("商品轮播图添加成功", banner); } return CommonResult.error("商品轮播图添加失败"); } @RequestMapping(value = "/banner/update") public CommonResult updateType(Banner banner) { if (bannerService.updateById(banner)) { return CommonResult.success("商品轮播图修改成功", banner); } return CommonResult.error("商品轮播图修改失败"); } @RequestMapping(value = "/banner/deleteById") public CommonResult deleteTypeById(Integer bannerId) { if (bannerService.deleteById(bannerId)) { return CommonResult.success("商品轮播图删除成功", "bannerId: " + bannerId); } return CommonResult.error("商品轮播图删除失败"); } @RequestMapping(value = "/banner/findAll") public CommonResult findAllType() { List<Banner> banners = bannerService.selectAll(); if (banners != null) { return CommonResult.success("商品轮播图查询成功", banners); } return CommonResult.error("商品轮播图查询失败"); } @RequestMapping(value = "/banner/findById") public CommonResult findById(Integer bannerId) { Banner banner = bannerService.selectById(bannerId); if (banner != null) { return CommonResult.success("商品轮播图查询成功", banner); } return CommonResult.error("商品轮播图查询失败"); } }
package com.qiu.controller; import cn.dev33.satoken.secure.SaSecureUtil; import cn.dev33.satoken.stp.StpUtil; import com.qiu.constant.UserStatusEnum; import com.qiu.entity.Role; import com.qiu.entity.User; import com.qiu.service.RoleService; import com.qiu.service.UserService; import com.qiu.util.general.CommonResult; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; /** * @author ZNZ * @email 469603589@qq.com * @date 2022/12/6 17:10 * @description 登录、退出、修改个人信息等业务操作 */ @Slf4j @CrossOrigin @RestController public class OperateController { private static final String EMAIL_FLAG = "@"; @Autowired private RoleService roleService; @Autowired private UserService userService; /** * 登录操作 * * @param username 用户登录的账号 * @param password 用户登录的密码 */ @RequestMapping(value = "/login", produces = {"application/json;charset=UTF-8"}) public CommonResult doLogin(String username, String password) { User user; if (username.contains(EMAIL_FLAG)) { //包含@符号,代表用户通过邮箱账号登录 user = userService.selectByKey(username); } else { //不包含@符号,代表用户通过手机号登录 user = userService.selectByPhone(username); } if (user == null) { return CommonResult.error("账号不存在"); } String encodePassword = SaSecureUtil.md5BySalt(password, user.getAccountNumber()); if (!encodePassword.equals(user.getPassword())) { return CommonResult.error("用户名或密码错误"); } // 账号被锁定 if (!user.getUserState()) { StpUtil.disable(user.getUserId(), -1); } StpUtil.login(user.getUserId()); //更新最后登录时间 user.setLoginTime(new Date()); userService.updateById(user); //存放用户信息 Map<String, Object> info = new HashMap<>(4); info.put("user", user); //存放sessionId, 即 token info.put("sessionId", StpUtil.getTokenInfo().getTokenValue()); List<Role> roles = userService.getRoleList(user.getUserId()); Set<String> roseNames = roles.stream().map(Role::getRoleName).collect(Collectors.toSet()); Set<String> roseDescribes = roles.stream().map(Role::getRoleDescribe).collect(Collectors.toSet()); info.put("role", roseNames); info.put("roleInfo", roseDescribes); return CommonResult.success("登录成功", info); } /** * 注销登录 */ @RequestMapping(value = "/logout") public CommonResult logout() { StpUtil.logout(); return CommonResult.success("注销成功"); } /** * 判断key是否存在 目前用于判断邮箱是否被注册过 * * @param email 邮箱号(账号) */ @RequestMapping(value = "/allow/existUser") public CommonResult existUser(String email) { Boolean isExist = userService.existsWithPrimaryKey(email); if (isExist != null) { return CommonResult.success("查询成功", isExist); } return CommonResult.error("查询失败"); } /** * 判断手机号phone是否存在 目前被用于绑定手机号时,确认手机号已被绑定 * * @param telephone 手机号 */ @RequestMapping(value = "/allow/existPhone") public CommonResult existPhone(String telephone) { Boolean isExist = userService.existsWithPrimaryPhone(telephone); if (isExist != null) { return CommonResult.success("手机号查询成功", isExist); } return CommonResult.error("手机号查询失败"); } /** * 重置密码、找回密码 * * @param account 账号 * @param password 密码 */ @RequestMapping(value = "/allow/resetpwd") public CommonResult resetPwd(String account, String password) { if (account != null && password != null) { String encodePassword = SaSecureUtil.md5BySalt(password, account); Integer id = userService.selectIdByKey(account); User user = new User(); user.setUserId(id); user.setPassword(encodePassword); if (userService.updateById(user)) { return CommonResult.success("重置密码成功", user); } return CommonResult.error("重置密码失败"); } return CommonResult.error("用户数据不存在"); } /** * 注册新用户 * * @param user 用户信息 */ @RequestMapping(value = "/allow/add") public CommonResult add(User user) { if (user.getPassword() != null && user.getUserName() != null) { String encodePassword = SaSecureUtil.md5BySalt(user.getPassword(), user.getAccountNumber()); user.setPassword(encodePassword); user.setUserState(true); user.setStatus(UserStatusEnum.CUSTOMER); if (userService.insertData(user)) { log.info("用户添加成功,用户信息:{}", user); return CommonResult.success("注册成功", user); } else { return CommonResult.error("注册失败"); } } return CommonResult.error("用户数据不存在"); } /** * 更新用户信息 * * @param user 用户信息 */ @RequestMapping(value = "/allow/update") public CommonResult update(User user) { if (user.getUserState() != null && user.getUserState()) { StpUtil.untieDisable(user.getUserId()); } if (userService.updateById(user)) { return CommonResult.success("信息保存成功", user); } return CommonResult.error("信息保存失败"); } }
package com.qiu.controller; import com.alibaba.fastjson.JSON; import com.qiu.entity.Logistics; import com.qiu.entity.Order; import com.qiu.entity.Product; import com.qiu.service.LogisticsService; import com.qiu.service.OrderService; import com.qiu.service.ProductService; import com.qiu.util.general.CommonResult; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; /** * @author ZNZ * @email 469603589@qq.com * @date 2022/12/28 18:11 * @description 订单相关业务 */ @RestController @CrossOrigin public class OrderController { private static final String VIP = "Vip"; private static final String COLLECT_GOODS_STATE = "已收货"; @Autowired private OrderService orderService; @Autowired private ProductService productService; @Autowired private LogisticsService logisticsService; @Autowired private RedisTemplate<String, String> redisTemplate; @RequestMapping(value = "/order/findById") public CommonResult findOrderById(Integer orderId) { Order order = orderService.selectById(orderId); if (orderId != null) { return CommonResult.success("订单信息查询成功", order); } return CommonResult.error("订单信息查询失败"); } @RequestMapping(value = "/order/findOrderInfo") public CommonResult findOrderInfo(String userAccount) { List<Map<String, Object>> orderMap = orderService.selectAllOrder(userAccount); if (orderMap != null) { return CommonResult.success("订单信息查询成功", orderMap); } return CommonResult.error("订单信息查询失败"); } @RequestMapping(value = "/order/findAll") public CommonResult findAllOrder() { List<Order> orders = orderService.selectAll(); if (orders != null) { return CommonResult.success("订单信息查询成功", orders); } return CommonResult.error("订单信息查询失败"); } @RequestMapping(value = "/order/findCount") public CommonResult findCount() { Integer count = orderService.selectCount(); if (count != null) { return CommonResult.success("订单数量查询成功", count); } return CommonResult.error("订单数量查询失败"); } @RequestMapping(value = "/order/add") public CommonResult addOrder(Order order) { if (order != null) { if (order.getProductNo().contains(VIP)) { return handleMemberOrders(order); } return handleMerchandiseOrders(order); } else { return CommonResult.error("订单数据不完整"); } } @RequestMapping(value = "/order/cartOrder") public CommonResult cartOrder(String orderNo, String ordersInfo, String cartIds) { List<String> cartIdList = JSON.parseArray(cartIds, String.class); List<Order> orders = JSON.parseArray(ordersInfo, Order.class); if (orders != null) { ArrayList<String> orderInfo = new ArrayList<>(); ArrayList<String> productInfo = new ArrayList<>(); for (Order order : orders) { Product product = productService.selectByKey(order.getProductNo()); Integer productStock = product.getProductStock(); Integer payAmount = order.getPayAmount(); if (productStock >= payAmount) { Product newProduct = new Product(); newProduct.setProductId(product.getProductId()); int newStock = productStock - payAmount; newProduct.setProductStock(newStock); newProduct.setIsStockOut(newStock < product.getLowestStock()); // 如果库存小于等于0,自动下架 newProduct.setIsSale(newStock > 0); if (productService.updateById(newProduct) && orderService.insertData(order)) { orderInfo.add(order.getOrderNo()); productInfo.add(order.getProductNo()); } } } if (!orderInfo.isEmpty()) { String cartIdsInfo = StringUtils.join(cartIdList.toArray(), ","); String orderNoInfo = StringUtils.join(orderInfo, ","); String productNoInfo = StringUtils.join(productInfo, ","); redisTemplate.opsForValue().set(orderNo, orderNoInfo, 24, TimeUnit.HOURS); redisTemplate.opsForValue().set("cartId" + orderNo, cartIdsInfo, 24, TimeUnit.HOURS); return CommonResult.success("创建订单成功", productNoInfo); } return CommonResult.error("创建订单失败,请查看商品库存是否满足购买数量"); } else { return CommonResult.error("订单数据不完整"); } } @RequestMapping(value = "/order/update") public CommonResult updateOrder(Order order) { if (orderService.updateById(order)) { return CommonResult.success("修改订单成功", order); } return CommonResult.error("修改订单失败"); } @RequestMapping(value = "/order/delete") public CommonResult deleteOrder(Integer orderId) { if (orderService.deleteById(orderId)) { return CommonResult.success("删除订单成功", "订单id:" + orderId); } return CommonResult.error("删除订单失败"); } @RequestMapping(value = "/order/receipt") public CommonResult updateOrder(Integer orderId) { Order order = new Order(); order.setOrderId(orderId); order.setOrderState(COLLECT_GOODS_STATE); if (orderService.updateById(order)) { return CommonResult.success("商品收货成功", order); } return CommonResult.error("商品收货失败"); } @RequestMapping(value = "/orderDetail/orderInfo") public CommonResult orderInfo(String orderNo) { ArrayList<Object> resultList = new ArrayList<>(); Order order = orderService.selectByKey(orderNo); Logistics logistics = logisticsService.selectOrderNo(orderNo); if (order != null) { resultList.add(order); } if (logistics != null) { resultList.add(logistics); } return CommonResult.success("订单详情查询成功", resultList); } /** * 处理会员订单 * * @param order 订单信息 */ private CommonResult handleMemberOrders(Order order) { if (orderService.insertData(order)) { return CommonResult.success("创建订单成功", order); } else { return CommonResult.error("创建订单失败"); } } /** * 处理商品订单 * * @param order 订单信息 */ private CommonResult handleMerchandiseOrders(Order order) { Product product = productService.selectByKey(order.getProductNo()); Integer productStock = product.getProductStock(); Integer payAmount = order.getPayAmount(); boolean isOk = productStock >= payAmount; if (isOk) { Product newProduct = new Product(); newProduct.setProductId(product.getProductId()); int newStock = productStock - payAmount; newProduct.setProductStock(newStock); newProduct.setIsStockOut(newStock < product.getLowestStock()); // 如果库存小于等于0,自动下架 newProduct.setIsSale(newStock > 0); if (productService.updateById(newProduct)) { if (orderService.insertData(order)) { redisTemplate.opsForValue().set(order.getOrderNo(), order.getOrderNo(), 24, TimeUnit.HOURS); return CommonResult.success("创建订单成功", order); } else { return CommonResult.error("创建订单失败"); } } else { return CommonResult.error("创建订单失败"); } } else { return CommonResult.error("商品库存不足"); } } }
五,项目总结
项目后台基于Springboot+MybatisPlus开发实现,前端使用VUE+Element开发实现,前后端分离开发,前端通过调用后台接口来进行相应的交互处理。
亮点技术:短信发送验证码、阿里云OSS云存储商品图片、邮箱自动发邮件验证操作权限,Shiro权限管理,数据加密处理,支付宝沙箱技术应用,Redis数据缓存处理。
项目功能完整,界面优雅大方,人机交互流畅,是一个难得的毕业设计作品。