Commit 8b818f4b authored by tangtuo's avatar tangtuo

纪念版nft相关接口编写

parent 9992f545
......@@ -21,5 +21,17 @@ public class RedisConstant {
*/
public static final String ADMIN_USER_TOKEN_PREFIX = "admin:user:token:";
/**
* 纪念版NFT
*/
public static final String COMMEMORATE_NFT_PREFIX = "commemorateNft:";
/**
* 纪念版nft领取成员列表
*/
public static final String COMMEMORATE_NFT_MEMBERS_PREFIX = "commemorateNft:members";
}
......@@ -56,6 +56,15 @@ public class CommemorateNft {
@ApiModelProperty("文件hash")
private String fileHash;
@ApiModelProperty("nft哈希")
private String nftHash;
@ApiModelProperty("nft token")
private Long tokenId;
@ApiModelProperty("nft发行时间")
private Date publishTime;
@ApiModelProperty("数量")
private Integer count;
......
......@@ -88,4 +88,7 @@ public class Nft extends BaseEntity {
@ApiModelProperty("0-下架 1-上架")
private Integer status;
@ApiModelProperty("是否是纪念版nft 0-否 1-是")
private Integer isCommemorate;
}
......@@ -10,4 +10,19 @@ import com.fzm.common.entity.CommemorateNft;
*/
public interface CommemorateNftService extends IService<CommemorateNft> {
/**
* 发布纪念版nft
*
* @param commemorateNft
* @return
*/
Integer publish(CommemorateNft commemorateNft);
/**
* 领取纪念版nft
*
* @param id
* @return
*/
Boolean receive(Integer id);
}
package com.fzm.common.service.impl;
import cn.fzm.chain.simplesdk.client.ParaChainClient;
import cn.fzm.chain.simplesdk.constant.TxStatusEnum;
import cn.fzm.chain.simplesdk.model.TxResult;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fzm.common.constant.RedisConstant;
import com.fzm.common.constant.SystemConstant;
import com.fzm.common.entity.Admin;
import com.fzm.common.entity.CommemorateNft;
import com.fzm.common.entity.Nft;
import com.fzm.common.entity.User;
import com.fzm.common.enums.ResultCode;
import com.fzm.common.exception.GlobalException;
import com.fzm.common.mapper.AdminMapper;
import com.fzm.common.mapper.CommemorateNftMapper;
import com.fzm.common.service.AdminService;
import com.fzm.common.service.CommemorateNftService;
import com.fzm.common.service.*;
import com.fzm.common.utils.JsonUtil;
import com.fzm.common.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
/**
* @author tangtuo
* @date 2021/7/5 15:09
*/
@Slf4j
@Service
public class CommemorateNftServiceImpl extends ServiceImpl<CommemorateNftMapper, CommemorateNft> implements CommemorateNftService {
@Resource
NftChainInfoService nftChainInfoService;
@Resource
private NftService nftService;
@Resource
private ParaChainClient paraChainClient;
@Value("${chain.para.contract-name}")
private String contractName;
@Resource
private UserService userService;
@Resource
private RedissonClient redisson;
@Resource
private RedisUtil redisUtil;
@Override
public Integer publish(CommemorateNft commemorateNft) {
User user = userService.getUserByToken();
String wallet = user.getWallet();
commemorateNft.setUserId(user.getId()).
setPublishAddress(wallet);
// 获取用户的私钥
String privkey = paraChainClient.walletDumpPrivkey(wallet);
// 发行nft
String txHash = paraChainClient.evmPublishNFT1155(contractName, wallet, privkey, commemorateNft.getCount(), true);
if (StringUtils.isBlank(txHash) || !txHash.contains("-")) {
throw GlobalException.newException(ResultCode.FAILED, "nft发行失败");
}
String[] split = txHash.split("-");
String hash = split[0];
long tokenId = Long.parseLong(split[1]);
// 构建上链信息
HashMap<String, String> map = new HashMap<>();
map.put("author", user.getNickname());
map.put("name", commemorateNft.getName());
map.put("hash", commemorateNft.getFileHash());
String tokenInfo = JsonUtil.toJson(map);
log.info("加密上链数据: {}", tokenInfo);
String tradeHash = paraChainClient.evmSetTokenInfo(contractName, tokenId, tokenInfo, wallet, privkey, true);
if (StringUtils.isBlank(tradeHash)) {
throw GlobalException.newException(ResultCode.PUBLISH_ERROR, "nft发行失败");
}
// 确认交易结果
TxResult txResult = paraChainClient.cycleConfirmTxWithHash(hash, true, 1000);
if (!TxStatusEnum.SUCCESS.equals(txResult.getStatus())) {
throw GlobalException.newException(ResultCode.PUBLISH_ERROR, txResult.getErrMsg().getValue());
}
commemorateNft.setNftHash(hash).setTokenId(tokenId).setPublishTime(new Date());
save(commemorateNft);
// 使用nft发行量作为Redisson信号量限制领取次数
RSemaphore semaphore = redisson.getSemaphore(RedisConstant.COMMEMORATE_NFT_PREFIX + commemorateNft.getId());
semaphore.trySetPermits(commemorateNft.getCount());
return commemorateNft.getId();
}
@Override
public Boolean receive(Integer id) {
CommemorateNft commemorateNft = getById(id);
if (commemorateNft == null) {
throw GlobalException.newException(ResultCode.DATA_ERROR, "没找到此纪念版nft详情,请稍后再试");
}
User user = userService.getUserByToken();
// 先判断当前用户有没有领取过此纪念版nft
if (redisUtil.sIsMember(RedisConstant.COMMEMORATE_NFT_MEMBERS_PREFIX + id, user.getId().toString())) {
throw GlobalException.newException(ResultCode.FAILED, "此纪念版nft每个用户只能领取一次");
}
// 获取此纪念版nft发行数的信号量
RSemaphore semaphore = redisson.getSemaphore(RedisConstant.COMMEMORATE_NFT_PREFIX + id);
// 判断纪念版nft有没有被领取完
boolean acquire = semaphore.tryAcquire();
// 领取完毕
if (!acquire) {
throw GlobalException.newException(ResultCode.FAILED, "抱歉,此纪念版nft已全部被领取完");
}
// 领取纪念版nft
String hash = paraChainClient.evmTransferNFT1155(contractName, commemorateNft.getPublishAddress(), null, user.getWallet(), commemorateNft.getTokenId(), 1, true);
if (StringUtils.isBlank(hash)) {
// 领取失败要释放信号量
semaphore.release();
throw GlobalException.newException(ResultCode.FAILED, "nft领取失败");
}
Nft nft = new Nft();
BeanUtil.copyProperties(commemorateNft, nft, true);
// 获取当前用户领取nft的领取顺序编号
int availablePermits = commemorateNft.getCount() - semaphore.availablePermits();
// nft编号为BJIFF11+5为顺序编号 : BJIFF1100123
String code = "00000" + availablePermits;
nft.setNftId("BJIFF11" + code.substring(code.length() - 5));
nft.setUserId(user.getId());
nft.setCreateDate(new Date());
nft.setUpdateDate(new Date());
nft.setIsArchives(SystemConstant.BOOLEAN_DATA_TRUE);
nft.setIsGrant(SystemConstant.BOOLEAN_DATA_FALSE);
nft.setIsCommemorate(SystemConstant.BOOLEAN_DATA_TRUE);
nftService.save(nft);
// 领取完毕,把当前用户id加入到纪念版nft的领取记录中
redisUtil.sAdd(RedisConstant.COMMEMORATE_NFT_MEMBERS_PREFIX + id, user.getId().toString());
return true;
}
public static void main(String[] args) {
int a = 12;
String code = "00000" + a;
System.out.println("BJIFF11" + code.substring(code.length() - 5));
}
}
......@@ -94,12 +94,12 @@ public class NftServiceImpl extends ServiceImpl<NftMapper, Nft> implements NftSe
@Override
public Boolean publish(NftDto nftDto) {
User user = userService.getById(JwtUtil.getUserIdFromToken(request.getHeader("Authorization")));
User user = userService.getUserByToken();
String wallet = user.getWallet();
// 获取用户的私钥
String privkey = paraChainClient.walletDumpPrivkey(wallet);
// 发行nft
String txHash = paraChainClient.evmPublishNFT1155(contractName, wallet, privkey, 1, true);
String txHash = paraChainClient.evmPublishNFT1155(contractName, wallet, privkey, 3, true);
if (StringUtils.isBlank(txHash) || !txHash.contains("-")) {
throw GlobalException.newException(ResultCode.FAILED, "nft发行失败");
}
......
......@@ -4,7 +4,7 @@
<select id="list" resultType="com.fzm.common.entity.Nft">
select * from tb_nft
where status = 1 and nft_hash != ''
where status = 1 and is_commemorate=0 and nft_hash != ''
<if test="categoryId != null and categoryId > 0">
and category_id=#{categoryId}
</if>
......@@ -40,7 +40,7 @@
tb_nft n
LEFT JOIN tb_user u ON n.user_id = u.id
WHERE
nft_hash != ''
is_commemorate=0 and nft_hash != ''
<if test="name != null and name != ''">
and n.name like concat ('%',#{name},'%')
</if>
......
package com.fzm.portal.controller;
import cn.hutool.crypto.SecureUtil;
import com.fzm.common.annotation.Authentication;
import com.fzm.common.entity.CommemorateNft;
import com.fzm.common.entity.Label;
import com.fzm.common.entity.User;
import com.fzm.common.enums.ResultCode;
import com.fzm.common.exception.GlobalException;
import com.fzm.common.model.ResponseModel;
import com.fzm.common.service.CommemorateNftService;
import com.fzm.common.service.LabelService;
import com.fzm.common.service.UserService;
import com.fzm.common.utils.OssUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;
/**
* @author tangtuo
* @date 2021/7/1 14:37
*/
@RestController
@RequestMapping(value = "/commemorate/nft")
@Api(tags = "纪念版nft")
public class CommemorateNftController {
@Resource
private CommemorateNftService commemorateNftService;
@Resource
private OssUtil ossUtil;
@Authentication
@PostMapping("/publish")
@ApiOperation(value = "发行纪念版nft", notes = "返回发行成功的数量")
public ResponseModel<Integer> publish(@ApiParam(value = "作品名称", required = true) String name,
@ApiParam(value = "作品简介", required = true) String synopsis,
@ApiParam(value = "类目id", required = true) Integer categoryId,
@ApiParam(value = "文件", required = true) MultipartFile file,
@ApiParam(value = "发行数量", required = true) Integer count) throws IOException {
if (file == null) {
throw GlobalException.newException(ResultCode.VALIDATE_FAILED, "文件不能为空");
}
String url = ossUtil.putSimpleObject(file);
CommemorateNft commemorateNft = new CommemorateNft().
setName(name).
setCount(count).
setSynopsis(synopsis).
setFileName(file.getOriginalFilename()).
setFileUrl(url).
setCategoryId(categoryId).
setFileHash(SecureUtil.md5(file.getInputStream()));
Integer id = commemorateNftService.publish(commemorateNft);
return ResponseModel.success(id);
}
@Authentication
@PostMapping("/receive")
@ApiOperation(value = "领取纪念版nft")
public ResponseModel<Boolean> receive(@RequestParam Integer id) {
Boolean result = commemorateNftService.receive(id);
return ResponseModel.success();
}
}
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