DomainOrderService.java 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  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.domain.DomainOrder;
  6. import com.izouma.nineth.domain.FileObject;
  7. import com.izouma.nineth.domain.User;
  8. import com.izouma.nineth.dto.PageQuery;
  9. import com.izouma.nineth.dto.excel.DomainCountDTO;
  10. import com.izouma.nineth.enums.CollectionStatus;
  11. import com.izouma.nineth.enums.OrderStatus;
  12. import com.izouma.nineth.enums.PayMethod;
  13. import com.izouma.nineth.exception.BusinessException;
  14. import com.izouma.nineth.repo.AssetRepo;
  15. import com.izouma.nineth.repo.DomainOrderRepo;
  16. import com.izouma.nineth.repo.UserRepo;
  17. import com.izouma.nineth.service.storage.StorageService;
  18. import com.izouma.nineth.utils.ImageUtils;
  19. import com.izouma.nineth.utils.JpaUtils;
  20. import com.izouma.nineth.utils.SecurityUtils;
  21. import lombok.AllArgsConstructor;
  22. import lombok.extern.slf4j.Slf4j;
  23. import org.apache.commons.lang3.RandomStringUtils;
  24. import org.springframework.cache.annotation.Cacheable;
  25. import org.springframework.data.annotation.Transient;
  26. import org.springframework.data.domain.Page;
  27. import org.springframework.data.domain.PageRequest;
  28. import org.springframework.data.domain.Pageable;
  29. import org.springframework.data.domain.Sort;
  30. import org.springframework.data.redis.core.RedisTemplate;
  31. import org.springframework.stereotype.Service;
  32. import javax.imageio.ImageIO;
  33. import java.awt.*;
  34. import java.awt.image.BufferedImage;
  35. import java.io.ByteArrayInputStream;
  36. import java.io.ByteArrayOutputStream;
  37. import java.io.IOException;
  38. import java.io.InputStream;
  39. import java.math.BigDecimal;
  40. import java.text.SimpleDateFormat;
  41. import java.time.LocalDateTime;
  42. import java.util.*;
  43. import java.util.List;
  44. import java.util.concurrent.atomic.AtomicBoolean;
  45. import java.util.regex.Matcher;
  46. import java.util.regex.Pattern;
  47. @Service
  48. @AllArgsConstructor
  49. @Slf4j
  50. public class DomainOrderService {
  51. private DomainOrderRepo domainOrderRepo;
  52. private ContentAuditService contentAuditService;
  53. private UserRepo userRepo;
  54. private AssetService assetService;
  55. private SysConfigService sysConfigService;
  56. private StorageService storageService;
  57. private RockRecordService rockRecordService;
  58. private AssetRepo assetRepo;
  59. private RedisTemplate<String, Object> redisTemplate;
  60. private CacheService cacheService;
  61. public Page<DomainOrder> all(PageQuery pageQuery) {
  62. return domainOrderRepo
  63. .findAll(JpaUtils.toSpecification(pageQuery, DomainOrder.class), JpaUtils.toPageRequest(pageQuery));
  64. }
  65. @Cacheable(value = "newestDomain")
  66. public List<DomainOrder> newest() {
  67. PageRequest pageRequest = PageRequest.of(0, 50);
  68. return domainOrderRepo.findAllByOrderStatusOrderByCreatedAtDesc(OrderStatus.FINISH, pageRequest).getContent();
  69. }
  70. public boolean isContainChinese(String str) {
  71. if (StringUtils.isEmpty(str)) {
  72. throw new BusinessException("sms context is empty!");
  73. }
  74. Pattern p = Pattern.compile("[\u4E00-\u9FA5|\\!|\\,|\\。|\\(|\\)|\\《|\\》|\\“|\\”|\\?|\\:|\\;|\\【|\\】]");
  75. Matcher m = p.matcher(str);
  76. return m.find();
  77. }
  78. public DomainOrder create(Long userId, String domain, BigDecimal price, Long year) {
  79. AtomicBoolean checkPoint = checkPoint(userId);
  80. List<DomainOrder> notPaidOrders = domainOrderRepo.findAllByUserIdAndOrderStatus(userId, OrderStatus.NOT_PAID);
  81. Long superUserId = Long.valueOf(sysConfigService.getString("domain_superUserId"));
  82. int min = sysConfigService.getInt("domain_minimum");
  83. min = min + 4;
  84. if (notPaidOrders.size() > 0) {
  85. throw new BusinessException("已存在未支付订单,不可继续下单");
  86. }
  87. if (domain.contains(".uni")) {
  88. throw new BusinessException("域名后缀不符合规定.");
  89. }
  90. if (!superUserId.equals(SecurityUtils.getAuthenticatedUser().getId())) {
  91. if (isContainChinese(domain)) {
  92. throw new BusinessException("禁止注册中文域名");
  93. }
  94. if (!checkPoint.get()) {
  95. if (domain.length() < min || domain.length() > 20) {
  96. throw new BusinessException("四位及以下域名只能官方创建。");
  97. }
  98. } else {
  99. if (domain.length() < 7 || domain.length() > 20) {
  100. throw new BusinessException("四位以下域名只能官方创建。");
  101. }
  102. }
  103. }
  104. String realName;
  105. int dotIndex = domain.indexOf(".");
  106. realName = domain.substring(0, dotIndex);
  107. Map<String, Object> checkResult = check(realName);
  108. if (!(Boolean) checkResult.get("result")) {
  109. throw new BusinessException(checkResult.get("reason").toString());
  110. }
  111. BigDecimal singlePrice = sysConfigService.getBigDecimal("domain_price");
  112. if (singlePrice.multiply(BigDecimal.valueOf(year)).compareTo(price) != 0) {
  113. throw new BusinessException("价格不符");
  114. }
  115. // LocalDateTime startTime = LocalDateTime.of(2023, 2, 10, 17, 0, 0);
  116. // if (LocalDateTime.now().isBefore(startTime)) {
  117. // throw new BusinessException("时间不符");
  118. // }
  119. // if (price.compareTo(BigDecimal.valueOf(40L)) != 0) {
  120. // throw new BusinessException("订单价格与配置不符,请重新下单.");
  121. // }
  122. User user = userRepo.findById(userId).orElseThrow(new BusinessException("未找到用户"));
  123. if (domain.contains(".")) {
  124. int dotIndex1 = domain.indexOf(".");
  125. domain = domain.substring(0, dotIndex1);
  126. }
  127. DomainOrder domainOrder = new DomainOrder();
  128. // domainOrder.setPic(Collections.singletonList(fileObject));
  129. domain = domain.replaceAll("[^a-zA-Z0-9\\u4E00-\\u9FA5]", "");
  130. domainOrder.setPicName(domain);
  131. domainOrder.setPrice(price);
  132. domainOrder.setDomainName((domain + ".nft").toLowerCase());
  133. domainOrder.setYears(year);
  134. domainOrder.setStatus(CollectionStatus.PENDING);
  135. domainOrder.setOrderStatus(OrderStatus.NOT_PAID);
  136. domainOrder.setUserId(user.getId());
  137. domainOrder.setUserAvatar(user.getAvatar());
  138. domainOrder.setUserName(user.getNickname());
  139. if (checkPoint.get()) {
  140. if (realName.length() < 5) {
  141. increaseCount(userId, 1);
  142. }
  143. }
  144. return domainOrderRepo.save(domainOrder);
  145. }
  146. public void increaseCount(Long userId, Integer usePoint) {
  147. if (usePoint > 0) {
  148. // 扣除积分
  149. userRepo.addVipPoint(userId, -usePoint);
  150. cacheService.clearUserMy(userId);
  151. }
  152. }
  153. public void decreaseCount(DomainOrder order) {
  154. userRepo.addVipPoint(order.getUserId(), 1);
  155. cacheService.clearUserMy(order.getUserId());
  156. log.info("取消加积分用户ID:{},订单ID:{},积分:{}", order.getUserId(), order.getId(), 1);
  157. }
  158. public AtomicBoolean checkPoint(Long userId) {
  159. AtomicBoolean atomicBoolean = new AtomicBoolean(false);
  160. User user = userRepo.findById(userId).orElseThrow(new BusinessException("用户不存在"));
  161. if (user.getVipPoint() > 0) {
  162. atomicBoolean.set(true);
  163. }
  164. return atomicBoolean;
  165. // Map<Long, Long> collections = JSONObject.parseObject(sysConfigService
  166. // .getString("domain_collection"), new TypeReference<HashMap<Long, Long>>() {
  167. // });
  168. // if (collections.size() == 0) {
  169. // return new AtomicBoolean(false);
  170. // }
  171. // List<AssetStatus> statuses = new ArrayList<>();
  172. // statuses.add(AssetStatus.NORMAL);
  173. // statuses.add(AssetStatus.AUCTIONING);
  174. // AtomicBoolean vipPoint = new AtomicBoolean(false);
  175. // collections.forEach((k, v) -> {
  176. // List<Asset> assets = assetRepo.findAllByCollectionIdAndStatusInAndUserId(k, statuses, userId);
  177. // if (assets.size() > 0) {
  178. // BoundValueOperations<String, Object> ops = redisTemplate.boundValueOps(RedisKeys.DOMAIN_COUNT + userId);
  179. // Integer count = (Integer) ops.get();
  180. // if (count != null) {
  181. // if (count > 0) {
  182. // vipPoint.set(true);
  183. // }
  184. // } else {
  185. // vipPoint.set(false);
  186. // }
  187. // }
  188. // });
  189. // return vipPoint;
  190. }
  191. public Map<String, Object> check(String domain) {
  192. int min = sysConfigService.getInt("domain_minimum");
  193. min = min + 4;
  194. AtomicBoolean checkPoint = checkPoint(SecurityUtils.getAuthenticatedUser().getId());
  195. Map<String, Object> result = new HashMap<>();
  196. Long superUserId = Long.valueOf(sysConfigService.getString("domain_superUserId"));
  197. String visibleDomain = domain;
  198. if (domain.contains(".uni")) {
  199. result.put("result", false);
  200. result.put("reason", "禁止使用.uni");
  201. return result;
  202. }
  203. if (!domain.contains(".nft")) {
  204. visibleDomain = domain + ".nft";
  205. }
  206. List<String> keywords = Arrays.asList(sysConfigService.getString("domain_keyword").split(","));
  207. if (!superUserId.equals(SecurityUtils.getAuthenticatedUser().getId())) {
  208. if (keywords.stream().anyMatch(keyword -> org.apache.commons.lang.StringUtils.equals(keyword, domain))) {
  209. result.put("result", false);
  210. result.put("reason", "包含敏感关键字");
  211. return result;
  212. }
  213. if (!checkPoint.get()) {
  214. if (visibleDomain.length() < min || visibleDomain.length() > 20) {
  215. result.put("result", false);
  216. result.put("reason", "域名长度不合规");
  217. return result;
  218. }
  219. } else {
  220. if (visibleDomain.length() < 7 || visibleDomain.length() > 20) {
  221. result.put("result", false);
  222. result.put("reason", "域名长度不合规");
  223. return result;
  224. }
  225. }
  226. if (!contentAuditService.auditText(domain)) {
  227. result.put("result", false);
  228. result.put("reason", "该域名内容不合规");
  229. return result;
  230. }
  231. }
  232. Integer count = domainOrderRepo
  233. .countAllByDomainNameEqualsAndOrderStatusNot(visibleDomain, OrderStatus.CANCELLED);
  234. if (count > 0) {
  235. result.put("result", false);
  236. result.put("reason", "该域名已被注册");
  237. return result;
  238. }
  239. result.put("result", true);
  240. result.put("reason", "可以注册");
  241. return result;
  242. }
  243. public List<Map<String, Object>> search(String domain) {
  244. if (domain.contains(".")) {
  245. int dotIndex = domain.indexOf(".");
  246. domain = domain.substring(0, dotIndex);
  247. }
  248. // domain = domain.replaceAll("[^a-zA-Z0-9\\u4E00-\\u9FA5]", "");
  249. Pageable pageable = PageRequest.of(0, 10, Sort.by("createdAt").descending());
  250. List<DomainOrder> used = domainOrderRepo.searchUsedDomain("%" + domain + "%", OrderStatus.CANCELLED, pageable)
  251. .getContent();
  252. String n = domain.substring(domain.length() - 1);
  253. List<Map<String, Object>> recommend = new ArrayList<>();
  254. for (int i = 0; i < 100; i++) {
  255. if (i != 0) {
  256. domain = domain + n;
  257. }
  258. Map<String, Object> checkResult = check(domain);
  259. if ((Boolean) checkResult.get("result")) {
  260. Map<String, Object> sold = new HashMap<>();
  261. sold.put("domain", (domain + ".nft").toLowerCase());
  262. sold.put("sold", false);
  263. recommend.add(sold);
  264. }
  265. if (recommend.size() > 2) {
  266. break;
  267. }
  268. }
  269. List<Map<String, Object>> result = new ArrayList<>(recommend);
  270. used.forEach(domainOrder -> {
  271. Map<String, Object> sold = new HashMap<>();
  272. if (!domainOrder.getDomainName().contains(".uni")) {
  273. sold.put("domain", domainOrder.getDomainName().toLowerCase());
  274. sold.put("endTime", domainOrder.getEndTime());
  275. sold.put("sold", true);
  276. result.add(sold);
  277. }
  278. });
  279. return result;
  280. }
  281. @Transient
  282. public void notify(Long id, PayMethod payMethod, String transactionId) throws FontFormatException, IOException, WriterException {
  283. DomainOrder domainOrder = domainOrderRepo.findById(id).orElseThrow(new BusinessException("未找到星图"));
  284. if (!domainOrder.getOrderStatus().equals(OrderStatus.NOT_PAID)) {
  285. throw new BusinessException("订单已经处理");
  286. }
  287. BufferedImage img = domainImg(domainOrder.getDomainName());
  288. ByteArrayOutputStream os = new ByteArrayOutputStream();
  289. ImageIO.write(img, "jpg", os);
  290. InputStream input = new ByteArrayInputStream(os.toByteArray());
  291. String path = "image/" + new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date())
  292. + RandomStringUtils.randomAlphabetic(8) + ".jpg";
  293. String realUrl = storageService.uploadFromInputStream(input, path);
  294. FileObject fileObject = new FileObject();
  295. fileObject.setName(domainOrder.getDomainName());
  296. fileObject.setType("image/jpeg");
  297. fileObject.setUrl(realUrl);
  298. domainOrder.setOrderStatus(OrderStatus.FINISH);
  299. domainOrder.setPayMethod(payMethod);
  300. domainOrder.setPic(Collections.singletonList(fileObject));
  301. domainOrder.setTransactionId(transactionId);
  302. domainOrder.setStatus(CollectionStatus.SUCCESS);
  303. domainOrder.setCreateAssetId(createAsset(domainOrder));
  304. domainOrder.setEndTime(LocalDateTime.now().plusYears(domainOrder.getYears()));
  305. domainOrderRepo.save(domainOrder);
  306. rockRecordService.addRock(domainOrder.getUserId(), domainOrder.getPrice(), "购买");
  307. }
  308. public void cancel(DomainOrder domainOrder) {
  309. domainOrder.setOrderStatus(OrderStatus.CANCELLED);
  310. domainOrder.setStatus(CollectionStatus.FAIL);
  311. if (domainOrder.getPicName().length() < 5) {
  312. decreaseCount(domainOrder);
  313. }
  314. domainOrderRepo.save(domainOrder);
  315. }
  316. public Long createAsset(DomainOrder domainOrder) {
  317. return assetService.createAsset(domainOrder, userRepo.findById(domainOrder.getUserId())
  318. .orElseThrow(new BusinessException("无用户记录")), null, domainOrder.getPrice(), "域名", null, false).getId();
  319. }
  320. public BufferedImage domainImg(String domain) throws IOException, FontFormatException, WriterException {
  321. String domainName;
  322. if (domain.contains(".")) {
  323. int dotIndex = domain.indexOf(".");
  324. domainName = domain.substring(0, dotIndex).toUpperCase();
  325. } else {
  326. domainName = domain.toUpperCase();
  327. }
  328. InputStream is1 = this.getClass()
  329. .getResourceAsStream("/font/VonwaonBitmap_16pxLite.ttf");
  330. Font font1 = Font.createFont(Font.TRUETYPE_FONT, is1);
  331. is1.close();
  332. InputStream is2 = this.getClass()
  333. .getResourceAsStream("/font/VonwaonBitmap_12pxLite.ttf");
  334. Font font2 = Font.createFont(Font.TRUETYPE_FONT, is2);
  335. is2.close();
  336. int length = domainName.length();
  337. BufferedImage shareImg;
  338. if (length == 1) {
  339. InputStream is3 = this.getClass().getResourceAsStream("/static/img/png_jing.png");
  340. shareImg = ImageIO.read(is3);
  341. is3.close();
  342. } else if (length == 2) {
  343. InputStream is3 = this.getClass().getResourceAsStream("/static/img/png_lv.png");
  344. shareImg = ImageIO.read(is3);
  345. is3.close();
  346. } else if (length == 3) {
  347. InputStream is3 = this.getClass().getResourceAsStream("/static/img/png_b.png");
  348. shareImg = ImageIO.read(is3);
  349. is3.close();
  350. } else if (length == 4) {
  351. InputStream is3 = this.getClass().getResourceAsStream("/static/img/png_h.png");
  352. shareImg = ImageIO.read(is3);
  353. is3.close();
  354. } else {
  355. InputStream is3 = this.getClass().getResourceAsStream("/static/img/png_zi.png");
  356. shareImg = ImageIO.read(is3);
  357. is3.close();
  358. }
  359. BufferedImage result = new BufferedImage(shareImg.getWidth(), shareImg.getHeight(), BufferedImage.TYPE_INT_RGB);
  360. Graphics2D g = result.createGraphics();
  361. g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
  362. // g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  363. // g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
  364. g.setComposite(AlphaComposite.SrcOver);
  365. g.drawImage(shareImg, 0, 0, null);
  366. // BufferedImage avatarImg = ImageUtils.makeRoundedCorner(ImageUtils.scale(ImageIO.read(new URL(user.getAvatar())),
  367. // 80, 80,
  368. // ImageUtils.Fit.COVER), 40);
  369. // g.drawImage(avatarImg, 334, 136, null);
  370. int domainLength = domainName.length();
  371. if (domainLength > 10) {
  372. g.setColor(new Color(255, 255, 255));
  373. Font topFont = font1.deriveFont(Font.PLAIN, 130f);
  374. Font downFont = font2.deriveFont(Font.BOLD, 36f);
  375. int subIndex = domainLength / 3;
  376. String str1 = domainName.substring(0, subIndex);
  377. String str2 = domainName.substring(subIndex, subIndex + subIndex);
  378. String str3 = domainName.substring(subIndex + subIndex, domainLength);
  379. ImageUtils.drawCenteredString(g, str1, new Rectangle(0, 180, shareImg
  380. .getWidth(), 86), topFont);
  381. ImageUtils.drawCenteredString(g, str2, new Rectangle(0, 300, shareImg
  382. .getWidth(), 86), topFont);
  383. ImageUtils.drawCenteredString(g, str3, new Rectangle(0, 420, shareImg
  384. .getWidth(), 86), topFont);
  385. ImageUtils.drawCenteredString(g, ".NFT", new Rectangle(0, 540, shareImg
  386. .getWidth(), 86), topFont);
  387. g.setColor(new Color(255, 255, 255));
  388. ImageUtils.drawCenteredString(g, domain, new Rectangle(0, 650, shareImg
  389. .getWidth(), 12), downFont);
  390. }
  391. if (domainLength > 5 & domainLength <= 10) {
  392. g.setColor(new Color(255, 255, 255));
  393. Font topFont = font1.deriveFont(Font.PLAIN, 190f);
  394. Font downFont = font2.deriveFont(Font.BOLD, 36f);
  395. int subIndex = domainLength / 2;
  396. String str1 = domainName.substring(0, subIndex);
  397. String str2 = domainName.substring(subIndex, domainLength);
  398. ImageUtils.drawCenteredString(g, str1, new Rectangle(0, 180, shareImg
  399. .getWidth(), 86), topFont);
  400. ImageUtils.drawCenteredString(g, str2, new Rectangle(0, 350, shareImg
  401. .getWidth(), 86), topFont);
  402. ImageUtils.drawCenteredString(g, ".NFT", new Rectangle(0, 520, shareImg
  403. .getWidth(), 86), topFont);
  404. g.setColor(new Color(255, 255, 255));
  405. ImageUtils.drawCenteredString(g, domain, new Rectangle(0, 650, shareImg
  406. .getWidth(), 12), downFont);
  407. }
  408. if (domainLength <= 5) {
  409. g.setColor(new Color(255, 255, 255));
  410. Font topFont = font1.deriveFont(Font.PLAIN, 240f);
  411. Font downFont = font2.deriveFont(Font.BOLD, 36f);
  412. ImageUtils.drawCenteredString(g, domainName, new Rectangle(17, 220, shareImg
  413. .getWidth(), 86), topFont);
  414. ImageUtils.drawCenteredString(g, ".NFT", new Rectangle(-10, 420, shareImg
  415. .getWidth(), 86), topFont);
  416. g.setColor(new Color(255, 255, 255));
  417. ImageUtils.drawCenteredString(g, domain, new Rectangle(0, 620, shareImg
  418. .getWidth(), 12), downFont);
  419. }
  420. //二维码
  421. // QRCodeWriter qrCodeWriter = new QRCodeWriter();
  422. // Map<EncodeHintType, Object> hints = new HashMap<>();
  423. // hints.put(EncodeHintType.MARGIN, 2);
  424. // BitMatrix bitMatrix = qrCodeWriter
  425. // .encode(env.getProperty("general.host") + "/wx/share?invitor=" + user.getId(),
  426. // BarcodeFormat.QR_CODE, 252, 252, hints);
  427. // g.drawImage(MatrixToImageWriter.toBufferedImage(bitMatrix), 250, 386, null);
  428. return result;
  429. }
  430. public List<DomainCountDTO> top20() {
  431. List<Map<String, Object>> map = assetRepo.domainTop20();
  432. JSONArray jsonArray = new JSONArray();
  433. jsonArray.addAll(map);
  434. return jsonArray.toJavaList(DomainCountDTO.class);
  435. }
  436. }