Browse Source

订单接口,用户绑卡,用户设置用户名密码接口

weifanli 2 years ago
parent
commit
73eb1a7506
21 changed files with 763 additions and 141 deletions
  1. 33 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/web/controller/UserController.java
  2. 10 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/req/OrderReq.java
  3. 81 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/OrderSearch.java
  4. 32 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/UserBankCard.java
  5. 25 2
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/UserOrderDetail.java
  6. 11 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/UserOrderPayment.java
  7. 9 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/UserBankCardService.java
  8. 8 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserBankCardServiceImpl.java
  9. 37 12
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserOrderServiceImpl.java
  10. 0 2
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/VipCardServiceImpl.java
  11. 45 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/UserOrderVo.java
  12. 13 28
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/res/OrderCreateRes.java
  13. 2 2
      cooleshow-user/user-biz/src/main/resources/config/mybatis/TeacherStyleVideoMapper.xml
  14. 56 4
      cooleshow-user/user-biz/src/main/resources/config/mybatis/UserOrderMapper.xml
  15. 2 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/UserOrderPaymentMapper.xml
  16. 36 0
      cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/UserBankCardController.java
  17. 1 1
      cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/UserWithdrawalController.java
  18. 95 88
      toolset/utils/pom.xml
  19. 103 0
      toolset/utils/src/main/java/com/yonge/toolset/utils/easyexcel/ExcelDataReader.java
  20. 31 0
      toolset/utils/src/main/java/com/yonge/toolset/utils/easyexcel/ExcelDataReaderProperty.java
  21. 133 0
      toolset/utils/src/main/java/com/yonge/toolset/utils/easyexcel/ExcelUtils.java

+ 33 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/web/controller/UserController.java

@@ -155,6 +155,39 @@ public class UserController extends BaseController {
         return succeed();
     }
 
+    @ApiOperation(value = "设置用户名密码")
+    @PostMapping(value = "/setUsernameAndPassword", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
+    @ApiImplicitParams({@ApiImplicitParam(name = "password", value = "密码", required = true, dataType = "String"),
+            @ApiImplicitParam(name = "username", value = "用户名", required = true, dataType = "String")})
+    public Object setPassword(String password, String username) {
+        if (StringUtils.isEmpty(password)) {
+            return failed("参数校验失败");
+        }
+        AuthUser authUser = SecurityUtils.getUser();
+        if (authUser == null) {
+            return failed("获取用户信息失败");
+        }
+        SysUser sysUser = sysUserService.get(authUser.getUserId());
+        if (sysUser == null) {
+            return failed("用户不存在");
+        }
+        if (sysUser.getUserType().contains("SYSTEM")) {
+            sysUser.setRealName(username);
+        }
+        sysUser.setUsername(username);
+		/*if(StringUtils.isEmpty(sysUser.getImToken())){
+			ImResult register = imFeignService.register(new ImUserModel(sysUser.getId().toString(), username, sysUser.getAvatar()));
+			sysUser.setImToken(register.getToken());
+		}else {
+			imFeignService.update(new ImUserModel(sysUser.getId().toString(),username,sysUser.getAvatar()));
+		}*/
+        password = new BCryptPasswordEncoder().encode(password);
+        sysUser.setPassword(password);
+        sysUser.setUpdateTime(new Date());
+        sysUserService.update(sysUser);
+        return succeed();
+    }
+
     @ApiOperation(value = "手机验证码修改密码")
     @PostMapping(value = "/updatePassword", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
     @ApiImplicitParams({@ApiImplicitParam(name = "mobile", value = "手机号", required = true, dataType = "String"),

+ 10 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/req/OrderReq.java

@@ -30,6 +30,8 @@ public class OrderReq {
     private String userNote;
     @ApiModelProperty(value = "业务内容 订单业务内容json")
     private String bizContent;
+    @ApiModelProperty(value = "优惠券id")
+    private Long couponId;
 
     public Long getUserId() {
         return userId;
@@ -78,4 +80,12 @@ public class OrderReq {
     public void setUserNote(String userNote) {
         this.userNote = userNote;
     }
+
+    public Long getCouponId() {
+        return couponId;
+    }
+
+    public void setCouponId(Long couponId) {
+        this.couponId = couponId;
+    }
 }

+ 81 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/OrderSearch.java

@@ -1,7 +1,14 @@
 package com.yonge.cooleshow.biz.dal.dto.search;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.yonge.cooleshow.biz.dal.enums.OrderStatusEnum;
+import com.yonge.cooleshow.biz.dal.enums.OrderTypeEnum;
 import com.yonge.cooleshow.common.page.QueryInfo;
 import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
 
 /**
  * @Author: liweifan
@@ -11,4 +18,78 @@ import io.swagger.annotations.ApiModel;
 public class OrderSearch extends QueryInfo{
 	private static final long serialVersionUID = 1L;
 
+	@ApiModelProperty("交易流水号/订单号")
+	private String searchNo;
+	@ApiModelProperty("订单类型:  VIP、开通会员  PRACTICE、陪练课购买  LIVE、直播课购买 VIDEO、视频课购买 MUSIC、单曲点播")
+	private OrderTypeEnum orderType;
+	@ApiModelProperty("订单状态 WAIT_PAY 待支付 PAYING 支付中  PAID 已付款 CLOSE 已关闭 ")
+	private OrderStatusEnum status;
+	@ApiModelProperty(value = "交易开始时间")
+	@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+	private Date startTime;
+	@ApiModelProperty(value = "交易结束时间")
+	@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+	private Date endTime;
+	@ApiModelProperty("买家id")
+	private Long userId;
+	@ApiModelProperty("卖家id")
+	private Long merchId;
+
+	public String getSearchNo() {
+		return searchNo;
+	}
+
+	public void setSearchNo(String searchNo) {
+		this.searchNo = searchNo;
+	}
+
+	public OrderTypeEnum getOrderType() {
+		return orderType;
+	}
+
+	public void setOrderType(OrderTypeEnum orderType) {
+		this.orderType = orderType;
+	}
+
+	public OrderStatusEnum getStatus() {
+		return status;
+	}
+
+	public void setStatus(OrderStatusEnum status) {
+		this.status = status;
+	}
+
+	public Date getStartTime() {
+		return startTime;
+	}
+
+	public void setStartTime(Date startTime) {
+		this.startTime = startTime;
+	}
+
+	public Date getEndTime() {
+		return endTime;
+	}
+
+	public void setEndTime(Date endTime) {
+		this.endTime = endTime;
+	}
+
+	public Long getUserId() {
+		return userId;
+	}
+
+	public void setUserId(Long userId) {
+		this.userId = userId;
+	}
+
+	public Long getMerchId() {
+		return merchId;
+	}
+
+	public void setMerchId(Long merchId) {
+		this.merchId = merchId;
+	}
 }

+ 32 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/UserBankCard.java

@@ -9,6 +9,8 @@ import java.util.Date;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import org.springframework.format.annotation.DateTimeFormat;
 
+import javax.validation.constraints.NotBlank;
+
 /**
  * 用户绑卡记录表
  */
@@ -24,18 +26,22 @@ public class UserBankCard implements Serializable {
     private Long userId;
     @ApiModelProperty("持卡人姓名 ")
 	@TableField(value = "name_")
+    @NotBlank(message = "持卡人姓名不能为空")
     private String name;
     @ApiModelProperty("开户行 ")
 	@TableField(value = "bank_name_")
     private String bankName;
     @ApiModelProperty("银行卡号 ")
 	@TableField(value = "bank_card_")
+    @NotBlank(message = "银行卡号不能为空")
     private String bankCard;
     @ApiModelProperty("银行预留手机号 ")
 	@TableField(value = "phone_")
+    @NotBlank(message = "银行预留手机号不能为空")
     private String phone;
     @ApiModelProperty("开户行编码 ")
 	@TableField(value = "bank_code_")
+    @NotBlank(message = "开户行不能为空")
     private String bankCode;
     @ApiModelProperty("是否默认 ")
 	@TableField(value = "is_default_")
@@ -141,5 +147,31 @@ public class UserBankCard implements Serializable {
     public void setUpdateTime(Date updateTime) {
         this.updateTime = updateTime;
     }
+/**
+ 工商银行   ICBC
+ 建设银行   CCB
+ 邮政储蓄银行   PSBC
+ 中国银行   BOC
+ 农业银行   ABC
+ 通银行   BC
+ 招商银行   CMB
+汇丰银行   HSBC
+交
+中国民生银行   CMB
+上海浦东发展银行   SPDB
+中信银行   无英文简写
+中国光大银行   CEB
+华夏银行   HB
+广东发展银行   GDB
+深圳发展银行   SDB
+兴业银行   CIB
+国家开发银行   CDB
+中国进出口银行   EIBC
+中国农业发展银行   ADBC
+北京银行   BOB
+中国人民银行   PBC
+
+ */
+
     
 }

+ 25 - 2
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/UserOrderDetail.java

@@ -8,6 +8,7 @@ import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
 import java.io.Serializable;
+import java.math.BigDecimal;
 import java.util.Date;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import org.springframework.format.annotation.DateTimeFormat;
@@ -30,6 +31,12 @@ public class UserOrderDetail implements Serializable {
     @ApiModelProperty("业务内容 ")
 	@TableField(value = "biz_content_")
     private String bizContent;
+    @ApiModelProperty("商品数量 ")
+    @TableField(value = "good_num_")
+    private Integer goodNum;
+    @ApiModelProperty("商品单价 ")
+    @TableField(value = "good_price_")
+    private BigDecimal goodPrice;
     @ApiModelProperty("下单时间 ")
 	@TableField(value = "create_time_")
     @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@@ -71,8 +78,24 @@ public class UserOrderDetail implements Serializable {
     public void setBizContent(String bizContent) {
         this.bizContent = bizContent;
     }
-    
-	public Date getCreateTime() {
+
+    public Integer getGoodNum() {
+        return goodNum;
+    }
+
+    public void setGoodNum(Integer goodNum) {
+        this.goodNum = goodNum;
+    }
+
+    public BigDecimal getGoodPrice() {
+        return goodPrice;
+    }
+
+    public void setGoodPrice(BigDecimal goodPrice) {
+        this.goodPrice = goodPrice;
+    }
+
+    public Date getCreateTime() {
         return createTime;
     }
 

+ 11 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/UserOrderPayment.java

@@ -36,6 +36,9 @@ public class UserOrderPayment implements Serializable {
     @ApiModelProperty("交易金额,必须大于0,保留两位小数点,如0.10、100.05等 ")
 	@TableField(value = "pay_amt_")
     private BigDecimal payAmt;
+    @ApiModelProperty("汇付收取的服务费 ")
+    @TableField(value = "fee_amt_")
+    private BigDecimal feeAmt;
     @ApiModelProperty("支付详情信息(用于拉起支付) ")
 	@TableField(value = "pay_info_")
     private String payInfo;
@@ -138,4 +141,12 @@ public class UserOrderPayment implements Serializable {
     public void setUpdateTime(Date updateTime) {
         this.updateTime = updateTime;
     }
+
+    public BigDecimal getFeeAmt() {
+        return feeAmt;
+    }
+
+    public void setFeeAmt(BigDecimal feeAmt) {
+        this.feeAmt = feeAmt;
+    }
 }

+ 9 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/UserBankCardService.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.yonge.cooleshow.biz.dal.vo.UserBankCardVo;
 import com.yonge.cooleshow.biz.dal.dto.search.UserBankCardSearch;
 import com.yonge.cooleshow.biz.dal.entity.UserBankCard;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
 
 /**
  * 用户绑卡记录表 服务类
@@ -26,4 +27,12 @@ public interface UserBankCardService extends IService<UserBankCard>  {
  	 * @date 2022-03-30
      */
     IPage<UserBankCardVo> selectPage(IPage<UserBankCardVo> page, UserBankCardSearch query);
+	/***
+	 * 用户绑卡
+	 * @author liweifan
+	 * @param: bankCard
+	 * @updateTime 2022/4/14 15:53
+	 * @return: com.yonge.cooleshow.common.entity.HttpResponseResult<com.yonge.cooleshow.biz.dal.entity.UserBankCard>
+	 */
+    HttpResponseResult<UserBankCard> bankCard(UserBankCard bankCard);
 }

+ 8 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserBankCardServiceImpl.java

@@ -2,6 +2,7 @@ package com.yonge.cooleshow.biz.dal.service.impl;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import org.springframework.stereotype.Service;
 import com.yonge.cooleshow.biz.dal.entity.UserBankCard;
 import com.yonge.cooleshow.biz.dal.vo.UserBankCardVo;
@@ -23,5 +24,11 @@ public class UserBankCardServiceImpl extends ServiceImpl<UserBankCardDao, UserBa
     public IPage<UserBankCardVo> selectPage(IPage<UserBankCardVo> page, UserBankCardSearch query){
         return page.setRecords(baseMapper.selectPage(page, query));
     }
-	
+
+    @Override
+    public HttpResponseResult<UserBankCard> bankCard(UserBankCard bankCard) {
+	    //todo 用户绑卡
+        return HttpResponseResult.succeed(bankCard);
+    }
+
 }

+ 37 - 12
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserOrderServiceImpl.java

@@ -88,7 +88,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
     @Override
     public UserOrderVo detail(Long id) {
         UserOrderVo userOrderVo = baseMapper.detailById(id);
-        if(null != userOrderVo){
+        if (null != userOrderVo) {
             userOrderVo.setOrderDetail(orderDetailService.detail(userOrderVo.getOrderNo()));
         }
         return userOrderVo;
@@ -97,7 +97,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
     @Override
     public UserOrderVo detail(String orderNo) {
         UserOrderVo userOrderVo = baseMapper.detailByOrderNo(orderNo);
-        if(null != userOrderVo){
+        if (null != userOrderVo) {
             userOrderVo.setOrderDetail(orderDetailService.detail(userOrderVo.getOrderNo()));
         }
         return userOrderVo;
@@ -125,8 +125,6 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
         }
         if (!checkPositiveOrZero(createRes.getOriginalPrice())
                 || !checkPositiveOrZero(createRes.getExpectPrice())
-                || !checkPositiveOrZero(createRes.getActualPrice())
-                || !checkPositiveOrZero(createRes.getCouponAmount())
         ) {
             return HttpResponseResult.failed("金额校验失败");
         }
@@ -160,16 +158,16 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
 
     @Override
     public void orderCallback(String data) {
-        JSONObject jsonObject = JSONObject.parseObject(data);
-        if (PayStatusEnum.succeeded.getCode().equals(jsonObject.getString("status"))) {
+        JSONObject hfRes = JSONObject.parseObject(data);
+        if (PayStatusEnum.succeeded.getCode().equals(hfRes.getString("status"))) {
             //订单完成
-            UserOrderVo detail = detail(jsonObject.getString("order_no"));
+            UserOrderVo detail = detail(hfRes.getString("order_no"));
             if (null == detail) {
                 log.error("汇付支付回调,订单未找到。 req is {}", data);
                 return;
             }
             if (detail.getStatus().equals(OrderStatusEnum.PAYING)) {
-                orderSuccess(detail);
+                orderSuccess(detail, hfRes);
             } else {
                 log.error("汇付支付回调,订单状态异常。 req is {}", data);
             }
@@ -270,6 +268,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
         insertOrderPayment(res, payReq);
         return HttpResponseResult.succeed(orderPayRes);
     }
+
     /***
      * 插入订单付款单
      * @author liweifan
@@ -334,11 +333,15 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
         userOrder.setStatus(OrderStatusEnum.WAIT_PAY);
         userOrder.setOriginalPrice(data.getOriginalPrice());
         userOrder.setExpectPrice(data.getExpectPrice());
-        userOrder.setActualPrice(data.getActualPrice());
-        userOrder.setCouponAmount(data.getCouponAmount());
+
+        //todo 优惠券优惠金额,暂时为0
+        BigDecimal couponAmount = new BigDecimal(0);
+
+        userOrder.setActualPrice(data.getExpectPrice().subtract(couponAmount).setScale(2));
+        userOrder.setCouponAmount(couponAmount);
         //平台服务费
         BigDecimal serviceFeeRate = getServiceFeeRate(orderReq.getOrderType());
-        userOrder.setPlantformFee(data.getActualPrice().multiply(serviceFeeRate));
+        userOrder.setPlantformFee(userOrder.getActualPrice().multiply(serviceFeeRate));
         userOrder.setPlantformFeeRate(serviceFeeRate);
         userOrder.setUserNote(orderReq.getUserNote());
         userOrder.setOrderType(orderReq.getOrderType());
@@ -352,6 +355,15 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
         orderDetail.setOrderNo(userOrder.getOrderNo());
         orderDetail.setBizId(data.getBizId());
         orderDetail.setBizContent(data.getBizContent());
+        if (null != data.getGoodNum()) {
+            orderDetail.setGoodNum(data.getGoodNum());
+        }
+
+        //商品单价计算,使用商品原价计算,退费计算公式(退费金额=实际订单金额-(商品单价 * 已经使用商品数))
+        //其中,已经使用的商品单价按照原价算
+        orderDetail.setGoodPrice(
+                data.getOriginalPrice().divide(new BigDecimal(data.getGoodNum())).setScale(2)
+        );
         orderDetail.setCreateTime(new Date());
         orderDetailService.save(orderDetail);
 
@@ -421,6 +433,10 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
         }
     }
 
+    void orderSuccess(UserOrderVo detail) {
+        orderSuccess(detail, null);
+    }
+
     /**
      * 订单完成
      *
@@ -429,7 +445,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
      * @updateTime 2022/4/13 17:17
      */
     @Transactional(rollbackFor = Exception.class)
-    void orderSuccess(UserOrderVo detail) {
+    void orderSuccess(UserOrderVo detail, JSONObject hfRes) {
         detail.setStatus(OrderStatusEnum.PAID);
         detail.setPayTime(new Date());
         updateById(detail);
@@ -437,6 +453,15 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
         UserOrderPayment orderPayment = orderPaymentService.detailByOrderNo(detail.getOrderNo());
         orderPayment.setStatus(PayStatusEnum.succeeded);
         orderPayment.setArrivalTime(new Date());
+        if (null != hfRes) {
+            try {
+                orderPayment.setPayAmt(new BigDecimal(hfRes.getString("pay_amt")));
+                orderPayment.setFeeAmt(new BigDecimal(hfRes.getString("fee_amt")));
+            } catch (Exception e) {
+                e.printStackTrace();
+                log.error("完成订单,付款单金额格式化失败,参数{}", hfRes.toJSONString());
+            }
+        }
         orderPaymentService.updateById(orderPayment);
         //调用业务
         Consumer<UserOrderVo> userOrderVoConsumer = orderSuccess.get(detail.getOrderType());

+ 0 - 2
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/VipCardServiceImpl.java

@@ -65,8 +65,6 @@ public class VipCardServiceImpl extends ServiceImpl<VipCardDao, VipCard> impleme
 
         orderCreateRes.setOriginalPrice(detail.getOriginalPrice());
         orderCreateRes.setExpectPrice(detail.getActualPrice());
-        orderCreateRes.setActualPrice(detail.getActualPrice());
-        orderCreateRes.setCouponAmount(new BigDecimal(0));
         return HttpResponseResult.succeed(orderCreateRes);
     }
 

+ 45 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/UserOrderVo.java

@@ -1,8 +1,12 @@
 package com.yonge.cooleshow.biz.dal.vo;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.yonge.cooleshow.biz.dal.entity.UserOrder;
 import com.yonge.cooleshow.biz.dal.entity.UserOrderDetail;
 import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.math.BigDecimal;
 
 /**
  * @Author: liweifan
@@ -11,8 +15,16 @@ import io.swagger.annotations.ApiModel;
 @ApiModel(value = "UserOrderVo对象", description = "平台订单表查询视图对象")
 public class UserOrderVo extends UserOrder {
 	private static final long serialVersionUID = 1L;
-
+	@ApiModelProperty("订单详情 ")
 	private UserOrderDetail orderDetail;
+	@ApiModelProperty("交易流水号 ")
+	private String transNo;
+	@ApiModelProperty("汇付收取的服务费 ")
+	private BigDecimal feeAmt;
+	@ApiModelProperty("用户昵称")
+	private String username;
+	@ApiModelProperty(value = "手机号")
+	private String phone;
 
 	public UserOrderDetail getOrderDetail() {
 		return orderDetail;
@@ -21,4 +33,36 @@ public class UserOrderVo extends UserOrder {
 	public void setOrderDetail(UserOrderDetail orderDetail) {
 		this.orderDetail = orderDetail;
 	}
+
+	public String getTransNo() {
+		return transNo;
+	}
+
+	public void setTransNo(String transNo) {
+		this.transNo = transNo;
+	}
+
+	public BigDecimal getFeeAmt() {
+		return feeAmt;
+	}
+
+	public void setFeeAmt(BigDecimal feeAmt) {
+		this.feeAmt = feeAmt;
+	}
+
+	public String getUsername() {
+		return username;
+	}
+
+	public void setUsername(String username) {
+		this.username = username;
+	}
+
+	public String getPhone() {
+		return phone;
+	}
+
+	public void setPhone(String phone) {
+		this.phone = phone;
+	}
 }

+ 13 - 28
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/res/OrderCreateRes.java

@@ -1,10 +1,8 @@
 package com.yonge.cooleshow.biz.dal.vo.res;
 
-import com.yonge.cooleshow.biz.dal.enums.YesOrNoEnum;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-import javax.validation.constraints.NotNull;
 import java.math.BigDecimal;
 
 /**
@@ -21,18 +19,13 @@ public class OrderCreateRes {
     private Long bizId;
     @ApiModelProperty(value = "业务内容")
     private String bizContent;
-    @NotNull(message = "原价不能为空")
-    @ApiModelProperty(value = "原价 ", required = true)
+    @ApiModelProperty("商品数量 ")
+    private Integer goodNum;
+
+    @ApiModelProperty(value = "原价 ")
     private BigDecimal originalPrice;
-    @NotNull(message = "预计价格不能为空")
-    @ApiModelProperty(value = "预计价格 ", required = true)
+    @ApiModelProperty(value = "预计价格 ")
     private BigDecimal expectPrice;
-    @NotNull(message = "实际价格不能为空")
-    @ApiModelProperty(value = "实际价格 ", required = true)
-    private BigDecimal actualPrice;
-    @NotNull(message = "优惠金额不能为空")
-    @ApiModelProperty(value = "优惠金额 ", required = true)
-    private BigDecimal couponAmount;
 
     public Boolean getRes() {
         return res;
@@ -74,22 +67,6 @@ public class OrderCreateRes {
         this.expectPrice = expectPrice;
     }
 
-    public BigDecimal getActualPrice() {
-        return actualPrice;
-    }
-
-    public void setActualPrice(BigDecimal actualPrice) {
-        this.actualPrice = actualPrice;
-    }
-
-    public BigDecimal getCouponAmount() {
-        return couponAmount;
-    }
-
-    public void setCouponAmount(BigDecimal couponAmount) {
-        this.couponAmount = couponAmount;
-    }
-
     public String getBizContent() {
         return bizContent;
     }
@@ -97,4 +74,12 @@ public class OrderCreateRes {
     public void setBizContent(String bizContent) {
         this.bizContent = bizContent;
     }
+
+    public Integer getGoodNum() {
+        return goodNum;
+    }
+
+    public void setGoodNum(Integer goodNum) {
+        this.goodNum = goodNum;
+    }
 }

+ 2 - 2
cooleshow-user/user-biz/src/main/resources/config/mybatis/TeacherStyleVideoMapper.xml

@@ -45,8 +45,8 @@
 		SELECT
 			<include refid="baseColumns"/>,
 			ta.live_flag_ as liveFlag,
-			u.avatar,
-			u.username
+			u.avatar_ as avatar,
+			u.username_ as username
 		FROM teacher_style_video t
 		LEFT JOIN teacher a on t.user_id_ = a.user_id_
 		LEFT JOIN sys_user u on t.user_id_ = u.id_

+ 56 - 4
cooleshow-user/user-biz/src/main/resources/config/mybatis/UserOrderMapper.xml

@@ -50,22 +50,74 @@
 
     <select id="detailById" resultType="com.yonge.cooleshow.biz.dal.vo.UserOrderVo">
         SELECT
-            <include refid="baseColumns"/>
+            <include refid="baseColumns"/>,
+            p.trans_no_ as transNo,
+            p.fee_amt_ as feeAmt,
+            u.username_ as username,
+            u.phone_ as phone
         FROM user_order t
+        left join user_order_payment p on t.order_no_ = p.order_no_
+        left join sys_user u on t.user_id_ = u.id_
         where t.id_ = #{id}
     </select>
 
     <select id="detailByOrderNo" resultType="com.yonge.cooleshow.biz.dal.vo.UserOrderVo">
         SELECT
-        <include refid="baseColumns"/>
+            <include refid="baseColumns"/>,
+            p.trans_no_ as transNo,
+            p.fee_amt_ as feeAmt,
+            u.username_ as username,
+            u.phone_ as phone
         FROM user_order t
+        left join user_order_payment p on t.order_no_ = p.order_no_
+        left join sys_user u on t.user_id_ = u.id_
         where t.order_no_ = #{orderNo}
     </select>
 
-    <select id="selectPage" resultMap="BaseResultMap">
+    <select id="selectPage" resultType="com.yonge.cooleshow.biz.dal.vo.UserOrderVo">
 		SELECT         
-        	<include refid="baseColumns" />
+        	<include refid="baseColumns" />,
+            p.trans_no_ as transNo,
+            p.fee_amt_ as feeAmt,
+            u.username_ as username,
+            u.phone_ as phone
 		FROM user_order t
+        left join user_order_payment p on t.order_no_ = p.order_no_
+        left join sys_user u on t.user_id_ = u.id_
+        <where>
+            <if test="null != param.search and '' != param.search">
+                AND (
+                    t.user_id_ LIKE CONCAT('%', #{param.search}, '%') or
+                    u.username_ LIKE CONCAT('%', #{param.search}, '%') or
+                    u.phone_ LIKE CONCAT('%', #{param.search}, '%')
+                )
+            </if>
+            <if test="null != param.searchNo and '' != param.searchNo">
+                AND (
+                    t.order_no_ LIKE CONCAT('%', #{param.search}, '%') or
+                    p.trans_no_ LIKE CONCAT('%', #{param.search}, '%')
+                )
+            </if>
+            <if test="null != param.orderType">
+                AND t.order_type_ = #{param.orderType}
+            </if>
+            <if test="null != param.status">
+                AND t.status_ = #{param.status}
+            </if>
+            <if test="param.startTime !=null">
+                <![CDATA[AND t.create_time_ >= #{param.startTime} ]]>
+            </if>
+            <if test="param.endTime !=null">
+                <![CDATA[AND t.create_time_ <= #{param.endTime} ]]>
+            </if>
+            <if test="param.userId !=null">
+                AND t.user_id_ = #{param.userId}
+            </if>
+            <if test="param.merchId !=null">
+                AND t.merch_id_ = #{param.merchId}
+            </if>
+        </where>
+        order by t.create_time_ desc
 	</select>
     <select id="selectPendingList" resultType="com.yonge.cooleshow.biz.dal.vo.UserOrderVo">
         SELECT * FROM user_order t

+ 2 - 0
cooleshow-user/user-biz/src/main/resources/config/mybatis/UserOrderPaymentMapper.xml

@@ -7,6 +7,7 @@
         <result column="trans_no_" property="transNo" />
         <result column="pay_channel_" property="payChannel" />
         <result column="pay_amt_" property="payAmt" />
+        <result column="fee_amt_" property="feeAmt" />
         <result column="pay_info_" property="payInfo" />
         <result column="status_" property="status" />
         <result column="arrival_time_" property="arrivalTime" />
@@ -21,6 +22,7 @@
         , t.trans_no_ as transNo
         , t.pay_channel_ as payChannel
         , t.pay_amt_ as payAmt
+        , t.fee_amt_ as feeAmt
         , t.pay_info_ as payInfo
         , t.status_ as status
         , t.arrival_time_ as arrivalTime

+ 36 - 0
cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/UserBankCardController.java

@@ -0,0 +1,36 @@
+package com.yonge.cooleshow.teacher.controller;
+
+import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.entity.UserBankCard;
+import com.yonge.cooleshow.biz.dal.service.UserBankCardService;
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+
+@RestController
+@RequestMapping("/userBankCard")
+@Api(value = "用户绑卡记录表", tags = "用户绑卡记录表")
+public class UserBankCardController extends BaseController {
+    @Autowired
+    private UserBankCardService userBankCardService;
+	@Autowired
+	private SysUserFeignService sysUserFeignService;
+
+	@PostMapping("/bankCard")
+	@ApiOperation(value = "用户绑卡")
+	public HttpResponseResult<UserBankCard> bankCard(@Valid @RequestBody UserBankCard bankCard) {
+		SysUser user = sysUserFeignService.queryUserInfo();
+		if (user == null || null == user.getId()) {
+			return failed(HttpStatus.FORBIDDEN, "请登录");
+		}
+		return userBankCardService.bankCard(bankCard);
+	}
+
+}

+ 1 - 1
cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/UserWithdrawalController.java

@@ -3,6 +3,7 @@ package com.yonge.cooleshow.teacher.controller;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dto.req.WithdrawalReq;
+import com.yonge.cooleshow.biz.dal.entity.UserBankCard;
 import com.yonge.cooleshow.biz.dal.entity.UserOrder;
 import com.yonge.cooleshow.biz.dal.enums.CacheNameEnum;
 import com.yonge.cooleshow.biz.dal.service.UserWithdrawalService;
@@ -30,7 +31,6 @@ public class UserWithdrawalController extends BaseController {
     @Autowired
     private SysUserFeignService sysUserFeignService;
 
-
     @PostMapping("/getWithdrawalInfo")
     @ApiOperation(value = "查询提现页面信息")
     public HttpResponseResult<WithdrawalInfoRes> getWithdrawalInfo() {

+ 95 - 88
toolset/utils/pom.xml

@@ -1,105 +1,112 @@
 <?xml version="1.0"?>
-<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-  <modelVersion>4.0.0</modelVersion>
-  <parent>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.yonge.toolset</groupId>
+        <artifactId>toolset</artifactId>
+        <version>1.0</version>
+    </parent>
     <groupId>com.yonge.toolset</groupId>
-    <artifactId>toolset</artifactId>
+    <artifactId>utils</artifactId>
     <version>1.0</version>
-  </parent>
-  <groupId>com.yonge.toolset</groupId>
-  <artifactId>utils</artifactId>
-  <version>1.0</version>
-  <name>utils</name>
-  <url>http://maven.apache.org</url>
-  <properties>
-    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-  </properties>
-  <dependencies>
-		<dependency>
-			<groupId>org.apache.commons</groupId>
-			<artifactId>commons-lang3</artifactId>
-		</dependency>
+    <name>utils</name>
+    <url>http://maven.apache.org</url>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
 
-		<dependency>
-			<groupId>commons-beanutils</groupId>
-			<artifactId>commons-beanutils</artifactId>
-		</dependency>
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+        </dependency>
 
-		<dependency>
-			<groupId>com.google.zxing</groupId>
-			<artifactId>core</artifactId>
-		</dependency>
+        <dependency>
+            <groupId>com.google.zxing</groupId>
+            <artifactId>core</artifactId>
+        </dependency>
 
-		<dependency>
-			<groupId>com.google.zxing</groupId>
-			<artifactId>javase</artifactId>
-		</dependency>
+        <dependency>
+            <groupId>com.google.zxing</groupId>
+            <artifactId>javase</artifactId>
+        </dependency>
 
-		<dependency>
-			<groupId>org.apache.httpcomponents</groupId>
-			<artifactId>httpclient</artifactId>
-		</dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+        </dependency>
 
-		<dependency>
-			<groupId>org.apache.httpcomponents</groupId>
-			<artifactId>httpmime</artifactId>
-		</dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpmime</artifactId>
+        </dependency>
 
-		<dependency>
-			<groupId>com.lowagie</groupId>
-			<artifactId>itext</artifactId>
-			<version>2.1.7</version>
-		</dependency>
+        <dependency>
+            <groupId>com.lowagie</groupId>
+            <artifactId>itext</artifactId>
+            <version>2.1.7</version>
+        </dependency>
 
-		<dependency>
-			<groupId>org.xhtmlrenderer</groupId>
-			<artifactId>flying-saucer-pdf</artifactId>
-			<version>9.0.7</version>
-		</dependency>
+        <dependency>
+            <groupId>org.xhtmlrenderer</groupId>
+            <artifactId>flying-saucer-pdf</artifactId>
+            <version>9.0.7</version>
+        </dependency>
 
-		<dependency>
-			<groupId>org.freemarker</groupId>
-			<artifactId>freemarker</artifactId>
-		</dependency>
+        <dependency>
+            <groupId>org.freemarker</groupId>
+            <artifactId>freemarker</artifactId>
+        </dependency>
 
-		<dependency>
-			<groupId>org.apache.poi</groupId>
-			<artifactId>poi</artifactId>
-			<version>3.12</version>
-		</dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi</artifactId>
+            <version>3.12</version>
+        </dependency>
 
-		<dependency>
-			<groupId>org.apache.poi</groupId>
-			<artifactId>poi-ooxml</artifactId>
-			<version>3.12</version>
-		</dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+            <version>3.12</version>
+        </dependency>
 
-		<dependency>
-			<groupId>iTextAsian</groupId>
-			<artifactId>iTextAsian</artifactId>
-			<version>1.0</version>
-		</dependency>
-		<dependency>
-			<groupId>org.ini4j</groupId>
-			<artifactId>ini4j</artifactId>
-			<version>0.5.4</version>
-		</dependency>
+        <dependency>
+            <groupId>iTextAsian</groupId>
+            <artifactId>iTextAsian</artifactId>
+            <version>1.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.ini4j</groupId>
+            <artifactId>ini4j</artifactId>
+            <version>0.5.4</version>
+        </dependency>
 
-		<dependency>
-			<groupId>com.alibaba</groupId>
-			<artifactId>fastjson</artifactId>
-			<version>1.2.70</version>
-		</dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.70</version>
+        </dependency>
 
-		<dependency>
-			<groupId>commons-io</groupId>
-			<artifactId>commons-io</artifactId>
-			<version>2.8.0</version>
-		</dependency>
-		<dependency>
-			<groupId>org.springframework</groupId>
-			<artifactId>spring-expression</artifactId>
-		</dependency>
-  </dependencies>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.8.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-expression</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>easyexcel</artifactId>
+            <version>2.1.6</version>
+        </dependency>
+    </dependencies>
 </project>

+ 103 - 0
toolset/utils/src/main/java/com/yonge/toolset/utils/easyexcel/ExcelDataReader.java

@@ -0,0 +1,103 @@
+package com.yonge.toolset.utils.easyexcel;
+
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.event.AnalysisEventListener;
+import org.apache.commons.collections.CollectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
+/**
+ * Excel公共监听类
+ *
+ * @author hgw
+ * Created by 2021-07-22
+ */
+public class ExcelDataReader<T> extends AnalysisEventListener<T> {
+    private static final Logger log = LoggerFactory.getLogger(ExcelDataReader.class);
+
+    //数据
+    private final List<ExcelDataReaderProperty<T>> dataList = new ArrayList<>();
+    //文件名称
+    private final String fileName;
+    //行数最大行数限制
+    private final int maxRows;
+    //当前的sheetNo是第几个
+    private Integer currentSheetNo = 0;
+    //当前传输行数
+    private final AtomicInteger rows = new AtomicInteger(0);
+    //异步执行的集合
+    private final List<CompletableFuture<ExcelDataReaderProperty<T>>> futureList = new ArrayList<>();
+    //校验
+    private final Validator vf;
+
+    public ExcelDataReader(int maxRows, String fileName) {
+        this.maxRows = maxRows;
+        this.fileName = fileName;
+        this.vf = Validation.buildDefaultValidatorFactory().getValidator();
+    }
+
+    public List<ExcelDataReaderProperty<T>> getDataList() {
+        return dataList;
+    }
+
+    public String getFileName() {
+        return fileName;
+    }
+
+    public int getRows() {
+        return rows.get();
+    }
+
+    @Override
+    public void invoke(T data, AnalysisContext context) {
+        //支持多sheet数据导入,每次换sheet后要清除上一个sheet的数据
+        Integer sheetNo = context.readSheetHolder().getSheetNo();
+        if (Objects.nonNull(sheetNo) && sheetNo > currentSheetNo) {
+            futureList.clear();
+            currentSheetNo = sheetNo;
+        }
+        if (rows.get() > maxRows) {
+            throw new RuntimeException("导入的数据超过最大行数限制!" + rows.get());
+        }
+        CompletableFuture<ExcelDataReaderProperty<T>> future = CompletableFuture.supplyAsync(() -> executed(data));
+        futureList.add(future);
+        rows.incrementAndGet();
+    }
+
+    @Override
+    public void doAfterAllAnalysed(AnalysisContext context) {
+        Integer sheetNo = context.readSheetHolder().getSheetNo();
+        //因为空白的sheet也会读取但是不会进入上面的invoke方法(坑),所以不会清除futureList所以空白的sheet可以直接跳过
+        if (Objects.nonNull(sheetNo) && sheetNo > currentSheetNo) {
+            return;
+        }
+        futureList.forEach(f -> dataList.add(f.join()));
+        log.info("ExcelDataReader >> fileName {} >> dataList size {}", fileName, dataList.size());
+    }
+
+    private ExcelDataReaderProperty<T> executed(T data) {
+        ExcelDataReaderProperty<T> property = new ExcelDataReaderProperty<>();
+        property.setClazz(data);
+        //执行注解校验
+        Set<ConstraintViolation<T>> set = vf.validate(data);
+        if (CollectionUtils.isNotEmpty(set)) {
+            String collect = set.stream()
+                    .map(ConstraintViolation::getMessage)
+                    .collect(Collectors.joining());
+            property.setErrorMessage(collect);
+        }
+        return property;
+    }
+
+}

+ 31 - 0
toolset/utils/src/main/java/com/yonge/toolset/utils/easyexcel/ExcelDataReaderProperty.java

@@ -0,0 +1,31 @@
+package com.yonge.toolset.utils.easyexcel;
+
+import java.io.Serializable;
+
+/**
+ * @author hgw
+ * Created by 2021-07-26
+ */
+public class ExcelDataReaderProperty<T> implements Serializable {
+
+    private T clazz;
+
+    private String errorMessage;
+
+    public T getClazz() {
+        return clazz;
+    }
+
+    public void setClazz(T clazz) {
+        this.clazz = clazz;
+    }
+
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    public void setErrorMessage(String errorMessage) {
+        this.errorMessage = errorMessage;
+    }
+
+}

+ 133 - 0
toolset/utils/src/main/java/com/yonge/toolset/utils/easyexcel/ExcelUtils.java

@@ -0,0 +1,133 @@
+package com.yonge.toolset.utils.easyexcel;
+
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.support.ExcelTypeEnum;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * 导入数据工具包
+ * <p>
+ * 1.导入默认行数为maxRows-10000行
+ * <p>
+ * 2.可以在Class实体类中使用Validation相关AOP注解
+ * <p>
+ * 例如:
+ * <p>
+ * 在多个字段上添加@NotBlank("xx不能为空!") 注解,
+ * 若多次触发该注解,<p>多个错误信息会用逗号拼接再放入 ExcelDataReaderProperty.errorMessage字段中
+ * <p>
+ *
+ * @author hgw
+ * Created by 2021-07-22
+ */
+public class ExcelUtils {
+    private static final Logger log = LoggerFactory.getLogger(ExcelUtils.class);
+
+    private static final int maxRows = 10000;
+
+    public static <T> ExcelDataReader<T> getReader(Class<T> clazz, HttpServletRequest req) {
+        return getReader(clazz, req, maxRows);
+    }
+
+    public static <T> ExcelDataReader<T> getReader(Class<T> clazz, HttpServletRequest req, int maxRows) {
+        StandardMultipartHttpServletRequest request = (StandardMultipartHttpServletRequest) req;
+        MultipartFile excel = request.getFile("file");
+        return getExcelDataReader(clazz, maxRows, excel);
+    }
+
+    public static <T> ExcelDataReader<T> getReader(Class<T> clazz, MultipartFile excel) {
+        return getReader(clazz, excel, maxRows);
+    }
+
+    public static <T> ExcelDataReader<T> getReader(Class<T> clazz, MultipartFile excel, int maxRows) {
+        return getExcelDataReader(clazz, maxRows, excel);
+    }
+
+    //导入数据
+    private static <T> ExcelDataReader<T> getExcelDataReader(Class<T> clazz, int maxRows, MultipartFile excel) {
+        //校验数据
+        ExcelTypeEnum readEnum = checkAndGetExcelType(excel);
+        //读取数据
+        ExcelDataReader<T> reader = new ExcelDataReader<>(maxRows, excel.getOriginalFilename());
+        try {
+            EasyExcel.read(excel.getInputStream(), clazz, reader)
+                    .excelType(readEnum)
+                    .doReadAll();
+        } catch (Exception e) {
+            throw new RuntimeException("导入数据异常!", e.getCause());
+        }
+        return reader;
+    }
+
+    //校验数据有效性并获导入格式
+    private static ExcelTypeEnum checkAndGetExcelType(MultipartFile excel) {
+        if (Objects.isNull(excel)) {
+            throw new RuntimeException("请选择一份需要导入的文件!");
+        }
+        if (excel.isEmpty()) {
+            throw new RuntimeException("导入的文件是空的!");
+        }
+        if (StringUtils.isBlank(excel.getOriginalFilename())) {
+            throw new RuntimeException("文件名不能为空!");
+        }
+        String[] split = excel.getOriginalFilename().split("\\.");
+        if (split.length != 2) {
+            throw new RuntimeException("文件名不规范!示例:文件名.xlsx 或 文件名.xls");
+        }
+        String excelType = split[1];
+        ExcelTypeEnum xlsxTypeEnum = ExcelTypeEnum.XLSX;
+        ExcelTypeEnum xlsTypeEnum = ExcelTypeEnum.XLS;
+        ExcelTypeEnum readEnum;
+        if (xlsxTypeEnum.getValue().equalsIgnoreCase("." + excelType)) {
+            readEnum = xlsxTypeEnum;
+        } else if (xlsTypeEnum.getValue().equalsIgnoreCase("." + excelType)) {
+            readEnum = xlsTypeEnum;
+        } else {
+            throw new RuntimeException("只能上传[ .xlsx 或 .xls ]格式的文件!");
+        }
+        return readEnum;
+    }
+
+    /**
+     * 导出数据
+     * <p>-导出默认.xlsx
+     * <p>-传入的导出文件名不能有符号
+     *
+     * @param data     需要导出的数据
+     * @param fileName 导出数据的名称
+     * @param <T>      导出数据实体类-需要@ExcelProperty标签
+     */
+    public static <T> void exportExcel(List<T> data, String fileName) {
+        HttpServletResponse response = Optional.ofNullable(RequestContextHolder.getRequestAttributes())
+                .map(r -> (ServletRequestAttributes) r)
+                .map(ServletRequestAttributes::getResponse)
+                .orElse(null);
+        if (Objects.isNull(response)) {
+            return;
+        }
+        response.setContentType("application/vnd.ms-excel;charset=utf-8");
+        response.setCharacterEncoding("utf-8");
+        String exportFileName = new String((fileName + ExcelTypeEnum.XLSX.getValue()).getBytes(), StandardCharsets.UTF_8);
+        response.setHeader("Content-Disposition", "attachment;filename=" + exportFileName);
+        try {
+            EasyExcel.write(response.getOutputStream(), data.get(0).getClass()).sheet().doWrite(data);
+        } catch (IOException e) {
+            throw new RuntimeException("导出数据异常!", e.getCause());
+        }
+    }
+
+}