I'm trying to redirect to the page where the user tried to login.
I mean, somepage → login → somepage
I know this;
In LoginAction
HttpServletRequest request = ServletActionContext.getRequest();
String url = request.getServletPath();
setUrl(url);
In struts.xml
<action name="LoginPro" method="login" class="LoginAction">
<result type="redirect">${url}</result>
<result name="input" type="tiles">login.error</result>
</action>
But it's not working.
The requested url is always "LoginPro" which is handling login process.
When a user clicks login button, page goes to LoginPro. So the request url is always loginPro...
It seems to be this way;
somepage → login → loginPro → LoginAction(request url is loginPro..) → loginPro
How can I redirect users to the page where they tried to login?
Thanks for your answers.
I found this way and it works!
url = request.getHeader("referer");
This url is the exact url where the action is called.
When you click a link of Login then in java behind that request store url as static variable.
static String url = request.getHeader("referer");</p>
Then after inserting login details u call come other method. Use that static variable to redirect.
For Example: I have used in my site.
<action name="login" class="actions.Login.LoginAuthenticate" method="input">
<!--Cookie functionality done -->
<result name="input">Login/login.jsp</result>
</action>
<action name="loginAuthenticate" class="actions.Login.LoginAuthenticate" method="execute">
<!--Cookie functionality done -->
<result name="redirect" type="redirect">${redirectUrl}</result>
<result name="input">Login/login.jsp</result>
</action>
public String execute() throws Exception {
if(getCheckCookies()){
setRedirectUrl("/login");
return "redirect";
}
Cookie un = new Cookie("un" , lemail);
un.setMaxAge(-1);
un.setVersion(1);
servletResponse.addCookie(un);
System.out.println("------>--------->------> " + redirectUrl);
return "redirect";
}
public String input() throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();
setRedirectUrl(request.getHeader("Referer"));
return INPUT;
}
public static String redirectUrl;
public void setRedirectUrl(String redirectUrl){
this.redirectUrl = redirectUrl;
}
public String getRedirectUrl(){
return this.redirectUrl;
}
How are you redirecting to your login action? If it's only a single place (or some common base that does the redirection) could you add a variable to the session, make your Login action SessionAware, and then just retrieve/remove the source URL after a successful login, and use that?
HttpServletRequest request = ServletActionContext.getRequest();
String url = request.getRequestURI();
Related
This is my struts.xml class:
<action name="{param1}/{param2}/{param3}"
class="myactionclass"
method="execute">
<result name="success">/success.jsp</result>
</action>
So in my action class, I have to create three String objects String param1, param2, param3 (and add getter and setter methods) to get the param values. What I want to do is, instead of creating 3 different String objects, create a single String array and store the param values into the String array using the setter.
How do I achieve this in my action class ?
Populating an array in Struts2 using parameters in query-string is pretty easy.
In your Action declare the array with corresponding setter
private String[] fruits;
public void setFruits(String[] fruits) {
this.fruits = fruits;
}
This request will populate your fruits array
/myactionuri?fruits=apple&fruits=banana&fruits=peach
But with static parameters this mechanism doesn't seem to work in the same way.
I found this solution, maybe not as elegant, but it works.
In your struts.xml:
<!-- warning: this pattern matches all requests with 3 tokens separated by slashes -->
<action name="*/*/*" class="com.xxx.MyAction" >
<param name="f1">{1}</param>
<param name="f2">{2}</param>
<param name="f3">{3}</param>
</action>
And in your Action:
private String[] fruits = new String[3]; //need to be initiated
public void setF1(String f1) {
this.fruits[0] = f1;
}
public void setF2(String f2) {
this.fruits[1] = f2;
}
public void setF3(String f3) {
this.fruits[2] = f3;
}
Hope this will help you.
You need to tell which parameter will go to which index in the array.
<action name="{param[0]}/{param[1]}/{param[2]}" class="myactionclass">
<result name="success">/success.jsp</result>
</action>
Action (using array):
private String[] param = new String[3];
// getter and setter
Instead of array you can use List, then there is no need to initialize it in the action.
Action (using List):
private List<String> param;
// getter and setter
Map is also an option.
Action (using Map):
private Map<String, String> param;
// getter and setter
struts.xml (using Map in action):
<action name="{param['p1']}/{param['p2']}/{param['p3']}" class="myactionclass">
<result name="success">/success.jsp</result>
</action>
How can I pass the parameter value in the result type="stream" action?
<action name="print" class="mypty.EntryAction" method="print">
<result name="pdf-stream-result" type="stream">
<param name="inputName">fileStream</param>
<param name="contentType">application/pdf</param>
<param name="contentDisposition">filename=${generatedPDFFileName}</param>
<param name="entryId">entryId=${entryId}</param>
</result>
<result name="input">/entry.jsp</result>
</action>
<action name="editEntry" class="mypty.EntryAction" method="editEntry">
<result>/Entry.jsp</result>
</action>
I am trying to call the action via javascript from Entry.jsp page.
function print1()
{
var w = 1024;
var h = 800;
var left = (screen.width/2)-(w/2);
var top = (screen.height/2)-(h/2);
var url="print.action";
var uploadWindow = window.open (url, 'PrintPopUp', 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=0, copyhistory=no, width='+w+', height='+h+', top='+top+', left='+left);
uploadWindow.focus();
}
If I call this action like below, I can get the entryId from the print action. No need to pass the value.
function print()
{
//print function
document.chooseDates.action = 'print.action';
document.chooseDates.submit();
}
I want to pass the value of entryId to the print action. I can see the value of entryId in the previous action. This print action is called when clicking on the button. But when print action is called, the entryID value becomes 0. Both action classes have getters and setters for entryId. Is there anyway to pass those value?
Once the action execution is done all objects in the valuestack will be nullified, if you want to access data from provious action you can use following
Using chain interceptor
Use session
In my application I have added interceptor to filter the request.Here each user is associated with a list of menu. So if user try to access page which is not associated to him then we will redirect him to unauthorizedUser.jsp page otherwise we will let the user to access the page.
Here is my interceptor code ...
#Override
public String intercept(ActionInvocation actionInvocation) throws Exception {
String returnAction = "unauth.user";
Map<String, String> keyValMap = FCCommonUtils.getALLMenuIdMap();
ActionContext context = actionInvocation.getInvocationContext();
HttpServletRequest request = (HttpServletRequest) context.get(StrutsStatics.HTTP_REQUEST);
HttpSession session = null;
if (request != null) {
session = request.getSession(false);
String contextPath = request.getContextPath();
contextPath = contextPath + RequestURIDtls.SEPERATOR;
String reqURI = request.getRequestURI().substring(contextPath.length(), request.getRequestURI().length());
String requestedRole = keyValMap.get(reqURI);
if (requestedRole != null && session != null) {
UserInfoUIForm userForm = (UserInfoUIForm) session.getAttribute(WebConstants.USER_INFO);
if (userForm != null) {
List<Long> userRoleLst = FCCommonUtils.getmenuids(userForm.getRoleId());
if (userRoleLst.contains(new Long(requestedRole))) {
//TODO : GUNJAN : NEED TO DO R&D WHY actionInvocation.invoke() CREATES NULL POINTER EXCEPTION
//returnAction=actionInvocation.invoke();
returnAction = "success";
} else {
returnAction = "unauth.user";
}
} else {
returnAction = "unauth.user";
}
} else {
returnAction = "unauth.user";
}
} else {
returnAction = "unauth.user";
}
return returnAction;
}
In above code returnAction=actionInvocation.invoke() gives null pointer exception.
Here is my struts.xml configuration to access the page ..
<action name="viewCorporate" class="com.ndil.web.corporate.MstCorporateAction" method="viewCorporatePage">
<interceptor-ref name="menuFilterInterceptor" />
<result name="unauth.user">/jsp/unAuthUser.jsp</result>
<result name="success">/jsp/mngCorporate.jsp</result>
</action>
Can any one suggest me why actionInvocation.invoke() gives null pointer exception ???
Thanks,
Gunjan Shah.
Free code review.
1) Intercept result decared as variable, unused.
2) Said value should be a constant anyway.
3) Variable is named incorrectly--it's not an action name, it's a result name.
4) If you're in an interceptor, you've gotten a request--there's just no way for this to be null. If it is null, something far more serious than an unauthorized user has occurred, and the world should blow up.
5) Similarly, unless you've specifically configured your entire app not to create sessions, checking for a session is redundant. If you don't, something has gone horribly wrong. Check for known session attributes to determine if a user is logged in, not for the presence of the session itself--much easier.
IMO both 4 and 5, if handled at all, should be handled with declarative exceptions. In that state, the web app is likely inoperable--peg the user to HTTP 500 or similar.
6) The nested conditionals are way too deep. Strict adherence to "one return per method" creates difficult-to-understand code, particularly when a method has deeply-nested conditionals.
7) It looks like you're relying on form data to determine the user's role. This is inherently insecure; user role information should be kept in the session, where it can't be easily manipulated.
8) Some miscellaneous tweaks leave us with this:
public class FooInterceptor {
private static final String UNAUTHORIZED_USER = "unauth.user";
public String intercept(ActionInvocation actionInvocation) throws Exception {
ActionContext context = actionInvocation.getInvocationContext();
HttpServletRequest request = (HttpServletRequest) context.get(StrutsStatics.HTTP_REQUEST);
if (request == null) {
return UNAUTHORIZED_USER;
}
HttpSession session = request.getSession(false);
if (session == null) {
return UNAUTHORIZED_USER;
}
Long requestedRole = getRequestedRole(request);
if (requestedRole == null) {
return UNAUTHORIZED_USER;
}
UserInfoUIForm userForm = (UserInfoUIForm) session.getAttribute(WebConstants.USER_INFO);
if (userForm == null) {
return UNAUTHORIZED_USER;
}
List<Long> userRoles = FCCommonUtils.getmenuids(userForm.getRoleId());
return userRoles.contains(requestedRole) ? ActionSupport.SUCCESS : UNAUTHORIZED_USER;
}
private Long getRequestedRole(HttpServletRequest request) {
String contextPath = request.getContextPath() + RequestURIDtls.SEPARATOR;
String reqURI = request.getRequestURI().substring(contextPath.length(), request.getRequestURI().length());
try {
return Long.valueOf(FCCommonUtils.getALLMenuIdMap().get(reqURI));
} catch (NumberFormatException e) {
return null;
}
}
}
While testing the method remains relatively difficult, it's much easier to understand the precise testing needs. It's easier to read, because you no longer have to wonder "what if the opposite is true?" as in the deeply-nested code.
Use this:
<action name="viewCorporate" class="com.ndil.web.corporate.MstCorporateAction" method="viewCorporatePage">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="menuFilterInterceptor" />
<result name="unauth.user">/jsp/unAuthUser.jsp</result>
<result name="success">/jsp/mngCorporate.jsp</result>
</action>
Struts won't add this default interceptor automatically when you are explicitly specifying a interceptor for action declaration.
I'm using JSR-286 + Struts 2.2.0 + PortletPlugin 2.2.0
I can't set name for file which user wants to download.
User can get file, but it's name is corrupted. Instead of "myImage.png" user gets "241883e9" or "241563a2".
If users renames downloaded file and opens it he can see that the file is not corrupted. Please, see my code:
file-listing.jsp:
<li onclick="goToAction('<s:url action="downloadattachement" portletUrlType="resource" />', {'attachementId':<s:property value="id" />}, 'POST')"><s:property value="name"/></li>
function "goToAction" dynamically generates from and submits it (I've tried both: POST and GET, it doesn't help.):
<form action="/wps/myportal/!VERY_LONG_PORTAL_URL_GOES_HERE/" method="POST" id="actionUrlTemporaryForm1295987206509"> <input type="hidden" name="attachementId" value="2" /> </form>
my struts xml config file:
<!-- Download attached file by attachementId -->
<action name="downloadattachement" class="ru.portal.DownloadAttachementAction">
<result name="success" type="stream">
<param name="allowCaching">false</param>
<param name="contentType">${contentType}</param>
<param name="inputName">attachementContents</param>
<param name="contentDisposition">>attachment;filename="${fileName}"</param>
<param name="bufferSize">1024</param>
</result>
</action>
And an action code:
#Override
protected String bareExecute() throws Exception {
String result = Action.SUCCESS;
Attachement attachement = EJBUtil.lookup(IAttachementManager.class).get(attachementId);
LOG.info("Trying to download Attachement[{}]", attachement);
File attachementFile = new File(attachement.getPath());
if(attachementFile.exists()){
attachementContents = new FileInputStream(attachementFile);
}else{
LOG.error("There is no attachement[{}] file here[{}]",attachementId, attachement.getPath());
}
return result;
}
public String getContentType(){
return attachement.getMimeType();
}
public String getFileName(){
LOG.trace("#getFileName {}", attachement.getName());
return attachement.getName();
}
public Integer getAttachementId() {
return attachementId;
}
public void setAttachementId(Integer attachementId) {
this.attachementId = attachementId;
}
public Attachement getAttachement() {
return attachement;
}
public InputStream getAttachementContents() {
return attachementContents;
}
#Override
public String getCurrentActionName() {
return "downloadattachement";
}
I've never seen this LOG line in my log file:
LOG.trace("#getFileName {}", attachement.getName());
But I see
[25.01.11 23:26:46:582 MSK] 00000052 srt W com.ibm.ws.webcontainer.srt.SRTServletResponse setHeader WARNING: Cannot set header. Resp
onse already committed.
Seems like I can't set headers for response... :(
What do I do wrong? Please help.
UPD: I've found partial solution:
I've added this code to my action:
PortletActionContext.getResponse().setProperty("content-Disposition", "attachment;filename=\""+attachement.getName()+"\"");
PortletActionContext.getResponse().setProperty("content-Type", attachement.getMimeType());
The problem is in file name now: if it contains non ascii char file name is corrupted.
File names like: "my file.doc", "02.png" work fine.
The problem was in result type="stream" and also in filename attribute value of "Content-disposition" header.
For FF I've used ISO-8859-1, for IE6-8 I've used url-encoding.
I've used user-agent header to determine browser. My solution has only one issue, but for me it's acceptabe: IE8 replaces whitespaces in file names with underscores. For example
"my fav image.png" will be "my_fav_image.png" is IE8.
FF does undestand default encoding for HTTP and doesn't try to corrupt filename attribute value.
You can find additional info here, on StackOverflow.
I've developed a web site using Struts2 as a controller and integrated it with Spring and Hibernate to do the business logic and DB stuff. The website's URIs are http://my.domian.com/URI; which {URI} is dynamically generated thorough the admin cms. The mapping of each uri to the servlet are done with help of Apache mod_rewrite, as follow:
RewriteCond %{HTTP_HOST} ^www\.domain\.com
RewriteRule ^([a-zA-Z0-9_-]+)$ /dynamic\.action?f=$1 [QSA,L]
(Before any further information, is this a good and suitable approach?)
The struts configuration is just a typically-academic one as:
<package name="Default" extends="struts-default" namespace="/">
...
<action name="dynamic" class="DynamicContentAction">
<result name="index">/content/web/dynamic/index.jsp</result>
</action>
</package>
DynamicContentAction is extending ActionSupport and implementing ServletRequestAware, ServletContextAware. I'm checking a couple of things (such as a current visiting language which is identified as a subdomain), looking up in the database that the requested uri is valid or not, generating that uri's content and setting a couple of runtime global variables (such as current visiting page id, layout config due to current visiting language ...) and put it on a Request object in this servlet.
Everything looks good and even works perfectly ok, unless too many dynamic pages being requested by a single user concurrently. "Too Many" in my case is at least 9-10 pages. In this case it throws exceptions, different ones! Sometimes the HttpServletRequest request is null, sometimes ServletContext servletContext is null, some other times these are ok, but the runtime variables are null which is used in business logic or db querying.
I've googled about it and found out that this action is being instantiated "Per Request". Isn't this so? If there is an action per request, what's wrong with this conflict or "nullability thing". Should I do some thread-like thing in that action, beyond the threading of struts?
I'd be so appreciated if you could help me out or point me a direction.
Here is simplified version of DynamicContentAction.java
public class DynamicContentAction extends ActionSupport implements ServletRequestAware, ServletContextAware {
private HttpServletRequest request;
private ServletContext servletContext;
private ResourceSelectorService resourceSelectorService;
private String f = null;
public String execute() {
if ( f != null ) {
HashMap<String, Object> resolvedURI = resourceSelectorService.resolveURI(f);
if ( resolvedURI.get("ERROR").equals(true) ) {
//Generating nice 404 error page content
} else {
//Generating Content
//and put it on request object as:
//request.setAttribute("attrName", resourceContent);
}
}
else {
//Generating nice 404 error page content
}
request = null;
servletContext = null;
f = null;
return "index";
}
#Override
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
#Override
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
public void setF(String f) {
this.f = f;
}
public String getF() {
return f;
}
}
as I'm writing this post, I have came to the knowledge that this class is NOT thread-safe. Is it? So I've changed it a little bit as follow:
Here is newer version of DynamicContentAction.java
public class DynamicContentAction extends ActionSupport {
private ResourceSelectorService resourceSelectorService;
private String f = null;
public String execute() {
if ( f != null ) {
final HttpServletRequest request = ServletActionContext.getRequest();
final ServletContext servletContext = ServletActionContext.getServletContext();
HashMap<String, Object> resolvedURI = resourceSelectorService.resolveURI(f);
if ( resolvedURI.get("ERROR").equals(true) ) {
//Generating nice 404 error page content
} else {
//Generating Content
//and put it on request object as:
//request.setAttribute("attrName", resourceContent);
}
f = null;
}
else {
//Generating nice 404 error page content
}
return "index";
}
public void setF(String f) {
this.f = f;
}
public String getF() {
return f;
}
}
and the Null thing problem is almost gone, but there is still conflict with the generated content. For example if user try to open:
http:// www.domain.com/A
http:// www.domain.com/B
http:// www.domain.com/C
http:// www.domain.com/D
http:// www.domain.com/E
simultaneously, all of the pages will be rendered in browser, but the content of A is shown in A and B, C is correct, and there is a very good chance that the content of D and E are incorrect too.