spring boot 学习笔记 (5) 文件上传

一、配置 

添加依赖包

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

引入了 spring-boot-starter-thymeleaf 做页面模板引擎。

添加配置

#是否支持 multipart 上传文件
spring.servlet.multipart.enabled=true
#支持文件写入磁盘
#spring.servlet.multipart.file-size-threshold=0
#上传文件的临时目录
#spring.servlet.multipart.location=
#最大支持文件大小
spring.servlet.multipart.maxFileSize=10MB
#最大支持请求大小
spring.servlet.multipart.maxRequestSize=10MB
#是否支持 multipart 上传文件时懒加载
#spring.servlet.multipart.resolve-lazily=false

再启动类中增加相关方法

@SpringBootApplication
public class FileUploadWebApplication {

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

    //Tomcat large file upload connection reset
    @Bean
    public TomcatServletWebServerFactory tomcatEmbedded() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        tomcat.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> {
            if ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol<?>)) {
                //-1 means unlimited
                ((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);
            }
        });
        return tomcat;
    }

}

TomcatServletWebServerFactory() 方法主要是为了解决上传文件大于 10M 出现连接重置的问题,此异常内容 GlobalException 也捕获不到。

二、相关代码

单文件上传

上传业务处理:

@PostMapping("/upload") 
public String singleFileUpload(@RequestParam("file") MultipartFile file,
                               RedirectAttributes redirectAttributes) {
    if (file.isEmpty()) {
      
        return "Please select a file to upload";
    }
    try {
        // Get the file and save it somewhere
        byte[] bytes = file.getBytes();
        // UPLOADED_FOLDER 文件本地存储地址
        Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
        Files.write(path, bytes);
  

    } catch (IOException e) {
        e.printStackTrace();
    }
    return "You successfully uploaded '" + file.getOriginalFilename() + "'";
}

异常处理

这里演示的是 MultipartException 的异常处理,也可以稍微改造监控整个项目的异常问题。

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MultipartException.class)
    public String handleError1(MultipartException e, RedirectAttributes redirectAttributes) {
        redirectAttributes.addFlashAttribute("message", e.getCause().getMessage());
        return "redirect:/uploadStatus";
    }
}

设置一个 @ControllerAdvice 用来监控 Multipart 上传的文件大小是否受限,当出现此异常时在前端页面给出提示。利用 @ControllerAdvice 可以做很多东西,比如全局的统一异常处理等,感兴趣的读者可以抽空了解一下。

多文件上传

@PostMapping("/uploadMore")
public String moreFileUpload(@RequestParam("file") MultipartFile[] files,
                               RedirectAttributes redirectAttributes) {
    if (files.length==0) {
       
        return  "Please select a file to upload";
    }
    for(MultipartFile file:files){
        try {
            byte[] bytes = file.getBytes();
            Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
            Files.write(path, bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    return  "You successfully uploaded all";
}

总的来说,文件上传的代码还是比较简单的,但是要注意,需要按照实际的需求去处理相关的业务,比如返回上传图片地址,存储文件的相对路径到数据库,

三、采坑记录

1、IDEA控制台 中文乱码问题,

在pom文件中添加 编码格式

IDEA设置编码的地方很多,需要注意要保持一致,

2、设置文件上传路径和显示路径

在开发过程中,如果不设置上传文件路径, 或者路径设置在项目中的文件中的时候,当项目重新发布时,上传的文件就丢失了。

所以这里我把文件上传到了本地文件夹。

这样带来一个问题,怎么显示上传的文件。

① 如果是直接放在tomcat中,可以通过修改tomcat的配置,

在tomcat>conf>server.xml 中,添加文件的映射

② 如果是用的IDEA发布的,可以修改相关配置。

先配置上传文件路径和外部访问路径

#静态资源对外暴露的访问路径
file.staticAccessPath=upload/**
#文件上传目录(注意Linux和Windows上的目录结构不同)
#file.uploadFolder=/root/uploadFiles/
file.uploadFolder=G://upload/

添加文件UploadFilePathConfig 用于映射两个路径的关系

@Configuration
public class UploadFilePathConfig extends WebMvcConfigurerAdapter {

    @Value("${file.staticAccessPath}")
    private String staticAccessPath;
    @Value("${file.uploadFolder}")
    private String uploadFolder;

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler(staticAccessPath).addResourceLocations("file:" + uploadFolder);
    }
}

注意,这里的外部访问路径都是相对路径,没有包含项目的根路径context-path, 在前端界面 使用时,需要手动添加。
这里我没有把根目录配置到文件路径中进去,而是在前段拼接。因为我会把文件的路径存储在数据库中,如果带有根路径相关数据,在项目名发生改变的时候改动会很多,

3、关于@RestController 和@Controller 的区别

@RestController是 @Controller 和 @ResponseBody 注解的合体版 ; 如果配置,则返回 相关字符串
如果配置为 @Controller,代表输出对应的页面。

不用弄错了

4、jsp和Thymeleaf混合使用

之前的上传界面是用jsp写的,引入进来之后,jsp界面一直找不到,

报错:

 Error resolving template [hello], template might not exist or might not be accessible by any of the configured Template Resolvers

但是反复确认了jsp文件和相关的配置都没有问题,后来才看到

spring boot   不建议使用jsp,并且对JSP支持存在一些限制

  • 使用Jetty和Tomcat,如果使用war包装,它应该可以工作。可执行的war在启动时将起作用java -jar,并且也可以部署到任何标准容器。使用可执行jar时不支持JSP。
  • Undertow不支持JSP。
  • 创建自定义error.jsp页面不会覆盖错误处理的默认视图 。 应该使用自定义错误页面。

 但是如果真的要使用jsp,还是有办法的:

1、在配置文件application.properties 中 配置 jsp,和之前的差不多,

spring.mvc.view.prefix=/WEB-INF/
spring.mvc.view.suffix=.jsp
spring.mvc.view.view-name=jsp/*
spring.mvc.view.order=2

2、在SpringbootApplication文件中添加对应的映射方法,并将相关配置设置到方法中

 @Value("${spring.mvc.view.prefix}")
    private String prefix;
    @Value("${spring.mvc.view.suffix}")
    private String suffix;
    @Value("${spring.mvc.view.view-name}")
    private String viewName;
    @Value("${spring.mvc.view.order}")
    private int order;

    @Bean
    InternalResourceViewResolver jspViewResolver(){
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix(prefix);
        viewResolver.setSuffix(suffix);
        viewResolver.setViewNames(viewName);
        viewResolver.setOrder(order);
        return viewResolver;
    }

3、在控制器中使用

  @RequestMapping("/welcome")
    public String  welcome(Map<String, Object> model) {
        model.put("time", new Date());
        model.put("message", "www.richduckling.com");
        model.put("count", 16);
        return "jsp/hello";
    }

注意:

这里配置jsp文件位置参数 时,我设置的是“spring.mvc.view.prefix=/WEB-INF/jsp” ,使用时 “return "jsp/hello"”,但是还是报错。重新安置上面的设置,就可以。因为 如果在控制器中不设置jsp路径,会默认去Thymeleaf的相关路径中去找,如果找不到对应的Thymeleaf视图就会报错,于是排在后面用来解析Jsp视图的InternalResourceViewResolver就失效了,不会继续在jsp相关文件中找。无语。

猜你喜欢

转载自blog.csdn.net/bihansheng2010/article/details/84775293