文件OSS上传

This commit is contained in:
haozq 2025-12-26 13:35:20 +08:00
parent ab672a0d69
commit 56b7f3159b
7 changed files with 364 additions and 149 deletions

View File

@ -5,17 +5,13 @@
</component>
<component name="ChangeListManager">
<list default="true" id="30706c6d-35cd-44ba-b6ec-9865ccea7a75" name="Changes" comment="文件OSS上传">
<change afterPath="$PROJECT_DIR$/realname-app/src/main/java/com/bonus/hnrn/rnama/core/controller/ResourceFileController.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/realname-app/src/main/resources/file/aqgzs.pdf" afterDir="false" />
<change afterPath="$PROJECT_DIR$/realname-app/src/main/resources/file/ygxy.pdf" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/realname-app/src/main/java/com/bonus/hnrn/rnama/core/config/BnsSecurityConfig.java" beforeDir="false" afterPath="$PROJECT_DIR$/realname-app/src/main/java/com/bonus/hnrn/rnama/core/config/BnsSecurityConfig.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/realname-app/src/main/java/com/bonus/hnrn/rnama/core/config/TokenFilter.java" beforeDir="false" afterPath="$PROJECT_DIR$/realname-app/src/main/java/com/bonus/hnrn/rnama/core/config/TokenFilter.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/realname-app/src/main/java/com/bonus/hnrn/rnama/person/entity/ContractBean.java" beforeDir="false" afterPath="$PROJECT_DIR$/realname-app/src/main/java/com/bonus/hnrn/rnama/person/entity/ContractBean.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/realname-app/src/main/java/com/bonus/hnrn/rnama/person/entity/WorkerPhotoBean.java" beforeDir="false" afterPath="$PROJECT_DIR$/realname-app/src/main/java/com/bonus/hnrn/rnama/person/entity/WorkerPhotoBean.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/realname-app/src/main/java/com/bonus/hnrn/rnama/core/controller/ResourceFileController.java" beforeDir="false" afterPath="$PROJECT_DIR$/realname-app/src/main/java/com/bonus/hnrn/rnama/core/controller/ResourceFileController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/realname-app/src/main/java/com/bonus/hnrn/rnama/person/entity/SubMsgBean.java" beforeDir="false" afterPath="$PROJECT_DIR$/realname-app/src/main/java/com/bonus/hnrn/rnama/person/entity/SubMsgBean.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/realname-app/src/main/java/com/bonus/hnrn/rnama/person/service/PersonIdentifyServiceImpl.java" beforeDir="false" afterPath="$PROJECT_DIR$/realname-app/src/main/java/com/bonus/hnrn/rnama/person/service/PersonIdentifyServiceImpl.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/realname-app/src/main/java/com/bonus/hnrn/rnama/person/service/WorkPersonServiceImpl.java" beforeDir="false" afterPath="$PROJECT_DIR$/realname-app/src/main/java/com/bonus/hnrn/rnama/person/service/WorkPersonServiceImpl.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/realname-app/src/main/resources/mappers/person/WorkPersonMapper.xml" beforeDir="false" afterPath="$PROJECT_DIR$/realname-app/src/main/resources/mappers/person/WorkPersonMapper.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/realname-app/src/main/resources/bootstrap.yml" beforeDir="false" afterPath="$PROJECT_DIR$/realname-app/src/main/resources/bootstrap.yml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/realname-app/src/main/resources/mappers/person/PersonIdentifyMapper.xml" beforeDir="false" afterPath="$PROJECT_DIR$/realname-app/src/main/resources/mappers/person/PersonIdentifyMapper.xml" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -55,57 +51,57 @@
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"Maven.HnRealNameBmw [clean].executor": "Run",
"Maven.HnRealNameBmw [install].executor": "Run",
"Maven.HnRealNameMmw [clean].executor": "Run",
"Maven.HnRealNameMmw [install].executor": "Run",
"Maven.hn-czl-service [clean].executor": "Run",
"Maven.hn-czl-service [install].executor": "Run",
"Maven.hn-gateway [clean].executor": "Run",
"Maven.hn-gateway [install].executor": "Run",
"Maven.hn_czl_screen [clean].executor": "Run",
"Maven.hn_czl_screen [install].executor": "Run",
"Maven.ldlz [clean].executor": "Run",
"Maven.ldlz [install].executor": "Run",
"Maven.real-name [clean].executor": "Run",
"Maven.real-name [install].executor": "Run",
"Maven.real-name-screen [clean].executor": "Run",
"Maven.real-name-screen [install].executor": "Run",
"Maven.realname-app [clean].executor": "Run",
"Maven.realname-app [install].executor": "Run",
"RequestMappingsPanelOrder0": "0",
"RequestMappingsPanelOrder1": "1",
"RequestMappingsPanelWidth0": "75",
"RequestMappingsPanelWidth1": "75",
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.git.unshallow": "true",
"SONARLINT_PRECOMMIT_ANALYSIS": "true",
"Spring Boot.BonusGatewayApplication.executor": "Debug",
"Spring Boot.CzlScreenApplication.executor": "Run",
"Spring Boot.CzlServiceApplication.executor": "Debug",
"Spring Boot.HnRealNameBmwApplication.executor": "Debug",
"Spring Boot.LdlzApplication.executor": "Debug",
"Spring Boot.RealNameAppApplication.executor": "Debug",
"Spring Boot.RnamaApplication.executor": "Run",
"Spring Boot.RnmwApplication.executor": "Run",
"git-widget-placeholder": "main",
"kotlin-language-version-configured": "true",
"last_opened_file_path": "F:/workspace/idea/hn_cloud_service/realname-app/src/main/resources/file",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "npm",
"project.structure.last.edited": "Project",
"project.structure.proportion": "0.15",
"project.structure.side.proportion": "0.43843496",
"run.configurations.included.in.services": "true",
"settings.editor.selected.configurable": "reference.settings.project.maven.importing",
"vue.rearranger.settings.migration": "true"
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;Maven.HnRealNameBmw [clean].executor&quot;: &quot;Run&quot;,
&quot;Maven.HnRealNameBmw [install].executor&quot;: &quot;Run&quot;,
&quot;Maven.HnRealNameMmw [clean].executor&quot;: &quot;Run&quot;,
&quot;Maven.HnRealNameMmw [install].executor&quot;: &quot;Run&quot;,
&quot;Maven.hn-czl-service [clean].executor&quot;: &quot;Run&quot;,
&quot;Maven.hn-czl-service [install].executor&quot;: &quot;Run&quot;,
&quot;Maven.hn-gateway [clean].executor&quot;: &quot;Run&quot;,
&quot;Maven.hn-gateway [install].executor&quot;: &quot;Run&quot;,
&quot;Maven.hn_czl_screen [clean].executor&quot;: &quot;Run&quot;,
&quot;Maven.hn_czl_screen [install].executor&quot;: &quot;Run&quot;,
&quot;Maven.ldlz [clean].executor&quot;: &quot;Run&quot;,
&quot;Maven.ldlz [install].executor&quot;: &quot;Run&quot;,
&quot;Maven.real-name [clean].executor&quot;: &quot;Run&quot;,
&quot;Maven.real-name [install].executor&quot;: &quot;Run&quot;,
&quot;Maven.real-name-screen [clean].executor&quot;: &quot;Run&quot;,
&quot;Maven.real-name-screen [install].executor&quot;: &quot;Run&quot;,
&quot;Maven.realname-app [clean].executor&quot;: &quot;Run&quot;,
&quot;Maven.realname-app [install].executor&quot;: &quot;Run&quot;,
&quot;RequestMappingsPanelOrder0&quot;: &quot;0&quot;,
&quot;RequestMappingsPanelOrder1&quot;: &quot;1&quot;,
&quot;RequestMappingsPanelWidth0&quot;: &quot;75&quot;,
&quot;RequestMappingsPanelWidth1&quot;: &quot;75&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;,
&quot;SONARLINT_PRECOMMIT_ANALYSIS&quot;: &quot;true&quot;,
&quot;Spring Boot.BonusGatewayApplication.executor&quot;: &quot;Debug&quot;,
&quot;Spring Boot.CzlScreenApplication.executor&quot;: &quot;Run&quot;,
&quot;Spring Boot.CzlServiceApplication.executor&quot;: &quot;Debug&quot;,
&quot;Spring Boot.HnRealNameBmwApplication.executor&quot;: &quot;Debug&quot;,
&quot;Spring Boot.LdlzApplication.executor&quot;: &quot;Debug&quot;,
&quot;Spring Boot.RealNameAppApplication.executor&quot;: &quot;Debug&quot;,
&quot;Spring Boot.RnamaApplication.executor&quot;: &quot;Run&quot;,
&quot;Spring Boot.RnmwApplication.executor&quot;: &quot;Run&quot;,
&quot;git-widget-placeholder&quot;: &quot;main&quot;,
&quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
&quot;last_opened_file_path&quot;: &quot;F:/workspace/idea/hn_cloud_service/realname-app/src/main/resources/file&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;project.structure.last.edited&quot;: &quot;Project&quot;,
&quot;project.structure.proportion&quot;: &quot;0.15&quot;,
&quot;project.structure.side.proportion&quot;: &quot;0.43843496&quot;,
&quot;run.configurations.included.in.services&quot;: &quot;true&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;reference.settings.project.maven.importing&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
}
}]]></component>
}</component>
<component name="ReactorSettings">
<option name="notificationShown" value="true" />
</component>
@ -231,9 +227,9 @@
</configuration>
<recent_temporary>
<list>
<item itemvalue="Spring Boot.BonusGatewayApplication" />
<item itemvalue="Spring Boot.LdlzApplication" />
<item itemvalue="Spring Boot.CzlServiceApplication" />
<item itemvalue="Spring Boot.LdlzApplication" />
<item itemvalue="Spring Boot.BonusGatewayApplication" />
<item itemvalue="Spring Boot.CzlScreenApplication" />
<item itemvalue="Spring Boot.RnmwApplication" />
</list>
@ -264,7 +260,9 @@
<workItem from="1765847372970" duration="757000" />
<workItem from="1765855068157" duration="57024000" />
<workItem from="1766108031136" duration="37559000" />
<workItem from="1766389415424" duration="59537000" />
<workItem from="1766389415424" duration="61352000" />
<workItem from="1766649486790" duration="8234000" />
<workItem from="1766659507857" duration="5117000" />
</task>
<task id="LOCAL-00001" summary="修改新增用户">
<option name="closed" value="true" />
@ -490,7 +488,15 @@
<option name="project" value="LOCAL" />
<updated>1766633422277</updated>
</task>
<option name="localTasksCounter" value="29" />
<task id="LOCAL-00029" summary="文件OSS上传">
<option name="closed" value="true" />
<created>1766646738276</created>
<option name="number" value="00029" />
<option name="presentableId" value="LOCAL-00029" />
<option name="project" value="LOCAL" />
<updated>1766646738276</updated>
</task>
<option name="localTasksCounter" value="30" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">

View File

@ -1,108 +1,258 @@
package com.bonus.hnrn.rnama.core.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import org.springframework.web.bind.annotation.RequestParam;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.Base64;
/**
* 资源文件访问控制器iOS+安卓全端预览适配解决WebView拦截下载问题
*/
@RestController
@RequestMapping("/api/resource")
@Slf4j
public class ResourceFileController {
// 固定文件根目录resources/files/
private static final String RESOURCE_ROOT = "file/";
private static final long MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
/**
* 获取资源文件支持直接预览/Base64预览两种模式
* @param request 请求对象
* @param filePath 文件路径
* @param forcePreview 是否强制预览默认true
* @param returnBase64 是否返回Base64前端兜底预览默认false
* @return 文件响应/Base64字符串
*/
@GetMapping("getResourceFile")
public ResponseEntity<byte[]> getResourceFile(@RequestParam String filePath) { // 显式声明@RequestParam避免参数绑定失败
public ResponseEntity<?> getResourceFile(
HttpServletRequest request,
@RequestParam String filePath,
@RequestParam(defaultValue = "true") boolean forcePreview,
@RequestParam(defaultValue = "false") boolean returnBase64) {
try {
// 1. 入参校验避免空指针
// 1. 入参校验
if (filePath == null || filePath.trim().isEmpty()) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
}
String fullPath = RESOURCE_ROOT + filePath.trim();
Resource resource = new ClassPathResource(fullPath);
long originalFileSize = 0;
if (resource.exists()) {
originalFileSize = resource.contentLength();
return buildErrorResponse(HttpStatus.BAD_REQUEST, "文件路径不能为空");
}
// 2. 校验文件存在性
// 2. 路径安全过滤
String cleanPath = sanitizeFilePath(filePath);
String fullPath = RESOURCE_ROOT + cleanPath;
// 3. 校验文件存在性和可读性
ClassPathResource resource = new ClassPathResource(fullPath);
if (!resource.exists() || !resource.isReadable()) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
}
// 3. 读取文件字节流核心确保完整读取兼容JAR包
byte[] fileBytes;
try (InputStream inputStream = resource.getInputStream()) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
bos.write(buffer, 0, bytesRead);
}
fileBytes = bos.toByteArray();
// 校验读取完整性
if (fileBytes.length != originalFileSize) {
System.err.println("警告:读取的字节数与原文件大小不一致!");
}
} catch (IOException e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
return buildErrorResponse(HttpStatus.NOT_FOUND, "文件不存在或不可读取");
}
// 4. 确定媒体类型优先PDF兜底自动识别
MediaType mediaType = MediaType.APPLICATION_PDF;
if (!filePath.endsWith(".pdf")) {
mediaType = getMediaTypeByFileName(filePath);
// 4. 校验文件大小
long fileSize = resource.contentLength();
if (fileSize > MAX_FILE_SIZE) {
return buildErrorResponse(HttpStatus.PAYLOAD_TOO_LARGE, "文件超过10MB暂不支持预览");
}
// 5. 构建响应头解决乱码/空白核心
HttpHeaders headers = new HttpHeaders();
headers.setContentType(mediaType); // 强制媒体类型
headers.setContentLength(fileBytes.length); // 明确文件大小
// 禁用缓存避免浏览器加载旧文件
headers.setCacheControl(CacheControl.noCache().noStore().getHeaderValue());
// 跨域配置完整且正确
// headers.setAccessControlAllowOrigin("*");
// List<HttpMethod> allowedMethods = Arrays.asList(HttpMethod.GET, HttpMethod.OPTIONS);
// headers.setAccessControlAllowMethods(allowedMethods);
// 关键预览模式inline避免触发下载
// 设置Content-Disposition
headers.setContentDisposition(ContentDisposition.builder("inline")
.filename(filePath, java.nio.charset.StandardCharsets.UTF_8)
.build());
// 5. 读取文件字节流
byte[] fileBytes = readFileToBytes(resource);
// 6. 返回字节数组核心修正不再返回Resource
return ResponseEntity.ok()
.headers(headers)
.body(fileBytes);
// 6. 解析文件名和媒体类型
String fileName = Paths.get(cleanPath).getFileName().toString();
MediaType mediaType = getMediaTypeByFileName(fileName);
// 7. 识别客户端类型
boolean isAndroid = isAndroidClient(request);
boolean isIOS = isIOSClient(request);
// 8. 前端兜底返回Base64绕过WebView拦截
if (returnBase64) {
String base64Data = Base64.getEncoder().encodeToString(fileBytes);
// 返回Base64+文件类型前端用<embed>/<img>渲染
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_JSON)
.body("{\"base64\":\"" + base64Data + "\",\"type\":\"" + mediaType.getType() + "/" + mediaType.getSubtype() + "\",\"fileName\":\"" + fileName + "\"}");
}
// 9. 构建全端兼容的响应头移除触发下载的配置
HttpHeaders headers = buildCrossPlatformHeaders(fileName, mediaType, fileBytes.length, isAndroid, isIOS, forcePreview,request);
// 10. 返回文件字节流
return ResponseEntity.ok().headers(headers).body(fileBytes);
} catch (IllegalArgumentException e) {
return buildErrorResponse(HttpStatus.BAD_REQUEST, e.getMessage());
} catch (IOException e) {
log.error("读取文件失败,路径:{}", filePath, e);
return buildErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, "文件读取失败:" + e.getMessage());
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
log.error("获取文件异常,路径:{}", filePath, e);
return buildErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, "服务器内部错误");
}
}
/**
* 兜底的媒体类型识别
* 识别安卓客户端包含微信/支付宝内置WebView
*/
private boolean isAndroidClient(HttpServletRequest request) {
String userAgent = request.getHeader("User-Agent");
if (userAgent == null) {
return false;
}
String lowerUA = userAgent.toLowerCase();
return lowerUA.contains("android") || lowerUA.contains("linux; u")
|| lowerUA.contains("micromessenger") || lowerUA.contains("alipayclient");
}
/**
* 识别iOS客户端
*/
private boolean isIOSClient(HttpServletRequest request) {
String userAgent = request.getHeader("User-Agent");
if (userAgent == null) {
return false;
}
String lowerUA = userAgent.toLowerCase();
return lowerUA.contains("iphone") || lowerUA.contains("ipad") || lowerUA.contains("ipod")
|| (lowerUA.contains("micromessenger") && lowerUA.contains("ios"));
}
/**
* 构建全端兼容响应头核心移除触发下载的配置
*/
private HttpHeaders buildCrossPlatformHeaders(String fileName, MediaType mediaType, int contentLength,
boolean isAndroid, boolean isIOS, boolean forcePreview,HttpServletRequest request) throws UnsupportedEncodingException {
HttpHeaders headers = new HttpHeaders();
// 基础配置
headers.setContentLength(contentLength);
headers.set(HttpHeaders.ACCEPT_RANGES, "bytes");
headers.set("X-Content-Type-Options", "nosniff");
headers.set("X-Frame-Options", "SAMEORIGIN");
// 文件名编码
String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name())
.replace("+", "%20")
.replace("%2B", "+");
// ========== iOS 适配 ==========
if (isIOS && forcePreview) {
headers.setContentType(mediaType);
headers.setCacheControl(CacheControl.maxAge(3600, java.util.concurrent.TimeUnit.SECONDS));
headers.setPragma("public");
headers.setExpires(System.currentTimeMillis() + 3600 * 1000);
if (MediaType.APPLICATION_PDF.equals(mediaType)) {
headers.add(HttpHeaders.CONTENT_DISPOSITION, "inline; filename*=UTF-8''" + encodedFileName);
} else if (isImageMediaType(mediaType)) {
headers.remove(HttpHeaders.CONTENT_DISPOSITION);
} else {
headers.add(HttpHeaders.CONTENT_DISPOSITION, "inline; filename*=UTF-8''" + encodedFileName);
}
headers.set("Access-Control-Allow-Origin", request.getHeader("Origin") == null ? "*" : request.getHeader("Origin"));
headers.set("Access-Control-Allow-Credentials", "true");
// ========== 安卓适配核心优化移除触发下载的配置 ==========
} else if (isAndroid && forcePreview) {
headers.setCacheControl(CacheControl.noCache().noStore().mustRevalidate());
headers.setPragma("no-cache");
headers.setExpires(0);
if (MediaType.APPLICATION_PDF.equals(mediaType)) {
// 关键移除Content-Transfer-Encoding避免WebView识别为下载文件
// 伪图片流适配让WebView认为是图片绕过PDF拦截
headers.setContentType(MediaType.parseMediaType("application/pdf"));
// 移除双Content-Type避免触发下载
// headers.add("Content-Type", "application/octet-stream");
headers.remove(HttpHeaders.CONTENT_DISPOSITION);
// 新增微信WebView兼容
headers.set("Access-Control-Allow-Origin", "*");
headers.set("Access-Control-Allow-Methods", "GET");
// 禁用下载引导
headers.set("Content-Disposition", "inline");
} else if (isImageMediaType(mediaType)) {
headers.setContentType(mediaType);
headers.remove(HttpHeaders.CONTENT_DISPOSITION);
// 移除base64编码头避免触发下载
// headers.set("Content-Transfer-Encoding", "base64");
} else if (isTextMediaType(mediaType)) {
headers.setContentType(mediaType);
headers.add(HttpHeaders.CONTENT_DISPOSITION, "inline; filename*=UTF-8''");
}
// ========== 其他客户端 ==========
} else {
headers.setContentType(mediaType);
headers.setCacheControl(CacheControl.maxAge(60, java.util.concurrent.TimeUnit.MINUTES));
headers.add(HttpHeaders.CONTENT_DISPOSITION,
"inline; filename=\"" + encodedFileName + "\"; filename*=UTF-8''" + encodedFileName);
}
return headers;
}
/**
* 读取文件到字节数组
*/
private byte[] readFileToBytes(ClassPathResource resource) throws IOException {
try (InputStream inputStream = resource.getInputStream()) {
byte[] buffer = new byte[4096];
int bytesRead;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while ((bytesRead = inputStream.read(buffer)) != -1) {
bos.write(buffer, 0, bytesRead);
}
return bos.toByteArray();
}
}
/**
* 构建错误响应
*/
private ResponseEntity<byte[]> buildErrorResponse(HttpStatus status, String message) {
return ResponseEntity.status(status)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(message.getBytes(StandardCharsets.UTF_8));
}
/**
* 路径安全过滤
*/
private String sanitizeFilePath(String filePath) {
String cleanPath = filePath.trim()
.replace("%2F", "/")
.replace("%5C", "\\");
if (cleanPath.contains("../") || cleanPath.contains("..\\")
|| cleanPath.startsWith("/") || cleanPath.startsWith("\\")
|| cleanPath.contains("://")) {
throw new IllegalArgumentException("非法文件路径,禁止路径遍历或绝对路径访问");
}
return cleanPath.replace("\\", "/");
}
/**
* 媒体类型识别
*/
private MediaType getMediaTypeByFileName(String fileName) {
if (fileName == null) {
return MediaType.APPLICATION_OCTET_STREAM;
}
String lowerName = fileName.toLowerCase();
if (lowerName.endsWith(".jpg") || lowerName.endsWith(".jpeg")) {
if (lowerName.endsWith(".pdf")) {
return MediaType.APPLICATION_PDF;
} else if (lowerName.endsWith(".jpg") || lowerName.endsWith(".jpeg")) {
return MediaType.IMAGE_JPEG;
} else if (lowerName.endsWith(".png")) {
return MediaType.IMAGE_PNG;
@ -110,8 +260,36 @@ public class ResourceFileController {
return MediaType.IMAGE_GIF;
} else if (lowerName.endsWith(".json")) {
return MediaType.APPLICATION_JSON;
} else if (lowerName.endsWith(".txt")) {
return MediaType.TEXT_PLAIN;
} else if (lowerName.endsWith(".html") || lowerName.endsWith(".htm")) {
return MediaType.TEXT_HTML;
} else {
return MediaType.APPLICATION_OCTET_STREAM;
}
}
}
/**
* 判断是否为图片媒体类型
*/
private boolean isImageMediaType(MediaType mediaType) {
if (mediaType == null) {
return false;
}
return MediaType.IMAGE_JPEG.isCompatibleWith(mediaType)
|| MediaType.IMAGE_PNG.isCompatibleWith(mediaType)
|| MediaType.IMAGE_GIF.isCompatibleWith(mediaType);
}
/**
* 判断是否为文本媒体类型
*/
private boolean isTextMediaType(MediaType mediaType) {
if (mediaType == null) {
return false;
}
return MediaType.TEXT_PLAIN.isCompatibleWith(mediaType)
|| MediaType.TEXT_HTML.isCompatibleWith(mediaType)
|| MediaType.APPLICATION_JSON.isCompatibleWith(mediaType);
}
}

View File

@ -32,31 +32,44 @@ public class SubMsgBean implements Serializable {
*/
private String idCardJustUrl;
private String idCardJustUrlPath;
/**
* 反面身份证照片路径
*/
private String idCardBackUrl;
private String idCardBackUrlPath;
/**
* 电子签名/印章照片路径
*/
private String signatureUrl;
private String signatureUrlPath;
/**
* 电子公章照片路径
*/
private String sealUrl;
private String sealUrlPath;
/**
* 营业执照片路径
*/
private String businessUrl;
private String businessUrlPath;
/**
* 安全许可证照片路径
*/
private String safetyUrl;
private String safetyUrlPath;
/**
* 登录账号电话
*/

View File

@ -49,7 +49,16 @@ public class PersonIdentifyServiceImpl implements PersonIdentifyService {
@Override
public SubMsgBean selectSubMsgByPhone(SubMsgBean bean) {
return dao.selectSubMsgByPhone(bean);
SubMsgBean bean1= dao.selectSubMsgByPhone(bean);
if(bean1!=null){
bean1.setIdCardBackUrlPath(uploadService.getPresignedUrl(bean1.getIdCardBackUrl()));
bean1.setIdCardJustUrlPath(uploadService.getPresignedUrl(bean1.getIdCardJustUrl()));
bean1.setSignatureUrlPath(uploadService.getPresignedUrl(bean1.getSignatureUrl()));
bean1.setSafetyUrlPath(uploadService.getPresignedUrl(bean1.getSafetyUrl()));
bean1.setBusinessUrlPath(uploadService.getPresignedUrl(bean1.getBusinessUrl()));
bean1.setSealUrlPath(uploadService.getPresignedUrl(bean1.getSealUrl()));
}
return bean1;
}
}

View File

@ -234,6 +234,11 @@ public class WorkPersonServiceImpl implements WorkPersonService {
String month = DateTimeHelper.getNowMonths();
String day = DateTimeHelper.getDay();
String imageFiles = "/rdata/gz_real_name/contract/pdf/";
String os = System.getProperty("os.name");
if(os.toLowerCase().startsWith("win")){
imageFiles="D://images/lsdPhoto/contract/pdf/";
}
String code = StringHelper.getPicNameFromPath(bean.getSubPdfUrl().replaceAll(".pdf",""));
String oldUrl = imageFiles + bean.getSubPdfUrl().replace("gzRealName/contract/pdf/","");
String newUrl = imageFiles + year +"/" + month +"/"+ day + "/" + code + "_sign.pdf";
@ -241,11 +246,13 @@ public class WorkPersonServiceImpl implements WorkPersonService {
bean.setSubPdfUrl(path);
List<String> list = new ArrayList<>();
String companySeal = "/rdata/gz_real_name/" + signUrl.replaceAll("gzRealName/","");
//String companySeal = "/rdata/gz_real_name/" + signUrl.replaceAll("gzRealName/","");
String companySeal=uploadService.getPresignedUrl( signUrl);
list.add(companySeal);
if (!StringHelper.isEmptyAndNull(clientSignUrl)){
String clientSign = "/rdata/gz_real_name/" + clientSignUrl.replaceAll("gzRealName/","");
//String clientSign = "/rdata/gz_real_name/" + clientSignUrl.replaceAll("gzRealName/","");
String clientSign=uploadService.getPresignedUrl( clientSignUrl);
list.add(clientSign);
}
@ -255,13 +262,17 @@ public class WorkPersonServiceImpl implements WorkPersonService {
if (!StringHelper.isEmptyAndNull(bean.getAqxysPath())){
//安全协议书
String codeAqxy = StringHelper.getPicNameFromPath(bean.getAqxysPath().replaceAll(".pdf",""));
String oldUrlAqxy = imageFiles + bean.getAqxysPath().replace("gzRealName/contract/pdf/","");
//String oldUrlAqxy = imageFiles + bean.getAqxysPath().replace("gzRealName/contract/pdf/","");
String oldUrlAqxy=uploadService.getPresignedUrl( bean.getAqxysPath());
String newUrlAqxy = imageFiles + year +"/" + month +"/"+ day + "/" + codeAqxy + "_sign.pdf";
String pathAqxy = "gzRealName/contract/pdf/" + year +"/" + month +"/"+ day +"/"+ codeAqxy + "_sign.pdf";
bean.setAqxysPath(pathAqxy);
PdfUtil pdfUtils = new PdfUtil();
try {
pdfUtils.addPdfMarkAqxy(oldUrlAqxy,newUrlAqxy,list);
File file=new File(newUrlAqxy);
Map<String,String> map=uploadService.uploadLocalFile(file,"app/contract/pdf");
// String pathAqxy = "gzRealName/contract/pdf/" + year +"/" + month +"/"+ day +"/"+ codeAqxy + "_sign.pdf";
boolean isDel=file.delete();
bean.setAqxysPath(map.get("url"));
} catch (Exception e) {
e.printStackTrace();
return 0;
@ -281,6 +292,7 @@ public class WorkPersonServiceImpl implements WorkPersonService {
bean2.setVideoUrlPath(uploadService.getPresignedUrl(bean2.getVideoUrl()));
bean2.setPersonPdfUrlPath(uploadService.getPresignedUrl(bean2.getPersonPdfUrl()));
bean2.setAqxysPathUrl(uploadService.getPresignedUrl(bean2.getAqcnsPath()));
bean2.setPartBSign(uploadService.getPresignedUrl(bean2.getPartBSign()));
}
return list;
}
@ -291,8 +303,10 @@ public class WorkPersonServiceImpl implements WorkPersonService {
for (ContractBean bean2 : list) {
bean2.setPersonPdfUrlPath(uploadService.getPresignedUrl(bean2.getPersonPdfUrl()));
bean2.setVideoUrlPath(uploadService.getPresignedUrl(bean2.getVideoUrl()));
bean2.setAqxysPathUrl(uploadService.getPresignedUrl(bean2.getAqcnsPath()));
bean2.setAqxysPathUrl(uploadService.getPresignedUrl(bean2.getAqxysPath()));
bean2.setPartBSign(uploadService.getPresignedUrl(bean2.getPartBSign()));
bean2.setAqcnsPath(uploadService.getPresignedUrl(bean2.getAqcnsPath()));
bean2.setJkcnsPath(uploadService.getPresignedUrl(bean2.getJkcnsPath()));
}
return list;
}
@ -384,6 +398,7 @@ public class WorkPersonServiceImpl implements WorkPersonService {
if(!file.exists()){//如果文件夹不存在
file.mkdirs();//创建文件夹
}
bean.setPartBSign(uploadService.getPresignedUrl(bean.getPartBSign()));
pdfUtil.exportReport(specfile + "/" + dataCode + ".pdf",bean);
path =imageFiles+ year +"/" + month +"/"+ day +"/"+ dataCode + ".pdf";
File lastFile=new File(path);

View File

@ -64,12 +64,6 @@ jasypt:
encryptor:
password: Encrypt
oss:
# endpoint: http://oss-ah-2-a.ops.sgmc.sgcc.com.cn/
endpoint: oss-cn-beijing.aliyuncs.com
accessKeyId: LTAI5tRkHKiF1GJiwK5dGFRj
accessKeySecret: jXewIIKO0ZmuuQedpN728M7bMFTNBO
bucketName: lsun

View File

@ -53,15 +53,15 @@
<select id="selectSubMsgByPhone" resultType="com.bonus.hnrn.rnama.person.entity.SubMsgBean">
SELECT
bs.id as subId,
bs.sub_name,
bs.sub_name subName,
bs.represent,
bs.re_contact as subPhone,
bs.id_card_just_url,
bs.id_card_back_url,
bs.signature_url,
bs.seal_url,
bs.business_url,
bs.safety_url
bs.id_card_just_url idCardJustUrl,
bs.id_card_back_url idCardBackUrl,
bs.signature_url signatureUrl,
bs.seal_url sealUrl,
bs.business_url businessUrl,
bs.safety_url safetyUrl
FROM
bns_smz_sys_user su
LEFT JOIN bns_smz_bm_subcontractor bs ON su.sub_id = bs.id