Struts2 type conversion

    The type conversion of Struts2 can be based on OGNL expressions, or you can customize the type converter. At the same time, you don't need to care about the exception handling logic. When inheriting the default Struts2 stack, there will be a conversion interceptor to automatically handle exceptions.

1. Built-in type converter

    Built-in conversions are supported for common primitive types, but also for Date, Array, and Collection. Among them, Date requires that the string is the SHORT form of Locale, the elements of the array are strings, and the elements of the collection are also strings.


2. OGNL conversion

    One, with generic

       JavaBean (User.java):

package DeepUse;

public class User {
	private String userName;
	
	private String password;

	public String getUserName() {//These get and set methods are best implemented with the functions that come with IDE
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}
}

   Presentation layer (input.jsp):

<s:form action="login">
    	<s:textfield name="users[0].userName" label="username"/> <!-- name is an OGNL expression, indicating that the value will be set as the userName property of the first object in the users list- ->
                                                            <!-- If users is a Map in the control layer, then the OGNL expression here should be users['any name'] -->
    	<s:textfield name="users[0].password" label="密码"/>
    	<tr>
    		<td colspan="2"><s:submit value="转化" theme="simple"/>
    		<s:reset value="重填" theme="simple"/></td>
    	</tr>
    </s:form>

    Control layer (LoginAction.java):

package DeepUse;

import java.util.List;

import com.opensymphony.xwork2.ActionSupport;

public class LoginAction extends ActionSupport{
	private static final long serialVersionUID = 1L;

	private List<User> users;
	
	public List<User> getUsers() {
		return users;
	}

	public void setUsers(List<User> users) {//Note setUsers here, if it is setUser, it will not be set.
                                                //This is determined by the passed parameter name, this method will be automatically completed when the form is submitted
		this.users = users;
	}
}

 Return the success view (success.jsp):

Welcome, <s:property value="users[0].userName"/>, your login password is <s:property value="users[0].password"/>
    <!--If it is a Map type, then the value method here is users['any name'].userName where any name corresponds to any of the above names -->

Finally, after configuring it in struts2.xml, open the browser output:

                        

Second, without generics

    Struts2 does not know how to convert types without generics. When removing generics:

    

At this time, the user name and password cannot be obtained because of a type conversion error. At this time, you need to implement it yourself through the local type conversion file. The file is named ActionName-conversion.properties, where ActionName is the java class name of the control layer, and -conversion.properties is the fixed part. Then add Element_<ListPropName>=<ElementType> to the file, where <ListPropName> is The name of the List collection, <ElementType> is the type of the List collection element.

    JavaBean (User.java), presentation layer (input.jsp), return view (success.jsp) are similar to the above

    Control layer (LoginAction.java):

package DeepUse;


import java.util.List;


import com.opensymphony.xwork2.ActionSupport;


public class LoginAction extends ActionSupport{
	private static final long serialVersionUID = 1L;


	private List users;//Remove generics here to specify types with local variables
	
	public List getUsers() {
		return users;
	}


	public void setUsers(List users) {
		this.users = users;
	}
}

 Then add the LoginAction.properties file:


     The content of the file is:

Element_users=DeepUse.User

If users is a Map type, the above line indicates the setting of the value in the Map. For the setting of the key in the Map, one more line should be added, as follows:

Element_users=DeepUse.User
Key_users=java.lang.String

The result is the same as above

3. Custom type conversion

  In addition to the built-in and ONGL, custom types can also be used. In this case, the convertValue method of the DefaultTypeConverter class needs to be implemented.

   JavaBean (User.java) and return view (success.jsp) same as above

    Presentation layer (input.jsp):

<s:form action="login">
    	<s:textfield name="user" label="用户"/>
    	<tr>
    		<td colspan="2"><s:submit value="转化" theme="simple"/>
    		<s:reset value="重填" theme="simple"/></td>
    	</tr>
    </s:form>

    Converter (UserConverter.java):

package DeepUse;

import java.util.Map;

import com.opensymphony.xwork2.conversion.impl.DefaultTypeConverter;

public class UserConverter extends DefaultTypeConverter{//In addition, the StrutsTypeConverter class with clearer logic can be implemented, such as the one mentioned in 4.Set type conversion
	@SuppressWarnings("rawtypes")
	@Override
	public Object convertValue(Map<String, Object> context, Object value,
			Class toType) {
		// TODO Auto-generated method stub
		if(toType==User.class){
			//to convert to object
			String[] params=(String[]) value;//The value here is obtained by getParams(name) of httpServletRequest
			User user=new User();
			String[] userValues=params[0].split(",");//Because params may be an array with multiple elements, such as the string from the checkbox after parsing
			user.setUserName(userValues[0]);
			user.setPassword(userValues[1]);
			return user;
		}else if(toType==String.class){//To convert to String
			User user=(User) value;
			return "<"+user.getUserName()+","+
					user.getPassword()+">";
		}
		return null;
	}
}

Control layer (LoginAction.java):

package DeepUse;

import com.opensymphony.xwork2.ActionSupport;

public class LoginAction extends ActionSupport{

	/**
	 *
	 */
	private static final long serialVersionUID = 1L;

	private User user;
	
	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}
}

Then register the converter and change the content in the above LoginAction-conversion.properties file to: <propName>=<ConverterClass>, where propName is the name of the conversion object

user=DeepUse.UserConverter

Output result:


Or it can also be registered as a global converter, specifically by providing xwork-conversion.properties in the classes directory, where the content is <propType>=<ConverterType>, for example, the content of the local file above is converted to the content of the global file: DeepUse.User= The advantage of DeepUse.UserConverter. This is that the convertValue function can be called multiple times for collections or arrays containing multiple such objects, while the local file can only be converted once.

4. Set type conversion

    It is generally not recommended to use Set collections in Actions, because its elements are unordered, and iterators are generally used to traverse its elements. The index cannot be used, and the JavaBean file needs to be modified here to use the index to complete the value like Map and List.

    JavaBean (User.java):

package DeepUse;

public class User {
	private String userName;
	
	private String password;

	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;
	}
	
	@Override
	public boolean equals(Object obj) {//The userName is used as the identifier to accurately extract the set collection elements, and the equals and hashCode methods are overloaded
		// TODO Auto-generated method stub
		if(this==obj){
			//same object
			return true;
		}
		if(obj!=null && obj.getClass()==User.class){
			//obj is of User type
			User user=(User)obj;
			return this.getUserName().equals(user.getUserName());//Because this field is an object not a character constant, it is not in the constant but in the heap, so you cannot use ==
		}
		return false;
	}
	
	@Override
	public int hashCode() {//Calculate has value according to name
		// TODO Auto-generated method stub
		return userName.hashCode();
	}
}

Converter (UserConverter.java):

package DeepUse;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.struts2.util.StrutsTypeConverter;

public class UserConverter2 extends StrutsTypeConverter{

	@Override
	public Object convertFromString(Map arg0, String[] arg1, Class arg2) {
		// TODO Auto-generated method stub
		Set result=new HashSet();
		for(int i=0;i<arg1.length;i++){
			User user=new User();
			String[] usersValues=arg1[i].split(",");
			user.setUserName(usersValues[0]);
			user.setPassword(usersValues[1]);
			result.add(user);
		}
		return result;//Return the set collection, not converting an element in the collection
	}

	@Override
	public String convertToString(Map arg0, Object arg1) {
		// TODO Auto-generated method stub
		if(arg1.getClass()==Set.class){
			Set users=(Set)arg1;
			String result="[";
			for(Object obj:users){
				User user=(User)obj;
				result+="<"+user.getUserName()+","+user.getPassword()+">";
			}
			return result+"]";
		}else{
			return "";
		}
	}
}

Return page (success.jsp):

Welcome,<s:property value="users('abc').userName"/>, your login password is <s:property value="users('abc').password"/>
    <!-- Note that the index uses parentheses here, while the list and map are square brackets -->

Control layer (LoginAction.java):

package DeepUse;

import java.util.Set;

import com.opensymphony.xwork2.ActionSupport;

public class LoginAction extends ActionSupport{

	/**
	 *
	 */
	private static final long serialVersionUID = 1L;

	private Set users ;

	public Set getUsers() {
		return users;
	}

	public void setUsers(Set users) {
		this.users = users;
	}
}

Register the converter and change the content of the above LoginAction-conversion.properties file to: in addition to <propName>=<ConverterType>, add a line of KeyProperty_<SetPropName>=<keyPropName>, note that the propName here is a collection name, and the front is Object name, mainly depends on the value returned by UserConverter.

users=DeepUse.UserConverter
KeyProperty_users=userName

The output is the same as above

5. Conversion error handling

    In the above input, if the user is not separated by commas but separated by &, a conversion error will occur. The struts2 default interceptor contains a reference to the conversionError interceptor, and the error information is put into the ActionContext, which can be used in the page < s:fielderror/> shows that if it is a form element, the error message will also be automatically displayed above the form element. Generally, the error message is in black font, which can be changed after adding <s:head/> to the return page (success.jsp). In red font. The default error message is in English format: Invalid field value for field xxx. You can add xwork.default.invalid.fieldvalue={0} field type conversion failure to the global internationalization resource to change the default display error message.

    Since conversion errors are returned to the input logical view, the physical view of the input also needs to be configured in struts.xml.

    The output is as follows:

    

In addition to global international resources, you can also use local international resources, the file name is ActionName.properties. The content format is:

    invalid.fieldvalue.<propName>=<tipMes>

Where propName supports OGNL expressions, as above, if the English prompt information is changed to Chinese:

First provide the LoginAction.properties file with the following contents:

invalid.fieldvalue.users=Please separate username and password with comma

Since the file contains Chinese, you need to use native2ascii to convert it. Specifically, open the terminal cmd in the directory where the file is located, and then enter the command:

    native2ascii LoginAction.properties LoginAction_zh_CN.properties

This will generate a new file LoginAction_zh_CN.properties, which is the unicode version of the original file, now you can delete LoginAction.properties to keep the new file. The directory is similar to:

    


This is a conversion error for collections. If the collection is converted from multiple values ​​of the same parameter name, and there is an error in the middle value, the parameter name conversion error will be displayed. If it is converted from different parameter names, the conversion error information of each parameter name will be displayed independently.

6. Summary

    For this part of the content, the workflow of struts2 is roughly: display the welcome page (input.jsp), when the user submits the form to trigger the action, struts2 searches struts2.xml to find the corresponding control class (LoginAction.java), and then calls the control class The set method in prepares to set the form parameters. If it is found that the object of the set is not a built-in object or an OGNL expression (with generics), then look for the corresponding local type conversion file. If the local file does not exist or is empty, then go to the global type conversion file. If it still cannot be found Then there are possible errors such as null pointer exception or range out of bounds, because the object is empty at this time. If the conversion file is a registered converter (UserConverter.java), then according to the logic of the converter, JavaBean (User.java) will be used. If the conversion fails, it will be intercepted by the struts2 interceptor and returned to the input logic view and display an error. Information, if the conversion is successful, execute the execute control class or specify a method in struts2.xml to return the logical view. Enter the logical view to match the physical view, and finally return to the physical view.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325647621&siteId=291194637