display photos in grails vs playframework - grails

I have been doing some tests using Grails framework and now I'm trying to do something similar in playframework.
Basically, I want to display some pictures, but to hide (in order to be able to avoid any crawling and to be able to change the hosting ) the pictures path.
The gsp page:
<g:each in="${images}" var="img">
<img class="thumbnail" src='${createLink(controller: "images", action: "displayImage", params:[img: img.name])}'/>
</g:each>
The controller:
def displayImage() {
File image = new File(IMAGES_DIR.absolutePath +'/' + params.img)
if(!image.exists()) {
response.status = 404
} else {
response.setContentType("application/jpg")
OutputStream out = response.getOutputStream();
out.write(image.bytes);
out.close();
}
}
The html generated page it looks like:
<img class="thumbnail" src='/myhost/images/displayImage?img=blabla.jpg' />
My questions:
Is this a best way to do it ?
Regarding the performance ?
Is this slower than juste displaying the pictures using http ?
Can I do something like this in Playframework ? If yes, how ?
Thanks.
C.C.

For static and public resources most probably using raw HTTP server will be fastest solution, so I don't think it's required to "drag" it through Java controller. Actually you can do it with Play very similar, but even easier - as Play allows yo to return a File as a response body directly ie (written from top of my head):
public static Result displayImage(String imagePath) {
File image = new File(SOME_CONFIGURED_FOLDER_WITH_IMAGES +'/' + imagePath)
if(!image.exists()) return notFound();
return ok(image).as("image/jpg");
}
Anyway, you should use it only if:
You are not gonna to use additional HTTP server (remember, that Play has built in one?)
You need to bring some access control
You want to perform some operations, ie. scaling, cropping etc. (in such case, IMHO it's also better to use Play only for creating the thumbnail, and serve it with common HTTP server...)
Thank's to this approach:
You don't waste processor's resources, as HTTP server just need to serve the file which is stored on disk, instead of rewriting it to the Result.
Your app can concentrate on other dynamic operations so it's faster.
You can (and should) use typical webmaster's techniques for optimizing serving static contents, like cookie free domains, advanced caching headers etc. (ofc you can do that also within Play controller, but...)

Related

How to make sure a cached page has its corresponding assets cached?

tl;dr. My Service Worker is caching HTML pages and CSS files in different versions. Going offline: since I have to limit the number of files I’m caching, how can I make sure that, for each HTML page in the cache, the versioned CSS files it needs are also in the cache? I need to delete old CSS files at some point, and they have no direct relation with the HTML files.
I’m trying to turn a traditional website into a PWA (sort of), implementing caching strategies with a Service Worker (I’m using Workbox but the question is supposed to be more generalist).
I’m caching pages as I navigate through the website (network-first strategy), in order to make them available offline.
I’m also caching a limited number of CSS and JS assets with a cache-first strategy. The URLs pointing to them are already "cachebusted" using a timestamp embedded in the filename: front.320472502.css for instance. Because of the cachebusting technique already in place, I only need/want to keep a small number of assets in this cache.
Now here’s the issue I’m having. Let’s suppose I cached page /contact which referenced /front.123.css (hence was also cached). As I navigate to other pages, CSS has changed several times in the meantime, and my CSS cache now might contain only /front.455.css and /front.456.css. If I’m going offline now, trying to load /contact will successfully retrieve the contents of the page, but the CSS will fail to load because it’s not in the cache anymore, and it will render an unstyled content page.
Either I keep versions of my CSS in cache for a long time, which is not ideal, or I try to purge cached CSS only if it is not required by any of the cached pages. But how would you go about that? Looping through the cached pages, looking for the front.123.css string?
Another solution might be to give back an offline page rather than an unstyled content page, but I’m not sure if it is doable, since the worker responds with the HTML before knowing what assets it will need.
The "best" solution here is to use precaching (either via Workbox, or via some other way of generating a build-time manifest), and making sure that all of your HTML and subresources are cached and expired atomically. You don't have to worry about version mismatches or cache misses if you can precache everything.
That being said, precaching everything isn't always a viable option, if your site relies on a lot of dynamic, server-rendered content, or if you have a lot of distinct HTML pages, or if you have a larger variety of subresources, many of which are only required on a subset of pages.
If you want to go with the runtime caching approach, I'd recommend a technique along the lines of what's described in "Smarter runtime caching of hashed assets". That uses a custom Workbox plugin to handle cache expiration and finding a "best-effort" cache match for a given subresource when the network is unavailable. The main difficulty in generalizing that code is that you need to use a consistent naming scheme for your hashes, and write some utility functions to programmatically translate a hashed URL into the "base" URL.
In the interest of providing some code along with this answer, here's a version of the plugin that I currently use. You'll need to customize it as described above for your hashing scheme, though.
import {WorkboxPlugin} from 'workbox-core';
import {HASH_CHARS} from './path/to/constants';
function getOriginalFilename(hashedFilename: string): string {
return hashedFilename.substring(HASH_CHARS + 1);
}
function parseFilenameFromURL(url: string): string {
const urlObject = new URL(url);
return urlObject.pathname.split('/').pop();
}
function filterPredicate(
hashedURL: string,
potentialMatchURL: string,
): boolean {
const hashedFilename = parseFilenameFromURL(hashedURL);
const hashedFilenameOfPotentialMatch =
parseFilenameFromURL(potentialMatchURL);
return (
getOriginalFilename(hashedFilename) ===
getOriginalFilename(hashedFilenameOfPotentialMatch)
);
}
export const revisionedAssetsPlugin: WorkboxPlugin = {
cachedResponseWillBeUsed: async ({cacheName, cachedResponse, state}) => {
state.cacheName = cacheName;
return cachedResponse;
},
cacheDidUpdate: async ({cacheName, request}) => {
const cache = await caches.open(cacheName);
const keys = await cache.keys();
for (const key of keys) {
if (filterPredicate(request.url, key.url) && request.url !== key.url) {
await cache.delete(key);
}
}
},
handlerDidError: async ({request, state}) => {
if (state.cacheName) {
const cache = await caches.open(state.cacheName);
const keys = await cache.keys();
for (const key of keys) {
if (filterPredicate(request.url, key.url)) {
return cache.match(key);
}
}
}
},
};

Bundling, but per user

We have javascript files which get bundled and compressed using the normal asp.net mvc mechanism.
We also have some javascript files which get transformed via httphandlers to deal with phrases, colour schemes, etc. At present these are simply linked in, could these be compressed and bundled but at the user level?
Unfortunately we can't group these easily, but even if we could we couldn't do it within a global.ascx file without a lot of rejigging. I mention this as it's not simply a case of having bundle1 = french, bundle2=german, etc
Compression I'm assuming could be done via IIS and static compression, but bundling?
thanks
There is no easy way to do this.
The easiest I can see is to skip the whole Bundling and Minification that is shipped with MVC 5.
Handle it yourself. Generate CSS for your user and have it go through this piece of code:
public static string RemoveWhiteSpaceFromStylesheets(string body)
{
body = Regex.Replace(body, #"[a-zA-Z]+#", "#");
body = Regex.Replace(body, #"[\n\r]+\s*", string.Empty);
body = Regex.Replace(body, #"\s+", " ");
body = Regex.Replace(body, #"\s?([:,;{}])\s?", "$1");
body = body.Replace(";}", "}");
body = Regex.Replace(body, #"([\s:]0)(px|pt|%|em)", "$1");
// Remove comments from CSS
body = Regex.Replace(body, #"/\*[\d\D]*?\*/", string.Empty);
return body;
}
Or any CSS minifier for that matter. Just make sure to include proper caching tag for your user and you won't even have to regenerate it too much.
Code taken from Mads Kristensen

Pure Dart DOM possibility?

I am learning Dart and suddenly had an epiphany (or possibly, an epiphany):
Can I write a Dart web app where the "view" is done 100% in Dart?
I'm talking: absolutely no (none/zero/nadda) HTML files (.html). 100% Dart code. Something like:
class SigninView {
LabelElement signinLabel;
InputElement emailTextField;
InputElement passwordTextField;
ButtonElement signinButton;
// constructors, getters, setters, etc.
// Perhaps called from inside constructor...
void initUI() {
signinLabel = new LabelElement();
signinLabel.innerHTML = "<span class=\"blah\">Please sign in</span>";
emailTextField = new InputElement();
emailTextField.innerHTML = "<input type=\"text\" name=\"fizz\" placeholder=\"Email\"/>";
// ...etc.
// htmlFactory would be something I'd need to write myself (?)
String html = htmlFactory.newHTML(signinLabel, emailTextField, ...);
querySelector("#someDivTag").innerHTML = html;
}
}
In theory (that is, my intentions with the above code), as soon as the SigninView is created, it initializes a bunch of DOM elements and populates someDivTag with them.
Is this possible? If so am I "doing it right", or is there a different/preferred/standardized approach to this?
Does this introduce any additional/potential caveats (memory leaks), performance or security issues that I should be aware of?
If I were to adopt this strategy throughout my whole app, can I assume the app would be quicker to download (less HTML text), but slower to execute (dynamic DOM element creation)? If so, is there a way to somehow instantiate all the DOM elements my app will need up front (slowing down initial download time), and then only make certain elements visible as I wish to render different views/screens (thus speeding up execution time)?
You need an HTML file with the script tags for the Dart startup.
Anything else can be done in Dart.

Way to organize client-side templates into individual files?

I'm using Handlebars.js, and currently all my templates live inside script tags which live inside .html files housing dozens of other templates, also inside script tags.
<script type="text/template" id="template-1">
<div>{{variable}}</div>
</script>
<script type="text/template" id="template-2">
<div>{{variable}}</div>
</script>
<script type="text/template" id="template-3">
<div>{{variable}}</div>
</script>
...
Then I include this file on the server-side as a partial.
This has the following disadvantages:
A bunch of templates are crammed into HTML files.
Finding a given template is tedious.
I'm looking for a better way to organize my templates. I'd like each each template to live in its own file. For example:
/public/views/my_controller/my_action/some_template.html
/public/views/my_controller/my_action/some_other_template.html
/public/views/my_controller/my_other_action/another_template.html
/public/views/my_controller/my_other_action/yet_another_template.html
/public/views/shared/my_shared_template.html
Then at the top of my view, in the backend code, I can include these templates when the page loads, like this:
SomeTemplateLibrary.require(
"/public/views/my_controller/my_action/*",
"/public/views/shared/my_shared_template.html"
)
This would include all templates in /public/views/my_controller/my_action/ and also include /public/views/shared/my_shared_template.html.
My question: Are there any libraries out there that provide this or similar functionality? Or, does anyone have any alternative organizational suggestions?
RequireJS is really good library for AMD style dependency management. You can actually use the 'text' plugin of requireJS to load the template file in to your UI component. Once the template is attached to the DOM, you may use any MVVM, MVC library for bindings OR just use jQuery events for your logic.
I'm the author of BoilerplateJS. BoilerplateJS reference architecture uses requireJS for dependency management. It also provides a reference implementations to show how a self contained UI Components should be created. Self contained in the sense to handle its own view template, code behind, css, localization files, etc.
There is some more information available on the boilerplateJS homepage, under "UI components".
http://boilerplatejs.org/
I ended up using RequireJS, which pretty much let me do this. See http://aaronhardy.com/javascript/javascript-architecture-requirejs-dependency-management/.
I use a template loader that loads the template using ajax the first time it is needed, and caches it locally for future requests. I also use a debug variable to make sure the template is not cached when I am in development:
var template_loader = {
templates_cache : {},
load_template : function load_template (params, callback) {
var template;
if (this.templates_cache[params.url]){
callback(this.templates_cache[params.url]);
}
else{
if (debug){
params.url = params.url + '?t=' + new Date().getTime(), //add timestamp for dev (avoid caching)
console.log('avoid caching url in template loader...');
}
$.ajax({
url: params.url,
success: function(data) {
template = Handlebars.compile(data);
if (params.cache){
this.templates_cache[params.url] = template;
}
callback(template);
}
});
}
}
};
The template is loaded like this:
template_loader.load_template({url: '/templates/mytemplate.handlebars'}, function (template){
var template_data = {}; //get your data
$('#holder').html(template(template_data)); //render
})
there's this handy little jquery plugin I wrote for exactly this purpose.
https://github.com/cultofmetatron/handlebar-helper

Show PDF in HTML in web

I'm using the object tag to render PDF in HTML, but I'm doing it in MVC like this:
<object data="/JDLCustomer/GetPDFData?projID=<%=ViewData["ProjectID"]%>&folder=<%=ViewData["Folder"] %>"
type="application/pdf" width="960" height="900">
</object>
and Controller/Action is
public void GetPDFData(string projID, Project_Thin.Folders folder)
{
Highmark.BLL.Models.Project proj = GetProject(projID);
List<File> ff = proj.GetFiles(folder, false);
if (ff != null && ff.Count > 0 && ff.Where(p => p.FileExtension == "pdf").Count() > 0)
{
ff = ff.Where(p => p.FileExtension == "pdf").ToList();
Response.ClearHeaders();
Highmark.BLL.PDF.JDLCustomerPDF pdfObj = new JDLCustomerPDF(ff, proj.SimpleDbID);
byte[] bArr = pdfObj.GetPDF(Response.OutputStream);
pdfObj = null;
Response.ContentType = "application/" + System.IO.Path.GetExtension("TakeOffPlans").Replace(".", "");
Response.AddHeader("Content-disposition", "attachment; filename=\"TakeOffPlans\"");
Response.BinaryWrite(bArr);
Response.Flush();
}
}
The problem is, as I'm downloading data first from server and then return the byte data, it is taking some time in downloading, so I want to show some kind of progress to show processing.
Please help me on this.
You may try the following (not tested under all browsers):
<div style="background: transparent url(progress.gif) no-repeat">
<object
data="<%= Url.Action("GetPDFData, new { projID = ViewData["ProjectID"], folder = ViewData["Folder"] }") %>"
type="application/pdf"
width="640"
height="480">
<param value="transparent" name="wmode"/>
</object>
</div>
Unfortunatly, there is no way (afaik) to interact with the Acrobat plugin and see when it's ready to display your PDF document.
There are components available that replace Acrobat and provide a proper Javascript interface.
I work for TallComponents on their PDFWebViewer.NET product which will display PDF without any plugins and works with ASP.NET MVC.
You do have some other options though. If you need the progress indicator because the PDF generation is taking longer than you would like you can poll the server for progress using AJAX calls.
On the server you would need to have some sort of progress information available that you can return as the result of the ajax call. In the browser you'd use the result to provide progress info to the user. There are several good examples available online (this blog for example). There are also other questions here on SO (for example here) with good pointers to more info.
If the generation process only takes a couple of seconds can you probably get way with showing a busy indicator. That could be as simple as showing a div in your page when you trigger the download from the server.
By the way, if I'm not mistaken you should replace the attachment keyword with inline in the Content-Disposition header. Setting that to attachment will cause the entire PDF to be downloaded before any content is displayed. If you set it to inline, Acrobat will start showing the first page as soon as it has downloaded enough data to do so.

Resources