添加上传接口

This commit is contained in:
2025-07-18 11:58:38 +08:00
parent c5e8b048de
commit 109e087bfd
5 changed files with 277 additions and 4 deletions

View File

@@ -44,10 +44,11 @@ public class AccountBlockAdminService extends BaseService {
* @param blockValue
* @return
*/
public IPage<AccountBlock> getAccountBlockList(Integer pageSize, Integer pageNum, Integer type, String blockValue) {
public IPage<AccountBlock> getAccountBlockList(Integer pageSize, Integer pageNum, Integer type, String blockValue, String blockDesc) {
QueryWrapper<AccountBlock> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(type != null && type > 0, AccountBlock::getBlockType, type)
.like(StringUtils.isNotBlank(blockValue), AccountBlock::getBlockValue, blockValue)
.like(StringUtils.isNotEmpty(blockDesc), AccountBlock::getBlockDesc, blockDesc)
.orderByDesc(AccountBlock::getCreateTime);
IPage<AccountBlock> page = new Page<>(pageNum, pageSize);
return accountBlockService.page(page, wrapper);
@@ -70,6 +71,7 @@ public class AccountBlockAdminService extends BaseService {
String endBlockTime, String blockDesc, Boolean wallStatus, String adminName, String remark,
String blockImgUrl, Byte blockDevice) throws Exception {
List<AccountBlock> list = new ArrayList<>();
Map<String, AccountBlock> accountBlockMap = accountBlockService.mapByBlockValue(blockValueList);
blockValueList.stream().forEach(blockValue -> {
AccountBlock accountBlock = new AccountBlock();
accountBlock.setBlockValue(blockValue);
@@ -83,7 +85,12 @@ public class AccountBlockAdminService extends BaseService {
}
}
accountBlock.setBlockStatus(1);
accountBlock.setBlockDesc(blockDesc);
AccountBlock oldRecord = accountBlockMap.get(blockValue);
if (oldRecord != null) {
accountBlock.setBlockDesc(String.format("%s+%s" , oldRecord.getBlockDesc(), blockDesc));
} else {
accountBlock.setBlockDesc(blockDesc);
}
accountBlock.setBlockStartTime(DateTimeUtil.convertStrToDate(startBlockTime, DateTimeUtil.DEFAULT_DATE_MINUTE_PATTERN));
accountBlock.setBlockEndTime(DateTimeUtil.convertStrToDate(endBlockTime, DateTimeUtil.DEFAULT_DATE_MINUTE_PATTERN));
accountBlock.setSource(BlockStatusEnum.BLOCKING.getValue());
@@ -146,4 +153,6 @@ public class AccountBlockAdminService extends BaseService {
}
return result;
}
}

View File

@@ -2,6 +2,8 @@ package com.accompany.admin.controller;
import com.accompany.common.result.BusiResult;
import com.accompany.common.tencent.cos.TencentCosUploadService;
import com.accompany.common.utils.FileTypeDetector;
import com.alibaba.fastjson.JSONObject;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
@@ -12,6 +14,7 @@ import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -45,4 +48,18 @@ public class TencentCosUploadController extends BaseController {
String fileUrl = uploadService.uploadByStream(file.getInputStream(), fileName);
return BusiResult.success(fileUrl);
}
@SneakyThrows
@PostMapping("/uploadFile")
public BusiResult<JSONObject> uploadFileV2(@RequestParam("file") MultipartFile file) {
String fileName = file.getOriginalFilename();
InputStream inputStream = file.getInputStream();
String fileType = FileTypeDetector.detectFileType(inputStream);
String fileUrl = uploadService.uploadByStream(inputStream, fileName);
JSONObject jsonObject = new JSONObject();
jsonObject.put("url", fileUrl);
jsonObject.put("fileName", fileName);
jsonObject.put("fileType", fileType);
return BusiResult.success(jsonObject);
}
}

View File

@@ -43,8 +43,8 @@ public class AccountBlockAdminController extends BaseController {
@ApiOperation("查询封禁列表")
@GetMapping(value = "/page")
public BusiResult<IPage<AccountBlock>> getAccountBlockList(Integer pageSize, Integer pageNum, Integer type, String blockValue) {
IPage<AccountBlock> pageInfo = accountBlockAdminService.getAccountBlockList(pageSize, pageNum, type, blockValue);
public BusiResult<IPage<AccountBlock>> getAccountBlockList(Integer pageSize, Integer pageNum, Integer type, String blockValue, String blockDesc) {
IPage<AccountBlock> pageInfo = accountBlockAdminService.getAccountBlockList(pageSize, pageNum, type, blockValue, blockDesc);
return BusiResult.success(pageInfo);
}

View File

@@ -0,0 +1,239 @@
package com.accompany.common.utils;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.io.InputStream;
@Slf4j
public class FileTypeDetector {
public static String detectFileType(InputStream is) throws IOException {
try {
// 读取文件头部的字节(通常16-32字节足够)
byte[] header = new byte[32];
int bytesRead = is.read(header);
if (bytesRead < 4) {
return "UNKNOWN";
}
// 根据魔数判断文件类型
if (isPng(header)) {
return "PNG";
} else if (isJpeg(header)) {
return "JPEG";
} else if (isGif(header)) {
return "GIF";
} else if (isMp3(header)) {
return "MP3";
} else if (isMp4(header)) {
return "MP4";
} else if (isAvi(header)) {
return "AVI";
} else if (isWebP(header)) {
return "WEBP";
} else if (isBmp(header)) {
return "BMP";
} else if (isTiff(header)) {
return "TIFF";
}
} catch (IOException e) {
log.error("FileTypeDetector.detectFileType, e:{}", e.getMessage(), e);
}
return "UNKNOWN";
}
private static boolean isPng(byte[] header) {
return header[0] == (byte) 0x89 &&
header[1] == 'P' &&
header[2] == 'N' &&
header[3] == 'G';
}
private static boolean isJpeg(byte[] header) {
return header[0] == (byte) 0xFF &&
header[1] == (byte) 0xD8;
}
private static boolean isGif(byte[] header) {
return header[0] == 'G' &&
header[1] == 'I' &&
header[2] == 'F';
}
private static boolean isPdf(byte[] header) {
return header[0] == '%' &&
header[1] == 'P' &&
header[2] == 'D' &&
header[3] == 'F';
}
/**
* 检测是否为MP3文件
* MP3文件可能有多种签名格式
* @param header 文件头部字节数组
* @return 如果是MP3文件返回true
*/
private static boolean isMp3(byte[] header) {
// 检查ID3标签 (ID3v2)
if (header.length >= 3 &&
header[0] == 'I' && header[1] == 'D' && header[2] == '3') {
return true;
}
// 检查MPEG帧头 (FF E0-FB)
if (header.length >= 2 &&
header[0] == (byte) 0xFF && (header[1] & 0xE0) == 0xE0) {
// 检查有效的MPEG版本和层
byte versionLayer = (byte) ((header[1] & 0x18) >>> 3);
byte layer = (byte) ((header[1] & 0x06) >>> 1);
return versionLayer != 1 && layer != 0;
}
// 检查ID3v1标签 (文件末尾的"TAG")
// 注意: 这个方法无法检测到ID3v1标签因为它位于文件末尾
return false;
}
/**
* 检测是否为MP4文件
* MP4文件基于"ftyp"盒子识别
* @param header 文件头部字节数组
* @return 如果是MP4文件返回true
*/
private static boolean isMp4(byte[] header) {
// 需要至少12字节来检测
if (header.length < 12) {
return false;
}
// 检查文件大小和"ftyp"标记
// MP4文件通常以大小(4字节)和"ftyp"(4字节)开始
// 但有些MP4文件可能在前面有额外的元数据
// 查找"ftyp"标记(66 74 79 70)
for (int i = 0; i <= header.length - 8; i++) {
if (header[i] == 'f' && header[i+1] == 't' &&
header[i+2] == 'y' && header[i+3] == 'p') {
// 检查常见的MP4子类型
if (i + 8 < header.length) {
// 检查子类型(如"mp42", "isom", "avc1"等)
String majorBrand = new String(header, i+4, 4);
return majorBrand.equals("mp42") || majorBrand.equals("isom") ||
majorBrand.equals("avc1") || majorBrand.equals("iso2") ||
majorBrand.equals("M4V ") || majorBrand.equals("M4A ");
}
return true;
}
}
// 检查一些MP4变体可能以"moov"开头
if (header[4] == 'm' && header[5] == 'o' &&
header[6] == 'o' && header[7] == 'v') {
return true;
}
return false;
}
/**
* 检测是否为AVI格式文件
* AVI文件签名: RIFF....AVI
* @param header 文件头部字节数组(至少需要12字节)
* @return 如果是AVI文件返回true
*/
private static boolean isAvi(byte[] header) {
// 最少需要12字节来识别AVI文件
if (header.length < 12) {
return false;
}
// 检查RIFF签名(52 49 46 46)
boolean isRiff = header[0] == 'R' &&
header[1] == 'I' &&
header[2] == 'F' &&
header[3] == 'F';
// 检查AVI签名(41 56 49 20 或 41 56 49 58)
boolean isAvi = (header[8] == 'A' &&
header[9] == 'V' &&
header[10] == 'I' &&
(header[11] == ' ' || header[11] == 'X'));
return isRiff && isAvi;
}
/**
* 检测是否为WebP格式文件
* WebP签名: RIFF....WEBP
* @param header 文件头部字节数组(至少需要12字节)
* @return 如果是WebP文件返回true
*/
private static boolean isWebP(byte[] header) {
// 最少需要12字节来识别WebP文件
if (header.length < 12) {
return false;
}
// 检查RIFF签名(52 49 46 46)
boolean isRiff = header[0] == 'R' &&
header[1] == 'I' &&
header[2] == 'F' &&
header[3] == 'F';
// 检查WEBP签名(57 45 42 50)
boolean isWebP = header[8] == 'W' &&
header[9] == 'E' &&
header[10] == 'B' &&
header[11] == 'P';
return isRiff && isWebP;
}
/**
* 检测是否为BMP格式文件
* BMP签名: BM (42 4D)
* @param header 文件头部字节数组(至少需要2字节)
* @return 如果是BMP文件返回true
*/
private static boolean isBmp(byte[] header) {
// 最少需要2字节来识别BMP文件
if (header.length < 2) {
return false;
}
// 检查BM签名(42 4D)
return header[0] == 'B' && header[1] == 'M';
}
/**
* 检测是否为TIFF格式文件
* TIFF签名:
* 小端序: II 2A 00
* 大端序: MM 00 2A
* @param header 文件头部字节数组(至少需要4字节)
* @return 如果是TIFF文件返回true
*/
private static boolean isTiff(byte[] header) {
// 最少需要4字节来识别TIFF文件
if (header.length < 4) {
return false;
}
// 检查小端序格式(II 2A 00)
boolean isLittleEndian = header[0] == 'I' &&
header[1] == 'I' &&
header[2] == 0x2A &&
header[3] == 0x00;
// 检查大端序格式(MM 00 2A)
boolean isBigEndian = header[0] == 'M' &&
header[1] == 'M' &&
header[2] == 0x00 &&
header[3] == 0x2A;
return isLittleEndian || isBigEndian;
}
}

View File

@@ -387,4 +387,12 @@ public class AccountBlockService extends ServiceImpl<AccountBlockMapper, Account
return betweenDate && accountBlock.getBlockStatus() != null
&& BlockStatusEnum.BLOCKING.getValue() == accountBlock.getBlockStatus().byteValue();
}
public Map<String, AccountBlock> mapByBlockValue(List<String> blockValueList) {
List<AccountBlock> accountBlocks = baseMapper.selectByIds(blockValueList);
if (CollectionUtils.isEmpty(accountBlocks)) {
return Collections.emptyMap();
}
return accountBlocks.stream().collect(Collectors.toMap(AccountBlock::getBlockValue, x -> x));
}
}