一、项目演示
项目演示地址:视频地址
二、项目介绍
项目描述:这是一个基于SpringCloud+Vue框架开发的校园二手市场系统。首先,这是一个前后端分离的项目,代码简洁规范,注释说明详细,易于理解和学习。其次,这项目功能丰富,具有一个校园二手市场系统该有的所有功能。
项目功能:此项目分为两个角色:普通用户和管理员。普通用户有登录注册、浏览商品信息、地址管理、添加购物车、结算支付订单、查看个人信息、查看个人订单详情、创建店铺、发布商品等等功能。管理员有管理所有商品信息、管理所有订单信息、管理所有用户信息、管理所有店铺信息、查看收益数据图表等等功能。
应用技术:SpringCloud + Vue + MySQL + MyBatis + Redis + ElementUI + 沙箱支付宝 + Nacos + openFeign + GateWay
运行环境:IntelliJ IDEA2019.3.5 + MySQL5.7(项目压缩包中自带) + Redis5.0.5(项目压缩包中自带) + JDK1.8 + Maven3.6.3(项目压缩包中自带)+ Node14.16.1(项目压缩包中自带)+ Nacos1.3.0(项目压缩包中自带)
注意:电脑内存最好16G,否则存在运行不起来的可能!!!
三、项目运行截图
项目运行截图:
四、主要代码
1.SpringCloud GateWay 网关拦截器代码:
package com.yjq.programmer.filter;
import com.yjq.programmer.constant.WhiteList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import javax.annotation.Resource;
/**
* @author 杨杨吖
* @QQ 823208782
* @WX yjqi12345678
* @create 2021-05-12 17:44
*/
@Component
public class LoginWebGatewayFilter implements GlobalFilter, Ordered {
private static final Logger logger = LoggerFactory.getLogger(LoginWebGatewayFilter.class);
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String path = exchange.getRequest().getURI().getPath();
// 判断该路径是否需要验证
for(String str : WhiteList.userNotNeedConfirmUrl){
if(path.equals(str)){
return chain.filter(exchange);
}
}
//获取header的token参数
String token = exchange.getRequest().getHeaders().getFirst("token");
logger.info("前台登录验证开始,token:{}", token);
if (token == null || token.isEmpty()) {
logger.info( "token为空,请求被拦截" );
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
Object object = stringRedisTemplate.opsForValue().get("USER_" + token);
if (object == null) {
logger.warn( "token无效,请求被拦截" );
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder()
{
// 过滤器执行优先级 值越小优先级越高
return 1;
}
}
2.沙箱支付宝支付订单业务逻辑代码:
/**
* 使用沙箱支付宝支付订单
* @param orderDTO
* @return
*/
@Override
public ResponseDTO<String> aliPayOrder(OrderDTO orderDTO) {
// 判断是否进行继续支付
if(!CommonUtil.isEmpty(orderDTO.getId())) {
Orders orders = ordersMapper.selectByPrimaryKey(orderDTO.getId());
return initAliPay(orders.getNo(), orders.getTotalPrice());
}
if(orderDTO.getCartIdList() == null || orderDTO.getCartIdList().size() == 0) {
return ResponseDTO.errorByMsg(CodeMsg.DATA_ERROR);
}
if(CommonUtil.isEmpty(orderDTO.getUserId())) {
return ResponseDTO.errorByMsg(CodeMsg.USER_SESSION_EXPIRED);
}
List<OrderItem> orderItemList = new ArrayList<>();
BigDecimal totalPrice = new BigDecimal("0.00");
String orderNo = String.valueOf(new SnowFlake(2, 3).nextId());
String orderId = UuidUtil.getShortUuid();
// 获取用户挑选的商品信息
for(String cartId : orderDTO.getCartIdList()) {
CartDTO cartDTO = new CartDTO();
cartDTO.setId(cartId);
ResponseDTO<CartDTO> responseDTO = userClient.getCartById(cartDTO);
if(!responseDTO.getCode().equals(CodeMsg.SUCCESS.getCode())) {
return ResponseDTO.errorByMsg(CodeMsg.ORDER_PRODUCT_ERROR);
}
cartDTO = responseDTO.getData();
// 判断商品库存是否足够
if(cartDTO.getQuantity() > cartDTO.getProductDTO().getStock()) {
CodeMsg codeMsg = CodeMsg.PRODUCT_STOCK_ERROR;
codeMsg.setMsg("商品(" + cartDTO.getProductDTO().getName() + ")库存不足!" );
return ResponseDTO.errorByMsg(codeMsg);
}
// 判断商品状态
if(!ProductStateEnum.SUCCESS.getCode().equals(cartDTO.getProductDTO().getState())) {
CodeMsg codeMsg = CodeMsg.PRODUCT_STATE_ERROR;
codeMsg.setMsg("商品(" + cartDTO.getProductDTO().getName() + ")状态异常!" );
return ResponseDTO.errorByMsg(codeMsg);
}
// 封装订单详情数据
OrderItem orderItem = new OrderItem();
orderItem.setId(UuidUtil.getShortUuid());
orderItem.setProductName(cartDTO.getProductDTO().getName());
orderItem.setProductId(cartDTO.getProductDTO().getId());
orderItem.setProductPhoto(cartDTO.getProductDTO().getPhoto());
orderItem.setProductPrice(cartDTO.getProductDTO().getPrice());
orderItem.setOrderId(orderId);
orderItem.setState(OrderStateEnum.WAIT.getCode());
orderItem.setStoreId(cartDTO.getProductDTO().getStoreId());
orderItem.setQuantity(cartDTO.getQuantity());
orderItem.setSumPrice(new BigDecimal(orderItem.getQuantity()).multiply(orderItem.getProductPrice()));
orderItemList.add(orderItem);
totalPrice = totalPrice.add(orderItem.getSumPrice());
// 移除购物车数据
userClient.removeCart(cartDTO);
}
// 订单详情数据入库
for(OrderItem orderItem : orderItemList){
if(orderItemMapper.insertSelective(orderItem) == 0) {
throw new RuntimeException(CodeMsg.ORDER_ADD_ERROR.getMsg());
}
}
// 封装订单数据 并入库
Orders orders = CopyUtil.copy(orderDTO, Orders.class);
orders.setId(orderId);
orders.setCreateTime(new Date());
orders.setNo(orderNo);
orders.setTotalPrice(totalPrice);
orders.setState(OrderStateEnum.WAIT.getCode());
if(ordersMapper.insertSelective(orders) == 0) {
throw new RuntimeException(CodeMsg.ORDER_ADD_ERROR.getMsg());
}
return initAliPay(orderNo, totalPrice);
}
3.其他服务调用商品服务的代码(openFeign):
package com.yjq.programmer.feignclient;
import com.yjq.programmer.dto.ProductDTO;
import com.yjq.programmer.dto.ResponseDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
/**
* @author 杨杨吖
* @QQ 823208782
* @WX yjqi12345678
* @create 2022-07-08 9:52
*/
@FeignClient("ProductService")
public interface ProductClient {
@PostMapping("/product/store/get")
ResponseDTO<List<ProductDTO>> getByStore(@RequestBody ProductDTO productDTO);
@PostMapping("/product/get")
ResponseDTO<ProductDTO> getById(@RequestBody ProductDTO productDTO);
@PostMapping("/product/save")
ResponseDTO<Boolean> saveProduct(@RequestBody ProductDTO productDTO);
@PostMapping("/product/remove/store_id")
ResponseDTO<Boolean> removeProductByStoreId(@RequestBody ProductDTO productDTO);
}
4.用户登录业务逻辑代码:
/**
* 前台用户登录
* @param userDTO
* @return
*/
@Override
public ResponseDTO<UserDTO> homeLogin(UserDTO userDTO) {
// 进行是否为空判断
if(CommonUtil.isEmpty(userDTO.getUsername())){
return ResponseDTO.errorByMsg(CodeMsg.USERNAME_EMPTY);
}
if(CommonUtil.isEmpty(userDTO.getPassword())){
return ResponseDTO.errorByMsg(CodeMsg.PASSWORD_EMPTY);
}
// 对比昵称和密码是否正确
UserExample userExample = new UserExample();
userExample.createCriteria().andUsernameEqualTo(userDTO.getUsername()).andPasswordEqualTo(userDTO.getPassword());
List<User> userList = userMapper.selectByExample(userExample);
if(userList == null || userList.size() != 1){
return ResponseDTO.errorByMsg(CodeMsg.USERNAME_PASSWORD_ERROR);
}
// 生成登录token并存入Redis中
UserDTO selectedUserDto = CopyUtil.copy(userList.get(0), UserDTO.class);
String token = UuidUtil.getShortUuid();
selectedUserDto.setToken(token);
//把token存入redis中 有效期1小时
stringRedisTemplate.opsForValue().set("USER_" + token, JSON.toJSONString(selectedUserDto), 3600, TimeUnit.SECONDS);
return ResponseDTO.successByMsg(selectedUserDto, "登录成功!");
}