DomainOrderService.java 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. package com.izouma.nineth.service;
  2. import com.alibaba.excel.util.StringUtils;
  3. import com.alibaba.fastjson.JSONArray;
  4. import com.google.zxing.WriterException;
  5. import com.izouma.nineth.config.GeneralProperties;
  6. import com.izouma.nineth.config.RedisKeys;
  7. import com.izouma.nineth.domain.Asset;
  8. import com.izouma.nineth.domain.Collection;
  9. import com.izouma.nineth.domain.DomainOrder;
  10. import com.izouma.nineth.domain.FileObject;
  11. import com.izouma.nineth.domain.User;
  12. import com.izouma.nineth.dto.PageQuery;
  13. import com.izouma.nineth.dto.excel.DomainCountDTO;
  14. import com.izouma.nineth.dto.nftdomain.DomainResult;
  15. import com.izouma.nineth.dto.nftdomain.DomainTop;
  16. import com.izouma.nineth.enums.*;
  17. import com.izouma.nineth.event.OrderNotifyEvent;
  18. import com.izouma.nineth.exception.BusinessException;
  19. import com.izouma.nineth.repo.*;
  20. import com.izouma.nineth.service.storage.StorageService;
  21. import com.izouma.nineth.utils.ImageUtils;
  22. import com.izouma.nineth.utils.JpaUtils;
  23. import com.izouma.nineth.utils.SecurityUtils;
  24. import com.sun.xml.bind.v2.TODO;
  25. import lombok.AllArgsConstructor;
  26. import lombok.extern.slf4j.Slf4j;
  27. import org.apache.commons.lang3.RandomStringUtils;
  28. import org.apache.rocketmq.spring.core.RocketMQTemplate;
  29. import org.springframework.cache.annotation.Cacheable;
  30. import org.springframework.data.annotation.Transient;
  31. import org.springframework.data.domain.Page;
  32. import org.springframework.data.domain.PageRequest;
  33. import org.springframework.data.domain.Pageable;
  34. import org.springframework.data.domain.Sort;
  35. import org.springframework.data.redis.core.BoundValueOperations;
  36. import org.springframework.data.redis.core.RedisTemplate;
  37. import org.springframework.scheduling.annotation.Scheduled;
  38. import org.springframework.stereotype.Service;
  39. import javax.imageio.ImageIO;
  40. import java.awt.*;
  41. import java.awt.image.BufferedImage;
  42. import java.io.ByteArrayInputStream;
  43. import java.io.ByteArrayOutputStream;
  44. import java.io.IOException;
  45. import java.io.InputStream;
  46. import java.math.BigDecimal;
  47. import java.text.SimpleDateFormat;
  48. import java.time.LocalDateTime;
  49. import java.util.*;
  50. import java.util.List;
  51. import java.util.concurrent.TimeUnit;
  52. import java.util.concurrent.atomic.AtomicBoolean;
  53. import java.util.regex.Matcher;
  54. import java.util.regex.Pattern;
  55. import static com.izouma.nineth.enums.HyperLinkType.COLLECTION;
  56. @Service
  57. @AllArgsConstructor
  58. @Slf4j
  59. public class DomainOrderService {
  60. private DomainOrderRepo domainOrderRepo;
  61. private ContentAuditService contentAuditService;
  62. private UserRepo userRepo;
  63. private AssetService assetService;
  64. private SysConfigService sysConfigService;
  65. private StorageService storageService;
  66. private RockRecordService rockRecordService;
  67. private AssetRepo assetRepo;
  68. private RedisTemplate<String, Object> redisTemplate;
  69. private CacheService cacheService;
  70. private UserBalanceService userBalanceService;
  71. private GeneralProperties generalProperties;
  72. private RocketMQTemplate rocketMQTemplate;
  73. private OrderRepo orderRepo;
  74. private CollectionRepo collectionRepo;
  75. public Page<DomainOrder> all(PageQuery pageQuery) {
  76. return domainOrderRepo
  77. .findAll(JpaUtils.toSpecification(pageQuery, DomainOrder.class), JpaUtils.toPageRequest(pageQuery));
  78. }
  79. @Cacheable(value = "newestDomain")
  80. public List<DomainOrder> newest() {
  81. PageRequest pageRequest = PageRequest.of(0, 50);
  82. return domainOrderRepo.findAllByOrderStatusOrderByCreatedAtDesc(OrderStatus.FINISH, pageRequest).getContent();
  83. }
  84. public boolean isContainChinese(String str) {
  85. if (StringUtils.isEmpty(str)) {
  86. throw new BusinessException("sms context is empty!");
  87. }
  88. boolean canChinese = sysConfigService.getBoolean("domain_sc");
  89. Pattern p;
  90. if (!canChinese) {
  91. p = Pattern.compile("[\u4E00-\u9FA5|\\!|\\,|\\。|\\(|\\)|\\《|\\》|\\“|\\”|\\?|\\:|\\;|\\【|\\】]");
  92. } else {
  93. p = Pattern.compile("[\\!|\\,|\\。|\\(|\\)|\\《|\\》|\\“|\\”|\\?|\\:|\\;|\\【|\\】]");
  94. }
  95. Matcher m = p.matcher(str);
  96. return m.find();
  97. }
  98. public DomainOrder create(Long userId, String domain, BigDecimal price, Long year) {
  99. AtomicBoolean checkPoint = checkPoint(userId);
  100. List<DomainOrder> notPaidOrders = domainOrderRepo.findAllByUserIdAndOrderStatus(userId, OrderStatus.NOT_PAID);
  101. Long superUserId = Long.valueOf(sysConfigService.getString("domain_superUserId"));
  102. int min = sysConfigService.getInt("domain_minimum");
  103. min = min + 4;
  104. if (notPaidOrders.size() > 0) {
  105. throw new BusinessException("已存在未支付订单,不可继续下单");
  106. }
  107. if (domain.contains(".uni")) {
  108. throw new BusinessException("域名后缀不符合规定.");
  109. }
  110. if (!superUserId.equals(SecurityUtils.getAuthenticatedUser().getId())) {
  111. if (isContainChinese(domain)) {
  112. throw new BusinessException("禁止注册中文域名");
  113. }
  114. if (!checkPoint.get()) {
  115. if (domain.length() < min || domain.length() > 20) {
  116. throw new BusinessException("四位及以下域名只能官方创建。");
  117. }
  118. } else {
  119. if (domain.length() < 6 || domain.length() > 20) {
  120. throw new BusinessException("四位以下域名只能官方创建。");
  121. }
  122. }
  123. }
  124. String realName;
  125. int dotIndex = domain.indexOf(".");
  126. realName = domain.substring(0, dotIndex);
  127. Map<String, Object> checkResult = check(realName);
  128. if (!(Boolean) checkResult.get("result")) {
  129. throw new BusinessException(checkResult.get("reason").toString());
  130. }
  131. BigDecimal singlePrice = sysConfigService.getBigDecimal("domain_price");
  132. if (singlePrice.multiply(BigDecimal.valueOf(year)).compareTo(price) != 0) {
  133. throw new BusinessException("价格不符");
  134. }
  135. // LocalDateTime startTime = LocalDateTime.of(2023, 2, 10, 17, 0, 0);
  136. // if (LocalDateTime.now().isBefore(startTime)) {
  137. // throw new BusinessException("时间不符");
  138. // }
  139. // if (price.compareTo(BigDecimal.valueOf(40L)) != 0) {
  140. // throw new BusinessException("订单价格与配置不符,请重新下单.");
  141. // }
  142. User user = userRepo.findById(userId).orElseThrow(new BusinessException("未找到用户"));
  143. if (domain.contains(".")) {
  144. int dotIndex1 = domain.indexOf(".");
  145. domain = domain.substring(0, dotIndex1);
  146. }
  147. DomainOrder domainOrder = new DomainOrder();
  148. // domainOrder.setPic(Collections.singletonList(fileObject));
  149. // domain = domain.replaceAll("[^a-zA-Z0-9\\u4E00-\\u9FA5]", "");
  150. domainOrder.setPicName(domain);
  151. domainOrder.setPrice(price);
  152. domainOrder.setDomainName((domain + ".nft").toLowerCase());
  153. domainOrder.setYears(year);
  154. domainOrder.setStatus(CollectionStatus.PENDING);
  155. domainOrder.setOrderStatus(OrderStatus.NOT_PAID);
  156. domainOrder.setUserId(user.getId());
  157. domainOrder.setUserAvatar(user.getAvatar());
  158. domainOrder.setUserName(user.getNickname());
  159. if (checkPoint.get()) {
  160. if (realName.length() < 5) {
  161. increaseCount(userId, 1);
  162. }
  163. }
  164. return domainOrderRepo.save(domainOrder);
  165. }
  166. public void increaseCount(Long userId, Integer usePoint) {
  167. if (usePoint > 0) {
  168. // 扣除积分
  169. userRepo.addVipPoint(userId, -usePoint);
  170. cacheService.clearUserMy(userId);
  171. }
  172. }
  173. public void decreaseCount(DomainOrder order) {
  174. userRepo.addVipPoint(order.getUserId(), 1);
  175. cacheService.clearUserMy(order.getUserId());
  176. log.info("取消加积分用户ID:{},订单ID:{},积分:{}", order.getUserId(), order.getId(), 1);
  177. }
  178. public AtomicBoolean checkPoint(Long userId) {
  179. AtomicBoolean atomicBoolean = new AtomicBoolean(false);
  180. // User user = userRepo.findById(userId).orElseThrow(new BusinessException("用户不存在"));
  181. // if (user.getVipPoint() > 0) {
  182. // atomicBoolean.set(true);
  183. // }
  184. return atomicBoolean;
  185. // Map<Long, Long> collections = JSONObject.parseObject(sysConfigService
  186. // .getString("domain_collection"), new TypeReference<HashMap<Long, Long>>() {
  187. // });
  188. // if (collections.size() == 0) {
  189. // return new AtomicBoolean(false);
  190. // }
  191. // List<AssetStatus> statuses = new ArrayList<>();
  192. // statuses.add(AssetStatus.NORMAL);
  193. // statuses.add(AssetStatus.AUCTIONING);
  194. // AtomicBoolean vipPoint = new AtomicBoolean(false);
  195. // collections.forEach((k, v) -> {
  196. // List<Asset> assets = assetRepo.findAllByCollectionIdAndStatusInAndUserId(k, statuses, userId);
  197. // if (assets.size() > 0) {
  198. // BoundValueOperations<String, Object> ops = redisTemplate.boundValueOps(RedisKeys.DOMAIN_COUNT + userId);
  199. // Integer count = (Integer) ops.get();
  200. // if (count != null) {
  201. // if (count > 0) {
  202. // vipPoint.set(true);
  203. // }
  204. // } else {
  205. // vipPoint.set(false);
  206. // }
  207. // }
  208. // });
  209. // return vipPoint;
  210. }
  211. public Map<String, Object> check(String domain) {
  212. int min = sysConfigService.getInt("domain_minimum");
  213. min = min + 4;
  214. AtomicBoolean checkPoint = checkPoint(SecurityUtils.getAuthenticatedUser().getId());
  215. Map<String, Object> result = new HashMap<>();
  216. Long superUserId = Long.valueOf(sysConfigService.getString("domain_superUserId"));
  217. String visibleDomain = domain;
  218. if (isContainChinese(domain)) {
  219. result.put("result", false);
  220. result.put("reason", "禁止使用中文");
  221. return result;
  222. }
  223. if (domain.contains(".uni")) {
  224. result.put("result", false);
  225. result.put("reason", "禁止使用.uni");
  226. return result;
  227. }
  228. if (!domain.contains(".nft")) {
  229. visibleDomain = domain + ".nft";
  230. }
  231. List<String> keywords = Arrays.asList(sysConfigService.getString("domain_keyword").split(","));
  232. if (!superUserId.equals(SecurityUtils.getAuthenticatedUser().getId())) {
  233. if (keywords.stream().anyMatch(keyword -> org.apache.commons.lang.StringUtils.equals(keyword, domain))) {
  234. result.put("result", false);
  235. result.put("reason", "包含敏感关键字");
  236. return result;
  237. }
  238. if (!checkPoint.get()) {
  239. if (visibleDomain.length() < min || visibleDomain.length() > 20) {
  240. result.put("result", false);
  241. result.put("reason", "域名长度不合规");
  242. return result;
  243. }
  244. } else {
  245. if (visibleDomain.length() < 6 || visibleDomain.length() > 20) {
  246. result.put("result", false);
  247. result.put("reason", "域名长度不合规");
  248. return result;
  249. }
  250. }
  251. if (!contentAuditService.auditText(domain)) {
  252. result.put("result", false);
  253. result.put("reason", "该域名内容不合规");
  254. return result;
  255. }
  256. }
  257. Integer count = domainOrderRepo
  258. .countAllByDomainNameEqualsAndOrderStatusNot(visibleDomain, OrderStatus.CANCELLED);
  259. if (count > 0) {
  260. result.put("result", false);
  261. result.put("reason", "该域名已被注册");
  262. return result;
  263. }
  264. result.put("result", true);
  265. result.put("reason", "可以注册");
  266. return result;
  267. }
  268. public List<Map<String, Object>> search(String domain) {
  269. if (domain.contains(".")) {
  270. int dotIndex = domain.indexOf(".");
  271. domain = domain.substring(0, dotIndex);
  272. }
  273. // domain = domain.replaceAll("[^a-zA-Z0-9\\u4E00-\\u9FA5]", "");
  274. Pageable pageable = PageRequest.of(0, 3, Sort.by("createdAt").descending());
  275. List<DomainOrder> used = new ArrayList<>();
  276. used.addAll(domainOrderRepo.searchUsedDomain("%" + domain + "%", OrderStatus.CANCELLED, pageable)
  277. .getContent());
  278. DomainOrder first = domainOrderRepo
  279. .findFirstByDomainNameAndOrderStatus(domain + ".nft", OrderStatus.FINISH);
  280. if (first != null) {
  281. if (!used.contains(first)) {
  282. used.add(first);
  283. }
  284. }
  285. String n = domain.substring(domain.length() - 1);
  286. List<Map<String, Object>> recommend = new ArrayList<>();
  287. for (int i = 0; i < 100; i++) {
  288. if (i != 0) {
  289. domain = domain + n;
  290. }
  291. Map<String, Object> checkResult = check(domain);
  292. if ((Boolean) checkResult.get("result")) {
  293. Map<String, Object> sold = new HashMap<>();
  294. sold.put("domain", (domain + ".nft").toLowerCase());
  295. sold.put("sold", false);
  296. recommend.add(sold);
  297. }
  298. if (recommend.size() > 2) {
  299. break;
  300. }
  301. }
  302. List<Map<String, Object>> result = new ArrayList<>(recommend);
  303. used.forEach(domainOrder -> {
  304. boolean b = domainOrder.isOpenHyperLink();
  305. Map<String, Object> sold = new HashMap<>();
  306. if (!domainOrder.getDomainName().contains(".uni")) {
  307. Asset asset = assetRepo
  308. .findFirstByNameAndStatus("RID元宇宙域名 " + domainOrder.getDomainName(), AssetStatus.NORMAL);
  309. if (asset != null) {
  310. if (asset.isConsignment()) {
  311. sold.put("canAsk", false);
  312. sold.put("collectionId", asset.getPublicCollectionId());
  313. } else {
  314. if (asset.isPublicShow()) {
  315. sold.put("collectionId", asset.getPublicCollectionId());
  316. }
  317. sold.put("canAsk", true);
  318. }
  319. sold.put("id", domainOrder.getId());
  320. sold.put("domain", domainOrder.getDomainName().toLowerCase());
  321. sold.put("endTime", domainOrder.getEndTime());
  322. sold.put("sold", true);
  323. sold.put("isOpenHyperLink", domainOrder.isOpenHyperLink());
  324. if (domainOrder.getHyperLinkType() == COLLECTION) {
  325. String url = domainOrder.getAddress();
  326. int secondSlashIndex = url.indexOf('/', url.indexOf('/') + 1);
  327. String secondNumber = url.substring(secondSlashIndex + 1);
  328. if (org.apache.commons.lang3.StringUtils.isNotBlank(secondNumber)) {
  329. Optional<Collection> collection = collectionRepo.findById(Long.parseLong(secondNumber));
  330. if (collection.isPresent()) {
  331. // 对象非空的情况
  332. sold.put("isOpenHyperLink", domainOrder.isOpenHyperLink());
  333. // 其他操作
  334. } else {
  335. // 对象为空的情况
  336. sold.put("isOpenHyperLink", false);
  337. // 其他操作
  338. }
  339. }
  340. }
  341. if (domainOrder.getHyperLinkType() != null) {
  342. sold.put("HyperLinkType", domainOrder.getHyperLinkType());
  343. }
  344. if (domainOrder.getAddress() != null) {
  345. sold.put("Address", domainOrder.getAddress());
  346. }
  347. result.add(sold);
  348. }
  349. }
  350. });
  351. return result;
  352. }
  353. @Transient
  354. public void notify(Long id, PayMethod payMethod, String transactionId) throws FontFormatException, IOException, WriterException {
  355. // 取消订单与订单回调不能同时进行,需要抢锁
  356. if (!getOrderLock(id)) {
  357. log.info("订单回调失败 orderId: {} redis锁定, 重新发送到队列", id);
  358. rocketMQTemplate.syncSend(generalProperties.getOrderNotifyTopic(),
  359. new OrderNotifyEvent(id, payMethod, transactionId, System.currentTimeMillis()));
  360. return;
  361. }
  362. DomainOrder domainOrder = domainOrderRepo.findById(id).orElseThrow(new BusinessException("未找到星图"));
  363. if (!domainOrder.getOrderStatus().equals(OrderStatus.NOT_PAID)) {
  364. throw new BusinessException("订单已经处理");
  365. }
  366. BufferedImage img = domainImg(domainOrder.getDomainName());
  367. ByteArrayOutputStream os = new ByteArrayOutputStream();
  368. ImageIO.write(img, "jpg", os);
  369. InputStream input = new ByteArrayInputStream(os.toByteArray());
  370. String path = "image/" + new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date())
  371. + RandomStringUtils.randomAlphabetic(8) + ".jpg";
  372. String realUrl = storageService.uploadFromInputStream(input, path);
  373. FileObject fileObject = new FileObject();
  374. fileObject.setName(domainOrder.getDomainName());
  375. fileObject.setType("image/jpeg");
  376. fileObject.setUrl(realUrl);
  377. domainOrder.setOrderStatus(OrderStatus.FINISH);
  378. domainOrder.setPayMethod(payMethod);
  379. domainOrder.setPic(Collections.singletonList(fileObject));
  380. domainOrder.setTransactionId(transactionId);
  381. // domainOrder.setStatus(CollectionStatus.SUCCESS);
  382. domainOrder.setCreateAssetId(createAsset(domainOrder));
  383. domainOrder.setEndTime(LocalDateTime.now().plusYears(domainOrder.getYears()));
  384. domainOrderRepo.save(domainOrder);
  385. rockRecordService.addRock(domainOrder.getUserId(), domainOrder.getPrice(), "购买");
  386. releaseOrderLock(id);
  387. }
  388. public void cancel(DomainOrder domainOrder) {
  389. log.info("尝试取消订单 {}", domainOrder.getId());
  390. // 取消订单与订单回调不能同时进行,需要抢锁
  391. if (!getOrderLock(domainOrder.getId())) {
  392. log.error("订单取消失败 {}, redis锁了", domainOrder.getId());
  393. return;
  394. }
  395. domainOrder.setOrderStatus(OrderStatus.CANCELLED);
  396. domainOrder.setStatus(CollectionStatus.FAIL);
  397. if (domainOrder.getPicName().length() < 5) {
  398. decreaseCount(domainOrder);
  399. }
  400. domainOrderRepo.save(domainOrder);
  401. releaseOrderLock(domainOrder.getId());
  402. }
  403. public Long createAsset(DomainOrder domainOrder) {
  404. return assetService.createAsset(domainOrder, userRepo.findById(domainOrder.getUserId())
  405. .orElseThrow(new BusinessException("无用户记录")), null, domainOrder
  406. .getPrice(), "域名", null, false).getId();
  407. }
  408. public BufferedImage domainImg(String domain) throws IOException, FontFormatException, WriterException {
  409. String domainName;
  410. if (domain.contains(".")) {
  411. int dotIndex = domain.indexOf(".");
  412. domainName = domain.substring(0, dotIndex).toUpperCase();
  413. } else {
  414. domainName = domain.toUpperCase();
  415. }
  416. Pattern p;
  417. p = Pattern.compile("[\u4E00-\u9FA5|\\!|\\,|\\。|\\(|\\)|\\《|\\》|\\“|\\”|\\?|\\:|\\;|\\【|\\】]");
  418. Matcher m = p.matcher(domain);
  419. boolean chinese = m.find();
  420. Font font1;
  421. Font font2;
  422. if (!chinese) {
  423. InputStream is1 = this.getClass()
  424. .getResourceAsStream("/font/VonwaonBitmap_16pxLite.ttf");
  425. font1 = Font.createFont(Font.TRUETYPE_FONT, is1);
  426. is1.close();
  427. InputStream is2 = this.getClass()
  428. .getResourceAsStream("/font/VonwaonBitmap_12pxLite.ttf");
  429. font2 = Font.createFont(Font.TRUETYPE_FONT, is2);
  430. is2.close();
  431. } else {
  432. InputStream is1 = this.getClass()
  433. .getResourceAsStream("/font/尔雅荣耀手书.ttf");
  434. font1 = Font.createFont(Font.TRUETYPE_FONT, is1);
  435. is1.close();
  436. InputStream is2 = this.getClass()
  437. .getResourceAsStream("/font/尔雅荣耀手书.ttf");
  438. font2 = Font.createFont(Font.TRUETYPE_FONT, is2);
  439. is2.close();
  440. }
  441. int length = domainName.length();
  442. BufferedImage shareImg;
  443. if (chinese) {
  444. InputStream is3 = this.getClass().getResourceAsStream("/static/img/png_baijiaxing.png");
  445. shareImg = ImageIO.read(is3);
  446. is3.close();
  447. } else {
  448. if (length == 1) {
  449. InputStream is3 = this.getClass().getResourceAsStream("/static/img/png_jing.png");
  450. shareImg = ImageIO.read(is3);
  451. is3.close();
  452. } else if (length == 2) {
  453. InputStream is3 = this.getClass().getResourceAsStream("/static/img/png_lv.png");
  454. shareImg = ImageIO.read(is3);
  455. is3.close();
  456. } else if (length == 3) {
  457. InputStream is3 = this.getClass().getResourceAsStream("/static/img/png_b.png");
  458. shareImg = ImageIO.read(is3);
  459. is3.close();
  460. } else if (length == 4) {
  461. InputStream is3 = this.getClass().getResourceAsStream("/static/img/png_h.png");
  462. shareImg = ImageIO.read(is3);
  463. is3.close();
  464. } else {
  465. InputStream is3 = this.getClass().getResourceAsStream("/static/img/png_zi.png");
  466. shareImg = ImageIO.read(is3);
  467. is3.close();
  468. }
  469. }
  470. BufferedImage result = new BufferedImage(shareImg.getWidth(), shareImg.getHeight(), BufferedImage.TYPE_INT_RGB);
  471. Graphics2D g = result.createGraphics();
  472. g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
  473. // g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  474. // g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
  475. g.setComposite(AlphaComposite.SrcOver);
  476. g.drawImage(shareImg, 0, 0, null);
  477. // BufferedImage avatarImg = ImageUtils.makeRoundedCorner(ImageUtils.scale(ImageIO.read(new URL(user.getAvatar())),
  478. // 80, 80,
  479. // ImageUtils.Fit.COVER), 40);
  480. // g.drawImage(avatarImg, 334, 136, null);
  481. int domainLength = domainName.length();
  482. if (chinese) {
  483. g.setColor(new Color(255, 241, 187));
  484. Font topFont = font1.deriveFont(Font.PLAIN, 180f);
  485. Font downFont = font2.deriveFont(Font.PLAIN, 30f);
  486. ImageUtils.drawCenteredString(g, domainName, new Rectangle(5, 200, shareImg
  487. .getWidth(), 86), topFont);
  488. ImageUtils.drawCenteredString(g, ".NFT", new Rectangle(-10, 370, shareImg
  489. .getWidth(), 86), topFont);
  490. g.setColor(new Color(255, 255, 255));
  491. ImageUtils.drawCenteredString(g, domain, new Rectangle(0, 600, shareImg
  492. .getWidth(), 12), downFont);
  493. } else {
  494. if (domainLength > 10) {
  495. g.setColor(new Color(255, 255, 255));
  496. Font topFont = font1.deriveFont(Font.PLAIN, 130f);
  497. Font downFont = font2.deriveFont(Font.BOLD, 36f);
  498. int subIndex = domainLength / 3;
  499. String str1 = domainName.substring(0, subIndex);
  500. String str2 = domainName.substring(subIndex, subIndex + subIndex);
  501. String str3 = domainName.substring(subIndex + subIndex, domainLength);
  502. ImageUtils.drawCenteredString(g, str1, new Rectangle(0, 180, shareImg
  503. .getWidth(), 86), topFont);
  504. ImageUtils.drawCenteredString(g, str2, new Rectangle(0, 300, shareImg
  505. .getWidth(), 86), topFont);
  506. ImageUtils.drawCenteredString(g, str3, new Rectangle(0, 420, shareImg
  507. .getWidth(), 86), topFont);
  508. ImageUtils.drawCenteredString(g, ".NFT", new Rectangle(0, 540, shareImg
  509. .getWidth(), 86), topFont);
  510. g.setColor(new Color(255, 255, 255));
  511. ImageUtils.drawCenteredString(g, domain, new Rectangle(0, 650, shareImg
  512. .getWidth(), 12), downFont);
  513. }
  514. if (domainLength > 5 & domainLength <= 10) {
  515. g.setColor(new Color(255, 255, 255));
  516. Font topFont = font1.deriveFont(Font.PLAIN, 190f);
  517. Font downFont = font2.deriveFont(Font.BOLD, 36f);
  518. int subIndex = domainLength / 2;
  519. String str1 = domainName.substring(0, subIndex);
  520. String str2 = domainName.substring(subIndex, domainLength);
  521. ImageUtils.drawCenteredString(g, str1, new Rectangle(0, 180, shareImg
  522. .getWidth(), 86), topFont);
  523. ImageUtils.drawCenteredString(g, str2, new Rectangle(0, 350, shareImg
  524. .getWidth(), 86), topFont);
  525. ImageUtils.drawCenteredString(g, ".NFT", new Rectangle(0, 520, shareImg
  526. .getWidth(), 86), topFont);
  527. g.setColor(new Color(255, 255, 255));
  528. ImageUtils.drawCenteredString(g, domain, new Rectangle(0, 650, shareImg
  529. .getWidth(), 12), downFont);
  530. }
  531. if (domainLength <= 5) {
  532. g.setColor(new Color(255, 255, 255));
  533. Font topFont = font1.deriveFont(Font.PLAIN, 240f);
  534. Font downFont = font2.deriveFont(Font.BOLD, 36f);
  535. ImageUtils.drawCenteredString(g, domainName, new Rectangle(17, 220, shareImg
  536. .getWidth(), 86), topFont);
  537. ImageUtils.drawCenteredString(g, ".NFT", new Rectangle(-10, 420, shareImg
  538. .getWidth(), 86), topFont);
  539. g.setColor(new Color(255, 255, 255));
  540. ImageUtils.drawCenteredString(g, domain, new Rectangle(0, 620, shareImg
  541. .getWidth(), 12), downFont);
  542. }
  543. }
  544. //二维码
  545. // QRCodeWriter qrCodeWriter = new QRCodeWriter();
  546. // Map<EncodeHintType, Object> hints = new HashMap<>();
  547. // hints.put(EncodeHintType.MARGIN, 2);
  548. // BitMatrix bitMatrix = qrCodeWriter
  549. // .encode(env.getProperty("general.host") + "/wx/share?invitor=" + user.getId(),
  550. // BarcodeFormat.QR_CODE, 252, 252, hints);
  551. // g.drawImage(MatrixToImageWriter.toBufferedImage(bitMatrix), 250, 386, null);
  552. return result;
  553. }
  554. public List<DomainCountDTO> top20() {
  555. List<Map<String, Object>> map = assetRepo.domainTop20();
  556. JSONArray jsonArray = new JSONArray();
  557. jsonArray.addAll(map);
  558. return jsonArray.toJavaList(DomainCountDTO.class);
  559. }
  560. // 获取订单锁,有效时间1小时
  561. public boolean getOrderLock(Long orderId) {
  562. BoundValueOperations<String, Object> ops = redisTemplate.boundValueOps(RedisKeys.DOMAIN_LOCK + orderId);
  563. Boolean flag = ops.setIfAbsent(1, 1, TimeUnit.HOURS);
  564. return Boolean.TRUE.equals(flag);
  565. }
  566. // 释放订单锁
  567. public void releaseOrderLock(Long orderId) {
  568. redisTemplate.delete(RedisKeys.DOMAIN_LOCK + orderId);
  569. }
  570. public void pass(Long id) {
  571. domainOrderRepo.findById(id).ifPresent(domainOrder -> {
  572. domainOrder.setStatus(CollectionStatus.SUCCESS);
  573. assetRepo.findById(domainOrder.getCreateAssetId()).ifPresent(asset1 -> {
  574. asset1.setStatus(AssetStatus.NORMAL);
  575. domainOrderRepo.save(domainOrder);
  576. assetRepo.save(asset1);
  577. });
  578. });
  579. }
  580. public void deny(Long id, String result) {
  581. domainOrderRepo.findById(id).ifPresent(domainOrder -> {
  582. domainOrder.setStatus(CollectionStatus.FAIL);
  583. domainOrder.setOrderStatus(OrderStatus.CANCELLED);
  584. domainOrder.setResult(result);
  585. assetRepo.findById(domainOrder.getCreateAssetId()).ifPresent(asset1 -> {
  586. asset1.setStatus(AssetStatus.DESTROYED);
  587. domainOrderRepo.save(domainOrder);
  588. assetRepo.save(asset1);
  589. });
  590. //退款
  591. userBalanceService.addBalance(domainOrder.getUserId(), domainOrder.getPrice(), domainOrder
  592. .getId(), BalanceType.REFUND);
  593. });
  594. }
  595. @Scheduled(cron = "0 0/5 9-20 * * ?")
  596. public void batchPass() {
  597. long time = sysConfigService.getInt("domain_pendingTime");
  598. LocalDateTime lastTime = LocalDateTime.now().minusHours(time - 1);
  599. List<DomainOrder> domainOrders = domainOrderRepo
  600. .findAllByStatusAndCreatedAtBeforeAndOrderStatus(CollectionStatus.PENDING, lastTime, OrderStatus.FINISH);
  601. domainOrders.forEach(domainOrder -> {
  602. try {
  603. pass(domainOrder.getId());
  604. } catch (Exception e) {
  605. log.info("自动通过出错" + domainOrder.getDomainName());
  606. }
  607. });
  608. }
  609. public List<DomainResult> newestOrder() {
  610. List<Map<String, Object>> map = orderRepo.newestDomainOrder();
  611. JSONArray jsonArray = new JSONArray();
  612. jsonArray.addAll(map);
  613. return jsonArray.toJavaList(DomainResult.class);
  614. }
  615. public List<DomainTop> domainTop() {
  616. List<Map<String, Object>> map = assetRepo
  617. .domainBuyerTop60(LocalDateTime.now().minusDays(7L), LocalDateTime.now());
  618. JSONArray jsonArray = new JSONArray();
  619. jsonArray.addAll(map);
  620. List<DomainTop> domainTops = jsonArray.toJavaList(DomainTop.class);
  621. domainTops.forEach(domainTop -> {
  622. if (domainTop.getUserId() == 14644) {
  623. domainTop.setCountNum(domainTop.getCountNum() + 200);
  624. }
  625. });
  626. return domainTops;
  627. }
  628. public void addHyperLink(Long assetId, boolean openHyperLink, HyperLinkType hyperLinkType, String address) {
  629. // 获取目标资产
  630. Asset asset = assetRepo.findByIdAndStatus(assetId, AssetStatus.NORMAL)
  631. .orElseThrow(() -> new BusinessException("未找到具有指定ID的正常状态资产"));
  632. // 获取目标域名,并通过 Optional 避免可能的 NullPointerException
  633. String domainName = Optional.ofNullable(asset.getName())
  634. .filter(n -> n.length() >= 9)
  635. .map(n -> n.substring(9))
  636. .orElseThrow(() -> new BusinessException("无法获取资产的域名信息"));
  637. // 获取目标订单
  638. DomainOrder domainOrder = domainOrderRepo.findFirstByDomainNameAndOrderStatus(domainName, OrderStatus.FINISH);
  639. // 更新订单信息
  640. domainOrder.setOpenHyperLink(openHyperLink);
  641. domainOrder.setHyperLinkType(openHyperLink ? hyperLinkType : null);
  642. domainOrder.setAddress(openHyperLink ? address : null);
  643. domainOrder.setCurrentOwnerId(openHyperLink ? SecurityUtils.getAuthenticatedUser().getId() : null);
  644. domainOrderRepo.save(domainOrder);
  645. }
  646. }