【问题标题】:Spring MVC 4 Upload File Blocked by Spring SecuritySpring MVC 4 上传文件被 Spring Security 阻止
【发布时间】:2016-09-07 15:54:46
【问题描述】:

我尝试通过 Spring Form 在我的 Spring MVC 4 项目中上传文件,但是当我用我的日志提交表单时说:Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@527de1e2Invalid CSRF token found

我从Spring Security Reference 找到了解决方案 ,但在 Spring 安全性之前放置 Multipart Filter 后,我的模型属性返回 NULL。

这是我的代码:

JSP 片段:

<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>

<html>
<body>
<div>
    <form:form action="save?${_csrf.parameterName}=${_csrf.token}"
    method="post" modelAttribute="book" enctype="multipart/form-data">
        <table>
            <form:input type="hidden" path="id" />
            <tr>
                <td>ISBN:</td>
                <td><form:input path="isbn" autofocus="autofocus"/></td>
            </tr>
            <tr>
                <td>Title:</td>
                <td><form:input path="title" /></td>
            </tr>
            <tr>
                <td>Author:</td>
                <td><form:input path="author" /></td>
            </tr>
            <tr>
                <td>Publisher:</td>
                <td><form:input path="publisher" /></td>
            </tr>
            <tr>
                <td>Call Number:</td>
                <td><form:input path="callNumber" /></td>
            </tr>
            <tr>
                <td>Pages:</td>
                <td><form:input path="pages" /></td>
            </tr>
            <tr>
                <td>Pages:</td>
                <td><form:input path="imageFile" type="file" /></td>
            </tr>
            <tr>
                <td colspan="2" align="center">
                    <input type="submit" value="Save">
                </td>
            </tr>
        </table>
    </form:form>
</div>

型号

@Entity
@Table(name="books")
public class Book implements Serializable {

  private static final long serialVersionUID = 4235334951865878125L;

  @Id
  @Column(name = "id")
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private int id;

  @NotNull
  @NotEmpty
  @Size(min = 1, max = 25)
  @Column(name = "isbn")
  private String isbn;

  @NotNull
  @NotEmpty
  @Size(min = 1, max = 50)
  @Column(name = "title")
  private String title;

  @Size(max = 50)
  @Column(name = "author")
  private String author;

  @Size(max = 50)
  @Column(name = "publisher")
  private String publisher;

  @Size(max = 25)
  @Column(name = "call_number")
  private String callNumber;

  @Column(name = "pages")
  private int pages;

  @Column(name = "image_file")
  private byte[] imageFile;

  //Setter & Getter
}

控制器片段:

@RequestMapping(value = "/save", method = RequestMethod.POST)
@PreAuthorize("hasAnyAuthority('BOOK_ADD', 'BOOK_EDIT')")
public String saveBook(@ModelAttribute @Valid Book book, BindingResult result) {
    bookValidator.validate(book, result);

    if (result.hasErrors()) {
        return "book/form";
    }
    if (bookService.getBook(book.getId()) == null) {
        bookService.save(book);
    } else {
        bookService.update(book);
    }
    return "redirect:/book";
}

Servlet 配置:

@Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver() {
    CommonsMultipartResolver resolver = new CommonsMultipartResolver();
    resolver.setDefaultEncoding("UTF-8");
    return resolver;
}

Spring 安全初始化器:

@Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
    insertFilters(servletContext, new MultipartFilter());
}

SQL 表:

CREATE TABLE `books` (
  `id` INT(5) UNSIGNED NOT NULL AUTO_INCREMENT,
  `isbn` VARCHAR(25) NOT NULL,
  `title` VARCHAR(50) NOT NULL,
  `author` VARCHAR(50) NULL DEFAULT NULL,
  `publisher` VARCHAR(50) NULL DEFAULT NULL,
  `call_number` VARCHAR(25) NULL DEFAULT NULL,
  `pages` INT(5) NULL DEFAULT NULL,
  `image_file` MEDIUMBLOB NULL,
  PRIMARY KEY (`id`)
)

我正在使用的库片段:

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>4.2.3.RELEASE</version>
</dependency>
<dependency.
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-web</artifactId>
   <version>4.0.3.RELEASE</version>
</dependency>
<dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-config</artifactId>
   <version>4.0.3.RELEASE</version>
</dependency>
<dependency>
   <groupId>commons-fileupload</groupId>
   <artifactId>commons-fileupload</artifactId>
   <version>1.3.1</version>
</dependency>
<dependency>
   <groupId>commons-io</groupId>
   <artifactId>commons-io</artifactId>
   <version>2.5</version>
</dependency>

【问题讨论】:

    标签: java spring hibernate spring-mvc spring-security


    【解决方案1】:

    您可以像其他人建议的那样在 Book 类中添加一个新的 MultipartFile 属性,并使其暂时化。设置此属性时,同时设置您的 imageFile。

    @Column(name = "image_file")
    private byte[] imageFile;
    
    @Transient
    private MultipartFile multiPartFile;
    
    public void setMultiPartFile(MultipartFile multiPartFile) {
        this.multiPartFile = multiPartFile;
        if(multiPartFile != null){
            this.setImageFile(multiPartFile.getBytes());
        }
    }
    

    【讨论】:

    • 谢谢@simon-l,这是一个很好的解决方案。但我找到了与 make 方法 InitBinder 注释相同的解决方案,将 MultipartFile 类型转换为控制器中的 byte[]。
    【解决方案2】:

    阿里普·希达亚特,

    我认为您需要编辑一些代码。

    很简单的java + spring mvc文件上传

    配置.xml

    <!-- MultipartResolver -->
    <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="-1" />
        <property name="maxInMemorySize" value="-1" />
    </bean>
    
    <!-- BeanNameViewResolver -->
    <bean id="downloadViewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver">
        <property name="order">
            <value>0</value>
        </property>
    </bean>
    

    HTML

    <form id="upload_form" action="/upload" method="POST" enctype="multipart/form-data">
         <label>file : </label> 
         <input type="file" name="file" id="file" /> 
         <input type="submit" value="upload" />
    </form>
    

    型号

    public class MultipartFileModel {
    
    
    private MultipartFile file;
    
    //...getter, setter
    

    }

    这很重要。

    输入标签名称=“文件”

    model MultipartFile 变量名 = "file"

    控制器

        @RequestMapping(value = "/upload")
        private ModelAndView writeFile(MultipartFileModel model) {
    
            MultipartFile multipartfile = model.getFile();
            // you use "multipartfile"
            // ... you write file
    }
    

    【讨论】:

    • 感谢您的建议。但是,如果我更改为 MultipartFile 类型,我会得到休眠映射异常。如果我使用 spring form tld,你有什么建议吗?
    • 您在 imgfile 中使用 DB?只需将filePath保存在db中,将imgfile保存在服务器本地。您维护实体类并更改变量名称 String imgfilepath。您添加类模型。在控制器中使用模型。
    • 是的,我将文件作为 blob 保存到数据库中。
    【解决方案3】:

    通过改变来尝试

    private byte[] imageFile;

    private MultipartFile imageFile;
    

    更新

    如果您在 DB 中使用 blob 数据类型,您会使用 MultipartFile 从前端接收文件,然后使用另一个带有 byte[] 的 getter setter。

    private MultipartFile imageFileFrntEnd;
    // getter
    public MultipartFile setImageFileFrntEnd(MultipartFile file){
       //convert to byte[] and set to imageFile
    }
    
    private byte[] imageFile;
    //getter setter
    

    【讨论】:

    • 感谢您的回答。但是如果我更改为 MultipartFile 我会收到此错误:org.hibernate.MappingException
    猜你喜欢
    • 2014-10-26
    • 2017-11-05
    • 2012-12-05
    • 2015-11-09
    • 2017-02-09
    • 2019-01-26
    • 2015-03-29
    • 1970-01-01
    • 2020-08-29
    相关资源
    最近更新 更多