1.Springboot的接收表單驗證操做
前端
2.json類型字符串經過Gson轉換爲對象java
3.對輸出到前端的屬性作轉換,JsonSerializemysql
4.使返回到前端的參數不能爲null的多種解決方法spring
章節問答sql
1.API分析數據庫
建立訂單 POST /sell/buyer/order/create 參數 name: "張三" phone: "18868822111" address: "慕課網總部" openid: "ew3euwhd7sjw9diwkq" //用戶的微信openid items: [{ productId: "1423113435324", productQuantity: 2 //購買數量 }] 返回 { "code": 0, "msg": "成功", "data": { "orderId": "147283992738221" } } 訂單列表 GET /sell/buyer/order/list 參數 openid: 18eu2jwk2kse3r42e2e page: 0 //從第0頁開始 size: 10 返回 { "code": 0, "msg": "成功", "data": [ { "orderId": "161873371171128075", "buyerName": "張三", "buyerPhone": "18868877111", "buyerAddress": "慕課網總部", "buyerOpenid": "18eu2jwk2kse3r42e2e", "orderAmount": 0, "orderStatus": 0, "payStatus": 0, "createTime": 1490171219, "updateTime": 1490171219, "orderDetailList": null }, { "orderId": "161873371171128076", "buyerName": "張三", "buyerPhone": "18868877111", "buyerAddress": "慕課網總部", "buyerOpenid": "18eu2jwk2kse3r42e2e", "orderAmount": 0, "orderStatus": 0, "payStatus": 0, "createTime": 1490171219, "updateTime": 1490171219, "orderDetailList": null }] } 查詢訂單詳情 GET /sell/buyer/order/detail 參數 openid: 18eu2jwk2kse3r42e2e orderId: 161899085773669363 返回 { "code": 0, "msg": "成功", "data": { "orderId": "161899085773669363", "buyerName": "李四", "buyerPhone": "18868877111", "buyerAddress": "慕課網總部", "buyerOpenid": "18eu2jwk2kse3r42e2e", "orderAmount": 18, "orderStatus": 0, "payStatus": 0, "createTime": 1490177352, "updateTime": 1490177352, "orderDetailList": [ { "detailId": "161899085974995851", "orderId": "161899085773669363", "productId": "157875196362360019", "productName": "招牌奶茶", "productPrice": 9, "productQuantity": 2, "productIcon": "http://xxx.com", "productImage": "http://xxx.com" } ] } } 取消訂單 POST /sell/buyer/order/cancel 參數 openid: 18eu2jwk2kse3r42e2e orderId: 161899085773669363 返回 { "code": 0, "msg": "成功", "data": null } 獲取openid 重定向到 /sell/wechat/authorize 參數 returnUrl: http://xxx.com/abc //【必填】 返回 http://xxx.com/abc?openid=oZxSYw5ldcxv6H0EU67GgSXOUrVg
2.建立BuyerOrderController類,寫上上面四個API方法,別忘記三個標籤@RestController@RequestMapping("/buyer/order")@Slf4j,在方法上面能夠寫json
package com.xiong.sell.service.impl; import com.xiong.sell.converter.OrderMaster2OrderDTOConverter; import com.xiong.sell.dataobject.OrderDetail; import com.xiong.sell.dataobject.OrderMaster; import com.xiong.sell.dataobject.ProductInfo; import com.xiong.sell.dto.CartDTO; import com.xiong.sell.dto.OrderDTO; import com.xiong.sell.enums.OrderStatusEnum; import com.xiong.sell.enums.ProductStatusEnum; import com.xiong.sell.enums.ResultEnum; import com.xiong.sell.exception.SellException; import com.xiong.sell.repository.OrderDetailRepository; import com.xiong.sell.repository.OrderMasterRepository; import com.xiong.sell.service.OrderService; import com.xiong.sell.service.ProductInfoService; import com.xiong.sell.utils.KeyUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import javax.transaction.Transactional; import java.math.BigDecimal; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; /** * @author Xiong YuSong * 2019/1/18 13:36 */ @Service @Slf4j public class OrderServiceImpl implements OrderService { @Autowired private ProductInfoService productInfoService; @Autowired private OrderDetailRepository orderDetailRepository; @Autowired private OrderMasterRepository orderMasterRepository; @Override @Transactional(rollbackOn = Exception.class) public OrderDTO create(OrderDTO orderDTO) { BigDecimal orderAmount = new BigDecimal(0); //生成orderID String orderId = KeyUtil.genUniqueKey(); //1.查詢商品(這裏只有商品編號和數量) for (OrderDetail orderDetail : orderDTO.getOrderDetailList()) { //根據Id查到商品以後 ProductInfo productInfo = productInfoService.findOne(orderDetail.getProductId()); if (productInfo == null) { throw new SellException(ResultEnum.PRODUCT_NOT_EXIST); } //2.計算訂單總價 orderAmount = productInfo.getProductPrice() .multiply(new BigDecimal(orderDetail.getProductQuantity())) .add(orderAmount); //將訂單詳情放入數據庫中,這裏注意orderDetail裏面的數據,時候是完整的,正確的 BeanUtils.copyProperties(productInfo, orderDetail); orderDetail.setDetailId(KeyUtil.genUniqueKey()); orderDetail.setOrderId(orderId); orderDetailRepository.save(orderDetail); } //3.寫入訂單數據庫 OrderMaster orderMaster = new OrderMaster(); orderDTO.setOrderId(orderId); orderDTO.setOrderAmount(orderAmount); BeanUtils.copyProperties(orderDTO, orderMaster); orderMaster.setOrderStatus(OrderStatusEnum.NEW.getCode()); orderMaster.setPayStatus(ProductStatusEnum.PayStatusEnum.WAIT.getCode()); orderMasterRepository.save(orderMaster); //4.扣庫存 List<CartDTO> cartDTOList = orderDTO.getOrderDetailList().stream().map(e -> new CartDTO(e.getProductId(), e.getProductQuantity())).collect(Collectors.toList()); productInfoService.decreaseStock(cartDTOList); return orderDTO; } @Override public OrderDTO findOne(String orderId) { Optional<OrderMaster> optional = orderMasterRepository.findById(orderId); if (!optional.isPresent()) { throw new SellException(ResultEnum.ORDER_NOT_EXIST); } OrderMaster orderMaster = optional.get(); List<OrderDetail> orderDetailList = orderDetailRepository.findByOrderId(orderId); if (CollectionUtils.isEmpty(orderDetailList)) { throw new SellException(ResultEnum.ORDERDETAIL_NOT_EXIST); } OrderDTO orderDTO = new OrderDTO(); BeanUtils.copyProperties(orderMaster, orderDTO); orderDTO.setOrderDetailList(orderDetailList); return orderDTO; } @Override public Page<OrderDTO> findList(String buyerOpenid, Pageable pageable) { Page<OrderMaster> orderMasterPage = orderMasterRepository.findByBuyerOpenid(buyerOpenid, pageable); List<OrderDTO> orderDTOList = OrderMaster2OrderDTOConverter.convert(orderMasterPage.getContent()); //PageImpl,泛型OrderDTO,須要參數爲列表,pageable,以及總數 return new PageImpl<OrderDTO>(orderDTOList, pageable, orderMasterPage.getTotalElements()); } @Override @Transactional(rollbackOn = Exception.class) public OrderDTO cancel(OrderDTO orderDTO) { OrderMaster orderMaster = new OrderMaster(); //判斷訂單狀態 if (!orderDTO.getOrderStatus().equals(OrderStatusEnum.NEW.getCode())) { log.error("【取消訂單】訂單狀態不正確, orderId={}, orderStatus={}", orderDTO.getOrderId(), orderDTO.getOrderStatus()); throw new SellException(ResultEnum.ORDER_STATUS_ERROR); } //修改訂單狀態 orderDTO.setOrderStatus(OrderStatusEnum.CANCEL.getCode()); BeanUtils.copyProperties(orderDTO, orderMaster); OrderMaster updateResult = orderMasterRepository.save(orderMaster); if (updateResult == null) { log.error("【取消訂單】更新失敗, orderMaster={}", orderMaster); throw new SellException(ResultEnum.ORDER_UPDATE_FAIL); } //返回庫存 if (CollectionUtils.isEmpty(orderDTO.getOrderDetailList())) { log.error("【取消訂單】訂單中無商品詳情, orderDTO={}", orderDTO); throw new SellException(ResultEnum.ORDER_DETAIL_EMPTY); } List<CartDTO> cartDTOList = orderDTO.getOrderDetailList().stream() .map(e -> new CartDTO(e.getProductId(), e.getProductQuantity())) .collect(Collectors.toList()); productInfoService.increaseStock(cartDTOList); //若是已支付, 須要退款 if (orderDTO.getPayStatus().equals(ProductStatusEnum.PayStatusEnum.SUCCESS.getCode())) { //TODO } return orderDTO; } @Override @Transactional(rollbackOn = Exception.class) public OrderDTO finish(OrderDTO orderDTO) { //判斷訂單狀態 if (!orderDTO.getOrderStatus().equals(OrderStatusEnum.NEW.getCode())) { log.error("【完結訂單】訂單狀態不正確, orderId={}, orderStatus={}", orderDTO.getOrderId(), orderDTO.getOrderStatus()); throw new SellException(ResultEnum.ORDER_STATUS_ERROR); } //修改訂單狀態 orderDTO.setOrderStatus(OrderStatusEnum.FINISHED.getCode()); OrderMaster orderMaster = new OrderMaster(); BeanUtils.copyProperties(orderDTO, orderMaster); OrderMaster updateResult = orderMasterRepository.save(orderMaster); if (updateResult == null) { log.error("【完結訂單】更新失敗, orderMaster={}", orderMaster); throw new SellException(ResultEnum.ORDER_UPDATE_FAIL); } return orderDTO; } @Override @Transactional(rollbackOn = Exception.class) public OrderDTO paid(OrderDTO orderDTO) { //判斷訂單狀態 if (!orderDTO.getOrderStatus().equals(OrderStatusEnum.NEW.getCode())) { log.error("【訂單支付完成】訂單狀態不正確, orderId={}, orderStatus={}", orderDTO.getOrderId(), orderDTO.getOrderStatus()); throw new SellException(ResultEnum.ORDER_STATUS_ERROR); } //判斷支付狀態 if (!orderDTO.getPayStatus().equals(ProductStatusEnum.PayStatusEnum.WAIT.getCode())) { log.error("【訂單支付完成】訂單支付狀態不正確, orderDTO={}", orderDTO); throw new SellException(ResultEnum.ORDER_PAY_STATUS_ERROR); } //修改支付狀態 orderDTO.setPayStatus(ProductStatusEnum.PayStatusEnum.SUCCESS.getCode()); OrderMaster orderMaster = new OrderMaster(); BeanUtils.copyProperties(orderDTO, orderMaster); OrderMaster updateResult = orderMasterRepository.save(orderMaster); if (updateResult == null) { log.error("【訂單支付完成】更新失敗, orderMaster={}", orderMaster); throw new SellException(ResultEnum.ORDER_UPDATE_FAIL); } return orderDTO; } }
3.前臺傳過來的是一個post是表單數據,因而咱們能夠建立一個OrderForm類放在form包下進行表單驗證,@NotEmpty(message = "姓名必填")微信
package com.xiong.sell.form; import lombok.Data; import javax.validation.constraints.NotEmpty; /** * @author Xiong YuSong * 2019/1/18 19:19 */ @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; }
4.這裏涉及到了OrderForm到OrderDTO的轉換,因此再創建一個轉換類OrderForm2OrderDTOConverterapp
package com.xiong.sell.converter; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.xiong.sell.dataobject.OrderDetail; import com.xiong.sell.dto.OrderDTO; import com.xiong.sell.enums.ResultEnum; import com.xiong.sell.exception.SellException; import com.xiong.sell.form.OrderForm; import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; import java.util.List; /** * @author Xiong YuSong * 2019/1/18 19:52 */ @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 { orderDetailList = gson.fromJson(orderForm.getItems(), new TypeToken<List<OrderDetail>>() { }.getType()); } catch (Exception e) { log.error("【對象轉換】錯誤, string={}", orderForm.getItems()); throw new SellException(ResultEnum.PARAM_ERROR); } orderDTO.setOrderDetailList(orderDetailList); } }
5.這裏使用到了Json轉類的方法,因此引入Gson,來完成dom
<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> </dependency>
6.進行Date和Long的轉換,新建一個序列化類serializer
package com.xiong.sell.utils.serializer; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; import java.util.Date; /** * @author Xiong YuSong * 2019/1/18 20:38 */ public class Date2LongSerializer extends JsonSerializer<Date> { @Override public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeNumber(value.getTime()/1000); } }
而後再須要轉換的屬行上@JsonSerialize(using = Date2LongSerializer.class)便可
/** * 建立時間. */ @JsonSerialize(using = Date2LongSerializer.class) private Date createTime; /** * 更新時間. */ @JsonSerialize(using = Date2LongSerializer.class) private Date updateTime;
7.此時咱們讓返回的參數不能爲空,這個時候咱們有兩個方法
1)參數設置一個默認值
2)在類的前面加上標籤
@Data @JsonInclude(JsonInclude.Include.NON_NULL) public class OrderDTO { }
或者設置在application.yml中設置
spring: datasource: driver-class-name: com.mysql.jdbc.Driver username: root password: 123456 url: jdbc:mysql://192.168.1.103/sell?characterEncoding=utf-8&useSSl=false jpa: show-sql: true jackson: default-property-inclusion: non_null server: servlet: context-path: /sell
8.在進行查看訂單詳情和取消訂單的時候須要驗證訂單的主人的微信openid是否是傳進來的openid,因此這裏須要建立一個新的BuyerServer來進行身份驗證
package com.xiong.sell.service; import com.xiong.sell.dto.OrderDTO; /** * @author Xiong YuSong * 2019/1/18 20:59 */ public interface BuyerService { /** * 查詢一個訂單 * @param openid * @param orderId * @return */ OrderDTO findOrderOne(String openid, String orderId); /** * 取消一個訂單 * @param openid * @param orderId * @return */ OrderDTO cancelOrder(String openid, String orderId); }