package com.artisan.order.repository; import com.artisan.order.ArtisanOrderApplicationTests; import com.artisan.order.domain.OrderDetail; import org.junit.Assert; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.math.BigDecimal; @Component public class OrderDetailRepositoryTest extends ArtisanOrderApplicationTests { @Autowired private OrderDetailRepository orderDetailRepository; @Test public void testSave() { OrderDetail orderDetail = new OrderDetail(); orderDetail.setDetailId("1111"); orderDetail.setOrderId("111111"); orderDetail.setProductIcon("http://xxx.com"); orderDetail.setProductId("22222"); orderDetail.setProductName("拿铁"); orderDetail.setProductPrice(new BigDecimal(0.01)); orderDetail.setProductQuantity(2); OrderDetail result = orderDetailRepository.save(orderDetail); Assert.assertTrue(result != null); } }
单元测试 通过。
Service层
分析下,我们要往artisan_order 和 order_detail中写入数据,肯定要传入Order和OrderDetail实体类,类似于 createOrder(Order order , OrderDetail orderDetail) ,根据业务规则,一个Order中可能有多个OrderDetail, 所以入参OrderDetail 必须是个集合,并且返回结果也不好定义。 因此我们将这俩合并一下,封装成DTO来使用,作为入参和返回结果。
Order 和OrderDetail 合并为一个DTO对象
下图中类上少儿个注解 @Data,注意补上
OrderService接口和实现类
package com.artisan.order.service; import com.artisan.order.dto.OrderDTO; public interface OrderService { OrderDTO createOrder(OrderDTO orderDTO); }
我们来分析下前端的请求
"name": "xxx", "phone": "xxxx", "address": "xxxx", "openid": "xxxx", //用户的微信openid "items": [ { "productId": "xxxxxx", "productQuantity": 2 //购买数量 } ]
结合业务逻辑
- 校验前台入参
- 查询商品信息(调用商品微服务)
- 计算订单总价
- 扣减库存(调用商品微服务)
- 订单入库
逐一分析下目前的可行性
- 参数校验,我们放在Controller层校验,所以Service层这里不写
- 调用微服务的,我们目前还不具备,没法做
- 计算订单总价,前台入参仅仅传了ProductId, 而Product的数据需要调用商品微服务,目前没法做
- 订单入库,其实分两部分,第一个是artisan_order表,第二个是Order_detail表。 order_detail表包含了Product的内容,目前也是做不了。
综合分析,目前在Service层能做的仅仅是 入库artisan_order表
那在实现类里,我们先实现部分吧
package com.artisan.order.service.impl; import com.artisan.order.domain.Order; import com.artisan.order.dto.OrderDTO; import com.artisan.order.enums.OrderStatusEnum; import com.artisan.order.enums.PayStatusEnum; import com.artisan.order.repository.OrderDetailRepository; import com.artisan.order.repository.OrderRepository; import com.artisan.order.service.OrderService; import com.artisan.order.utils.KeyUtil; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.math.BigDecimal; @Service public class OrderServiceImpl implements OrderService { @Autowired OrderRepository orderRepository; @Autowired OrderDetailRepository orderDetailRepository; @Override public OrderDTO createOrder(OrderDTO orderDTO) { // TODO 查询商品信息(调用商品微服务) // TODO 计算订单总价 // TODO 扣减库存(调用商品微服务) //订单入库 Order order = new Order(); orderDTO.setOrderId(KeyUtil.genUniqueKey()); // 复制属性 BeanUtils.copyProperties(orderDTO, order); // 设置其他属性 order.setOrderAmount(new BigDecimal("100")); // TODO 后需要修改 order.setOrderStatus(OrderStatusEnum.NEW.getCode()); order.setPayStatus(PayStatusEnum.WAIT.getCode()); orderRepository.save(order); return orderDTO; } }
Controller层
这里仅列出关键代码,其余请参考github
package com.artisan.order.form; import lombok.Data; import org.hibernate.validator.constraints.NotEmpty; import java.util.List; @Data public class OrderForm { /** * 对应 * * { * "name": "xxx", * "phone": "xxxx", * "address": "xxxx", * "openid": "xxxx", //用户的微信openid * "items": [ * { * "productId": "xxxxxx", * "productQuantity": 2 //购买数量 * } * ] * } * * * */ /** * 买家姓名 */ @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; }
package com.artisan.order.converter; import com.artisan.order.domain.OrderDetail; import com.artisan.order.dto.OrderDTO; import com.artisan.order.enums.ResultEnum; import com.artisan.order.exception.OrderException; import com.artisan.order.form.OrderForm; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; import java.util.List; @Slf4j public class OrderForm2OrderDTOConverter { public static OrderDTO convert(OrderForm orderForm) { Gson gson = new Gson(); OrderDTO orderDTO = new OrderDTO(); orderDTO.setBuyerName(orderForm.getName()); orderDTO.setBuyerPhone(orderForm.getPhone()); orderDTO.setBuyerAddress(orderForm.getAddress()); orderDTO.setBuyerOpenid(orderForm.getOpenid()); List<OrderDetail> orderDetailList = new ArrayList<>(); try { // fromJson 从Json相关对象到Java实体的方法 ,转换成列表类型 orderDetailList = gson.fromJson(orderForm.getItems(), new TypeToken<List<OrderDetail>>() { }.getType()); }catch(Exception e){ log.error("【json转换】错误, string={}", orderForm.getItems()); throw new OrderException(ResultEnum.PARAM_ERROR); } orderDTO.setOrderDetailList(orderDetailList); return orderDTO; } }
package com.artisan.order.controller; import com.artisan.order.converter.OrderForm2OrderDTOConverter; import com.artisan.order.dto.OrderDTO; import com.artisan.order.enums.ResultEnum; import com.artisan.order.exception.OrderException; import com.artisan.order.form.OrderForm; import com.artisan.order.service.OrderService; import com.artisan.order.vo.Result; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; import java.util.HashMap; import java.util.Map; @RestController @RequestMapping("/order") @Slf4j public class OrderController { @Autowired OrderService orderService; @PostMapping("/create") public Result create(@Valid OrderForm orderForm, BindingResult bindingResult) { if (bindingResult.hasErrors()){ log.error("【Create Order】参数不正确, orderForm={}", orderForm); throw new OrderException(ResultEnum.PARAM_ERROR.getCode(), bindingResult.getFieldError().getDefaultMessage()); } // orderForm -> orderDTO OrderDTO orderDTO = OrderForm2OrderDTOConverter.convert(orderForm); if (CollectionUtils.isEmpty(orderDTO.getOrderDetailList())) { log.error("【Create Order】购物车信息为空"); throw new OrderException(ResultEnum.CART_EMPTY); } OrderDTO result = orderService.createOrder(orderDTO); Map<String, String> map = new HashMap<>(); map.put("orderId", result.getOrderId()); return Result.success(map); } }
测试
使用PostMan
查看数据库
OK
说明下: x-www-form-urlencoded 这种格式 就是application/x-www-from-urlencoded,会将表单内的数据转换为键值对,比如:name=artisan&phone=123
知识点总结
Gson库
谷歌提供的 JSON – Java Object 相互转换的 Java序列化/反序列化库。
将Json转换为对象
解析json数组
orderDetailList = gson.fromJson(orderForm.getItems(), new TypeToken<List<OrderDetail>>() { }.getType());
将Java对象转换为Json
Github
https://github.com/yangshangwei/springcloud-o2o/tree/master/artisan-product