In Struts2, the Action part, that is, the Controller layer, adopts a low intrusion method. Why do you say so? This is because in Struts2 action class does not need to inherit any base class or implement any interface, nor is it directly coupled with the Servlet API. It is usually more like a normal POJO (usually should contain an execute method without parameters), and can define a series of methods (no parameter methods) in the content, and can be used as an independent action through configuration, thereby realizing code reuse.
For example:
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
The properties in this Action class can encapsulate parameters and process results. The system does not strictly distinguish them.
However, in order to make the user-developed Action class 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, when we write Action, we usually do not implement the interface, but 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 form field verification error 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; } }// Method to obtain international 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 used to access international resource packages public ResourceBundle getTexts() { return textProvider.getTexts(); } public ResourceBundle getTexts(String aBundleName) { return textProvider.getTexts(aBundleName); }//Add an error message of action public void addActionError(String anErrorMessage) { validationAware.addActionError(anErrorMessage); }//Add ordinary information of action 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 with the Servlet API, so how does it access the Servlet API?
It turns out that struts2 provides an ActionContext class, which simulates the Servlet API. The main methods are as follows:
1)Object get (Object key): This method simulates the HttpServletRequest.getAttribute(String name) method.
2) Map getApplication() returns a Map object that simulates a ServletContext instance.
3)static ActionContext getContext(): Get the ActionContext instance of the system.
4)Map getSession(): Returns a Map object that simulates an HttpSession instance.
5)Map getParameters(): Get all request parameters, simulated HttpServletRequest.getParameterMap()
You may wonder why these methods always return a map? This is mainly for ease of testing. As for how it converts Map objects with actual Servlet API instances, we don't worry about this at all, because struts2 has built-in interceptors to help us complete this conversion.
In order to directly use the Servlet API, Struts2 provides us with the following interfaces.
1) ServletContextAware: The Action that implements this interface can directly access the ServletContext instance.
2) ServletRequestAware: The action that implements this interface can directly access the HttpServletRequest instance.
3) ServletResponseAware: The action that implements this interface can directly access the HttpServletResponse instance.
The above mainly talks about action access servlets. Let's take a look at how Struts2's Action implements code reuse. Take UserAction for example. If I let this action handle both user registration and login (longin), how should I rewrite this action? The rewritten UserAction is as follows:
package example;public class UserAction extends ActionSupport { private String username; private String password; public String registration() 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; }} Action Configuration in struts.xml
Is it OK to write this way? Of course, it doesn't work. We must also configure it in the struts.xml file. There are two configuration methods:
1) Use a normal way to specify the method attribute for the Action element.
<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) Use wildcards to specify the method attribute for the Action element.
<action name=”*Action” class=”example.UserAction” method=”{1}”> <result name=”success”>/success.jsp</result></action>The way to use wildcards is too flexible, and the following is a more complex configuration situation.
<action name=”*_*” class=”example.{1}Action” method=”{2}”>……….</action>Where the placeholder {1} matches the previous * of _, and {2} matches the next *.
Action configuration based on annotation method:
The configuration of Action I want to talk about below is not in src/struts.xml, but the prerequisite for configuring it using annotation is that in addition to the basic six jar packages, you also need a struts-2.1.8.1/lib/struts2-convention-plugin-2.1.8.1.jar
However, struts.xml still needs specific examples
Login.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Struts2Log in Verification</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>Struts2Login</h3><hr/> <form action="${pageContext.request.contextPath}/user/login.qqi" method="post"> <table> <tr> <td>Username</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="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> <!-- Encoding method of request parameters --> <constant name="struts.i18n.encoding" value="UTF-8"/> <!-- Specify the request suffix type processed by struts2. Multiple separated by commas --> <constant name="struts.action.extension" value="action,do,go,qqi"/> <!-- When struts.xml is changed, whether to reload. The default value is false (used in production environment), it is best to open the development stage --> <constant name="struts.configuration.xml.reload" value="true"/> <!-- Whether to use the development mode of struts. There will be more debugging information in the development model. The default value is false (used in production environment), and it is best to open the development stage --> <constant name="struts.devMode" value="false"/> <!-- Set whether the browser caches static content. The default value is true (used in production environment), it is best to close the development stage --> <constant name="struts.serve.static.browserCache" value="false" /> <!-- Specify that spring is responsible for the creation of the action object<constant name="struts.objectFactory" value="spring" /> --> <!-- Whether to start the state method call --> <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
Explanation of annotation configuration
1) @ParentPackage Specify the parent package
2) @Namespace Specify the namespace
3) @Results An array of results
4) @Result(name="success",location="/msg.jsp") A mapping of results
5) @Action(value="login") Specifies the request URL for a request processing method. Note that it cannot be added to the Action class, to the method.
6) @ExceptionMappings Array of first-level declaration of exceptions
7) @ExceptionMapping Map a declaration exception
Since this method is not very commonly used, you can only understand it