Sending objects in a get request - spring

I 'll explain first what I'm trying to do:
There's a service method that receives a thymeleaf template html file, process that and then transform into a pdf. The job that was assigned to me is to create an endpoint which returns the template html so the service will call that endpoint to get the html.
I don't know how to pass objects in a get request.
The code in the service method before:
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("/templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
TemplateEngine templateEngine = new TemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
Context context = new Context();
context.setVariable("expenseReportPdf", expenseReportPdf);
context.setVariable("expensePdf", expensePdfList);
context.setVariable("expenseImg", jpgFile);
context.setVariable("amountCompanyCurrency", amountCompanyCurrency);
context.setVariable("expenseIncurredList", expenseIncurredList);
context.setVariable("expenseRiepiloghiList",expenseRiepiloghiList);
context.setVariable("advancePayBigDecimal", advancePayBigDecimal);
context.setVariable("dailyAllowanceList", dailyAllowanceList);
context.setVariable("dailyAllowanceFlag", dailyAllowanceFlag.booleanValue());
context.setVariable("logo",logo);
context.setVariable("logoSmartex",logoSmartex);
logger.debug("Logo Smartex:" + logoSmartex);
logger.debug("Logo Company:" + logo);
String renderedHtmlContent = templateEngine.process("template", context);
Firstly I moved that part in a configuration class which creates the beans necessary to return the html.
#Configuration
public class TemplateConfiguration {
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(htmlTemplateResolver2());
return templateEngine;
}
// Esiste giĆ  un bean che si chiama htmlTemplateResolver
#Bean
public ClassLoaderTemplateResolver htmlTemplateResolver2() {
ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver();
resolver.setOrder(Integer.valueOf(3));
resolver.setPrefix("templates/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
return resolver;
}
}
Then i create the endpoint which should return the html processed.
#GetMapping(path = "/get-template-html")
public String getTemplateHTMLEndpoint(#RequestParam("expenseReportPdf") String expenseReportPdfJSON, #RequestParam("expensePdfList") String expensePdfListJSON,
#RequestParam("jpgFile") String jpgFileJSON, #RequestParam("amountCompanyCurrency") String amountCompanyCurrencyJSON,
#RequestParam("expenseIncurredList") String expenseIncurredListJSON, #RequestParam("expenseRiepiloghiList") String expenseRiepiloghiListJSON,
#RequestParam("advancePayBigDecimal") String advancePayBigDecimalJSON, #RequestParam("dailyAllowanceList") String dailyAllowanceListJSON,
#RequestParam("dailyAllowanceFlag") String dailyAllowanceFlag, #RequestParam("logo") String logo, #RequestParam("logoSmartex") String logoSmartex) {
// TODO convert JSON params to relative objects
Context context = new Context();
context.setVariable("expenseReportPdf", expenseReportPdf);
context.setVariable("expensePdf", expensePdfList);
context.setVariable("expenseImg", jpgFile);
context.setVariable("amountCompanyCurrency", amountCompanyCurrency);
context.setVariable("expenseIncurredList", expenseIncurredList);
context.setVariable("expenseRiepiloghiList",expenseRiepiloghiList);
context.setVariable("advancePayBigDecimal", advancePayBigDecimal);
context.setVariable("dailyAllowanceList", dailyAllowanceList);
context.setVariable("dailyAllowanceFlag", String dailyAllowanceFlag);
context.setVariable("logo",logo);
context.setVariable("logoSmartex",logoSmartex);
String renderedHtmlContent = templateEngine.process("template", context);
return renderedHtmlContent;
}
}
Finally I created a method in the service which calls the endpoint.
private String callGetTemplateHTMLEndPoint(ExpenseReportPdf expenseReportPdf, List<ExpensePdf> expensePdfList, List<ExpenseImg> jpgFile,
BigDecimal amountCompanyCurrency, List<ExpenseIncurred> expenseIncurredList,
List<ExpenseRiepiloghi> expenseRiepiloghiList, BigDecimal advancePayBigDecimal,
List<DailyAllowanceDetails> dailyAllowanceList, Boolean dailyAllowanceFlag, String logo,
String logoSmartex) {
ObjectMapper objectMapper = new ObjectMapper();
String JSONExpenseReportPdf = "";
String JSONExpensePdfList = "";
String JSONJpgFile = "";
String JSONAmountCompanyCurrency = "";
String JSONExpenseIncurredList = "";
String JSONExpenseRiepiloghiList = "";
String JSONAdvancePayBigDecimal = "";
String JSONDailyAllowanceList = "";
// Trasformo i parametri in JSON
try {
JSONExpenseReportPdf = objectMapper.writeValueAsString(expenseReportPdf);
JSONExpensePdfList = objectMapper.writeValueAsString(expensePdfList);
JSONJpgFile = objectMapper.writeValueAsString(jpgFile);
JSONAmountCompanyCurrency = objectMapper.writeValueAsString(amountCompanyCurrency);
JSONExpenseIncurredList = objectMapper.writeValueAsString(expenseIncurredList);
JSONExpenseRiepiloghiList = objectMapper.writeValueAsString(expenseRiepiloghiList);
JSONAdvancePayBigDecimal = objectMapper.writeValueAsString(advancePayBigDecimal);
JSONDailyAllowanceList = objectMapper.writeValueAsString(dailyAllowanceList);
} catch (JsonProcessingException e1) {
e1.printStackTrace();
}
// Creo i query params coi JSON
String params = "?";
params += "expenseReportPdf=" + JSONExpenseReportPdf + "&";
params += "expensePdfList=" + JSONExpensePdfList + "&";
params += "jpgFile=" + JSONJpgFile + "&";
params += "amountCompanyCurrency=" + JSONAmountCompanyCurrency + "&";
params += "expenseIncurredList=" + JSONExpenseIncurredList + "&";
params += "expenseRiepiloghiList=" + JSONExpenseRiepiloghiList + "&";
params += "advancePayBigDecimal=" + JSONAdvancePayBigDecimal + "&";
params += "dailyAllowanceList=" + JSONDailyAllowanceList + "&";
params += "dailyAllowanceFlag=" + dailyAllowanceFlag + "&";
params += "logo=" + logo + "&";
params += "logoSmartex=" + logoSmartex;
HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest httpRequest = HttpRequest.newBuilder()
.uri(URI.create("http://localhost:9898/Smartex/expense-report-pdf/get-template-html" + params))
.build();
String templateHTML = "Problems with the request";
try {
templateHTML = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString())
.body();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return templateHTML;
}
I don't know how to send/receive the params needed for the processing of the template, any idea?
TY
After a while I thought I could transform objects into JSON, add them as query params and then transform them back in the controller but there are 2 problems:
The URL is too much long (2568 characters)
URL contains {} and give error

Related

How to download a large file in a Spring Boot microservices application?

I am trying to download a large file in a Spring Boot microservices application. Can anyone suggest a way of doing that?
Here is my front-end code
<a href={path + curDoc.id} download></a>
AJAX controller code
#GetMapping("/download-collector-file/{collectorFileId}")
public ResponseEntity<Resource> downloadCollectorFile(#PathVariable String collectorFileId) {
System.out.println("kjwenfjkewew beforr");
ResponseEntity<Resource> r= fileServiceAPI.downloadCollectorFile("token",collectorFileId, false);
System.out.println("after api");
return r;
}
Feign client code
#GetMapping("/order-files/read/{id}")
ResponseEntity<Resource> downloadCollectorFile(#RequestHeader("Authorization") String auth,
#PathVariable String id,
#RequestParam("isDownload") Boolean isDownload);
And my service back-end API code
#RequestMapping(value="/{id}" , method = RequestMethod.GET )
public ResponseEntity<InputStreamResource> downloadCollectorFile(#RequestHeader("Authorization") String auth, #PathVariable String id, #RequestParam(required = false, value = "isDownload") boolean isDownload) throws TgxValidationException, IOException {
System.out.println("new file id------===>"+id);
Optional<TgxFilesEntity> optionalTgxFilesEntity = tgxFilesRepository.findByIdAndDeletedFalse(id);
if (optionalTgxFilesEntity.isPresent()) {
TgxFilesEntity tgxFilesEntity = optionalTgxFilesEntity.get();
logger.info(">> UPLOAD_FOLDER=" + UPLOAD_FOLDER_PATH);
String absolutePath = UPLOAD_FOLDER_PATH + "/collector/" + tgxFilesEntity.getRelationalId() + "/";
final File parent = new File(absolutePath + tgxFilesEntity.getFilename());
InputStreamResource resource = new InputStreamResource(new FileInputStream(parent));
String mimeType = URLConnection.guessContentTypeFromName(tgxFilesEntity.getFilename());
logger.info("mimeType" + mimeType);
HttpHeaders headers = new HttpHeaders();
if (!isDownload) {
headers.add("Content-disposition", "inline; filename=" + tgxFilesEntity.getFilename());
if (mimeType == null) {
int lastIndexOf = tgxFilesEntity.getFilename().lastIndexOf(".");
if (tgxFilesEntity.getFilename().substring(lastIndexOf).contains(".json")) {
mimeType = "application/json";
} else if (tgxFilesEntity.getFilename().substring(lastIndexOf).contains(".xlsx")) {
mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
} else if (tgxFilesEntity.getFilename().substring(lastIndexOf).contains(".doc")) {
mimeType = "application/msword";
}
else if (tgxFilesEntity.getFilename().substring(lastIndexOf).contains(".zip")) {
mimeType = "application/zip";
}
else {
mimeType = "text/plain";
}
}
} else {
logger.info("hello else");
headers.add("Content-disposition", "attachment; filename=" + tgxFilesEntity.getFilename());
mimeType = "multipart/form-data";
}
System.out.println("brefore return===>"+resource.getFilename());
return ResponseEntity.ok().headers(headers).contentType(MediaType.parseMediaType(mimeType)).body(resource);
} else throw new FileNotFoundException(environment.getProperty("tgx.validation.file_not_found"));
}
Basically, it is not working for larger files like (300mb,400mb).
Is there any better approach of doing this?

#Async is not working for one of my method

I think when I add #Async notation for this method, it returns an empty result. The method is to get data from a website and return the data. It works when I remove #Async. When I am not using #Async, it is using a thread called "http-nio-8080-exec-1", when I use #Async, it is using a thread with my naming prefix "My-thread1". I do not know if I need to config anywhere else like xml or something. Thank you!
#Async
public CompletableFuture<List<Post>> searchByTag(String[] tags, String sortBy, String direction ) throws ExecutionException, InterruptedException, IOException {
logger.info("I am here---------------------------------------------------------- ");
if(tags == null || tags.length == 0){
throw new ResponseStatusException(HttpStatus.BAD_REQUEST , "Tags parameter is required");
}
if(sortBy == null){
sortBy = "id";
} else if(!sortBy.equals("id") && !sortBy.equals("reads") && !sortBy.equals("likes") && !sortBy.equals("popularity")){
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "sortBy parameter is invalid");
}
if(direction == null){
direction = "asc";
} else if(!direction.equals("asc") && !direction.equals("desc")){
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "direction parameter is invalid");
}
long start = System.currentTimeMillis();
Set<Post> postSet = new HashSet<Post>();
String baseUrl = "https://api.hatchways.io/assessment/blog/posts?tag=";
HttpClient client = HttpClient.newHttpClient();
// send a get request to get all the posts with certain tag
for(int i = 0; i < tags.length; i++){
String url = baseUrl + tags[i];
HttpRequest request = HttpRequest.newBuilder()
.GET()
.header("Accept", "application/json")
.uri(URI.create(url))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
ObjectMapper mapper = new ObjectMapper();
// HttpResponse<String> result = response.get();
String responseBody = response.body().substring(9, response.body().length()-1);
logger.info("Using Thread: " + Thread.currentThread().getName());
List<Post> posts = mapper.readValue(responseBody, new TypeReference<List<Post>>() {});
// put all the posts into a set to filter out all the repeated posts
postSet.addAll(posts);
}
ArrayList<Post> postList = new ArrayList<>(postSet);
sortThePosts(sortBy, direction, postList);
long end = System.currentTimeMillis();
logger.info("Total time: " + Long.toString(end-start));
return CompletableFuture.completedFuture(postList);
}
Following is my config:
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
#Configuration
#EnableAsync
public class AsyncConfig {
#Bean(name = "threadPoolTaskExecutor")
public Executor taskExecutor(){
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(3);
threadPoolTaskExecutor.setMaxPoolSize(5);
threadPoolTaskExecutor.setQueueCapacity(20);
threadPoolTaskExecutor.setThreadNamePrefix("My_Thread");
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
}
The configuration looks fine. Have you created searchByTag() method in the same class you are calling the method from? If so try creating a separate service class that will contain your Async methods.

Handling multipart response from spring rest controller

I am having controller method like this
#PostMapping(path = "/downloadAttachment",
produces = "application/octet-stream")
public ResponseEntity<?> downloadAttachment(#Valid #RequestBody Attachment attachmentModel) {
refreshProp(false);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
try {
String byteRes = null;
JSONArray responseFromDownloadAttachment =
databaseOperations.downloadAttachment(attachmentModel);
if (responseFromDownloadAttachment.length() == 0) {
return new ResponseEntity<>("", HttpStatus.NO_CONTENT);
}
else {
for (int blobRes = 0; blobRes < responseFromDownloadAttachment.length(); blobRes++) {
JSONObject blobObj = responseFromDownloadAttachment.getJSONObject(blobRes);
if (blobObj != null) {
byteRes = (String) blobObj.getString("file");
}
}
}
byte[] byteArrray = byteRes.getBytes();
return new ResponseEntity<>(byteArrray, HttpStatus.OK);
} catch (Exception e) {
log.error("Exception occurred!" + e);
e.printStackTrace();
JSONObject errObj = new JSONObject();
errObj.put("status", "E");
errObj.put("message", e);
return new ResponseEntity<>(errObj.toString(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
I am sending byte array as response.But i am not sure which type of file i will be getting from service layer.It can be in any form like xlsx,txt,png,jpg or any multimedia.I am setting headers to octet-stream and also produces to octet-stream.Can i use octet-stream to handle these type of responses?

upload file using rest services in spring mvc

I want to upload a file( any type of file ) into a forlder using web services and spring mvc so I have a sever side and a client side.
On my client side this is the code
#RequestMapping(value = "/uploadMultipleFile", method = RequestMethod.POST , produces="application/json")
public #ResponseBody
Boolean uploadMultipleFileHandler(
#RequestParam("name") MultipartFile[] files) {
MailService ms= new MailService();
Map<String, List<ByteArrayResource>>rval = new HashMap<String, List<ByteArrayResource>>();
String message = "";
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
List<Object> files1 = new ArrayList<>();
List<Object> files2 = new ArrayList<>();
for (int i = 0; i < files.length; i++) {
MultipartFile file = files[i];
System.out.println(file.getOriginalFilename());
try {
byte[] bytes = file.getBytes();
files1.add(new ByteArrayResource(bytes));
files2.add(file.getOriginalFilename());
//System.out.println(map.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
map.put("files", files1);
map.put("names", files2);
System.out.println(map.get("files").toString());
RestTemplate restTemplate = new RestTemplate();
String SERVER_URI="http://localhost:8080/BackEndFinalVersion";
Boolean p=restTemplate.postForObject(SERVER_URI+"/uploadMultipleFile", map, Boolean.class);
System.out.println(p.toString());
//message = message + ms.encodeFileToBase64Binary( bytes);
//rval.put("success",message);
return true;
}
and the server side code is
#RequestMapping(value = "/uploadMultipleFile", method = RequestMethod.POST, produces = "application/json")
public #ResponseBody Boolean uploadMultipleFileHandler(#RequestParam("files") List<Object> files , #RequestParam("names") List<Object> names) {
//MailService ms= new MailService();
//Map<String, Object> rval = new HashMap<String, Object>();
String message = "";
System.out.println("looool");
System.out.println(files);
System.out.println(names);
//System.out.println(files.get(0).toString());
for (int i = 0; i < files.size(); i++) {
System.out.println(files.get(i).getClass());
String file = (String)files.get(i);
try {
byte[] bytes = file.getBytes();
//FileUtils.writeStringToFile(new File("log.txt"), file, Charset.defaultCharset());
// Creating the directory to store file
String rootPath = "C:/Users/Wassim/Desktop/uploads";
File dir = new File(rootPath);
if (!dir.exists())
dir.mkdirs();
File serverFile = new File(dir.getAbsolutePath() + File.separator + ( names.get(i)));
BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(serverFile));
stream.write(bytes);
stream.close();
//message = message + "You successfully uploaded file=" + ( (MultipartFile) files.get(i)).getOriginalFilename() + "<br />";
//FileUtils.writeByteArrayToFile(new File(dir.getAbsolutePath() + File.separator + files.get(i).getOriginalFilename()), ms.decodeFileToBase64Binary(ms.encodeFileToBase64Binary( bytes)));
//rval.put("success"+i, message);
System.out.println("noooo");
} catch (Exception e) {
message += "You failed to upload " + " => " + e.getMessage();
//rval.put("error", message);
return false;
}
}
return true;
My problem is that this code doesn't work only with .txt files
can any one support me ??

#Around advice returning correct response but at client side response is null or undefined

I am trying to apply Around advice to my "Login.jsp" with angular js. And the problem is my controller method is check and I am applying around advice to check method but when I run my application I will get undefined as response at Login.jsp. And but the result which I had printed in my advice contains expected result.But I am not getting it on client side.
AroundAdvice.java
#Aspect #Component
public class AroundAdvice {
static Logger log = Logger.getLogger(AfterLoginAspect.class.getName());
#Around("execution(* com.admin.controller.LoginController.check(..))")
public void logWrittter(ProceedingJoinPoint jp) throws Throwable {
SimpleDateFormat date=new SimpleDateFormat();
log.info("Date Time :: " + date.format(new Date().getTime()));
Object result = jp.proceed();
System.out.println("result around");
log.info("result :: " + result);
// returns {"get Status":"home"}
}
}
LoginController.jsp
// authentication check
#RequestMapping(value = "/PostFormData", method = RequestMethod.POST)
public #ResponseBody JSONObject check(#RequestBody LoginBo login) {
System.out.println("checkCredentials::" + login.getUserName());
String username = login.getUserName();
// log.info("uswername ::"+username);
JSONObject result = new JSONObject();
String encrptedpassword = encryptdPwd.encrypt(login.getPassWord());
boolean login_status = loginService.checkCredentials(username, encrptedpassword);
// log.info("login_status ::"+login_status);
// System.out.println("staus ::"+login_status);
if (login_status == true && login.isIs_system_generated_pwd() == true) {
System.out.println("sys gen chnge pwd:: " + login.isIs_system_generated_pwd());
result.put("getStatus", "change");
// System.out.println(resultPage);
// login.setIs_system_generated_pwd(false);
} else if (login_status == true && login.isIs_system_generated_pwd() == false) {
result.put("getStatus", "home");
// System.out.println("Home paege ");
} else {
result.put("getStatus", "error");
}
System.out.println("result ::" + result);
// log.info("result ::"+resultPage);
return result;
}
Your pointcut does not match because the advice has a void return type, but your method returns a JSONObject. So maybe you want to change your advice declaration to:
#Aspect #Component
public class AroundAdvice {
static Logger log = Logger.getLogger(AfterLoginAspect.class.getName());
#Around("execution(* com.admin.controller.LoginController.check(..))")
public JSONObject logWriter(ProceedingJoinPoint jp) throws Throwable {
SimpleDateFormat date=new SimpleDateFormat();
log.info("Date Time :: " + date.format(new Date().getTime()));
JSONObject result = (JSONObject) jp.proceed();
System.out.println("result around");
log.info("result :: " + result);
return result;
}
}
Please note
public JSONObject logWriter instead of public void logWrittter,
JSONObject result = (JSONObject) jp.proceed(); instead of Object result = jp.proceed(); and
return result; instead of no return value.

Resources