I have a problem with sharing image between Spring and React. What i do:
I get file from input:
<input type='file' id='upload-button' accept='image/*'
onBlur={() => image.onBlur()}
onChange={e => onChangeHandler(e)}/>
Then my handlerMethod with base64Encoder:
const onChangeImage = async (e: any) => {
const file = e.target.files[0]
const base64 = await convertToBase64(file)
setValue(base64)
}
export const convertToBase64 = (file: any) => {
return new Promise((resolve, reject) => {
const fileReader = new FileReader()
fileReader.readAsDataURL(file)
fileReader.onload = () => {
resolve(fileReader.result)
}
fileReader.onerror = (error) => {
reject(error)
}
})
}
And after that i send this file to method:
DishesService.addDish(dish, image.value)
This method:
export default class DishesService {
static async addDish(dish: IDish, file: any) {
try {
await axios.post<IDish>('http://localhost:8080/dishes', dish)
.then(response => {
this.updateDishImage(response.data.id, file)
})
} catch (e) {
console.log('произошла ошибка при добавлении блюда')
}
}
static async updateDishImage(id: number | undefined, image: any) {
try {
await axios.put('http://localhost:8080/dishes/' + id, {}, {
params: {
file: image
}
})
} catch (e) {
console.log('Произошла ошибка при добавлении картинки к блюду')
}
}
}
And my Spring Boot controller:
#PutMapping(path = "{dishId}")
public ResponseEntity<DishEntity> updateDishImage(#PathVariable Long dishId, #RequestParam("file") String base64File) {
DishEntity updateDish = dishService.updateDishImage(base64File, dishId);
return ResponseEntity.ok(updateDish);
}
Method:
#Override
public DishEntity updateDishImage(String base64File, Long id) {
DishEntity dishById = findById(id);
byte[] byteImage = Base64.decodeBase64(base64File);
dishById.setImage(byteImage);
DishEntity updatedDish;
try {
updatedDish = dishRepository.save(dishById);
} catch (Exception ex) {
throw new OperationFailedException("Update dish image method failed!");
}
return updatedDish;
}
Whan i do my code, I get exception:
Last encoded character (before the paddings if any) is a valid base 64 alphabet but not a possible value. Expected the discarded bits to be zero.
If you faced with this problem, please, help me to fix this error
Related
Currently, I try to send an image file in JPEG format to Angular. However, I'm getting the following error when I send it out through Postman.
class
org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile
cannot be cast to class java.lang.String
(org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile
is in unnamed module of loader 'app'; java.lang.String is in module
java.base of loader 'bootstrap')
The idea is to upload this image into cloudinary repository.
Here my code of the REST API:
#PostMapping("/uploads")
public ResponseEntity<?> upload(MultipartFile imagen) throws Exception {
Map<String, Object> response = new HashMap<>();
File conversion = new File(imagen.getOriginalFilename());
imagen.transferTo(conversion);
Cloudinary cloudinary = new Cloudinary();
cloudinary.uploader().upload("C:\\Users\\Dell\\Pictures\\"+conversion.getName(), ObjectUtils.asMap("public_id", imagen,
"api_key", "xxxxxxxxxxxxxxx", "api_secret", "xxxxxxxxxxxxxxxxxxxxxx", "cloud_name", "xxxxxxx"));
return new ResponseEntity<Map<String, Object>>(HttpStatus.CREATED);
}
Any Suggest will be appreciated
Code in Angular service Layer called paciente.services.ts
#Injectable({
providedIn: 'root'
})
export class PacienteService extends GenericService<Paciente> {
private pacienteCambio: Subject<Paciente[]> = new Subject<Paciente[]>
();
private mensajeCambio: Subject<string> = new Subject<string>();
constructor(protected http: HttpClient) {
super(
http,
`${environment.HOST}/pacientes/uploads`);
}
listarPacientes(){
return this.http.get<any>(`${this.url}`);
}
listarPageable(p: number, s:number){
return this.http.get<any>(`${this.url}/pageable?
page=${p}&size=${s}`);
}
subirImagen(archivo: string){
return this.http.post(`${this.url}/${archivo}`,archivo);
}
obtenerURLImagen(nombreImagen: String){
return this.http.get<Paciente[]>
(`${this.url}/descripcionAssets/${nombreImagen}`);
}
listar(){
return this.http.get<Paciente[]>(this.url);
}
listarPorId(id: number){
return this.http.get<Paciente>(`${this.url}/${id}`);
}
registrar(paciente: Paciente){
return this.http.post(this.url, paciente);
}
modificar(paciente: Paciente){
return this.http.put(this.url, paciente);
}
eliminar(id: number){
return this.http.delete(`${this.url}/${id}`);
}
//////////////////////////
getPacienteCambio(){
return this.pacienteCambio.asObservable();
}
setPacienteCambio(lista: Paciente[]){
this.pacienteCambio.next(lista);
}
getMensajeCambio(){
return this.mensajeCambio.asObservable();
}
setMensajeCambio(msj: string){
this.mensajeCambio.next(msj);
}
}
And this is the component where I setup the REST API subirImagen
export class PacienteEdicionComponent implements OnInit {
id: number = 0;
edicion: boolean = false;
nombreArchivo: File;
form: FormGroup;
public archivos: any = []
public files: NgxFileDropEntry[] = [];
constructor(
private route: ActivatedRoute,
private router: Router,
private pacienteService: PacienteService,
private sanitizer: DomSanitizer
) { }
ngOnInit(): void {
this.form = new FormGroup({
'id': new FormControl(0),
'nombres': new FormControl(''),
'apellidos': new FormControl(''),
'dni': new FormControl(''),
'telefono': new FormControl(''),
'direccion': new FormControl(''),
'fondo-imagen': new FormControl(''),
'email': new FormControl(''),
});
this.route.params.subscribe(data => {
this.id = data['id'];
this.edicion = data['id'] != null;
this.initForm();
});
}
for (const droppedFile of files) {
// Is it a file?
if (droppedFile.fileEntry.isFile) {
const fileEntry = droppedFile.fileEntry as FileSystemFileEntry;
fileEntry.file((file: File) => {
// Here you can access the real file
this.nombreArchivo = file;
**//This is the test i make to find out if image is uploaded**
this.pacienteService.subirImagen(**this.nombreArchivo.name**);
// You could upload it like this:
const formData = new FormData()
formData.append('logo', file)
// Headers
/* const headers = new HttpHeaders({
'security-token': 'mytoken'
})
this.http.post('https://mybackend.com/api/upload/sanitize-and-save-
logo', formData, { headers: headers, responseType: 'blob' })
.subscribe(data => {
// Sanitized logo returned from backend
})
**/
});
} else {
// It was a directory (empty directories are added, otherwise only
files)
const fileEntry = droppedFile.fileEntry as FileSystemDirectoryEntry;
console.log(droppedFile.relativePath, fileEntry);
}
}
}
#PostMapping(value="/uploads", consumes = {
MediaType.MULTIPART_FORM_DATA_VALUE })
public ResponseEntity<?> guardarImagen(#RequestParam("adjunto")
MultipartFile file, Integer id) throws Exception{
Paciente pac = service.listarPorId(id);
//Se valida si existe el id en la base de datos
if(pac == null) {
throw new ModeloNotFoundException("ID NO ENCONTRADO " + id);
}
String fotoUsuario = file.getOriginalFilename();
Cloudinary cloudinary = new Cloudinary();
cloudinary.uploader().upload(file.getBytes(),
ObjectUtils.asMap("public_id", file.getOriginalFilename()));
Map result = cloudinary.api().resource(file.getOriginalFilename(),
ObjectUtils.emptyMap());
service.actualizarFoto(id, fotoUsuario);
return new ResponseEntity<>(result, HttpStatus.OK);
}
How do I get EventSource.onmessage to work?
Here is my subscribe and pushevent code:
public SseEmitter subscribe() throws Exception {
SseEmitter emitter = new SseEmitter(1800000L);
emitters.add(emitter);
emitter.onCompletion(() -> {
synchronized (emitters) {
emitters.remove(emitter);
}
});
emitter.onTimeout(() -> {
emitter.complete();
emitters.remove(emitter);
});
return emitter;
}
#Async
public void pushEventMap(Map<String, Object> pushMap) throws IOException {
List<SseEmitter> deadEmitters = new ArrayList<>();
HashMap<String,Object> map = (HashMap<String,Object>) pushMap;
emitters.forEach(emitter -> {
try {
emitter.send(SseEmitter.event().name("myEvent").data(map));
} catch (Exception e) {
emitter.completeWithError(e);
logger_error.error("pushEvent Exception:" + e);
deadEmitters.add(emitter);
}
});
emitters.removeAll(deadEmitters);
}
The controller for the above service is:
#RequestMapping(value = "/subscribe", produces = "text/event-stream")
public ResponseEntity<SseEmitter> subscribe() throws Exception {
final SseEmitter emitter = eventService.subscribe();
return new ResponseEntity<>(emitter, HttpStatus.OK);
}
#RequestMapping(value = "/publish")
public void publish() throws IOException {
eventService.pushEventMap(pushMap);
}
I want the client to receive the data of event push through js.
const eventInit = () => {
console.log("eventInit called");
const url = 'http://localhost:8080/itf/subscribe';
const eventSource = new EventSource(url);
var httpRequest = new XMLHttpRequest();
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('===');
console.log(data);
}
eventSource.onopen = (event) => {
console.log('sse open');
console.log(event);
}
eventSource.onerror = (event) => {
if (event.readyState == EventSource.CLOSED) {
console.log('sse close');
} else {
console.log("onerror", e);
}
}
}
In this state, if I send event-generating data through postman, sse open appears on the console.
However, the result of the event is not displayed.
If I directly access /itf/subscribe through the url, the result of the event is displayed on the screen. However, I am not receiving the result of the event through event.onmessage.
What I want is to raise an event, and then receive the result of the event through the onmessage function.
I am wondering how can I get the result of the event.
best regards
There is no issue with code, the actual issue is when I am writing response to client my response message should look like as below.
PrintWriter out = response.write("data: message"+value+"\n\n");
out.flush(); //don't forget to flush
In my code I was missing the last part "\n\n" in response object so source.onmessage(datalist) in javascript didn't get hit.
eventSource.addEventListener('myEvent', function (event) {
console.log(event);
const data = JSON.parse(event.data);
console.log('addEventListener');
console.log(data);
// console.log(data.siteCode);
eventEffect(data);
}, false);
this is normally work!
Front: Angular2+
Back: Java15 Spring Boot
DataBase: MySql
I take all examples for upload files in database form in byte[]. with a complex object with file by attribute.
I try desperately to upload an image file on my database so I try to create post API rest by I have error
I'm take
o.s.web.servlet.PageNotFound : Request method 'POST' not supported
#PostMapping(value = "/Ninja/image/")
public ResponseEntity<ResponseMessage> saveNinjaImage(#RequestParam("file") MultipartFile file) {
String message = "";
try {
Iterable<Syndic> lstN= NinjaRepository.findAll();
if(lstN.iterator().hasNext()) {
Ninja s = lstN.iterator().next();
s.setPicture(file.getBytes());
logger.info(s.toString());
}
} catch(Exception e) {
//return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(new ResponseMessage(message));
logger.info(e.toString());
}
return ResponseEntity.status(HttpStatus.OK).body(new ResponseMessage(message));
}
//service
public postNinja(file: File) {
const formData: FormData = new FormData();
formData.append('file', file);
const req = new HttpRequest('POST', `${this.host}/Ninja/image`, formData, {
headers: this.headers,
reportProgress: true,
responseType: 'json'
});
return this.http.request(req);
}
/* ts */
public onSave() {
this.frontDynamic.submitted = true;
if (this.frontDynamic.updateNinja.invalid) {
return;
} else {
const formValue = this.frontDynamic.updateNinja.value;
const newNinja = new Ninja(formValue['nom']);
newNinja.address = formValue['adresse'];
newNinja.description = formValue['description'];
newNinja.website = formValue['site'];
this.ninjaService.putNinja(newNinja,formValue['image']).subscribe(response => {},
error => {console.log(error);}
,
()=>{
this.ninjaService.postNinja(formValue['image']).subscribe(
event => {},
err => {});
);
}
}
I need really your support.
I have a big problem that I don't understand why happens.
I used https-nativescript plugin because I want to communicate with protocol https.
So, Firstly I install this plugin, and write in component.ts this code:
enableSSLpinning() {
let certificate: any;
Https.enableSSLPinning({ host: 'xx.xxx.xx.xx:3333', certificate, allowInvalidCertificates: true, validatesDomainName: false })
Https.request({
url: 'https://xx.xxx.xx.xx:3333/user',
method: 'GET',
headers: {
"Content-type": "application/x-www-form-urlencoded",
},
}).then(function (response) {
console.log('Https.request response', response);
}).catch(function (error) {
console.error('Https.request error', error);
})
}
in https.android.js I modify only certificate in this part:
function enableSSLPinning(options) {
if (!peer.host && !peer.certificate
) {
var certificate = void 0;
var InputSteram = void 0;
try {
var inputStream = new java.io.ByteArrayInputStream(new java.lang.String("-----BEGIN CERTIFICATE-----\n"
+ "MIIFjDCCA3SgAwIBAgIJAMOXpEn+QQSVMA0GCSqGSIb3DQEBCwUAMIGBMQswCQYD\n"
+ "VQQGEwJVUzELMAkGA1UECAwCTUExDzANBgNVBAcMBkJvc3RvbjETMBEGA1UECgwK\n"
..................
+ "1AYJwo2yFqmetdmOYaFh6Cli8OerUERDqPB1UKPmYQE=\n"
+ "-----END CERTIFICATE-----").getBytes("UTF-8"));
var x509Certificate = java.security.cert.CertificateFactory.getInstance('X.509').generateCertificate(inputStream);
peer.x509Certificate = x509Certificate;
certificate = okhttp3.CertificatePinner.pin(x509Certificate);
inputStream.close();
}
catch (error) {
try {
if (inputStream) {
console.log('inputStream', inputStream)
inputStream.close();
}
}
catch (e) { }
console.error('nativescript-https > enableSSLPinning error', error);
return;
}
peer.host = options.host;
peer.certificate = certificate;
if (options.allowInvalidCertificates == true) {
peer.allowInvalidCertificates = true;
}
if (options.validatesDomainName == false) {
peer.validatesDomainName = false;
}
}
peer.enabled = true;
getClient(true);
console.log('nativescript-https > Enabled SSL pinning');
}
This parts execute correct, in console print 'nativescript-https > Enabled SSL pinning'
Error show in this part: console.error('Https.request error', error);
JS: Https.request error javax.net.ssl.SSLHandshakeException:
java.security.cert.CertPathValidatorException: Trust anchor for
certification path not found.
And in https.android.js call this function
function request(opts) {
console.log('opts', opts)
return new Promise(function (resolve, reject) {
try {
var client = getClient();
var request_1 = new okhttp3.Request.Builder();
request_1.url(opts.url);
var reqheads_1 = opts.headers;
Object.keys(reqheads_1).forEach(function (key) {
request_1.addHeader(key, reqheads_1[key]);
});
if (opts.method == 'GET') {
request_1.get();
}
else if (opts.method == 'POST') {
var type = okhttp3.MediaType.parse('application/json');
var body = okhttp3.RequestBody.create(type, opts.content);
request_1.post(body);
}
client.newCall(request_1.build()).enqueue(new okhttp3.Callback({
onResponse: function (task, response) {
var content;
try {
content = JSON.parse(response.body().string());
}
catch (error) {
return reject(error);
}
var statusCode = response.code();
var headers = {};
var heads = response.headers();
var i, len = heads.size();
for (i = 0; i < len; i++) {
var key = heads.name(i);
var value = heads.value(i);
headers[key] = value;
}
resolve({ content: content, statusCode: statusCode, headers: headers });
},
onFailure: function (task, error) {
reject(error);
},
}));
}
catch (error) {
reject(error);
}
});
}
Please, can you ask me any idea, which is the problem in my code? Thank you
Thanks!
Update:
I think that a problem is in this part of code:
onResponse: function (task, response) {
console.load('testfdsfsdfsdfsd')
var content;
console.log('content', content)
try {
content = JSON.parse(response.body().string());
console.log('content1', content)
}
catch (error) {
console.log('error111111', error)
return reject(error);
}
var statusCode = response.code();
var headers = {};
var heads = response.headers();
var i, len = heads.size();
for (i = 0; i < len; i++) {
var key = heads.name(i);
var value = heads.value(i);
headers[key] = value;
}
resolve({ content: content, statusCode: statusCode, headers: headers });
},
because this part is not executed, it passes directly to onFailure
onFailure: function (task, error) {
reject(error);
},
This is web code:
DecoupledEditor
.create( document.querySelector( '#webDetails' ),{
language: 'zh-cn',
image: {
toolbar: [ 'imageTextAlternative' ],
styles: [ 'full', 'side' ]
},
ckfinder: {
uploadUrl: '<%=WEBPATH%>/platform/updateMaterial'
}
} )
.then( editor => {
const toolbarContainer = document.querySelector( '#toolbar-webDetails' );
toolbarContainer.appendChild( editor.ui.view.toolbar.element );
} )
This is Spring controller:
#PostMapping("updateMaterial")
#ResponseBody
public String updateMaterial(#RequestParam("upload") MultipartFile file, HttpServletRequest request){
String trueFileName = null;
String realPath = null;
try {
realPath = request.getSession().getServletContext().getRealPath("/upload");
System.out.println(realPath);
trueFileName = uploadImg(realPath, file);
} catch (IllegalStateException | IOException e) {
e.printStackTrace();
}
return "{\"default\":\"" + realPath + File.separator + trueFileName + "\"}";
}
Here I return the address of the image on disk.
It is json String style. I want CKEditor 5 api to return the information, but still failure.
What do I need to return in the background to succeed, or am I missing the step?
thank you.
There are many people asking this question, but none of them have a clear solution. Finally, I found it. My code is as follows.
class UploadAdapter {
constructor(loader) {
this.loader = loader;
}
upload() {
return new Promise((resolve, reject) => {
const data = new FormData();
data.append('upload', this.loader.file);
data.append('allowSize', 10);//允许图片上传的大小/兆
$.ajax({
url: 'loadImage',
type: 'POST',
data: data,
dataType: 'json',
processData: false,
contentType: false,
success: function (data) {
if (data.res) {
resolve({
default: data.url
});
} else {
reject(data.msg);
}
}
});
});
}
abort() {
}
}
DecoupledEditor
.create( document.querySelector( '#b' ), {
language:"zh-cn"
})
.then( editor => {
const toolbarContainer = document.querySelector( '#a' );
toolbarContainer.appendChild( editor.ui.view.toolbar.element );
// This place loads the adapter.
editor.plugins.get('FileRepository').createUploadAdapter = (loader)=>{
return new UploadAdapter(loader);
};
} )
.catch( error => {
console.error( error );
} );