英文:
tomcat server doesn't mapped my real domain name
问题
Spring Boot 应用中的多部分文件获取在生产环境中不起作用
我有一个使用Thymeleaf的Spring Boot MVC Web应用程序。在本地PC上一切正常工作,但在生产环境(远程服务器)尝试查看和下载文件时,URL前缀仍然是"localhost:8080/file-url/view"而不是"example.az/file-url/view"。我的应用程序服务器是Tomcat 9.0.71版本在Linux服务器上。
以下是代码片段
Controller类
@Controller
public class FileBBController {
private final CategoryBBService categoryBBService;
public FileBBController(CategoryBBService categoryBBService) {
this.categoryBBService = categoryBBService;
}
@GetMapping("/files/bb/new")
public String newFile() {
return "legislation/bb/upload_form";
}
@PostMapping(value = "/files/bb/upload")
public String uploadFile(@RequestParam("file") MultipartFile file, Model model) {
String message;
try {
categoryBBService.storeFile(file);
message = "Fayl bazaya müvəfəqiyyətlə yükləndi: " + file.getOriginalFilename();
model.addAttribute("message", message);
Thread.sleep(4000);
} catch (Exception e) {
message = "Diqqət bir fayl seçməlisiniz!";
model.addAttribute("message", message);
}
return "redirect:/bb/files";
}
// 其他控制器方法...
}
Service类
@Service
public class CategoryBBService {
// 服务类代码...
}
Entity类
@Entity
@Table(name = "category_bb")
public class CategoryBB extends FileDB {
// 实体类代码...
}
FileDB抽象类
@MappedSuperclass
public abstract class FileDB implements Serializable {
// 抽象类代码...
}
ResponseFile类
public class ResponseFile {
// 响应文件类代码...
}
files.html
<!-- HTML模板代码... -->
当我点击"Fayla bax (查看文件)"和"Faylı yüklə (下载文件)"按钮时,它的前缀是"http://localhost:8080/files/c9376e46-55cb-4cf5-beab-ba886bb23c5f/bb/view/"之类的。您能帮助我解决这个问题吗?
英文:
Spring boot application multipart get file doesn't working in production environment
I have a spring boot mvc web application with thymeleaf. So everything is working normally in local pc but in production environment (remote server) trying to view and download the file the url prefix is sticking localhost:8080/file-url/view not example.az/file-url/view. My appication server is tomcat 9.0.71 version in linux server.
So here is the code snippet
Controller class
@Controller
public class FileBBController {
private final CategoryBBService categoryBBService;
public FileBBController(CategoryBBService categoryBBService) {
this.categoryBBService = categoryBBService;
}
@GetMapping("/files/bb/new")
public String newFile() {
return "legislation/bb/upload_form";
}
@PostMapping(value = "/files/bb/upload")
public String uploadFile(@RequestParam("file") MultipartFile file, Model model) {
String message;
try {
categoryBBService.storeFile(file);
message = "Fayl bazaya müvəfəqiyyətlə yükləndi: " + file.getOriginalFilename();
model.addAttribute("message", message);
Thread.sleep(4000);
} catch (Exception e) {
message = "Diqqət bir fayl seçməlisiniz!";
model.addAttribute("message", message);
}
return "redirect:/bb/files";
}
@GetMapping("/bb/files")
public String getFiles(Model model) {
String keyword = null;
return getOnePage(1, model, "createdAt", "desc", keyword);
}
@GetMapping("/files/{id}")
public ResponseEntity<Resource> getFile(@PathVariable String id) {
CategoryBB fileDB = categoryBBService.getFile(id);
return ResponseEntity.ok().contentType(MediaType.APPLICATION_PDF)
.header(org.springframework.http.HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + fileDB.getName() + "\"")
.body(new ByteArrayResource(fileDB.getData()));
}
@GetMapping("/bb/files/page/{pageNo}")
public String getOnePage(@PathVariable("pageNo") int currentPage, Model model,
@RequestParam(value = "sortField", required = false) String sortField,
@RequestParam(value = "sortDir", required = false) String sortDir,
@RequestParam(value = "keyword", required = false) String keyword
) {
Page<ResponseFile> page = categoryBBService.findPaginated(currentPage, PAGE_SIZE, sortField, sortDir, keyword).map(dbFile -> {
String fileDownloadUri = ServletUriComponentsBuilder.
fromCurrentContextPath()
.path("/files/")
.path(dbFile.getId())
.toUriString();
System.out.println(fileDownloadUri);
return new ResponseFile(dbFile.getName(),
fileDownloadUri,
dbFile.getType(),
FileUtils.byteCountToDisplaySize(dbFile.getData().length),
dbFile.getCreatedAt());
});
List<ResponseFile> files = page.getContent();
model.addAttribute("currentPage", currentPage);
model.addAttribute("totalPages", page.getTotalPages());
model.addAttribute("totalElements", page.getTotalElements());
model.addAttribute("sortField", sortField);
model.addAttribute("sortDir", sortDir);
model.addAttribute("reverseSortDir", sortDir.equals("asc") ? "desc" : "asc");
model.addAttribute("keyword", keyword);
model.addAttribute("files", files);
return "legislation/bb/files";
}
@RequestMapping(value = "/files/{id}/bb/delete", method = RequestMethod.GET)
public String deleteFile(@PathVariable("id") String id) {
categoryBBService.deleteFileById(id);
return "redirect:/bb/files";
}
@GetMapping("/files/{id}/bb/view")
public void viewFile(@PathVariable String id, HttpServletResponse resp) throws IOException {
CategoryBB file = categoryBBService.getFile(id);
byte[] byteArray = file.getData();
resp.setContentLength(byteArray.length);
try (OutputStream os = resp.getOutputStream()) {
os.write(byteArray, 0, byteArray.length);
}
}
}
Service class
@Service
public class CategoryBBService {
private final CategoryBBRepository categoryBBRepository;
public CategoryBBService(CategoryBBRepository categoryBBRepository) {
this.categoryBBRepository = categoryBBRepository;
}
public void storeFile(MultipartFile file) throws IOException {
String fileName = StringUtils.getFilename(file.getOriginalFilename());
if (StringUtils.endsWithIgnoreCase(fileName, ".pdf")) {
CategoryBB fileDB = new CategoryBB(fileName, file.getContentType(), file.getBytes());
categoryBBRepository.save(fileDB);
} else {
throw new RuntimeException("Wrong file type uploaded");
}
}
public CategoryBB getFile(String id) {
return categoryBBRepository.findById(id).orElse(null);
}
public Page<CategoryBB> findPaginated(int pageNo, int pageSize,
String sortField,
String sortDirection,
String keyword) {
Sort sort = SortUtil.sorting(sortDirection, sortField);
Pageable pageable = PageRequest.of(pageNo - 1, pageSize, sort);
if (keyword != null) {
return categoryBBRepository.findAll(keyword, pageable);
}
return categoryBBRepository.findAll(pageable);
}
public void deleteFileById(String id) {
categoryBBRepository.deleteById(id);
}
}
Entity class
@Entity
@Table(name = "category_bb")
public class CategoryBB extends FileDB {
public CategoryBB() {
}
public CategoryBB(String name, String type, byte[] data) {
super(name, type, data);
}
}
Super class for Entity
@MappedSuperclass
public abstract class FileDB implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
private String id;
private String name;
private String type;
@Column(name = "file_url")
private String fileUrl;
@Lob
private byte[] data;
@CreationTimestamp
@Column(name = "created_at")
private LocalDateTime createdAt;
public FileDB() {
}
public FileDB(String name, String type, byte[] data) {
this.name = name;
this.type = type;
this.data = data;
}
public FileDB(String name, String type, String fileUrl, byte[] data) {
this.name = name;
this.type = type;
this.fileUrl = fileUrl;
this.data = data;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public byte[] getData() {
return data;
}
public void setData(byte[] data) {
this.data = data;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public String getFileUrl() {
return fileUrl;
}
public void setFileUrl(String fileUrl) {
this.fileUrl = fileUrl;
}
ResponseFile class
public class ResponseFile {
private String name;
private String url;
private String type;
private String size;
public ResponseFile() {
}
public ResponseFile(String name, String url, String type, String size, LocalDateTime createdAt) {
this.name = name;
this.url = url;
this.type = type;
this.size = size;
this.createdAt = createdAt;
}
private LocalDateTime createdAt;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
}
files.html
<div th:if="${files.size() > 0}" class="table-responsive">
<table class="table table-hover table-bordered border-primary">
<thead class="thead-light table-secondary">
<tr class="text-center">
<th scope="col">№</th>
<th scope="col">Faylın adı</th>
<th scope="col">Faylı yüklə</th>
<th scope="col">Fayla bax</th>
<th scope="col">Ölçüsü</th>
<th sec:authorize="hasRole('ADMIN')" scope="col">Actions</th>
<th scope="col">
<a style="text-decoration: none; color: black"
th:href="@{'/bb/files/page/' + ${currentPage} + '?sortField=createdAt&sortDir=' + ${reverseSortDir} + ${keyword != null ? '&keyword=' + keyword : ''}}">
Tarix
</a>
</th>
</tr>
</thead>
<tbody class="table-group-divider">
<tr th:each="file, fileStat : ${files}">
<td class="text-center" th:text="${fileStat.count}"></td>
<td th:text="${file.name}"></td>
<td class="text-center"><a th:href="@{${file.url}}"><i class="fa-solid fa-cloud-arrow-down fa-lg"></i></a></td>
<td class="text-center"><a target="_blank" th:href="@{${file.url} + '/bb/view/'}"><i class="fa fa-thin fa-eye fa-lg"></i></a></td>
<td th:text="${file.size}"></td>
<td th:text="${#temporals.format(file.createdAt, 'dd-MM-yyyy, HH:mm')}"></td>
<td sec:authorize="hasRole('ADMIN')" class="text-center">
<a th:href="@{${file.url} + '/bb/delete/'}" th:fileName="${file.name}" style="border: none; background: none"
id="btnDelete" class="btn-delete" data-bs-toggle="modal" data-bs-target="#exampleModal">
<i class="fa-solid fa-trash fa-xl" style="color: red"></i>
</a>
</td>
</tr>
</tbody>
</table>
</div>
When I click the buttton "Fayla bax (view file)" and "Faylı yüklə(download file)" it's prefix comming "http://localhost:8080/files/c9376e46-55cb-4cf5-beab-ba886bb23c5f/bb/view/" something like that. Would you help me solve this issue ?
答案1
得分: 0
基于评论:
如果您仅使用Spring Boot应用程序而没有任何反向代理(如Apache、Nginx),请尝试配置Spring的属性 server.forward-headers-strategy
为 native
或 framework
,这应该解决该问题。
英文:
based on comments:
If you are using just spring-boot application without any reverse proxy (such as apache, nginx) try to configure spring's property server.forward-headers-strategy
to either native
or framework
and it should resolve the issue.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论