企业级开发项目“苍穹外卖”(三)
设置店铺营业状态#
先去我之前写的博客“Redis数据库学习笔记"学习Redis的基本操作。
在config层下创建Redis的配置类,里面编写:
@Configuration
@Slf4j
public class RedisConfiguration {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
log.info("开始创建redis对象:{}",redisConnectionFactory);
RedisTemplate redisTemplate = new RedisTemplate();
//设置redis工厂对象
redisTemplate.setConnectionFactory(redisConnectionFactory);
//设置redis序列化器
redisTemplate.setKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
}
然后再在controller层里面创建shop店铺管理的类,里面编写设置店铺状态和查询店铺状态的代码:
@RestController("adminShopController")
@Slf4j
@Api(tags = "店铺管理")
@RequestMapping("/admin/shop")
public class ShopController {
@Autowired
private RedisTemplate redisTemplate;
@PutMapping("/{status}")
@ApiOperation("设置店铺营业状态")
public Result setStaus(@PathVariable Integer status){
log.info("设置店铺营业状态:{}",status ==1 ?"营业中": "打烊中");
redisTemplate.opsForValue().set("SHOP_STATUS",status);
return Result.success();
}
@GetMapping("/status")
@ApiOperation("获取店铺营业状态")
public Result<Integer> getStatus(){
Integer shopStatus = (Integer) redisTemplate.opsForValue().get("SHOP_STATUS");
log.info("获取店铺营业状态:{}",shopStatus ==1 ?"营业中": "打烊中");
return Result.success(shopStatus);
}
}
记得在yml和的-dev yml里面配置redis的用户连接信息:
redis:
host: localhost
port: 6379
password: 123456
database: 1
接口管理分开管理端和用户端#
· 在WebMvcConfiguration里面复制一个bean注解下的代码,并在new Docket下编写.groupName("管理端接口/用户端接口"),具体代码如下:
/**
* 通过knife4j生成接口文档
* @return
*/
@Bean
public Docket docket1() {
log.info("准备生成接口文档...");
ApiInfo apiInfo = new ApiInfoBuilder()
.title("苍穹外卖项目接口文档")
.version("2.0")
.description("苍穹外卖项目接口文档")
.build();
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.groupName("管理端接口")
.apiInfo(apiInfo)
.select()
.apis(RequestHandlerSelectors.basePackage("com.sky.controller.admin"))
.paths(PathSelectors.any())
.build();
return docket;
}
@Bean
public Docket docket2() {
log.info("准备生成接口文档...");
ApiInfo apiInfo = new ApiInfoBuilder()
.title("苍穹外卖项目接口文档")
.version("2.0")
.description("苍穹外卖项目接口文档")
.build();
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.groupName("用户端接口")
.apiInfo(apiInfo)
.select()
.apis(RequestHandlerSelectors.basePackage("com.sky.controller.user"))
.paths(PathSelectors.any())
.build();
return docket;
}
这样在项目接口文档里面就可以区分开这两个端了。
微信小程序开发#
下载微信开发者工具,然后将资料里面的前端文件导入进来,输入自己的openid(openid和小程序appid和secret自己去网上搜),微信小程序开发我博客之前也写过。
将资料里面的用户端文件导入进对应server文件夹里
Spring Cache#
maven坐标:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
常用注解:
在苍穹外卖项目中的应用:用于缓存套餐数据,只需在启动类上加入@EnableCaching注解,在admin的SetmealController里面的删改和启动禁用上加上@CacheEvict(cacheNames = "setmealCache",allEntries = true)注解,增加套餐上添加@CacheEvict(cacheNames = "setmealCache",key="#setmealDTO.categoryId")注解。在user的SetmealController的根据id查询套餐上添加@Cacheable(cacheNames ="setmealCache",key="#categoryId")
购物车管理#
后面的购物车管理就跟之前的差不多了,直接上impl的代码:
@Autowired
private ShoppingCartMapper shoppingCartMapper;
@Autowired
private SetmealMapper setmealMapper;
@Autowired
private DishMapper dishMapper;
/**
* 添加物品
* @param shoppingCartDTO
*/
public void addShoppingCart(ShoppingCartDTO shoppingCartDTO) {
//判断当前加入购物车的商品是否存在
ShoppingCart shoppingCart=new ShoppingCart();
BeanUtils.copyProperties(shoppingCartDTO,shoppingCart);
Long userId= BaseContext.getCurrentId();
shoppingCart.setUserId(userId);
List<ShoppingCart> list =shoppingCartMapper.list(shoppingCart);
//如果已经存在了,只需要将数量增加
if (list !=null&& list.size()>0){
ShoppingCart cart=list.get(0);
cart.setNumber(cart.getNumber()+1);
shoppingCartMapper.updateById(cart);
}else {
//判断是为菜品还是套餐
Long dishId = shoppingCart.getDishId();
if (dishId !=null){
Dish dish=dishMapper.getById(dishId);
shoppingCart.setName(dish.getName());
shoppingCart.setImage(dish.getImage());
shoppingCart.setAmount(dish.getPrice());
shoppingCart.setNumber(1);
shoppingCart.setCreateTime(LocalDateTime.now());
}else {
//为套餐
Long setmealId=shoppingCart.getSetmealId();
Setmeal setmeal=setmealMapper.pageById(setmealId);
shoppingCart.setName(setmeal.getName());
shoppingCart.setImage(setmeal.getImage());
shoppingCart.setAmount(setmeal.getPrice());
shoppingCart.setNumber(1);
shoppingCart.setCreateTime(LocalDateTime.now());
}
shoppingCartMapper.insert(shoppingCart);
}
}
导入收货地址接口(AdressBook)和用户下单接口代码(Order),代码的话就自己去下载看看吧,没啥新技术。
除了用户下单的 ServiceImpl的代码有点难:其他的还将就
/**
* 用户下单
*
* @param ordersSubmitDTO
* @return
*/
@Transactional
public OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO) {
//异常情况的处理(收货地址为空、购物车为空)
AddressBook addressBook = addressBookMapper.getById(ordersSubmitDTO.getAddressBookId());
if (addressBook == null) {
throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
}
Long userId = BaseContext.getCurrentId();
ShoppingCart shoppingCart = new ShoppingCart();
shoppingCart.setUserId(userId);
//查询当前用户的购物车数据
List<ShoppingCart> shoppingCartList = shoppingCartMapper.list(shoppingCart);
if (shoppingCartList == null || shoppingCartList.size() == 0) {
throw new ShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
}
//构造订单数据
Orders order = new Orders();
BeanUtils.copyProperties(ordersSubmitDTO,order);
order.setPhone(addressBook.getPhone());
order.setAddress(addressBook.getDetail());
order.setConsignee(addressBook.getConsignee());
order.setNumber(String.valueOf(System.currentTimeMillis()));
order.setUserId(userId);
order.setStatus(Orders.PENDING_PAYMENT);
order.setPayStatus(Orders.UN_PAID);
order.setOrderTime(LocalDateTime.now());
//向订单表插入1条数据
orderMapper.insert(order);
//订单明细数据
List<OrderDetail> orderDetailList = new ArrayList<>();
for (ShoppingCart cart : shoppingCartList) {
OrderDetail orderDetail = new OrderDetail();
BeanUtils.copyProperties(cart, orderDetail);
orderDetail.setOrderId(order.getId());
orderDetailList.add(orderDetail);
}
//向明细表插入n条数据
orderDetailMapper.insertBatch(orderDetailList);
//清理购物车中的数据
shoppingCartMapper.deleteByUserId(userId);
//封装返回结果
OrderSubmitVO orderSubmitVO = OrderSubmitVO.builder()
.id(order.getId())
.orderNumber(order.getNumber())
.orderAmount(order.getAmount())
.orderTime(order.getOrderTime())
.build();
return orderSubmitVO;
}
这里就顺便补充下@Transactional注解:
事务处理translational
概念:指一组原子性的操作序列,这些操作要么全部执行,要么全部不执行
特性:原子性、一致性、隔离性和持久性
应用场景:当一组操作需要同时执行时。–金融行业、电商平台、物流行业
开发流程:在需要事务管理的方法上加注解:@Transactional()
rollbackFor属性:回滚指定类型的异常:@Transactional(rollbackFor =
Exception.class)
Propagation属性 :
事务传播:当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制。
REQUIRED – 【默认值】需要事务,有则加入,无则创建新事务
REQUIRES_NEW --总是创建新事务
内网穿透#
封面图就是内网穿透的原理图:
进入临时域名的使用网站:https://dashboard.cpolar.com/,注册一个账户登进去选择免费的临时域名,下载cpolar的安装exe,按照步骤安装好就行。然后回到cpolar网站选择验证,复制你的Authtoken,然后运行刚刚安装好的cpolar.exe,输入cpolar.exe authtoken 【刚刚复制的】 ,再输入cpolar.exe http 8080然后回车,这时您的公网域名就创建好了,别人的电脑和手机就可以访问你的苍穹外卖了。可以输入https://xxxx/doc.html访问你的接口文档。
其他的接口就参考day9的资料吧:
微信小程序备案上线#
剩下的催单接口和表格输出就自己去看黑马的吧~
苍穹外卖,完结!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?