I remember I've read this from somewhere but still unsure.
consider scenario below:
<action name="doSomething" class="com.domain.MyAction" method="myMethod">
</action>
and
public class MyAction extends ActionSupport{
public String myMethod(){
private String param;
}
//getter
//setter
}
then via web page I do POST o GET: domain/doSomething?param=hello
I can recover "param" value using any method below, are they the same?
this.getParam();
(String)request.getParameter("param");
(String)request.getSession.getAttribute("param");
if so, then struts will always put request parameters into http_session?
Struts uses getters and setters of request parameters to pass them in the action.
public class MyAction extends ActionSupport{
private String param;
public void setParam(String p){ param=p; }
public String getParam() { return param; }
public String myMethod(){
System.out.println("Got the request parameter automatically just by having a getter and setter for that parameter " + param);
}
}
Related
I'm passing parameter projectId to Struts action
http://localhost:8080/app/myaction.action?projectId=100
Simple action class is defined as:
public class MyAction extends AnyStrutsAction {
private ParamReader paramReader = new ParamReader();
public ParamReader getParamReader() {
return paramReader;
}
public void setProjectId(String id) {
getParamReader().setProjectId(id);
}
public void execute()
// ...
}
}
And everything works ok (/)
Next method setProjectId is extracted to interface and implemented as Java8 default method:
public interface ParamReaderAware {
ParamReader getParamReader();
default void setProjectId(String id) {
getParamReader().setProjectId(id);
}
}
public class MyAction extends AnyStrutsAction implements ParamReaderAware {
private ParamReader paramReader = new ParamReader();
#Override
public ParamReader getParamReader() {
return paramReader;
}
public void execute()
// ...
}
}
Now calling
http://localhost:8080/app/myaction.action?projectId=100
does not set parameter projectId. The default implementation is not visible for struts
My question is:
- does Struts2 support default interface method ?
- Is there any way to do so (any struts configuration, version (currentyly im using 2.3.16) )
Why I extract method to interface.
- I want to add reading parameter feature to multiple class actions
HI i have created one action, that contain one Document Object. I want to display those properties in jsp. i used to struts tag i am not able to get it , i am able to get string property of action , but not Object can you please help me... se my code below. i went all suport. i am not able to fix it. i am using tomcat7 .
public class SearchResultAction extends ActionSupport{
private static Logger log = Logger.getLogger(SearchResultAction.class);
private String name;
private DocumentData documentData;
public String execute() throws Exception {
documentData=new DocumentData();
documentData.setdocName("docName");
documentData.setdDocTitle("docTitle");
if (documentData!=null)
{
return SUCCESS;
}else{
return ERROR;
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public DocumentData getDocumentData() {
return documentData;
}
public void setDocumentData(DocumentData documentData) {
this.documentData = documentData;
}
}
My jsp code is:
<s:property value="documentData.docName" default="object is null"/>
My pojo class is:
public class DocumentData {
String docName;
String dDocTitle;
String dDocDate;
String dDocAuther;
// setters and getters for all property
}
Your docName setter doesn't follow JavaBean conventions; does your getter?
E.g., setdocName should be setDocName, the getter getDocName.
OGNL is going to call getDocName(), if the method doesn't exist, you won't get data.
I have a Java EE 6 web application and use the WebSocket protocol to communicate with browsers. The browser can send various types of messages and in the servers onMessage method I would like to route (or dispatch) the message to a specific message handler class depending on the message type. I would like to configure or register these message handlers via annotations, similar to the mechanism of servlets (#WebServlet("/there")). And like in servlets, I would like to be able to use CDI injection in the message handlers.
For now I have a MessageType annotation, a MessageHandler interface and 3 implementations.
#Documented
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface MessageType
{
String value();
}
public interface MessageHandler
{
public void processMessage(String inputMesssage);
}
#MessageType("first")
public class FirstMessageHandler implements MessageHandler
{
#Inject
ResourceBundleProvider resourceBundleProvider;
#Override
public void processMessage(String inputMesssage)
{
System.out.println("FirstMessageHandler#processMessage: " + inputMesssage);
System.out.println("InjectionTest: " + resourceBundleProvider.getValue("label.language"));
}
}
#MessageType("second")
public class SecondMessageHandler implements MessageHandler
{
#Override
public void processMessage(String inputMesssage)
{
System.out.println("SecondMessageHandler#processMessage: " + inputMesssage);
}
}
public class DefaultMessageHandler implements MessageHandler
{
#Override
public void processMessage(String inputMesssage)
{
System.out.println("DefaultMessageHandler#processMessage: " + inputMesssage);
}
}
I also have a class MessageDispatcher which uses reflections to scan the classpath for the annotated message handlers, instantiates them and puts them into a map:
#ApplicationScoped
public class MessageDispatcher
{
private Map<String, MessageHandler> messageHandlerMap = new HashMap<String, MessageHandler>();
#Inject
DefaultMessageHandler defaultMessageHandler;
public MessageDispatcher()
{
registerAnnotatedHandlers();
}
private void registerAnnotatedHandlers()
{
Reflections reflections = new Reflections("namespace");
try
{
for (Class<?> annotatedClass : reflections.getTypesAnnotatedWith(MessageType.class))
{
String annotationValue = annotatedClass.getAnnotation(MessageType.class).value();
for (Class<?> interfaceClass : annotatedClass.getInterfaces())
if (!annotationValue.isEmpty() && interfaceClass.equals(MessageHandler.class))
messageHandlerMap.put(annotationValue, (MessageHandler) annotatedClass.newInstance());
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
public MessageHandler getMessageHandler(String key)
{
MessageHandler messageHandler = messageHandlerMap.get(key);
return messageHandler != null ? messageHandler : defaultMessageHandler;
}
}
And finally in my websocket servlet's onMessage method I extract the key from the inbound message and use it for the message routing:
public synchronized void onMessage(String data)
{
String[] message = data.split(":");
// Choose the message handler from the message
MessageHandler messageHandler = messageDispatcher.getMessageHandler(message[0]);
// Process the message by the message handler
messageHandler.processMessage(message[1]);
}
My 3 incoming sample messages are:
"first:Message to handle with FirstMessageHandler"
"second:Message to handle with SecondMessageHandler"
"third:Message to handle with DefaultMessageHandler"
This works fine, The first and second messages are processed by FirstMessageHandler and SecondMessageHandler respectively. The third message is processed by the default message handler since there is no other handler registered for handling the key "third".
My Problem: I cannot use injection in the message handlers because they are created using Java reflection. Does anybody know how to get annotation processing and CDI injection 'married'? Or does anybody think this approach is bullshit and has another solution for that?
Best Regards
Sebastian
This is my final approach:
I spend a PostConstruct method to my MessageDispachter where I look for all message handler beans. For each of these beans I get their annotation value and a reference to the bean (which also includes creation of the bean). Then I store both, the annotation value and the bean reference into my messageHandlerMap. There is a lot of CDI delegating and interception involved, but it works:
public class MessageDispatcher
{
private Map<String, MessageHandler> messageHandlerMap = new HashMap<String, MessageHandler>();
#Inject
DefaultMessageHandler defaultMessageHandler;
#Inject
BeanManager beanManager;
#PostConstruct
public void registerHandlers()
{
Set<Bean<?>> messageHandlerBeans = beanManager.getBeans(MessageHandler.class, new MessageTypeLiteral());
for (Bean<?> bean : messageHandlerBeans)
{
String key = bean.getBeanClass().getAnnotation(MessageType.class).value();
if (!key.isEmpty())
{
CreationalContext<?> creationalContext = beanManager.createCreationalContext(bean);
MessageHandler messageHandler = (MessageHandler) beanManager.getReference(bean, MessageHandler.class, creationalContext);
messageHandlerMap.put(key, messageHandler);
}
}
}
public MessageHandler getMessageHandler(String key)
{
MessageHandler messageHandler = (MessageHandler) messageHandlerMap.get(key);
return messageHandler != null ? messageHandler : defaultMessageHandler;
}
}
#Documented
#Qualifier
#Retention(RUNTIME)
#Target({TYPE, METHOD, FIELD, PARAMETER})
public #interface MessageType
{
#Nonbinding
String value();
}
#SuppressWarnings("all")
public class MessageTypeLiteral extends AnnotationLiteral<MessageType> implements MessageType
{
private static final long serialVersionUID = 1L;
#Override
public String value()
{
return "";
}
}
public class DefaultMessageHandler implements MessageHandler
{
#Inject
ResourceBundleProvider resourceBundleProvider;
#Override
public void processMessage(String inputMesssage)
{
...
#MessageType("first")
public class FirstMessageHandler implements MessageHandler
{
#Inject
ResourceBundleProvider resourceBundleProvider;
#Override
public void processMessage(String inputMesssage)
{
...
The #NonBinding annotation in the #MessageType annotation seems to be important to find all beans annotated with #MessageType("xxx") independent of the actual annotation value (here: xxx).
I hope this explains the important things. For further details please ask me
Sebastian
I think your simplest solution to this would be to keep what you have, strip out the scanning because you don't need it, change your annotation to be a qualifier and fire a CDI event with the qualifier (you'll need to create an AnnotationLiteral for each of three different qualifiers because the value is binding) and the message as the payload.
I can explain more if you need it.
See and adjust Dynamically fire CDI event with qualifier with members
It is a CDI way for dynamic runtime selecting services by runtime decision. The TypeEnum can also be a String.
I am using struts 2 together with the convention plugin and am seeing strange behaviour. The execute() of my class is not being called but the execute() in the superclass ActionSupport is being called instead. Thus my business logic is not being executed. In this example, the message attribute obtained in the view is null. When I tried to abandon the convention plugin and declared the action in struts.xml, it worked fine. Below is my code.
public class HelloAction extends ActionSupport {
private String message;
#Override
public String execute() {
message = new Date().toString();
return SUCCESS;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
Any help is appreciated.
Thanks and regards,
M Cachia
There is nothing to do with the given code, its working fine in my system and the controller going into the execute() method HelloAction class. I used below xml configuration its working fine.
<action name="test" class="com.HelloAction">
<result>/jsp/results.jsp</result>
</action>
Please check with the configuration file.
For example, I have an URL: /test.action?a=1&b=2
Now I want in jsp page use to get only "a=1&b=2" out of the URL, how to do this?
Action Code
public class MyAction extends ActionSupport {
private String a;
private String a;
public String execute() throws Exception {
// do something here
return SUCCESS;
}
public String getA() {
return a;
}
public void setA(final String a) {
this.a= a;
}
public String getB() {
return b;
}
public void setB(final String b) {
this.a= a;
}
}
Using Struts tags:
<s:property value="a"/>
<s:property value="b"/>
Still i am not sure what exactly is your requirement as its not very clear from your question
Just a side note <s:url> This tag is used to create a URL