I am new to Spring Boot and I'm getting the following error when writing a file upload API:
Error:Description:
Field fileStorageService in com.primesolutions.fileupload.controller.FileController required a bean of type 'com.primesolutions.fileupload.service.FileStorageService' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.primesolutions.fileupload.service.FileStorageService' in your configuration.*
Controller class:
public class FileController
{
private static final Logger logger = LoggerFactory.getLogger(FileController.class);
@Autowired
private FileStorageService fileStorageService;
@PostMapping("/uploadFile")
public UploadFileResponse uploadFile(@RequestParam("file") MultipartFile file) {
String fileName = fileStorageService.storeFile(file);
String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
.path("/downloadFile/")
.path(fileName)
.toUriString();
return new UploadFileResponse(fileName, fileDownloadUri,
file.getContentType(), file.getSize());
}
@PostMapping("/uploadMultipleFiles")
public List<UploadFileResponse> uploadMultipleFiles(@RequestParam("files") MultipartFile[] files) {
return Arrays.asList(files)
.stream()
.map(file -> uploadFile(file))
.collect(Collectors.toList());
}
}
Service class:
private final Path fileStorageLocation;
@Autowired
public FileStorageService(FileStorageProperties fileStorageProperties) {
this.fileStorageLocation = Paths.get(fileStorageProperties.getUploadDir())
.toAbsolutePath().normalize();
try {
Files.createDirectories(this.fileStorageLocation);
} catch (Exception ex) {
throw new FileStorageException("Could not create the directory where the uploaded files will be stored.", ex);
}
}
public String storeFile(MultipartFile file) {
// Normalize file name
String fileName = StringUtils.cleanPath(file.getOriginalFilename());
try {
// Check if the file's name contains invalid characters
if(fileName.contains("..")) {
throw new FileStorageException("Sorry! Filename contains invalid path sequence " + fileName);
}
// Copy file to the target location (Replacing existing file with the same name)
Path targetLocation = this.fileStorageLocation.resolve(fileName);
Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);
return fileName;
} catch (IOException ex) {
throw new FileStorageException("Could not store file " + fileName + ". Please try again!", ex);
}
}
Configuration class:
@ConfigurationProperties(prefix = "file")
public class FileStorageProperties {
private String uploadDir;
public String getUploadDir()
{
return uploadDir;
}
public void setUploadDir(String uploadDir) {
this.uploadDir = uploadDir;
}
}
Main:
@SpringBootApplication
@EnableConfigurationProperties({
FileStorageProperties.class
})
public class FileApplication {
public static void main(String[] args) {
SpringApplication.run(FileApplication.class, args);
}
}
properties file
## MULTIPART (MultipartProperties)
# Enable multipart uploads
spring.servlet.multipart.enabled=true
# Threshold after which files are written to disk.
spring.servlet.multipart.file-size-threshold=2KB
# Max file size.
spring.servlet.multipart.max-file-size=200MB
# Max Request Size
spring.servlet.multipart.max-request-size=215MB
## File Storage Properties
# All files uploaded through the REST API will be stored in this directory
file.upload-dir=C:/Projects/SpringBootProject/Primesolutions/PrimeSolutions/FileUpload
I'm trying to read the file upload property and pass it to the controller class.
By default, the @Autowired annotation implies that the dependency is required. This means an exception will be thrown when a dependency is not resolved. You can override that default behavior using the (required=false) option with @Autowired .
Spring @Autowired annotation is used for automatic dependency injection. Spring framework is built on dependency injection and we inject the class dependencies through spring bean configuration file.
org.springframework.beans.factory.annotation. Annotation Type Autowired. @Target(value={CONSTRUCTOR,FIELD,METHOD}) @Retention(value=RUNTIME) @Documented public @interface Autowired. Marks a constructor, field, setter method or config method as to be autowired by Spring's dependency injection facilities.
The error seems to indicate that Spring does not know any bean of type com.primesolutions.fileupload.service.FileStorageService
.
As said in the comment, make sure you class FileStorageService
is annotated by @Service
or @Component
:
@Service
public class FileStorageService {
...
}
Make also sure that this class is located in a sub-package of your class FileApplication
. For example, if your FileApplication
class is located in a package com.my.package
, make sure your FileStorageService
is located in the package com.my.package.** (same package or any sub package).
Few notes to improve your code by the way :
When your class has only one not default constructor, the use of @Autowired
on the constructor is optional.
Do not put too much code in your constructor. Use instead the @PostConstruct
annotation.
@Service
public class FileStorageService {
private FileStorageProperties props;
// @Autowired is optional in this case
public FileStorageService (FileStorageProperties fileStorageProperties) {
this.props = fileStorageProperties;
this.fileStorageLocation = Paths.get(fileStorageProperties.getUploadDir())
.toAbsolutePath().normalize();
}
@PostConstruct
public void init() {
try {
Files.createDirectories(this.fileStorageLocation);
} catch (Exception ex) {
throw new FileStorageException("Could not create the directory where the uploaded files will be stored.", ex);
}
}
}
@Autowired
on a field. Use the constructor instead. It is better for your tests, and more maintainable:public class FileController {
private FileStorageService service;
public FileController(FileStorageService service) {
this.service = service;
}
}
I solved this problem using where i use @Autowired annotation just replace with this`
@Autowired(required = false)
`
Tried with removing the (exclude = {DataSourceAutoConfiguration.class }) parameter with @SpringBootApplication:
Before:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
public class SpringBootMain { ...
After:
@SpringBootApplication
public class SpringBootMain { ...
Worked for me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With