Commit da3689dd authored by tangtuo's avatar tangtuo

Merge branch 'dev_1.0.0' into test_v1.0.0

parents 3bf7e4f6 0e238e12
......@@ -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";
}
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.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* @author tangtuo
* @date 2021/6/30 15:42
*/
@Data
@ApiModel("纪念版nft信息")
@Accessors(chain = true)
@TableName("tb_commemorate_nft")
public class CommemorateNft {
@TableId(type = IdType.AUTO)
private Integer id;
@NotNull(message = "类目id不能为空")
@ApiModelProperty("类目id")
private Integer categoryId;
@ApiModelProperty("用户id")
private Integer userId;
@ApiModelProperty("发行人地址")
private String publishAddress;
@NotBlank(message = "名称不能为空")
@Length(max = 20, message = "名称最大长度为20")
@ApiModelProperty("名称")
private String name;
@ApiModelProperty("封面")
private String cover;
@NotBlank(message = "简介不能为空")
@Length(max = 500, message = "简介最大长度为500")
@ApiModelProperty("简介")
private String synopsis;
@ApiModelProperty("文件名")
private String fileName;
@ApiModelProperty("文件地址--用户选择不存档的情况下为空")
private String fileUrl;
@NotBlank(message = "作品哈希不能为空")
@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;
@ApiModelProperty("创建时间")
private Date createDate;
@ApiModelProperty("修改时间")
private Date updateDate;
}
......@@ -82,10 +82,16 @@ public class Nft extends BaseEntity {
@ApiModelProperty("nft发行时间")
private Date publishTime;
@ApiModelProperty("交易转让hash")
private String transferHash;
@ApiModelProperty("是否置顶 0-否 1-是")
private Integer isTop;
@ApiModelProperty("0-下架 1-上架")
private Integer status;
@ApiModelProperty("是否是纪念版nft 0-否 1-是")
private Integer isCommemorate;
}
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.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* @author tangtuo
* @date 2021/6/30 15:42
*/
@Data
@ApiModel("纪念版nft上链信息")
@Accessors(chain = true)
@TableName("tb_commemorate_nft_chain_info")
public class NftChainInfo {
@TableId(type = IdType.AUTO)
private Integer id;
@ApiModelProperty("纪念版nft主键")
private Integer commemorateNftId;
@ApiModelProperty("nft编号")
private String nftNum;
@ApiModelProperty("nft哈希")
private String nftHash;
@ApiModelProperty("nft token")
private Long tokenId;
@ApiModelProperty("nft发行时间")
private Date publishTime;
@ApiModelProperty("是否已被领取 0-否 1-是")
private Integer isReceive;
}
......@@ -23,6 +23,9 @@ public class CollectionNftVo {
@ApiModelProperty("名称")
private String name;
@ApiModelProperty("封面")
private String cover;
@ApiModelProperty("主题,多个用逗号,隔开")
private String theme;
......@@ -35,5 +38,6 @@ public class CollectionNftVo {
this.nftId = nft.getNftId();
this.category = category.getCategoryName();
this.name = nft.getName();
this.cover = nft.getCover();
}
}
package com.fzm.common.entity.vo;
import cn.hutool.core.date.DateUtil;
import com.fzm.common.entity.CommemorateNft;
import com.fzm.common.entity.Nft;
import com.fzm.common.entity.User;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* @author tangtuo
* @date 2021/7/1 10:35
*/
@Data
public class CommemorateNftVo {
@ApiModelProperty("主键")
private Integer id;
@ApiModelProperty("类目")
private String category;
@ApiModelProperty("名称")
private String name;
@ApiModelProperty("封面")
private String cover;
@ApiModelProperty("发行人")
private String publisher;
@ApiModelProperty("头像")
private String avatar;
@ApiModelProperty("钱包地址")
private String publishAddress;
@ApiModelProperty("发行个数")
private Integer publishCount;
@ApiModelProperty("已领取个数")
private Integer receiveCount;
@ApiModelProperty("发行时间")
private Date publishTime;
@ApiModelProperty("简介")
private String synopsis;
@ApiModelProperty("nft哈希")
private String nftHash;
@ApiModelProperty("0-当前用户已领取 1-纪念版nft还未领取完 2-纪念版nft已领取完")
private Integer status;
public CommemorateNftVo(CommemorateNft nft, User user) {
this.id = nft.getId();
this.name = nft.getName();
this.avatar = user.getAvatar();
this.publishAddress = nft.getPublishAddress();
this.publishCount = nft.getCount();
this.publisher = user.getNickname();
this.nftHash = nft.getNftHash();
this.publishTime = nft.getPublishTime();
this.synopsis = nft.getSynopsis();
this.cover = nft.getCover();
}
}
......@@ -52,7 +52,7 @@ public class NftCertificateVo {
this.id = nft.getId();
this.publisher = user.getNickname();
this.publishTime = nft.getPublishTime();
this.wallet=user.getWallet();
this.wallet=nft.getPublishAddress();
this.qrCode = qrCode;
this.examineStatus = 0;
this.copyrightStatus = 0;
......
package com.fzm.common.entity.vo;
import cn.hutool.core.date.DateUtil;
import com.fzm.common.entity.Nft;
import com.fzm.common.entity.User;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author tangtuo
* @date 2021/7/1 10:35
*/
@Data
public class NftTransferVo {
@ApiModelProperty("nft主键")
private Integer id;
@ApiModelProperty("nft名称")
private String name;
@ApiModelProperty("转出人的用户id")
private Integer userId;
@ApiModelProperty("转出人的头像")
private String avatar;
@ApiModelProperty("转出人的昵称")
private String nickname;
@ApiModelProperty("转出人的钱包地址")
private String wallet;
@ApiModelProperty("nft编号")
private String nftId;
public NftTransferVo(Nft nft, User user) {
this.id = nft.getId();
this.name = nft.getName();
this.userId = user.getId();
this.avatar = user.getAvatar();
this.wallet = user.getWallet();
this.nickname = user.getNickname();
this.nftId=nft.getNftId();
}
}
package com.fzm.common.mapper;
import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fzm.common.entity.CommemorateNft;
import com.fzm.common.entity.Nft;
import com.fzm.common.entity.vo.CollectionNftVo;
import com.fzm.common.entity.vo.NftListVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author tangtuo
* @date 2021/6/30 15:54
*/
@Mapper
public interface CommemorateNftMapper extends BaseMapper<CommemorateNft> {
}
package com.fzm.common.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fzm.common.entity.NftChainInfo;
import org.apache.ibatis.annotations.Mapper;
/**
* @author tangtuo
* @date 2021/6/30 15:54
*/
@Mapper
public interface NftChainInfoMapper extends BaseMapper<NftChainInfo> {
}
package com.fzm.common.params;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* @author tangtuo
* @date 2021/7/21 17:45
*/
@Data
public class NftTransferParam {
@ApiModelProperty("nft主键")
@NotNull(message = "nft主键不能为空")
private Integer id;
@ApiModelProperty("验证码")
@NotBlank(message = "验证码不能为空")
private String code;
@ApiModelProperty("短信验证码类型 sms-短信 email-邮箱 voice-语音")
@NotNull(message = "短信验证码类型不能为空")
private String codeType;
@ApiModelProperty("接收人地址")
@NotBlank(message = "接收人地址不能为空")
private String receiveWallet;
@ApiModelProperty("接收人")
@NotBlank(message = "接收人不能为空")
private String receiveNickname;
@ApiModelProperty("数量")
@NotNull(message = "数量不能为空")
private Integer count;
}
package com.fzm.common.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.fzm.common.entity.Admin;
import com.fzm.common.entity.CommemorateNft;
/**
* @author tangtuo
* @date 2021/7/5 15:08
*/
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;
import com.baomidou.mybatisplus.extension.service.IService;
import com.fzm.common.entity.NftChainInfo;
/**
* @author tangtuo
* @date 2021/7/5 15:08
*/
public interface NftChainInfoService extends IService<NftChainInfo> {
}
......@@ -5,6 +5,7 @@ import com.fzm.common.entity.Nft;
import com.fzm.common.entity.NftDto;
import com.fzm.common.entity.vo.CollectionNftVo;
import com.fzm.common.entity.vo.NftListVo;
import com.fzm.common.params.NftTransferParam;
import com.github.pagehelper.PageInfo;
import java.util.List;
......@@ -126,4 +127,12 @@ public interface NftService extends IService<Nft> {
* @return
*/
Boolean publish(NftDto nftDto);
/**
* nft转让
*
* @param param
* @return
*/
Boolean transfer(NftTransferParam param);
}
......@@ -61,7 +61,6 @@ public interface UserService extends IService<User> {
UserStatisticVo getStatistic();
/**
*
* @param telephone
* @param nickname
* @param authType
......@@ -70,4 +69,12 @@ public interface UserService extends IService<User> {
* @return
*/
List<UserListVo> list(String telephone, String nickname, Integer authType, String start, String end);
/**
* 根据钱包地址查询用户信息
*
* @param publishAddress
* @return
*/
User getUserByWallet(String publishAddress);
}
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.*;
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领取失败");
}
// 确认转让结果
TxResult txResult = paraChainClient.cycleConfirmTxWithHash(hash, true, 1000);
if (!TxStatusEnum.SUCCESS.equals(txResult.getStatus())) {
// 领取失败要释放信号量
semaphore.release();
throw GlobalException.newException(ResultCode.PUBLISH_ERROR, txResult.getErrMsg().getValue());
}
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.setTransferHash(hash);
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));
}
}
package com.fzm.common.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fzm.common.entity.NftChainInfo;
import com.fzm.common.mapper.NftChainInfoMapper;
import com.fzm.common.service.NftChainInfoService;
import org.springframework.stereotype.Service;
/**
* @author tangtuo
* @date 2021/7/5 15:09
*/
@Service
public class NftChainInfoServiceImpl extends ServiceImpl<NftChainInfoMapper, NftChainInfo> implements NftChainInfoService {
}
......@@ -17,14 +17,13 @@ import com.fzm.common.entity.vo.NftListVo;
import com.fzm.common.enums.ResultCode;
import com.fzm.common.exception.GlobalException;
import com.fzm.common.mapper.NftMapper;
import com.fzm.common.params.NftTransferParam;
import com.fzm.common.properties.SmsProperties;
import com.fzm.common.service.CategoryService;
import com.fzm.common.service.CollectionService;
import com.fzm.common.service.NftService;
import com.fzm.common.service.UserService;
import com.fzm.common.utils.JsonUtil;
import com.fzm.common.utils.JwtUtil;
import com.fzm.common.utils.OssUtil;
import com.fzm.common.utils.RedisUtil;
import com.fzm.common.utils.*;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
......@@ -71,6 +70,11 @@ public class NftServiceImpl extends ServiceImpl<NftMapper, Nft> implements NftSe
private OssUtil ossUtil;
@Resource
private SmsUtil smsUtil;
private SmsProperties smsProperties;
@Resource
private HttpServletRequest request;
@Value("${chain.para.contract-name}")
......@@ -94,12 +98,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发行失败");
}
......@@ -138,6 +142,46 @@ public class NftServiceImpl extends ServiceImpl<NftMapper, Nft> implements NftSe
return true;
}
@Override
public Boolean transfer(NftTransferParam param) {
Nft nft = getById(param.getId());
if (nft == null) {
throw GlobalException.newException(ResultCode.DATA_ERROR, "没找到此nft详情");
}
// 转出人的个人信息
User user = userService.getUserByToken();
if (!nft.getUserId().equals(user.getId())) {
throw GlobalException.newException(ResultCode.FORBIDDEN, "您无权转让他人的nft");
}
// 校验短信验证码
// todo 现在用的是登录验证码模板,后续需要修改短信模板
if (!smsUtil.validateCode(smsProperties.getMessageLoginCodetype(), user.getTelephone(), param.getCode(), param.getCodeType())) {
throw GlobalException.newException(ResultCode.FAILED, "短信验证码校验失败");
}
// 校验接收人的个人信息
User receiveUser = userService.getUserByWallet(param.getReceiveWallet());
if (receiveUser == null) {
throw GlobalException.newException(ResultCode.FAILED, "接手人非本系统注册用户,暂不支持转让");
}
// 转让nft
String hash = paraChainClient.evmTransferNFT1155(contractName, user.getWallet(), null, param.getReceiveWallet(), nft.getTokenId(), param.getCount(), true);
if (StringUtils.isBlank(hash)) {
throw GlobalException.newException(ResultCode.FAILED, "nft领取失败");
}
// 确认转让结果
TxResult txResult = paraChainClient.cycleConfirmTxWithHash(hash, true, 1000);
if (!TxStatusEnum.SUCCESS.equals(txResult.getStatus())) {
throw GlobalException.newException(ResultCode.PUBLISH_ERROR, txResult.getErrMsg().getValue());
}
// 修改nft的拥有者用户id
Nft transferNft = new Nft().
setUserId(receiveUser.getId()).
setTransferHash(hash);
transferNft.setId(nft.getId());
updateById(transferNft);
return true;
}
public Boolean checkResult(String nftHash) {
TxResult txResult = paraChainClient.confirmTxWithGrpTxHash(nftHash);
if (TxStatusEnum.RUNNING.equals(txResult.getStatus())) {
......@@ -214,7 +258,7 @@ public class NftServiceImpl extends ServiceImpl<NftMapper, Nft> implements NftSe
if (categoryId != null) {
queryWrapper.eq("category_id", categoryId);
}
queryWrapper.orderByDesc("is_top", "publish_time");
queryWrapper.orderByDesc("publish_time");
return nftMapper.selectList(queryWrapper);
}
......
......@@ -193,6 +193,13 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
}
@Override
public User getUserByWallet(String publishAddress) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("wallet", publishAddress);
return getOne(queryWrapper);
}
@Override
public List<UserListVo> list(String telephone, String nickname, Integer authType, String start, String end) {
DateTime startDate = null;
DateTime endDate = null;
......
......@@ -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.constant.RedisConstant;
import com.fzm.common.entity.CommemorateNft;
import com.fzm.common.entity.Label;
import com.fzm.common.entity.User;
import com.fzm.common.entity.vo.CommemorateNftVo;
import com.fzm.common.enums.ResultCode;
import com.fzm.common.exception.GlobalException;
import com.fzm.common.model.ResponseModel;
import com.fzm.common.service.CategoryService;
import com.fzm.common.service.CommemorateNftService;
import com.fzm.common.service.LabelService;
import com.fzm.common.service.UserService;
import com.fzm.common.utils.JwtUtil;
import com.fzm.common.utils.OssUtil;
import com.fzm.common.utils.RedisUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
/**
* @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;
@Resource
private UserService userService;
@Resource
private CategoryService categoryService;
@Resource
private RedissonClient redisson;
@Resource
private RedisUtil redisUtil;
@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) MultipartFile cover,
@ApiParam(value = "发行数量", required = true) Integer count) throws IOException {
if (file == null || cover == null) {
throw GlobalException.newException(ResultCode.VALIDATE_FAILED, "文件不能为空");
}
String coverName = cover.getOriginalFilename().toLowerCase();
if (!coverName.endsWith(".png") && !coverName.endsWith(".jpg")) {
throw GlobalException.newException(ResultCode.FILE_UPLOAD_ERROR, "封面类型有误");
}
String fileUrl = ossUtil.putSimpleObject(file);
String coverUrl = ossUtil.putSimpleObject(cover);
CommemorateNft commemorateNft = new CommemorateNft().
setName(name).
setCover(coverUrl).
setCount(count).
setSynopsis(synopsis).
setFileName(file.getOriginalFilename()).
setFileUrl(fileUrl).
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(result);
}
@Authentication
@GetMapping("/get/{id}")
@ApiOperation(value = "纪念版nft详情页")
public ResponseModel<CommemorateNftVo> getById(@PathVariable Integer id, @RequestHeader String Authorization) {
CommemorateNft nft = commemorateNftService.getById(id);
if (nft == null) {
throw GlobalException.newException(ResultCode.DATA_ERROR, "此纪念版nft已下架");
}
User user = userService.getById(nft.getUserId());
CommemorateNftVo commemorateNftVo = new CommemorateNftVo(nft, user);
commemorateNftVo.setCategory(categoryService.getById(nft.getCategoryId()).getCategoryName());
RSemaphore semaphore = redisson.getSemaphore(RedisConstant.COMMEMORATE_NFT_PREFIX + id);
int permits = semaphore.availablePermits();
commemorateNftVo.setReceiveCount(nft.getCount() - permits);
Boolean receive = redisUtil.sIsMember(RedisConstant.COMMEMORATE_NFT_MEMBERS_PREFIX + id, JwtUtil.getUserIdFromToken(Authorization).toString());
// 当前用户已领取
if (receive) {
commemorateNftVo.setStatus(0);
} else {
// 未领取完毕
if (commemorateNftVo.getPublishCount() > commemorateNftVo.getReceiveCount()) {
commemorateNftVo.setStatus(1);
} else {
commemorateNftVo.setStatus(2);
}
}
return ResponseModel.success(commemorateNftVo);
}
@GetMapping("/list")
@ApiOperation(value = "首页banner页(纪念版nft列表)")
public ResponseModel<List<CommemorateNft>> list() {
return ResponseModel.success(commemorateNftService.list());
}
}
......@@ -4,22 +4,22 @@ import cn.hutool.crypto.SecureUtil;
import com.fzm.common.annotation.Authentication;
import com.fzm.common.constant.RedisConstant;
import com.fzm.common.constant.SystemConstant;
import com.fzm.common.constant.TokenConstant;
import com.fzm.common.entity.Nft;
import com.fzm.common.entity.NftDto;
import com.fzm.common.entity.User;
import com.fzm.common.entity.vo.CollectionNftVo;
import com.fzm.common.entity.vo.NftCertificateVo;
import com.fzm.common.entity.vo.NftTransferVo;
import com.fzm.common.entity.vo.NftVo;
import com.fzm.common.enums.ResultCode;
import com.fzm.common.exception.GlobalException;
import com.fzm.common.model.ResponseModel;
import com.fzm.common.params.NftTransferParam;
import com.fzm.common.service.CategoryService;
import com.fzm.common.service.NftService;
import com.fzm.common.service.UserService;
import com.fzm.common.utils.JwtUtil;
import com.fzm.common.utils.OssUtil;
import com.fzm.common.utils.QRCodeUtil;
import com.fzm.common.utils.RedisUtil;
import com.fzm.common.utils.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
......@@ -48,9 +48,6 @@ import java.util.stream.Collectors;
public class NftController {
@Resource
private OssUtil ossUtil;
@Resource
private NftService nftService;
@Resource
......@@ -111,16 +108,19 @@ public class NftController {
if (nft == null) {
throw GlobalException.newException(ResultCode.DATA_ERROR, "没找到此nft的详情");
}
User user = userService.getById(nft.getUserId());
User user = userService.getUserByWallet(nft.getPublishAddress());
if (user == null) {
throw GlobalException.newException(ResultCode.DATA_ERROR, "没找到此nft的发布人的信息");
}
NftVo nftVo = new NftVo(nft, user);
nftVo.setCategory(categoryService.getById(nft.getCategoryId()).getCategoryName());
if (StringUtils.isNotBlank(Authorization)) {
Integer userId = JwtUtil.getUserIdFromToken(Authorization);
Boolean collection = redisUtil.sIsMember(RedisConstant.COLLECTION_USER_PREFIX + userId, id.toString());
nftVo.setCollection(collection);
String realToken = Authorization.substring(TokenConstant.TOKEN_PREFIX.length());
if (StringUtils.isNotBlank(realToken) && !"null".equals(realToken)) {
Integer userId = JwtUtil.getUserIdFromToken(Authorization);
Boolean collection = redisUtil.sIsMember(RedisConstant.COLLECTION_USER_PREFIX + userId, id.toString());
nftVo.setCollection(collection);
}
}
return ResponseModel.success(nftVo);
}
......@@ -128,14 +128,23 @@ public class NftController {
@Authentication
@GetMapping("/list/current")
@ApiOperation(value = "获取我的nft列表")
public ResponseModel<Map<String, Object>> listCurrent(@ApiParam(value = "类目id,查询全部的时候传null") @RequestParam(required = false) Integer categoryId) {
List<Nft> list = nftService.listCurrent(categoryId, JwtUtil.getUserIdFromToken(request.getHeader("Authorization")));
public ResponseModel<Map<String, Object>> listCurrent(@ApiParam(value = "类目id,查询全部的时候传null") @RequestParam(required = false) Integer categoryId) throws Exception {
Integer userId = JwtUtil.getUserIdFromToken(request.getHeader("Authorization"));
List<Nft> list = nftService.listCurrent(categoryId, userId);
List<CollectionNftVo> nftVoList = list.stream()
.map(nft -> new CollectionNftVo(nft, categoryService.getCategoryById(nft.getCategoryId())))
.collect(Collectors.toList());
HashMap<String, Object> result = new HashMap<>(4);
User user = userService.getById(userId);
// 生成二维码
HashMap<String, Object> qrCodeMap = new HashMap<>();
qrCodeMap.put("nickname", user.getNickname());
qrCodeMap.put("avatar", user.getAvatar());
qrCodeMap.put("wallet", user.getWallet());
String qrCode = QRCodeUtil.encode(JsonUtil.toJson(qrCodeMap), null, false);
HashMap<String, Object> result = new HashMap<>(8);
result.put("list", nftVoList);
result.put("size", nftVoList.size());
result.put("qrCode", qrCode);
return ResponseModel.success(result);
}
......@@ -168,7 +177,7 @@ public class NftController {
if (!nft.getUserId().equals(userId)) {
throw GlobalException.newException(ResultCode.FORBIDDEN, "您无权查看别人的nft证书");
}
User user = userService.getById(userId);
User user = userService.getUserByWallet(nft.getPublishAddress());
String qrCode = QRCodeUtil.encode(PATH, null, false);
NftCertificateVo vo = new NftCertificateVo(nft, user, qrCode);
return ResponseModel.success(vo);
......@@ -180,4 +189,26 @@ public class NftController {
public void download(@ApiParam(value = "nft主键") @PathVariable Integer id) {
nftService.download(id);
}
@Authentication
@ApiOperation(value = "查询nft转出人的个人信息")
@GetMapping("/transfer/user")
public ResponseModel<NftTransferVo> getTransferUserInfo(@RequestParam Integer id) {
Nft nft = nftService.getById(id);
if (nft == null) {
throw GlobalException.newException(ResultCode.DATA_ERROR, "没有找到此nft的详情信息,请稍后再试");
}
User user = userService.getById(nft.getUserId());
return ResponseModel.success(new NftTransferVo(nft, user));
}
@Authentication
@ApiOperation(value = "转让nft")
@PostMapping("/transfer")
public ResponseModel<Boolean> transfer(@RequestBody @Validated NftTransferParam param) {
Boolean result = nftService.transfer(param);
return ResponseModel.success(result);
}
}
......@@ -6,10 +6,13 @@ import com.fzm.common.utils.OssUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
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.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.Map;
/**
......@@ -31,4 +34,11 @@ public class OssController {
Map<String, String> policy = ossUtil.policy();
return ResponseModel.success(policy);
}
@Authentication
@PostMapping("/upload")
@ApiOperation("普通文件上传")
public ResponseModel<String> upload(MultipartFile file) throws IOException {
return ResponseModel.success(ossUtil.putSimpleObject(file));
}
}
......@@ -137,4 +137,11 @@ public class UserController {
return ResponseModel.success();
}
@Authentication
@ApiOperation("根据钱包地址获取用户详情")
@GetMapping("/getUserByWallet")
public ResponseModel<User> getUserByWallet(@RequestParam String wallet) {
User user = userService.getUserByWallet(wallet);
return ResponseModel.success(user);
}
}
package com.fzm.portal.controller;
import com.fzm.common.annotation.Authentication;
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.properties.SmsProperties;
import com.fzm.common.service.UserService;
import com.fzm.common.utils.SmsUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
......@@ -26,12 +30,14 @@ import javax.annotation.Resource;
public class VerificationCodeController {
@Resource
private UserService userService;
@Resource
private SmsProperties smsProperties;
@Resource
private SmsUtil sendSms;
private SmsUtil smsUtil;
@PostMapping(value = "/send/sms")
......@@ -41,7 +47,19 @@ public class VerificationCodeController {
@ApiImplicitParam(name = "codetype", value = "短信模板, 1:登录短信 2:修改密码 3:修改手机号"),
})
public ResponseModel<Boolean> sendSms(@RequestParam String telephone, @RequestParam Integer codetype) {
return ResponseModel.success(sendSms.sendSms(getCodeType(codetype), telephone));
return ResponseModel.success(smsUtil.sendSms(getCodeType(codetype), telephone));
}
@Authentication
@ApiOperation("发送转让nft的短信")
@PostMapping("/send/Sms/transferNft")
public ResponseModel<Boolean> sendTransferNftSms() {
User user = userService.getUserByToken();
if (user == null || StringUtils.isBlank(user.getTelephone())) {
throw GlobalException.newException(ResultCode.UNAUTHORIZED, "当前用户的手机号为空");
}
Boolean result = smsUtil.sendSms(smsProperties.getMessageLoginCodetype(), user.getTelephone());
return ResponseModel.success(result);
}
......
......@@ -3,6 +3,8 @@ package com.fzm.portal;
import cn.hutool.crypto.SecureUtil;
import java.io.File;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
/**
* @author tangtuo
......@@ -11,10 +13,6 @@ import java.io.File;
public class FileTest {
public static void main(String[] args) {
File file = new File("C:\\Users\\tangtuo\\Pictures\\微信图片_20210208094951.jpg");
String s = SecureUtil.md5(file);
System.out.println(s);
}
}
......@@ -2,9 +2,14 @@ package com.fzm.portal;
import cn.fzm.chain.simplesdk.client.ParaChainClient;
import com.fzm.common.constant.RedisConstant;
import com.fzm.common.enums.ResultCode;
import com.fzm.common.exception.GlobalException;
import com.fzm.common.utils.JsonUtil;
import com.fzm.common.utils.RedisUtil;
import org.junit.jupiter.api.Test;
import org.redisson.Redisson;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
......@@ -28,9 +33,23 @@ class LyPortalApplicationTests {
@Resource
ParaChainClient paraClient;
@Resource
RedissonClient redisson;
@Test
void contextLoads() {
System.out.println(redisUtil.sIsMember(RedisConstant.COLLECTION_USER_PREFIX + 9, "2"));
System.out.println("redisson = " + redisson);
RSemaphore semaphore = redisson.getSemaphore("banner09");
boolean b = semaphore.trySetPermits(10);
for (int i = 0; i < 3; i++) {
boolean acquire = semaphore.tryAcquire();
if (!acquire) {
throw GlobalException.newException(ResultCode.VALIDATE_FAILED);
}
//System.out.println("semaphore.drainPermits() = " + semaphore.drainPermits());
System.out.println("semaphore.availablePermits() = " + semaphore.availablePermits());
}
}
}
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