Struts2 Fileupload giving null file in the action class - java

I am trying to implement the file upload process in my web application using struts2 fileUpload interceptor. below is my code in
index.jsp
<tags:form action="fileUpload" method="post" enctype="multipart/form-data">
<tags:file name="fileUpload" label="Choose File"/>
<tags:submit value="Upload"/>
</tags:form>
struts.xml
<action name="fileUpload" class="com.hibernate.action.FileUploadAction">
<interceptor-ref name="fileUploadStack"/>
<interceptor-ref name="fileUpload">
<param name="maximumSize">1024000</param>
<param name="allowedTypes">application/pdf</param>
</interceptor-ref>
<result name="success">/viewChapters.jsp</result>
</action>
FileUploadAction.java
public class FileUploadAction extends ActionSupport
{
private File fileUpload;
private String contentType;
private String fileName;
private String destPath;
/// setter and getter methods
public String execute()
{
destPath="C:\\WebPortal_testing";
try
{
System.out.println("Source File Name:"+fileUpload);
System.out.println("Destination File Name:"+fileName);
File destFile= new File(destPath,fileName);
FileUtils.copyFile(fileUpload, destFile);
}
catch(IOException exception)
{
exception.printStackTrace();
return ERROR;
}
return SUCCESS;
}
when I select a pdf file in the index.jsp page and click on upload button it is giving null value to the fileUpload field of the action class.
I am executing the application in debug mode and gave this
System.out.println("Source File Name:"+fileUpload);
to check what it is returning and I am getting null.

1. Interceptor configuration is wrong
FileUploadStack is:
<!-- Sample file upload stack -->
<interceptor-stack name="fileUploadStack">
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="basicStack"/>
</interceptor-stack>
then what you're really defining is:
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="basicStack"/>
<interceptor-ref name="fileUpload">
<param name="maximumSize">1024000</param>
<param name="allowedTypes">application/pdf</param>
</interceptor-ref>
Using
two times the fileUpload interceptor
applying your limitations on maximumSize and allowedTypes only to the second.
Just do
<interceptor-ref name="fileUploadStack">
<param name="fileUpload.maximumSize">1024000</param>
<param name="fileUpload.allowedTypes">application/pdf</param>
</interceptor-ref>
2. File attributes are wrong
Content type and file name attributes must start with the File attribute name.
In your case:
private File fileUpload;
private String fileUploadContentType;
private String fileUploadFileName;
You can find a full example on this question.
3. You are printing the File instead of the filename
System.out.println("Source File Name:"+fileUpload);
That is the file, not the filename, and btw the filename is passed in the other variable.
Fix this and retry. Also note that is not safe to use <tags: as prefix when the whole world is using <s:. There's no gain in doing that, only complications. Just use <s:.

Related

Unable to match csrf-token using ajax/json

I have one login page, with a sign-in pop-up, which has username, password and a captcha. Each time when I try to post the form using ajax ( return value is json ), I will get an error like this:
com.opensymphony.xwork2.ognl.OgnlValueStack - Error setting expression 'struts.token.name' with value '[Ljava.lang.String;#53401791' ognl.OgnlException: source is null for getProperty(null, "token")
and
Form token B4KX7L4ER1FXK5BRJZJ19QTGG4EGRGME does not match the session token null
Login.jsp
<script>
var strutsToken = "<s:property value="#session['struts.tokens.token']" />";
</script>
and inside body tag
<s:token/>
Signin.jsp (Popup for login)
<script>
var strutsToken = "<s:property value="#session['struts.tokens.token']" />";
</script>
<script>
$(document).ready(function () {
// For making new captcha image
var df = "Captcha?token=" + strutsToken + "&struts.token.name=token";
$("#IMA").attr("src", df); // IMA is id of captcha image
$('#mini').click(function () { // mini is id of submit button
$.post('Auth', {
username: document.getElementById('username').value,
pass: document.getElementById('pass').value,
Captcha: document.getElementById('Captcha').value,
token: strutsToken,
'struts.token.name': "token"
}, function (jsonResponse) {
if (jsonResponse.res == "1") {
console.log('valid');
window.location = "campaign/campaign_dashboard.jsp";
}
else if (jsonResponse.res == "2") {
console.log('valid');
window.location = "Main.jsp";
} else {
$('#result').text(jsonResponse.res);
}
}, 'json');
});
});
</script>
Struts.xml
<interceptor-stack name="myStack">
<interceptor-ref name="authenticationInterceptor" > </interceptor-ref>
<interceptor-ref name="cachingHeadersInterceptor" />
<interceptor-ref name="fileUpload" >
</interceptor-ref>
<interceptor-ref name="token"></interceptor-ref>
<interceptor-ref name="params">
<param name="params.excludeParams">
token,dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*
</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="myStack"/>
What is preventing the token to be correctly passed to the action ?
You need to exclude the token parameters from the ones intercepted by the Parameters Interceptor.
By default, the Parameters Interceptor already excludes them:
This interceptor can be forced to ignore parameters, by setting its excludeParams attribute. This attribute accepts a comma separated list of regular expressions. When any of these expressions match the name of a parameter, such parameter will be ignored by the interceptor. Interceptor stacks defined by Struts already exclude some parameters:
Default List of Parameters Excluded
dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,
^servlet(Request|Response)\..*,parameters\...*
By default, the ^struts\..* part of the regex will excldue struts.token and struts.token.name.
You have most likely overriden the default excluded parameters in your Parameters Interceptor, without extending the original excluded ones.
Then:
Manually add the exclusion for the token parameters:
<interceptor-ref name="params">
<param name="excludeParams">
myStuff\..*,struts.token,struts.token.name
</param>
</interceptor-ref>
or, much better, add your custom exclusion to the original list instead of replacing it:
<interceptor-ref name="params">
<param name="excludeParams">
myStuff\..*,dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,
^servlet(Request|Response)\..*,parameters\...*
</param>
</interceptor-ref>
EDIT
After you added the code, I can see some error:
remove myStuff\..*, I put it as a placeholder to your real customization, it's not needed;
put the whole regex in one line, I've splitted it only to improve readability of the answer;
You are setting the param exclusion on a Parameters Interceptor, then importing the whole defaultStack that itself contains another Parameters Interceptor. You should open the defaultStack tag and set the exclusion there (this however doesn't explain the problem because it means you are not overriding the default exclusion...).
Also the FileUpload Interceptor is already in the defaultStack, so you're running it twice.
Then try with:
<interceptor-stack name="myStack">
<interceptor-ref name="authenticationInterceptor" />
<interceptor-ref name="cachingHeadersInterceptor" />
<interceptor-ref name="token" />
<interceptor-ref name="defaultStack" />
</interceptor-stack>
If it doesn't work, try with:
<interceptor-stack name="myStack">
<interceptor-ref name="authenticationInterceptor" />
<interceptor-ref name="cachingHeadersInterceptor" />
<interceptor-ref name="token" />
<interceptor-ref name="defaultStack">
<param name="params.excludeParams">
token,dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*
</param>
</interceptor-ref>
</interceptor-stack>

File upload interceptor does not call setter methods

I need to do very basic file upload operation, but in my case setter methods are not called by file upload interceptor.
I have checked the solution of similar questions like this on stackoverflow but they didnot resolve my issue.
Please let me know what mistake i am doing in code.
Action class
public class ResultFileUploadAction extends ActionSupport {
private File upload;
private String uploadFileName;
private String uploadContentType;
private Logger logger = Logger.getRootLogger();
#Override
public String execute() throws Exception {
logger.info("ResultFileUploadAction->execute");
String destPath = "C:/work/";
try {
System.out.println("Src File name: " + upload);
System.out.println("Dst File name: " + uploadFileName);
File destFile = new File(destPath, uploadFileName);
FileUtils.copyFile(upload, destFile);
} catch (IOException e) {
e.printStackTrace();
return ERROR;
}
return super.execute();
}
public void setUpload(File upload) {
this.upload = upload;
}
public void setUploadContentType(String uploadContentType) {
this.uploadContentType = uploadContentType;
}
public void setUploadFileName(String uploadFileName) {
this.uploadFileName = uploadFileName;
}
}
Jsp file
<body>
<s:form action="upload" method="post" enctype="multipart/form-data">
<input type="file" name="upload" id="uploadfile" />
<input type="submit" id="submit" />
</s:form>
</body>
Struts.xml
<interceptors>
<interceptor name="fileupload"
class="org.apache.struts2.interceptor.FileUploadInterceptor"></interceptor>
<interceptor name="servletConfig"
class="org.apache.struts2.interceptor.ServletConfigInterceptor" />
<interceptor name="authenticationinterceptor"
class="interceptors.common.AuthenticationInterceptor"></interceptor>
<interceptor-stack name="securestack">
<interceptor-ref name="authenticationinterceptor"></interceptor-ref>
<interceptor-ref name="servletConfig"></interceptor-ref>
</interceptor-stack>
</interceptors>
<action name="upload" class="actions.result.ResultFileUploadAction"
method="execute">
<interceptor-ref name="securestack"></interceptor-ref>
<interceptor-ref name="fileupload"></interceptor-ref>
<result name="success" type="dispatcher">/AddResultBullk.jsp</result>
</action>
Since, setters are not called therefore i am getting NPE in execute().
As stated in the fileUpload interceptor docs:
It adds the following parameters, where [File Name] is the name given to the file uploaded by the HTML form. [fileName, contentType]
When mucking with interceptor stacks there are always two plans of attack:
Try a non-custom stack
Don't mess with the stack unless you know precisely why you're doing it, and what you're doing.
Also, actions that are configured to use almost no interceptors, as yours is, are almost always suspect, because they eliminate the bulk of framework functionality. Params in particular is key to essentially every form-based action.
When you want to implements a new interceptors, it is a good idea to add them to the default stack in front or back of the chain, i faced the same problem before when I am trying to add an interceptor for authentication and ended with the following practice, I will update your
code to mention my idea:
...
<interceptors>
<interceptor name="authenticationinterceptor" class="your.class.name" />
<interceptor-stack name="securestack">
<interceptor-ref name="authenticationinterceptor" />
<interceptor-ref name="defaultStack" />
</interceptor-stack>
</interceptors>
<!--
Implicitly use securestack for all actions.
-->
<default-interceptor-ref name="securestack" />
....
<!--
and if you want some actions to pass from secureStack and use defaultStack
(ex login page), you can state that explicitly, See:
-->
<action name="GetLoginPageAction" class="your.class.name">
<interceptor-ref name="defaultStack" />
...
</action>
<!--
for upload action you can use interceptor without define
it in the interceptors tag only in the action,
Note that you should explicitly use securestack below
-->
<action name="upload" class="actions.result.ResultFileUploadAction">
<!-- You can remove the below refs because fileUpload is already
included in defaultStack that is included in the securestack
and securestack is default interceptor for all actions.
<interceptor-ref name="securestack"/>
<interceptor-ref name="fileUpload"/>
-->
...
</action>
I hope these notes help you.

Struts 2 Message Store Interceptor Removing Errors on No Redirect

I am having an issue with the Message Store Interceptor in Struts 2. I have the following action in my struts.xml file:
<action name="rfi" method="add" class="org.test.action.RfiAction">
<interceptor-ref name="store">
<param name="operationMode">AUTOMATIC</param>
</interceptor-ref>
<interceptor-ref name="defaultStack" />
<result name="error">../display/irrt/rfi.jsp</result>
<result name="input">../display/irrt/rfi.jsp</result>
<result name="success" type="redirectAction">
<param name="actionName">rfis</param>
<param name="namespace">/irrt</param>
</result>
</action>
When the action returns successfully, it redirects to the action listed and the success message is properly saved and retrieved by the interceptor.
However, when an error occurs, there is no redirect and it goes to the listed JSP page but the error doesn't show up (all other data does). It's like the MessageStoreInterceptor wipes out the contents of the error variables when it runs so that if no redirect occurs, the current action no longer has the error message.
This happens when the interceptor is set to either STORE or AUTOMATIC mode (even though the interceptor shouldn't even run if it's in AUTOMATIC mode and the result doesn't include a redirect).
My code only ever adds errors or messages. It never deletes them. The action code is below:
private String add()
{
try
{
// add the rfi entry
this.rfiService.addRfi(this.rfiEntry, this.getLoggedInUser());
}
catch(ConnectionException e)
{
this.addActionError("Could not add RFI entry.");
e.printStackTrace();
return ERROR;
}
// set success message
this.addActionMessage("RFI entry added.");
return SUCCESS;
}
This is the code in the JSP being used to display the messages:
<s:if test="hasActionErrors() == true">
<s:iterator value="actionErrors">
<p class="text"><b><font color="red"><s:property /></font></b></p>
</s:iterator>
</s:if>
<s:elseif test="hasActionMessages() == true">
<s:iterator value="actionMessages">
<p class="text"><b><font color="green"><s:property /></font></b></p>
</s:iterator>
</s:elseif>
Any help with this issue would be greatly appreciated.
<result name="success" type="redirectAction">
<param name="actionName">rfis</param>
<param name="namespace">/irrt</param>
</result>
The redirectAction rfis should also go through the store interceptor.
<action name="rfis" class="..." method="...">
<interceptor-ref name="store">
<param name="operationMode">AUTOMATIC</param>
</interceptor-ref>
<interceptor-ref name="defaultStack" />
<result ..../>
</action>
I was missing the include on this particular page that included the errors.
Moral of the story: don't assume code that's on every single other page is on the one that's not working.

Adding interceptors in struts.xml for all Action classes

I've used the Struts 2 framework and I have created a web application which has a Login Page. I have three different Action classes named Action1, Action2, Action3, and different views for JSP pages which are rendered by running some business logic in the Action classes.
Now, I want to check whether a user has logged in before the Action class carries out processing. So,
I created an interceptor below that works fine:
public String intercept(ActionInvocation invocation) throws Exception
{
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
HttpSession session = request.getSession();
if(session.isNew())
{
response.sendRedirect("Login.action");
}
System.out.println("Interceptor Fired");
String result = invocation.invoke();
return result;
}
What I want to be in struts.xml is instead of adding an interceptor for all the actions like the one below
<interceptor-ref name="newStack"/>
My struts.xml file has:
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="printMsgInterceptor" class="LoginInterceptor"></interceptor>
<interceptor-stack name="newStack">
<interceptor-ref name="printMsgInterceptor"/>
<interceptor-ref name="defaultStack" />
</interceptor-stack>
</interceptors>
<action name="actone" class="Action1">
<result name="success">/success.jsp</result>
<interceptor-ref name="newStack"/>
</action>
<action name="acttwo" class="Action2">
<result name="success">/success.jsp</result>
<interceptor-ref name="newStack"/>
</action>
<action name="actthree" class="Action3">
<result name="success">/success.jsp</result>
<interceptor-ref name="newStack"/>
</action>
</package>
For every action I want to have some definition written in struts.xml which runs the interceptor rather than manually adding
<interceptor-ref name="newStack"/>
<interceptor name="test" class="Full path for LoginInterceptor" />
<interceptor-stack name="testStack">
<interceptor-ref name="test"/>
<interceptor-ref name="defaultStack"/> //here you are including default stack
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="testStack"></default-interceptor-ref>
Now testStack will execute for every request
Use
<default-interceptor-ref name="newStack"/>
If you not putting interceptor-ref manually for each action you could use the default-interceptor-ref to intercept all actions that has not explicitly defined interceptors configuration. See How do we configure an Interceptor to be used with every Action.
We can create our own named stacks and even declare a new default interceptor stack for a package
<package name="default" extends="struts-default" >
<interceptors>
<interceptor-stack name="myStack">
<interceptor-ref name="timer"/>
<interceptor-ref name="logger"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
However, if you say that the interceptor above works fine I will encourage you to be cautious about a business logic that the login action will not be executed if it fails on the first execution. Instead of checking for the new session you should check for results of the authenticated user and save these results in the session that you could check in the interceptor. See this question for example.
The example of writing the interceptor that use the authenticated user information with the session you could find here.

Struts 2 Download - How to configure the file name dynamically?

I am developing one application , where people will download the required file from a location mentioned in the DB to their Local. I am using struts 2 for downloading the file from the server . I can download the file without any exception and it works perfectly.
But the files am download has the filename i specified in struts.xml , i want it to be the exact filename which am downloading . example if the original file name is struts.pdf , i am downloading it as download.pdf, how to prevent it and download the file with actual filename
My struts.xml configuration as follows ,
<action name="download" class="action.DownloadAction">
<result name="success" type="stream">
<param name="contentType">application/octet-stream</param>
<param name="inputName">fileInputStream</param>
<param name="contentDisposition">attachment;filename="download.log"</param>
<param name="bufferSize">1024</param>
</result>
<result name="error">/live/useradminerror.jsp</result>
</action>
And i forgot to mention am using struts2-jquery for developing the UI .Please help me in this , as am in very critical stage of my project .
IF i am correct you want to pass the file which is being stored in your DB, if this is the case you can easily do this by passing all those parameters from you action class like
class MyFileDownloadAction extends ActionSupport{
private String fileName;
// getter and setter
public String fileDownload() throws exception{
// file download logic
fileName ="abc" // can set name dynamic from DB
}
}
<action name="download" class="action.DownloadAction">
<result name="success" type="stream">
<param name="contentType">application/octet-stream</param>
<param name="inputName">fileInputStream</param>
<param name="contentDisposition">attachment;filename="${filename}"</param>
<param name="bufferSize">1024</param>
</result>
<result name="error">/live/useradminerror.jsp</result>
</action>
You can pass each parameter dynamically in your struts.xml class.Hope this will help you
This is how you will use this file name in your XML
For annotations in struts, its same. The solution was very helpful. Thank you. The "contentType" for me did not make much difference.
#Action(value = "/download", results = { #Result(name = "success", type = "stream",
params= {"contentType", "application/octet-stream", "inputName","fileInputStream",
"contentDisposition","attachment; filename=\"${fileName}\"", "bufferSize", "1024" })
})

Categories

Resources