Retrieve image using spring boot and angular 9 problem - javascript

i have problem with getting image from spring boot (webapp/images) to angular 9 using api rest and spring security jwt.
when i save my image it work ... i found it in the folder webapp/images
but when i try to get the image i have problem with showing it
Here is my code.
Saving image:
//region Save UserProfile
#PostMapping
public ResponseEntity<?> createUserProfile(#RequestParam("file") MultipartFile file, #Valid #RequestParam("userProfile") String userProfile)throws Exception{
boolean isExit = new File(context.getRealPath("/Images/")).exists();
if (!isExit)
{
new File (context.getRealPath("/Images/")).mkdir();
System.out.println("---Folder Was Created---");
}
String filename = file.getOriginalFilename();
String newFileName = FilenameUtils.getBaseName(filename)+"."+FilenameUtils.getExtension(filename);
File serverFile = new File (context.getRealPath("/Images/"+File.separator+newFileName));
try
{
System.out.println("Image");
FileUtils.writeByteArrayToFile(serverFile,file.getBytes());
}catch(Exception e) {
e.printStackTrace();
}
UserProfile userProfileMapper = new ObjectMapper().readValue(userProfile, UserProfile.class);
userProfileMapper.setUrlImage(newFileName);
UserProfile newUserProfile=iCommonService.save(userProfileMapper);
return new ResponseEntity<>("UserProfile was saved",HttpStatus.CREATED);
}
//endregion
Spring boot controller:
//USERPROFILE_IMAGE_BY_USER_UID= "/imageuserprofile/{userprofileuid}"
#GetMapping(path = APIName.USERPROFILE_IMAGE_BY_USER_UID)
public byte[] getPhoto(#PathVariable("userprofileuid") String userprofileuid) throws Exception{
UserProfile userProfile = iCommonService.findByUid(userprofileuid);
if(userProfile == null){
throw new CommonServiceException("User profile uid not found");
}
return Files.readAllBytes(Paths.get(context.getRealPath("/Images/")+userProfile.getUrlImage()));
}
Angular Service
private baseUrl = 'http://localhost:8080/userprofile';
public host :string = "http://localhost:8080";
getUserProfileImage(uid: string): Observable<any> {
return this.http.get(`${this.baseUrl}/imageuserprofile/${uid}`);
}
My Component
constructor(
public userProfileService: UserProfileService,
) {}
getImageUserProfile() {
this.userProfileService
.getUserProfileImage(this.userProfileUid)
.subscribe((image) => {
this.imageUserProfile =image;
});
}
In the Template i try with :
<img
class="profile-user-img img-responsive img-circle"
[src]= "'data:image/png;base64,'+imageUserProfile"
alt="User profile picture"
/>
this give me (data:image/png;base64,undefined:1 GET data:image/png;base64,undefined net::ERR_INVALID_URL)
Or
<img
class="profile-user-img img-responsive img-circle"
[src]= "imageUserProfile"
alt="User profile picture"
/>
this give me ("Unexpected token � in JSON at position 0")
also i try with
<img
class="profile-user-img img-responsive img-circle"
src= "{{this.userProfileService.host+'/userprofile/imageuserprofile/'+userProfileUid}}"
alt="User profile picture"
/>
this give me (GET http://localhost:8080/userprofile/imageuserprofile/2SGI2U8WXUVSfMdgZqhQrok66wLaU03y 403)
can some tell me what is im doing wrong or what.
thanks in advenced.

There are two things to be corrected here:
You are probably getting a 403 error because you are not passing the jwt auth token that is required in the headers of the http.get() request. I could tell certainly only if you share the code related to spring security where you have overridden default spring boot security config for implementing your jwt security.
Your http.get() should probably look something like this.
private baseUrl = 'http://localhost:8080/userprofile';
public host :string = "http://localhost:8080";
getUserProfileImage(uid: string): Observable<any> {
headers:HttpHeaders=new HttpHeaders().set(<jwt header name>,<token value>)
return this.http.get(`${this.baseUrl}/imageuserprofile/${uid}`,{headers:headers});
}
Coming to the second part about how to properly process and display the image you receive
from angular http.get(), this stack answer will help you
GET data:image/png;base64,{{image}} net::ERR_INVALID_URL

Related

Java backend throws NoSuchFileException exception on multipart form file upload

I have a REACT frontend app and Java Spring backend. I send an image from frontend to backend but REST Controller throws the following error in Java:
java.nio.file.NoSuchFileException: C:\Users\User\AppData\Local\Temp\tomcat.8080.4543654899823294058\work\Tomcat\localhost\ROOT\upload_8189f9b4_9186_424d_b7c4_c4eec0f67e23_00000005.tmp
Controller:
#PostMapping(path="/add", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
public ResponseEntity<Product> addProduct(#ModelAttribute Product product) throws IOException {
...
}
Product Model:
#Document(collection = "products" )
public class Product {
#Id
private String id;
#Field("title")
private String title;
...
#Field("images")
private List<ProductImages> images;
}
I don't even know how to dig it further, what's the issue here?
Images that I send are in multipart FormData with the following structure:
{ data: base64 buffer,
contentType: jpg/png/etc.
}
On the react frontend:
let formData = new FormData();
...
formData.append("images", this.state.images[0]);
...
axios.post(`${server_url}/product/add`,formData)...

CORS error with Spring boot, javascript and web socket

I'm working on a little test project with a simple html page (using javascript) as Frontend and a Spring Boot application for my apis as Backend. I use websocket with stomp and sockJS to keep alive my connection between front and back. My problem is the following : when I test my connection with Postman i have no problems but when I call the api from my javascript I have the following error :
I tried every solutions I've found on internet and now i'm just stuck
Here is my Spring boot App_controller :
#RestController
#CrossOrigin(origins = "*")
public class App_Controller {
int id = 0;
ArrayList<Player> players = new ArrayList<Player>();
public void addTab(Player p){
players.add(p);
}
#MessageMapping("/batch-socket")
#SendTo("/topic/messages")
public String send(String message) throws Exception {
String time = new SimpleDateFormat("HH:mm").format(new Date());
return (message + " : " + time);
}
#RequestMapping (value = "/error", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
public String error(){
return "erreur";
}
}
Here is my corsConfiguration :
#Configuration
public class CorsConfig {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry){
registry.addMapping("/**")
.allowCredentials(true)
.allowedOrigins("*")
.allowedHeaders("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.maxAge(3600);
}
};
}
}
Here is my WebSocketConfiguration :
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.setApplicationDestinationPrefixes("/topic")
.enableSimpleBroker("/app");
}
#Override public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/batch-socket");
registry.addEndpoint("/batch-socket")
.setAllowedOrigins("*")
.withSockJS();
}
}
And finally here is my function to connect to this WebSocket :
function connect(){
var socket = new SockJS("http://localhost:8080/batch-socket");
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame){
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/messages', function(msgOutput){
console.log(msgOutput);
})
})
}
I tried to just add the #CrossOrigin(origins="*") and #CrossOrigins(origins="http://localhost:63342") and I test multiple possibilities with my CorsConfig.
Thank you for your help in advance
(sorry for my english)
You didn't say how your HTML page with JS is loaded. Is it the same localhost:8080 or maybe local file?
For testing you can tell Chrome to ignore cors restrictions:
chrome --disable-web-security --user-data-dir={some dir}
In your code you are doing registry.addEndpoint() twice, remove one and replace "*" with "http://localhost:63342". Remove all other CORS related code.
I think that you don’t need to create the #bean WebMvcConfigurer corsConfigurer, if it is for a simple test. Could you please do a test removing the registration of that bean and change the order of the annotations?
#CrossOrigin(origins = "http://localhost:63342")
#RestController

How to do a POST request from SAPUI5 controller to Java Servlet?

I have created a dynamic web project with a Tomcat 8.5 Server and then I created an index.html that do start my first view (a simple form for login). When I click the button for login start function onPress:
onPress : function() {
var user = this.getView().byId("userInput").getValue();
var pwd = this.getView().byId("passwordInput").getValue();
var request = {
un : user,
pw : pwd
};
$.post("LoginServlet", request, function() {
alert("Ciao");
});
}
I want to pass user and pwd to this servlet (LoginServlet)
public class LoginServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, java.io.IOException {
try {
UserBean user = new UserBean();
user.setUserName(request.getParameter("un"));
user.setPassword(request.getParameter("pw"));
user = UserDAO.login(user);
/*if (user.isValid()) {
HttpSession session = request.getSession(true);
session.setAttribute("currentSessionUser", user);
response.sendRedirect("userLogged.jsp"); // logged-in page
}else
response.sendRedirect("invalidLogin.jsp"); // error page*/
} catch (Throwable theException) {
System.out.println(theException);
}
}
}
The error I am getting is:
404 Not Found. Description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. Message: /LOGIN_RACMET_UI5_DynamicWebProject/LoginServlet
I need that the frontend is developed in SAPUI5, so I can't use JSP, PHP, etc.
The project is structured like this
When i do the call this is the result
I resolve it. It's wrong the url
$.post("LOGIN_RACMET_UI5_DynamicWebProject/LoginServlet", request, function() {
alert("Ciao");
});
This is right

403 (Forbidden) response from SignalR Hub using ASP.NET hosting on IIS server

I'm hosting a SignalR Hub on Windows Server 2012 with IIS as an ASP.NET Web application that I've tested successfully on my local machine. But when I publish and try to connect from a Angular application the server responds with 403 Forbidden on the /negotiate request. The Angular application is located on a different domain then the Hub server.
I've read that this is caused by a CORS issue, but I've tried every solution I can find without any change. Can it be a IIS server issue or have I missed something in my code?
The route being called is https://example.com/signalr/negotiate
SignalR Server:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
EnableJSONP = true,
EnableDetailedErrors = true
};
map.RunSignalR(hubConfiguration);
});
}
}
// Hub that handles Online user list
public class OnlineHub : Hub
{
private static List<AppUserDto> _usersOnline = new List<AppUserDto>();
public OnlineHub()
{
// Automapper Setup
MappingConfig.Init();
}
public override Task OnConnected()
{
var user = GetUser();
_usersOnline.Add(user);
Clients.All.listUpdated(_usersOnline);
return base.OnConnected();
}
public override Task OnReconnected()
{
var user = GetUser();
// Add user to list of online users if it doesn't exist
if (!_usersOnline.Any(u => u.Email == user.Email))
{
_usersOnline.Add(user);
Clients.All.listUpdated(_usersOnline);
}
return base.OnReconnected();
}
public override Task OnDisconnected(bool stopCalled)
{
var user = GetUser();
if (!_usersOnline.Any(u => u.Email == user.Email))
{
// Remove user from list of online users
_usersOnline.Remove(user);
Clients.All.listUpdated(_usersOnline);
}
return base.OnDisconnected(stopCalled);
}
private AppUserDto GetUser()
{
using (var db = new EntityDbContext())
{
// Get connected AppUserDto
var user = db.AppUsers.FirstOrDefault(u => u.UserName == Context.User.Identity.Name);
// Add user to list of online users
if (user != null)
{
return Mapper.Map<AppUserDto>(user);
}
return null;
}
}
}
Angular Application SignalR Service
import { AppSettings } from './../app.settings';
import { EventEmitter, Injectable } from '#angular/core';
declare const $: any;
#Injectable()
export class SignalRService {
// Declare the variables
private proxy: any;
private connection: any;
private authData: any;
// create the Event Emitter
public messageReceived: EventEmitter<any>;
public connectionEstablished: EventEmitter<Boolean>;
public connectionExists: Boolean;
constructor(private appSettings: AppSettings) {
// Setup
this.connectionEstablished = new EventEmitter<Boolean>();
this.messageReceived = new EventEmitter<any>();
this.connectionExists = false;
}
public initialize(proxyName: string): void {
this.connection = $.hubConnection(this.appSettings.SIGNALR_BASE_URL);
this.proxy = this.connection.createHubProxy(proxyName);
this.registerOnServerEvents();
this.startConnection();
}
private startConnection(): void {
this.connection.start({withCredentials: false})
.done((data: any) => {
console.log('SignalR Connected with: ' + data.transport.name);
this.connectionEstablished.emit(true);
this.connectionExists = true;
})
.fail((error: any) => {
console.log('SignalR could not connect: ' + error);
this.connectionEstablished.emit(false);
});
}
private registerOnServerEvents() {
this.proxy.on('listUpdated', (list: any) => {
console.log(list);
this.messageReceived.emit(list);
});
}
}
initialize(proxyName) gets called from a controller to start a connection to the Hub.
UPDATE
I've tried to rebuild the server and Hub using .NET Core 2.0, but when I test that on the IIS server I get:
"Failed to load https://signalr.example.com/online/negotiate: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://example.com' is therefore not allowed access."
So it's still a CORS issue even though I've setup everything just as multiple guides have done.
I've had issues in the past where the api path you are trying to hit is actually a virtual directory, and then IIS returns you a 403 because it thinks you are trying to view / access that directory instead of the webAPI route.
GET api/negotiate will 403 if you have the directory api/negotiate on your server.
This will be the case if you WebApiController is located in your project in a directory like:
/api/negotiate/NegotiateApiController.cs
You can resolve this very easily if that's the case by either changing the route or the directory name.
Note: This will come back as a 405 on some browsers.

How to create a connection between Angular.js and PostgreSQL using a WEB API 2 controller?

I am trying to connect an Angularjs script with a PostgreSQL database (the resulting HTML has to be able to show the data extracted from the PostgreSQL database). The PostgreSQL database was created locally with the default settings (during installation). I am working in the visual studio environment.
I tried using a similar approach to this (albeit this is meant to connect with a SQL Server rather than to a PostgreSQL database): http://cybarlab.com/crud-operations-in-angularjs-and-web-api
Essentially you define a web.config file with a connection string, create an object class for your database table rows, use update-database command in the Package Manager Console to create the appropriate table in the PostgreSQL database (which worked fine), create a WEB API 2 controller based upon the previously created object class (to get the CRUD operations) and get the data using $http.get function in the angular.js script (also invoking the controller in the html file).
The problem is, I have no idea what to write in the html.get(url) url field. All of my attempts have not been successful, which together with the lack of information on Google for this problem, leads me to believe this approach for PostgreSQL simply doesn't work. So is there any way to make it work? Or is there another way to establish the connection? While the description of the task does not note that the $http.get command should be used, it does note that this should be done using the WEB API 2 controller for the CRUD operations.
The connection string (the update-database command worked so it should be correct):
<connectionStrings>
<add name="TestProjectContext" providerName="Npgsql" connectionString="Server=127.0.0.1;Port=5432;Database=TestProject;User Id=postgres;Password=NotTelling;" />
</connectionStrings>
The class object (a table with these attributes was generated in the PostgreSQL database after using the update-table command):
public class DataDestination
{
[Key]
public Guid Id { get; set; }
public string Server { get; set; }
public string Port { get; set; }
public string Database { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string SqlType { get; set; }
public string Owner { get; set; }
}
The output table in HTML:
<body data-ng-app="app" data-ng-controller="TestController">
<table style="width:100%" , border="1">
<tr>
<td>Id</td>
<td>Server</td>
<td>Port</td>
<td>Database</td>
<td>Username</td>
<td>Password</td>
<td>SqlType</td>
<td>Owner</td>
</tr>
<tr data-ng-repeat="std in DataDestinations">
<td>
{{std.Id}}
</td>
<td>
{{std.Server}}
</td>
<td>
{{std.Port}}
</td>
<td>
{{std.Database}}
</td>
<td>
{{std.Username}}
</td>
<td>
{{std.Password}}
</td>
<td>
{{std.SqlType}}
</td>
<td>
{{std.Owner}}
</td>
</tr>
</body>
{{error}}
Finally, the angular.js script statement I tried to use (the rest of the script seems to be running fine and the error message is also thrown successfully):
$http.get('http://localhost:5432/TestProject').success(function (data) {
$scope.DataDestinations = data;
})
.error(function () {
$scope.error = "An Error has occured while loading posts!";
});
EDIT: Thank you for your responses. the WEB API 2 controller was created using the Add -> Controller -> WEB API 2 Controller with actions, using Entity Framework -> Choose the previously created class and context. So basically it was generated based on the class. Here is the code:
public class TestController : ApiController
{
private TestProjectContext db = new TestProjectContext();
// GET: api/Test
public IQueryable<DataDestination> GetDataDestinations()
{
return db.DataDestinations;
}
// GET: api/Test/5
[ResponseType(typeof(DataDestination))]
public IHttpActionResult GetDataDestination(Guid id)
{
DataDestination dataDestination = db.DataDestinations.Find(id);
if (dataDestination == null)
{
return NotFound();
}
return Ok(dataDestination);
}
// PUT: api/Test/5
[ResponseType(typeof(void))]
public IHttpActionResult PutDataDestination(Guid id, DataDestination dataDestination)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != dataDestination.Id)
{
return BadRequest();
}
db.Entry(dataDestination).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!DataDestinationExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
// POST: api/Test
[ResponseType(typeof(DataDestination))]
public IHttpActionResult PostDataDestination(DataDestination dataDestination)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.DataDestinations.Add(dataDestination);
try
{
db.SaveChanges();
}
catch (DbUpdateException)
{
if (DataDestinationExists(dataDestination.Id))
{
return Conflict();
}
else
{
throw;
}
}
return CreatedAtRoute("DefaultApi", new { id = dataDestination.Id }, dataDestination);
}
// DELETE: api/Test/5
[ResponseType(typeof(DataDestination))]
public IHttpActionResult DeleteDataDestination(Guid id)
{
DataDestination dataDestination = db.DataDestinations.Find(id);
if (dataDestination == null)
{
return NotFound();
}
db.DataDestinations.Remove(dataDestination);
db.SaveChanges();
return Ok(dataDestination);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
private bool DataDestinationExists(Guid id)
{
return db.DataDestinations.Count(e => e.Id == id) > 0;
}
}
}
I will also post the context for the object just in case that is wrong:
namespace TestProject.Models
{
public class TestProjectContext : DbContext
{
public TestProjectContext()
{
Database.SetInitializer<DbContext>(null);
}
public DbSet<DataDestination> DataDestinations { get; set; }
}
}
EDIT2: Added the CORS package to the project and added it to the beginning of the already defined WEB API controller:
using TestProject.Models;
using System.Web.Http.Cors;
namespace TestProject.Controllers
{
[EnableCors(origins: "http://localhost", headers: "*", methods: "*")]
public class TestController : ApiController
{
private TestProjectContext db = new TestProjectContext();
code is the same as in previous WEB API
Didn't fix the problem in and of itself. The same self defined error is being output - "An Error has occured while loading posts!".
After heeding Henri Cavalcante's request to create a WEB API, I ended up searching for the easiest way to do so and found the PostgREST program. What it does is automatically create an REST server based on your selected PostgreSQL database in the 3000 port. After doing so I could get the data out of the database without much hassle.
If there is anybody in a similar situation, here is a link for the postgREST first usage example: http://postgrest.com/examples/start/
In addendum I would like to say, that I really miss JDBC.
My suggestion is create a WEB api to make a connection between the front-end and the database.
You could use solutions like:
http://restify.com/ or http://loopback.io/
Or build your own solution using:
http://expressjs.com/ or http://koajs.com/

Categories

Resources