AI Reading
Quick summary of this article
This guide explains how to build a Spring Boot CRUD REST API that connects to a MySQL database and supports image uploads. The tutorial covers setting up the development environment in VS Code, creating the project structure with layers like Entity, DTO, Repository, Service, and Controller, and implementing the full control flow from HTTP requests to database operations.
- Use VS Code with Java 17+, Maven, MySQL, and extensions like Java Extension Pack, Spring Boot Extension Pack, and Thunder Client for testing.
- The application.properties file configures MySQL connection, username, password, and enables automatic table updates with Hibernate.
- The User entity stores id, name, email, and imageUrl fields, while the UserDTO uses MultipartFile to handle image uploads separately from data.
- The Service layer saves images to an "uploads/" folder with a unique filename and stores the filename in the database.
- The Controller provides POST, GET, PUT, and DELETE endpoints under "/api/users" for full CRUD operations.
Creating a Spring Boot CRUD REST API with MySQL and Image Upload – Step-by-Step Guide
In today’s full-stack development, building a robust backend API is essential for powering dynamic web or mobile applications. In this tutorial, we’ll walk you through creating a Spring Boot CRUD REST API using MySQL as the database and also handling image upload. Whether you’re building a user management system or an admin dashboard, CRUD operations (Create, Read, Update, Delete) form the backbone of your app.
✅ VS Code Setup
- Install Java 17+
- Install Maven
- Install MySQL Server
- Install VS Code with these extensions:
- Java Extension Pack
- Spring Boot Extension Pack
- Maven for Java
- Thunder Client (for API testing)
- Lombok Support
⚙️ Create Project Using Spring Initializr in VS Code
Open VS Code → Use Spring Initializr Extension → Choose:
- Project Type: Maven
- Language: Java
- Spring Boot: 3.x
- Dependencies: Spring Web, Spring Data JPA, MySQL Driver, Lombok
📁 Project Structure
src/
├── config/
│ └── SecurityConfig.java
├── controller/
│ └── UserController.java
├── dto/
│ └── UserDTO.java
├── entity/
│ └── User.java
├── repository/
│ └── UserRepository.java
├── service/
│ └── UserService.java
└── SpringAngularCrudApplication.java
🔁 Control Flow
Here’s how the control flows through the app:
- Client (Angular or Postman) sends HTTP requests
- Controller receives request, maps DTOs, calls Service
- Service handles business logic and file saving
- Repository handles DB interaction via JPA
- Entity represents DB table
- DTO ensures safe and efficient data transfer
💾 application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=yourpassword
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
📦 Entity – User.java
@Entity
@Data
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
private String imageUrl;
}
🧾 DTO – UserDTO.java
@Data
public class UserDTO {
private Long id;
private String name;
private String email;
private MultipartFile image;
}
📁 Repository – UserRepository.java
public interface UserRepository extends JpaRepository<User, Long> {}
🔧 Service – UserService.java
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public User saveUser(UserDTO dto) throws IOException {
User user = new User();
user.setName(dto.getName());
user.setEmail(dto.getEmail());
if (dto.getImage() != null) {
String fileName = UUID.randomUUID() + "_" + dto.getImage().getOriginalFilename();
Path path = Paths.get("uploads/" + fileName);
Files.copy(dto.getImage().getInputStream(), path);
user.setImageUrl(fileName);
}
return userRepository.save(user);
}
public List<User> getAllUsers() {
return userRepository.findAll();
}
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
public User updateUser(Long id, UserDTO dto) throws IOException {
User user = userRepository.findById(id).orElseThrow();
user.setName(dto.getName());
user.setEmail(dto.getEmail());
if (dto.getImage() != null) {
String fileName = UUID.randomUUID() + "_" + dto.getImage().getOriginalFilename();
Path path = Paths.get("uploads/" + fileName);
Files.copy(dto.getImage().getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);
user.setImageUrl(fileName);
}
return userRepository.save(user);
}
}
🌐 Controller – UserController.java
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public ResponseEntity<User> createUser(@ModelAttribute UserDTO dto) throws IOException {
return ResponseEntity.ok(userService.saveUser(dto));
}
@GetMapping
public List<User> getAll() {
return userService.getAllUsers();
}
@PutMapping("/{id}")
public ResponseEntity<User> update(@PathVariable Long id, @ModelAttribute UserDTO dto) throws IOException {
return ResponseEntity.ok(userService.updateUser(id, dto));
}
@DeleteMapping("/{id}")
public void delete(@PathVariable Long id) {
userService.deleteUser(id);
}
}
🗂️ Static File Setup
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/uploads/**")
.addResourceLocations("file:uploads/");
}
}
✅ Summary
You’ve now built a complete Spring Boot backend with:
- REST APIs for user management (CRUD)
- MySQL as the persistent store
- Image uploading via
MultipartFile - Clean project structure with DTO, Entity, Repository, Service, and Controller layers
- VS Code as your lightweight, full-featured development environment
