Spring MVC/Spring Boot实现图片文件上传和显示

2025-10-29 01:12:52

1、第一步、在eclipse中构建一个标准的Maven工程

工程的信息:

  <groupId>fantasy</groupId>

  <artifactId>image</artifactId>

Spring MVC/Spring Boot实现图片文件上传和显示

Spring MVC/Spring Boot实现图片文件上传和显示

2、为工程添加Spring MVC和Spring boot相关的依赖

      <parent>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-parent</artifactId>

        <version>1.5.9.RELEASE</version>

    </parent>

    <dependencies>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-thymeleaf</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-devtools</artifactId>

            <optional>true</optional>

        </dependency>

    </dependencies>

Spring MVC/Spring Boot实现图片文件上传和显示

3、创建文件存储服务的接口和实现类,对处理WEB页面的文件上传服务

1)文件存储服务接口类:StorageService.java

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);

    void deleteAll();

}

2)文件存储服务接口实现类:FileSystemStorageService.java

package image.storage;

import java.io.IOException;

import java.net.MalformedURLException;

import java.nio.file.Files;

import java.nio.file.Path;

import java.nio.file.Paths;

import java.nio.file.StandardCopyOption;

import java.util.stream.Stream;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.core.io.Resource;

import org.springframework.core.io.UrlResource;

import org.springframework.stereotype.Service;

import org.springframework.util.FileSystemUtils;

import org.springframework.util.StringUtils;

import org.springframework.web.multipart.MultipartFile;

/**

 * 文件系统存储服务

 * @author fantasy

 *

 */

@Service

public class FileSystemStorageService implements StorageService

{

//文件存储路径

    private final Path rootLocation;

    @Autowired

    public FileSystemStorageService(StorageProperties properties) {

        this.rootLocation = Paths.get(properties.getLocation());

    }

    @Override

    public void store(MultipartFile file) {

        String filename = StringUtils.cleanPath(file.getOriginalFilename());

        try {

            if (file.isEmpty()) {

                throw new StorageException("File is empty: " + filename);

            }

            if (filename.contains("..")) {

                // 文件路径安全校验

                throw new StorageException(

                        "不能将文件保存到相对目录路径中: "

                                + filename);

            }

            //将上传的文件保存到指定位置

            Files.copy(file.getInputStream(), this.rootLocation.resolve(filename),

                    StandardCopyOption.REPLACE_EXISTING);

        }

        catch (IOException e) {

            throw new StorageException("上传文件失败 " + filename, e);

        }

    }

    /**

     * 加载所有的文件路径

     */

    @Override

    public Stream<Path> loadAll() {

        try {

            return Files.walk(this.rootLocation, 1)

                    .filter(path -> !path.equals(this.rootLocation))

                    .map(path -> this.rootLocation.relativize(path));

        }

        catch (IOException e) {

            throw new StorageException("Failed to read stored files", e);

        }

    }

    @Override

    public Path load(String filename) {

        return rootLocation.resolve(filename);

    }

    @Override

    public Resource loadAsResource(String filename) {

        try {

            Path file = load(filename);

            Resource resource = new UrlResource(file.toUri());

            if (resource.exists() || resource.isReadable()) {

                return resource;

            }

            else {

                throw new StorageFileNotFoundException(

                        "Could not read file: " + filename);

            }

        }

        catch (MalformedURLException e) {

            throw new StorageFileNotFoundException("Could not read file: " + filename, e);

        }

    }

    @Override

    public void deleteAll() {

        FileSystemUtils.deleteRecursively(rootLocation.toFile());

    }

    @Override

    public void init() {

        try {

            Files.createDirectories(rootLocation);

        }

        catch (IOException e) {

            throw new StorageException("Could not initialize storage", e);

        }

    }

}

3)文件存储处理的异常类

StorageException.java

package image.storage;

/**

 * 文件存储异常运行时处理类

 * @author fantasy

 *

 */

public class StorageException extends RuntimeException {

private static final long serialVersionUID = 2430191988074222554L;

public StorageException(String message) {

        super(message);

    }

    public StorageException(String message, Throwable cause) {

        super(message, cause);

    }

}

4) 文件存储异常类:StorageFileNotFoundException.java

package image.storage;

public class StorageFileNotFoundException extends StorageException {

private static final long serialVersionUID = -7119518537629449580L;

public StorageFileNotFoundException(String message) {

        super(message);

    }

    public StorageFileNotFoundException(String message, Throwable cause) {

        super(message, cause);

    }

}

Spring MVC/Spring Boot实现图片文件上传和显示

4、创建一个文件存储属性配置类,实现文件存储的相关自定义属性配置,如文件

上传的目录名称:StorageProperties.java

该类指定了文件上传的目录位置为:upload-dir

package image.storage;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("storage")

public class StorageProperties {

    /**

     * Folder location for storing files

     */

    private String location = "upload-dir";

    public String getLocation() {

        return location;

    }

    public void setLocation(String location) {

        this.location = location;

    }

}

Spring MVC/Spring Boot实现图片文件上传和显示

5、实现文件上传控制器,这个是整个WEB应用的的核心,实现WEB页面到文件存储服务的联接控制。

文件名:FileUploadController.java

package image;

import java.io.IOException;

import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.core.io.Resource;

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.method.annotation.MvcUriComponentsBuilder;

import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import image.storage.StorageFileNotFoundException;

import image.storage.StorageService;

/**

 * 文件上传服务控制器

 * @author Fantasy

 *

 */

@Controller

public class FileUploadController {

    private final StorageService storageService;

    @Autowired

    public FileUploadController(StorageService storageService) {

        this.storageService = storageService;

    }

    //文件上传的url入口:/upload,然后转入templates目录下的uploadForm.html文件

    @GetMapping("/upload")

    public String showUploadPage(Model model) throws IOException {

        return "uploadForm";

    }

    //处理post上传文件的url:/upload,处理成功后页面跳转掉“/result”

    @PostMapping("/upload")

    public String handleFileUpload(@RequestParam("file") MultipartFile file,

            RedirectAttributes redirectAttributes) {

        storageService.store(file);

        redirectAttributes.addFlashAttribute("message",

                "文件: " + file.getOriginalFilename() + "上传成功!");

       return "redirect:/result";

    }

    

    //处理url:/result的请求,显示templates目录下的uploadResult.html文件

    //显示上传的文件列表

    @GetMapping("/result")

    public String listUploadedFiles(Model model) throws IOException {

        model.addAttribute("files", storageService.loadAll().map(

                path -> MvcUriComponentsBuilder.fromMethodName(FileUploadController.class,

                        "serveFile", path.getFileName().toString()).build().toString())

                .collect(Collectors.toList()));        

        System.out.println(model);

        return "uploadResult";

    }

    

    //查看已经上传的文件

    @GetMapping("/files/{filename:.+}")

    @ResponseBody

    public ResponseEntity<Resource> serveFile(@PathVariable String filename) {

   

        Resource file = storageService.loadAsResource(filename);

        return ResponseEntity.ok(file);

    }

    

    //图片文件的路径是虚拟路径,如何在页面中直接显示呢?

    @GetMapping("img/{filename:.+}")

    @ResponseBody

    public ResponseEntity<Resource> getFile(@PathVariable String filename)

    {

    Resource file = storageService.loadAsResource(filename);

   

    return ResponseEntity.ok(file);

    }

    

    @ExceptionHandler(StorageFileNotFoundException.class)

    public ResponseEntity<?> handleStorageFileNotFound(StorageFileNotFoundException exc) {

        return ResponseEntity.notFound().build();

    }

}

6、为页面创建静态资源目录,存储静态的html、js,css、图片等文件

如在项目中需要用的jquery则需要将jquery的库文件放在工程的静态目录中:

E:\workspace\image\src\main\resources\static\js\jquery-3.2.1.min.js

在这个工程中我们将index.html和jquery-3.2.1.min.js放在静态文件目录下。

Spring MVC/Spring Boot实现图片文件上传和显示

7、为Spring MVC提供thymeleaf模板的WEB页面文件,提供文件上传的页面和文件展现的页面;

1)文件上传页面:该页面展示了如何引用静态js文件

uploadForm.html

<html xmlns:th="http://www.thymeleaf.org">

<head>

<!-- 静态文件css,js等放在static目录下 -->

<script src="./js/jquery-3.2.1.min.js"></script>

<script>

$(document).ready(function(){

alert("Upload File Page");

});

</script>

</head>

<body>

<div>

<form method="POST" enctype="multipart/form-data" action="/upload">

<table>

<tr><td>File to upload:</td><td><input type="file" name="file"  accept="image/*"/></td></tr>

<tr><td></td><td><input type="submit" value="Upload" /></td></tr>

</table>

</form>

</div>

</body>

</html>

2)文件上传结果展示页面:uploadResult.html

注意:上传的文件是图片文件时才可以在页面上正常显示的

<html xmlns:th="http://www.thymeleaf.org">

<body>

<div th:if="${message}">

<h2 th:text="${message}"/>

</div>

<div>

<ul>

<li th:each="file : ${files}">

<img th:src="${file}"/>

<a th:href="${file}" th:text="${file}" />

</li>

</ul>

</div>

</body>

</html>

Spring MVC/Spring Boot实现图片文件上传和显示

8、为Spring应用设置相关的属性,如文件上传的大小,避免出现大坑

在resources目录下创建spring的属性配置文件application.properties

spring.http.multipart.max-file-size=128MB

spring.http.multipart.max-request-size=128MB

Spring MVC/Spring Boot实现图片文件上传和显示

9、最后创建Spring boot的应用程序入口Application.java

package image;

import org.springframework.boot.CommandLineRunner;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.boot.context.properties.EnableConfigurationProperties;

import org.springframework.context.annotation.Bean;

import image.storage.StorageProperties;

import image.storage.StorageService;

@SpringBootApplication

@EnableConfigurationProperties(StorageProperties.class)

public class Application {

    public static void main(String[] args) {

        SpringApplication.run(Application.class, args);

    }

    @Bean

    CommandLineRunner init(StorageService storageService)

    {

    return (args)->{

    storageService.deleteAll();

    storageService.init();

    };

    }

}

10、运行application.java类,启动spring boot应用

10:53:55.672 [main] DEBUG org.springframework.boot.devtools.settings.DevToolsSettings - Included patterns for restart : []

10:53:55.674 [main] DEBUG org.springframework.boot.devtools.settings.DevToolsSettings - Excluded patterns for restart : [/spring-boot-starter/target/classes/, /spring-boot-autoconfigure/target/classes/, /spring-boot-starter-[\w-]+/, /spring-boot/target/classes/, /spring-boot-actuator/target/classes/, /spring-boot-devtools/target/classes/]

10:53:55.674 [main] DEBUG org.springframework.boot.devtools.restart.ChangeableUrls - Matching URLs for reloading : [file:/E:/workspace/image/target/classes/]

  .   ____          _            __ _ _

 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \

( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \

 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )

  '  |____| .__|_| |_|_| |_\__, | / / / /

 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::        (v1.5.9.RELEASE)

2018-01-07 10:53:55.950  INFO 2932 --- [  restartedMain] image.Application                        : Starting Application on V3EQ67T1ANYZUSN with PID 2932 (E:\workspace\image\target\classes started by Administrator in E:\workspace\image)

2018-01-07 10:53:55.950  INFO 2932 --- [  restartedMain] image.Application                        : No active profile set, falling back to default profiles: default

2018-01-07 10:53:56.193  INFO 2932 --- [  restartedMain] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@1f8de44: startup date [Sun Jan 07 10:53:56 CST 2018]; root of context hierarchy

2018-01-07 10:53:57.719  INFO 2932 --- [  restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)

2018-01-07 10:53:57.734  INFO 2932 --- [  restartedMain] o.apache.catalina.core.StandardService   : Starting service [Tomcat]

2018-01-07 10:53:57.736  INFO 2932 --- [  restartedMain] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.23

2018-01-07 10:53:57.862  INFO 2932 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext

2018-01-07 10:53:57.862  INFO 2932 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1670 ms

2018-01-07 10:53:58.020  INFO 2932 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]

2018-01-07 10:53:58.025  INFO 2932 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]

2018-01-07 10:53:58.025  INFO 2932 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]

2018-01-07 10:53:58.026  INFO 2932 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]

2018-01-07 10:53:58.026  INFO 2932 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]

2018-01-07 10:53:58.361  INFO 2932 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@1f8de44: startup date [Sun Jan 07 10:53:56 CST 2018]; root of context hierarchy

2018-01-07 10:53:58.435  INFO 2932 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/img/{filename:.+}],methods=[GET]}" onto public org.springframework.http.ResponseEntity<org.springframework.core.io.Resource> image.FileUploadController.getFile(java.lang.String)

2018-01-07 10:53:58.436  INFO 2932 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/upload],methods=[GET]}" onto public java.lang.String image.FileUploadController.showUploadPage(org.springframework.ui.Model) throws java.io.IOException

2018-01-07 10:53:58.440  INFO 2932 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/upload],methods=[POST]}" onto public java.lang.String image.FileUploadController.handleFileUpload(org.springframework.web.multipart.MultipartFile,org.springframework.web.servlet.mvc.support.RedirectAttributes)

2018-01-07 10:53:58.440  INFO 2932 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/files/{filename:.+}],methods=[GET]}" onto public org.springframework.http.ResponseEntity<org.springframework.core.io.Resource> image.FileUploadController.serveFile(java.lang.String)

2018-01-07 10:53:58.441  INFO 2932 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/result],methods=[GET]}" onto public java.lang.String image.FileUploadController.listUploadedFiles(org.springframework.ui.Model) throws java.io.IOException

2018-01-07 10:53:58.443  INFO 2932 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)

2018-01-07 10:53:58.443  INFO 2932 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)

2018-01-07 10:53:58.473  INFO 2932 --- [  restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]

2018-01-07 10:53:58.473  INFO 2932 --- [  restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]

2018-01-07 10:53:58.516  INFO 2932 --- [  restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]

2018-01-07 10:53:59.020  INFO 2932 --- [  restartedMain] oConfiguration$WelcomePageHandlerMapping : Adding welcome page: class path resource [static/index.html]

2018-01-07 10:53:59.241  INFO 2932 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729

2018-01-07 10:53:59.328  INFO 2932 --- [  restartedMain] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup

2018-01-07 10:53:59.419  INFO 2932 --- [  restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)

2018-01-07 10:53:59.426  INFO 2932 --- [  restartedMain] image.Application                        : Started Application in 3.737 seconds (JVM running for 4.758)

Spring MVC/Spring Boot实现图片文件上传和显示

11、在浏览器中进行测试web应用,推荐使用chrome或极速浏览器,windows 10的edge浏览器不支持的

Spring MVC/Spring Boot实现图片文件上传和显示

Spring MVC/Spring Boot实现图片文件上传和显示

声明:本网站引用、摘录或转载内容仅供网站访问者交流或参考,不代表本站立场,如存在版权或非法内容,请联系站长删除,联系邮箱:site.kefu@qq.com。
猜你喜欢