package com.izouma.nineth.service; import com.alibaba.excel.util.StringUtils; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.TypeReference; import com.google.zxing.WriterException; import com.izouma.nineth.config.RedisKeys; import com.izouma.nineth.domain.Asset; import com.izouma.nineth.domain.DomainOrder; import com.izouma.nineth.domain.FileObject; import com.izouma.nineth.domain.User; import com.izouma.nineth.dto.PageQuery; import com.izouma.nineth.dto.excel.DomainCountDTO; import com.izouma.nineth.enums.AssetStatus; import com.izouma.nineth.enums.CollectionStatus; import com.izouma.nineth.enums.OrderStatus; import com.izouma.nineth.enums.PayMethod; import com.izouma.nineth.exception.BusinessException; import com.izouma.nineth.repo.AssetRepo; import com.izouma.nineth.repo.DomainOrderRepo; import com.izouma.nineth.repo.UserRepo; import com.izouma.nineth.service.storage.StorageService; import com.izouma.nineth.utils.ImageUtils; import com.izouma.nineth.utils.JpaUtils; import com.izouma.nineth.utils.SecurityUtils; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.cache.annotation.Cacheable; import org.springframework.data.annotation.Transient; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.redis.core.BoundValueOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.util.*; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Matcher; import java.util.regex.Pattern; @Service @AllArgsConstructor @Slf4j public class DomainOrderService { private DomainOrderRepo domainOrderRepo; private ContentAuditService contentAuditService; private UserRepo userRepo; private AssetService assetService; private SysConfigService sysConfigService; private StorageService storageService; private RockRecordService rockRecordService; private AssetRepo assetRepo; private RedisTemplate redisTemplate; private CacheService cacheService; public Page all(PageQuery pageQuery) { return domainOrderRepo .findAll(JpaUtils.toSpecification(pageQuery, DomainOrder.class), JpaUtils.toPageRequest(pageQuery)); } @Cacheable(value = "newestDomain") public Page newest() { PageRequest pageRequest = PageRequest.of(0, 50); return domainOrderRepo.findAllByOrderStatusOrderByCreatedAtDesc(OrderStatus.FINISH, pageRequest); } public boolean isContainChinese(String str) { if (StringUtils.isEmpty(str)) { throw new BusinessException("sms context is empty!"); } Pattern p = Pattern.compile("[\u4E00-\u9FA5|\\!|\\,|\\。|\\(|\\)|\\《|\\》|\\“|\\”|\\?|\\:|\\;|\\【|\\】]"); Matcher m = p.matcher(str); if (m.find()) { return true; } return false; } public DomainOrder create(Long userId, String domain, BigDecimal price, Long year) { AtomicBoolean checkPoint = checkPoint(userId); List notPaidOrders = domainOrderRepo.findAllByUserIdAndOrderStatus(userId, OrderStatus.NOT_PAID); Long superUserId = Long.valueOf(sysConfigService.getString("domain_superUserId")); int min = sysConfigService.getInt("domain_minimum"); min = min + 4; if (notPaidOrders.size() > 0) { throw new BusinessException("已存在未支付订单,不可继续下单"); } if (domain.contains(".uni")) { throw new BusinessException("域名后缀不符合规定."); } if (!superUserId.equals(SecurityUtils.getAuthenticatedUser().getId())) { if (isContainChinese(domain)) { throw new BusinessException("禁止注册中文域名"); } if (!checkPoint.get()) { if (domain.length() < min || domain.length() > 20) { throw new BusinessException("四位及以下域名只能官方创建。"); } } else { if (domain.length() < 8 || domain.length() > 20) { throw new BusinessException("四位以下域名只能官方创建。"); } } } String realName; int dotIndex = domain.indexOf("."); realName = domain.substring(0, dotIndex); Map checkResult = check(realName); if (!(Boolean) checkResult.get("result")) { throw new BusinessException(checkResult.get("reason").toString()); } BigDecimal singlePrice = sysConfigService.getBigDecimal("domain_price"); if (singlePrice.multiply(BigDecimal.valueOf(year)).compareTo(price) != 0) { throw new BusinessException("价格不符"); } // LocalDateTime startTime = LocalDateTime.of(2023, 2, 10, 17, 0, 0); // if (LocalDateTime.now().isBefore(startTime)) { // throw new BusinessException("时间不符"); // } // if (price.compareTo(BigDecimal.valueOf(40L)) != 0) { // throw new BusinessException("订单价格与配置不符,请重新下单."); // } User user = userRepo.findById(userId).orElseThrow(new BusinessException("未找到用户")); if (domain.contains(".")) { int dotIndex1 = domain.indexOf("."); domain = domain.substring(0, dotIndex1); } DomainOrder domainOrder = new DomainOrder(); // domainOrder.setPic(Collections.singletonList(fileObject)); domainOrder.setPicName(domain); domainOrder.setPrice(price); domainOrder.setDomainName((domain + ".nft").toLowerCase()); domainOrder.setYears(year); domainOrder.setStatus(CollectionStatus.PENDING); domainOrder.setOrderStatus(OrderStatus.NOT_PAID); domainOrder.setUserId(user.getId()); domainOrder.setUserAvatar(user.getAvatar()); domainOrder.setUserName(user.getNickname()); if (checkPoint.get()) { if (realName.length() < 5) { increaseCount(userId, 1); } } return domainOrderRepo.save(domainOrder); } public void increaseCount(Long userId, Integer usePoint) { if (usePoint > 0) { // 扣除积分 userRepo.addVipPoint(userId, -usePoint); cacheService.clearUserMy(userId); } } public void decreaseCount(DomainOrder order) { userRepo.addVipPoint(order.getUserId(), 1); cacheService.clearUserMy(order.getUserId()); log.info("取消加积分用户ID:{},订单ID:{},积分:{}", order.getUserId(), order.getId(), 1); } public AtomicBoolean checkPoint(Long userId) { AtomicBoolean atomicBoolean = new AtomicBoolean(false); User user = userRepo.findById(userId).orElseThrow(new BusinessException("用户不存在")); if (user.getVipPoint() > 0) { atomicBoolean.set(true); } return atomicBoolean; // Map collections = JSONObject.parseObject(sysConfigService // .getString("domain_collection"), new TypeReference>() { // }); // if (collections.size() == 0) { // return new AtomicBoolean(false); // } // List statuses = new ArrayList<>(); // statuses.add(AssetStatus.NORMAL); // statuses.add(AssetStatus.AUCTIONING); // AtomicBoolean vipPoint = new AtomicBoolean(false); // collections.forEach((k, v) -> { // List assets = assetRepo.findAllByCollectionIdAndStatusInAndUserId(k, statuses, userId); // if (assets.size() > 0) { // BoundValueOperations ops = redisTemplate.boundValueOps(RedisKeys.DOMAIN_COUNT + userId); // Integer count = (Integer) ops.get(); // if (count != null) { // if (count > 0) { // vipPoint.set(true); // } // } else { // vipPoint.set(false); // } // } // }); // return vipPoint; } public Map check(String domain) { int min = sysConfigService.getInt("domain_minimum"); min = min + 4; AtomicBoolean checkPoint = checkPoint(SecurityUtils.getAuthenticatedUser().getId()); Map result = new HashMap<>(); Long superUserId = Long.valueOf(sysConfigService.getString("domain_superUserId")); String visibleDomain = domain; if (domain.contains(".uni")) { result.put("result", false); result.put("reason", "禁止使用.uni"); return result; } if (!domain.contains(".nft")) { visibleDomain = domain + ".nft"; } List keywords = Arrays.asList(sysConfigService.getString("domain_keyword").split(",")); if (!superUserId.equals(SecurityUtils.getAuthenticatedUser().getId())) { if (keywords.stream().anyMatch(keyword -> org.apache.commons.lang.StringUtils.equals(keyword, domain))) { result.put("result", false); result.put("reason", "包含敏感关键字"); return result; } if (!checkPoint.get()) { if (visibleDomain.length() < min || visibleDomain.length() > 20) { result.put("result", false); result.put("reason", "域名长度不合规"); return result; } } else { if (visibleDomain.length() < 8 || visibleDomain.length() > 20) { result.put("result", false); result.put("reason", "域名长度不合规"); return result; } } if (!contentAuditService.auditText(domain)) { result.put("result", false); result.put("reason", "该域名内容不合规"); return result; } } Integer count = domainOrderRepo .countAllByDomainNameEqualsAndOrderStatusNot(visibleDomain, OrderStatus.CANCELLED); if (count > 0) { result.put("result", false); result.put("reason", "该域名已被注册"); return result; } result.put("result", true); result.put("reason", "可以注册"); return result; } public List> search(String domain) { if (domain.contains(".")) { int dotIndex = domain.indexOf("."); domain = domain.substring(0, dotIndex); } Pageable pageable = PageRequest.of(0, 10, Sort.by("createdAt").descending()); List used = domainOrderRepo.searchUsedDomain("%" + domain + "%", OrderStatus.CANCELLED, pageable) .getContent(); String n = domain.substring(domain.length() - 1); List> recommend = new ArrayList<>(); for (int i = 0; i < 100; i++) { if (i != 0) { domain = domain + n; } Map checkResult = check(domain); if ((Boolean) checkResult.get("result")) { Map sold = new HashMap<>(); sold.put("domain", (domain + ".nft").toLowerCase()); sold.put("sold", false); recommend.add(sold); } if (recommend.size() > 2) { break; } } List> result = new ArrayList<>(recommend); used.forEach(domainOrder -> { Map sold = new HashMap<>(); if (!domainOrder.getDomainName().contains(".uni")) { sold.put("domain", domainOrder.getDomainName().toLowerCase()); sold.put("endTime", domainOrder.getEndTime()); sold.put("sold", true); result.add(sold); } }); return result; } @Transient public void notify(Long id, PayMethod payMethod, String transactionId) throws FontFormatException, IOException, WriterException { DomainOrder domainOrder = domainOrderRepo.findById(id).orElseThrow(new BusinessException("未找到星图")); if (!domainOrder.getOrderStatus().equals(OrderStatus.NOT_PAID)) { throw new BusinessException("订单已经处理"); } BufferedImage img = domainImg(domainOrder.getDomainName()); ByteArrayOutputStream os = new ByteArrayOutputStream(); ImageIO.write(img, "jpg", os); InputStream input = new ByteArrayInputStream(os.toByteArray()); String path = "image/" + new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()) + RandomStringUtils.randomAlphabetic(8) + ".jpg"; String realUrl = storageService.uploadFromInputStream(input, path); FileObject fileObject = new FileObject(); fileObject.setName(domainOrder.getDomainName()); fileObject.setType("image/jpeg"); fileObject.setUrl(realUrl); domainOrder.setOrderStatus(OrderStatus.FINISH); domainOrder.setPayMethod(payMethod); domainOrder.setPic(Collections.singletonList(fileObject)); domainOrder.setTransactionId(transactionId); domainOrder.setStatus(CollectionStatus.SUCCESS); domainOrder.setCreateAssetId(createAsset(domainOrder)); domainOrder.setEndTime(LocalDateTime.now().plusYears(domainOrder.getYears())); domainOrderRepo.save(domainOrder); rockRecordService.addRock(domainOrder.getUserId(), domainOrder.getPrice(), "购买"); } public void cancel(DomainOrder domainOrder) { domainOrder.setOrderStatus(OrderStatus.CANCELLED); domainOrder.setStatus(CollectionStatus.FAIL); if (domainOrder.getPicName().length() < 5) { decreaseCount(domainOrder); } domainOrderRepo.save(domainOrder); } public Long createAsset(DomainOrder domainOrder) { return assetService.createAsset(domainOrder, userRepo.findById(domainOrder.getUserId()) .orElseThrow(new BusinessException("无用户记录")), null, domainOrder.getPrice(), "域名", null, false).getId(); } public BufferedImage domainImg(String domain) throws IOException, FontFormatException, WriterException { String domainName; if (domain.contains(".")) { int dotIndex = domain.indexOf("."); domainName = domain.substring(0, dotIndex).toUpperCase(); } else { domainName = domain.toUpperCase(); } InputStream is1 = this.getClass() .getResourceAsStream("/font/VonwaonBitmap_16pxLite.ttf"); Font font1 = Font.createFont(Font.TRUETYPE_FONT, is1); is1.close(); InputStream is2 = this.getClass() .getResourceAsStream("/font/VonwaonBitmap_12pxLite.ttf"); Font font2 = Font.createFont(Font.TRUETYPE_FONT, is2); is2.close(); int length = domainName.length(); BufferedImage shareImg; if (length <= 2) { InputStream is3 = this.getClass().getResourceAsStream("/static/img/png_jing.png"); shareImg = ImageIO.read(is3); is3.close(); } else if (length <= 4) { InputStream is3 = this.getClass().getResourceAsStream("/static/img/png_lv.png"); shareImg = ImageIO.read(is3); is3.close(); } else { InputStream is3 = this.getClass().getResourceAsStream("/static/img/png_zi.png"); shareImg = ImageIO.read(is3); is3.close(); } BufferedImage result = new BufferedImage(shareImg.getWidth(), shareImg.getHeight(), BufferedImage.TYPE_INT_RGB); Graphics2D g = result.createGraphics(); g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); // g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g.setComposite(AlphaComposite.SrcOver); g.drawImage(shareImg, 0, 0, null); // BufferedImage avatarImg = ImageUtils.makeRoundedCorner(ImageUtils.scale(ImageIO.read(new URL(user.getAvatar())), // 80, 80, // ImageUtils.Fit.COVER), 40); // g.drawImage(avatarImg, 334, 136, null); int domainLength = domainName.length(); if (domainLength > 10) { g.setColor(new Color(255, 255, 255)); Font topFont = font1.deriveFont(Font.PLAIN, 130f); Font downFont = font2.deriveFont(Font.BOLD, 36f); int subIndex = domainLength / 3; String str1 = domainName.substring(0, subIndex); String str2 = domainName.substring(subIndex, subIndex + subIndex); String str3 = domainName.substring(subIndex + subIndex, domainLength); ImageUtils.drawCenteredString(g, str1, new Rectangle(0, 180, shareImg .getWidth(), 86), topFont); ImageUtils.drawCenteredString(g, str2, new Rectangle(0, 300, shareImg .getWidth(), 86), topFont); ImageUtils.drawCenteredString(g, str3, new Rectangle(0, 420, shareImg .getWidth(), 86), topFont); ImageUtils.drawCenteredString(g, ".NFT", new Rectangle(0, 540, shareImg .getWidth(), 86), topFont); g.setColor(new Color(255, 255, 255)); ImageUtils.drawCenteredString(g, domain, new Rectangle(0, 650, shareImg .getWidth(), 12), downFont); } if (domainLength > 5 & domainLength <= 10) { g.setColor(new Color(255, 255, 255)); Font topFont = font1.deriveFont(Font.PLAIN, 190f); Font downFont = font2.deriveFont(Font.BOLD, 36f); int subIndex = domainLength / 2; String str1 = domainName.substring(0, subIndex); String str2 = domainName.substring(subIndex, domainLength); ImageUtils.drawCenteredString(g, str1, new Rectangle(0, 180, shareImg .getWidth(), 86), topFont); ImageUtils.drawCenteredString(g, str2, new Rectangle(0, 350, shareImg .getWidth(), 86), topFont); ImageUtils.drawCenteredString(g, ".NFT", new Rectangle(0, 520, shareImg .getWidth(), 86), topFont); g.setColor(new Color(255, 255, 255)); ImageUtils.drawCenteredString(g, domain, new Rectangle(0, 650, shareImg .getWidth(), 12), downFont); } if (domainLength <= 5) { g.setColor(new Color(255, 255, 255)); Font topFont = font1.deriveFont(Font.PLAIN, 240f); Font downFont = font2.deriveFont(Font.BOLD, 36f); ImageUtils.drawCenteredString(g, domainName, new Rectangle(17, 220, shareImg .getWidth(), 86), topFont); ImageUtils.drawCenteredString(g, ".NFT", new Rectangle(-10, 420, shareImg .getWidth(), 86), topFont); g.setColor(new Color(255, 255, 255)); ImageUtils.drawCenteredString(g, domain, new Rectangle(0, 620, shareImg .getWidth(), 12), downFont); } //二维码 // QRCodeWriter qrCodeWriter = new QRCodeWriter(); // Map hints = new HashMap<>(); // hints.put(EncodeHintType.MARGIN, 2); // BitMatrix bitMatrix = qrCodeWriter // .encode(env.getProperty("general.host") + "/wx/share?invitor=" + user.getId(), // BarcodeFormat.QR_CODE, 252, 252, hints); // g.drawImage(MatrixToImageWriter.toBufferedImage(bitMatrix), 250, 386, null); return result; } public List top20() { List> map = assetRepo.domainTop20(); JSONArray jsonArray = new JSONArray(); jsonArray.addAll(map); return jsonArray.toJavaList(DomainCountDTO.class); } }