Fetch thymeleaf fragments from external URL - java

I have a spring-boot/thymeleaf website on server A, and I want to load some fragments from server B. The fragments are dynamic and some of them call java methods defined in server A, so what I need is to fetch those fragments (as plain text?) from server B and include them in my html pages in server A, where they will be processed etc. Server B will act like a repository, it won't do any processing at all, just serve the fragments to server A.
Is this possible?

Ok, I posted this question because all my attempts were failing, but after all it was just a typo that was holding me back... So here's what worked for me, in case anyone is interested:
I saved the fragments in src/main/resources/static/fragments on server B. Let's assume a file named frg with a fragment called "content" inside it.
I created a controller in server B to serve the files as plain text, like this:
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.io.File;
import java.nio.file.Files;
import javax.servlet.http.HttpServletResponse;
#Controller
public class FragmentsController {
#RequestMapping(value = "/fragments/{fragmentPage}")
#ResponseBody
public String GetFragment (#PathVariable String fragmentPage, HttpServletResponse response) throws Exception {
response.setHeader("Content-Type", "text/plain");
response.setHeader("success", "no");
if (fragmentPage == null)
{
System.err.println("Nothing to serve!");
return null;
}
System.out.println("Serving fragment: " + fragmentPage);
String fileName = "static/fragments/"+fragmentPage;
File resource = new ClassPathResource(fileName).getFile();
String frg = "";
try
{
frg= new String(Files.readAllBytes(resource.toPath()));
response.setHeader("success", "yes");
}
catch (Exception e)
{
frg = "Error loading fragment: " + e.getMessage();
}
return frg;
}
}
From server A, I can now fetch the fragment like this:
<div th:include="http://<server_b_url:port>/fragments/frg :: content"></div>

Related

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>

Azure functions using Java - How to created #BlobTrigger

i need to created Azure function BlobTrigger using Java to monitor my storage container for new and updated blobs.
tried with below code
import java.util.*;
import com.microsoft.azure.serverless.functions.annotation.*;
import com.microsoft.azure.serverless.functions.*;
import java.nio.file.*;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import com.microsoft.azure.storage.*;
import com.microsoft.azure.storage.blob.*;
#FunctionName("testblobtrigger")
public String testblobtrigger(#BlobTrigger(name = "test", path = "testcontainer/{name}") String content) {
try {
return String.format("Blob content : %s!", content);
} catch (Exception e) {
// Output the stack trace.
e.printStackTrace();
return "Access Error!";
}
}
when executed it is showing error
Storage binding (blob/queue/table) must have non-empty connection. Invalid storage binding found on method:
it is working when added connection string
public String kafkablobtrigger(#BlobTrigger(name = "test", path = "testjavablobstorage/{name}",connection=storageConnectionString) String content) {
why i need to add connection string when using blobtrigger?
in C# it is working without connection string:
public static void ProcessBlobContainer1([BlobTrigger("container1/{blobName}")] CloudBlockBlob blob, string blobName)
{
ProcessBlob("container1", blobName, blob);
}
i didn't see any Java sample for Azure functions for #BlobTrigger.
After all, connection is necessary for the trigger to identify where the container locates.
After test I find #Mikhail is right.
For C#, the default value(in local.settings.json or in application settings in portal) will be used if connection is ignored. But unfortunately there's no same settings for java.
You can add #StorageAccount("YourStorageConnection") below your #FuncionName as it's another valid way to choose. And value of YourStorageConnection in local.settings.json or in portal's application settings is up to you.
You can follow this tutorial, use mvn azure-functions:add to find four(Http/Blob/Queue/TimerTrigger) templates for java.

How to integrate karate with testrail

I am new to Java and using karate for API automation. I need help to integrate testrail with karate. I want to use tags for each scenario which will be the test case id (from testrail) and I want to push the result 'after the scenario'.
Can someone guide me on this? Code snippets would be more appreciated. Thank you!
I spent a lot of effort for this.
That's how I implement. Maybe you can follow it.
First of all, you should download the APIClient.java and APIException.java files from the link below.
TestrailApi in github
Then you need to add these files to the following path in your project.
For example: YourProjectFolder/src/main/java/testrails/
In your karate-config.js file, after each test, you can send your case tags, test results and error messages to the BaseTest.java file, which I will talk about shortly.
karate-config.js file
function fn() {
var config = {
baseUrl: 'http://111.111.1.111:11111',
};
karate.configure('afterScenario', () => {
try{
const BaseTestClass = Java.type('features.BaseTest');
BaseTestClass.sendScenarioResults(karate.scenario.failed,
karate.scenario.tags, karate.info.errorMessage);
}catch(error) {
console.log(error)
}
});
return config;
}
Please dont forget give tag to scenario in Feature file.
For example #1111
Feature: ExampleFeature
Background:
* def conf = call read('../karate-config.js')
* url conf.baseUrl
#1111
Scenario: Example
Next, create a runner file named BaseTests.java
BaseTest.java file
package features;
import com.intuit.karate.junit5.Karate;
import net.minidev.json.JSONObject;
import org.junit.jupiter.api.BeforeAll;
import testrails.APIClient;
import testrails.APIException;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class BaseTest {
private static APIClient client = null;
private static String runID = null;
#BeforeAll
public static void beforeClass() throws Exception {
String fileName = System.getProperty("karate.options");
//Login to API
client = new APIClient("Write Your host, for example
https://yourcompanyname.testrail.io/");
client.setUser("user.name#companyname.com");
client.setPassword("password");
//Create Test Run
Map data = new HashMap();
data.put("suite_id", "Write Your Project SuitId(Only number)");
data.put("name", "Api Test Run");
data.put("description", "Karate Architect Regression Running");
JSONObject c = (JSONObject) client.sendPost("add_run/" +
TESTRAİL_PROJECT_ID, data);
runID = c.getAsString("id");
}
//Send Scenario Result to Testrail
public static void sendScenarioResults(boolean failed, List<String> tags, String errorMessage) {
try {
Map data = new HashMap();
data.put("status_id", failed ? 5 : 1);
data.put("comment", errorMessage);
client.sendPost("add_result_for_case/" + runID + "/" + tags.get(0),
data);
} catch (IOException e) {
e.printStackTrace();
} catch (APIException e) {
e.printStackTrace();
}
}
#Karate.Test
Karate ExampleFeatureRun() {
return Karate.run("ExampleFeatureRun").relativeTo(getClass());
}
}
Please look at 'hooks' documented here: https://github.com/intuit/karate#hooks
And there is an example with code over here: https://github.com/intuit/karate/blob/master/karate-demo/src/test/java/demo/hooks/hooks.feature
I'm sorry I can't help you with how to push data to testrail, but it may be as simple as an HTTP request. And guess what Karate is famous for :)
Note that values of tags can be accessed within a test, here is the doc for karate.tagValues (with link to example): https://github.com/intuit/karate#the-karate-object
Note that you need to be on the 0.7.0 version, right now 0.7.0.RC8 is available.
Edit - also see: https://stackoverflow.com/a/54527955/143475

Spring Boot store upload file

I have to store an image for a few minutes after user upload it to show a preview, before confirmation, after confirmation i need get it back and persist.
I would like to know the best pratice to do this.
I saw about Cache and Caffeine, but i don't know if this is the best pratice and how store in Cache with a random hash to get it back after
[EDIT]
Maybe I was overestimating the problem
Following the #Robert suggestion i'll use temporary files, but i still need some way to garantee that files will be deleted. So i created a new question and i'll keep this to help others that do search with these terms.
Follow the link
How guarantee the file will be deleted after automatically some time?
I do this in one of my apps.
In the upload POST, I save the image to a temporary file and then store the temporary file name in a session attribute. I use the session attribute because the image being previewed shouldn't be visible to any other users until it has been written to persistent storage.
In the subsequent GET, I pull the temporary file name out of the session and stream it out to the response, deleting it when finished. I don't bother keeping the file after the preview is rendered as I don't need it anymore.
See the full implementation below:
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
#RestController
#RequestMapping("/api/imagePreview")
public class ImagePreviewController
{
#PostMapping
public ResponseEntity<?> post(HttpSession session, #RequestPart MultipartFile file) throws IOException
{
if (file.getContentType() != null && file.getContentType().startsWith("image/")) {
Path tempFile = Files.createTempFile("", file.getOriginalFilename());
file.transferTo(tempFile.toFile());
session.setAttribute("previewImage", tempFile.toFile().getPath());
session.setAttribute("previewImageContentType", file.getContentType());
return ResponseEntity.status(HttpStatus.CREATED).build();
} else {
return ResponseEntity.status(HttpStatus.UNSUPPORTED_MEDIA_TYPE).build();
}
}
#GetMapping
public void get(HttpServletRequest request, HttpServletResponse response) throws IOException
{
HttpSession session = request.getSession(false);
if (session == null) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
String path = (String) session.getAttribute("previewImage");
String contentType = (String) session.getAttribute("previewImageContentType");
if (path == null || contentType == null) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
response.setContentType(contentType);
try (OutputStream out = response.getOutputStream()) {
Files.copy(Paths.get(path), out);
} finally {
Files.deleteIfExists(Paths.get(path));
}
}
}

Map a image file through Spring controller

Is there any way to map a image file using a spring controller? In my spring application, I want store the images in the directory src/main/resources (i'm using maven) and access them with a method like this:
#RequestMapping(value="image/{theString}")
public ModelAndView image(#PathVariable String theString) {
return new ModelAndView('what should be placed here?');
}
the string theString it's the image name (without extension). With this approach, I should be able to access my images this way:
/webapp/controller_mapping/image/image_name
Anyone can point a direction to do that?
You can return HttpEntity<byte[]>. Construct new instance providing image byte array and necessary headers like content length and mime type then return it from your method. Image bytes can be obtained using classloader getResourceAsStream method.
This works for me. It could use some cleaning up but it works. The ServiceException is just a simple base exception.
Good Luck!
package com.dhargis.example;
import java.io.File;
import java.io.IOException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
#RequestMapping("/image")
public class ImageController {
private static final Logger log = Logger.getLogger(ImageController.class);
private String filestore = "C:\\Users\\dhargis";
//produces = "application/octet-stream"
#RequestMapping(value = "/{filename:.+}", method = RequestMethod.GET)
public void get( #PathVariable String filename,
HttpServletRequest request,
HttpServletResponse response) {
log.info("Getting file " + filename);
try {
byte[] content = null;
File store = new File(filestore);
if( store.exists() ){
File file = new File(store.getPath()+File.separator+filename);
if( file.exists() ){
content = FileUtils.readFileToByteArray(file);
} else {
throw new ServiceException("File does not exist");
}
} else {
throw new ServiceException("Report store is required");
}
ServletOutputStream out = response.getOutputStream();
out.write(content);
out.flush();
out.close();
} catch (ServiceException e) {
log.error("Error on get", e);
} catch (IOException e) {
log.error("Error on get", e);
}
}
}
<!-- begin snippet: js hide: false -->

Categories