post-image

Hướng dẫn upload file trong Spring Boot

Spring Boot Starters & Common Configurations

Nếu mọi người muốn lưu trữ một ảnh vào trong cơ sở dữ liệu mọi người sẽ chọn cách nào? Mã hóa ảnh và lưu vào cơ sở dữ liệu hay là chúng ta sẽ lưu đường dẫn của nó. Mình sẽ chọn cách là lưu đường dẫn của file ảnh vào trong cơ sở dữ liệu và bài viết này mình sẽ hướng dẫn upload file trong Spring Boot. Những kiến thức liên quan đến bài viết như Lombok, Builder Pattern. Ngoài ra các bạn sau khi làm theo bài viết này còn có thể tự viết cho mình một project upload file trong Spring Boot sử dụng API.

Cài đặt thư viện

Mọi người tạo ứng dụng Spring Boot và thêm một số thư viện như sau:

implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-data-jdbc' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' runtimeOnly 'mysql:mysql-connector-java' annotationProcessor 'org.projectlombok:lombok' testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' }
Code language: JavaScript (javascript)

Cấu hình file application.properties

Ở file application.properties chúng ta cấu hình như sau:

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/product_management spring.datasource.username=root spring.datasource.password=123456 spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=none spring.jpa.properties.hibernate.hbm2ddl.auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect upload.path=E:\\image\\ spring.servlet.multipart.max-file-size=5MB spring.servlet.multipart.max-request-size=5MB spring.resources.static-locations=file:///${upload.path}
Code language: JavaScript (javascript)

Trong đó upload.path được cấu hình để lữu trữ ảnh sau khi upload xong. Mọi người có thể thay đổi lại đường dẫn theo ý muốn của mình.

spring.servlet.multipart.max-file-size: kích cỡ file lưu trữ tối đa.

spring.servlet.multipart.max-request-size: kích thước file upload lên server tối đa.

spring.resources.static-locations=file:///${upload.path}: cấu hình đường dẫn file tĩnh đến ảnh của Spring Boot

Hướng dẫn upload file trong SpringBoot

Model

Chúng ta tạo 2 file class lần lượt là Product và ProductFrom sử dụng Builder Pattern trong đó Product sẽ là Entity được tạo trong cơ sở dữ liệu có kiểu dữ liệu của thuộc tính image là String còn ProductForm là một class trung gian để lưu trữ ảnh dưới dạng MultipartFile. 

Product.java

package com.example.demo.model; import lombok.Data; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity @Data public class Product { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String description; private String image; public Product(ProductBuilder productBuilder) { this.name = productBuilder.name; this.description = productBuilder.description; this.image = productBuilder.image; } public Product() { } public static class ProductBuilder { private final String name; private String description; private String image; public ProductBuilder(String name) { this.name = name; } public ProductBuilder description(String description) { this.description = description; return this; } public ProductBuilder image(String image) { this.image = image; return this; } public Product build() { return new Product(this); } } }
Code language: JavaScript (javascript)

ProductForm.java

package com.example.demo.model; import lombok.Data; import org.springframework.web.multipart.MultipartFile; @Data public class ProductForm { private Long id; private String name; private String description; private MultipartFile image; public ProductForm() { } public ProductForm(ProductFormBuilder productFormBuilder) { this.name = productFormBuilder.name; this.description = productFormBuilder.description; this.image = productFormBuilder.image; } public static class ProductFormBuilder { private final String name; private String description; private MultipartFile image; public ProductFormBuilder(String name) { this.name = name; } public ProductFormBuilder description(String description) { this.description = description; return this; } public ProductFormBuilder image(MultipartFile image) { this.image = image; return this; } public ProductForm build() { return new ProductForm(this); } } }
Code language: JavaScript (javascript)

Repository

ProductRepository.java

package com.example.demo.repository; import com.example.demo.model.Product; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; @Repository public interface IProductRepository extends CrudRepository<Product, Long> { }
Code language: CSS (css)

Service

GeneralService.java

package com.example.demo.service; import java.util.Optional; public interface GeneralService<T> { Iterable<T> findAll(); Optional<T> findById(Long id); T save(T t); void remove(Long id); }
Code language: HTML, XML (xml)

IProductService.java

package com.example.demo.service; import com.example.demo.model.Product; public interface IProductService extends GeneralService<Product> { }
Code language: CSS (css)

ProductService.java

package com.example.demo.service; import com.example.demo.model.Product; import com.example.demo.repository.IProductRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Optional; @Service public class ProductService implements IProductService { @Autowired private IProductRepository productRepository; @Override public Iterable<Product> findAll() { return productRepository.findAll(); } @Override public Optional<Product> findById(Long id) { return productRepository.findById(id); } @Override public Product save(Product product) { return productRepository.save(product); } @Override public void remove(Long id) { productRepository.deleteById(id); } }
Code language: CSS (css)

ProductController.java

package com.example.demo.controller; import com.example.demo.model.Product; import com.example.demo.model.ProductForm; import com.example.demo.service.IProductService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.util.FileCopyUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.view.RedirectView; import java.io.File; import java.io.IOException; import java.util.List; @Controller @RequestMapping("/products") public class ProductController { @Autowired private IProductService productService; @Value("${upload.path}") private String fileUpload; @GetMapping public ModelAndView home(){ ModelAndView modelAndView = new ModelAndView("/product/list"); List<Product> products = (List<Product>) productService.findAll(); modelAndView.addObject("products", products); modelAndView.addObject("message", "Thanh cong"); return modelAndView; } @GetMapping("/create") public ModelAndView showFormCreate(){ ModelAndView modelAndView = new ModelAndView("/product/create"); modelAndView.addObject("product", new ProductForm()); return modelAndView; } @PostMapping("/create") public RedirectView createProduct(@ModelAttribute ProductForm product){ Product product1 = new Product.ProductBuilder(product.getName()) .description(product.getDescription()).build(); MultipartFile multipartFile = product.getImage(); String fileName = multipartFile.getOriginalFilename(); try { FileCopyUtils.copy(product.getImage().getBytes(), new File(this.fileUpload + fileName)); } catch (IOException e) { e.printStackTrace(); } product1.setImage(fileName); productService.save(product1); return new RedirectView(""); } }
Code language: JavaScript (javascript)

Sử dụng @Value để lấy giá trị đường dẫn từ file application.properties.

Thymleaf

list.html

<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>Tasks</h1> <table border="1px"> <thead> <tr> <th> Name </th> <th> Description </th> <th> Image </th> </tr> </thead> <tbody> <tr th:each="product: ${products}"> <td th:text="${product.getName()}"></td> <td th:text="${product.getDescription()}"></td> <td> <img th:src="${product.image}"> </td> </tr> </tbody> </table> </body> </html>
Code language: HTML, XML (xml)

create.html

<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Create new product</title> </head> <body> <h1>Create new product</h1> <form method="post" th:object="${product}" enctype="multipart/form-data"> <table> <tr> <td>Name</td> <td><input type="text" th:field="*{name}"></td> </tr> <tr> <td>Desciption</td> <td><input type="text" th:field="*{description}"></td> </tr> <tr> <td>Image</td> <td><input type="file" th:field="*{image}"></td> </tr> <tr> <td></td> <td><input type="submit" value="Create"></td> </tr> </table> </form> </body> </html>
Code language: HTML, XML (xml)

Vậy là bạn đã có lưu được đường dẫn ảnh vào trong cơ sở dữ liệu và lưu trữ file tại máy mình. Hi vọng bài viết này sẽ giúp ích cho mọi người trong việc xử lý lưu trữ file ảnh trong Spring Boot.

>> Xem ngay Tài liệu Java Core giúp bạn “Nâng Cấp” kỹ năng lập trình

Leave a Reply

Your email address will not be published. Required fields are marked *