Spring MVC - Display Blob images from Database - database

Firstly, I am new to Spring MVC and I am really sorry if this seems like a duplicated question however I am struggling to find a break down guide/tutorial on how to display images on a JSP page after receiving them as blobs from the database. Most of the responses I've read just give you small snippets which confuse me more.
I have a MySQL DB which has a table full of images stored as blobs. I have a Service which retrieves the blob images from the database and populates an arrays of CommonsMultipartFile. I also have a Controller which passes the array to the JSP page where a loop iterates over each image which I'm trying to display.
CONTROLLER
#RequestMapping(value = { "/my/images" }, method = RequestMethod.GET)
public String getAllImages(HttpServletRequest request, HttpServletResponse response, ModelMap model) {
final List<CommonsMultipartFile> images = new ArrayList<CommonsMultipartFile>();
myService.getAllImages(images);
model.addAttribute("myImages", images );
return getUrl(request);
}
JSP
<c:forEach items="${myImages}" var="image">
<img src="${image}">
</c:forEach>
This is as far as I got. The images are not displaying. Please can someone help?
Many Thanks in advance!

The best is to save those binary-files to harddisk (using pk as filename) and directly serve them to the browser.
You can write a Servlet too but its quite hard to write asynchron Servlets.

Related

Download file from api in ReactJs

I have ASP.NET Core MVC back-end api. One controller returns File from server. Is there a way to make request to api route by [href] attribute of <a> tag? Looks like it tries to call React route but not make a request to server.
Also I made AJAX call to that controller and got back file as a string (screenshot is attached). Why is it a string, shouldn.t it be a byte array? How to build back file from that string? (it's a .pdf file). I have an empty PDF if use JavaScript new File([], 'name', {options}).
ASP.NET Core controller returns PDF this way:
return PhysicalFile(Path.GetFullPath(relativePath), "application/pdf", reportName);
In React I receive it as a string this way:
let stringPDFBinary = await ReportService.getReport(id, reportFileName)
I just need to download file from api by any way.
So, the answer is here: PDF is blank when downloading using javascript
The same problem. Let it be one more topic, easier to find for others. The AJAX response is encoded string. In request config set 'responseType = 'arraybuffer'' somehow and receiving pdf will not be blank. Solved.
I Just copied and pasted from the code source. The problem seems to be the same that i had:
Asp net controller:
[HttpGet]
[Route("File")]
[AllowAnonymous]
public IActionResult GetFile(string key)
{
var file = (FileCacheValue)_fileCache.Cache[key.Replace(" ", "+")];
if (file == null)
return NotFound();
Response.Headers["content-disposition"] = $"inline;filename={file.Name}.pdf";
return File(file.Data, "application/pdf");
}
In this case comes from a cache system. The data is a byte array.
Front-end React:
const onClick = () =>
{
window.open(pdfByteArray, '_blank', 'fullscreen=yes');
}
Exactly what i have. I just put the data on a new window and open the pdf.
The Ajax part is straight forward, get the value from the response and set it on a variable

Error Image Upload and Get, Method App\Image::__toString() must not throw an exception, caught Illuminate\Database\Eloquent\JsonEncodingException

I am uploading user profile image which is uploading and moved to storage/app/upload/images folder but when I am trying to display that image, below given error occurs.
Method App\Image::__toString() must not throw an exception, caught Illuminate\Database\Eloquent\JsonEncodingException
Here is my controller function for displaying
public function userProfile() {
$image = Image::all();
return view('frontend.layouts.Profile',compact('image'));
}
My view in which I am displaying image
#foreach($image as $images)
<img style="width:210px ; height: 230px " src="/storage/app/upload/images/{{$images->image}}" >
#endforeach
Please Upload your image in Public directory and then try to access that, it will work fine
There are three ways of making an image available to a user:
1. As a public asset
Here the image is made available to everyone. For instance your website logo, or landing page image would be accessed by all. So there is a url to the image that is easily accessed by all. These sort of files would go straight to public/img/ folder.
2. As a protected image available only if specific url is requested
Here user specific images would be accessed by specific people. Think of your members' personal photos that you want to make available only to the member herself or to some specific person. In this case you would store the images in storage/app/public and make a symlink using the artisan command php artisan storage:link You can read more on this here. Assuming that you store your files using random names using str_random() you would then generate urls to your image using the asset() helper like: echo asset('storage/X3jf5j5b2j3n.jpg'); Given that the file names are random, it would be hard to access this image by everyone excepting those who have the url generated using the asset() helper.
3. As a protected image made available using Intervention library
In this case you would first check if user is logged in and then dynamically load the image using Intervention via another protected route. So in your web routes you would first have the user authorization using auth middleware:
Route::group(['middleware' => 'auth'], function () {
Route::get('user', 'UserController#userProfile');
Route::get('images/{image}', 'UserController#serveImage'); // this route serves the image only if user is logged in
});
Then once your have installed Intervention library using composer, our UserController would look like:
use Intervention;
class UserController extends Controller
{
public function userProfile()
{
$images = Image::all();
return view('frontend.layouts.Profile', compact('images'));
}
public function serveImage($image)
{
$filename = storage_path('app/images/'.$image);
return Intervention::make($filename)->response();
}
}
You can see that the image is now being served from the storage folder and not public folder. So this method serveImage() is called only when the route defined earlier for it is authorized. Intervention then works its magic to read the image and send it as a http response.
Your view would change one tad bit to accommodate the new route end point that we defined called images. I assume here that you are storing the filename of the image in db by a field named filename:
#foreach($images as $image)
<img style="width:210px ; height: 230px " src="{{ url('/images/'.$image->filename) }}" >
#endforeach
Note: Do bear in mind that the preferred way to serve images is by using method 2 since it is much faster. You can use method 3 sparingly if you really don't want anyone to even stumble upon the files using the urls.

Laravel returning a 404 on an image

This should be fairly simple though it is completely stumping me.
I have a backend Laravel installation running on localhost:8000
I have a front end Angular app running on localhost:9001.
I have some 'static' images I have included in my seed data (eg.
'1', 'user.png'), these images are being rendered perfectly in my front end (they are also served from the exact place my image uploads are going).
The URL I am currently serving images from is http://localhost:8000/images/{filename}
I can upload images from the front to the back end and they appear in the DB and the image is being put in the filesystem, I'm populating the correct URL in my front end (as evidenced by the previous URL).
My uploaded images are not being shown.
In my logs I am getting:
[2015-01-20 18:13:49] local.ERROR: NotFoundHttpException Route: http://localhost:8000/images/j249ae747ce28c317e02f1fb6d0a10c3.jpg [] []
[2015-01-20 18:13:49] local.ERROR: exception 'Symfony\Component\HttpKernel\Exception\NotFoundHttpException'
I tried a method in my routes file, but couldnt see why, when I am already serving some images already?
I have also set all permissions to 755 on my /images folder.
Any ideas?
I'm not sure I follow every bit of multi-system interaction you have going on, but I'd drop back to first HTTP principles.
Try accessing the image URL directly.
http://localhost:8000/images/j249ae747ce28c317e02f1fb6d0a10c3.jpg
If the error in your browser (or your logs, if you're not developing with debug set to true) is
local.ERROR: NotFoundHttpException Route: http://localhost:8000/images/j249ae747ce28c317e02f1fb6d0a10c3.jpg
This means your web server couldn't find a file at images/j249ae747ce28c317e02f1fb6d0a10c3.jpg, and handed the request to Laravel. This means you need to figure out why your webserver can't see the file.
Assuming you're serving index.php from the public folder
Do you have a public/images/j249ae747ce28c317e02f1fb6d0a10c3.jpg file?
Are you sure? Copy and paste the path into terminal and to a ls public/images/j249ae747ce28c317e02f1fb6d0a10c3.jpg to make sure your brain isn't missing some subtle case issue
Are any errors showing up in your web server's logs (not Laravel's)
Can you create a text/html file in the images folder and serve it? If not, then you may not be pointing your web server at the folder you think you are.
Something like
http://localhost:8000/images/test.txt
http://localhost:8000/images/test.html
Some first principles debugging like that should point you in the right direction.
rm public/storage
php artisan optimize:clear
php artisan storage:link
This worked for me.
The problem is you haven't generated a url for your uploaded image
Try accessing your url like this
http://localhost:8000/storage/images/j249ae747ce28c317e02f1fb6d0a10c3.jpg
To generate the above url
Add this method \Storage::disk('public')->url(); method in your controller.This method accesses the public disk array which is found in Config\filesystems.php and it generates a url in the following format
http://localhost:8000/storage/images/j249ae747ce28c317e02f1fb6d0a10c3.jpg
For example the method below stores the image in the image folder and generates the url of the image path.
public function uploadImage(Request $request)
{
$request->validate(['image'=>'file|image|max:5000']);
$imageProfile = new ImageProfile();
if($request->hasFile('image') && $request->file('image')->isValid())
{
$image = $request->file('image')->store('images');
$imageProfile->image_profile_url = \Storage::disk('public')->url($image);
$imageProfile->save()
}
return response()->json($imageProfile,200);
}
The code returns a Json response below
{
"id": 13,
"image_profile_url ": "http://127.0.0.1:8000/storage/images/cxlogqdI8aodERsmw74nmEx7BkxkWrnyJLMH7sFj.jpeg",
"updated_at": "2020-01-13 16:27:37",
"created_at": "2020-01-13 16:27:37",
}
Try to copy the url and test it in postman.
Visit the link to learn more about Laravel file storage
Laravel File Storage
Hope it helps.
laravel 8
Controler function
public function store(Request $request)
{
$this->validate($request, [
'site_title' => 'required',
'logo_image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
]);
$input['logo_image'] = time().'.'.$request->logo_image->getClientOriginalExtension();
$request->logo_image->move(public_path('images'), $input['logo_image']);
$input['site_title'] = $request->site_title;
//dd($input);
Site_settings::create($input);
return back()->with('success','Image Uploaded successfully.');
}
blade view
<td>
<img src="{{ url('/images/').'/'.$site_settings->logo_image ?? '' }}" alt="" width="250px" height="auto">
</td>

Image serving from the high performance blobstore without direct access to get_serving_url()

I'm converting my site over to using the blobstore for image serving and am having a problem. I have a page with a large number of images being rendered dynamically (through jinja), and the only data available are entity keys that point to image objects that contain the relevant serving url.
Previously each image had a url along the lines of "/show-image?key={{image_key}}", which points to a request handler along the lines of this:
def get(self):
imageInfo = db.get(self.request.args.get("key"))
imagedata = imageInfo.data // the image is stored as a blob in the normal datastore
response = Response()
response.data = imagedata
response.headers['Content-Type'] = imageInfo.type
return response
My question is: How can I modify this so that, rather than returning a response with imageInfo.data, I return a response with imageInfo.saved_serving_url (generated from get_serving_url when the image object was created). More importantly, is this even a good idea? It seems like converting the saved_serving_url back into data (eg using urllib.fetch) might just counteract the speed and efficiency of using the high-speed datastore in the first place?
Maybe I should just rewrite my code so that the jinja template has direct access to the serving urls of each image. But ideally I'd like to avoid that due to the amount of parallel lists I'd have to pass about.
why not returning the serving url instead of the imagedata?
<img src="/show-image?key={{image_key}}" />
def get(self):
imageInfo = db.get(self.request.args.get("key"))
return imageInfo.saved_serving_url

Caching contents of a page?

I'm generating page content like:
// index.jsp
<%
List<Horse> horses = database.getHorses();
for (Horse it : horses) {
%>
<div><%= it.getName() %></div>
<%
}
%>
is it possible to grab the entire page content at the end of the jsp file, and dump it into a String, like:
String page = this.getPrintWriter().toString();
I'm just curious if this is possible. I might try caching the page as a String, but would need to rewrite my page generation to build everything in one StringBuilder like:
StringBuilder sb = new StringBuilder();
sb.append("<div>"); sb.append(it.getName()); sb.append("</div>");
...
<%= sb.toString() %>
String cached = sb.toString();
Thanks
Since it's user-specific data, you can't use GAE's memcache for this. It's an application wide cache. I'd just store it in the session scope.
HttpSession session = request.getSession();
List<Horse> horses = (List<Horse>) session.getAttribute("horses");
if (horses == null) {
horses = database.getHorses();
session.setAttribute("horses", horses);
}
That said, try to avoid using scriptlets as much as possible. The above can perfectly be done in a Servlet class and you can display them using JSTL c:forEach as follows:
<c:forEach items="${horses}" var="horse">
<div>${horse.name}</div>
</c:forEach>
Capturing generated page content can't be done by simply calling PrintWriter#toString(). The StringBuilder idea is funny, but it's really not worth it. Caching dynamic content has very little benefits for the purposes as you mention.
Best what you in this case can do with regard to page caching is just to leverage the webbrowser's default task to cache GET requests.
See also
How to avoid Java code in JSP?
How to capture dynamically generated content?
I would create a HttpServlet which just retrieves page content from a real page (any kind of page, also JSP). Then cache it.
Next time the user makes the same request it would try to get the data from memcache and if present, retrieve only the mem cache content.
Of course you have to check parameters, user id, e.t.c. which would change the content on cached page.
This way you could also have a full control of cache size (you can set cache expiration during PUT, limit cached page count e.t.c.)
BTW.. the answer with session data storage won't work!!. Session data is persisted only on single server. As appengine is running on some seriously large cluster (many-many machines), it won't ensure that two same request, from the same client would be served by the same machine - therefore the session data won't be accessible!
Learned this the hard way when i tried to do progress bars ;)
EDIT
Seems like sessions are working now with appengine and are shared across all servers (as google states they are using memcache internaly)

Resources