Search code examples
springspring-mvcmultipartform-datathymeleaf

Spring Multipart File Upload


I'm trying to upload a MultipartFile using Spring MVC, tomcat, Tyhmleaf but can't get it work.

java.lang.NullPointerException
com.cars.actions.controller.brand.BrandController.persist2(BrandController.java:75)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:483)

My controller:

@RequestMapping(value = "/addimage", method = RequestMethod.POST)
public String persist2(  @Valid @ModelAttribute("brand") BrandDTO brandDTO, BindingResult result, RedirectAttributes redirectAttrs, Model model) {

if (result.hasErrors()) {

     if (!brandDTO.getFile().isEmpty()) { // null pointer exception

        errorNotValid(model, "");
        return ADD_PAGE;
} else {
try {
            BufferedImage src = ImageIO.read(new ByteArrayInputStream(brandDTO.getFile().getBytes()));
            File destination = new File("/Users/katsu/Desktop/file/");
         ImageIO.write(src, "png", destination);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
     } 
        try {
            Brand brand = getEntity(brandDTO);
            service.save(brand);
            successAddMesage(model, "succes");
            model.addAttribute(businessObject, new Brand());
            return ADD_PAGE;
        } catch (DuplicateItemFoundException e) {
            errorDuplicateMessage(redirectAttrs, "dublucate");
            return REDIRECT_LIST_PAGE;
        } 

    }
}

My DTO:

public class BrandDTO {

private Integer id;
private String name;
private boolean enabled;
private CommonsMultipartFile file;

Apliaiton iniliaze:

public class ApplicationInitializer implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext servletContext) throws ServletException {

    // Register the Root application context
    AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
    rootContext.register(RootConfig.class);

    // Register the Web application context
    AnnotationConfigWebApplicationContext mvcContext = new AnnotationConfigWebApplicationContext();
    mvcContext.register(WebAppConfig.class);

    // Context loader listener
    //servletContext.addListener(new ContextLoaderListener(rootContext));

    // Register the Dandelion filter
    FilterRegistration.Dynamic dandelionFilter = servletContext.addFilter("dandelionFilter", new DandelionFilter());    
    dandelionFilter.addMappingForUrlPatterns(null, false, "/*");

    // Register the Spring dispatcher servlet
    ServletRegistration.Dynamic dispatcher = servletContext.addServlet("springServlet", new DispatcherServlet(mvcContext));
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("/");
    //dispatcher.setMultipartConfig(rootContext.getBean(Multi));

    // Register the Dandelion servlet
    ServletRegistration.Dynamic dandelionServlet = servletContext.addServlet("dandelionServlet",new DandelionServlet());
    dandelionServlet.setLoadOnStartup(2);
    dandelionServlet.addMapping("/dandelion-assets/*");

}

My Web initialize:

    @Bean
public CommonsMultipartResolver multipartResolver() {
    CommonsMultipartResolver resolver=new CommonsMultipartResolver();
    resolver.setDefaultEncoding("utf-8");
    resolver.setMaxUploadSize(40000000);
    return resolver;
}

My Form:

<form class="mainForm" action="#" data-th-action="@{/admin/brand/addimage}" data-th-object="${brand}" method="post" accept-charset="utf-8" enctype="multipart/form-data">
            <!-- Input text fields -->
            <fieldset>
                <div class="widget first">
                    <div class="head">
                        <h5 class="iList">Marka Ekleme</h5>
                    </div>
                    <div class="rowElem">
                        <label>Marka Adı:</label>

                        <div class="formRight">
                            <input type="text" placeholder="adını giriniz" data-th-value="*{name}" data-th-field="*{name}" />
                            <span th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Name Error</span>
                        </div>
                        <div class="fix"></div>
                    </div>
                    <div class="rowElem">
                        <label>Marka Logo:</label>

                        <div class="formRight">
                            <input type="file" data-th-field="*{file}"/>
                        </div>
                        <div class="fix"></div>
                    </div>

                    <div class="rowElem">
                        <label>Aktif Mi:</label>

                        <div class="formRight">
                            <select  class="select2" title="Click to Select a City"  th:field="*{enabled}">
                                <option th:each="type : ${enabledOptions}" th:value="${type}" th:text="${type}">Dropdown</option>
                            </select>
                        </div>
                        <div class="fix"></div>
                    </div>

                    <input type="submit" value="Submit form" class="greyishBtn submitForm" />
                    <div class="fix"></div>
                </div>
            </fieldset>
        </form>

and last tomcat permission:

<Context allowCasualMultipartParsing="true"> 

I digging all internet but cant resolve this problem. whats my wrong?


Solution

  • Try to replace

    @ModelAttribute BrandDTO brandDTO
    

    with

    @ModelAttribute("brand") BrandDTO brandDTO
    

    Currently your controller expects a model attribute named "brandDTO" which is null since without explicit naming it is derived from the argument type. But in your form you set a data-th-object=${brand}.

    If instead you keep the brandDTO name for the attribute and rename your th object in the page you better change :

    data-th-field="${brand.file}"
    

    to:

    data-th-field="*{file}"