Hi,
By default, portal does not have a Spring MVC Controller that can expose files or images to web browser. You have to create it manually in your project.
This controller doesn’t have to read files from a disk manually since your application can be deployed in a distributed configuration.
There is a special infrastructure interface FileLoader that can load binary data of files to client. Let’s use it to show images in a portal application. See also: FileLoader Interface - CUBA Platform. Developer’s Manual
First of all we need to create a controller that will load binary data from a middleware when a web browser requests image content:
@Controller
public class PngFilesController {
private final Logger log = LoggerFactory.getLogger(PngFilesController.class);
@Inject
protected UserSessionService userSessionService;
@Inject
protected DataService dataService;
@Inject
protected FileLoader fileLoader; // file loader is used to load file data from middleware to clients
@GetMapping("/images/{fileId}")
public void downloadImage(@PathVariable String fileId,
@RequestParam(required = false) Boolean attachment,
HttpServletResponse response) throws IOException {
UUID uuid;
try {
uuid = UUID.fromString(fileId);
} catch (IllegalArgumentException e) {
response.sendError(HttpStatus.BAD_REQUEST.value(), "Invalid entity ID");
return;
}
LoadContext<FileDescriptor> ctx = LoadContext.create(FileDescriptor.class).setId(uuid);
FileDescriptor fd = dataService.load(ctx);
// We will send only PNG files here
if (fd == null || !"png".equals(fd.getExtension())) {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
// YOU HAVE TO CHECK SECURITY RULES MANUALLY HERE OR SETUP ACCESS GROUP CONSTRAINTS FOR ALL USERS !
try {
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
response.setHeader("Content-Type", getContentType(fd));
response.setHeader("Content-Disposition", (BooleanUtils.isTrue(attachment) ? "attachment" : "inline")
+ "; filename=\"" + fd.getName() + "\"");
ServletOutputStream os = response.getOutputStream();
try (InputStream is = fileLoader.openStream(fd)) {
IOUtils.copy(is, os);
os.flush();
}
} catch (Exception e) {
log.error("Error on downloading the file {}", fileId, e);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
protected String getContentType(FileDescriptor fd) {
if (StringUtils.isEmpty(fd.getExtension())) {
return FileTypesHelper.DEFAULT_MIME_TYPE;
}
return FileTypesHelper.getMIMEType("." + fd.getExtension().toLowerCase());
}
}
Here we simply load binary data and write it to HTTP response. Please note that you have to setup Access groups (including anonymous user)
with proper security settings or check security manually in the controller.
After that, let’s load all the PNG images from a database and show them on index page.
Portal controller:
@Controller
public class PortalController {
@Inject
protected DataService dataService;
@RequestMapping(value = "/", method = RequestMethod.GET)
public String index(Model model) {
// load all .png files from db
List<FileDescriptor> files = dataService.loadList(LoadContext.create(FileDescriptor.class)
.setQuery(new LoadContext.Query("select fd from sys$FileDescriptor fd")));
List<UUID> fileIds = files.stream()
.filter(fd -> "png".equals(fd.getExtension()))
.map(BaseUuidEntity::getId)
.collect(Collectors.toList());
model.addAttribute("fileIds", fileIds);
return "index";
}
}
Add the following code to index.html thymeleaf template:
<h1>All .png images from FileStorage</h1>
<ul th:each="fileId: ${fileIds}">
<li>
<img th:src="@{${'images/'+ fileId}}"/>
</li>
</ul>
The last option we have to set is to setup Spring Security options in portal-security-spring.xml:
<!-- We will simply enable anonymous access to images,
but you can decide if want to do it or not -->
<http pattern="/images/**" security="none"/>
Now we can restart the application and upload a couple of PNG images using web interface.
Finally, open index page of portal - and we will see our images.
You can find complere sample project on GitHub: GitHub - cuba-labs/portal-images: How to load and shows images from FileStorage in portal module