HTML for serving Images through Spring Boot from Database - html

I store avatar images in PGSQL in Heroku and I used to serve through API REST GET controller, everything fine. I'm now trying to serve through API REST URL at server domain, via thymeleaf, so I prepared an MVC for that. Everything is working, except that I can't use the server URL to embed into HTML tag in my frontend application, it shows a missing link, which I don't understand, because if I open the link itself in the browser it works well and shows the image.
What I'm trying to do is something similar to the google avatar HTML, I copied that google HTML simple code and served as it, in the google HTML works, but not with mine...
Google example:
https://lh3.googleusercontent.com/a-/AOh14GgQ4X0_nQVH0NszR1-YGu90CIk40XSWT97uqW_V=s96-c
My output:
https://chefscript.herokuapp.com/avatar?emailHash=7ad248c8b830100b95ae8fe57d6f07324b8d5c69872dcf4a5d280a993b8ab676
So, both works well, but I can only use the google one in my HTML IMG SRC at the frontend, my output shows a borken link. :(
My HTML Tempalte:
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="${title}"></title>
<meta name="viewport" content="width=device-width, minimum-scale=0.1">
</head>
<body style="margin: 0px; background: #0e0e0e;">
<img style="-webkit-user-select: none;margin: auto;" th:if="${avatarData != null}" th:src="'data:image/jpeg;base64,' + ${avatarData}">
<img style="-webkit-user-select: none;margin: auto;" th:if="${avatarData == null}" th:src="#{${avatarURL}}">
</body>
</html>
And my controller code:
#GetMapping("/avatar")
public String getAvatar(#RequestParam(name="emailHash", required=false, defaultValue="") String hashEmail, Model model) {
User user = userRepository.findByHashEmail(hashEmail).orElseThrow(() -> new ResourceNotFoundException());
byte[] image = userService.getImageBlobByEmailHash(hashEmail, true, false);
model.addAttribute("title", "AVT-" + hashEmail);
if ( image != null ) {
model.addAttribute("avatarData", Base64.getEncoder().withoutPadding().encodeToString(image));
} else {
if ( user.getAvatar() != "" && user.getAvatar() != null ) {
model.addAttribute("avatarData", null);
model.addAttribute("avatarURL", user.getAvatar());
} else {
model.addAttribute("avatarURL", "/img/avatar-128.png");
}
}
return "avatar";
}
Finally my frontend, where the broken link shows:
<a href (click)="false" [routerLink]="'/social/user/'+user.hashEmail">
<img class="s-ava-alone-img" width="150" height="150" [src]="'https://chefscript.herokuapp.com/avatar?emailHash='+user.hashEmail">
</a>

Find it.
Issue with headers and response type.
I wanted to use avatar images trhough HTML/TEXT to later one use in the IMG SRC at the Frontend. Bad strategy.
I saw in the google one that the Content-Type header is set to image/jpeg and the Content-Disposition header is set to inline. This way it can be used later on.

Related

How to render html http response to a new page or a new component in Angular?

I am wondering if there is a way to render http response that is html in a new page or in a new component? The specific problem is described below.
code to call the backend:
const headers = { 'content-type': 'application/x-www-form-urlencoded'}
let obs = this.http.post<any>("http://localhost:8080/project/Raffle", _data,{ headers, responseType: 'text' as 'json'});
obs.subscribe((response)=>console.log(response));
The response is an html page displayed in the console.
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Thank you for taking the survey! You win the raffle of two movie tickets!</title>
</head>
<body>
...
</body>
</html>
My question is how may I render the content in a new component or possibly as a new html page?
Many thanks!
You should be able to create a template using the output and Handlebar.js and display it as an html page.
Please refer to this resources=>
https://www.npmjs.com/package/handlebars
https://handlebarsjs.com/

Thymeleaf Content-Type is being ignored in HTML Email (not rendered as HTML)

I'm developing a RESTful API with Spring Boot as backend and an Angular 9 frontend. Upon user registration, a verification email is sent, in which the user needs to click on a link to verify their account. Functionally, all is set and working. However, the HTML is never rendered despite having Content-Type set to 'text/html' and charset to UTF-8. I'm using Thymeleaf to generate the HTML:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html charset=UTF-8" />
</head>
<body>
<header>TooManyThoughts</header>
<section>
<p th:text="#{registration.mail.greeting(${#messages.msg('mail.greeting.title.' + user.personalData.title.representation, user.personalData.firstName, user.personalData.lastName)})}"></p>
<p th:text="#{registration.mail.preamble}"></p>
<p>
<a th:text="#{registration.mail.link}"
th:href="#{http://localhost:8081/auth/register/email/verify/{id}/{key}(id = ${user.id}, key = ${user.emailValidationKey}, send='auth,login', verified='email')}"></a>
</p>
<p>
<span th:text="#{registration.mail.clue01(${user.credentials.username})}"></span>
<span th:text="#{registration.mail.clue02}"></span>
</p>
<p th:text="#{registration.mail.catchphrase}"></p>
<p th:text="#{registration.mail.goodbye}"></p>
<p>
<span th:text="#{registration.mail.signature01}"></span>
<br>
<span th:text="#{registration.mail.signature02}"></span>
</p>
</section>
<footer></footer>
</body>
At the time of writing, all frameworks used are in their latest versions. Currently, I'm sending the email to my personal gmail account. When googling the issue, I've found some rendering issues with gmail, but they've all been old and from around 2011 or so. The only other posts and entries I could find were about setting Content-Type and charset properly, which in my opinion I've done.
I'm kinda stuck here since two days with what I believe should be a very basic issue, so any help is highly appreciated.
Thanks to Andrew's hint on using setContent() instead of setText() for javax.mail.Message, I realized that I've never actually set the content type of my email anywhere in the code. I'm not using javax.mail but springframework.mail.javamail, so I had to look for a solution and I found it here. The working code now looks like this:
public EmailVerificationModel sendMail(final EmailVerificationModel model) {
final MimeMessagePreparator msgPreparator = mimeMessage -> {
final MimeMessageHelper msgHelper = new MimeMessageHelper(mimeMessage, "UTF-8");
msgHelper.setFrom("petesideburner#gmail.com");
msgHelper.setTo(model.getCredentials().getEmail());
msgHelper.setSubject(this.mailBuilder.subject(model));
msgHelper.setText(this.mailBuilder.build(model), true);
};
this.mailSender.send(msgPreparator);
return this.verificationMailSent(model);
}
All that I had to do was to pass true as 2nd argument to Spring's MimeMessageHelper.setText() method. The hidden quirks of method signatures. Personally, I prefer more distinct names for methods and variables, and so for better readability of my code I've changed it to:
public EmailVerificationModel sendHtmlMail(final EmailVerificationModel model) {
final boolean html = true;
final MimeMessagePreparator msgPreparator = mimeMessage -> {
[...]
msgHelper.setText(this.mailBuilder.build(model), html);
};
this.mailSender.send(msgPreparator);
return this.verificationMailSent(model);
}

Replacing iframe source with main URL

I am not sure if this is possible or not...
I am trying to replace a specific part of a URL from my iframe with a string that is part of the mainframe's URL.
i.e. I am trying to replace the iframe link to include the userID.
Main URL: https://web.example.com?userID=9553c6
<iframe src="https://app.example.com?[Insert userID here]"></iframe>
If your site where is content under address https://web.example.com?userID=9553c6 in my opinion you can do this using eg. php
<body>
<iframe src="http://example.com?user_id=<?php echo urlencode($_GET['userId']) ?>"></iframe>
</body>
Then variable $_GET['userId'] will have value of 9553c6
Or you can use only js which will be a bit harder, because you have to parse location.search https://www.w3schools.com/jsref/prop_loc_search.asp and get specific part of it. Of course this value of param userId will be from main site.
Direct solution
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<style>
iframe {
width: 100%;
height: 1000px;
}
</style>
</head>
<body>
<iframe src="http://fotokrajobrazy.warmia.pl/galeria/fota.php?nr=1004"></iframe>
</body>
<script>
window.onload = function () {
var res = location.search.match(/userId\=(\w+)/);
var fr = document.getElementsByTagName('iframe')[0];
fr.setAttribute('src', fr.getAttribute('src').replace(/(nr\=)\d+/, '$1'+res[1]));
};
</script>
</html>
You can then edit main url like this:
http://127.0.0.1/stack.html?userId=1003
and
http://127.0.0.1/stack.html?userId=1002
etc. and the url of iframe will change too.
You need some simple string-hangling.
You say you're injecting the frame via JavaScript, so I'll suppose your code looks something like this.
let
ifr = document.createElement('iframe'),
src = 'some/url/here?user={user-id}',
user_id = '123456';
src = src.replace('{user-id}', user_id)
;
document.body.appendChild(ifr);
The key line is the one with .replace() - that's where we replace the placeholder with the actual value.

Adobe Creative SDK - Web based image editor

Has anyone used the Adobe Creative SDK yet? I registered my site and received the api key and plugged into my web page. It is extremely simple, basically copying their example and using my own image except i keep getting the following error:
"There was a problem loading the image URI provided to the 'url' config key. Please verify that the URI is publicly accessible, and that the image is a supported format."
I checked the Adobe site with no luck and I have a small 354 x 384 image i am using.
Code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Aviary Test</title>
<!-- Load Feather code -->
<script type="text/javascript" src="http://feather.aviary.com/imaging/v3/editor.js"></script>
<!-- Instantiate Feather -->
<script type='text/javascript'>
var featherEditor = new Aviary.Feather({
apiKey: 'MY KEY',
theme: 'dark', // Check out our new 'light' and 'dark' themes!
tools: 'all',
appendTo: '',
onSave: function(imageID, newURL) {
var img = document.getElementById(imageID);
img.src = newURL;
},
onError: function(errorObj) {
alert(errorObj.message);
}
});
function launchEditor(id, src) {
featherEditor.launch({
image: id,
url: src
});
return false;
}
</script>
</head>
<body>
<div id='injection_site'></div>
<img id='image1' src='desert.jpg'/>
<!-- Add an edit button, passing the HTML id of the image and the public URL of the image -->
<p><input type='image' src='http://images.aviary.com/images/edit-photo.png' value='Edit photo' onclick="return launchEditor('image1', 'Desert.jpg');" /></p>
</body>
</html>
I am having the same problem.
Everything works, but when you try to load an image from a different location you get the "there was a problem loading the image uri provided to the 'url' config key" error.
My site looks like this:
full (full sized image folder)
thumb (folder)
index.html
You can see the error here: http://koffid.nl/memetests/sdk2/
When you use the Edit Photo button which uses an external URL to the image it works.
When you click on the image which uses my file structure instead of the button the error shows up.
So this doesn't work:
<img id='image1' src='thumb/feather_thumb.jpg' value='Edit photo' onclick="return launchEditor('image1', 'full/feather_default.jpg');" /></p>
And this does work:
<p><input type='image' src='http://images.aviary.com/images/edit-photo.png' value='Edit photo' onclick="return launchEditor('image1', 'http://images.aviary.com/imagesv5/feather_default.jpg');" /></p>
You can't use a relative url, you need to pass the full url of the image, ie. http://example.com/images/myimage.jpg

Inputting a default image in case the src attribute of an html <img> is not valid?

Is there any way to render a default image in an HTML <img> tag, in case the src attribute is invalid (using only HTML)? If not, what would be your lightweight way to work around it?
You asked for an HTML only solution...
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Object Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<p>
<object data="https://stackoverflow.com/does-not-exist.png" type="image/png">
<img src="https://cdn.sstatic.net/Img/unified/sprites.svg?v=e5e58ae7df45" alt="Stack Overflow logo and icons and such">
</object>
</p>
</body>
</html>
Since the first image doesn't exist, the fallback (the sprites used on this web site*) will display. And if you're using a really old browser that doesn't support object, it will ignore that tag and use the img tag. See caniuse website for compatibility. This element is widely supported by all browsers from IE6+.
* Unless the URL for the image changed (again), in which case you'll probably see the alt text.
This works well for me. Maybe you wanna use JQuery to hook the event.
<img src="foo.jpg" onerror="if (this.src != 'error.jpg') this.src = 'error.jpg';" alt="add alternative text here">
Updated with jacquargs error guard
Updated: CSS only solution
I recently saw Vitaly Friedman demo a great CSS solution I wasn't aware of. The idea is to apply the content property to the broken image. Normally :after or :before do not apply to images, but when they're broken, they're applied.
<img src="nothere.jpg" alt="add alternative text here">
<style>
img:before {
content: ' ';
display: block;
position: absolute;
height: 50px;
width: 50px;
background-image: url(ishere.jpg);
}
</style>
Demo: https://jsfiddle.net/uz2gmh2k/2/
As the fiddle shows, the broken image itself is not removed, but this will probably solve the problem for most cases without any JS nor gobs of CSS. If you need to apply different images in different locations, simply differentiate with a class: .my-special-case img:before { ...
Found this solution in Spring in Action 3rd Ed.
<img src="../resources/images/Image1.jpg" onerror="this.src='../resources/images/none.jpg'" />
Update:
This is not an HTML only solution... onerror is javascript
a simple img-element is not very flexible so i combined it with a picture-element. this way no CSS is needed. when an error occurs, all srcset's are set to the fallback version. a broken link image is not showing up. it does not load unneeded image versions. the picture-element supports responsive design and multiple fallbacks for types that are not supported by the browser.
<picture>
<source id="s1" srcset="image1_not_supported_by_browser.webp" type="image/webp">
<source id="s2" srcset="image2_broken_link.png" type="image/png">
<img src="image3_fallback.jpg" alt="" onerror="this.onerror=null;document.getElementById('s1').srcset=document.getElementById('s2').srcset=this.src;">
</picture>
Simple and neat solution involving some good answers and comment.
<img src="foo.jpg" onerror="this.src='error.jpg';this.onerror='';">
It even solve infinite loop risk.
Worked for me.
<style type="text/css">
img {
background-image: url('/images/default.png')
}
</style>
Be sure to enter dimensions of image and whether you want the image to tile or not.
I don't think it is possible using just HTML. However using javascript this should be doable. Bassicly we loop over each image, test if it is complete and if it's naturalWidth is zero then that means that it not found. Here is the code:
fixBrokenImages = function( url ){
var img = document.getElementsByTagName('img');
var i=0, l=img.length;
for(;i<l;i++){
var t = img[i];
if(t.naturalWidth === 0){
//this image is broken
t.src = url;
}
}
}
Use it like this:
window.onload = function() {
fixBrokenImages('example.com/image.png');
}
Tested in Chrome and Firefox
<img style="background-image: url(image1), url(image2);"></img>
Use background image that let you add multiple images.
My case:
image1 is the main image, this will get from some place (browser doing a request)
image2 is a default local image to show while image1 is being loaded.
If image1 returns any kind of error, the user won't see any change and this will be clean for user experience
If you're using Angular/jQuery then this might help...
<img ng-src="{{item.url}}" altSrc="{{item.alt_url}}" onerror="this.src = $(this).attr('altSrc')">
Explanation
Assuming that item has a property url that might be null, when it is then the image will show up as broken. That triggers execution of onerror attribute expression, as described above. You need to override the src attribute as described above, but you will need jQuery to access your altSrc. Couldn't get it to work with vanilla JavaScript.
Might seem a little hacky but saved the day on my project.
angular2:
<img src="{{foo.url}}" onerror="this.src='path/to/altimg.png'">
An HTML only solution, where the only requirement is that you know the size of the image that you're inserting. Will not work for transparent images, as it uses background-image as a filler.
We can successfully use background-image to link the image that appears if the given image is missing. Then the only problem is the broken icon image - we can remove it by inserting a very big empty character, thus pushing the content outside the display of img.
img {
background-image: url("http://placehold.it/200x200");
overflow: hidden;
}
img:before {
content: " ";
font-size: 1000px;
}
This image is missing:
<img src="a.jpg" style="width: 200px; height: 200px"/><br/>
And is displaying the placeholder
An CSS only solution (Webkit only)
img:before {
content: " ";
font-size: 1000px;
background-image: url("http://placehold.it/200x200");
display: block;
width: 200px;
height: 200px;
position: relative;
z-index: 0;
margin-bottom: -16px;
}
This image is there:
<img src="http://placehold.it/100x100"/><br/>
This image is missing:
<img src="a.jpg"/><br/>
And is displaying the placeholder
Update: 2022 (works on chrome still!!)
I recently had to build a fall back system which included any number of fallback images. Here's how I did it using a simple JavaScript function.
HTML
<img src="some_image.tiff"
onerror="fallBackImg(this);"
data-src-1="some_image.png"
data-src-2="another_image.jpg">
JavaScript
function fallBackImg(elem){
elem.error = null;
let index = elem.dataset.fallIndex || 1;
elem.src = elem.dataset[`src-${index}`];
elem.dataset.fallIndex = ++index;
}
I feel like it's a pretty lightweight way of handling many fallback images.
If you want "HTML only" then this
<img src="some_image.tiff"
onerror="this.error = null;
let i = this.dataset.i || 1;
this.src = this.dataset[`src-${i}`];
this.dataset.i = ++i;"
data-src-1="some_image.png"
data-src-2="another_image.jpg">
A modulable version with JQuery, add this at the end of your file:
<script>
$(function() {
$('img[data-src-error]').error(function() {
var o = $(this);
var errorSrc = o.attr('data-src-error');
if (o.attr('src') != errorSrc) {
o.attr('src', errorSrc);
}
});
});
</script>
and on your img tag:
<img src="..." data-src-error="..." />
There is no way to be sure the myriad number of clients (browsers) that will try to view your page. One aspect to consider is that email clients are defacto web browsers and may not handle such trickamajickery ...
As such you should ALSO include an alt/text with a DEFAULT WIDTH and HEIGHT, like this. This is a pure HTML solution.
alt="NO IMAGE" width="800" height="350"
So the other good answer would be slightly modified as follows:
<img src="foo.jpg" onerror="if (this.src != 'error.jpg') this.src = 'error.jpg';" alt="NO IMAGE" width="800" height="350">
I had issues with the object tag in Chrome, but I would imagine this would apply to that as well.
You can further style the alt/text to be VERY BIG ...
So my answer is use Javascript with a nice alt/text fallback.
I also found this interesting: How to style an image's alt attribute
React
<img
src="https://example.com/does_not_exist.png"
onError={(e) => {
e.currentTarget.src = "https://example.com/default.png"
}}
/>
The above solution is incomplete, it missed the attribute src.
this.src and this.attribute('src') are NOT the same, the first one contains the full reference to the image, for example http://my.host/error.jpg, but the attribute just keeps the original value, error.jpg
Correct solution
<img src="foo.jpg" onerror="if (this.src != 'error.jpg' && this.attribute('src') != 'error.jpg') this.src = 'error.jpg';" />
3 solutions for this:
Consider following html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<img id="imageId">
<script src="setimage.js"></script>
</body>
</html>
Solution one :
reference this block of JS code inside the body tag of your html as
<script src="setimage.js"></script>
and set the src paths, the first is the one if there is an error, the next is the one you hope works first time :)
var img = document.getElementById("imageId")
img.onerror = () => {
img.src= "../error.png";
}
img.src= "../correct.webp.png";
Solution two:
this solution is almost the same, instead you will call the method, again at the end of your body within a script tag, but would supply the paths there.
function setImageWithFallback(mainImgPath, secondaryImgPath) {
var img = document.getElementById("imageId")
img.onerror = () => {
img.src= mainImgPath;
}
img.src= secondaryImgPath;
}
Solution three:
if its just a single image, this would be the simplest :) simply set the onerror at the img tag
<img id="imageId" src="../correct.webp.png"
onerror="if (this.src != '../error.png') this.src = '../error.png';">
If you are using Angular 1.x you can include a directive that will allow you to fallback to any number of images. The fallback attribute supports a single url, multiple urls inside an array, or an angular expression using scope data:
<img ng-src="myFirstImage.png" fallback="'fallback1.png'" />
<img ng-src="myFirstImage.png" fallback="['fallback1.png', 'fallback2.png']" />
<img ng-src="myFirstImage.png" fallback="myData.arrayOfImagesToFallbackTo" />
Add a new fallback directive to your angular app module:
angular.module('app.services', [])
.directive('fallback', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var errorCount = 0;
// Hook the image element error event
angular.element(element).bind('error', function (err) {
var expressionFunc = $parse(attrs.fallback),
expressionResult,
imageUrl;
expressionResult = expressionFunc(scope);
if (typeof expressionResult === 'string') {
// The expression result is a string, use it as a url
imageUrl = expressionResult;
} else if (typeof expressionResult === 'object' && expressionResult instanceof Array) {
// The expression result is an array, grab an item from the array
// and use that as the image url
imageUrl = expressionResult[errorCount];
}
// Increment the error count so we can keep track
// of how many images we have tried
errorCount++;
angular.element(element).attr('src', imageUrl);
});
}
};
}])
Using Jquery you could do something like this:
$(document).ready(function() {
if ($("img").attr("src") != null)
{
if ($("img").attr("src").toString() == "")
{
$("img").attr("src", "images/default.jpg");
}
}
else
{
$("img").attr("src", "images/default.jpg");
}
});
For any image, just use this javascript code:
if (ptImage.naturalWidth == 0)
ptImage.src = '../../../../icons/blank.png';
where ptImage is a <img> tag address obtained by document.getElementById().
Google threw out this page to the "image fallback html" keywords, but because non of the above helped me, and I was looking for a "svg fallback support for IE below 9", I kept on searching and this is what I found:
<img src="base-image.svg" alt="picture" />
<!--[if (lte IE 8)|(!IE)]><image src="fallback-image.png" alt="picture" /><![endif]-->
It might be off-topic, but it resolved my own issue and it might help someone else too.
In addition to Patrick's brilliant answer, for those of you who are searching for a cross-platform angular js solution, here you go:
<object type="image/png" data-ng-attr-data="{{ url || 'data:' }}">
<!-- any html as a fallback -->
</object>
Here's a plunk where I was playing trying to find the right solution: http://plnkr.co/edit/nL6FQ6kMK33NJeW8DVDY?p=preview
If you have created dynamic Web project and have placed the required image in WebContent then you can access the image by using below mentioned code in Spring MVC:
<img src="Refresh.png" alt="Refresh" height="50" width="50">
You can also create folder named img and place the image inside the folder img and place that img folder inside WebContent then you can access the image by using below mentioned code:
<img src="img/Refresh.png" alt="Refresh" height="50" width="50">
I am adding loading="lazy" to img tag. In some cases it works..
here is a simple Jquery that worked for me
$(image).on('error', function(event) {
imgage.attr('src', 'your_image.png');})
Well!!
I found this way convenient , check for the height attribute of image to be 0, then you can overwrite the src attribute with default image:
https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image
image.setAttribute('src','../icons/<some_image>.png');
//check the height attribute.. if image is available then by default it will
//be 100 else 0
if(image.height == 0){
image.setAttribute('src','../icons/default.png');
}