主管理员 1 month ago
parent
commit
c40fe2c465
5 changed files with 44 additions and 64 deletions
  1. +1
    -0
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/impl/AppletApiLoginService.java
  2. +33
    -64
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/impl/AppletApiWaterServiceImpl.java
  3. +5
    -0
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletConfig/controller/AppletConfigController.java
  4. +3
    -0
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletConfig/service/impl/AppletConfigServiceImpl.java
  5. +2
    -0
      jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/java/org/jeecg/JeecgSystemApplication.java

+ 1
- 0
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/impl/AppletApiLoginService.java View File

@ -191,6 +191,7 @@ public class AppletApiLoginService {
user.setCreateTime(new Date());
user.setCreateBy("system");
user.setInviter(inviter);
user.setIsPromote("N");
// TODO: 如果需要unionid字段需要在AppletUser实体类中添加该字段
// user.setUnionid(unionid);


+ 33
- 64
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/impl/AppletApiWaterServiceImpl.java View File

@ -84,20 +84,21 @@ public class AppletApiWaterServiceImpl implements AppletApiWaterService {
// 获取必要的配置信息
String xcxSharePage = appletConfigService.getContentByCode("xcxSharePage");
String backgroundImageUrl = appletConfigService.getContentByCode("qr_code_bg");
// 获取二维码位置配置参数
int qrCodeX = appletConfigService.getContentByCodeAsInt("qr_code_x");
int qrCodeY = appletConfigService.getContentByCodeAsInt("qr_code_y");
// 优化缓存策略使用更精确的缓存key包含所有影响因素包括背景图片URL
String cacheKey = String.format("inviteCode:final:%s:%s:%s:%s", user.getId(), trial, xcxSharePage.hashCode(), backgroundImageUrl.hashCode());
String imageCacheKey = String.format("inviteCode:image:%s:%s:%s:%s", user.getId(), trial, xcxSharePage.hashCode(), backgroundImageUrl.hashCode());
// 优化缓存策略使用更精确的缓存key包含所有影响因素包括背景图片URL和二维码位置配置
String cacheKey = String.format("inviteCode:final:%s:%s:%s:%s:%s:%s",
user.getId(), trial, xcxSharePage.hashCode(), backgroundImageUrl.hashCode(), qrCodeX, qrCodeY);
// 首先检查是否有最终合成图片的缓存
byte[] cachedImage = (byte[]) redisUtil.get(imageCacheKey);
if (cachedImage != null) {
log.info("从缓存返回邀请码图片,用户ID: {}", user.getId());
return cachedImage;
}
// 移除图片数据的Redis缓存避免类型转换错误
// 直接检查OSS中是否已存在最终图片
// 检查OSS中是否已存在最终图片
String finalPath = "invite/final/" + user.getId() + "_" + xcxSharePage + "_" + trial + ".jpg";
String finalPath = String.format("invite/final/%s_%s_%s_%s_%s_%s.jpg",
user.getId(), trial, xcxSharePage.hashCode(), backgroundImageUrl.hashCode(), qrCodeX, qrCodeY);
try {
InputStream ossFile = OssBootUtil.getOssFile(finalPath, null);
if (ossFile != null) {
@ -112,8 +113,7 @@ public class AppletApiWaterServiceImpl implements AppletApiWaterService {
buffer.flush();
byte[] ossImageBytes = buffer.toByteArray();
// 将OSS中的图片缓存到Redis设置24小时过期
redisUtil.set(imageCacheKey, ossImageBytes, 24 * 60 * 60);
// 直接返回OSS中的图片不再缓存到Redis
log.info("从OSS返回邀请码图片,用户ID: {}", user.getId());
return ossImageBytes;
} finally {
@ -125,26 +125,15 @@ public class AppletApiWaterServiceImpl implements AppletApiWaterService {
}
try {
// 检查是否有小程序码的缓存
String qrCodeCacheKey = String.format("inviteCode:qrcode:%s:%s:%s", user.getId(), trial, xcxSharePage.hashCode());
byte[] cachedQrCode = (byte[]) redisUtil.get(qrCodeCacheKey);
byte[] qrCodeBytes;
if (cachedQrCode != null) {
log.info("使用缓存的小程序码,用户ID: {}", user.getId());
qrCodeBytes = cachedQrCode;
} else {
log.info("生成新的小程序码,用户ID: {}", user.getId());
qrCodeBytes = generateWxQrCode(user, xcxSharePage, trial);
// 缓存小程序码设置7天过期小程序码相对稳定
redisUtil.set(qrCodeCacheKey, qrCodeBytes, 7 * 24 * 60 * 60);
}
// 直接生成小程序码移除Redis缓存避免类型转换错误
log.info("生成小程序码,用户ID: {}", user.getId());
byte[] qrCodeBytes = generateWxQrCode(user, xcxSharePage, trial);
// 生成最终合成图片
byte[] finalImage = this.generateAndCombineImagesFromUrl2(qrCodeBytes, backgroundImageUrl);
// 生成最终合成图片传递已获取的配置参数避免重复调用
byte[] finalImage = this.generateAndCombineImagesFromUrl2(qrCodeBytes, backgroundImageUrl, qrCodeX, qrCodeY);
// 异步上传到OSS并缓存
uploadAndCacheAsync(finalImage, finalPath, imageCacheKey);
// 异步上传到OSS移除Redis缓存
uploadToOssAsync(finalImage, finalPath);
return finalImage;
} catch (Exception e) {
@ -187,10 +176,10 @@ public class AppletApiWaterServiceImpl implements AppletApiWaterService {
}
/**
* 异步上传到OSS并缓存到Redis
* 异步上传到OSS
*/
private void uploadAndCacheAsync(byte[] imageBytes, String ossPath, String cacheKey) {
// 使用线程池异步执行上传和缓存操作
private void uploadToOssAsync(byte[] imageBytes, String ossPath) {
// 使用线程池异步执行上传操作
CompletableFuture.runAsync(() -> {
try {
// 上传到OSS
@ -199,48 +188,28 @@ public class AppletApiWaterServiceImpl implements AppletApiWaterService {
} catch (Exception e) {
log.error("异步上传OSS失败,路径: {}", ossPath, e);
}
}, asyncExecutor).thenRunAsync(() -> {
try {
// 缓存到Redis设置24小时过期
redisUtil.set(cacheKey, imageBytes, 24 * 60 * 60);
log.info("异步缓存完成,key: {}", cacheKey);
} catch (Exception e) {
log.error("异步缓存失败,key: {}", cacheKey, e);
}
}, asyncExecutor);
}
public byte[] generateAndCombineImagesFromUrl2(byte[] qrCodeImageByte, String backgroundUrl) {
public byte[] generateAndCombineImagesFromUrl2(byte[] qrCodeImageByte, String backgroundUrl, int qr_code_x, int qr_code_y) {
File file = null;
try {
// 缓存背景图片避免重复下载
String bgCacheKey = "background_image:" + backgroundUrl.hashCode();
BufferedImage backgroundImage = (BufferedImage) redisUtil.get(bgCacheKey);
if (backgroundImage == null) {
// 从URL加载背景图像
URL backgroundImageUrl = new URL(backgroundUrl);
backgroundImage = ImageIO.read(backgroundImageUrl);
// 缓存背景图片设置1小时过期
redisUtil.set(bgCacheKey, backgroundImage, 60 * 60);
log.debug("背景图片已缓存");
} else {
log.debug("使用缓存的背景图片");
}
// 直接从URL加载背景图像移除Redis缓存避免类型转换问题
URL backgroundImageUrl = new URL(backgroundUrl);
BufferedImage backgroundImage = ImageIO.read(backgroundImageUrl);
log.debug("从URL加载背景图片: {}", backgroundUrl);
// 从字节数组加载小程序码图像
BufferedImage qrCodeImage = ImageIO.read(new ByteArrayInputStream(qrCodeImageByte));
// 获取配置参数
int qr_code_y = appletConfigService.getContentByCodeAsInt("qr_code_y");
int qr_code_x = appletConfigService.getContentByCodeAsInt("qr_code_x");
// 使用传入的配置参数避免重复调用配置服务
// 创建一个新的BufferedImage来保存合并后的图像复制背景图片
// 直接使用背景图片作为基础避免创建新的图像导致黑边
BufferedImage combinedImage = new BufferedImage(
backgroundImage.getWidth(),
backgroundImage.getHeight(),
BufferedImage.TYPE_INT_RGB
backgroundImage.getType() // 使用背景图片的原始类型保持透明度
);
Graphics2D g2d = combinedImage.createGraphics();
@ -250,8 +219,8 @@ public class AppletApiWaterServiceImpl implements AppletApiWaterService {
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 绘制背景图像
g2d.drawImage(backgroundImage, 0, 0, null);
// 绘制背景图像完全覆盖画布
g2d.drawImage(backgroundImage, 0, 0, backgroundImage.getWidth(), backgroundImage.getHeight(), null);
int wh = backgroundImage.getWidth() / 3;
@ -259,7 +228,7 @@ public class AppletApiWaterServiceImpl implements AppletApiWaterService {
int qrCodeX = (backgroundImage.getWidth() - wh) / 2;
int qrCodeY = (int) ((backgroundImage.getHeight() - wh) * 0.6);
// 绘制小程序码图像
// 绘制小程序码图像使用传入的位置参数
g2d.drawImage(qrCodeImage, qrCodeX + qr_code_x, qrCodeY + qr_code_y, wh, wh, null);
// 释放Graphics2D资源


+ 5
- 0
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletConfig/controller/AppletConfigController.java View File

@ -29,6 +29,7 @@ import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.jeecg.common.system.base.controller.JeecgController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
@ -90,6 +91,7 @@ public class AppletConfigController extends JeecgController<AppletConfig, IApple
@Operation(summary="小程序配置-添加")
@RequiresPermissions("appletConfig:applet_config:add")
@PostMapping(value = "/add")
@CacheEvict(value = "appletConfig", allEntries = true)
public Result<String> add(@RequestBody AppletConfig appletConfig) {
appletConfigService.save(appletConfig);
@ -106,6 +108,7 @@ public class AppletConfigController extends JeecgController<AppletConfig, IApple
@Operation(summary="小程序配置-编辑")
@RequiresPermissions("appletConfig:applet_config:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
@CacheEvict(value = "appletConfig", allEntries = true)
public Result<String> edit(@RequestBody AppletConfig appletConfig) {
appletConfigService.updateById(appletConfig);
return Result.OK("编辑成功!");
@ -121,6 +124,7 @@ public class AppletConfigController extends JeecgController<AppletConfig, IApple
@Operation(summary="小程序配置-通过id删除")
@RequiresPermissions("appletConfig:applet_config:delete")
@DeleteMapping(value = "/delete")
@CacheEvict(value = "appletConfig", allEntries = true)
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
appletConfigService.removeById(id);
return Result.OK("删除成功!");
@ -136,6 +140,7 @@ public class AppletConfigController extends JeecgController<AppletConfig, IApple
@Operation(summary="小程序配置-批量删除")
@RequiresPermissions("appletConfig:applet_config:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
@CacheEvict(value = "appletConfig", allEntries = true)
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.appletConfigService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");


+ 3
- 0
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletConfig/service/impl/AppletConfigServiceImpl.java View File

@ -3,6 +3,7 @@ package org.jeecg.modules.demo.appletConfig.service.impl;
import org.jeecg.modules.demo.appletConfig.entity.AppletConfig;
import org.jeecg.modules.demo.appletConfig.mapper.AppletConfigMapper;
import org.jeecg.modules.demo.appletConfig.service.IAppletConfigService;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -19,6 +20,7 @@ import java.util.List;
public class AppletConfigServiceImpl extends ServiceImpl<AppletConfigMapper, AppletConfig> implements IAppletConfigService {
@Override
@Cacheable(value = "appletConfig", key = "#code")
public String getContentByCode(String code) {
AppletConfig config = lambdaQuery()
.eq(AppletConfig::getCode, code)
@ -28,6 +30,7 @@ public class AppletConfigServiceImpl extends ServiceImpl<AppletConfigMapper, App
@Override
@Cacheable(value = "appletConfig", key = "'int_' + #code")
public Integer getContentByCodeAsInt(String code) {
String i = getContentByCode(code);
return i != null ? Integer.parseInt(i) : null;


+ 2
- 0
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/java/org/jeecg/JeecgSystemApplication.java View File

@ -6,6 +6,7 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;
@ -19,6 +20,7 @@ import java.util.Map;
*/
@Slf4j
@SpringBootApplication
@EnableCaching
public class JeecgSystemApplication extends SpringBootServletInitializer {
@Override


Loading…
Cancel
Save