#java #file-io
#java #file-io
Вопрос:
У меня есть generic.exe файл, который не содержит в себе никаких сведений о пользователях. У меня также есть REST API, который принимает идентификатор пользователя и возвращает файл клиенту.
Теперь, что мы хотим реализовать в нашем проекте, так это то, что когда кто-то обращается к REST API, мы хотим использовать это generic.exe и переименуйте его в manager_userId.exe и верни обратно это » .manager_userId.exe «.
Здесь следует отметить, что:
- The generic.exe файл вообще не должен быть изменен / удален
- Когда 2 пользователя (UserA и UserB) одновременно обращаются к одному и тому же API, они должны получить свою собственную копию manager_userA.exe и manager_userB.exe
Код, который я написал
@RequestMapping(value = "/downloadExecutable", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON, produces = {MediaType.APPLICATION_OCTET_STREAM})
@ResponseBody
public Response downloadExecutable(@RequestBody DownloadExecutableRequest downloadExecutableRequest,
HttpServletRequest request, HttpServletResponse response) {
File file = downloadExecutable(downloadExecutableRequest, request, response,
getUserID(request), osDetails);
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
.header("Content-Disposition", "attachment;filename=" file.getName()).build();
}
public File downloadExecutable(DownloadExecutableRequest downloadExecutableRequest, HttpServletRequest request,
HttpServletResponse response, String userId, String osDetails) {
File file = null;
String path = "/home/genericCopy/generic.exe";
synchronized (this) {
BufferedWriter fileWriter = null;
try {
File source = null;
source = new File(path);
Path destination = Paths.get("/tmp/");
Files.copy(source, destination.toFile());
fileWriter = new BufferedWriter(new FileWriter(destination.getFileName().toString() "_" userId));
file = new File(destination.getFileName().toString());
} catch (IOException e) {
} finally {
if (fileWriter != null) {
fileWriter.close();
}
}
}
return file;
}
Код работает, но он создает временный файл, затем переименовывает его, а затем возвращает обратно, но он будет продолжать создавать копии файла для каждого запроса.
Есть ли какой-нибудь более разумный способ, которым я могу добиться, чтобы не создавать такие временные копии пользовательских файлов, а также обрабатывать сценарий, когда 2 пользователя одновременно обращаются к API?
Комментарии:
1. Зачем вы вообще копируете исходный файл? Просто установите расположение содержимого на имя, под которым вы хотите его загрузить, и верните файл шаблона.
2. Боковой комментарий: Вы действительно требуете, чтобы ваши пользователи загружали и выполняли динамически сгенерированный исполняемый файл? Понимаете ли вы угрозу безопасности для систем пользователей?
Ответ №1:
Имя файла, который загружается пользователем, не имеет никакого отношения к имени файла на диске.
Вы можете просто указать любое имя файла в заголовке, и пользователь увидит имя.
В частности, вы бы просто установили имя файла, которое вы хотите, чтобы пользователь видел в Content-Disposition
заголовке, и всегда загружали один и тот же exe-файл с диска.
Что-то вроде этого:
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
.header("Content-Disposition", "attachment;filename=executable_" getUserID(request) ".exe";
Вам не нужно выполнять какое-либо копирование в downloadExecutable
функции.
Ответ №2:
Вам не нужно создавать копию generic.exe
файла, чтобы вернуть его с измененным именем. Вы можете использовать правильно параметризованный Content-Disposition
заголовок, чтобы он каждый раз возвращал один и тот же файл с именем файла, указанным пользователем.
Здесь вы можете найти пример:
@RestController
public class DemoController {
@GetMapping(value = "/file", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@ResponseBody
public ResponseEntity downloadExecutable(@RequestParam("userId") String userId) throws IOException {
byte[] file = Files.readAllBytes(Paths.get("/home/genericCopy/generic.exe"));
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=generic_" userId ".exe")
.contentLength(file.length)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(file);
}
}
и результат выполнения этого метода: