Web Framework - Struts 2

MVC Architecture

struts_architecture

MVC is popular as it isolates the application logic from the user interface layer

Flow: Here the Controller receives all requests for the application and then works with the Model to prepare any data needed by the View. The View then uses the data prepared by the Controller to generate a final presentable response.

Struts 2 Architecture

Struts2 is realized with following five core components:

Struts 2 is slightly different from a traditional MVC framework in that the action takes the role of the model rather than the controller, although there is some overlap. (note: action contains both business logic and model data)

struts_architecture_2

Work Flow

Hello World Example

一个最简单的应用,可以分为三个部分,真好对应了MVC的三个点。

参考 -> http://www.tutorialspoint.com/struts_2/struts_examples.htm

对比Struts2和Spring MVC,其实整个workflow是很类似的。为什么最终大多数人选择了Spring?个人感觉有以下几个原因。

Configuration

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
   http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
   id="WebApp_ID" version="3.0">

   <display-name>Struts 2</display-name>
   
   <welcome-file-list>
      <welcome-file>index.jsp</welcome-file>
   </welcome-file-list>

   <filter>
      <filter-name>struts2</filter-name>
      <filter-class>
         org.apache.struts2.dispatcher.FilterDispatcher
      </filter-class>
   </filter>

   <filter-mapping>
      <filter-name>struts2</filter-name>
      <url-pattern>/*</url-pattern>
   </filter-mapping>
</web-app>

struts.xml

<?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.devMode" value="true" />
   <package name="helloworld" extends="struts-default">

      <action name="hello"
            class="com.tutorialspoint.struts2.HelloWorldAction"
            method="execute">
            <result name="success">/HelloWorld.jsp</result>
      </action>

   </package>
</struts>

Annotation

an alternative to struts.xml

EXAMPLE:

key point: extend ActionSupportclass; @Results, @Result, @Action, @RequiredFieldValidator, @IntRangeFieldValidator

import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import com.opensymphony.xwork2.validator.annotations.*;

@Results({
   @Result(name="success", location="/success.jsp"),
   @Result(name="input", location="/index.jsp")
})
public class Employee extends ActionSupport{
   private String name;
   private int age;

   @Action(value="/empinfo")
   public String execute()
   {
       return SUCCESS;
   }

   @RequiredFieldValidator( message = "The name is required" )
   public String getName() {
       return name;
   }
   public void setName(String name) {
       this.name = name;
   }

   @IntRangeFieldValidator(message = "Age must be in between 28 and 65",
                                      min = "29", max = "65")
   public int getAge() {
       return age;
   }
   public void setAge(int age) {
       this.age = age;
   }
}

struts.properties (Optional)

When set to true, Struts will act much more friendly for developers
struts.devMode = true

Enables reloading of internationalization files
struts.i18n.reload = true

Enables reloading of XML configuration files
struts.configuration.xml.reload = true

Sets the port that the server is run on
struts.url.http.port = 8080

Notice: Actually all of the properties contained within the struts.properties configuration file can also be configured in the web.xml using the init-param, as well using the constant tag in the struts.xml configuration file.

Action

contain model, execute business logic

FLOW:

(.jsp) form (action="doSomething") 
-> 
action class 
-> 
return "success"/"failure" 
-> 
view page(.jsp)

EXAMPLE:

import com.opensymphony.xwork2.ActionSupport;

public class HelloWorldAction extends ActionSupport{
   private String name;

   public String execute() throws Exception {
      if ("SECRET".equals(name))
      {
         return SUCCESS;
      }else{
         return ERROR;
      }
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }
}

Interceptor

e.g. struts.xml:

<?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.devMode" value="true" />
   <package name="helloworld" extends="struts-default">
      <action name="hello"
         class="com.tutorialspoint.struts2.HelloWorldAction"
         method="execute">
         <interceptor-ref name="params"/>
         <interceptor-ref name="timer" />
         <result name="success">/HelloWorld.jsp</result>
      </action>
   </package>
</struts>

->

INFO: Executed action [//hello!execute] took 109 ms.

Result Type

<results> tag plays the role of a view

result type:

e.g. type = dispatcher:

<result name="success" type="dispatcher">
   <param name="location">
      /HelloWorld.jsp
   </param>
</result>

Value Stack/OGNL

a stack where keeps all the model data

e.g. get value stack and store something in action class

ValueStack stack = ActionContext.getContext().getValueStack();
stack.push(...);

e.g. get some value from the stack in jsp

<s:property value="name"/>

e.g. store some data into the stack in jsp

   <form action="hello">
      <input type="text" name="name"/>
      <input type="submit" value="Say Hello"/>
   </form>
   <!--name must match the property in action class-->

View Technology

Struts 2 Tags

Form Validation

Validation in Action Class using validate()

FLOW:

http-request 
-> 
dispacher filter
-> 
interceptors 
-> 
validate() 
->
pass: action class execute()
fail: <result name="input">not validated</result>

EXAMPLE: (key point: validate())

import com.opensymphony.xwork2.ActionSupport;

public class Employee extends ActionSupport{
   private String name;
   private int age;

   public String execute() {
       return SUCCESS;
   }
   public String getName() {
       return name;
   }
   public void setName(String name) {
       this.name = name;
   }
   public int getAge() {
       return age;
   }
   public void setAge(int age) {
       this.age = age;
   }

   public void validate() {
      if (name == null || name.trim().equals(""))
         addFieldError("name","The name is required");
      if (age < 28 || age > 65)
         addFieldError("age","Age must be in between 28 and 65");
   }
}

key point: result input

<?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.devMode" value="true" />
   <package name="helloworld" extends="struts-default">

      <action name="empinfo"
         class="com.tutorialspoint.struts2.Employee"
         method="execute">
         <result name="input">/index.jsp</result>
         <result name="success">/success.jsp</result>
      </action>

   </package>

</struts>

Validation using XML

'[action-class]'-validation.xml

<!DOCTYPE validators PUBLIC
"-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">

<validators>
   <field name="name">
      <field-validator type="required">
         <message>
            The name is required.
         </message>
      </field-validator>
   </field>

   <field name="age">
     <field-validator type="int">
         <param name="min">29</param>
         <param name="max">64</param>
         <message>
            Age must be in between 28 and 65
         </message>
      </field-validator>
   </field>
</validators>

Database Access

就是在 Action Class 里面直接使用 Java JDBC API 连接数据库。

public String execute() {
   String ret = ERROR;
   Connection conn = null;

   try {
      String URL = "jdbc:mysql://localhost/struts_tutorial";
      Class.forName("com.mysql.jdbc.Driver");
      conn = DriverManager.getConnection(URL, "root", "root123");
      String sql = "SELECT name FROM login WHERE";
      sql+=" user = ? AND password = ?";
      PreparedStatement ps = conn.prepareStatement(sql);
      ps.setString(1, user);
      ps.setString(2, password);
      ResultSet rs = ps.executeQuery();

      while (rs.next()) {
         name = rs.getString(1);
         ret = SUCCESS;
      }
   } catch (Exception e) {
      ret = ERROR;
   } finally {
      if (conn != null) {
         try {
            conn.close();
         } catch (Exception e) {
         }
      }
   }
   return ret;
}

http://www.tutorialspoint.com/struts_2/struts_database_access.htm

Struts2 V.S. Struts 1

Action Class

Thread Modeling

Servlet Dependency

Harvesting Input

Binding values into views

Configuration

Front Controller

Read More

Fork me on GitHub