微信点餐SpringBoot-11:买家订单---Controller层与API的实现

Controller层的实现

Controller层主要实现四个方法:
创建订单,订单列表,订单详情,查询订单

@Slf4j
@RestController
@RequestMapping("/buyer/order")
public class BuyerOrderController {

    @Autowired
    private OrderService orderService;

    @Autowired
    private BuyerService buyerService;

    /**
     * 创建订单
     *
     * 注解验证:@Valid,对OrderForm中加了@NotEmpty注解的参数进行校验
     * BindingResult收集验证不通过的错误信息
     * BindingResult和@Valid配对使用,如果不加BindingResult会抛出异常信息,加了之后异常信息会放进bindingResult对象中
     * @param orderForm
     * @param bindingResult
     * @return
     */
    @PostMapping("/create")
    public ResultVO<Map<String,String>> create(@Valid OrderForm orderForm, BindingResult bindingResult){
        if(bindingResult.hasErrors()){
            log.error("【创建订单】参数不正确,orderForm={}",orderForm);
            throw new SellException(ResultEnum.PARAM_ERROR.getCode()
                    ,bindingResult.getFieldError().getDefaultMessage());
        }

        //因为创建订单传入的参数为OrderDTO,因此需要类型转换
        OrderDTO orderDTO = OrderForm2OrderDTO.convert(orderForm);
        if(CollectionUtils.isEmpty(orderDTO.getOrderDetailList())){
            log.error("【创建订单】购物车不能为空");
            throw new SellException(ResultEnum.CART_EMPTY);
        }
        
        OrderDTO createResult = orderService.create(orderDTO);

        //返回ResultVO<Map<String,String>>结果
        Map<String,String> map = new HashMap<>();
        map.put("orderId",createResult.getOrderId());
        return ResultVOUtil.success(map);
    }

    //订单列表
    @GetMapping("/list")
    public ResultVO<List<OrderDTO>> list(
    @RequestParam("openid")String openid,
    @RequestParam(value = "page",defaultValue = "0")Integer page,
    @RequestParam(value = "size",defaultValue = "10")Integer size){
        if(StringUtils.isEmpty(openid)){
            log.error("【查询订单列表】 openid为空");
            throw new SellException(ResultEnum.PARAM_ERROR);
        }
        PageRequest request = PageRequest.of(page,size);
        Page<OrderDTO> orderDTOPage = orderService.findList(openid, request);
        return ResultVOUtil.success(orderDTOPage.getContent());
    }

    //订单详情
    @GetMapping("/detail")
    public ResultVO<OrderDTO> detail(@RequestParam("openid")String openid,
    							 @RequestParam("orderId")String orderId){
        OrderDTO orderDTO = buyerService.findOrderOne(openid, orderId);
        return ResultVOUtil.success(orderDTO);
    }

    //取消订单
    @PostMapping("/cancle")
    public ResultVO cancle(@RequestParam("openid")String openid,
                           @RequestParam("orderId")String orderId){

        buyerService.cancleOrder(openid, orderId);
        return ResultVOUtil.success();
    }
}

1. 创建订单API的实现

1、创建订单的API:

下面是创建订单的API,我们要做的就是根据这个API来写Controller层的代码:
在这里插入图片描述2、方法返回值类型:

根据API返回的结果,可以将返回类型写成ResultVO<Map<String,String>>
在这里插入图片描述
3、方法的参数:

根据API的请求参数:name,phone,openid。。。但是不可能把这些参数都写进去,可以将这些封装在类OrderForm中,其中加上@Empty注解的是要校验的参数,验证注解的元素值不为null且不为空:

@Data
public class OrderForm {
    /**
     * 买家姓名
     */
    @NotEmpty(message = "姓名必填")
    private String name;

    /**
     * 买家手机号
     */
    @NotEmpty(message = "手机号必填")
    private String phone;

    /**
     * 买家地址
     */
    @NotEmpty(message = "地址必填")
    private String address;

    /**
     * 买家微信openid
     */
    @NotEmpty(message = "openid必填")
    private String openid;

    /**
     * 购物车
     */
    @NotEmpty(message = "购物车不能为空")
    private String items;
}

@Valid注解用于对OrderForm中加了@NotEmpty注解的参数进行校验,BindingResult收集验证不通过的错误信息,然后判断有没有错误:
在这里插入图片描述4、创建订单:

现在创键订单方法的参数和返回值类型都确定了,下一步就是调用Service层的逻辑实现创建订单的操作了:
在这里插入图片描述
Service层中create方法传入的参数是OrderDTO,但是这里Controller层create方法传入的参数为OrderForm,因此需要进行类型转换:

@Slf4j
public class OrderForm2OrderDTO {

    public static OrderDTO convert(OrderForm orderForm){
        OrderDTO orderDTO = new OrderDTO();
        orderDTO.setBuyerName(orderForm.getName());
        orderDTO.setBuyerPhone(orderForm.getPhone());
        orderDTO.setBuyerAddress(orderForm.getAddress());
        orderDTO.setBuyerOpenid(orderForm.getOpenid());

        //将前端中items属性的json格式转换为List集合
        Gson gson = new Gson();

        List<OrderDetail> orderDetailList = new ArrayList<>();
        try {
            orderDetailList = gson.fromJson(orderForm.getItems(),
                    new TypeToken<List<OrderDetail>>() {
                    }.getType());
        } catch (JsonSyntaxException e) {
            log.error("【对象转换】错误,string={}",orderForm.getItems());
            throw new SellException(ResultEnum.PARAM_ERROR);
        }

        orderDTO.setOrderDetailList(orderDetailList);
        return orderDTO;
    }
}

类型转换后最好判断下前端传来的参数中的购物车内是否有西,有东西就进行创建订单:
在这里插入图片描述
5、返回结果:
在这里插入图片描述
6、进行前后端联调验证Controller层的代码:

如果使用浏览器访问会报错405,因为发送的是post请求,而我们需要有请求体,但是前段代码已经封装了,因此需要时使用一个软件Postman:
在这里插入图片描述
在这里插入图片描述
说明:如果中间有错误,建议前后端联调一下,看一下哪里出了问题,在后端打上断点,然后前端发送请求,就会跳到后端代码上去的。

2. 订单列表API的实现

1、订单列表API:
在这里插入图片描述
2、方法返回值类型:

根据API返回结果可以判断方法的返回值类型为ResultVO<List<OrderDTO>>
在这里插入图片描述
3、方法的参数:

根据API可得方法的参数有三个:openid,page,size
这里@RequestParam注解可以不用使用,但是如果想指定默认值需要使用。
判断下前端传来的请求参数openid不为空,如果不为空我们才可以根据openid显示订单列表:
在这里插入图片描述
4、查询订单类列表:

现在方法的返回值类型和参数都已经确定了,下面要做的就是根据Service层的逻辑去向数据库中分页查询订单列表:
在这里插入图片描述
在这里插入图片描述
5、返回查询结果:

orderDTOPage中封装的是查询的订单列表:
在这里插入图片描述
6、前后端联调校验:
在这里插入图片描述

3. 订单详情API的实现

1、订单详情API:
在这里插入图片描述
2、方法返回值类型:

根据API可得方法的返回值类型为ResultVO<OrderDTO>
在这里插入图片描述
3、方法参数:

根据API可得方法的参数有两个:openid,orderId
至于@RequestParam可以使用,也可以不使用,这个注解的作用是当前端传来的参数和方法的参数不一致时,还用这个注解来标注前端传来的参数:
在这里插入图片描述
4、查询商品详情:

现在方法的返回值和方法的参数已经确定,下面就是调用Service层的逻辑来查询商品详情:
在这里插入图片描述
但是为了增强程序的安全,我们希望通过openid和orderId来查询某个订单详情,而不是只通过orderId来查询,否则只要活得orderId就能查到任何一个人的订单了,因此写一个接口Buyer接口来验证买家openid和orderId,(也可以写在Controller层,但是希望业务逻辑都写在Service层):

public interface BuyerService {
    //查询一个订单
    OrderDTO findOrderOne(String openid,String orderId);
}

BuyerService的实现类:

@Service
@Slf4j
public class BuyerServiceImpl implements BuyerService {
    @Autowired
    private OrderService orderService;

    public OrderDTO checkOrderOwner(String openid,String orderId){
        OrderDTO orderDTO = orderService.findOnes(orderId);
        if(orderDTO.getOrderId()==null){
            return null;
        }
        //判断是否为自己的订单
        if(!orderDTO.getBuyerOpenid().equalsIgnoreCase(openid)){
            log.error("【查询订单】订单的openid不一致,openid={}",openid);
            throw new SellException(ResultEnum.ORDER_OWNER_ERROR);
        }
        return orderDTO;
    }

    @Override
    public OrderDTO findOrderOne(String openid, String orderId) {
        return checkOrderOwner(openid,orderId);
    }
}

下面调用BuyerService的方法实现查询订单,并返回结果:
在这里插入图片描述
5、前后端联调:

在这里插入图片描述

4. 取消订单API的实现

1、取消订单API:

在这里插入图片描述
2、取消订单:

先来看下Service层的业务逻辑:
在这里插入图片描述
同样为了增强程序的安全性,在BuyerService接口中加一个取消订单的方法:

public interface BuyerService {
    //取消订单
    OrderDTO cancleOrder(String openid,String orderId);
}
@Service
@Slf4j
public class BuyerServiceImpl implements BuyerService {

    @Autowired
    private OrderService orderService;

    public OrderDTO checkOrderOwner(String openid,String orderId){
        OrderDTO orderDTO = orderService.findOnes(orderId);
        if(orderDTO.getOrderId()==null){
            return null;
        }
        //判断是否为自己的订单
        if(!orderDTO.getBuyerOpenid().equalsIgnoreCase(openid)){
            log.error("【查询订单】订单的openid不一致,openid={}",openid);
            throw new SellException(ResultEnum.ORDER_OWNER_ERROR);
        }
        return orderDTO;
    }

    @Override
    public OrderDTO cancleOrder(String openid, String orderId) {
        OrderDTO orderDTO = checkOrderOwner(openid, orderId);
        if(orderDTO==null){
            log.error("【取消订单】查不到该订单,orderId={}",orderId);
            throw new SellException(ResultEnum.ORDER_NOT_EXIST);
        }
        return orderService.cancel(orderDTO);
    }
}

调用BuyerService接口中的方法取消订单:
在这里插入图片描述
其次,数据为null的对象我们不想显示,比如data,可以在application.proertites中加上:

#对象为null的字段不显示在页面
spring.jackson.default-property-inclusion=non_null

3、前后端联调:

此时数据库中的订单状态为0:
在这里插入图片描述
在这里插入图片描述
订单取消成功后,数据库中的订单状态为2:
在这里插入图片描述

发布了665 篇原创文章 · 获赞 115 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/qq_42764468/article/details/104777356
今日推荐