Details how to configure Action in Java's Struts2 framework

  • 2020-05-07 19:43:54
  • OfStack

In Struts2, the Action part, or Controller layer, takes a low intrusion approach. Why do you say that? This is because in Struts2 the action class does not need to inherit any base classes or implement any interfaces, and is not directly coupled to API of Servlet. It is usually more like a normal POJO (which should normally contain an execute method with no arguments), and you can define 1 series of methods (no-argument methods) in the content, and you can configure each method to be used as a separate action for code reuse.
Such as:


package example;

public class UserAction {

    private String username;

    private String password;

  public String execute() throws Exception {

       // ..................... ..

    return  " success " ;

  }

  public String getUsername() {

    return username;

  }

  public void setUsername(String username) {

    this.username = username;

  }

  public String getPassword() {

    return password;

  }

  public void setPassword(String password) {

    this.password = password;

  }

}

action access servlet

Properties in the Action class can encapsulate both arguments and results. The system doesn't strictly distinguish between them.

However, in order to make the Action class developed by users more standardized, Struts2 provides us with an interface Action, which is defined as follows:


publicinterface Action {

  publicstaticfinal String ERROR="error";

  publicstaticfinal String INPUT="input";

  publicstaticfinal String NONE="none";

  publicstaticfinal String LOGIN="login";

  publicstaticfinal String SUCCESS="success";

  public String execute()throws Exception;

}

However, we write Action not to implement the interface in general, but to inherit the implementation class ActionSupport of the interface.

The code of this class is as follows:


public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable {

   ................

  public void setActionErrors(Collection errorMessages) {

    validationAware.setActionErrors(errorMessages);

  }

  public Collection getActionErrors() {

    return validationAware.getActionErrors();

  }

  public void setActionMessages(Collection messages) {

    validationAware.setActionMessages(messages);

  }

  public Collection getActionMessages() {

    return validationAware.getActionMessages();

  }

    public Collection getErrorMessages() {

    return getActionErrors();

  }

    public Map getErrors() {

    return getFieldErrors();

  }

// Set the form field to check for errors 

  public void setFieldErrors(Map errorMap) {

    validationAware.setFieldErrors(errorMap);

  }

  public Map getFieldErrors() {

    return validationAware.getFieldErrors();

  }

  public Locale getLocale() {

    ActionContext ctx = ActionContext.getContext();

    if (ctx != null) {

      return ctx.getLocale();

    } else {

      LOG.debug("Action context not initialized");

      return null;

    }

  }

// Methods for obtaining internationalization information 

  public String getText(String aTextName) {

    return textProvider.getText(aTextName);

  }

  public String getText(String aTextName, String defaultValue) {

    return textProvider.getText(aTextName, defaultValue);

  }

  public String getText(String aTextName, String defaultValue, String obj) {

    return textProvider.getText(aTextName, defaultValue, obj);

  }

    .........

// Methods for accessing internationalized resource bundles 

  public ResourceBundle getTexts() {

    return textProvider.getTexts();

  }

  public ResourceBundle getTexts(String aBundleName) {

    return textProvider.getTexts(aBundleName);

  }

// add action Error message 

  public void addActionError(String anErrorMessage) {

    validationAware.addActionError(anErrorMessage);

  }

// add action General information 

  public void addActionMessage(String aMessage) {

    validationAware.addActionMessage(aMessage);

  }

  public void addFieldError(String fieldName, String errorMessage) {

    validationAware.addFieldError(fieldName, errorMessage);

  }

   

  public void validate() {

  }

  public Object clone() throws CloneNotSupportedException {

    return super.clone();

  }

..........

}

As mentioned earlier, struts2 is not directly coupled to API of Servlet, so how does it access API of Servlet?

An ActionContext class was provided in the original struts2, which simulates API of Servlet. The main methods are as follows:

1)Object get (Object key) : this method simulates the HttpServletRequest.getAttribute(String name) method.

2)Map getApplication() returns an Map object, which simulates an ServletContext instance.

3)static ActionContext getContext(): get the ActionContext instance of the system.

4)Map getSession(): returns an Map object that simulates an HttpSession instance.

5)Map getParameters(): get all request parameters, simulate HttpServletRequest.getParameterMap ()

You may wonder why these methods always return 1 Map? This is mainly for testing purposes. As for how it converts Map objects to actual Servlet API instances, we don't have to worry about that at all, because struts2 already has some interceptors built in to help us with this conversion.

To use Servlet's API directly, Struts2 provides us with the following interfaces.

1) ServletContextAware: the Action implementing the interface can directly access the ServletContext instance.

2) ServletRequestAware: Action that implements this interface can directly access HttpServletRequest instances.

3) ServletResponseAware: Action implementing the interface can directly access HttpServletResponse instances.

Since action accesses servlet, let's take a look at how Action of Struts2 implements code reuse. So for UserAction, how do I rewrite action if I want this action to handle both user registration (regist) and login (longin)? UserAction after rewriting is as follows:


package example;

public class UserAction extends ActionSupport {

    private String username;

    private String password;

  public String regist() throws Exception {

       // ..................... ..

    return SUCCESS;

  }

public String login() throws Exception {

       // ..................... ..

    return SUCCESS;

  }

  public String getUsername() {

    return username;

  }

  public void setUsername(String username) {

    this.username = username;

  }

  public String getPassword() {

    return password;

  }

  public void setPassword(String password) {

    this.password = password;

  }

}

struts. action configuration in xml
Is
ok? Of course not. We still have to configure 1 in struts.xml. There are two configuration methods:

1)           specifies method attributes for Action elements in the normal way.


<action name= " loginAction "  class= " example.UserAction "  method= " login " >

    <result name= " success " >/success.jsp</result>

</action>

<action name= " registAction "  class= " example.UserAction "  method= " regist " >

    <result name= " success " >/success.jsp</result>

</action>

2)           specifies method attributes for Action elements in a wildcard manner.


<action name= " *Action "  class= " example.UserAction "  method= " {1} " >

    <result name= " success " >/success.jsp</result>

</action>

The use of wildcards is too flexible. Here is a more complex configuration.


<action name= " *_* "  class= " example.{1}Action "  method= " {2} " >

 ...... .

</action>

Where the placeholder {1} matches the first * of _, and {2} matches the last *.

annotation-based Action configuration:
The configuration of Action described below is not in src/ struts.xml, but is configured using annotations
The premise is that in addition to the basic six jar packages, one struts-2.1.8.1 \lib\ struts2-convention-plugin-2.1.8.1.jar
But struts.xml will have it
Concrete example
Login.jsp
 


<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html> 
 <head> 
  <title>Struts2 Login authentication </title> 
  <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 
  <meta http-equiv="description" content="This is my page"> 
  <!-- 
  <link rel="stylesheet" type="text/css" href="styles.css"> 
  --> 
 </head> 
  
 <body> 
 <h3>Struts2 The login </h3><hr/> 
  <form action="${pageContext.request.contextPath}/user/login.qqi" method="post"> 
    <table border="1" width="500px"> 
      <tr> 
        <td> The user name </td> 
        <td><input type="text" name="loginname"/></td> 
      </tr> 
      <tr> 
        <td> password </td> 
        <td><input type="password" name="pwd"/></td> 
      </tr> 
      <tr> 
        <td colspan="2"><input type="submit" value=" The login "/></td> 
      </tr> 
    </table> 
  </form> 
 </body> 
</html> 

  src/struts.xml
 


<span style="font-size: large;"><?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE struts PUBLIC 
  "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN" 
  "http://struts.apache.org/dtds/struts-2.1.7.dtd"> 
 
<struts> 
  <!--  How the request parameters are encoded  --> 
  <constant name="struts.i18n.encoding" value="UTF-8"/> 
  <!--  Specified by struts2 The type of request suffix being processed. Multiple are separated by commas  --> 
  <constant name="struts.action.extension" value="action,do,go,qqi"/> 
  <!--  when struts.xml After the change, whether to reload. The default value is false( Used in production environment ), The development phase is best opened  --> 
  <constant name="struts.configuration.xml.reload" value="true"/> 
  <!--  Whether to use struts Development mode. Development mode has more debugging information. The default value is false( Used in production environment ), The development phase is best opened  --> 
  <constant name="struts.devMode" value="false"/> 
  <!--  Sets whether the browser caches static content. The default value is true( Used in production environment ), The development phase is best closed  --> 
  <constant name="struts.serve.static.browserCache" value="false" /> 
  <!--  Specified by the spring To be responsible for the action Object creation   
  <constant name="struts.objectFactory" value="spring" /> 
  --> 
  <!--  Whether to enable dynamic method invocation  --> 
  <constant name="struts.enable.DynamicMethodInvocation" value="false"/> 
</struts></span> 

 
  LoginAction.java
 


package com.javacrazyer.web.action; 
 
import org.apache.struts2.convention.annotation.Action; 
import org.apache.struts2.convention.annotation.ExceptionMapping; 
import org.apache.struts2.convention.annotation.ExceptionMappings; 
import org.apache.struts2.convention.annotation.Namespace; 
import org.apache.struts2.convention.annotation.ParentPackage; 
import org.apache.struts2.convention.annotation.Result; 
import org.apache.struts2.convention.annotation.Results; 
 
import com.opensymphony.xwork2.ActionSupport; 
 
/** 
 *  Use annotations to configure Action 
 * 
 */ 
@ParentPackage("struts-default") 
//  Parent package  
@Namespace("/user") 
@Results( { @Result(name = "success", location = "/msg.jsp"), 
    @Result(name = "error", location = "/error.jsp") }) 
@ExceptionMappings( { @ExceptionMapping(exception = "java.lange.RuntimeException", result = "error") }) 
public class LoginAction extends ActionSupport { 
  private static final long serialVersionUID = -2554018432709689579L; 
  private String loginname; 
  private String pwd; 
 
  @Action(value = "login") 
  public String login() throws Exception { 
 
    if ("qq".equals(loginname) && "123".equals(pwd)) { 
      return SUCCESS; 
    } else { 
      return ERROR; 
    } 
  } 
 
  @Action(value = "add", results = { @Result(name = "success", location = "/index.jsp") }) 
  public String add() throws Exception { 
    return SUCCESS; 
  } 
 
  public String getLoginname() { 
    return loginname; 
  } 
 
  public void setLoginname(String loginname) { 
    this.loginname = loginname; 
  } 
 
  public String getPwd() { 
    return pwd; 
  } 
 
  public void setPwd(String pwd) { 
    this.pwd = pwd; 
  } 
 
}

 
I won't post success.jsp and error.jsp

Annotate the explanation of the configuration
 
  1) @ParentPackage specifies the parent package
  2) @Namespace specifies the namespace
  3) @Results 1 array of results
  4) @Result (name="success",location="/ msg.jsp ") mapping of 1 result
  5) @Action (value="login") request URL that specifies a request handling method. Note that it cannot be added to the Action class; it is added to a method.
  6) @ExceptionMappings 1 - level array to declare exceptions
  7) @ExceptionMapping maps 1 declaration exception

Because this way is not very common, so we just do to understand


Related articles: