From a4aa10f1bc384c209a6198dc68f6dd547e45c068 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Tue, 22 Apr 2025 00:29:57 +0800 Subject: [PATCH] =?UTF-8?q?=E7=83=AD=E6=9B=B4=E6=96=B0=E5=8C=85=E7=BB=B4?= =?UTF-8?q?=E6=8A=A4=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/AdminAppMarketUpdateController.java | 56 ++++++ ...er.java => AppMarketUpdateController.java} | 2 +- .../service/AdminAppMarketUpdateService.java | 47 +++++ .../impl/AdminAppMarketUpdateServiceImpl.java | 186 +++++++++++++++++- .../modules/admin/AdminAppMarketUpdate.java | 3 + .../mall/common/pojo/dto/FileInfoDTO.java | 35 ++++ .../mall/common/utils/StringUtils.java | 64 ++++++ 7 files changed, 384 insertions(+), 9 deletions(-) create mode 100644 mall-admin/src/main/java/com/suisung/mall/admin/controller/admin/AdminAppMarketUpdateController.java rename mall-admin/src/main/java/com/suisung/mall/admin/controller/mobile/{AdminAppMarketUpdateController.java => AppMarketUpdateController.java} (97%) create mode 100644 mall-common/src/main/java/com/suisung/mall/common/pojo/dto/FileInfoDTO.java diff --git a/mall-admin/src/main/java/com/suisung/mall/admin/controller/admin/AdminAppMarketUpdateController.java b/mall-admin/src/main/java/com/suisung/mall/admin/controller/admin/AdminAppMarketUpdateController.java new file mode 100644 index 00000000..2dd15246 --- /dev/null +++ b/mall-admin/src/main/java/com/suisung/mall/admin/controller/admin/AdminAppMarketUpdateController.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.admin.controller.admin; + +import cn.hutool.json.JSONObject; +import com.suisung.mall.admin.service.AdminAppMarketUpdateService; +import com.suisung.mall.common.api.CommonResult; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + + +@Api(tags = "安卓应用市场 APP 版本检查") +@RestController +@RequestMapping("/admin/admin/app-market-update") +public class AdminAppMarketUpdateController { + + @Resource + private AdminAppMarketUpdateService adminAppMarketUpdateService; + + @ApiOperation(value = "安卓市场热更新记录搜索列表", notes = "安卓市场热更新记录搜索列表") + @RequestMapping(value = "/search/list", method = RequestMethod.POST) + public CommonResult searchList(@RequestBody JSONObject paramsJSON) { + return adminAppMarketUpdateService.searchListInAdmin(paramsJSON.getInt("marketId"), paramsJSON.getStr("keyword"), paramsJSON.getInt("pageNum"), paramsJSON.getInt("pageSize")); + } + + @ApiOperation(value = "新增安卓市场热更新记录", notes = "新增安卓市场热更新记录") + @RequestMapping(value = "/add/new", method = RequestMethod.POST) + public CommonResult addNew(@RequestBody JSONObject paramsJSON) { + return adminAppMarketUpdateService.addNewInAdmin(paramsJSON); + } + + @ApiOperation(value = "修改安卓市场热更新记录", notes = "修改安卓市场热更新记录") + @RequestMapping(value = "/modify", method = RequestMethod.POST) + public CommonResult modify(@RequestBody JSONObject paramsJSON) { + return adminAppMarketUpdateService.modifyInAdmin(paramsJSON); + } + + @ApiOperation(value = "关闭安卓市场热更新记录", notes = "关闭安卓市场热更新记录") + @RequestMapping(value = "/enable-or-disable", method = RequestMethod.POST) + public CommonResult enableOrDisable(@RequestBody JSONObject paramsJSON) { + return adminAppMarketUpdateService.enableOrDisableInAdmin(paramsJSON.getLong("id"), paramsJSON.getInt("status")); + } + +} \ No newline at end of file diff --git a/mall-admin/src/main/java/com/suisung/mall/admin/controller/mobile/AdminAppMarketUpdateController.java b/mall-admin/src/main/java/com/suisung/mall/admin/controller/mobile/AppMarketUpdateController.java similarity index 97% rename from mall-admin/src/main/java/com/suisung/mall/admin/controller/mobile/AdminAppMarketUpdateController.java rename to mall-admin/src/main/java/com/suisung/mall/admin/controller/mobile/AppMarketUpdateController.java index 1ab77400..1c296697 100644 --- a/mall-admin/src/main/java/com/suisung/mall/admin/controller/mobile/AdminAppMarketUpdateController.java +++ b/mall-admin/src/main/java/com/suisung/mall/admin/controller/mobile/AppMarketUpdateController.java @@ -24,7 +24,7 @@ import javax.annotation.Resource; @Api(tags = "安卓应用市场 APP 版本检查") @RestController @RequestMapping("/mobile/admin/app-market-update") -public class AdminAppMarketUpdateController { +public class AppMarketUpdateController { @Resource private AdminAppMarketUpdateService adminAppMarketUpdateService; diff --git a/mall-admin/src/main/java/com/suisung/mall/admin/service/AdminAppMarketUpdateService.java b/mall-admin/src/main/java/com/suisung/mall/admin/service/AdminAppMarketUpdateService.java index 67394650..62aa04bd 100644 --- a/mall-admin/src/main/java/com/suisung/mall/admin/service/AdminAppMarketUpdateService.java +++ b/mall-admin/src/main/java/com/suisung/mall/admin/service/AdminAppMarketUpdateService.java @@ -8,7 +8,9 @@ package com.suisung.mall.admin.service; +import cn.hutool.json.JSONObject; import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.modules.admin.AdminAppMarketUpdate; public interface AdminAppMarketUpdateService { @@ -23,4 +25,49 @@ public interface AdminAppMarketUpdateService { CommonResult checkLatestVersion(Integer marketId, String packageName, Integer currVersionKey); + /** + * 后台管理员搜索列表 + * + * @param marketId + * @param keyword + * @param pageNum + * @param pageSize + * @return + */ + CommonResult searchListInAdmin(Integer marketId, String keyword, Integer pageNum, Integer pageSize); + + /** + * 后台管理员新增 + * + * @param paramsJSON + * @return + */ + CommonResult addNewInAdmin(JSONObject paramsJSON); + + /** + * 后台管理员修改 + * + * @param paramsJSON + * @return + */ + CommonResult modifyInAdmin(JSONObject paramsJSON); + + /** + * 后台管理员禁用/启用 + * + * @param id + * @param status + * @return + */ + CommonResult enableOrDisableInAdmin(Long id, Integer status); + + /** + * 获取一条记录 + * + * @param marketId + * @param packageName + * @param versionKey + * @return + */ + AdminAppMarketUpdate getAppMarketUpdate(Integer marketId, String packageName, Integer versionKey); } diff --git a/mall-admin/src/main/java/com/suisung/mall/admin/service/impl/AdminAppMarketUpdateServiceImpl.java b/mall-admin/src/main/java/com/suisung/mall/admin/service/impl/AdminAppMarketUpdateServiceImpl.java index 63772bd2..a7f38e9a 100644 --- a/mall-admin/src/main/java/com/suisung/mall/admin/service/impl/AdminAppMarketUpdateServiceImpl.java +++ b/mall-admin/src/main/java/com/suisung/mall/admin/service/impl/AdminAppMarketUpdateServiceImpl.java @@ -9,14 +9,23 @@ package com.suisung.mall.admin.service.impl; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.suisung.mall.admin.mapper.AdminAppMarketUpdateMapper; import com.suisung.mall.admin.service.AdminAppMarketUpdateService; import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.domain.UserDto; import com.suisung.mall.common.modules.admin.AdminAppMarketUpdate; +import com.suisung.mall.common.pojo.dto.FileInfoDTO; +import com.suisung.mall.common.utils.StringUtils; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; import org.springframework.stereotype.Service; +import static com.suisung.mall.common.utils.ContextUtil.getCurrentUser; + @Service public class AdminAppMarketUpdateServiceImpl extends BaseServiceImpl implements AdminAppMarketUpdateService { /** @@ -33,20 +42,181 @@ public class AdminAppMarketUpdateServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("market_id", marketId).eq("package_name", packageName) - .orderByDesc("version_key").last("limit 1"); - - AdminAppMarketUpdate adminAppMarketUpdate = getOne(queryWrapper); + AdminAppMarketUpdate adminAppMarketUpdate = getAppMarketUpdate(marketId, packageName, currVersionKey); if (adminAppMarketUpdate == null) { - return CommonResult.failed("当前应用已是最新版本"); + return CommonResult.failed("当前已是最新版本"); } - if (!ObjectUtil.isEmpty(currVersionKey) && adminAppMarketUpdate.getVersion_key() <= currVersionKey) { - return CommonResult.failed("当前应用已是最新版本"); + return CommonResult.failed("当前已是最新版本"); + } + + // 更新包后缀处理 + if (StrUtil.isNotBlank(adminAppMarketUpdate.getDownload_url()) && StrUtil.isBlank(adminAppMarketUpdate.getFile_ext())) { + adminAppMarketUpdate.setFile_ext(StringUtils.getFileExt(adminAppMarketUpdate.getDownload_url())); } return CommonResult.success(adminAppMarketUpdate); } + + /** + * 后台管理员搜索列表 + * + * @param marketId + * @param keyword + * @return + */ + @Override + public CommonResult searchListInAdmin(Integer marketId, String keyword, Integer pageNum, Integer pageSize) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (ObjectUtil.isNotEmpty(marketId)) { + queryWrapper.eq("market_id", marketId); + } + if (StrUtil.isNotBlank(keyword)) { + queryWrapper.and(wrapper -> wrapper.like("package_name", keyword) + .or().like("version_name", keyword) + .or().like("description", keyword)); + } + + queryWrapper.orderByDesc("id"); + + Page list = lists(queryWrapper, pageNum, pageSize); + + return CommonResult.success(list); + } + + /** + * 后台管理员新增 + * + * @param paramsJSON + * @return + */ + @Override + public CommonResult addNewInAdmin(JSONObject paramsJSON) { + String userId = "0"; + UserDto user = getCurrentUser(); + if (user != null) { + userId = String.valueOf(user.getId()); + } + + if (ObjectUtil.isEmpty(paramsJSON)) { + return CommonResult.failed("缺少必要参数"); + } + + + AdminAppMarketUpdate adminAppMarketUpdate = JSONUtil.toBean(paramsJSON, AdminAppMarketUpdate.class); + if (ObjectUtil.isEmpty(adminAppMarketUpdate)) { + return CommonResult.failed("参数格式有误"); + } + + + if (ObjectUtil.isEmpty(adminAppMarketUpdate.getMarket_id()) || ObjectUtil.isEmpty(adminAppMarketUpdate.getPackage_name()) + || ObjectUtil.isEmpty(adminAppMarketUpdate.getVersion_key()) || ObjectUtil.isEmpty(adminAppMarketUpdate.getVersion_name()) + || ObjectUtil.isEmpty(adminAppMarketUpdate.getDownload_url())) { + return CommonResult.failed("缺少关键参数"); + } + + AdminAppMarketUpdate record = getAppMarketUpdate(adminAppMarketUpdate.getMarket_id(), adminAppMarketUpdate.getPackage_name(), adminAppMarketUpdate.getVersion_key()); + if (record != null) { + return CommonResult.failed("当前版本升级包已存在"); + } + + FileInfoDTO fileInfoDTO = StringUtils.getFileInfoFromUrl(adminAppMarketUpdate.getDownload_url()); + if (fileInfoDTO != null) { + adminAppMarketUpdate.setPackage_size(fileInfoDTO.getFileSize()); + adminAppMarketUpdate.setFile_ext(fileInfoDTO.getFileExtension()); + adminAppMarketUpdate.setMd5_checksum(fileInfoDTO.getMd5()); + } + + adminAppMarketUpdate.setCreated_by(userId); + adminAppMarketUpdate.setUpdated_by(userId); + + return add(adminAppMarketUpdate) ? CommonResult.success() : CommonResult.failed("操作失败"); + } + + /** + * 后台管理员修改 + * + * @param paramsJSON + * @return + */ + @Override + public CommonResult modifyInAdmin(JSONObject paramsJSON) { + String userId = "0"; + UserDto user = getCurrentUser(); + if (user != null) { + userId = String.valueOf(user.getId()); + } + + if (ObjectUtil.isEmpty(paramsJSON)) { + return CommonResult.failed("缺少必要参数"); + } + + if (ObjectUtil.isEmpty(paramsJSON.getLong("id"))) { + return CommonResult.failed("缺少id参数"); + } + + AdminAppMarketUpdate adminAppMarketUpdate = JSONUtil.toBean(paramsJSON, AdminAppMarketUpdate.class); + if (ObjectUtil.isEmpty(adminAppMarketUpdate)) { + return CommonResult.failed("参数格式有误"); + } + + FileInfoDTO fileInfoDTO = StringUtils.getFileInfoFromUrl(adminAppMarketUpdate.getDownload_url()); + if (fileInfoDTO != null) { + adminAppMarketUpdate.setPackage_size(fileInfoDTO.getFileSize()); + adminAppMarketUpdate.setFile_ext(fileInfoDTO.getFileExtension()); + adminAppMarketUpdate.setMd5_checksum(fileInfoDTO.getMd5()); + } + + adminAppMarketUpdate.setUpdated_by(userId); + + return saveOrUpdate(adminAppMarketUpdate) ? CommonResult.success() : CommonResult.failed("操作失败"); + } + + /** + * 后台管理员禁用/启用 + * + * @param id + * @param status + * @return + */ + @Override + public CommonResult enableOrDisableInAdmin(Long id, Integer status) { + Integer userId = 0; + UserDto user = getCurrentUser(); + if (user != null) { + userId = user.getId(); + } + + if (ObjectUtil.isEmpty(id) || ObjectUtil.isEmpty(status)) { + return CommonResult.failed("缺少必要参数"); + } + + AdminAppMarketUpdate adminAppMarketUpdate = new AdminAppMarketUpdate(); + adminAppMarketUpdate.setId(id); + adminAppMarketUpdate.setStatus(status); + adminAppMarketUpdate.setUpdated_by(String.valueOf(userId)); + return saveOrUpdate(adminAppMarketUpdate) ? CommonResult.success() : CommonResult.failed("操作失败"); + } + + /** + * 获取一条记录 + * + * @param marketId + * @param packageName + * @param versionKey + * @return + */ + @Override + public AdminAppMarketUpdate getAppMarketUpdate(Integer marketId, String packageName, Integer versionKey) { + if (ObjectUtil.isEmpty(marketId) || ObjectUtil.isEmpty(packageName) || ObjectUtil.isEmpty(versionKey)) { + return null; + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("market_id", marketId).eq("package_name", packageName) + .eq("version_key", versionKey); + + return findOne(queryWrapper); + } } diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/admin/AdminAppMarketUpdate.java b/mall-common/src/main/java/com/suisung/mall/common/modules/admin/AdminAppMarketUpdate.java index 91e9b252..e7c68534 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/admin/AdminAppMarketUpdate.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/admin/AdminAppMarketUpdate.java @@ -46,6 +46,9 @@ public class AdminAppMarketUpdate implements Serializable { @ApiModelProperty(value = "热更新包的下载链接,用户可通过此链接下载更新包完成应用更新") private String download_url; + @ApiModelProperty(value = "更新包后缀:apk, wgt") + private String file_ext; + @ApiModelProperty(value = "热更新的发布时间,记录更新包正式发布的时刻") private Date release_time; diff --git a/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/FileInfoDTO.java b/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/FileInfoDTO.java new file mode 100644 index 00000000..f718f776 --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/FileInfoDTO.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.common.pojo.dto; + +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +@ApiModel(value = "文件信息", description = "文件信息") +public class FileInfoDTO { + + String md5; + String fileExtension; + long fileSize; + + public FileInfoDTO(String md5, String fileExtension, long fileSize) { + this.md5 = md5; + this.fileExtension = fileExtension; + this.fileSize = fileSize; + } + + @Override + public String toString() { + return "MD5: " + md5 + ", 文件后缀: " + fileExtension + ", 文件大小: " + fileSize + " 字节"; + } + +} diff --git a/mall-common/src/main/java/com/suisung/mall/common/utils/StringUtils.java b/mall-common/src/main/java/com/suisung/mall/common/utils/StringUtils.java index eba58e3e..31fa3e85 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/utils/StringUtils.java +++ b/mall-common/src/main/java/com/suisung/mall/common/utils/StringUtils.java @@ -1,7 +1,9 @@ package com.suisung.mall.common.utils; +import cn.hutool.core.util.StrUtil; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.*; +import com.suisung.mall.common.pojo.dto.FileInfoDTO; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; @@ -10,8 +12,12 @@ import org.xml.sax.InputSource; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.*; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; import java.net.URLEncoder; import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.text.MessageFormat; import java.text.SimpleDateFormat; @@ -709,6 +715,64 @@ public final class StringUtils extends org.apache.commons.lang3.StringUtils { return false; } + /** + * 根据url文件,生成文件MD5文摘签名 + * + * @param fileUrl + * @return + */ + public static FileInfoDTO getFileInfoFromUrl(String fileUrl) { + if (StrUtil.isBlank(fileUrl)) { + return null; + } + + try { + URL url = new URL(fileUrl); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + + // 获取文件大小 + long fileSize = connection.getContentLengthLong(); + + // 获取文件后缀 + String path = url.getPath(); + String fileExtension = ""; + int dotIndex = path.lastIndexOf('.'); + if (dotIndex != -1) { + fileExtension = path.substring(dotIndex + 1); + } + + try (InputStream inputStream = connection.getInputStream()) { + // 获取 MD5 消息摘要实例 + MessageDigest digest = MessageDigest.getInstance("MD5"); + byte[] buffer = new byte[8192]; + int bytesRead; + // 从输入流读取数据并更新摘要 + while ((bytesRead = inputStream.read(buffer)) != -1) { + digest.update(buffer, 0, bytesRead); + } + // 完成摘要计算 + byte[] md5Bytes = digest.digest(); + // 将字节数组转换为十六进制字符串 + StringBuilder md5String = new StringBuilder(); + for (byte b : md5Bytes) { + md5String.append(String.format("%02x", b)); + } + String md5 = md5String.toString(); + return new FileInfoDTO(StrUtil.isBlank(md5) ? "" : md5, fileExtension, fileSize); + } finally { + connection.disconnect(); + } + } catch (MalformedURLException e) { + logger.error("错误:提供的 URL 格式不正确,请检查 URL 字符串", e); + } catch (NoSuchAlgorithmException e) { + logger.error("错误:系统不支持 MD5 算法,这可能是 Java 环境的问题", e); + } catch (IOException e) { + logger.error("错误:在连接 URL 或读取文件内容时发生 I/O 异常,可能是网络问题或文件不存在", e); + } + return null; + } + /** * 生成的随机数类型