Render images in file browser blob view

Add /repo/{name}/raw/{hash}/** endpoint serving binary file content
with correct Content-Type. Blob view detects image extensions (png,
jpg, gif, bmp, webp, svg, ico) and renders an <img> tag instead of
a <pre> text block.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-02-27 10:17:30 +01:00
parent b0c869829f
commit d68933bc2f
5 changed files with 103 additions and 3 deletions
@@ -3,6 +3,8 @@ package be.seeseepuff.webgit.controller;
import be.seeseepuff.webgit.service.GitService;
import lombok.RequiredArgsConstructor;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@@ -12,11 +14,25 @@ import org.springframework.web.bind.annotation.RequestParam;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Controller
@RequiredArgsConstructor
public class RepoController
{
private static final Set<String> IMAGE_EXTENSIONS = Set.of("png", "jpg", "jpeg", "gif", "bmp", "webp", "svg", "ico");
private static final Map<String, String> IMAGE_MIME_TYPES = Map.of(
"png", "image/png",
"jpg", "image/jpeg",
"jpeg", "image/jpeg",
"gif", "image/gif",
"bmp", "image/bmp",
"webp", "image/webp",
"svg", "image/svg+xml",
"ico", "image/x-icon"
);
private final GitService gitService;
@GetMapping("/repo/{name}")
@@ -109,13 +125,32 @@ public class RepoController
String fullPath = request.getRequestURI();
String prefix = "/repo/" + name + "/blob/" + hash + "/";
String filePath = fullPath.substring(prefix.length());
String ext = filePath.contains(".") ? filePath.substring(filePath.lastIndexOf('.') + 1).toLowerCase() : "";
boolean isImage = IMAGE_EXTENSIONS.contains(ext);
model.addAttribute("name", name);
model.addAttribute("hash", hash);
model.addAttribute("filePath", filePath);
model.addAttribute("content", gitService.getFileContentAtCommit(name, hash, filePath));
model.addAttribute("isImage", isImage);
if (!isImage)
model.addAttribute("content", gitService.getFileContentAtCommit(name, hash, filePath));
return "blob";
}
@GetMapping("/repo/{name}/raw/{hash}/**")
public ResponseEntity<byte[]> rawFile(@PathVariable String name, @PathVariable String hash,
jakarta.servlet.http.HttpServletRequest request) throws IOException
{
String fullPath = request.getRequestURI();
String prefix = "/repo/" + name + "/raw/" + hash + "/";
String filePath = fullPath.substring(prefix.length());
byte[] bytes = gitService.getRawFileAtCommit(name, hash, filePath);
if (bytes == null)
return ResponseEntity.notFound().build();
String ext = filePath.contains(".") ? filePath.substring(filePath.lastIndexOf('.') + 1).toLowerCase() : "";
String mimeType = IMAGE_MIME_TYPES.getOrDefault(ext, MediaType.APPLICATION_OCTET_STREAM_VALUE);
return ResponseEntity.ok().contentType(MediaType.parseMediaType(mimeType)).body(bytes);
}
@PostMapping("/repo/{name}/checkout-commit")
public String checkoutCommit(@PathVariable String name, @RequestParam String hash) throws IOException, GitAPIException
{
@@ -490,6 +490,14 @@ public class GitService
}
public String getFileContentAtCommit(String name, String commitHash, String filePath) throws IOException
{
byte[] bytes = getRawFileAtCommit(name, commitHash, filePath);
if (bytes == null)
return null;
return new String(bytes, StandardCharsets.UTF_8);
}
public byte[] getRawFileAtCommit(String name, String commitHash, String filePath) throws IOException
{
try (Git git = openRepository(name))
{
@@ -505,7 +513,7 @@ public class GitService
if (tw == null)
return null;
ObjectLoader loader = repo.open(tw.getObjectId(0));
return new String(loader.getBytes(), StandardCharsets.UTF_8);
return loader.getBytes();
}
}
}
+4 -1
View File
@@ -25,7 +25,10 @@
</table>
<h3>Content</h3>
<pre th:text="${content}">File content here</pre>
<div th:if="${isImage}">
<img th:src="@{/repo/{name}/raw/{hash}/{filePath}(name=${name}, hash=${hash}, filePath=${filePath})}" alt="" border="0">
</div>
<pre th:unless="${isImage}" th:text="${content}">File content here</pre>
</body>
</html>