框架学习——Struts2框架几点总结

本文深入解析Struts2框架的关键组件,包括result元素、自定义拦截器、文件上传下载、ActionContext与ValueStack数据存取、EL表达式改进、迭代标签使用等,以及表单提交案例,为开发者提供全面的Struts2应用指南。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

result元素

  • 作用:为动作指定结果视图
  • 属性name:逻辑视图的名称,对应着动作方法的返回值。默认值是success。
  • type:结果类型,指的就是用什么方式转到定义的页面。默认是dispatcher。
  • 常用type:dispatcher、redirect、redirectAction、chain
  • dispatcher(默认值):使用请求转发,转向一个页面。
  • redirect:使用重定向,转向一个页面。
  • redirectAction:重定向到另一个动作。分为相同名称空间的动作和不同名称空间的动作。
  • 相同名称空间的动作配置如下:
<result name="success" type="redirectAction">action2</result>
  • 不同名称空间的动作配置如下:
<result name="success" type="redirectAction">
    <param name="namespace">/n2</param>
    <param name="actionName">action2</param>
</result>
  • chain:使用请求转发到另一个动作。分为相同名称空间和不同名称空间的动作。
  • 相同名称空间的动作配置如下:
<result name="success" type="chain">action2</result>
  • 不同名称空间的动作配置如下:
<result name="success" type="chain">
    <param name="namespace">/n2</param>
    <param name="actionName">action2</param>
</result>

自定义拦截器

  • struts.xml文件中的配置信息
<package name="pack" extends="struts-default">
	<interceptors>
	    <!-- 自定义拦截器 -->
		<interceptor name="checkLoginInterceptor" class="interceptor.CheckLoginInterceptor" />
		<!-- 自定义拦截器栈,其由默认拦截器栈和自定义拦截器组成 -->
		<interceptor-stack name="myDefaultStack">
			<interceptor-ref name="defaultStack"></interceptor-ref>
			<interceptor-ref name="checkLoginInterceptor"></interceptor-ref>
		</interceptor-stack>
	</interceptors>
	<!-- 将自定义拦截器栈设置为默认的拦截器栈 -->
	<default-interceptor-ref name="myDefaultStack"></default-interceptor-ref>
	<!-- 设置全局结果视图 -->
	<global-results>
		<result name="input">/login.jsp</result>
	</global-results>
	
	<action name="login" class="action.DemoAction" method="login">
		<!-- 使用默认拦截器栈,只是设置自定义拦截器不拦截的动作方法名称 -->
		<interceptor-ref name="myDefaultStack">
			<!-- 在引用自定义拦截器栈的时候,给指定的拦截器注入参数。方式就是:拦截器名称.属性名称 -->
			<param name="checkLoginInterceptor.excludeMethods">login</param>
		</interceptor-ref>
		<result type="redirectAction">showMain</result>
	</action>
	<!-- 下面两个动作执行使用默认拦截器栈中的拦截器 -->
	<action name="showMain" class="action.DemoAction" >
		<result>/main.jsp</result>
	</action>		
	<action name="showOther" class="action.DemoAction" >
		<result>/otherpage.jsp</result>
	</action>
</package>
  • 拦截器类
package interceptor

import javax.servlet.http.HttpSession;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;

/* 拦截器需要继承抽象类AbstractInterceptor。重写intercept方法。
如若需要实现通过参数注入方式设置哪些方法不被该拦截器拦截,哪些方法需要被该拦截器拦截。
则需要自定义拦截器继承抽象类AbstractInterceptor的子类MethodFilterInterceptor。重写doIntercept方法。
*/
public class CheckLoginInterceptor extends MethodFilterInterceptor {

	public String doIntercept(ActionInvocation invocation) throws Exception {
		//1.获取HttpSession
		HttpSession session = ServletActionContext.getRequest().getSession();
		//2.获取session域中的登录标记
		Object obj = session.getAttribute("user");
		//3.判断是否有登录标记
		if(obj == null){
			//用户没有登录
			return "input";
		}
		//4.用户登录了,放行
		String rtValue = invocation.invoke();
		return rtValue;
	}
}

文件上传

  • struts.xml配置
<!-- 限制上传文件的大小,通过修改struts2的常量。
    在default.properties中配的struts.multipart.maxSize=2097152 -->
<constant name="struts.multipart.maxSize" value="5242880"></constant>
<package name="p1" extends="struts-default">
	<action name="upload" class="action.UploadAction" method="upload">
	    <!-- 文件上传是通过默认拦截器栈中的一个叫做fileUpload拦截器实现的,所以可以通过参数注入的方式限制上传文件类型 -->
		<interceptor-ref name="defaultStack">
			<!-- 限制上传文件的扩展名。如果有多个,使用逗号分隔 
			<param name="fileUpload.allowedExtensions">jpg,png,bmp</param>-->
			<!-- 限制上传文件的MIME类型。 如果有多个,使用逗号分隔 -->
			<param name="fileUpload.allowedTypes">image/jpg,image/pjpeg,image/png</param>
		</interceptor-ref> 
		<result name="input">/upload.jsp</result>
	</action>
</package>
  • UploadAction动作类
package action;

import java.io.File;

import javax.servlet.ServletContext;

import org.apache.commons.io.FileUtils;
import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

public class UploadAction extends ActionSupport {

	//表单上提供的字段
	private String username;
	private File photo;
	//struts2在文件上传时提供的属性
	private String photoFileName;//上传的文件名。上传字段名称+FileName  注意大小写
	private String photoContentType;//上传文件的MIME类型。上传字段名称+ContentType 注意大小写
	
	public String upload(){
		//1.拿到ServletContext
		ServletContext application = ServletActionContext.getServletContext();
		//2.调用realPath方法,获取根据一个虚拟目录得到的真实目录
		String filePath = application.getRealPath("/WEB-INF/uploadFiles");
		//3.如果这个真实的目录不存在,需要创建
		File file = new File(filePath);
		if(!file.exists()){
			file.mkdirs();
		}
		//4.把photo存过去
		//拷贝:把photo的临时文件复制到指定的位置。注意:临时文件还在
		//FileUtils.copyFile(photo, new File(file,photoFileName));
		
		//剪切:把临时文件剪切指定的位置,并且给他重命名。 注意:临时文件没有了
		photo.renameTo(new File(file,photoFileName));
		
		return null;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public File getPhoto() {
		return photo;
	}

	public void setPhoto(File photo) {
		this.photo = photo;
	}

	public String getPhotoFileName() {
		return photoFileName;
	}

	public void setPhotoFileName(String photoFileName) {
		this.photoFileName = photoFileName;
	}

	public String getPhotoContentType() {
		return photoContentType;
	}

	public void setPhotoContentType(String photoContentType) {
		this.photoContentType = photoContentType;
	}
}
  • upload.jsp页面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
	<title>struts2中的文件上传</title>
  </head>
  <body>
  	<%--文件上传的必要前提:
  		 1.请求方式必须是post
  		 2.enctype属性的取值必须是multipart/form-data
  		 3.提供一个文件选择域
  	--%>
  	<%-- 注意这里在jsp页面中使用的都是struts标签来代替html标签。
  	s:actionerror是用来回显动作类中的错误信息 --%>
  	<s:actionerror/>
  	<s:form action="upload.action" enctype="multipart/form-data">
  		<s:textfield name="username" label="用户名" />
  		<s:file name="photo" label="照片" />
  		<s:submit value="上传"/>
  	</s:form>
  </body>
</html>

文件下载

  • struts.xml配置
<action name="download" class="action.DownloadAction" method="download">
	<result name="success" type="stream">
		<!-- 给stream的结果类型注入参数:Content-Type -->
		<param name="contentType">application/octet-stream</param>
		<!-- 告知客户浏览器以下载的方式打开
		<param name="contentDisposition">attachment;filename=photo.jpg</param> -->
		<!-- 使用OGNL表达式,来动态获取文件名 
			 ${@java.net.URLEncoder@encode(filename,"UTF-8")} 把${}中间的内容当成一个OGNL表达式来看待
		-->
		<param name="contentDisposition">attachment;filename=${@java.net.URLEncoder@encode(filename,"UTF-8")}</param>
		<!-- 注入字节输入流 :取值要写动作类中set方法的名称,首字母改成小写-->
		<param name="inputName">inputStream</param>
	</result>
</action>
  • DownloadAction动作类
package action;

import java.io.FileInputStream;
import java.io.InputStream;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

public class DownloadAction extends ActionSupport {
	
	private InputStream inputStream;
	//创建一个文件名的属性
	private String filename;
	
	public String download()throws Exception{
		//1.找到文件的存储路径
		String filePath = ServletActionContext.getServletContext().getRealPath("/WEB-INF/files/5.jpg");
		//2.把文件读到一个InputStream中
		inputStream = new FileInputStream(filePath);
		
		//在返回之前,给filename赋值
		filename="照片.jpg";
		
		//3.返回一个成功
		return SUCCESS;
		//4.由一个叫做stream的结果类型为我们把剩下的事情做完。
	}

	public InputStream getInputStream() {
		return inputStream;
	}

	public void setInputStream(InputStream inputStream) {
		this.inputStream = inputStream;
	}

	public String getFilename() {
		return filename;
	}

	public void setFilename(String filename) {
		this.filename = filename;
	}
}

ActionContext存取数据

  • struts.xml配置
<action name="action1" class="action.Demo1Action">
    <result>/demo1.jsp</result>
</action>
  • Demo1Action动作类
package action;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import java.util.Map;

public class Demo1Action extends ActionSupport {
    public String execute() {
        //1.得到ActionContext对象
        ActionContext context = ActionContext.getContext();//这是从当前线程的局部变量中获取引用
        //2.往map中存入数据
        context.put("contextMap", "hello contextMap");//把数据直接存到了大Map中

        //往session中存数据
        //第一种方式:获取key为session的map
        Map<String, Object> sessionAttribute = context.getSession();//得到key值为session的小map
        sessionAttribute.put("sessionMap", "hello sessionMap");
        //第二种方式:直接使用原始的HttpSession对象
        HttpSession session = ServletActionContext.getRequest().getSession();
        session.setAttribute("sessionMap1", "hello sessionMap1");

        //往ServletContext域中存数据
        //第一种方式:获取key值为application的map
        Map<String, Object> applicationAttribute = context.getApplication();
        applicationAttribute.put("applicationMap", "hello applicationMap");
        //第二种方式:获取原始ServletContext对象
        ServletContext application = ServletActionContext.getServletContext();
        application.setAttribute("applicationMap1", "hello applicationMap1");

        return SUCCESS;
    }
}
  • demo1.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>取ActionContext数据</title>
</head>
<body>
<%--使用s:property来获取ActionContext中的数据。
    value属性的取值是一个OGNL表达式。--%>
<br/>---------获取大Map中的数据-------------<br/>
<%--获取大Map中的数据,在取的时候是#key名称--%>
<s:property value="#contextMap"/>
<br/>---------获取小Map中的数据-------------<br/>
<%--获取大Map中小Map的数据 ,使用#大Map的key.小Map的key--%>
<s:property value="#session.sessionMap"/><br/>
<s:property value="#session.sessionMap1"/><br/>
<s:property value="#application.applicationMap"/><br/>
<s:property value="#application.applicationMap1"/>
<s:debug/>
</body>
</html>
  • 浏览器页面显示内容:
---------获取大Map中的数据-------------
hello contextMap 
---------获取小Map中的数据-------------
hello sessionMap
hello sessionMap1
hello applicationMap
hello applicationMap1 

ValueStack存取数据

  • struts.xml配置
<action name="action2" class="action.Demo2Action">
    <result>/demo2.jsp</result>
</action>
  • Demo2Action动作类
package action;

import domain.Student;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;

/**
 * 利用VauleStack存数据
 */
public class Demo2Action extends ActionSupport {

    private String name = "泰斯特2";//动作类内部的成员变量,需要为其设置get/set方法

    public String execute() {
        //获取ValueStack对象的引用,以下三种方式得到的是同一对象
//		//第一种方式:获取HttpServletRequest对象,通过对象的getAttribute方法,从域中取
//		//1.获取request对象
//		HttpServletRequest request = ServletActionContext.getRequest();
//		//2.根据key获取ValueStack对象的引用
//		ValueStack vs1 = (ValueStack)request.getAttribute("struts.valueStack");
//		System.out.println(vs1.hashCode());
//
//		//第二种方式:先获取ActionContext对象,再取出requestMap,然后通过map的get方法获取
//		//1.获取ActionContext对象
//		ActionContext context = ActionContext.getContext();
//		//2.获取requestMap
//		Map<String,Object> requestAttribute = (Map<String,Object>)context.get("request");
//		//3.根据key获取对象的引用
//		ValueStack vs2 = (ValueStack)requestAttribute.get("struts.valueStack");
//		System.out.println(vs2.hashCode());
//
//		//第三种方式:使用ActionContext对象的方法,直接获取ValueStack对象的引用
//		ValueStack vs3 = context.getValueStack();
//		System.out.println(vs3.hashCode());

        //栈的操作
        ActionContext context = ActionContext.getContext();
        ValueStack vs = context.getValueStack();
        //压栈操作
        vs.push(new Student("泰斯特", 21));
        /*
         * ValueStack的其他方法
         * setValue(String expr, Object value);
         * 		String expr:它是一个OGNL表达式
         * 		Object value:我们要操作的数据
         *  把数据存到哪里去?
         *  	看expr是否使用了#
         *  	如果使用了#,操作的就是ActionContext
         *  	如果没使用#,操作的就是ValueStack
         */
        vs.setValue("#name", "张三");//把数据放到ActionContext中。 key是name,value=张三
        vs.setValue("name", "李四");//把ValueStack中第一个name属性的值换成李四。如果没有一个name属性的对应的setName方法,会报错。

        /*
         *  set(String key, Object o);
         *  String key : Map的key
         *  Object o : Map的value
         *  如果栈顶是一个Map元素,直接把key作为map的key,把Object作为map的value存入。存入的是栈顶。
         *  如果栈顶不是一个Map元素,创建一个Map对象,把key作为map的key,把Object作为map的value,压入栈顶。
         */
        vs.set("s1", new Student("王五", 18));
        vs.push(new Student("test", 23));
        vs.set("s2", new Student("aaa", 28));//此时栈顶不是Map元素,创建一个
        vs.set("s3", new Student("bbb", 30));//此时栈顶是Map元素,直接存入

        return SUCCESS;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  • demo2.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ page import="com.opensymphony.xwork2.util.ValueStack" %>
<%@ page import="com.opensymphony.xwork2.ActionContext" %>
<html>
<head>
    <title>取ValueStack中的数据</title>
</head>
<body>
<%--使用s:property标签,获取ValueStack中的元素。
    value属性的取值是一个OGNL表达式。它只能获取元素中的属性。
    注意:
        取ValueStack中的对象属性时,不使用#。
    它是从栈顶逐个对象查找指定的属性名称。只要找到了,就不再继续查找。
--%>
<s:property value="name"/><br/>
<%-- 获取ValueStack中指定位置的属性: --%>
0-name <s:property value="[0].name" /><br/>
1-name <s:property value="[1].name" /><br/>
2-name <s:property value="[2].name" /><br/>
3-name <s:property value="[3].name" /><br/>
4-name <s:property value="[4].name" /><br/>
<%--取HashMap中的元素 --%>
<s:property value="s3.name" /><br/>

<%--当s:property什么都不写:
    默认取栈顶元素
 --%>
<s:property />
<%//模拟原理:其实全是ValueStack的findValue和findString
    ValueStack vs = ActionContext.getContext().getValueStack();
    Object obj = vs.findValue("[2].name");
    out.print("<br/>-------------------------<br/>");
    out.print(obj);
%>
<s:debug/>
</body>
</html>
  • 浏览器页面显示内容:
test
0-name test
1-name test
2-name 李四
3-name 李四
4-name 泰斯特2
bbb
{s3=domain.Student@7676f25f, com.opensymphony.xwork2.util.OgnlValueStack.MAP_IDENTIFIER_KEY=, s2=domain.Student@2643cfa8} 
-------------------------
李四 

struts2对EL表达式的改变

  • 在jsp页面中,我们会使用EL表达式来获取域中的对象,正常的查找顺序是:page Scope————>request Scope————>sessionScope————>application Scope
  • 经过struts2对request的getAttribute方法进行重写,查找的顺序变成了:page Scope————>request Scope————>valueStack————>contextMap————>sessionScope————>application Scope

iterator标签的使用

  • struts.xml配置
<action name="action4" class="action.Demo4Action" method="findAll">
    <result>/demo4.jsp</result>
</action>
  • Demo4Action动作类
package action;

import java.util.ArrayList;
import java.util.List;

import domain.Student;
import com.opensymphony.xwork2.ActionSupport;

/**
 * s:iterator标签的使用
 */
public class Demo4Action extends ActionSupport {
    //Action动作类的引用,默认情况下就在ValueStack的栈顶
    private List<Student> students;

    public String findAll() {
        //调用service层的方法,List findAllStudent()
        students = new ArrayList<Student>();
        students.add(new Student("张三", 23));
        students.add(new Student("李四", 24));
        students.add(new Student("王五", 21));
        return SUCCESS;
    }

    public List<Student> getStudents() {
        return students;
    }

    public void setStudents(List<Student> students) {
        this.students = students;
    }
}
  • demo4.jsp页面(重点部分)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>s:iterator的使用</title>
</head>
<body>
<table width="500px" border="1" align="center">
    <tr>
        <th>序号</th>
        <th>姓名</th>
        <th>年龄</th>
    </tr>
    <%--s:iterator:struts2的迭代标签
        属性详解:
        begin,end,step和jstl的forEach标签是一样的
        value属性:要遍历的集合,是OGNL表达式。
        var属性:取值就是一个字符串
            如果写了该属性:把var的值作为key,把当前遍历的元素作为value。存到ActionContext这个大Map中
            如果不写该属性:把当前遍历的元素压入栈顶
        status属性:遍历时的一些计数信息。
            int getIndex() 从0开始
            int getCount() 从1开始
            boolean isFirst()
            boolean isLast()
            boolean isOdd()
            boolean isEven()
        --%>
    <s:iterator value="students" var="s" status="vs" >
        <tr>
            <td><s:property value="#vs.index"/></td>
            <td><s:property value="#s.name" /></td>
            <td><s:property value="#s.age" /></td>
        </tr>
    </s:iterator>
</table>
<hr/>
<table width="500px" border="1" align="center">
    <tr>
        <th>序号</th>
        <th>姓名</th>
        <th>年龄</th>
    </tr>
    <s:iterator value="students" status="vs">
        <tr>
            <td><s:property value="#vs.count"/></td>
            <td><s:property value="name" /></td>
            <td><s:property value="age" /></td>
        </tr>
    </s:iterator>
</table>
<s:debug/>
</body>
</html>

struts2其他一些标签

  • jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>struts2中的一些其他标签的使用</title>
</head>
<body>
<br/>-------s:set------------<br/>
<%--s:set标签
    value属性:取值是一个OGNL表达式
    var属性:是一个普通的字符串
    它是把value属性的值作为value,把var属性的值作为key,把存到ActionContext大map中。
--%>
<s:set value="'test'" var="str1"/>
<br/>-------s:if s:ifelse s:else------------<br/>
<%-- 条件判断的标签--%>
<s:set value="'C'" var="grade"/>
<s:if test="#grade=='D'"></s:if>
<s:elseif test="#grade=='C'"></s:elseif>
<s:else>其他</s:else>
<br/>-------s:url------------<br/>
<%--s:url标签:
    value属性:是把值直接输出到页面上
    action属性:是把动作的请求地址输出到页面上 ${pageContext.request.contextPath}/action1
    var属性:把action的取值作为value,把var的取值作为key,放到ActionContext中
    注意:它会自动根据struts配置,来转换后缀名。
--%>
<s:url value="action1"/>
<s:url action="action1" var="url" >
    <%--把name作为key,把value作为值,绑定到请求连接地址后面。相当于get方式拼接请求参数
        注意:
            name的取值就是一个普通的字符串
            value的取值是一个OGNL表达式,要想转成字符串请使用''
    --%>
    <s:param name="name" value="'张三'"></s:param>
</s:url>
<br/>
<a href="<s:property value='#url' />" >点击 s:url</a>
<s:debug/>
</body>
</html>

struts2中的符号使用

#
  • 取ActionContext中key时使用,例如<s:property value="#name" />
  • OGNL中创建Map对象时使用,例如:<s:radio list="#{‘male’:‘男’,‘female’:‘女’}" />
$
  • 在JSP中使用EL表达式时使用,例如${name}
  • 在xml配置文件中,编写OGNL表达式时使用,例如文件下载时,文件名编码。struts.xml——>${@java.net.URLEncoder@encode(filename,“UTF-8”)}
%
  • 在struts2中,有些标签的value属性取值就是一个OGNL表达式,例如<s:property value=“OGNL Expression” />
  • 还有一部分标签,value属性的取值就是普通字符串,例如<s:textfield value=“username”/>,如果想把一个普通的字符串强制看成时OGNL,就需要使用%{}把字符串套起来。例如<s:textfield value="%{username}"/>。

struts2表单提交案例

  • struts.xml配置
<action name="saveCustomer" class="action.Demo7Action" method="save"/>
  • Demo7Action动作类
package action;

import domain.Customer;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

/*
实现ModelDriven接口,通过ModelDrivenInterceptor拦截器能够将customer对象放进ValueStack中;
之后通过ParametersInterceptor拦截器能够将参数都赋值给customer对象中的成员
*/
public class Demo7Action extends ActionSupport implements ModelDriven<Customer> {

    //定义一个模型,注意:必须自己实例化
    private Customer customer = new Customer();

    public Customer getModel() {
        return customer;
    }

    public String save(){
        System.out.println(customer);//执行之前已经将参数都封装进customer对象
        return null;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }
}
  • Costomer类
package domain;

import java.io.Serializable;

public class Customer implements Serializable{

    private String name;
    private String password;
    private boolean married;
    private String hobby;
    private String city;
    private String description;
    private String gender;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public boolean isMarried() {
        return married;
    }
    public void setMarried(boolean married) {
        this.married = married;
    }
    public String getHobby() {
        return hobby;
    }
    public void setHobby(String hobby) {
        this.hobby = hobby;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    @Override
    public String toString() {
        return "Customer [name=" + name + ", password=" + password
                + ", married=" + married + ", hobby=" + hobby + ", city="
                + city + ", description=" + description + ", gender=" + gender
                + "]";
    }
}
  • dome7.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>一个表单的小例子</title>
</head>
<body>
<s:form action="saveCustomer">
    <s:textfield name="name" label="用户名" />
    <s:password name="password" label="密码" />
    <s:checkbox name="married" label="已婚" value="true" />
    <s:checkboxlist name="hobby" list="{'摄影','旅行','足球'}" label="爱好" />
    <s:select name="city" label="故乡"  list="#{'BJ':'北京','SH':'上海','SZ':'苏州'}" headerKey="" headerValue="---请选择---"/>
    <s:textarea name="description" label="个人介绍" rows="5"  cols="25" />
    <s:radio name="gender" list="#{'male':'','female':''}" label="性别" value="'male'" /><%--value是一个OGNL表达式 --%>
    <s:submit value="提交" /><s:reset value="重置" />
</s:form>
 <s:debug/>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值