Commit 4819f7b0 authored by tangtuo's avatar tangtuo

微信支付

parent 96d5d17e
......@@ -34,7 +34,8 @@ public class WxPayConfig {
private WxPayProperties wxPayProperties;
private PrivateKey getPrivateKey() {
@Bean
public PrivateKey wxPrivateKey() {
// 加载商户私钥(privateKey:私钥字符串地址)
try {
ClassPathResource resource = new ClassPathResource(wxPayProperties.getPrivateKeyPath());
......@@ -44,23 +45,20 @@ public class WxPayConfig {
}
}
@Bean
public CloseableHttpClient client() throws NotFoundException, HttpCodeException, GeneralSecurityException, IOException {
public CloseableHttpClient client(PrivateKey wxPrivateKey) throws NotFoundException, HttpCodeException, GeneralSecurityException, IOException {
// 获取证书管理器实例
CertificatesManager certificatesManager = CertificatesManager.getInstance();
// 向证书管理器增加需要自动更新平台证书的商户信息
PrivateKey merchantPrivateKey = getPrivateKey();
String mchId = wxPayProperties.getMchId();
String apiV3Key = wxPayProperties.getApiV3Key();
String mchSerialNum = wxPayProperties.getMchSerialNum();
certificatesManager.putMerchant(mchId, new WechatPay2Credentials(mchId,
new PrivateKeySigner(mchSerialNum, merchantPrivateKey)), apiV3Key.getBytes(StandardCharsets.UTF_8));
new PrivateKeySigner(mchSerialNum, wxPrivateKey)), apiV3Key.getBytes(StandardCharsets.UTF_8));
// 从证书管理器中获取verifier
Verifier verifier = certificatesManager.getVerifier(mchId);
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant(mchId, mchSerialNum, merchantPrivateKey)
.withMerchant(mchId, mchSerialNum, wxPrivateKey)
.withValidator(new WechatPay2Validator(verifier));
// ... 接下来,你仍然可以通过builder设置各种参数,来配置你的HttpClient
// 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新
......
......@@ -56,16 +56,11 @@ public class Nft extends BaseEntity {
@ApiModelProperty("简介")
private String synopsis;
@ApiModelProperty("文件名")
private String fileName;
@ApiModelProperty("文件地址--用户选择不存档的情况下为空")
private String fileUrl;
@NotBlank(message = "作品哈希不能为空")
@ApiModelProperty("文件hash")
private String fileHash;
@NotBlank(message = "nft编号不能为空")
@ApiModelProperty("nft编号")
private String nftId;
......
package com.fzm.common.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import java.util.Date;
/**
* @author tangtuo
* @date 2022/1/19 15:33
*/
@Data
@TableName("tb_order")
public class Order {
@ApiModelProperty("主键")
private Long id;
@ApiModelProperty("订单名")
private String orderName;
@ApiModelProperty("支付场景 1-nft发行 2-版权申请")
private Integer payScene;
@ApiModelProperty("产品id nft主键或者版权主键")
private Integer productId;
@ApiModelProperty("用户id")
private Integer userId;
@ApiModelProperty("订单价格-单位(分)")
private Long fee;
@ApiModelProperty("0-支付中 1-支付成功 2-订单已关闭 3-已退款")
private Integer orderStatus;
@ApiModelProperty("支付类型 1-微信支付 2-支付宝支付")
private Integer payType;
@ApiModelProperty("创建时间")
private Date createDate;
@ApiModelProperty("最后一次修改时间")
private Date updateDate;
}
package com.fzm.common.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
@Data
@TableName("tb_payment")
public class Payment {
@TableId(type = IdType.AUTO)
private Integer id;
@ApiModelProperty("商品订单编号")
private Long orderId;
@ApiModelProperty("支付系统交易编号")
private String transactionId;
@ApiModelProperty("交易类型")
private String tradeType;
@ApiModelProperty("交易状态")
private String tradeState;
@ApiModelProperty("支付金额(分)")
private Integer totalFee;
@ApiModelProperty("商品订单编号")
private String successTime;
@ApiModelProperty("通知参数")
private String content;
private Date createDate;
private Date updateDate;
}
\ No newline at end of file
package com.fzm.common.entity.dto;
import lombok.Data;
/**
* @author tangtuo
* @date 2022/1/20 18:45
*/
@Data
public class JsapiPayDto {
private String openid;
private Long orderId;
}
package com.fzm.common.entity.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author tangtuo
* @date 2022/1/19 15:09
*/
@Data
public class OrderDto {
@ApiModelProperty("订单价格")
private Long fee;
@ApiModelProperty("支付场景 1-nft发行 2-版权申请")
private Integer payScene;
@ApiModelProperty("产品id nft的id或者copyright的id")
private Integer productId;
}
package com.fzm.common.entity.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author tangtuo
* @date 2022/1/21 13:08
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OrderProcessMsg {
private Integer productId;
private Integer payScene;
}
......@@ -12,7 +12,7 @@ import lombok.ToString;
@Getter
@AllArgsConstructor
public enum CopyrightApplyState {
TO_BE_PAY(-2, "待支付", ""),
WITHDRAW(-1, "已撤回", ""),
TO_BE_REVIEWED(0, "待核验", ""),
SUBMITTED(2, "提交审核", "请耐心等待湖北版权局审核受理,受理成功后将在15个工作日内完成登记"),
......
package com.fzm.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author tangtuo
* @date 2022/1/19 15:53
*/
@AllArgsConstructor
@Getter
public enum OrderStatus {
// 支付中
PAYING(0),
// 支付成功
PAYED(1),
// 已关单
CLOSED(2),
// 退款中
REFUNDING(3),
// 退款成功
REFUNDED(4),
// 订单已取消(已关闭)
CANCEL(5),
;
private Integer status;
}
package com.fzm.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author tangtuo
* @date 2022/1/18 17:49
*/
@Getter
@AllArgsConstructor
public enum PayScene {
NFT(1, "NFT发行"),
COPYRIGHT(2, "版权申请");
private Integer code;
private String type;
public static String getTypeByCode(Integer code) {
for (PayScene value : PayScene.values()) {
if (value.getCode().equals(code)) {
return value.getType();
}
}
return NFT.getType();
}
}
package com.fzm.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public enum PayType {
/**
* 微信
*/
WXPAY(1, "微信支付"),
/**
* 支付宝
*/
ALIPAY(2, "支付宝支付");
/**
* 类型
*/
private Integer code;
private final String type;
}
......@@ -20,6 +20,7 @@ public enum ResultCode implements IErrorCode {
OPERATION_FAILED(418, "操作失败"),
COPYRIGHT_FAILED(420, "版权申请失败"),
SELECT_FAILED(421, "查询失败"),
PAY_FAILED(422, "支付失败"),
;
......
package com.fzm.common.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fzm.common.entity.Order;
import org.apache.ibatis.annotations.Mapper;
/**
* @author tangtuo
* @date 2022/1/19 15:41
*/
@Mapper
public interface OrderMapper extends BaseMapper<Order> {
}
package com.fzm.common.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fzm.common.entity.Payment;
import org.apache.ibatis.annotations.Mapper;
/**
* @author tangtuo
* @date 2022/1/20 16:39
*/
@Mapper
public interface PaymentMapper extends BaseMapper<Payment> {
}
package com.fzm.common.properties;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
......@@ -17,6 +18,9 @@ public class WxPayProperties {
@ApiModelProperty("微信公众号appId")
private String appId;
@ApiModelProperty("微信公众号APPSecret")
private String appSecret;
@ApiModelProperty("商户号")
private String mchId;
......@@ -29,4 +33,10 @@ public class WxPayProperties {
@ApiModelProperty("商户私钥文件路径")
private String privateKeyPath;
@ApiModelProperty("h5支付回调地址")
private String h5PayNotifyUrl;
@ApiModelProperty("h5退款回调地址")
private String h5RefundNotifyUrl;
}
......@@ -143,4 +143,12 @@ public interface CopyrightApplyService extends IService<CopyrightApply> {
*/
List<String> getSerialCodes();
/**
* 修改状态
*
* @param copyrightId
* @param state
* @return
*/
boolean updateRegisterState(Integer copyrightId, int state);
}
......@@ -23,7 +23,7 @@ public interface NftService extends IService<Nft> {
* @param nft
* @return
*/
NftDto saveNft(Nft nft);
Integer saveNft(Nft nft);
/**
* 查看nft列表
......@@ -124,10 +124,10 @@ public interface NftService extends IService<Nft> {
/**
* 发行nft
*
* @param nftDto
* @param id
* @return
*/
Integer publish(NftDto nftDto);
Integer publish(Integer id);
/**
* nft转让
......
package com.fzm.common.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.fzm.common.entity.Order;
import com.fzm.common.entity.dto.OrderDto;
import com.fzm.common.enums.OrderStatus;
/**
* @author tangtuo
* @date 2022/1/19 15:41
*/
public interface OrderService extends IService<Order> {
/**
* 根据支付场景和产品id查询订单
*
* @param payScene
* @param productId
* @return
*/
Order getByPaySceneAndProductId(Integer payScene, Integer productId);
/**
* 更新订单状态
*
* @param out_trade_no
* @param orderStatus
*/
void updateOrderStatus(Long out_trade_no, OrderStatus orderStatus);
/**
* 下单
* @param orderDto
* @return
*/
Long createOrder(OrderDto orderDto);
/**
*
* @param orderId
* @param payType
*/
Boolean updatePayType(Long orderId, Integer payType);
}
package com.fzm.common.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.fzm.common.entity.Payment;
/**
* @author tangtuo
* @date 2022/1/20 16:40
*/
public interface PaymentService extends IService<Payment> {
}
package com.fzm.common.service;
import cn.hutool.json.JSONObject;
import com.fzm.common.entity.dto.JsapiPayDto;
import javax.servlet.http.HttpServletRequest;
import java.security.GeneralSecurityException;
import java.util.Map;
/**
* @author tangtuo
* @date 2022/1/13 10:13
*/
public interface WxPayService {
/**
* h5支付下单并生成签名
*
* @param jsapiPayDto
* @return
* @throws Exception
*/
Map<String, Object> payJsapi(JsapiPayDto jsapiPayDto) throws Exception;
String encryptByPrivateKey(String data) throws Exception;
Boolean notifyH5(HttpServletRequest request);
/**
* 支付成功后处理订单
*
* @param jsonObject
*/
void processOrder(JSONObject jsonObject) throws GeneralSecurityException;
String queryOrder(Long orderId);
}
......@@ -114,8 +114,8 @@ public class CopyrightApplyServiceImpl extends ServiceImpl<CopyrightApplyMapper,
throw GlobalException.newException(ResultCode.VALIDATE_FAILED);
}
CopyrightApply copyrightApply = new CopyrightApply(copyrightDTO);
// 首次提交,登记状态为待提交
copyrightApply.setRegisterState(CopyrightApplyState.TO_BE_REVIEWED.getCode());
// 首次提交,登记状态为待支付
copyrightApply.setRegisterState(CopyrightApplyState.TO_BE_PAY.getCode());
copyrightApply.setUserId(user.getId());
copyrightApply.setApplyTime(new Date());
try {
......@@ -303,7 +303,7 @@ public class CopyrightApplyServiceImpl extends ServiceImpl<CopyrightApplyMapper,
copyrightApplyOwnerRelationService.saveBatch(owners);
}
copyrightApply.setApplyTime(new Date());
copyrightApply.setRegisterState(CopyrightApplyState.TO_BE_REVIEWED.getCode());
copyrightApply.setRegisterState(CopyrightApplyState.TO_BE_PAY.getCode());
return updateById(copyrightApply);
}
......@@ -444,4 +444,12 @@ public class CopyrightApplyServiceImpl extends ServiceImpl<CopyrightApplyMapper,
return copyrightApplyMapper.getSerialCodes();
}
@Override
public boolean updateRegisterState(Integer copyrightId, int state) {
CopyrightApply copyrightApply = new CopyrightApply();
copyrightApply.setId(copyrightId);
copyrightApply.setRegisterState(state);
return updateById(copyrightApply);
}
}
......@@ -14,7 +14,6 @@ import com.fzm.common.utils.JwtUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
......@@ -38,16 +37,19 @@ public class EntrustShelfServiceImpl extends ServiceImpl<EntrustShelfMapper, Ent
@Override
public Boolean submit(EntrustShelf entrustShelf) {
// 查询当前nft是否已提交过申请
QueryWrapper<EntrustShelf> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("nft_hash", entrustShelf.getNftHash());
queryWrapper.eq("status", SystemConstant.BOOLEAN_DATA_FALSE);
if (this.count(queryWrapper) > 0) {
throw GlobalException.newException(ResultCode.FAILED, "此nft已提交过上架申请,请勿重复提交");
}
// 修改当前nft的是否已申请的状态为是
nftService.updateEntrust(entrustShelf.getNftHash(), SystemConstant.BOOLEAN_DATA_TRUE);
String authorization = request.getHeader("Authorization");
Integer userId = JwtUtil.getUserIdFromToken(authorization);
entrustShelf.setUserId(userId);
try {
return this.save(entrustShelf);
} catch (DuplicateKeyException e) {
throw GlobalException.newException(ResultCode.FAILED, "此nft已提交过上架申请,请勿重复提交");
}
}
@Override
......@@ -91,6 +93,7 @@ public class EntrustShelfServiceImpl extends ServiceImpl<EntrustShelfMapper, Ent
public EntrustShelf getByNftHash(String nftHash) {
QueryWrapper<EntrustShelf> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("nft_hash", nftHash);
queryWrapper.eq("status", SystemConstant.BOOLEAN_DATA_FALSE);
return this.getOne(queryWrapper);
}
}
package com.fzm.common.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fzm.common.entity.Order;
import com.fzm.common.entity.dto.OrderDto;
import com.fzm.common.enums.OrderStatus;
import com.fzm.common.enums.PayScene;
import com.fzm.common.enums.PayType;
import com.fzm.common.mapper.OrderMapper;
import com.fzm.common.service.CopyrightApplyService;
import com.fzm.common.service.NftService;
import com.fzm.common.service.OrderService;
import com.fzm.common.utils.JwtUtil;
import com.fzm.common.utils.SnowflakeUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
/**
* @author tangtuo
* @date 2022/1/19 15:42
*/
@Service
@Transactional(rollbackFor = RuntimeException.class)
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
@Resource
private NftService nftService;
@Resource
private CopyrightApplyService copyrightApplyService;
@Resource
private SnowflakeUtil snowflakeUtil;
@Resource
private HttpServletRequest request;
@Override
public Order getByPaySceneAndProductId(Integer payScene, Integer productId) {
QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("pay_scene", payScene)
.eq("product_id", productId);
return this.getOne(queryWrapper);
}
@Override
public void updateOrderStatus(Long out_trade_no, OrderStatus orderStatus) {
Order order = new Order();
order.setId(out_trade_no);
order.setOrderStatus(orderStatus.getStatus());
this.updateById(order);
}
@Override
public Long createOrder(OrderDto orderDto) {
Order order = new Order();
long id = snowflakeUtil.snowflakeId();
Integer productId = orderDto.getProductId();
String orderName;
if (PayScene.NFT.getCode().equals(orderDto.getPayScene())) {
orderName = nftService.getById(productId).getName();
} else {
orderName = copyrightApplyService.getById(productId).getOpusName();
}
order.setId(id);
order.setOrderName(orderName);
order.setPayScene(orderDto.getPayScene());
order.setOrderName(orderName);
order.setFee(orderDto.getFee());
order.setProductId(productId);
order.setUserId(JwtUtil.getUserIdFromToken(request.getHeader("Authorization")));
order.setOrderStatus(OrderStatus.PAYING.getStatus());
this.save(order);
return id;
}
@Override
public Boolean updatePayType(Long orderId, Integer payType) {
Order o = new Order();
o.setId(orderId);
o.setPayType(payType);
return updateById(o);
}
}
package com.fzm.common.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fzm.common.entity.Payment;
import com.fzm.common.mapper.PaymentMapper;
import com.fzm.common.service.PaymentService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @author tangtuo
* @date 2022/1/20 16:40
*/
@Service
@Transactional(rollbackFor = RuntimeException.class)
public class PaymentServiceImpl extends ServiceImpl<PaymentMapper, Payment> implements PaymentService {
}
package com.fzm.common.utils;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.IdUtil;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
@Slf4j
public class SnowflakeUtil {
@JsonFormat(shape = JsonFormat.Shape.STRING)
private long workerId = 0;//为终端ID
private long datacenterId = 1;//数据中心ID
private Snowflake snowflake = IdUtil.createSnowflake(workerId, datacenterId);
@PostConstruct
public void init() {
workerId = NetUtil.ipv4ToLong(NetUtil.getLocalhostStr());
log.info("当前机器的workId:{}", workerId);
}
public long snowflakeId() {
return snowflake.nextId();
}
public long snowflakeId(long workerId, long datacenterId) {
Snowflake snowflake = IdUtil.createSnowflake(workerId, datacenterId);
return snowflake.nextId();
}
}
2022-01-18 17:04:13.739 [background-preinit] INFO org.hibernate.validator.internal.util.Version-HV000001: Hibernate Validator 6.1.7.Final
2022-01-18 17:04:13.756 [main] INFO com.fzm.portal.WxPayTest-Starting WxPayTest on LAPTOP-AT8CNAMK with PID 117992 (started by tangtuo in D:\workspace\fzm-joying\joying-portal)
2022-01-18 17:04:13.757 [main] INFO com.fzm.portal.WxPayTest-The following profiles are active: nj
2022-01-18 17:04:14.838 [main] INFO o.s.d.r.config.RepositoryConfigurationDelegate-Multiple Spring Data modules found, entering strict repository configuration mode!
2022-01-18 17:04:14.841 [main] INFO o.s.d.r.config.RepositoryConfigurationDelegate-Bootstrapping Spring Data Redis repositories in DEFAULT mode.
2022-01-18 17:04:14.894 [main] INFO o.s.d.r.config.RepositoryConfigurationDelegate-Finished Spring Data repository scanning in 13ms. Found 0 Redis repository interfaces.
2022-01-18 17:04:16.143 [main] INFO c.a.d.s.b.a.DruidDataSourceAutoConfigure-Init DruidDataSource
2022-01-18 17:04:18.251 [main] INFO com.alibaba.druid.pool.DruidDataSource-{dataSource-1} inited
2022-01-18 17:04:21.406 [main] INFO com.obs.services.ObsClient-Storage|1|HTTP+XML|ObsClient||||2022-01-18 17:04:20|2022-01-18 17:04:21|||0|
2022-01-18 17:04:21.408 [main] WARN com.obs.services.ObsClient-[OBS SDK Version=3.20.6.1];[Endpoint=https://obs.cn-east-3.myhuaweicloud.com:443/];[Access Mode=Virtul Hosting]
2022-01-18 17:04:21.741 [main] INFO org.redisson.Version-Redisson 3.16.0
2022-01-18 17:04:22.734 [redisson-netty-4-20] INFO o.r.connection.pool.MasterPubSubConnectionPool-1 connections initialized for 146.56.218.121/146.56.218.121:6379
2022-01-18 17:04:22.872 [redisson-netty-4-19] INFO org.redisson.connection.pool.MasterConnectionPool-24 connections initialized for 146.56.218.121/146.56.218.121:6379
2022-01-18 17:04:23.032 [main] WARN c.b.mybatisplus.core.metadata.TableInfoHelper-Warn: Could not find @TableId in Class: com.fzm.common.entity.CopyrightApplyOwnerRelation.
2022-01-18 17:04:23.170 [main] WARN c.b.mybatisplus.core.metadata.TableInfoHelper-Warn: Could not find @TableId in Class: com.fzm.common.entity.CopyrightAuthorityRelation.
2022-01-18 17:04:23.313 [main] INFO o.s.scheduling.concurrent.ThreadPoolTaskExecutor-Initializing ExecutorService 'threadPoolTaskExecutor'
2022-01-18 17:04:25.206 [scheduled_update_cert_thread] INFO c.w.p.c.apache.httpclient.cert.CertificatesManager-Begin update Certificates.Date:2022-01-18T09:04:25.206Z
2022-01-18 17:04:25.251 [main] INFO s.d.s.w.PropertySourcedRequestMappingHandlerMapping-Mapped URL path [/v2/api-docs] onto method [springfox.documentation.swagger2.web.Swagger2Controller#getDocumentation(String, HttpServletRequest)]
2022-01-18 17:04:25.446 [scheduled_update_cert_thread] INFO c.w.p.c.apache.httpclient.cert.CertificatesManager-Finish update Certificates.Date:2022-01-18T09:04:25.445Z
2022-01-18 17:04:26.989 [main] INFO s.d.s.web.plugins.DocumentationPluginsBootstrapper-Context refreshed
2022-01-18 17:04:27.034 [main] INFO s.d.s.web.plugins.DocumentationPluginsBootstrapper-Found 1 custom documentation plugin(s)
2022-01-18 17:04:27.085 [main] INFO s.d.spring.web.scanners.ApiListingReferenceScanner-Scanning for api listing references
2022-01-18 17:04:27.271 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: listUsingGET_1
2022-01-18 17:04:27.278 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: listUsingGET_2
2022-01-18 17:04:27.292 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: listUsingGET_3
2022-01-18 17:04:27.317 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: listUsingGET_4
2022-01-18 17:04:27.357 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: getByIdUsingGET_1
2022-01-18 17:04:27.381 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: listUsingGET_5
2022-01-18 17:04:27.409 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: addUsingPOST_1
2022-01-18 17:04:27.410 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: deleteUsingPOST_1
2022-01-18 17:04:27.416 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: listUsingGET_6
2022-01-18 17:04:27.417 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: updateUsingPOST_1
2022-01-18 17:04:27.419 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: deleteUsingPOST_2
2022-01-18 17:04:27.423 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: listUsingGET_7
2022-01-18 17:04:27.431 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: getByIdUsingGET_2
2022-01-18 17:04:27.433 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: submitUsingPOST_1
2022-01-18 17:04:27.474 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: listUsingGET_8
2022-01-18 17:04:27.483 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: publishUsingPOST_1
2022-01-18 17:04:27.504 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: saveUsingPOST_1
2022-01-18 17:04:27.513 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: getDetailUsingGET_1
2022-01-18 17:04:27.516 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: listUsingGET_9
2022-01-18 17:04:27.519 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: listUsingGET_10
2022-01-18 17:04:27.521 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: deleteUsingPOST_3
2022-01-18 17:04:27.522 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: downloadUsingPOST_1
2022-01-18 17:04:27.524 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: uploadUsingPOST_1
2022-01-18 17:04:27.564 [main] INFO s.d.s.w.r.operation.CachingOperationNameGenerator-Generating unique operation named: updateUsingPOST_2
2022-01-18 17:04:27.598 [main] INFO com.fzm.portal.WxPayTest-Started WxPayTest in 14.245 seconds (JVM running for 15.64)
2022-01-18 17:04:28.366 [SpringContextShutdownHook] INFO o.s.scheduling.concurrent.ThreadPoolTaskExecutor-Shutting down ExecutorService 'threadPoolTaskExecutor'
2022-01-18 17:04:28.565 [SpringContextShutdownHook] INFO com.alibaba.druid.pool.DruidDataSource-{dataSource-1} closing ...
2022-01-18 17:04:28.574 [SpringContextShutdownHook] INFO com.alibaba.druid.pool.DruidDataSource-{dataSource-1} closed
This diff is collapsed.
......@@ -5,7 +5,7 @@
<parent>
<artifactId>fzm-joying</artifactId>
<groupId>com.fzm</groupId>
<version>1.0.0</version>
<version>1.1.0</version>
</parent>
<artifactId>joying-portal</artifactId>
......@@ -36,6 +36,11 @@
<artifactId>joying-common</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
</dependencies>
<build>
......
package com.fzm.portal.config;
import org.springframework.amqp.core.*;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author tangtuo
* @date 2022/1/21 11:28
*/
@Configuration
public class RabbitConfig {
/**
* 处理订单的交换机
*/
@Bean
public DirectExchange orderExchange() {
return new DirectExchange("order-exchange", true, false);
}
/**
* 处理订单的队列
*
* @return
*/
@Bean
public Queue orderQueue() {
return new Queue("order.process.queue", true);
}
/**
* 处理订单的队列和交换机之间的绑定
*
* @return
*/
@Bean
public Binding orderBinding() {
return BindingBuilder.bind(orderQueue()).to(orderExchange()).with("order.process");
}
/**
* 发行nft的交换机
*
* @return
*/
@Bean
public DirectExchange nftExchange() {
return new DirectExchange("nft-exchange", true, false);
}
/**
* 死信交换机,死信到期后将会被转发到这个交换机,然后再路由到相应的队列
*/
@Bean
public DirectExchange dlNftExchange() {
return new DirectExchange("dl-nft-exchange", true, false);
}
/**
* 死信队列,用户把nft的交易hash发到此队列,
*
* @return
*/
@Bean
public Queue dlNftQueue() {
return QueueBuilder.durable("dl.nft.queue")
.ttl(1000 * 10)
.deadLetterExchange("dl-nft-exchange")
.deadLetterRoutingKey("nft")
.build();
}
/**
* 接收死信的列队,用户监听这个队列
*
* @return
*/
@Bean
public Queue nftPublishQueue() {
return new Queue("nft.publish.queue", true);
}
/**
* 死信队列和nft交换机的绑定
*
* @return
*/
@Bean
public Binding dlNftBinding() {
return BindingBuilder.bind(dlNftQueue()).to(nftExchange()).with("nft.publish");
}
@Bean
public Binding nftBinding() {
return BindingBuilder.bind(nftPublishQueue()).to(dlNftExchange()).with("nft");
}
@Bean
public MessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
}
......@@ -58,19 +58,19 @@ public class NftController {
@Authentication
@PostMapping("/save")
@ApiOperation(value = "nft基本信息保存(基本信息和加密上链两个步骤)")
public ResponseModel<NftDto> save(@Validated @ModelAttribute Nft nft) {
public ResponseModel<Integer> save(@Validated @ModelAttribute Nft nft) {
return ResponseModel.success(nftService.saveNft(nft));
}
@Authentication
@PostMapping("/publish")
@ApiOperation("发行nft")
public ResponseModel<Integer> publish(@Validated @RequestBody NftDto nftDto) {
Integer id = nftService.publish(nftDto);
return ResponseModel.success(id);
}
// @Authentication
// @PostMapping("/publish")
// @ApiOperation("发行nft")
// public ResponseModel<Integer> publish(@Validated @RequestBody NftDto nftDto) {
// Integer id = nftService.publish(nftDto);
//
// return ResponseModel.success(id);
// }
@GetMapping("/list")
@ApiOperation(value = "获取nft列表")
......
package com.fzm.portal.controller;
import com.fzm.common.annotation.Authentication;
import com.fzm.common.entity.Order;
import com.fzm.common.entity.dto.OrderDto;
import com.fzm.common.enums.PayScene;
import com.fzm.common.model.ResponseModel;
import com.fzm.common.service.CopyrightApplyService;
import com.fzm.common.service.NftService;
import com.fzm.common.service.OrderService;
import com.fzm.common.utils.SnowflakeUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* @author tangtuo
* @date 2022/1/20 18:22
*/
@Authentication
@Api(tags = "作品类别")
@RestController
@RequestMapping("/opus/category")
public class OrderController {
@Resource
private OrderService orderService;
@PostMapping("/create")
@ApiOperation("下单")
public ResponseModel<Long> createOrder(@RequestBody OrderDto orderDto) {
Long orderId = orderService.createOrder(orderDto);
return ResponseModel.success(orderId);
}
@GetMapping("/query-order-status")
@ApiOperation(value = "查询订单状态")
public ResponseModel<Integer> queryOrderStatus(@PathVariable Long orderId) {
return ResponseModel.success(orderService.getById(orderId).getOrderStatus());
}
}
package com.fzm.portal.controller;
import cn.hutool.http.HttpStatus;
import com.fzm.common.annotation.Authentication;
import com.fzm.common.entity.dto.JsapiPayDto;
import com.fzm.common.entity.dto.OrderDto;
import com.fzm.common.model.ResponseModel;
import com.fzm.common.service.WxPayService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
/**
* @author tangtuo
* @date 2022/1/13 9:55
*/
@Authentication
@Api(tags = "微信支付")
@RestController
@RequestMapping("/wx-pay")
public class WxPayController {
@PostMapping("/pay/h5")
@ApiOperation(value = "发起h5支付")
public ResponseModel<String> payH5() {
@Resource
private WxPayService wxPayService;
@Authentication
@PostMapping("/pay/jsapi")
@ApiOperation(value = "发起jsapi支付")
public ResponseModel<Map<String, Object>> payH5(@RequestBody JsapiPayDto jsapiPayDto) throws Exception {
return ResponseModel.success(wxPayService.payJsapi(jsapiPayDto));
}
return ResponseModel.success();
@ApiOperation("jsapi支付回调通知")
@PostMapping("/notify/jsapi")
public Map<String, String> notifyJsapi(HttpServletRequest request, HttpServletResponse response) {
Map<String, String> result = new HashMap<>();
Boolean notify = wxPayService.notifyH5(request);
if (notify) {
result.put("code", "SUCCESS");
result.put("message", "成功");
response.setStatus(HttpStatus.HTTP_OK);
} else {
result.put("code", "FAILED");
result.put("message", "系统异常");
response.setStatus(HttpStatus.HTTP_INTERNAL_ERROR);
}
return result;
}
}
package com.fzm.portal.listener;
import com.fzm.common.entity.dto.OrderProcessMsg;
import com.fzm.common.enums.CopyrightApplyState;
import com.fzm.common.enums.PayScene;
import com.fzm.common.service.CopyrightApplyService;
import com.fzm.common.service.NftService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @author tangtuo
* @date 2022/1/21 11:44
*/
@Slf4j
@Component
public class OrderListener {
@Resource
private NftService nftService;
@Resource
private CopyrightApplyService copyrightApplyService;
@RabbitListener(queues = "order.process.queue")
public void listenProcessOrder(OrderProcessMsg msg) {
log.info("收到处理订单的消息: {}", msg);
if (PayScene.NFT.getCode().equals(msg.getPayScene())) {
// 如果支付场景是发行nft的话,需要把此订单的nft发行
nftService.publish(msg.getProductId());
} else {
// 如果支付场景是版权申请的话,需要把当前订单对应的版权状态改为待核验
copyrightApplyService.updateRegisterState(msg.getProductId(), CopyrightApplyState.TO_BE_REVIEWED.getCode());
}
}
@RabbitListener(queues = "nft.publish.queue")
public void listenProcessOrder(Long id) {
log.info("接收到信息: {}", id);
}
}
......@@ -45,7 +45,19 @@ spring:
type: redis
redis:
time-to-live: 86400000
rabbitmq:
host: 172.16.101.135
port: 5672
username: admin
password: admin
listener:
simple:
retry:
enabled: true
max-attempts: 5 # 最大重试次数
initial-interval: 1000 # 初始的失败等待时长为1秒
multiplier: 2 # 下次失败的等待时长倍数,下次等待时长 = multiplier * last-interval
stateless: true # true无状态;false有状态。如果业务中包含事务,这里改为false
swagger:
title: 乐映影视门户系统
description: 乐映影视门户系统RESTFUL API
......@@ -96,7 +108,10 @@ huaweiyun:
wx-pay:
app-id: wxbdddd81913c795e9
app-secret: aa201717c46a0e07c4c143b1ee73229a
mch-id: 1604477044
api-v3-key: D864DA53FEF8ACD41519064967DC10D2
mch-serial-num: 72A62544B0A08A214FAEC780108692EDC6E7D5FA
private-key-path: apiclient_key.pem
h5-pay-notify-url: https://146.56.218.121:12100/wx-pay/notify/h5
h5-refund-notify-url:
......@@ -54,10 +54,10 @@ spring:
simple:
retry:
enabled: true
max-attempts: 5
initial-interval: 1000
multiplier: 2
stateless: true
max-attempts: 5 # 最大重试次数
initial-interval: 1000 # 初始的失败等待时长为1秒
multiplier: 2 # 下次失败的等待时长倍数,下次等待时长 = multiplier * last-interval
stateless: true # true无状态;false有状态。如果业务中包含事务,这里改为false
swagger:
title: 乐映影视门户系统
description: 乐映影视门户系统RESTFUL API
......@@ -108,7 +108,10 @@ huaweiyun:
wx-pay:
app-id: wxbdddd81913c795e9
app-secret: aa201717c46a0e07c4c143b1ee73229a
mch-id: 1604477044
api-v3-key: D864DA53FEF8ACD41519064967DC10D2
mch-serial-num: 72A62544B0A08A214FAEC780108692EDC6E7D5FA
private-key-path: apiclient_key.pem
h5-pay-notify-url: https://146.56.218.121:12100/wx-pay/notify/h5
h5-refund-notify-url:
\ No newline at end of file
......@@ -46,7 +46,19 @@ spring:
type: redis
redis:
time-to-live: 86400000
rabbitmq:
host: 129.211.166.223
port: 5672
username: guest
password: guest
listener:
simple:
retry:
enabled: true
max-attempts: 5 # 最大重试次数
initial-interval: 1000 # 初始的失败等待时长为1秒
multiplier: 2 # 下次失败的等待时长倍数,下次等待时长 = multiplier * last-interval
stateless: true # true无状态;false有状态。如果业务中包含事务,这里改为false
swagger:
title: 乐映影视门户系统
description: 乐映影视门户系统RESTFUL API
......@@ -109,7 +121,10 @@ huaweiyun:
wx-pay:
app-id: wxbdddd81913c795e9
app-secret: aa201717c46a0e07c4c143b1ee73229a
mch-id: 1604477044
api-v3-key: D864DA53FEF8ACD41519064967DC10D2
mch-serial-num: 72A62544B0A08A214FAEC780108692EDC6E7D5FA
private-key-path: apiclient_key.pem
h5-pay-notify-url: https://test.inmvo.com:8985/proxyApi/wx-pay/notify/h5
h5-refund-notify-url:
......@@ -46,6 +46,19 @@ spring:
type: redis
redis:
time-to-live: 86400000
rabbitmq:
host: 192.168.0.11
port: 5672
username: admin
password: admin
listener:
simple:
retry:
enabled: true
max-attempts: 5 # 最大重试次数
initial-interval: 1000 # 初始的失败等待时长为1秒
multiplier: 2 # 下次失败的等待时长倍数,下次等待时长 = multiplier * last-interval
stateless: true # true无状态;false有状态。如果业务中包含事务,这里改为false
swagger:
title: 乐映影视门户系统
......@@ -97,7 +110,10 @@ huaweiyun:
wx-pay:
app-id: wxbdddd81913c795e9
app-secret: aa201717c46a0e07c4c143b1ee73229a
mch-id: 1604477044
api-v3-key: D864DA53FEF8ACD41519064967DC10D2
mch-serial-num: 72A62544B0A08A214FAEC780108692EDC6E7D5FA
private-key-path: apiclient_key.pem
h5-pay-notify-url: https://nft.inmvo.com/proxyApi/wx-pay/notify/h5
h5-refund-notify-url:
\ No newline at end of file
spring:
profiles:
active: nj
active: local
application:
name: joying-portal
servlet:
......
......@@ -86,7 +86,7 @@ class LyPortalApplicationTests {
}
@Test
void contextLoads() {
public void contextLoads() {
System.out.println("redisson = " + redisson);
RSemaphore semaphore = redisson.getSemaphore("banner09");
boolean b = semaphore.trySetPermits(10);
......
package com.fzm.portal;
import com.fzm.common.utils.SnowflakeUtil;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
/**
* @author tangtuo
* @date 2022/1/19 14:04
*/
@SpringBootTest
public class SnawFlakeTest {
@Resource
private SnowflakeUtil snowflakeUtil;
@Test
public void test1() {
System.out.println(snowflakeUtil.snowflakeId());
}
}
......@@ -3,6 +3,9 @@ package com.fzm.portal;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fzm.common.properties.WxPayProperties;
import com.fzm.common.service.WxPayService;
import com.fzm.common.utils.SnowflakeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
......@@ -19,6 +22,7 @@ import java.io.IOException;
* @author tangtuo
* @date 2022/1/13 15:30
*/
@Slf4j
@SpringBootTest
public class WxPayTest {
......@@ -29,34 +33,79 @@ public class WxPayTest {
@Resource
private WxPayProperties wxPayProperties;
@Resource
private WxPayService wxPayService;
@Resource
private SnowflakeUtil snowflakeUtil;
@Test
public void testSnowFlake() {
for (int i = 0; i < 10; i++) {
log.info(String.valueOf(snowflakeUtil.snowflakeId()));
}
}
@Test
public void testH5Pay() throws IOException {
for (int i = 0; i < 10; i++) {
log.info(String.valueOf(snowflakeUtil.snowflakeId()));
}
// String url = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
// HttpPost httpPost = new HttpPost(url);
// httpPost.addHeader("Accept", "application/json");
// httpPost.addHeader("Content-type", "application/json; charset=utf-8");
// ByteArrayOutputStream bos = new ByteArrayOutputStream();
// ObjectMapper objectMapper = new ObjectMapper();
//
// ObjectNode rootNode = objectMapper.createObjectNode();
// rootNode.put("mchid", wxPayProperties.getMchId())
// .put("appid", wxPayProperties.getAppId())
// .put("description", "Image形象店-深圳腾大-QQ公仔")
// .put("notify_url", "http://www.baidu.com")
// .put("out_trade_no", "nft-123");
// rootNode.putObject("amount")
// .put("total", 1);
// rootNode.putObject("payer")
// .put("openid", "oRpMVw3OiOuVDZPrJTzMwTJALf70");
// String json = objectMapper.writeValueAsString(rootNode);
// System.out.println("json = " + json);
// objectMapper.writeValue(bos, rootNode);
//
// httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
// CloseableHttpResponse response = httpClient.execute(httpPost);
//
// String bodyAsString = EntityUtils.toString(response.getEntity());
// System.out.println(bodyAsString);
//
// String data = "wx8888888888888888\n1414561699\n5K8264ILTKCH16CQ2502SI8ZNMTM67VS\nprepay_id=wx201410272009395522657a690389285100";
// try {
// System.out.println(wxPayService.encryptByPrivateKey(data));
// } catch (Exception e) {
// e.printStackTrace();
// }
}
@Test
void test() {
String prepay_id = "wx181704295362907bc91140bfb2a71b0000";
String url = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type","application/json; charset=utf-8");
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode rootNode = objectMapper.createObjectNode();
rootNode.put("mchid",wxPayProperties.getMchId())
rootNode.put("mchid", wxPayProperties.getMchId())
.put("appid", wxPayProperties.getAppId())
.put("description", "Image形象店-深圳腾大-QQ公仔")
.put("notify_url", "http://www.baidu.com")
.put("out_trade_no", "nft-123");
rootNode.putObject("amount")
.put("total", 1);
rootNode.putObject("payer")
.put("openid", "oRG0ZxPPF0fbH1KCmMV5goJ69W8I");
String json = objectMapper.writeValueAsString(rootNode);
System.out.println("json = " + json);
objectMapper.writeValue(bos, rootNode);
httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
CloseableHttpResponse response = httpClient.execute(httpPost);
}
String bodyAsString = EntityUtils.toString(response.getEntity());
System.out.println(bodyAsString);
}
}
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
......@@ -6,7 +6,7 @@
<groupId>com.fzm</groupId>
<artifactId>fzm-joying</artifactId>
<version>1.0.0</version>
<version>1.1.0</version>
<modules>
<module>joying-common</module>
<module>joying-portal</module>
......
......@@ -574,5 +574,40 @@ UPDATE `tb_opus_category` SET `value` = '其他作品' WHERE `id` = 18;
alter table tb_copyright_apply modify column evidence_date datetime DEFAULT NULL COMMENT '存证时间';
-- v2.1.0
CREATE UNIQUE INDEX idx_nfthash ON tb_entrust_shelf ( nft_hash );
alter table tb_nft add column is_entrust tinyint(1) not null default 0 comment '是否已委托上架 0-否 1-是' after status;
CREATE TABLE `tb_entrust_shelf` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL COMMENT '用户id',
`nft_hash` varchar(255) NOT NULL COMMENT 'nft哈希',
`name` varchar(12) NOT NULL DEFAULT '' COMMENT '姓名',
`telephone` varchar(16) NOT NULL DEFAULT '' COMMENT '电话号码',
`wechat_num` varchar(128) DEFAULT NULL COMMENT '微信号',
`status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0-委托中 1-已取消',
`create_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='委托上架';
CREATE TABLE `tb_banner` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL DEFAULT '' COMMENT '名称',
`poster` varchar(255) NOT NULL DEFAULT '' COMMENT '海报',
`jump_url` varchar(255) NOT NULL DEFAULT '' COMMENT '跳转地址',
`sort` int(2) NOT NULL DEFAULT '0' COMMENT '排序',
`create_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
CREATE TABLE `tb_order` (
`id` bigint(20) NOT NULL,
`pay_scene` tinyint(1) NOT NULL COMMENT '支付场景 1-nft发行 2-版权申请',
`product_id` int(11) NOT NULL COMMENT '产品id nft主键或者版权主键',
`user_id` int(11) NOT NULL COMMENT '用户id',
`fee` bigint(20) NOT NULL COMMENT '订单价格-单位(分)',
`order_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0-支付中 1-支付成功 2-订单已关闭 3-已退款',
`prepay_id` varchar(128) NOT NULL COMMENT '微信预支付交易会话标识',
`create_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment