Java Programming

Upload File Spring MVC

Cấu hình upload file

Để upload vào thư mục đang chạy web ta cần tạo cấu hình chuyển đổi upload file trên thư mục web đăng chạy trên server bằng cách tạo MvcConfig.java trong webapp như sau:

@Configuration
public class MvcConfig implements WebMvcConfigurer{
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        String dirName = "images";
        Path dir = Paths.get("images");
        String uploadPath = dir.toFile().getAbsolutePath();
        registry.addResourceHandler("/" + dirName + "/**").addResourceLocations("file:/" + uploadPath + "/");
    }
}

Tạo Service Upload File

Tạo thêm thư mục services trong src/main/java/webapp

Tạo class StorageProperties

Tạo thư mục images trong src/main/resources/static

Tạo StorageProperties.java trong thư mục services để khai báo đường dẫn images trên thư mục web resource như sau:

@ConfigurationProperties("storage")
public class StorageProperties {
    private String location = "./src/main/resources/static/images";
    public String getLocation() {
        return location;
    }
    public void setLocation(String location) {
        this.location = location;
    }
}

Sau khi tạo class StorageProperties xong ta cấu hình chạy khi webapp được khởi tạo trong class WebStoreApplication như sau

@EnableConfigurationProperties(StorageProperties.class)
public class WebStoreApplication {

    public static void main(String[] args) {
        SpringApplication.run(WebStoreApplication.class, args);
    }
}

Trong code trên ta chỉ thêm phần code @EnableConfigurationProperties(StorageProperties.class), để biết được đường dẫn lưu trữ file trong resources

Tạo class Helper

Tạo Helper.java trong thư mục services để xử lý upload file với nội dung sau

public class Helper {
    public static String saveFile(String uploadDir, MultipartFile file, int len) throws IOException {
        Path path = Paths.get(uploadDir);
        if(!Files.exists(path)) {
            Files.createDirectories(path);
        }
        String name = file.getOriginalFilename();
        String ext = name.substring(name.lastIndexOf('.'));
        String fileName = randomString(len - ext.length()) + ext;
        Path filePath = path.resolve(fileName);
        file.transferTo(filePath);
        return fileName;
    }
    public static String randomString(int len){
        StringBuilder sb = new StringBuilder(len);
        String pattern = "1234567890qwertyuiopasdfghjklzxcvbnm";
        Random random = new Random();
        for(int i = 0; i < len; i++){
            sb.append(pattern.charAt(random.nextInt(pattern.length())));
        }
        return sb.toString();
    }
}

Trong class trên có phương thức randomString để tạo chuỗi ngẫu nhiên với chiều dài truyền vào là len

Đối với phương thức saveFile xử lý với mục địch lưu trữ vào thư mục, trong quá trình lưu file cần tạo chuỗi ngẫu nhiên nhắm tránh trường hợp trùng tên tập tin, sẽ bị ghi đè

Cấu hình kích thước file upload

Trường hợp kích thước file vượt quá mặc định cho phép trong Spring MVC ta cần cấu hình kích thước tập tin tối đa có thể upload trong application.properties như sau

spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB

Tạo model

Tạo class Image

Tạo Image.java trong thư mục models để lưu trữ các thông tin như đường dẫn, kiểu tập tin, kích thước như trong code sau:

@Entity
public class Image {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ImageId")
    private int id;
    @Column(name = "ImageUrl")
    private String url;
    private long size;
    private String type;
    public Image() {  
    }
    public Image(int id, String url, long size, String type) {
        super();
        this.id = id;
        this.url = url;
        this.size = size;
        this.type = type;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public long getSize() {
        return size;
    }
    public void setSize(long size) {
        this.size = size;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
}

Class ImageRepository

Tạo tiếp ImageRepository.java trong models với nội dung sau:

public interface ImageRepository extends CrudRepository<Image, Integer>{
}

Tạo Controller

Tạo UploadController

Trong thư mục controllers tạo UploadController.java với nội dung sau:

@Controller
public class UploadController {
    @Autowired
    private ImageRepository repository;
    @GetMapping("/upload")
    public String index(Model model){
        model.addAttribute("list", repository.findAll());
        return "upload/index";
    }
    @GetMapping("/upload/add")
    public String add(){
        return "upload/add";
    }
    @PostMapping("/upload/add")
    public String add(MultipartFile f){       
        try {
            String fileName = Helper.saveFile("images", f, 32);
            Image image = new Image(0, fileName, f.getSize(), f.getContentType());
            repository.save(image);
        return "redirect:/upload";
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "upload/add";
    }
}

Tạo Views

Tạo thư mục upload trong templates

Tạo view index

Trong thư mục upload tạo index.html với nội dung sau để hiển thị thông tin upload file như sau:

<a href="/upload/add">Add</a>
<table>
    <tbody>
        <tr th:each="o : ${list}">
            <td th:text="${o.id}"></td>
            <td>
                <img th:src="@{/images/{url}(url=${o.url})}" width="80">
            </td>
            <td th:text="${o.type}"></td>
        </tr>
    </tbody>
</table>

Tạo view add

Trong thư mục upload tiếp tục tạo add.html để upload file

<form enctype="multipart/form-data" method="post">
    <div>
        <label for="f">Image</label>
        <div>
            <input type="file" name="f" id="f" accept="image/*">
        </div>
    </div>
    <div>
        <button>Upload</button>
    </div>
</form>