I'm developing BBS in struts2 and tiles(2) framework.
I want to push a value in ActionSupport class and pop the value in layout.jsp of tiles. but i just keep failing to access to the value.
I will explain my works step by step.
1) Users click a link to view an article at list page. And BoardView class will be called as defined in struts.xml
--list.jsp--
${ subject }
--struts.xml--
<action name="View_board" class="board.BoardView">
<result type="tiles">board.view</result>
</action>
2)Action class will put title into the value stack... right?
--BoardView class--
public class BoardView extends ActionSupport
private String title;
public void Execute() throws Exception {
...
setTitle(board.getSubject());
return SUCCESS;
}
...
(setter and getter of title)
3) As ActionClass returns SUCCESS, it will go to tiles definition named board.view
--struts.xml--
<action name="View_board" class="board.BoardView">
<result type="tiles">board.view</result>
</action>
4)Here's the tiles-def.xml and the problem. I think the value of 'title' can't be popped from value stack.
==tiles-def.xml==
<definition name="board.view" extends="layout">
<put-attribute name="title" value="%title" />
<put-attribute name="body" value="/board/view.jsp" />
</definition>
(I can't indent with tags... sorry)
Here's the layout.jsp
==layout.jsp==
...
<title><tiles:getAsString name="title" /></title>
...
I tried to replace the value attribute to %{title}, $title and ${title}. But nothings worked out. Web Browser just shows the string itself($title).
I don't know what to do... please help me.
I hope you all understand my works despite my bad explanation.
As my solution on current Project.
In template jsp: put <c:out value="${pageTitle}" default="My Title"></c:out>
So, in every actions class, you should create the variable pageTitle to DYNAMIC Title.
Related
I'm having an issue removing the #Action and #Result Convention plugin annotations from an action and replacing them with the equivalent config in struts.xml.
package com.microed.cars.web;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Result;
import com.opensymphony.xwork2.ActionSupport;
public class HomeAction extends ActionSupport {
#Action(results = {
#Result(location = "/jsp/home.jsp")
})
#Override
public String execute() throws Exception {
return super.execute();
}
}
When these annotations are there, I can successfully access localhost:port/context/home.action
When I remove the annotations I get 'no result defined for action..... ' struts error, despite there being a 'capture all' result in struts.xml - the entire struts.xml is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
"http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<constant name="struts.devMode" value="true"/>
<constant name="struts.convention.package.locators" value="web"/>
<constant name="struts.convention.default.parent.package" value="beetroot"/>
<package name="beetroot" extends="json-default">
<action name="home" class="homeAction">
<result>/jsp/home.jsp</result>
</action>
<action name="cars" class="baseCarsAction">
<result name="input" type="json">
<param name="root">autoResults</param>
/jsp/home.jsp
</result>
</action>
</package>
</struts>
It extends json-default because I need the json result type for an autocomplete function.
I don't know why it's not picking up the action mapping for the homeAction class. I know struts.xml is being read because if I remove the action mapping "cars" then the autocomplete is disabled (but this needs the annotations which I'm trying to remove in order to validate this).
I know that 'no result defined' is a simple error, usually caused by spelling/capitalization errors but this is definitely not the case here, it's simply seems to be ignoring the whole "home" action mapping.
When stepping through DefaultActionInvocation.createResult, there are no 'results' at all for it to try to match against.
As it stands the cars action declaration isn't valid (nor does it make sense, IMO):
<action name="cars" class="baseCarsAction">
<result name="input" type="json">
<param name="root">autoResults</param>
<param name="location">/jsp/home.jsp</param>
</result>
</action>
That said: if it's a JSON result, a JSP isn't helpful, and it'll be ignored (or downright rejected, I'm not sure if it's an error or not). A single result will be either JSON, or HTML.
Turn logging up to DEBUG level to catch startup errors to narrow the range of possible causes.
If baseAction is configured in your Spring config file (which is unnecessary if you're using Spring annotations for injection) the configuration for the home action is valid.
I'd be wary of deploying the convention plugin if you're not actually using it: it changes how actions are mapped; it may have an impact on the surrounding application and cause problems. Stick with one or the other, avoid both–it makes it harder to reason about the source of application behavior.
Unrelated, but I recommend putting JSP pages under /WEB-INF to disallow direct client access.
i've got a form with 3 fields, two String (one select and a text field) and an int. When i put a letter or something else than an int (52.4 or aaa) in the field i got an error that i cannot "catch", my select disapear and on the message box i ve got a message from my validation xml file (in french) and another one in english (i suppose sent by struts).
error in tomcat :
(ognl.OgnlValueStack 60 ) Error setting expression 'userSize' with value '[Ljava.lang.String;#14aa6c3'
error on message box :
Invalid field value for field "userSize".
test size
JSP code :
<s:form action="sendUserCreation" method="POST">
<s:action namespace="/" name="civilityPicklist" executeResult="true"/><br />
<s:textfield name="lastName" /><br />
<s:textfield name="userSize" /><br />
struts.xml code :
<action name="createUser">
<result>/jsp/user/create.jsp</result>
</action>
<action name="sendUserCreation" class="fr.action.UserAction" method="createUser">
<result>/jsp/splash.jsp?messKey=${messKey}</result>
<result name="input">/jsp/user/create.jsp</result>
</action>
<action name="civilityPicklist" class="fr.imaps.oxygene.portal.action.CivilityPicklistAction">
<result>/jsp/user/civilityPicklist.jsp</result>
</action>
UserAction-validation.xml code:
<validators>
<field name="userSize">
<field-validator type="conversion">
<message>test size</message>
</field-validator>
</field>
</validators>
UserAction code :
private int userSize;
public int getUserSize() {
return userSize;
}
public void setUserSize(int userSize) {
this.userSize = userSize;
}
I thought the "conversion" validation type will "catch" this kind of problem but it seems not... what's wrong with my code ?
I've been taking a quick look at this and I think that the reason for the double message is that, in my case at least, it looks like conversion errors may be being handled twice, firstly by the StrutsConversionErrorInterceptor and again by the AnnotationValidationInterceptor. Both these interceptors are in the struts-default stack.
Removing the StrutsConversionErrorInterceptor from the stack removes the Struts generated message and leaves the user defined message as the only error message displayed. However, I've not had time yet to investigate any other side consequences of removing this inreceptor.
(Sorry for the length of the post!!)
edit:
By dynamically I mean--> when the selection of a drop down changes I want the contents of other drop downs to change as well. Thanks!!
I am trying to dynamically populate dropdown menu in jsp (I guess this is a very common question). I am using struts 2 framework.
I found some solutions by googling and from some books but most of them required a lot of scripting in the jsp page, which I dont want to do, cause I think it is not a good practice.
I was hoping to find a way where I could call an action from an onChange event where all the coding part could be done (ofcourse some scripting will be used :) ) .
One way I found was by using dojo. I implemented it and its working fine except for 2 problems:
The action gets called on loading of the page itself, even when the selection of any of the drop downs has not changed.
Following error message is displayed just above the form which has the drop down menus --> "Error loading '/GetLists.htm' (500 Internal Server Error)".
One more question I want to ask is that wether this is a good way to implement dynamically populated drop downs or not. And is my notion of avoiding scripts on jsp pages right or not.
Here are the codings:
The jsp page:
<s:form id="lists" action="viewDayReport">
<s:url id="scriptURL" action="GetLists"/>
<sd:div listenTopics="getLists" href="%{scriptURL}" formId="lists" showLoadingText="Working..."/>
<s:select label="Customer " name="customer" headerKey="0" headerValue="Select" list="customerList" onchange="dojo.event.topic.publish('getLists');return false;"/>
<s:select label="Contact " name="contact" headerKey="0" headerValue="Select" list="contactList" onchange="dojo.event.topic.publish('getLists');return false;"/>
<s:select label="Employee " name="employee" headerKey="0" headerValue="Select" list="employeeList" onchange="dojo.event.topic.publish('getLists');return false;"/>
<s:select label="Stage " name="stage" headerKey="0" headerValue="Select" list="stageList" onchange="dojo.event.topic.publish('getLists');return false;"/>
<s:select label="Type " name="type" headerKey="0" headerValue="Select" list="typeList" onchange="dojo.event.topic.publish('getLists');return false;"/>
<sd:datetimepicker label="Date" name="date" displayFormat="dd/MM/yyyy" />
<s:submit value="View Report(s)"/>
</s:form>
This is the struts config file:
<struts>
<package name="Deutek.admin" extends="struts-default" >
<result-types>
<result-type name="tiles" class="org.apache.struts2.views.tiles.TilesResult" />
</result-types>
//this is the action that is executed when the page first loads. It populates the lists for drop downs
<action name="dayReportPage" class="admin.dayReportAction">
<result type="tiles">dayReport</result>
</action>
//this is the action that is executed when a drop down selection is changed. currently the action just prints some output.
<action name="GetLists" class="admin.GetListsAction">
<result type="tiles">dayReport</result>
</action>
</package>
</struts>
I would suggest ether 1. populating it from your struts action class or 2. via static method invocation at the jsp level.
If you want to set the lists up in your struts action, you can do it by implementing Preparable in the action:
public MyAction extends ActionSupport implements Preparable{
private List customerList;
public void prepare(){
customerList= CustomersDAO.getCustomerList();
}
// Getters and Setters
}
You can then get the list from the jsp like this:
<s:select label="Customer " name="customer" headerKey="0" headerValue="Select"
List="customerList"/>
To set up dynamic method invocation you can access the CustomersDAO object from the previous example directly something like this:
<s:select label="Customer " name="customer" headerKey="0" headerValue="Select"
List="#com.mypackage.CustomersDAO#getCustomerList()"/>
To enable static method access set the struts2 constant in the struts.properties file:
struts.ognl.allowStaticMethodAccess=true
All you need is a doubleselect tag.
Here's a good example.
On default I want my struts2 app to forward to an action:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="false" />
<package name="myApp" namespace="/myApp" extends="struts-default">
<action name="Login_*" method="{1}" class="myApp.SessionManager">
<result name="input">/myApp/Login.jsp</result>
<result type="redirectAction">Menu</result>
</action>
</package>
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="index" />
<action name="index">
<result type="redirectAction">
<param name="actionName">Login_input.action</param>
<param name="namespace">/myApp</param>
</result>
</action>
</package>
</struts>
I'm looking for the application to call SessionManager.input(), but instead it calls SessionManager.execute().
You don't want typically a public input() method. The most basic and typical scenario for an Action is:
The Action is intended to "do something" (one thing), and this action needs some user input.
The Action does than something in the method execute()
If the Action did succesfully that something, it returs SUCCESS. This triggers a result informative JSP page.
If the Action didn't get the user input (because there wasn't any, or because it was insufficient or wrong) it returns INPUT. This triggers a "input form" JSP so that the user can fill the data and (re)try the action.
Now, this basic scenario can be coded in several ways, among them:
1) Two different mappings, one for the input form, other for the execution
<!-- default action class: execute does nothing, returns SUCCES -->
<action name="ActionXXXShowForm">
<result>/myApp/XXXForm.jsp</result>
</action>
<action name="ActionXXX" class="myApp.XXXAction">
<result name="input">/myApp/XXXForm.jsp</result>
<result>/myApp/XXXDone.jsp</result>
</action>
2) Just one mapping
<action name="ActionXXX" class="myApp.XXXAction">
<result name="input">/myApp/XXXForm.jsp</result>
<result>/myApp/XXXDone.jsp</result>
</action>
Both are very similar (specially if your are doing programmatic validation).
In both cases, we have only a "struts" method in the action (execute), which is good practice as our action only "does one thing".
But in the second case, we need to deal with the case in which no data is post, and dont emit an error message for that case.
Example: In case 1:
public class XXXAction extends ActionSupport {
...
public String execute() throws Exception {
if(! inputOk()) return INPUT;
// .. do your stuff
return SUCCESS;
}
private boolean inputOk() {
// ... check your inputs - sort of programatic validation
if( surname == null ) addActionError("no surname");
// .... more checks
return ! hasActionErrors());
}
}
In case 2 you modify it slightly:
public class XXXAction extends ActionSupport {
....
public String execute() throws Exception {
if( emptyInput() ) return INPUT; // no error messages in this case
if(! inputOk()) return INPUT;
// .. do your stuff
return SUCCESS;
}
private boolean inputOk() {
// same as before
}
private boolean emptyInput() {
// detect no input was sent. do not emit errors herer
}
}
When you call an actions from jsp, the default method is execute(). If you want to call another method, you can spec by the attribute method="".
<s:url action="SessionManager" method="input"/>
The attribute method is common on other tags.
If you are using a <s:a... tag, then you will not be able to call the intended method apart from the default execute() method. Instead of <s:a... tag, you need to define the action using an <s:url... tag with an id and call the same using normal html anchor tag ie.,
<a href=${<<id>>} but you may need to specify the method in your struts.xml or any other xml configuration file, which you have included in your struts.xml file with the method attribute in your <action... method="..." clause.
In my struts2 application I am using “File Upload Interceptor”. Its running well but after uploading when same jsp page appears it does not show browsed file name in the textbox of <s:file> tag i.e textbox comes empty after successful uploading.
Here is my code snippet-
main.jsp
<s:form action="smAction" enctype="multipart/form-data" theme="simple">
<s:file name="sample"/>
<s:submit action="uploadSample" value="All upload" />
</s:form>
struts.xml
<action name=" uploadSample " class=" UploadMySample">
<interceptor-ref name="defaultStack"/>
<result name="input"> /login.jsp</result>
<result name="success">/main.jsp</result>
</action>
UploadMySample.java
public class UploadMySample extends ActionSupport {
private File sample;
private String sampleContentType;
private String sampleFileName;
public File getSample () {
return sample;
}
public void setSample (File sample) {
this. sample = sample;
}
//Here is the file uploading code
return SUCCESS;
}
Please suggest.
This is not a problem of Struts. For security reasons modern browser don't allow to set a value for file upload fields. If you want to display the file name after the upload you'll have to use simple text.