因为setProperty是JSP中的标签,因此使用model 2模式JSP+Servlet+JavaBean的时候,JSP将form提交给Servlet程序,而Servlet程序无法像JSP一样使用setProperty对数据进行封装,
id="calculator" class="cn.megustas.javabean.Calculator" scope="page"/>
property="*" name="calculator"/>
但是可以通过内省技术进行数据的封装,但是每一次写内省程序是一件很麻烦的事情,并且内省匹配也会有问题(例如一侧是String,一侧是int,还需要进行数据转化),因此,内省(基于反射,方便操作javabean的API)封装form数据到javabean的代码,一般不自己编写,使用已经编写好的工具开发包BeanUtils开发包。
注意:如果想自动封装数据,表单form中元素的name需要与JavaBean中的属性一致。
BeanUtils一套开发包,Apache公司提供 ,专门进行javabean操作,在web层各种框架中被使用,例如:struts 使用BeanUtils操作JavaBean 。
实例
1、下载BeanUtils的jar :commons-beanutils 、commons-logging,需要同时下载两个jar包。(BeanUtils依赖Logging的jar包 )
2、将beanutils和logging的 jar包复制 工程/WebContent/WEB-INF/lib
JavaBean
package cn.megustas.javabean;
/**
* 必须满足 三个条件 :必须满足 三个条件 :无参数构造器(不创建有参数构造器,即会有系统默认的无参构造器)、private成员,public get/set
*
* @author Megustas
*
*/
public class Person {
private String name;
private String city;
private String hobby;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
public String getHobby() {
return hobby;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
JSP页面
<body>
<form action="/megustas/demo" method="post">
姓名 <input type="text" name="name" /> <br/>
城市 <input type="text" name="city" /> <br/>
爱好 <input type="text" name="hobby" /> <br/>
年龄 <input type="text" name="age" /><br/>
<input type="submit" value="提交" />
form>
body>
通过action将form表单提交给servlet程序,对数据进行封装,封装到Person对象中
Servlet程序(映射中的url为/megustas/demo):
package cn.megustas.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import cn.itcast.javabean.Person;
/**
* 获得form数据 ,将form数据封装 Person对象中
*
* @author Megustas
*
*/
public class DemoServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");// 处理乱码
// 将form参数 自动封装 Person对象
Person person = new Person();
try {
BeanUtils.populate(person, request.getParameterMap());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//检验是否封装到person对象中
System.out.println(person.getName());
System.out.println(person.getCity());
System.out.println(person.getHobby());
System.out.println(person.getAge());
System.out.println(person.getBirthday());
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
注意:
常用方法:
//将请求的Map封装为Person对象(JavaBean)
BeanUtils.populate(Object bean,Map properties);
(注:因为需要为Map类型,因此需要通过request.getParameterMap()方法将form表单中的数据变为Map类型)
实际上是通过JavaBean中的setName等方法,将form表单中的属性的值封装到person对象中去。对于类型转换,我们可以看下如下的这个例子,我们在JavaBean中添加一个属性Date(对应set/get方法也需要添加):
public class Person {
private String name;
private String city;
private String hobby;
private int age;
private Date birthday;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
public String getHobby() {
return hobby;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Date getBirthday() {
return birthday;
}
}
JSP页面中增加:
生日 type="text" name="birthday" />
Servlet程序中增加一个输出
System.out.println(person.getBirthday());
则将会报错,因为服务器端为Date类型,从输入的form表单的数据无法转换过去,即如果在Person类添加特殊类型Date类型,对于特殊类型如何封装 ?因此,需要了解一下BeanUtils的封装原理
即任何的类型转换都是通过转换器来实现的。例如我们之前的例子,String类型的提交数据是通过IntegerConverter转换器转换为person对象中的int类型的。可以总结为如下:
1、如果form参数是String类型,javabean属性String类型 —- 调用BeanUtils.populate 将form数据封装 javabean
2、如果JavaBean属性类型不是String —- 将form数据封装javabean 需要转换器 —– 在BeanUtils API 提供很多默认转换器(完成常见转换)
3、如果需要转换类型非常特殊,可以通过自定义转换器完成 定义类实现Converter接口,实现convert方法 ,在populate调用之前通过ConvertUtils.register注册转换器
因此,如果出现上种情况,即需要将String类型转换为java.util.Date类型,我们可以自定义转换器。
自定义转换器(或者在已有转换器,但是不知道如何使用的情况也可以通过自定义转换器来进行类型转换):
1.需要实现Converter接口
class MyDateConverter implements Converter {
@Override
// 需要 将value数据转换 c的类型
// value 是 String类型,将String转换Date类型
public Object convert(Class c, Object value) {
String s = (String) value; // 代表用户输入生日
//定义格式
DateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日");
try {
Object result = dateFormat.parse(s); // 将String解析为 Date,将日期变为字符串使用format方法
return result;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
因为在转换器中定义了“yyyy年MM月dd日”的格式,因此在jsp页面的form表单需要输入信息为“1998年2月12日”这类的格式的字符串,才可以通过我们自定义的转换器进行转换,转换为Date类型并之后进行存储。
2.注册转换器
ConvertUtils.register(转换器, 目标类型.class);
修改之后的Servlet程序:
public class Demo4Servlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");// 处理乱码
// 将form参数 自动封装 Person对象
Person person = new Person();
// 将String类型 转换 java.util.Date类型 --- 自定义转换器
// 在封装数据之前 ,注册转换器
ConvertUtils.register(new MyDateConverter(), Date.class);
try {
BeanUtils.populate(person, request.getParameterMap());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//检验是否封装到person对象中
System.out.println(person.getName());
System.out.println(person.getCity());
System.out.println(person.getHobby());
System.out.println(person.getAge());
System.out.println(person.getBirthday());
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
BeanUtils.populate(Object bean, Map properties)
方法进行数据封装最通俗的说法,JavaBean就是一个存数据的地方,要么
(1)通过JSP页面中的标签去存储form表单中的数据(action跳转到JSP页面,之后“useBean”,“setProperty”进行数据存储),再在JSP界面中通过“getProperty”显示数据。
(2)在JSP页面中通过action跳转到Servlet程序的url,在Servlet程序中通过BeanUtils工具类的相关方法对JSP页面中的表单信息进行存储。
JSP+Servlet+JavaBean模式示意图: