Java, Spark, return index.html - java

I'm trying to create SPA, using Spark on server-side.
Here is my App.java:
package com.farot;
import java.util.HashMap;
import java.util.UUID;
import java.net.URL;
import java.net.URISyntaxException;
import java.nio.file.Paths;
import java.nio.file.Files;
import java.nio.charset.Charset;
import java.io.IOException;
import com.google.gson.Gson;
import static spark.Spark.*;
import com.farot.utils.Path;
import com.farot.controllers.UserController;
import com.farot.controllers.AccountController;
import com.farot.controllers.MapController;
public class App
{
private static Gson gson = new Gson();
private static String renderIndex() {
try {
URL url = App.class.getResource("index.html");
return new String(Files.readAllBytes(Paths.get(url.toURI())), Charset.defaultCharset());
} catch (IOException | URISyntaxException e) {
System.out.println(e.getMessage());
}
return null;
}
public static void main( String[] args )
{
staticFiles.location("/public");
before((req, res) -> {
String path = req.pathInfo();
if (path.endsWith("/"))
res.redirect(path.substring(0, path.length() - 1));
});
// Site pages
get("/", "text/html", (req, res) -> renderIndex());
get("/login", "text/html", (req, res) -> renderIndex());
post(Path.Web.api.Account.DEFAULT, (req, res) -> {
return AccountController.create(req, res);
}, gson::toJson);
}
}
POST request at Path.Web.api.Account.DEFAULT works as expected, but request at /login returns 404. What can be wrong?
index.html's path is /resources/public/index.html.

The problem is in the function renderIndex(). After using the correct resource path (i.e. /public/index.html) the variable url is not null anymore, but according to what you said in the comments it's something weird (jar:file:/home/gorrtack/workspace/Farot/target/Farot-1.0-SNA‌PSHOT-jar-with-depen‌​dencies.jar!/public/‌​index.html), something with no valid path.
When Paths.get() tries to resolve this path it fails and throws a NoSuchFileException (which is an IOException). Then, you catch it in the catch block, and returns null. The returning of null is wrong and it's the reason for the error 404 you're getting.
So you need:
To change something in the structure of your project so the path of index.html is right. Then you'll avoid the problems in this scenario.
Handle the exceptions correctly, means - don't return null. Decide what you want to do in these cases and then, if you want, you can still serve a normal error message to the client and/or use request.status() API or any any other response APIs to set a response status by yourself.

In the renderIndex() method, access the path as below:
URL url = App.class.getResource("/public/index.html");

Related

Java Google Api application Default credentials

How do I declare the application credentials? I have my .json file which is the key.
package shyam;
// Imports the Google Cloud client library
import com.google.cloud.vision.v1.AnnotateImageRequest;
import com.google.cloud.vision.v1.AnnotateImageResponse;
import com.google.cloud.vision.v1.BatchAnnotateImagesResponse;
import com.google.cloud.vision.v1.EntityAnnotation;
import com.google.cloud.vision.v1.Feature;
import com.google.cloud.vision.v1.Feature.Type;
import com.google.cloud.vision.v1.Image;
import com.google.cloud.vision.v1.ImageAnnotatorClient;
import com.google.protobuf.ByteString;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public class App {
public static void main(String[] args) throws Exception {
// Initialize client that will be used to send requests. This client only needs to be created
// once, and can be reused for multiple requests. After completing all of your requests, call
// the "close" method on the client to safely clean up any remaining background resources.
try (ImageAnnotatorClient vision = ImageAnnotatorClient.create()) {
// The path to the image file to annotate
String fileName = "./resources/wakeupcat.jpg";
// Reads the image file into memory
Path path = Paths.get(fileName);
byte[] data = Files.readAllBytes(path);
ByteString imgBytes = ByteString.copyFrom(data);
// Builds the image annotation request
List<AnnotateImageRequest> requests = new ArrayList<>();
Image img = Image.newBuilder().setContent(imgBytes).build();
Feature feat = Feature.newBuilder().setType(Type.LABEL_DETECTION).build();
AnnotateImageRequest request =
AnnotateImageRequest.newBuilder().addFeatures(feat).setImage(img).build();
requests.add(request);
// Performs label detection on the image file
BatchAnnotateImagesResponse response = vision.batchAnnotateImages(requests);
List<AnnotateImageResponse> responses = response.getResponsesList();
for (AnnotateImageResponse res : responses) {
if (res.hasError()) {
System.out.format("Error: %s%n", res.getError().getMessage());
return;
}
// for (EntityAnnotation annotation : res.getLabelAnnotationsList()) {
// annotation
// .getAllFields()
// .forEach((k, v) -> System.out.format("%s : %s%n", k, v.toString()));
// }
}
}
}
}
I'm getting the error
Application default credentials are not available
I have already set it in my cmd using set GOOGLE_APPLICATION_CREDENTIALS='key_path'. I have a lot initialized my Google Cloud Account in the cli. Hope someone can help me. Thank you.

Java webclient returns 2 double quotes on string response

package com.myproject.extract.Generic;
import com.myproject.extract.Callbacks.catchError;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonObject;
import org.bson.types.ObjectId;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
public class ajax {
public static Mono<String> Post(String url, ObjectId projectId, JsonObject data) {
try {
// To call https, following is required.
SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE)
.build();
HttpClient httpClient = HttpClient.create().secure(t -> t.sslContext(sslContext));
WebClient webClient = WebClient.builder().baseUrl("https://localhost:3100/api/" + url)
.defaultHeader("projectId", projectId.toString()) // TODO: there was option of only header instead
// of
// defaultheader. don't know why that was not
// working. don't know the difference either.
.clientConnector(new ReactorClientHttpConnector(httpClient)).build();
return webClient.post().syncBody(toJsonNode(data)).retrieve().bodyToMono(String.class);
} catch (Exception e) {
catchError.handlError(e);
}
return null;
}
public static JsonNode toJsonNode(JsonObject jsonObj) throws Exception {
return new ObjectMapper().readTree(jsonObj.toString());
}
}
I am using above method as following.
As you can see response shows 2 double quotes for string value. Because of this I am unable to parse it to ObjectID.
What wrong am I doing?
Why it returns 2 double quoted value ""60cc845e86114119f8aa4306"" instead of 1 double quoted value "60cc845e86114119f8aa4306"?
How to prevent 2 double quoted value and retrieve 1 double quoted value?
Looks like when I return JSON response and I use bodyToMono(String.class), it stringifies that.
When I return string from the server, bodyToMono(String.class) stringifies that as well and adds extra quotes. For now, I have removed it manually using substring.

Java Spring - Can't save image to static folder

I want to save image to resources/static/photos file, but Java/Kotlin can't find it. It finds project/photos well though.
This is a code, in Kotlin, but I don't think it matters
override fun saveImage(imageFile: MultipartFile, id: String) {
val bytes = imageFile.bytes
val path = Paths.get(
"$imagesFolderPath$id.${imageFile.originalFilename.substringAfter('.')}")
Files.write(path, bytes)
}
I need this to be saved to resources/static/photos to be able to access it from thymeleaf.
Thanks.
The problem is, you may be able to save files inside your projects directory during the development phase, but that won't be possible as soon as you export your project as an application package (a .jar-application, .war-archive etc), because at that point, everything that previously was an actual directory on your file-system is now a single file.
Here's an example how you could implement this by saving the images in a configurable folder:
I never wrote a line of code in Kotlin. I hope this example helps you even if it is in Java.
This is an example controller that accepts images to be uploaded on a POST endpoint and being downloaded on a GET endpoint:
package example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.PathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Optional;
#RestController
public class MyController {
private final Path imageStorageDir;
/*
The target path can be configured in the application.properties / application.yml or using the parameter -Dimage-storage.dir=/some/path/
*/
#Autowired
public MyController(#Value("${image-storage-dir}") Path imageStorageDir) {
this.imageStorageDir = imageStorageDir;
}
#PostConstruct
public void ensureDirectoryExists() throws IOException {
if (!Files.exists(this.imageStorageDir)) {
Files.createDirectories(this.imageStorageDir);
}
}
/*
This enables you to perform POST requests against the "/image/YourID" path
It returns the name this image can be referenced on later
*/
#PostMapping(value = "/image/{id}", produces = MediaType.TEXT_PLAIN_VALUE)
public String uploadImage(#RequestBody MultipartFile imageFile, #PathVariable("id") String id) throws IOException {
final String fileExtension = Optional.ofNullable(imageFile.getOriginalFilename())
.flatMap(MyController::getFileExtension)
.orElse("");
final String targetFileName = id + "." + fileExtension;
final Path targetPath = this.imageStorageDir.resolve(targetFileName);
try (InputStream in = imageFile.getInputStream()) {
try (OutputStream out = Files.newOutputStream(targetPath, StandardOpenOption.CREATE)) {
in.transferTo(out);
}
}
return targetFileName;
}
/*
This enables you to download previously uploaded images
*/
#GetMapping("/image/{fileName}")
public ResponseEntity<Resource> downloadImage(#PathVariable("fileName") String fileName) {
final Path targetPath = this.imageStorageDir.resolve(fileName);
if (!Files.exists(targetPath)) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(new PathResource(targetPath));
}
private static Optional<String> getFileExtension(String fileName) {
final int indexOfLastDot = fileName.lastIndexOf('.');
if (indexOfLastDot == -1) {
return Optional.empty();
} else {
return Optional.of(fileName.substring(indexOfLastDot + 1));
}
}
}
Let's say you uploaded am image with the file-ending .png and the id HelloWorld, you could then access the image using the url:
http://localhost:8080/image/HelloWorld.png
Using this URL you can also reference the image in any of your thymeleaf templates:
<img th:src="#{/image/HelloWorld.png}"></img>

Incomplete java.net.URL.openStream() stream

I’m using java.net.URL.openStream() to access a HTTPS resource. The returned stream is incomplete for some URLs: for the example below, it yields a 1,105,724 byte-file whereas the same URL accessed from a browser yields a 5,755,858 byte-file (even when "disabling" Content-Encoding).
And it doesn’t even throw an exception.
What am I missing?
import static java.nio.file.Files.copy;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Paths;
public class Test {
public static void main(String... args) throws IOException {
try (final InputStream in = new URL(
"https://upload.wikimedia.org/wikipedia/commons/9/95/Germany_%28orthographic_projection%29.svg").openStream()) {
copy(in, Paths.get("germany.svg"));
}
}
}
Edit
I’ve tested this code a lot of times (on different networks, but always on JRE 1.8.0_60 / Mac OS X 10.11.4), and sometimes it’s suddenly "starting to work".
However, switching to another of my problematic URLs (e.g. "https://upload.wikimedia.org/wikipedia/commons/c/ce/Andorra_in_Europe_%28zoomed%29.svg") enables me to reproduce the issue.
Does this mean that it is a server issue? I’ve never seen it on a browser though.
It's working fine.
As others have suggested there may be a problem with your network, try connecting to another network.
package test;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
public class TestMain2 {
public static void main(String[] args) {
System.out.println("Started");
try (final InputStream in = new URL(
"https://upload.wikimedia.org/wikipedia/commons/9/95/Germany_%28orthographic_projection%29.svg")
.openStream()) {
Path outputFile = Paths.get("test.svg");
Files.copy(in, outputFile, StandardCopyOption.REPLACE_EXISTING);
System.out.println("Output file size : " + outputFile.toFile().length());
System.out.println("Finished");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Output
Started
Output file size : 5755858
Finished

How to get this property value in my java code?

I'm learning Java and sometimes I have some problem to retrieve the information I need from objects...
When I debug my code I can see in targetFile, a path property but I don't know how to get it in my code.
This is a screenshot:
(source: toile-libre.org)
This is my complete code:
package com.example.helloworld;
import com.github.axet.wget.WGet;
import com.github.axet.wget.info.DownloadInfo;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class HelloWorld {
public static void main(String[] args) throws IOException {
nodejs();
}
public static void nodejs() throws IOException {
// Scrap the download url.
Document doc = Jsoup.connect("http://nodejs.org/download").get();
Element link = doc.select("div.interior:nth-child(2) > table:nth-child(2) > tbody:nth-child(1) > tr:nth-child(1) > td:nth-child(3) > a:nth-child(1)").first();
String url = link.attr("abs:href");
// Print the download url.
System.out.println(url);
// Download file via the scraped url.
URL download = new URL(url);
File target = new File("/home/lan/Desktop/");
WGet w = new WGet(download, target);
w.download();
// Get the targetFile property
// ???
}
}
How can I get this value?
I do not know your code but the field you are interested in may be encapsulated and thus not accessible in your code, but the debugger can see it at runtime :)
Update:
https://github.com/axet/wget/blob/master/src/main/java/com/github/axet/wget/WGet.java
The field is default package, you can only access it from within the package.
This can be frustrating at times, but you should ask yourself why the designers of this class decided to hide this field.

Categories