I am trying to upload multiple files and I am facing an issue while doing so. Can someone please suggest what is wrong?
I am enclosing relevant snippets of my code to debug better.
html code
<label>
welcome {{name}}, welcome to new app.
</label>
<div>
<input type="file" multiple placeholder="Select Files to be upload" accept=".xlsx" (change)=selectedfiles($event)>
</div>
upload logic
selectedfiles(event){
this.selectedxlfiles=event.target.files;
this.fileandinstancekeyobj.filetoupload=this.selectedxlfiles;
this.fileandinstancekeyobj.instancekey=this.instancekey;
this.uploadservice.uploadtoserver(this.fileandinstancekeyobj).subscribe(result=>{
console.log(result);
})
}
uploadservice
uploadtoserver(selectedfileandinstacekeyobj): Observable<HttpEvent<{}>>{
let url:string=environment.url+'uploadfile';
const newrequest=new HttpRequest('POST',url,selectedfileandinstacekeyobj,{
reportProgress:true,
responseType:'text'
});
return this.http.request(newrequest);
}
springboot controller
#RestController
public class uploadcontroller {
#PostMapping("/uploadfile")
public ResponseEntity<String> handleupload(#RequestBody uploaddto dto){
System.out.println("sucessfull");
System.out.println(dto.getInstancekey()+" "+dto.getFiletoupload().length);
return ResponseEntity.status(HttpStatus.OK).body("ok");
}
upload DTO
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
class uploaddto {
List<MultipartFile> filetoupload;
String instancekey;
public uploaddto(List<MultipartFile> filetoupload, String instancekey) {
super();
filetoupload=new ArrayList<MultipartFile>();
this.filetoupload = filetoupload;
this.instancekey = instancekey;
}
public List<MultipartFile> getFiletoupload() {
return filetoupload;
}
public void setFiletoupload(List<MultipartFile> filetoupload) {
this.filetoupload = filetoupload;
}
public String getInstancekey() {
return instancekey;
}
public void setInstancekey(String instancekey) {
this.instancekey = instancekey;
}
}
I am receiving the following error
[org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error:
Cannot deserialize instance of `java.util.ArrayList<org.springframework.web.multipart.MultipartFile>` out of START_OBJECT token;
nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException:
Cannot deserialize instance of `java.util.ArrayList<org.springframework.web.multipart.MultipartFile>` out of START_OBJECT token
at [Source: (PushbackInputStream); line: 1, column: 17] (through reference chain: com.example.demo.uploaddto["filetoupload"])]
Any suggestion would be appreciated
I am adding this answer so that i could help someone save his day, what i did
change in uploadcontroller
this.selectedxlfiles=event.target.files;
const data:FormData=new FormData();
for(let i=0;i<this.selectedxlfiles.length;i++){
this.currentfile=this.selectedxlfiles[i];
data.append('selectedfile',this.currentfile);
}
data.append('instancekey',this.instancekey);
this.uploadservice.uploadtoserver(data).subscribe(Response=>{
console.log(Response);
})
changes in upload service
uploadtoserver(data:FormData): Observable<HttpEvent<{}>>{
let url:string=environment.url+'uploadfile';
// console.log(url);
// const data: FormData=new FormData();
// data.append('selectedfile',selectedfile);
// data.append('instancekey',instancekey);
const newrequest=new HttpRequest('POST',url,data,{
reportProgress: true,
responseType: 'text',
});
return this.http.request(newrequest);
//return this.http.post(url,selectedfiles);
}
changes in springboot controller
#RestController
public class uploadcontroller {
#PostMapping("/uploadfile")
public ResponseEntity<String> handleupload(#ModelAttribute uploaddto dto){
System.out.println("sucessfull");
System.out.println(dto.getInstancekey()+" "+dto.getFiletoupload().length);
return ResponseEntity.status(HttpStatus.OK).body("ok");
}
the only change in controller #modelattribute
Related
I am trying to write a search function, but I encounter a bug when I pass the search query from frontend to backend. I tried most of the solution on Internet but it's still not ok.
Complete Error log
2022-10-12 15:05:10.575 WARN 21272 --- [nio-8090-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required request parameter 'searchQuery' for method parameter type String is not present]
frontend
<template>
<div class="input-group mb-3">
<input type="search" class="form-control rounded" v-model="searchQuery" placeholder="Company name" aria-label="Search" aria-describedby="search-addon" />
<button type="button" class="btn btn-outline-primary" #click='searchRecord'>Search</button>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'RegistrationEnquiry',
components: {
},
data() {
return {
records: [],
searchQuery: '',
};
},
computed: {},
methods: {
searchRecord(){
axios.post('searchRecord', this.searchQuery)
.then(successResponse => {
console.log(successResponse)
})
.catch(failResponse => {
alert("Error(failResponse)")
console.log(failResponse)
})
},
},
}
</script>
SearchRecordController.java
#Controller
public class SearchRecordController {
#Autowired
SearchRecordService searchRecordService;
#CrossOrigin
#PostMapping(value = "api/searchRecord")
#ResponseBody
public String searchRecord(#RequestParam(value = "searchQuery") String searchQuery) {
System.out.println(searchQuery);
return searchRecordService.searchRecordService(searchQuery);
}
}
It is not the correct way of sending parameters through axios.
You can send params by changing your code in frontend to :-
axios.post(`api/searchRecord`, null, { params: {
searchQuery
}}
Which will send the request as :
https://localhost:8080/api/searchRecord?searchQuery=valueofsearchtext
Keep your controller as it is as there are no changes required in the backend.
#CrossOrigin
#PostMapping(value = "api/searchRecord")
#ResponseBody
public String searchRecord(#RequestParam(value = "searchQuery") String searchQuery) {
System.out.println(searchQuery);
return searchRecordService.searchRecordService(searchQuery);
}
this should sort the issue in your code.
From backend side it seems ok, I think you need to send data in post like that:
searchRecord(){
axios.post({
method: 'post',
url: '/api/searchRecord',
data: {
searchQuery: this.searchQuery
}
})
.then(successResponse => {
console.log(successResponse)
})
.catch(failResponse => {
alert("Error(failResponse)")
console.log(failResponse)
})
}
basically, it appears when you send no value from the front end but your controller expects some parameter from the frontend side,
to avoid this u can use "required = false" or u can fix a default value based on your requirement to check where you are going wrong.
public String searchRecord(#RequestParam(value = "searchQuery",required = false,defaultValue = "") String searchQuery) {
return searchRecordService.searchRecordService(searchQuery);
}
Front end is not sending data to the controller. Try giving default value=null;
Is it possible to concisely implement a single HAL-JSON & JSON endpoints in Spring Boot 2? The goal is to have:
curl -v http://localhost:8091/books
return this application/hal+json result:
{
"_embedded" : {
"bookList" : [ {
"title" : "The As",
"author" : "ab",
"isbn" : "A"
}, {
"title" : "The Bs",
"author" : "ab",
"isbn" : "B"
}, {
"title" : "The Cs",
"author" : "cd",
"isbn" : "C"
} ]
}
and for this (and/or the HTTP Accept header since this is a REST API):
curl -v http://localhost:8091/books?format=application/json
to return the plain application/json result:
[ {
"title" : "The As",
"author" : "ab",
"isbn" : "A"
}, {
"title" : "The Bs",
"author" : "ab",
"isbn" : "B"
}, {
"title" : "The Cs",
"author" : "cd",
"isbn" : "C"
} ]
with minimal controller code. These endpoints work as expected:
#GetMapping("/asJson")
public Collection<Book> booksAsJson() {
return _books();
}
#GetMapping("/asHalJson")
public CollectionModel<Book> booksAsHalJson() {
return _halJson(_books());
}
#GetMapping
public ResponseEntity<?> booksWithParam(
#RequestParam(name="format", defaultValue="application/hal+json")
String format) {
return _selectedMediaType(_books(), format);
}
#GetMapping("/asDesired")
public ResponseEntity<?> booksAsDesired() {
return _selectedMediaType(_books(), _format());
}
with the following helpers:
private String _format() {
// TODO: something clever here...perhaps Spring's content-negotiation?
return MediaTypes.HAL_JSON_VALUE;
}
private <T> static CollectionModel<T> _halJson(Collection<T> items) {
return CollectionModel.of(items);
}
private <T> static ResponseEntity<?> _selectedMediaType(
Collection<T> items, String format) {
return ResponseEntity.ok(switch(format.toLowerCase()) {
case MediaTypes.HAL_JSON_VALUE -> _halJson(items);
case MediaType.APPLICATION_JSON_VALUE -> items;
default -> throw _unknownFormat(format);
});
}
but the booksWithParam implementation is too messy to duplicate for each endpoint. Is there a way to get to, or close to, something like the booksAsDesired implementation or something similarly concise?
One way you could tell Spring that you want to support plain JSON is by adding a custom converter for such media types. This can be done by overwriting the extendMessageConverters method of WebMvcConfigurer and adding your custom converters there like in the sample below:
import ...PlainJsonHttpMessageConverter;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.web.config.EnableSpringDataWebSuport;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servelt.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
import javax.annotation.Nonnull;
#Configuration
#EnableSpringeDataWebSupport
public class WebMvcConfiguration implements WebMvcConfigurer {
#Override
public void extendMessageConverters(#Nonnull final List<HttpMessageConverter<?>> converters) {
converters.add(new PlainJsonHttpMessageConverter());
}
}
The message converter itself is also no rocket-science as can be seen by the PlainJsonHttpMessageConverter sample below:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsr310.JavaTimeModule;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
import org.springframework.stereotype.Component;
import javax.annotation.Nonnull;
#Component
public class PlainJsonHttpMessageConverter extends AbstractJackson2HttpMessageConverter {
public PlainJsonHttpMessageConverter() {
super(new ObjectMapper(), MediaType.APPLICATION_JSON);
// add support for date and time format conversion to ISO 8601 and others
this.defaultObjectMapper.registerModule(new JavaTimeModule());
// return JSON payload in pretty format
this.defaultObjectMapper.enable(SerializationFeature.INDENT_OUTPUT);
}
#Override
protected boolean supports(#Nonnull final Class<?> clazz) {
return RepresentationModel.class.isAssignableFrom(clazz);
}
}
This should enable plain JSON support besides HAL-JSON without you having to do any further branching or custom media-type specific conversion within your domain logic or service code.
I.e. let's take a simple task as example case. Within a TaskController you might have a code like this
#GetMapping(path = "/{taskId:.+}", produces = {
MediaTypes.HAL_JSON_VALUE,
MediaType.APPLICATION_JSON_VALUE,
MediaTypes.HTTP_PROBLEM_DETAILS_JSON_VALUE
})
public ResponseEntity<?> task(#PathVariable("taskId") String taskId,
#RequestParam(required = false) Map<String, String> queryParams,
HttpServletRequest request) {
if (queryParams == null) {
queryParams = new HashMap<>();
}
Pageable pageable = RequestUtils.getPageableForInput(queryParams);
final String caseId = queryParams.get("caseId");
...
final Query query = buildSearchCriteria(taskId, caseId, ...);
query.with(pageable);
List<Task> matches = mongoTemplate.find(query, Task.class);
if (!matches.isEmpty()) {
final Task task = matches.get(0);
return ResponseEntity.ok()
.eTag(Long.toString(task.getVersion())
.body(TASK_ASSEMBLER.toModel(task));
} else {
if (request.getHeader("Accept").contains(MediaTypes.HTTP_PROBLEM_DETAILS_JSON_VALUE)) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.contentType(MediaTypes.HTTP_PROBLEM_DETAILS_JSON)
.body(generateNotFoundProblem(request, taskId));
} else {
final String msg = "No task with ID " + taskId + " found";
throw new ResponseStatusException(HttpStatus.NOT_FOUND, msg);
}
}
}
which simply retrieves an arbitrary task via its unique identifier and returns the representation for it according to the one specified in the Accept HTTP header. The TASK_ASSEMBLER here is just a custom Spring HATEOAS RepresentationModelAssembler<Task, TaskResource> class that converts task objects to task resources by adding links for certain related things.
This can now be easily tested via Spring MVC tests such as
#Test
public void halJson() throws Exception {
given(mongoTemplate.find(any(Query.class), eq(Task.class)))
.willReturn(setupSingleTaskList());
final ResultActions result = mockMvc.perform(
get("/api/tasks/taskId")
.accept(MediaTypes.HAL_JSON_VALUE)
);
result.andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON_VALUE));
// see raw payload received by commenting out below line
// System.err.println(result.andReturn().getResponse().getContentAsString());
verifyHalJson(result);
}
#Test
public void plainJson() throws Exception {
given(mongoTemplate.find(any(Query.class), eq(Task.class)))
.willReturn(setupSingleTaskList());
final ResultActions result = mockMvc.perform(
get("/api/tasks/taskId")
.accept(MediaType.APPLICATION_JSON_VALUE)
);
result.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE));
// see raw payload received by commenting out below line
// System.err.println(result.andReturn().getResponse().getContentAsString());
verifyPlainJson(result);
}
...
private void verifyHalJson(final ResultActions action) throws Exception {
action.andExpect(jsonPath("taskId", is("taskId")))
.andExpect(jsonPath("caseId", is("caseId")))
...
.andExpect(jsonPath("_links.self.href", is(BASE_URI + "/tasks/taskId")))
.andExpect(jsonPath("_links.up.href", is(BASE_URI + "/tasks")));
}
rivate void verifyPlainJson(final ResultActions action) throws Exception {
action.andExpect(jsonPath("taskId", is("taskId")))
.andExpect(jsonPath("caseId", is("caseId")))
...
.andExpect(jsonPath("links[0].rel", is("self")))
.andExpect(jsonPath("links[0].href", is(BASE_URI + "/tasks/taskId")))
.andExpect(jsonPath("links[1].rel", is("up")))
.andExpect(jsonPath("links[1].href", is(BASE_URI + "/tasks")));
}
Note how links are presented here differently depending on which media type you've selected.
Can I use this method on different ports? Its working on port :8080 and i can download file but on :4200 i see only logs and nothing more.
Method:
#GetMapping("/downloadJson")
public ResponseEntity<byte[]> downloadJsonFile() {
List<Wine> wines = wineService.findAllWines();
String wineJsonString = jsonExporter.export(wines);
byte[] wineJsonBytes = wineJsonString.getBytes();
return ResponseEntity
.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=wines.json")
.contentType(MediaType.APPLICATION_JSON)
.body(wineJsonBytes);
}
HTML:
<a class="nav-link" (click)="downloadFile()">Download<span class="sr-only">(current)</span></a>
Service:
public downloadJsonFile(): Observable<any> {
return this.http.get<any>(`${this.apiServerUrl}/wine/downloadJson`)
}
Component:
public downloadFile() {
this.wineService.downloadJsonFile().subscribe();
}
I had to change download method in component.ts:
public downloadFile(): void {
this.wineService
.download()
.subscribe(blob => saveAs(blob, 'wine.json'));
}
Service:
public download(): Observable<Blob> {
return this.http.get(`${environment.apiBaseUrl}/wine/downloadJson`, {
responseType: 'blob'
});
}
To use 'saveAs' in component i had to download new package:
npm install --save file-saver
and import in app.component.ts
import { saveAs } from 'file-saver';
I'm trying to use nvd3d candlestick chart with Angular, but I'm not getting to render it when using a rest service built in Java.
How to consume a java rest to render nv3d candlestick chart with Angular?
My rest is returning this:
[{"id":450,"vwap":3821.62,"faixa":69.48,"open":3858.7,"high":3863.29,"low":3793.81,"close":3795.54,"date":19338}]
The component expected this:
[{values:[{"id":450,"vwap":3821.62,"faixa":69.48,"open":3858.7,"high":3863.29,"low":3793.81,"close":3795.54,"date":19338}]}]
My Angular code:
import { Injectable } from '#angular/core';
import { Provider, SkipSelf, Optional, InjectionToken } from '#angular/core';
import { Response, Http } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import { HttpInterceptorService, RESTService } from '#covalent/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/do';
export interface IDolFutDiario {
id: number;
date: number;
open: number;
high: number;
low: number;
close: number;
vwap: number;
faixa: number;
}
#Injectable()
export class DolfudiarioService extends RESTService<IDolFutDiario>{
constructor(private _http: HttpInterceptorService) {
super(_http, {
baseUrl: 'http://localhost:8080',
path: '',
});
}
staticQuery(): Observable<IDolFutDiario[]> {
return this.http.get('http://localhost:8080/dolfutdiarios')
.map(this.extractData)
.catch(this.handleErrorObservable);
}
extractData(res: Response) {
let body = res.json();
return body;
}
private handleErrorObservable (error: Response | any) {
console.error(error.message || error);
return Observable.throw(error.message || error);
}
}
My Java code:
#RestController
public class DolFutRestController {
#Autowired
DolFutDiarioService dolFutDiarioService;
#RequestMapping(value = "dolfutdiarios", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<DolFutDiario>> list() {
List<DolFutDiario> dolfutdiarios = dolFutDiarioService.listDolFutDiarios();
return ResponseEntity.ok().body(dolfutdiarios);
}
}
PS: When I put the second block of data [[values: ..... , it works.
However when I get from Java Service it does not.
No errors returned as well.
Well, you need to convert the block of data you get to the one you want. It's not going to work if you use the wrong format. The crux of the matter is in this method:
extractData(res: Response) {
let body = res.json();
return body;
}
There you can map your data to what you need; for example, if you want to wrap it in a values object, do it like so:
extractData(res: Response) {
const body = res.json();
return [{ values: body }];
}
Also, try console.log'ing your code in different steps to see what you have and compare to what you need!
I have a JSON REST endpoint response and I wanted to get the value of hotelNbr from it. How do i do it ?
{
"found": [
{
"hotelNbr": 554050442,
"hotelAddress": "119 Maven Lane, New Jersey",
}
],
"errors": []
}
I am using the below code to get it but it fails in below mentioned line:
public List<Hotel> RDS_POST_HotelDetails(String HotelName, String sUrl) throws Exception, IOException {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
// Create your http client
CloseableHttpClient httpclient = HttpClientBuilder.create().build();
// Create http Put object
HttpPost ohttppost = new HttpPost(sUrl);
// Message Body
StringEntity input = new StringEntity(
"{\"hotelNbr\":[\""+HotelName+"\" ]}"
);
// Set content type for post
input.setContentType("application/json");
// attach message body to request
ohttppost.setEntity(input);
// submit request and save response
HttpResponse response = httpclient.execute(ohttppost);
// Get response body (entity and parse to string
String sEntity = EntityUtils.toString(response.getEntity());
List<Hotel> hotelobject = new ArrayList<Hotel>();
// Create a type token representing the type of objects in your json response
// I had to use the full class path of TYPE because we also have a Type class in our project
java.lang.reflect.Type cType = new TypeToken<List<Hotel>>() {
}.getType();
// Convert to Array object using gson.fromJson(<json string>,
// <type>)
hotelObject = gson.fromJson(sEntity, cType); // I am getting error here
String hotelNumber = hotelObject.get(0).getFound().get(0).getItemNbr().toString();
}
Please find the Hotel.java class below
package com.hotels.company;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Hotel {
#SerializedName("found")
#Expose
private List<Found> found = null;
#SerializedName("errors")
#Expose
private List<Object> errors = null;
public List<Found> getFound() {
return found;
}
public void setFound(List<Found> found) {
this.found = found;
}
public List<Object> getErrors() {
return errors;
}
public void setErrors(List<Object> errors) {
this.errors = errors;
}
}
Please find Found.java class below :
package com.hotels.company;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Found {
#SerializedName("hotelNbr")
#Expose
private Integer hotelNbr;
#SerializedName("hotelAddress")
#Expose
private String hotelAddress;
public Integer getHotelNbr() {
return hotelNbr;
}
public void setHotelNbr(Integer hotelNbr) {
this.hotelNbr = hotelNbr;
}
public String getHotelAddress() {
return hotelAddress;
}
public void setHotelAddress(String hotelAddress) {
this.hotelAddress = hotelAddress;
}
}
I tried finding some examples in StackOverflow questions but didn't get solution for mine. Any help will be appreciated.
The JSON you are parsing is not well formatted..
There is a comma after "hotelAddress" remove that
Correct JSON would be:
{
"found":[
{
"hotelNbr":554050442,
"hotelAddress":"119 Maven Lane, New Jersey"
}
],
"errors":[ ]
}
I found a couple of issues:
Json is not valid. Observe there is a comma at the end of "hotelAddress": "119 Maven Lane, New Jersey",. Remove it.
You are trying to deserialize the json into List<Hotel>, but the json mentioned is not a list. Either update the json or deserialise it into Hotel object instead of List.