springboot InputStream - spring-boot

I have a controller
void upload(#RequestParam(value="file", MultiPartFile file, #RequestParam(value = "content", required = false) InputStream stream){}
I never get a handle to InputStream when user uploads a file through Stream.
How do i configure that?
The normal file upload works just fine.
I am sending Bzip2 content to upload and multipart default enabled in springboot.
I do get this error.
Caused by: java.lang.IllegalArgumentException: Could not retrieve
InputStream for class path resource [BZh91AY&SY90WT�A�%L
!���!��9D�����ܑN�$�L��]:
at
org.springframework.beans.propertyeditors.InputStreamEditor.setAsText(InputStreamEditor.java:77)
at
org.springframework.beans.TypeConverterDelegate.doConvertTextValue(TypeConverterDelegate.java:449)
at
org.springframework.beans.TypeConverterDelegate.doConvertValue(TypeConverterDelegate.java:422)
at
org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:195)
at
org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:107)
at
org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java:64)

Controller
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.flasher.service.ImageService;
#RestController
public class ImageControllerRest {
#Autowired
ImageService imageService;
#PostMapping("/upload_img")
public ResponseEntity<?> uploadImage(#RequestParam("file") MultipartFile file, Authentication authentication) {
try {
imageService.store(file, authentication.getName());
return new ResponseEntity<>(HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
Service
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.flasher.util.UUIDGenerator;
#Service
public class ImageService {
#Value("${flasher.absolute.img.path}")
String imageUploadPath;
#Autowired
UUIDGenerator uuidGenerator;
public void store(MultipartFile file, String username) {
try {
File uploadFolder = new File(imageUploadPath+username);
if (!uploadFolder.exists()) {
uploadFolder.mkdirs();
}
Files.copy(file.getInputStream(),
Paths.get(uploadFolder.getAbsolutePath()).resolve(uuidGenerator.generateUUID()+"."+file.getContentType().split("/")[1]));
} catch (IOException e) {
e.printStackTrace();
}
}
}
You can achive file upload by this way

Related

Spring-Boot OpenAPI - #RestControllerAdvice not limited to methods throwing the Exception

I need to document my SpringBoot APIs and their possible exceptions with OpenAPI,
and I am using SpringDoc-OpenAPI https://springdoc.org/.
To handle the NotFound cases I created this exception class:
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
public class NotFoundException extends ResponseStatusException {
public NotFoundException() {
super(HttpStatus.NOT_FOUND);
}
}
and this #RestControllerAdvice
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
#RestControllerAdvice
public class GlobalControllerExceptionHandler {
#ExceptionHandler(NotFoundException.class)
#ResponseStatus(HttpStatus.NOT_FOUND)
public ResponseEntity<String> handleNotFoundException(RuntimeException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
}
}
The problem I am facing is that the generated OpenAPI yaml file has
responses:
"404":
description: Not Found
content:
'*/*':
schema:
type: string
for all #RestController endpoints, instead of only for the methods with throws NotFoundException.
How can I limit the #ControllerAdvice (or the OpenAPI), to generate the 404 Response documentation only for methods with the throwing signature?
Do I need to use something else other than the #RestControllerAdvice?
I would like to avoid having to annotate every single method.
A possible solution is to:
Make the #RestControllerAdvice #Hidden
Provide an OperationCustomizer #Bean
import io.swagger.v3.oas.annotations.Hidden;
import it.eng.cysec.ot.risk.assessment.api.exceptions.NotFoundException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
#Hidden
#RestControllerAdvice
public class GlobalControllerExceptionHandler {
#ExceptionHandler(NotFoundException.class)
#ResponseStatus(HttpStatus.NOT_FOUND)
public ResponseEntity<String> handleNotFoundException(NotFoundException exception) {
return new ResponseEntity<>(exception.getMessage(), HttpStatus.NOT_FOUND);
}
}
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.media.Content;
import io.swagger.v3.oas.models.media.MediaType;
import io.swagger.v3.oas.models.media.StringSchema;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses;
import it.eng.cysec.ot.risk.assessment.api.exceptions.NotFoundException;
import org.springdoc.core.customizers.OperationCustomizer;
import org.springframework.web.method.HandlerMethod;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
public class OperationResponseCustomizer implements OperationCustomizer {
public static final ApiResponse NOT_FOUND_API_RESPONSE;
static {
MediaType mediaType = new MediaType();
mediaType.setSchema(new StringSchema());
Content content = new Content();
content.addMediaType("*/*", mediaType);
NOT_FOUND_API_RESPONSE = new ApiResponse()
.description("Not Found")
.content(content);
}
/**
* Customize operation.
*
* #param operation input operation
* #param handlerMethod original handler method
* #return customized operation
*/
#Override
public Operation customize(Operation operation, HandlerMethod handlerMethod) {
Method method = handlerMethod.getMethod();
List<Class<?>> exceptions = Arrays.asList(method.getExceptionTypes());
if(exceptions.contains(NotFoundException.class)){
ApiResponses apiResponses = operation.getResponses();
apiResponses.addApiResponse("404", NOT_FOUND_API_RESPONSE);
}
return operation;
}
}

Implementing JUnit test cases in Spring batch Jobs calling from Controller

I am new to Junit. I am literally struggling to write Junit test cases for my code. I am working with Spring boot, Batch and JPA. I configured Jobs,file read and write in to DB everything working fine. But when it comes to JUnit, I don't even get an idea to write code. Can anyone help me. Below is my code
FileProcessController.java
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameter;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.sc.batchservice.model.StatusResponse;
import lombok.extern.slf4j.Slf4j;
#Slf4j
#RestController
#RequestMapping("/fileProcess")
public class FileProcessController {
#Autowired
private JobLauncher jobLauncher;
#Autowired
#Qualifier("euronetFileParseJob")
private Job job;
#GetMapping(path = "/process")
public #ResponseBody StatusResponse process() throws Exception {
try {
Map<String, JobParameter> parameters = new HashMap<>();
parameters.put("date", new JobParameter(new Date()));
jobLauncher.run(job, new JobParameters(parameters));
return new StatusResponse(true);
} catch (Exception e) {
log.error("Exception", e);
Throwable rootException = ExceptionUtils.getRootCause(e);
String errMessage = rootException.getMessage();
log.info("Root cause is instance of JobInstanceAlreadyCompleteException --> "+(rootException instanceof JobInstanceAlreadyCompleteException));
if(rootException instanceof JobInstanceAlreadyCompleteException){
log.info(errMessage);
return new StatusResponse(false, "This job has been completed already!");
} else{
throw e;
}
}
}
}
BatchConfig.java
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import com.sc.batchservice.model.DetailsDTO;
#Configuration
#EnableBatchProcessing
public class BatchConfig {
private JobBuilderFactory jobBuilderFactory;
#Autowired
public void setJobBuilderFactory(JobBuilderFactory jobBuilderFactory) {
this.jobBuilderFactory = jobBuilderFactory;
}
#Autowired
StepBuilderFactory stepBuilderFactory;
#Value("file:${input.files.location}${input.file.pattern}")
private Resource[] fileInputs;
#Value("${euronet.file.column.names}")
private String filecolumnNames;
#Value("${euronet.file.column.lengths}")
private String fileColumnLengths;
#Value("${input.files.location}")
private String inputFileLocation;
#Value("${input.file.pattern}")
private String inputFilePattern;
#Autowired
FlatFileWriter flatFileWriter;
#Bean
public Job euronetFileParseJob() {
return jobBuilderFactory.get("euronetFileParseJob")
.incrementer(new RunIdIncrementer())
.start(fileStep())
.build();
}
public Step fileStep() {
return stepBuilderFactory.get("fileStep")
.<DetailsDTO, DetailsDTO>chunk(10)
.reader(new FlatFileReader(fileInputs, filecolumnNames, fileColumnLengths))
.writer(flatFileWriter)
.build();
}
}
FlatFileReader.java
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.MultiResourceItemReader;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.FixedLengthTokenizer;
import org.springframework.core.io.Resource;
import com.sc.batchservice.model.DetailsDTO;
import com.sc.batchservice.util.CommonUtil;
import lombok.extern.slf4j.Slf4j;
#Slf4j
public class FlatFileReader extends MultiResourceItemReader<DetailsDTO> {
public EuronetFlatFileReader(Resource[] fileInputs, String filecolumnNames, String fileColumnLengths) {
setResources(fileInputs);
setDelegate(reader(filecolumnNames, fileColumnLengths));
setStrict(true);
}
private FlatFileItemReader<DetailsDTO> reader(String filecolumnNames, String fileColumnLengths) {
FlatFileItemReader<DetailsDTO> flatFileItemReader = new FlatFileItemReader<>();
FixedLengthTokenizer tokenizer = CommonUtil.fixedLengthTokenizer(filecolumnNames, fileColumnLengths);
FieldSetMapper<DetailsDTO> mapper = createMapper();
DefaultLineMapper<DetailsDTO> lineMapper = new DefaultLineMapper<>();
lineMapper.setLineTokenizer(tokenizer);
lineMapper.setFieldSetMapper(mapper);
flatFileItemReader.setLineMapper(lineMapper);
return flatFileItemReader;
}
/*
* Mapping column data to DTO
*/
private FieldSetMapper<DetailsDTO> createMapper() {
BeanWrapperFieldSetMapper<DetailsDTO> mapper = new BeanWrapperFieldSetMapper<>();
try {
mapper.setTargetType(DetailsDTO.class);
} catch(Exception e) {
log.error("Exception in mapping column data to dto ", e);
}
return mapper;
}
}
I have Writer,Entity and model classes also, But if any example or idea upto this code, I can proceed with those classes.

Spring Cloud Stream Processor Unit Testing - #Autowire not working

I am trying to write a spring cloud stream processor class that takes an XML in through using the #StreamListener(Processor.INPUT) annotation.
The processor then extracts smaller XML messages and sends them to the output via this.processor.output().send(message);
I have not yet deployed this to dataflow because I wanted to test it with junit. When I run this with junit I can not seem to get my Processor object to instantiate.
I have tried using #Autowired which is how I have seen it done in may examples but I can't seem to get it to work. Any ideas would be appreciated.
My code is below.
package io.spring.dataflow.sample.usagecostprocessor;
import java.io.File;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Processor;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import lombok.AllArgsConstructor;
#AllArgsConstructor
#EnableBinding(Processor.class)
public class REDACTXMLSplitter {
private Processor processor;
//#Autowired
//private SendingBean sendingBean;
#SuppressWarnings("unchecked")
#StreamListener(Processor.INPUT)
public void parseForREDACTApplications(String redactXML) {
InputSource doc = new InputSource( new StringReader( redactXML ) );
try
{
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true); // never forget this!
XPathFactory xfactory = XPathFactory.newInstance();
XPath xpath = xfactory.newXPath();
String xpathQuery = "//REDACT/Application";
xpath = xfactory.newXPath();
XPathExpression query = xpath.compile(xpathQuery);
NodeList productNodesFiltered = (NodeList) query.evaluate(doc, XPathConstants.NODESET);
for (int i=0; i<productNodesFiltered.getLength(); ++i)
{
Document suppXml = dBuilder.newDocument();
//we have to recreate the root node <products>
Element root = suppXml.createElement("REDACT");
Node productNode = productNodesFiltered.item(i);
//we append a product (cloned) to the new file
Node clonedNode = productNode.cloneNode(true);
suppXml.adoptNode(clonedNode); //We adopt the orphan :)
root.appendChild(clonedNode);
suppXml.appendChild(root);
//write out files
//At the end, we save the file XML on disk
// TransformerFactory transformerFactory = TransformerFactory.newInstance();
// Transformer transformer = transformerFactory.newTransformer();
// transformer.setOutputProperty(OutputKeys.INDENT, "yes");
// DOMSource source = new DOMSource(suppXml);
// StreamResult result = new StreamResult(new File("test_" + i + ".xml"));
// transformer.transform(source, result);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(suppXml), new StreamResult(writer));
String output = writer.getBuffer().toString().replaceAll("\n|\r", "");
System.out.println(output);
Message<String> message = (Message<String>) suppXml;
this.processor.output().send(message);
}
}
catch (XPathExpressionException | ParserConfigurationException | TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package io.spring.dataflow.sample.usagecostprocessor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class REDACTXMLSplitterApplication {
public static void main(String[] args) {
SpringApplication.run(REDACTXMLSplitterApplication.class, args);
}
}
package io.spring.dataflow.sample.usagecostprocessor;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.stream.messaging.Processor;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.util.ResourceUtils;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#DirtiesContext
public class MAIPXMLSplitterApplicationTests {
#Autowired
private Processor myProcessor;
#Test
public void contextLoads() {
}
#Test
public void parseXML() {
try {
String cmErrorPayloadXML = readFile(ResourceUtils.getFile(this.getClass().getResource("/XMLSamples/REDACTApplicationXMLSamples/redact.xml")));
REDACTXMLSplitter redactXMLSplitter = new REDACTXMLSplitter(myProcessor);
redactXMLSplitter.parseForREDACTApplications(cmErrorPayloadXML);
} catch (IOException e) {
e.printStackTrace();
}
}
public String readFile(File file) {
StringBuffer stringBuffer = new StringBuffer();
if (file.exists())
try {
//read data from file
FileInputStream fileInputStream = new FileInputStream(file);
int c;
while ((c = fileInputStream.read()) != -1){
stringBuffer.append((char) c);
}
} catch (IOException e) {
e.printStackTrace();
}
return stringBuffer.toString();
}
}
Update,
I tried this but myProcessor is still null
package io.spring.dataflow.sample.usagecostprocessor;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Processor;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.ResourceUtils;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
#RunWith(SpringRunner.class)
#SpringBootTest(classes = MAIPXMLSplitterApplicationTests.TestProcessor.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MAIPXMLSplitterApplicationTests {
#Autowired
private Processor myProcessor;
#Test
public void contextLoads() {
}
#Test
public void parseXML() {
try {
String cmErrorPayloadXML = readFile(ResourceUtils.getFile(this.getClass().getResource("/XMLSamples/MAIPApplicationXMLSamples/354_20191126_MAIP.xml")));
MAIPXMLSplitter maipXMLSplitter = new MAIPXMLSplitter(myProcessor);
maipXMLSplitter.parseForMAIPApplications(cmErrorPayloadXML);
} catch (IOException e) {
e.printStackTrace();
}
}
public String readFile(File file) {
StringBuffer stringBuffer = new StringBuffer();
if (file.exists())
try {
//read data from file
FileInputStream fileInputStream = new FileInputStream(file);
int c;
while ((c = fileInputStream.read()) != -1){
stringBuffer.append((char) c);
}
} catch (IOException e) {
e.printStackTrace();
}
return stringBuffer.toString();
}
#EnableBinding(Processor.class)
#EnableAutoConfiguration
public static class TestProcessor {
}
}
You need to have #EnableBinding(Processor.class) in one of the configuration classes used by the Test class.
Typically, you can have a simple #Configuration subclass and have it part of the #SpringBootTest classes list. You can see an example here

Spring Web Flux Websocket push after data received the existing resource

package org.springframework.webflux.websocket.webfluxwebsocketdemo;
import java.net.URISyntaxException;
import java.time.Duration;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter;
import reactor.core.publisher.Flux;
#SpringBootApplication
#RestController
public class WebFluxWebSocketDemoApplication {
public static void main(String[] args) {
SpringApplication.run(WebFluxWebSocketDemoApplication.class, args);
}
#GetMapping(path = "/pushData")
public void getRemoteStreaming( #RequestParam("message") String message ) throws URISyntaxException {
}
#Bean
public HandlerMapping webSocketMapping() {
Map<String, WebSocketHandler> map = new HashMap<>();
map.put("/echo", session -> session.send(
Flux.<String>generate(sink -> sink.next(String.format("{ message: 'got local message', date: '%s' }", new Date())))
.delayElements(Duration.ofSeconds(1)).map(session::textMessage)));
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setUrlMap(map);
mapping.setOrder(1);
return mapping;
}
#Bean
public WebSocketHandlerAdapter handlerAdapter() {
return new WebSocketHandlerAdapter();
}
}
Above code will send the message every second to websocket client
"{ message: 'got local message', date: 'Tue Oct 02 11:34:17 IST 2018' }"
But how do we send the message whenever i received the data from "pushData" resource, then i have to pass it to websocket client.

How and where to add new bean in Sping application generated by Jhipster

I generated my Spring application using Jhipster. Now I want to add controller for FilesUpload, and StorageService for it. But when I run my application it gets me this message
Description:Parameter 0 of constructor in com.kongresspring.myapp.web.rest.FileUploadResource required a bean of type 'com.kongresspring.myapp.service.StorageService' that could not be found.
Action:Consider defining a bean of type 'com.kongresspring.myapp.service.StorageService' in your configuration.
I can't find beans.xml to add new bean. I'm new in spring, so maybe there's some other way to configure bean, I'm not familiar whit. Here's my code for uploading file controller:
package com.kongresspring.myapp.web.rest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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.RestController;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.kongresspring.myapp.service.StorageService;
#RestController
#RequestMapping("/api")
public class FileUploadResource {
private final Logger log = LoggerFactory.getLogger(FileUploadResource.class);
private final StorageService storageService;
#Autowired
public FileUploadResource(StorageService storageService) {
this.storageService = storageService;
}
/**
* POST uploadFile
*/
#PostMapping("/upload-file")
public String uploadFile(#RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) {
storageService.store(file);
redirectAttributes.addFlashAttribute("message",
"You successfully uploaded " + file.getOriginalFilename() + "!");
return "success";
}
/**
* GET preview
*/
#GetMapping("/preview")
public String preview() {
return "preview";
}
}
And here's my StorageService code:
package com.kongresspring.myapp.service;
import org.springframework.core.io.Resource;
import org.springframework.web.multipart.MultipartFile;
import java.nio.file.Path;
import java.util.stream.Stream;
public interface StorageService {
void init();
void store(MultipartFile file);
Stream<Path> loadAll();
Path load(String filename);
Resource loadAsResource(String filename);
}
You can create an implementation for StorageService, and annotate it as #Service/#Component, spring will automatically discover the bean:
#Service
public class StorageServiceImpl implements StorageService {
void init(){// You code goes here/}
void store(MultipartFile file){///}
Stream<Path> loadAll(){///}
Path load(String filename){//}
Resource loadAsResource(String filename){///}
}

Resources