经过测试这样的实现是可行的,我给你一份错误的代码,你把这个实现进去
package com.example.server.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.base.config.KafkaService;
import com.example.base.config.RedisCache;
import com.example.base.config.WechatConfigService;
import com.example.base.util.HttpClientUtils;
import com.example.page.manage.domain.Ziliao;
import com.example.page.manage.service.impl.ZiliaoServiceImpl;
import com.example.server.dto.WeChatDTO;
import com.example.utils.core.domain.AjaxResult;
import com.example.utils.utils.StringUtils;
import io.micrometer.core.annotation.Timed;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.multipart.MultipartFile;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import static com.alibaba.fastjson.JSON.parseObject;
@Service
public class WechatService {
// 微信配置
@Value("${wechat.appid}")
private String appid;
@Value("${wechat.secret}")
private String secret;
// Redis缓存
@Autowired
private RedisCache redisCache;
@Autowired
private WechatConfigService wechatConfigService; // 注入配置服务
@Autowired
private KafkaService kafkaService;
// 文件存储路径
@Value("${file.upload-dir}")
private String uploadDir; // 如:/data/wechat_files
@Autowired
private ZiliaoServiceImpl ziliaoService;
// 微信Token缓存配置
private static final Logger log = LoggerFactory.getLogger(WechatService.class);
private static final String WECHAT_TOKEN_KEY = "wechat:access_token";
private static final long TOKEN_EXPIRE = 7200; // 2小时(微信Token有效期)
private HttpClientUtils httpClientUtils;
/**
* 获取微信jsapi_ticket(带Redis缓存)
*/
public AjaxResult getWechatConfig(Map<String, String> req) {
try {
String url = req.get("url");
if (StringUtils.isBlank(url)) {
throw new IllegalArgumentException("URL参数不能为空");
}
// 1. 生成nonceStr和timestamp
String nonceStr = UUID.randomUUID().toString().replace("-", "").substring(0, 16);
long timestamp = System.currentTimeMillis() / 1000;
// 2. 获取jsapi_ticket(带缓存)
String jsapiTicket = getJsapiTicketWithCache();
// 3. 计算签名(确保参数顺序和拼接正确)
String signature = calculateSignature(jsapiTicket, nonceStr, timestamp, url);
AjaxResult tokenAjax = getToken();
String token = (String) tokenAjax.get("msg");
// 4. 返回配置参数
return AjaxResult.success(Map.of("appId", appid, // 替换为实际AppIDs
"timestamp", String.valueOf(timestamp), "nonceStr", nonceStr, "signature", signature, "token", token));
} catch (Exception e) {
System.err.println("获取微信配置失败:" + e.getMessage());
e.printStackTrace(); // 打印完整堆栈
return AjaxResult.error("获取微信配置异常");
}
}
// 生成随机字符串(16位)
private String generateNonceStr() {
return UUID.randomUUID().toString().replace("-", "").substring(0, 16);
}
// 获取jsapi_ticket(带Redis缓存)
public String getJsapiTicketWithCache() throws IOException {
String cacheKey = "wechat:jsapi_ticket";
String ticket = redisCache.getCacheObject(cacheKey);
if (ticket == null) {
synchronized (this) {
ticket = redisCache.getCacheObject(cacheKey);
if (ticket == null) {
// 获取access_token
String accessToken = getAccessToken();
// 调用微信API获取jsapi_ticket
String url = String.format("https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=%s", accessToken);
String response = httpClientUtils.get(url);
JSONObject json = parseObject(response);
if (json.getIntValue("errcode") != 0) {
throw new RuntimeException("获取jsapi_ticket失败: " + json.getString("errmsg"));
}
ticket = json.getString("ticket");
redisCache.setCacheObject(cacheKey, ticket, 7200, TimeUnit.SECONDS); // 缓存2小时
}
}
}
return ticket;
}
// 计算HMAC-SHA1签名
public String calculateSignature(String jsapiTicket, String nonceStr, long timestamp, String url) {
String rawString = String.format("jsapi_ticket=%s&noncestr=%s×tamp=%d&url=%s", jsapiTicket, nonceStr, timestamp, url);
try {
Mac mac = Mac.getInstance("HmacSHA1");
SecretKeySpec secretKeySpec = new SecretKeySpec(jsapiTicket.getBytes(StandardCharsets.UTF_8), "HmacSHA1");
mac.init(secretKeySpec);
byte[] hash = mac.doFinal(rawString.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(hash);
} catch (Exception e) {
throw new RuntimeException("签名计算失败", e);
}
}
/**
* 获取微信Access Token(带Redis缓存)
*/
public AjaxResult getToken() throws IOException {
String token = redisCache.getCacheObject(WECHAT_TOKEN_KEY);
token = "95_XrWtIb9U2oqStOC4pITcyhW_W328kuSADUtctYS4q4fyYhB0JV481qtMntxNJVmjCL_CN4ovVsnaaQvF6R5RhCTs87QIbPoVIVIzPhSiV7KxwPLN83q3PVVIhWcANTiAJAVIO";
if (token == null) {
synchronized (this) { // 双重检查锁防止缓存击穿
token = redisCache.getCacheObject(WECHAT_TOKEN_KEY);
if (token == null) {
token = fetchWeChatTokenFromApi(); // 调用微信API获取
redisCache.setCacheObject(WECHAT_TOKEN_KEY, token, (int) TOKEN_EXPIRE, TimeUnit.SECONDS);
}
}
}
return AjaxResult.success(token);
}
/**
* 微信登录(获取openid)
*/
public String login(String code) {
try {
String url = "https://api.weixin.qq.com/sns/jscode2session" + "?appid=" + appid + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code";
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("GET");
conn.connect();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
return response.toString();
} catch (Exception e) {
e.printStackTrace();
return "登录失败: " + e.getMessage();
}
}
/**
* 使用kafka消费从微信服务器下载指定 media_id 的图片,并根据 type 保存到大图或小图目录
*/
public AjaxResult downloadFromWeChatByKafka(ArrayList<WeChatDTO> weChatDTOList) {
Map<String, String> result = new HashMap<>();
// 0.时间戳-文件名
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
String formattedTimestamp = sdf.format(new Date());
try {
for (WeChatDTO weChatDTO : weChatDTOList) {
// 1. 参数基础校验
String type = weChatDTO.getType();
if (type == null || (!type.equals("temp") && !type.equals("stemp"))) {
return AjaxResult.error("参数 type 错误,必须是 'temp' 或 'stemp'");
}
String mediaId = weChatDTO.getMedia_id();
if (mediaId == null || mediaId.trim().isEmpty()) {
return AjaxResult.error("参数 media_id 不能为空");
}
// 2.构造下载任务对象
WeChatDTO task = new WeChatDTO();
task.setMedia_id(mediaId);
task.setType(type);
task.setBianhao(UUID.randomUUID().toString()); // uuid+文件名(当前时间戳)
// 时间戳-文件名
task.setFilename(formattedTimestamp);
// 3. 发送任务到 Kafka
kafkaService.sendMessage("file-download-task", JSONObject.toJSONString(task));
// 4. 返回kafka的请求id-》ziliao入库id-》带时间戳(用于命名文件)
result.put("bianhao", task.getBianhao());
result.put("filename", task.getFilename());
System.out.println("已提交下载任务到 Kafka,mediaId = " + mediaId + ", type = " + type);
}
// 4. 立即返回成功响应(实际下载由后台异步执行)
// return AjaxResult.success("文件下载任务已提交,后台正在处理");
return AjaxResult.success(result);
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("提交下载任务失败:" + e.getMessage());
}
}
/**
* 私有方法:从微信API获取Access Token(经过缓存)
*/
private String fetchWeChatTokenFromApi() throws IOException {
String url = "https://api.weixin.qq.com/cgi-bin/token?" + "grant_type=client_credential&appid=" + appid + "&secret=" + secret;
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("GET");
conn.connect();
if (conn.getResponseCode() != 200) {
throw new IOException("微信Token接口返回错误状态码: " + conn.getResponseCode());
}
String response = new String(conn.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
JSONObject json = JSONObject.parseObject(response);
if (!json.containsKey("access_token")) {
throw new IOException("微信Token获取失败: " + json.getString("errmsg"));
}
// 缓存Token(有效期7200秒)
redisCache.setCacheObject(WECHAT_TOKEN_KEY, json.getString("access_token"), (int) TOKEN_EXPIRE, TimeUnit.SECONDS);
return json.getString("access_token");
}
/**
* 私有方法:获取Access Token(带缓存逻辑)
*/
public String getAccessToken() throws IOException {
String token = redisCache.getCacheObject(WECHAT_TOKEN_KEY);
token = "95_XrWtIb9U2oqStOC4pITcyhW_W328kuSADUtctYS4q4fyYhB0JV481qtMntxNJVmjCL_CN4ovVsnaaQvF6R5RhCTs87QIbPoVIVIzPhSiV7KxwPLN83q3PVVIhWcANTiAJAVIO";
if (token == null) {
token = fetchWeChatTokenFromApi();
redisCache.setCacheObject(WECHAT_TOKEN_KEY, token, (int) TOKEN_EXPIRE, TimeUnit.SECONDS);
}
return token;
}
/**
* 图片查看接口(通用,支持原图/缩略图)前端调用
*/
public ResponseEntity<?> downloadFile(String fileName, String type) {
try {
if (fileName == null || fileName.trim().isEmpty()) {
return ResponseEntity.badRequest().body("文件名不能为空");
}
if (!"temp".equals(type) && !"stemp".equals(type)) {
return ResponseEntity.badRequest().body("类型错误(仅支持temp/stemp)");
}
String subDir = "temp".equals(type) ? "temp" : "stemp";
String dirPath = uploadDir + "/upload/" + subDir + "/" + fileName;
/* 2. 路径规范化 去掉 file:/ 前缀 */
if (dirPath.startsWith("file:/")) {
dirPath = dirPath.substring("file:/".length());
}
Path filePath = Paths.get(dirPath).toAbsolutePath().normalize();
if (!filePath.startsWith(dirPath) || !Files.exists(filePath)) {
System.out.println("code:404, 文件下载失败,目录不存在: " + filePath);
return ResponseEntity.notFound().build();
}
// 4. 加载资源并设置响应头
Resource resource = new UrlResource(filePath.toUri());
String contentType = Files.probeContentType(filePath); // 自动检测文件类型(如image/jpeg)
if (contentType == null) {
contentType = "application/octet-stream"; // 默认类型(避免浏览器无法识别)
}
return ResponseEntity.ok().contentType(MediaType.parseMediaType(contentType)) // 动态设置内容类型
.body(resource);
} catch (Exception e) {
return ResponseEntity.internalServerError().body("下载失败: " + e.getMessage());
}
}
/**
* 根据文件获取图片的实际格式
*/
private String getImageFormat(File imageFile) throws IOException {
String format = "jpg"; // 默认假设为 jpg
String fileName = imageFile.getName().toLowerCase();
if (fileName.endsWith(".png")) {
format = "png";
} else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
format = "jpg";
} else if (fileName.endsWith(".gif")) {
format = "gif";
} else if (fileName.endsWith(".bmp")) {
format = "bmp";
} else {
// 如果无法通过扩展名判断,尝试通过文件头判断
format = getImageFormatByHeader(imageFile);
}
return format;
}
/**
* 通过文件头判断图片的实际格式
*/
private String getImageFormatByHeader(File imageFile) throws IOException {
try (InputStream is = new FileInputStream(imageFile)) {
byte[] header = new byte[8];
int bytesRead = is.read(header);
if (bytesRead < 8) {
return "unknown";
}
// JPEG
if (header[0] == (byte) 0xFF && header[1] == (byte) 0xD8 && header[2] == (byte) 0xFF) {
return "jpg";
}
// PNG
if (header[0] == (byte) 0x89 && header[1] == (byte) 0x50 && header[2] == (byte) 0x4E && header[3] == (byte) 0x47 && header[4] == (byte) 0x0D && header[5] == (byte) 0x0A && header[6] == (byte) 0x1A && header[7] == (byte) 0x0A) {
return "png";
}
// GIF
if ((header[0] == (byte) 0x47 && header[1] == (byte) 0x49 && header[2] == (byte) 0x46 && header[3] == (byte) 0x38) && (header[4] == (byte) 0x39 || header[4] == (byte) 0x37) && header[5] == (byte) 0x61) {
return "gif";
}
// BMP
if (header[0] == (byte) 0x42 && header[1] == (byte) 0x4D) {
return "bmp";
}
return "unknown";
}
}
/**
* 从微信服务器下载指定 media_id 的图片,并根据 type 保存到大图或小图目录
*/
public AjaxResult downloadFromWeChat(@RequestBody ArrayList<WeChatDTO> weChatDTOList) {
HttpURLConnection wechatConn = null;
InputStream inputStream = null;
Map<String, String> result = new HashMap<>();
// 生成16位时间戳(如20250731105217356)作为多个文件的唯一标识(文件名)
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
String formattedTimestamp = sdf.format(new Date());
// 生成时间戳用于文件命名(这段代码属于方案二)
// String timestamp = String.valueOf(System.currentTimeMillis());
// String uuid = UUID.randomUUID().toString().replace("-", "");
for (WeChatDTO weChatDTO : weChatDTOList) {
try {
// ======================
// 1. 获取微信 Access Token
// ======================
String accessToken = null;
accessToken = getAccessToken();
if (accessToken == null || accessToken.isEmpty()) {
return AjaxResult.error("获取微信 Access Token 失败");
}
// 测试使用(必须与上传时使用的token一致),实际业务注释本行代码即可
// accessToken = "95_GnZ7oa-IUO5ZVxy6qlh9broUq4NxS7lD3TEcWotYlqX75nheaOVMQXqAeJJsRQe0fq-u1sEsXJwaMVRlTr5jcZfdJmP_6yvQw0XbB2_NHHC0wmHckEL1fYaPQtsOHDcAIATMI";
// ======================
// 2. 检查 type 参数
// ======================
String type = weChatDTO.getType();
if (type == null || (!type.equals("temp") && !type.equals("stemp"))) {
return AjaxResult.error("参数 type 错误,必须是 'temp' 或 'stemp'");
}
// ======================
// 3. 调用微信 API 下载图片
// ======================
String wechatDownloadUrl = "https://api.weixin.qq.com/cgi-bin/media/get" + "?access_token=" + accessToken + "&media_id=" + weChatDTO.getMedia_id();
URL url = new URL(wechatDownloadUrl);
wechatConn = (HttpURLConnection) url.openConnection();
wechatConn.setRequestMethod("GET");
wechatConn.connect();
int responseCode = wechatConn.getResponseCode();
if (responseCode != 200) {
// 读取微信返回的错误信息
InputStream errorStream = wechatConn.getErrorStream();
String errorMsg = errorStream != null ? new String(errorStream.readAllBytes(), java.nio.charset.StandardCharsets.UTF_8) : "未知错误,HTTP状态码: " + responseCode;
return AjaxResult.error("微信下载失败: " + errorMsg);
}
// ======================
// 4. 定义存储路径
// ======================
String contentType = wechatConn.getContentType();
System.out.println("Content-Type: " + contentType);
String fileExtension = ".jpg"; // 默认扩展名
if (contentType != null) {
if (contentType.toLowerCase().contains("image/jpeg")) {
fileExtension = ".jpg";
} else if (contentType.toLowerCase().contains("image/png")) {
fileExtension = ".png";
} else if (contentType.toLowerCase().contains("image/gif")) {
fileExtension = ".gif";
} else {
System.out.println("未识别的 Content-Type: " + contentType + ",默认使用 .jpg");
}
}
// 根据 type 动态设置保存目录
// 大图:temp,小图:stemp
String subDir = type.equals("temp") ? "temp" : "stemp";
String dirPath = uploadDir + "/upload/" + subDir;
/* 2. 路径规范化 去掉 file:/ 前缀 */
if (dirPath.startsWith("file:/")) {
dirPath = dirPath.substring("file:/".length());
}
Path saveDirPath = Paths.get(dirPath).toAbsolutePath().normalize();
// 打印路径(调试用)
System.out.println(type + " 图片存储目录: " + saveDirPath);
// 创建目录(如果不存在)
try {
Files.createDirectories(saveDirPath);
} catch (IOException e) {
return AjaxResult.error("创建目录失败: " + e.getMessage());
}
// ======================
// 5. 生成唯一文件名
// ======================
// 方案一
String fileName = formattedTimestamp + fileExtension;
// 方案二
// String fileName = timestamp + "_" + uuid + fileExtension; // 1754703957349_b03eb7428f994c73b7f7282ea1bfda8c.jpg
// ======================
// 6. 保存图片到对应目录
// ======================
Path filePath = saveDirPath.resolve(fileName);
File imageFile = filePath.toFile();
try (InputStream in = wechatConn.getInputStream(); // 微信返回的图片二进制流
OutputStream out = new FileOutputStream(imageFile) // 保存到本地文件
) {
byte[] buffer = new byte[8192]; // 8KB 缓冲区
int bytesRead;
long totalBytesRead = 0;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
totalBytesRead += bytesRead;
}
System.out.println("图片下载完成,总字节数: " + totalBytesRead);
} catch (IOException e) {
e.printStackTrace();
return AjaxResult.error("保存图片文件失败: " + e.getMessage());
}
// 检查文件是否成功保存
if (!imageFile.exists()) {
return AjaxResult.error(type + " 图片文件保存失败,路径: " + filePath);
}
// 打印文件大小,用于调试
long fileSize = imageFile.length();
System.out.println(type + " 图片文件大小: " + fileSize + " 字节");
// ======================
// 7. 返回访问 URL
// ======================
// 假设你的 Spring Boot 静态资源映射了 /upload/** 到 upload 目录
// 比如通过 WebConfig 添加了资源映射
if ("temp".equals(type)) {
String fileUrl = "/upload/" + subDir + "/" + fileName;
// 数据入库
Ziliao ziliao = new Ziliao();
// 图片路径
ziliao.setTupian(subDir + "/" + fileName);
// 图片扩展名
ziliao.setKuozhanming(fileExtension);
// 时间
ziliao.setShijian(new Date());
// 项目编号
ziliao.setBianhao(UUID.randomUUID().toString());
// 大小图标识
ziliao.setWendangtype(type);
int code = ziliaoService.insertZiliao(ziliao);
if (code == 0) {
return AjaxResult.error(500, "图片信息入库失败");
}
String fileUrl1 = result.put("fileUrl", fileUrl);
result.put("bianhao", ziliao.getBianhao());
}
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("下载失败: " + e.getMessage());
} finally {
// 关闭资源
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (wechatConn != null) {
wechatConn.disconnect();
}
}
}
return AjaxResult.success(result);
}
/**
* 上传图片到微信临时素材接口
*/
public AjaxResult uploadImage(MultipartFile file) {
// 1. 基本校验
if (file == null || file.isEmpty()) {
return AjaxResult.error("请选择要上传的图片文件");
}
String originalFilename = file.getOriginalFilename();
if (originalFilename == null || !isValidImageExtension(originalFilename)) {
return AjaxResult.error("不支持的图片格式(仅允许 jpg、jpeg、png、gif)");
}
// 微信限制:图片最大 2MB
if (file.getSize() > 2 * 1024 * 1024) {
return AjaxResult.error("微信限制图片大小不能超过 2MB");
}
// 2. 获取 AccessToken
String accessToken;
try {
accessToken = getAccessToken();
} catch (IOException e) {
log.error("[uploadImage] 获取微信 AccessToken 失败", e);
return AjaxResult.error("系统异常,无法获取微信令牌");
}
// 3. 构建上传地址
String uploadUrl = String.format("https://api.weixin.qq.com/cgi-bin/media/upload?access_token=%s&type=image", accessToken);
CloseableHttpClient httpClient = null;
CloseableHttpResponse response = null;
try {
httpClient = HttpClients.custom().setConnectionTimeToLive(5, TimeUnit.SECONDS).build();
HttpPost httpPost = new HttpPost(uploadUrl);
MultipartEntityBuilder builder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.BROWSER_COMPATIBLE).setCharset(StandardCharsets.UTF_8).addBinaryBody("media", file.getInputStream(), ContentType.create(getMimeType(originalFilename)), originalFilename);
httpPost.setEntity(builder.build());
// 4. 执行上传
response = httpClient.execute(httpPost);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
String errorBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
log.error("[uploadImage] 微信返回非200状态码:{}, 响应体:{}", statusCode, errorBody);
return AjaxResult.error("微信服务器异常:" + statusCode);
}
// 5. 解析响应
String responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
JSONObject json = JSON.parseObject(responseBody);
if (json.getIntValue("errcode") != 0) {
String errMsg = json.getString("errmsg");
log.error("[uploadImage] 微信上传失败:{}", errMsg);
return AjaxResult.error("微信上传失败:" + errMsg);
}
// 6. 异步触发下载任务
String mediaId = json.getString("media_id");
WeChatDTO dto = new WeChatDTO();
dto.setMedia_id(mediaId);
dto.setBianhao(UUID.randomUUID().toString());
dto.setFilename(new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + "_" + originalFilename);
kafkaService.sendMessage("file-download-task", JSON.toJSONString(dto));
return AjaxResult.success(Map.of("mediaId", mediaId, "type", json.getString("type"), "msg", "上传成功,后台正在异步下载图片"));
} catch (IOException e) {
log.error("[uploadImage] 文件上传失败", e);
return AjaxResult.error("文件处理失败:" + e.getClass().getSimpleName() + ": " + e.getMessage());
} catch (Exception e) {
log.error("[uploadImage] 未知异常", e);
return AjaxResult.error("系统异常,请稍后重试");
} finally {
// 7. 确保资源关闭
if (response != null) {
try {
response.close();
} catch (IOException e) {
log.warn("[uploadImage] 关闭 response 异常", e);
}
}
if (httpClient != null) {
try {
httpClient.close();
} catch (IOException e) {
log.warn("[uploadImage] 关闭 httpClient 异常", e);
}
}
}
}
/**
* 校验图片扩展名(防伪造MIME类型)
* @param filename 文件名
* @return 是否合法
*/
private boolean isValidImageExtension(String filename) {
if (filename == null) {
return false;
}
String lowerFilename = filename.toLowerCase();
return lowerFilename.endsWith(".jpg") || lowerFilename.endsWith(".jpeg") || lowerFilename.endsWith(".png") || lowerFilename.endsWith(".gif");
}
private String getMimeType(String filename) {
if (filename == null) return "image/jpeg";
String lower = filename.toLowerCase();
if (lower.endsWith(".png")) return "image/png";
if (lower.endsWith(".gif")) return "image/gif";
return "image/jpeg"; // 默认
}
}
若无必要不要改动uploadImage以外的内容
最新发布