|
Jun 11
|
The ActionMapper is the component that maps a url onto one of your action classes. More information can be found about it here:
http://struts.apache.org/2.1.6/docs/actionmapper.html
In most applications you won’t need to change the default ActionMapper. A project I am currently working on required that I implement an API specified by a 3rd party. The requests that they send us are all POST requests over HTTPS. Nothing fancy. To determine which method/procedure that they want to call, they send a parameter on the request named ‘function’. I decided that I would implement the receiving service using Struts 2 and create a custom ActionMapper. I did a search, but the results didn’t show any examples of creating a custom ActionMapper, so I downloaded the struts 2 source to see how the default one worked, and then I constructed mine with that as a ‘guide’.
My implementation is rather basic, as it isn’t such a complex requirement.:
import com.opensymphony.xwork2.config.ConfigurationManager;
import com.opensymphony.xwork2.config.entities.ActionConfig;
import org.apache.log4j.Logger;
import org.apache.struts2.dispatcher.mapper.ActionMapper;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
public class SyncActionMapper implements ActionMapper {
private final Logger LOG = Logger.getLogger(getClass());
private static final String UNKNOW_FUNCTION_MAPPING = "unknownFunction";
@Override
public ActionMapping getMapping(HttpServletRequest request,
ConfigurationManager configurationManager) {
Map<String, ActionConfig> actions =
configurationManager.getConfiguration().
getPackageConfig("sync-facade").getActionConfigs();
ActionMapping mapping = new ActionMapping();
mapping.setNamespace("/");
String actionName = request.getParameter("function");
if (actionName == null || actionName.length() < 1) {
LOG.error("function param no found on request " + actionName);
actionName = UNKNOW_FUNCTION_MAPPING;
} else if (!actions.containsKey(actionName)) {
LOG.error("action not found in struts.xml " + actionName);
actionName = UNKNOW_FUNCTION_MAPPING;
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("function param found, "
+ " mapping to action with the name: " + actionName);
}
}
mapping.setName(actionName);
return mapping;
}
@Override
public ActionMapping getMappingFromActionName(String actionName) {
ActionMapping mapping = new ActionMapping();
mapping.setName(actionName);
mapping.setNamespace("/");
return mapping;
}
@Override
public String getUriFromActionMapping(ActionMapping actionMapping) {
throw new IllegalStateException("not implemented");
}
}
I also wanted to map unknown functions to an error action. Checking the struts.xml file and returning a valid ActionMapping is not part of the ActionMapper contract (so the docs say), but I decided to add this here. After getting the function name, I check to see if this function exists in struts.xml using the ConfigurationManager (i may need to optimize this line of code, not sure yet).
To set my custom ActionMapper to be the default I added a reference to it in struts.xml:
<constant name="struts.mapper.class"
value="com.devedup.sync.dispatcher.mapper.SyncActionMapper"/>
I can now map to actions simply from the url http://localhost/myapp?function=myAction (or similarly with the function param in the body of the POST request).