邀请活动-二维码

This commit is contained in:
khalil
2024-03-14 02:01:25 +08:00
parent 0d07758146
commit f7b578e94b
11 changed files with 166 additions and 134 deletions

View File

@@ -72,11 +72,6 @@
<artifactId>tomcat-embed-core</artifactId> <artifactId>tomcat-embed-core</artifactId>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>${zxing.version}</version>
</dependency>
<!-- Sa-Token 权限认证, 在线文档https://sa-token.cc/ --> <!-- Sa-Token 权限认证, 在线文档https://sa-token.cc/ -->
<dependency> <dependency>

View File

@@ -5,14 +5,13 @@ import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.accompany.admin.dto.link.ShortLinkAdminDto; import com.accompany.admin.dto.link.ShortLinkAdminDto;
import com.accompany.admin.service.link.ShortLinkAdminService; import com.accompany.admin.service.link.ShortLinkAdminService;
import com.accompany.admin.util.QrCodeUtil; import com.accompany.business.util.QrCodeUtil;
import com.accompany.admin.vo.link.ShortLinkAdminVo; import com.accompany.admin.vo.link.ShortLinkAdminVo;
import com.accompany.business.enums.link.ShortLinkTypeEnum; import com.accompany.business.enums.link.ShortLinkTypeEnum;
import com.accompany.business.model.link.ShortLink; import com.accompany.business.model.link.ShortLink;
import com.accompany.business.model.link.ShortLinkRecord; import com.accompany.business.model.link.ShortLinkRecord;
import com.accompany.business.mybatismapper.link.ShortLinkMapper; import com.accompany.business.mybatismapper.link.ShortLinkMapper;
import com.accompany.business.mybatismapper.link.ShortLinkRecordMapper; import com.accompany.business.mybatismapper.link.ShortLinkRecordMapper;
import com.accompany.business.service.api.QinniuService;
import com.accompany.common.constant.Constant; import com.accompany.common.constant.Constant;
import com.accompany.common.model.PageReq; import com.accompany.common.model.PageReq;
import com.accompany.common.tencent.cos.TencentCosUploadService; import com.accompany.common.tencent.cos.TencentCosUploadService;
@@ -109,7 +108,7 @@ public class ShortLinkAdminServiceImpl implements ShortLinkAdminService {
String url = linkUrl + code; String url = linkUrl + code;
InputStream inputStream = null; InputStream inputStream = null;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
QrCodeUtil.encode(url, 200, 200, outputStream); QrCodeUtil.encode(url, outputStream);
inputStream = new ByteArrayInputStream(outputStream.toByteArray()); inputStream = new ByteArrayInputStream(outputStream.toByteArray());
String fileName = UUIDUtil.get() + ".png"; String fileName = UUIDUtil.get() + ".png";
qrcode = uploadService.uploadByStream(inputStream, fileName); qrcode = uploadService.uploadByStream(inputStream, fileName);

View File

@@ -1,42 +0,0 @@
package com.accompany.admin.util;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Hashtable;
import java.util.Map;
/**
* 二维码生成工具类
*/
public class QrCodeUtil {
/**
* 生成二维码
* David
*
* @param url url 网址
* @param width 二维码宽度
* @param height 二维码高度
*/
public static void encode(String url, int width, int height, OutputStream outputStream) {
Map<EncodeHintType, Object> hints = new Hashtable<>();
// 指定纠错等级
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
// 指定编码格式
hints.put(EncodeHintType.CHARACTER_SET, "UTF8");
try {
BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, width, height, hints);
MatrixToImageWriter.writeToStream(bitMatrix, "png", outputStream);
} catch (Exception ignored) {
}
}
}

View File

@@ -3,9 +3,11 @@ package com.accompany.business.model;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.util.Date; import java.util.Date;
@Data
public class UserInviteCode { public class UserInviteCode {
@TableId(value = "id", type = IdType.AUTO) @TableId(value = "id", type = IdType.AUTO)
@@ -35,86 +37,10 @@ public class UserInviteCode {
@TableField("gen_scene") @TableField("gen_scene")
private Byte genScene; private Byte genScene;
@TableField("qr_code_url")
private String qrCodeUrl;
@TableField("creator") @TableField("creator")
private String creator; private String creator;
public Byte getGenScene() {
return genScene;
}
public void setGenScene(Byte genScene) {
this.genScene = genScene;
}
public String getCreator() {
return creator;
}
public void setCreator(String creator) {
this.creator = creator;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Long getUid() {
return uid;
}
public void setUid(Long uid) {
this.uid = uid;
}
public String getInviteCode() {
return inviteCode;
}
public void setInviteCode(String inviteCode) {
this.inviteCode = inviteCode == null ? null : inviteCode.trim();
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public Byte getStatus() {
return status;
}
public void setStatus(Byte status) {
this.status = status;
}
public Boolean getIsPrimary() {
return isPrimary;
}
public void setIsPrimary(Boolean isPrimary) {
this.isPrimary = isPrimary;
}
public Integer getInviteCodeType() {
return inviteCodeType;
}
public void setInviteCodeType(Integer inviteCodeType) {
this.inviteCodeType = inviteCodeType;
}
} }

View File

@@ -1,5 +1,6 @@
package com.accompany.business.vo.invite; package com.accompany.business.vo.invite;
import com.accompany.common.annotation.ReplaceAppDomain;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@@ -43,4 +44,7 @@ public class UserInviteProfitVo {
@ApiModelProperty("间接邀请收益") @ApiModelProperty("间接邀请收益")
private Long indirectProfit = 0L; private Long indirectProfit = 0L;
@ReplaceAppDomain
@ApiModelProperty("二维码url")
private String qRCodeUrl;
} }

View File

@@ -105,6 +105,11 @@
<artifactId>cloudauth20190307</artifactId> <artifactId>cloudauth20190307</artifactId>
<version>${cloudauth20190307.version}</version> <version>${cloudauth20190307.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>${zxing.version}</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -3,11 +3,21 @@ package com.accompany.business.service.user;
import com.accompany.business.model.UserInviteCode; import com.accompany.business.model.UserInviteCode;
import com.accompany.business.mybatismapper.UserInviteCodeMapper; import com.accompany.business.mybatismapper.UserInviteCodeMapper;
import com.accompany.business.util.InviteCodeUtil; import com.accompany.business.util.InviteCodeUtil;
import com.accompany.business.util.QrCodeUtil;
import com.accompany.common.constant.AppEnum;
import com.accompany.common.tencent.cos.TencentCosUploadService;
import com.accompany.common.utils.UUIDUtil;
import com.accompany.core.base.SpringContextHolder;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -16,6 +26,7 @@ import java.util.stream.Collectors;
* 3 * @Date: 2018/10/26 10:44 * 3 * @Date: 2018/10/26 10:44
* 4 * 4
*/ */
@Slf4j
@Service @Service
public class UserInviteCodeService extends ServiceImpl<UserInviteCodeMapper, UserInviteCode> { public class UserInviteCodeService extends ServiceImpl<UserInviteCodeMapper, UserInviteCode> {
@@ -69,8 +80,34 @@ public class UserInviteCodeService extends ServiceImpl<UserInviteCodeMapper, Use
userInviteCodeMapper.insert(userInviteCode); userInviteCodeMapper.insert(userInviteCode);
} }
public void updateUserAllInviteCodeNoPrimary(Long uid) { public void updateUserAllInviteCodeNoPrimary(Long uid) {
userInviteCodeMapper.updateUserAllInviteCodeNoPrimary(uid); userInviteCodeMapper.updateUserAllInviteCodeNoPrimary(uid);
} }
public void buildInviteQRCodeUrl(UserInviteCode userInviteCode){
String linkUrl = String.format("https//%s/%s/modules/game/register.html?inviteCode=%s&shareUid=%d",
AppEnum.getCurApp().getApiDomain(), AppEnum.getCurApp().getH5RootDir(), userInviteCode.getInviteCode(), userInviteCode.getUid());
String fileName = String.format("invite_qrCode_%d_%s.png", userInviteCode.getUid(), userInviteCode.getInviteCode());
String url = null;
InputStream inputStream = null;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
QrCodeUtil.encodeWithLogo(linkUrl, outputStream);
inputStream = new ByteArrayInputStream(outputStream.toByteArray());
url = SpringContextHolder.getBean(TencentCosUploadService.class).uploadByStream(inputStream, fileName);
log.info("[邀请二维码] uid {} code {} 生成邀请二维码成功 {}", userInviteCode.getUid(), userInviteCode.getInviteCode(), url);
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
IOUtils.closeQuietly(inputStream);
}
lambdaUpdate().set(UserInviteCode::getQrCodeUrl, url)
.eq(UserInviteCode::getId, userInviteCode.getId())
.update();
userInviteCode.setQrCodeUrl(url);
}
} }

View File

@@ -13,6 +13,7 @@ import com.accompany.common.constant.Constant;
import com.accompany.common.exception.ApiException; import com.accompany.common.exception.ApiException;
import com.accompany.core.base.UidContextHolder; import com.accompany.core.base.UidContextHolder;
import com.accompany.core.service.SysConfService; import com.accompany.core.service.SysConfService;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -30,7 +31,7 @@ import java.util.List;
public class UserInviteService { public class UserInviteService {
@Autowired @Autowired
private UserInviteCodeMapper userInviteCodeMapper; private UserInviteCodeService userInviteCodeService;
@Autowired @Autowired
private UserInviteFissionRewardRecordMapper userInviteFissionRewardRecordMapper; private UserInviteFissionRewardRecordMapper userInviteFissionRewardRecordMapper;
@@ -45,9 +46,10 @@ public class UserInviteService {
return profit; return profit;
} }
profit.setUid(uid); profit.setUid(uid);
List<UserInviteCode> userInviteCodes = userInviteCodeMapper.selectList(Wrappers.<UserInviteCode>lambdaQuery() List<UserInviteCode> userInviteCodes = userInviteCodeService.lambdaQuery()
.eq(UserInviteCode::getUid, uid) .eq(UserInviteCode::getUid, uid)
.eq(UserInviteCode::getStatus, UserInviteCodeService.INVITE_CODE_STATUS_VALID)); .eq(UserInviteCode::getStatus, UserInviteCodeService.INVITE_CODE_STATUS_VALID)
.list();
if (CollectionUtil.isEmpty(userInviteCodes)) { if (CollectionUtil.isEmpty(userInviteCodes)) {
return profit; return profit;
} }
@@ -57,6 +59,13 @@ public class UserInviteService {
} }
UserInviteCode userInviteCode = userInviteCodes.get(0); UserInviteCode userInviteCode = userInviteCodes.get(0);
profit.setInviteCode(userInviteCode.getInviteCode()); profit.setInviteCode(userInviteCode.getInviteCode());
//todo 如有性能问题可异步
if (StringUtils.isEmpty(userInviteCode.getQrCodeUrl())) {
userInviteCodeService.buildInviteQRCodeUrl(userInviteCode);
}
profit.setQRCodeUrl(userInviteCode.getQrCodeUrl());
List<UserInviteFissionRewardRecord> records = userInviteFissionRewardRecordMapper.selectList(Wrappers.<UserInviteFissionRewardRecord>lambdaQuery() List<UserInviteFissionRewardRecord> records = userInviteFissionRewardRecordMapper.selectList(Wrappers.<UserInviteFissionRewardRecord>lambdaQuery()
.eq(UserInviteFissionRewardRecord::getUid, uid) .eq(UserInviteFissionRewardRecord::getUid, uid)
.between(config.getStartTime() != null && config.getEndTime() != null, UserInviteFissionRewardRecord::getCreateTime, config.getStartTime(), config.getEndTime())); .between(config.getStartTime() != null && config.getEndTime() != null, UserInviteFissionRewardRecord::getCreateTime, config.getStartTime(), config.getEndTime()));

View File

@@ -0,0 +1,97 @@
package com.accompany.business.util;
import com.accompany.common.config.TencentCosConfig;
import com.accompany.common.tencent.cos.TencentCosUploadService;
import com.accompany.core.base.SpringContextHolder;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import lombok.SneakyThrows;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
/**
* 二维码生成工具类
*/
public class QrCodeUtil {
private static final String LOGO_FILE = "piko_logo_60x60.png";
/**
* 生成二维码
* David
*
* @param url url 网址
* @return
*/
@SneakyThrows
public static void encode(String url, OutputStream outputStream) {
Map<EncodeHintType, Object> hints = new Hashtable<>();
// 指定纠错等级
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
// 指定编码格式
hints.put(EncodeHintType.CHARACTER_SET, "UTF8");
BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 200, 200, hints);
MatrixToImageWriter.writeToStream(bitMatrix, "png", outputStream);
}
/**
* 生成二维码
*/
@SneakyThrows
public static void encodeWithLogo(String url, OutputStream outputStream) {
Map<EncodeHintType, Object> hints = new HashMap<>();
//内容编码格式
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
// 指定纠错等级
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
//设置二维码边的空度,非负数
hints.put(EncodeHintType.MARGIN, 1);
BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 150, 150, hints);
//MatrixToImageWriter.writeToPath(bitMatrix, "png", new File("C:\\Users\\84232\\Desktop\\321.png").toPath());// 输出原图片
MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF);
BufferedImage logoImage = LogoMatrix(MatrixToImageWriter.toBufferedImage(bitMatrix,matrixToImageConfig));
ImageIO.write(logoImage, "png", outputStream);
}
/**
* 二维码添加logo
* @return 返回带有logo的二维码图片
*/
@SneakyThrows
public static BufferedImage LogoMatrix(BufferedImage bufferedImage) {
Graphics2D g2 = bufferedImage.createGraphics();
int matrixWidth = bufferedImage.getWidth();
int matrixHeigh = bufferedImage.getHeight();
String url = SpringContextHolder.getBean(TencentCosConfig.class).getUrlPrefix() + "/" + LOGO_FILE;
BufferedImage logo = ImageIO.read(new URL(url));
//开始绘制图片
g2.drawImage(logo,matrixWidth/5*2,matrixHeigh/5*2, matrixWidth/5, matrixHeigh/5, null);//绘制
BasicStroke stroke = new BasicStroke(5,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
g2.setStroke(stroke);// 设置笔画对象
g2.dispose();
bufferedImage.flush() ;
return bufferedImage ;
}
}

View File

@@ -10,6 +10,8 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.io.ByteArrayOutputStream;
/** /**
* @author: liaozetao * @author: liaozetao
* @date: 2024/3/12 15:26 * @date: 2024/3/12 15:26

View File

@@ -99,7 +99,7 @@
<hippo4j-core.version>1.5.0</hippo4j-core.version> <hippo4j-core.version>1.5.0</hippo4j-core.version>
<android-json.version>0.0.20131108.vaadin1</android-json.version> <android-json.version>0.0.20131108.vaadin1</android-json.version>
<bcprov-jdk15on.version>1.64</bcprov-jdk15on.version> <bcprov-jdk15on.version>1.64</bcprov-jdk15on.version>
<zxing.version>3.2.0</zxing.version> <zxing.version>3.5.3</zxing.version>
<bitwalker.version>1.20</bitwalker.version> <bitwalker.version>1.20</bitwalker.version>
<sa-token.version>1.34.0</sa-token.version> <sa-token.version>1.34.0</sa-token.version>
<pinyin4j.version>2.5.1</pinyin4j.version> <pinyin4j.version>2.5.1</pinyin4j.version>