0

Some update:

I have some clue. From the answer: ServletFileUpload#parseRequest(request) returns an empty list

Request instance can only be parsed once I found my struts log when processing request:

2015-11-05 12:23:58,917: DEBUG com.opensymphony.xwork2.interceptor.ParametersInterceptor - Setting params data => [ /Users/zhoum/Documents/tools/apache-tomcat-7.0.55/work/Catalina/localhost/nemo-upload-service/upload_b4a8ce33_67cf_482f_9798_0985ff974c60_00000001.tmp ] dataContentType => [ text/plain ] dataFileName => [ test.txt ] id => [ 1 ]

So I'm afraid struts deals with request before. Is it the problem?


I am working on a Struts2 Restful project. There is a file-uploading api receiving files and parameters. My problem is HttpServletRequest.getPart("filename") always returns null.

The environment is

  1. multipart/form-data as content-type
  2. Tomcat7
  3. Servlet 3.0.1
  4. JDK 1.6

My code:

package nz.co.niwa.nemo.uploadservice.web.rest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;

import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.rest.DefaultHttpHeaders;
import org.apache.struts2.rest.HttpHeaders;

import com.opensymphony.xwork2.ModelDriven;

@MultipartConfig(fileSizeThreshold=1024*1024, 
maxFileSize=1024*1024*5, maxRequestSize=1024*1024*5*5)
public class RequestController implements ModelDriven<Map<String, Object>>, ServletRequestAware {
private HttpServletRequest request;
private Map<String, Object> model;

public HttpHeaders test() {
    getHttpRequestContent();
    return new DefaultHttpHeaders();
}

private void getHttpRequestContent() {
    model = new HashMap<String, Object>();
    model.put("http method", request.getMethod());
    model.put("content length", request.getContentLength());
    System.out.println(request.getContentType());

    // parts
    try {
        Part part = request.getPart("data");
        model.put("filename", getSubmittedFileName(part));
        BufferedReader in = new BufferedReader(new InputStreamReader(part.getInputStream()));
        String textString = in.readLine();
        // the first line
        model.put("content", textString);
    } catch (IOException e1) {
        e1.printStackTrace();
    } catch (ServletException e1) {
        e1.printStackTrace();
    }

    // params
    Map<String, Object> params = new HashMap<String, Object>();
    for(Enumeration<?> e = request.getParameterNames(); e.hasMoreElements();) {
        String paramName = (String)e.nextElement();
        params.put(paramName, request.getParameter(paramName));
    }
    model.put("params", params);
}


@Override
public Map<String, Object> getModel() {
    return model;
}

@Override
public void setServletRequest(HttpServletRequest request) {
    this.request = request;

}

private static String getSubmittedFileName(Part part) {
    for (String cd : part.getHeader("content-disposition").split(";")) {
        if (cd.trim().startsWith("filename")) {
            String fileName = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
            return fileName.substring(fileName.lastIndexOf('/') + 1).substring(fileName.lastIndexOf('\\') + 1); // MSIE fix.
        }
    }
    return null;
}

}

My struts.xml

<?xml version="1.0" encoding="utf-8"?>

<constant name="struts.convention.action.suffix" value="Controller"/>
<constant name="struts.convention.action.mapAllMatches" value="true"/>
<constant name="struts.convention.default.parent.package" value="rest-default"/>
<!-- Locator is the last word of the package within which controller action class resides. -->
<constant name="struts.convention.package.locators" value="rest"/>
<constant name="struts.rest.defaultExtension" value="json" />
<!-- Set to false if the json content can be returned for any kind of http method -->
<constant name="struts.rest.content.restrictToGET" value="false"/> 

My web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
    <display-name>Archetype Created Web Application</display-name>

    <!-- Spring configuration files location -->  
    <context-param>    
        <param-name>contextConfigLocation</param-name>   
        <param-value>classpath:spring/*</param-value>  
    </context-param>

    <!-- execution sequence:1. filter 2.servlet -->
    <!-- struts filter-->
    <filter>  
        <filter-name>struts2</filter-name>  
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>  
    </filter>  
    <filter-mapping>  
        <filter-name>struts2</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping>

    <!-- Spring listener -->  
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- Servlet listener that exposes the request to the current thread, through both LocaleContextHolder and RequestContextHolder. -->
    <!-- e.g. request can get login users' name and role -->
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>NEMO UPLOAD RESTFUL</web-resource-name>
            <!-- all resources under webapp/ folder are applied this rule  -->
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <!-- JAAS security section -->
        <auth-constraint>
            <role-name>admin</role-name>
            <role-name>user</role-name>
        </auth-constraint>
        <!-- SSL -->
        <user-data-constraint>
            <!-- TODO CONFIDENTIAL -->
            <transport-guarantee>NONE</transport-guarantee>
        </user-data-constraint>
    </security-constraint>
    <login-config>
        <!-- Basic authentication, your browser will store the user credentials until it's closed.  -->
        <auth-method>BASIC</auth-method>
        <realm-name>NEMO upload service requires authentication.</realm-name>
    </login-config>
    <security-role>
        <role-name>admin</role-name>
    </security-role>
    <security-role>
        <role-name>user</role-name>
    </security-role>
</web-app>

I found this answer: https://stackoverflow.com/questions/27255132/multipartconfig-annotation-can-be-applied-only-to-servlets

Since mine is struts restful controller doesn't extends Action, so I have no idea how to deal with this situation. And I tried to add an constant in struts.xml:

<constant name="struts.multipart.maxSize" value="30000000" />

But still doesn't work.

One important thing I want to mention is my server(tomcat) has received the file, creating a temp file. When I was debugging in eclipse, I inspected into the HttpServeletRequest instance, it has a multi private valuable containing a valuable called "files". Where I found my uploading file. This is the thing I saw when I use eclipse to inspect HttpServletRequest.multi.files valuable:

{data=[name=test.txt, StoreLocation=/Users/zhoum/Documents/tools/apache-tomcat-7.0.55/work/Catalina/localhost/nemo-upload-service/upload_9dc69a88_ccfa_4ba1_9a8e_ae6912bb6d5c_00000001.tmp, size=23 bytes, isFormField=false, FieldName=data]}

Community
  • 1
  • 1
Willie Z
  • 476
  • 7
  • 12

0 Answers0