以一个案例介绍反射机制的一种常见的使用场景,以及具体实现。
1.本文案例
在编写Java Web应用程序时,使用表单提交数据是一个必不可少的环节,后台对于前台使用表单提交的数据需要能够从请求中解析,并封装到相应的实体中,也就是封装到一个Java对象中。
那么,能否有某种方式使程序能够自动的将表单提交的数据设置到一个相应的对象中呢?
2.创建用于提交表单的页面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>利用反射自动填充数据</title> </head> <body> <form action="LoginServlet" method="POST"> <span>UserName: </span><input name="userName" type="text" /><br/> <span>Password: </span><input name="password" type="password"><br/> <button type="submit">Login</button> </form> </body> </html>
注意,此处的表单中的name属性后面会用到,这个那么属性,需要与存放这两个值的class的属性名称相同
3.创建用于存放从表单提交的数据的类
创建一个 UserBean,其实就是个普通的Java类,其中包含与表单中属性name值同名的属性,并且有相应的 getter、setter方法
public class UserBean { @Override public String toString() { return "Username: " + this.userName + " Password: " + this.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; } private String userName; private String password; }
这个UserBean中的 toString() 方法是为了测试的时候便于打印输出而添加的,不是必须的
4.创建实现自动填充功能的工具类
接下来这步是关键部分了,能够实现将表单数据自动填充到一个类中就主要是在这里实现了。
import java.lang.reflect.Field; import java.lang.reflect.Method; import javax.servlet.http.HttpServletRequest; public class AutoFillBeanUtil { public static <T> T fillBean(HttpServletRequest request, Class<T> cls) { T bean = null; try { bean = cls.newInstance(); Field[] fields = cls.getDeclaredFields(); for(Field field : fields) { String fieldName = field.getName(); Method method = cls.getDeclaredMethod("set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1), String.class); String value = request.getParameter(fieldName); method.invoke(bean, value); } } catch(Exception e) { e.printStackTrace(); } return bean; } }
这里利用反射机制,首先获取需要被填充的JavaBean(也就是这里的cls参数)的所有属性,然后逐一尝试从请求中获取相应的参数,然后调用这个JavaBean的setter方法,将从请求中获取的值设置到这个JavaBean中,最后返回这个JavaBean。
5.创建接受表单请求的Servlet进行测试
接下来创建用于接受表单请求的Servlet,然后在Servlet中调用这个实现,测试效果
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.oolong.javawebreflect.bean.UserBean; import com.oolong.javawebreflect.util.AutoFillBeanUtil; @WebServlet("/LoginServlet") public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; public LoginServlet() { super(); } protected void doGet(HttpServletRequest request , HttpServletResponse response) throws ServletException, IOException { response.getWriter().append("Served at: ") .append(request.getContextPath()); } protected void doPost(HttpServletRequest request , HttpServletResponse response) throws ServletException, IOException { UserBean bean = AutoFillBeanUtil.fillBean(request, UserBean.class); System.out.println(bean.toString()); doGet(request, response); } }
这里可以看到,调用了
UserBean bean = AutoFillBeanUtil.fillBean(request, UserBean.class);
然后会从请求中将表单中的数据解析出来,填充到一个UserBean中,之后会打印这个UserBean中的内容,查看是否获取成功。
结果:
控制台打印:
测试成功!