学习struts的基本原理是为了更好的使用struts来解决问题。分析一下写struts的思路和尝试模拟写某些代码,能加深对struts原理的理解。下面就来模拟struts填充form的功能。初步分析一下可以抽取如下的过程:首先是根据类的全名进行反射创建ActionForm,然后需要把页面的参数提取出来,最后把参数名与bean中的属性名进行匹配,如果一致就填充到bean中。下面就是填充Form时的模拟工具类代码:
public class FormUtil {
public static void fillForm(HttpServletRequest request, String formClassName, String formName) {
try {
ActionForm form = (ActionForm) Class.forName(formClassName).newInstance();
Enumeration parameterEnumeration = request.getParameterNames();
Field[] fields = form.getClass().getDeclaredFields();
while (parameterEnumeration.hasMoreElements()) {
String parameterName = (String) parameterEnumeration.nextElement();
for (Field field : fields) {
String fieldName = field.getName();
if (parameterName.equals(fieldName)) {
String value = request.getParameter(parameterName);
BeanUtils.setProperty(form, fieldName, value);
}
}
}
request.getSession().setAttribute(formName, form);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void fillForm_(HttpServletRequest request, String formClassName, String formName) {
try {
ActionForm form = (ActionForm) Class.forName(formClassName).newInstance();
Enumeration parameterEnumeration = request.getParameterNames();
PropertyDescriptor[] properties = Introspector.getBeanInfo(form.getClass()).getPropertyDescriptors();
while (parameterEnumeration.hasMoreElements()) {
String parameterName = (String) parameterEnumeration.nextElement();
for (PropertyDescriptor property : properties) {
String propertyName = property.getName();
if (rparameterName.equals(propertyName)) {
String value = request.getParameter(parameterName);
BeanUtils.setProperty(form, propertyName, value);
}
}
}
request.getSession().setAttribute(formName, form);
} catch (Exception e) {
e.printStackTrace();
}
}
}
如上面的代码所示,首先是通过类的全名载入类的字节码并实例化一个ActionForm对象。接着是通过request的getParameterNames()方法获取浏览器传递过来的所有的参数的集合。第三步是获取ActionForm对象中的成员变量,实际的struts是根据getter和setter方法来填充form的。这里为求简便,只是简单模拟,所以通过字段名来填充form。程序中是将得到的参数名和form中的字段名进行匹配。如果匹配,就将从客户端获得的参数值设置到相应的属性上。最后是将form表单存入session范围里面。上面的代码中有两个填充表单的工具方法,总的来说,第二个方法要相对优雅一些。因为第二个方法不是获取所有的声明的字段,而是获取bean属性。bean属性和字段还是有区别的,bean属性需要满足一定的规范,将满足条件的属性放入PropertyDescriptor数组中,而第一个是直接将声明的普通字段全部放入Field数组。但是两者的过程其实差不多,代码也很相似。就两行代码有点差别。
有了上面这个工具,就可以模拟一下struts了。这里假设配置信息已经获取到,所以程序中直接用。模拟ActionServlet的代码,就只是简单创建一个Servlet,重写doPost和doGet方法。
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String formClassName= "com.yxb.struts.AddStudentForm";
String formName = "addStudentForm";
FormUtil.fillForm(request, formClassName, formName);
System.out.println(request.getSession().getAttribute(formName));
request.getRequestDispatcher("addStudentSuccess.jsp").forward(request, response);
}
上面的代码表示,当请求到达ActionServlet后,通过前面的表单填充工具类创建一个form表单,然后模拟转发请求道相应的JSP页面。为了看到填充成功,直接在控制台打印出相应的form表单中的信息。其中模拟的ActionForm与前面的写法一模一样,只是重写了toString方法,打印出该类中所以字段的名字和相应的值。最 后建立相应的请求和结果的JSP页面,web.xml文件中的ActionServlet换成自己写的类。完成后就可以访问这个应用程序了,当发送请求后,就会发现form表单的值填充成功了。写完这个应用后,就会发现对struts的原理有了进一步的理解。视频中原理的讲解基本上就结束了。下面学习的是struts的标签以及其他功能。
struts标记库有四类,分别是html、bean、logic和tiles标记。其中struts的html标记是用来生成HTML标记的,bean标记用来在JSP页面中管理struts应用的Bean,logic标记用来在JSP页面中控制流程,最后的tiles标记用模板来动态生成普通的页面。
现在从bean标记库来开始学习struts的标记库。bean标记库中包含用于定义新bean、访问bean及其属性的标记。它可以分为四个子类:创建和复制bean的标记、脚本变量定义标记、bean翻译标记和消息国际化标记。要在JSP页面中使用标签,就要引入tablib指令:
<%@ taglib prefix="bean" uri="http://struts.apache.org/tags-bean" %>
<bean:define id="new_user" name="user" scope="request" toScope="session" property="userName"/>
<bean:write name="new_user" scope="session"/>
上面代码是比较常用的,其中第二行是定义一个新的变量。这个名字是new_user的变量存储的值是名字为user的bean里面属性为userName的成员变量的值。user变量就是一个简单的用户类,只有userName和passWord这两个属性和相应的getter和setter方法。为了试验这个标签,可以在页面上创建如下JAVA脚本:
<%
User user = new User();
user.setUserName("zhangsan");
user.setPassWord("123");
request.setAttribute("user",user);
%>
这是模拟应用程序将bean对象放入相应的作用域中,通常情况下是相应的actionForm对象。需要注意的是上面的<bean:define>中的property属性没有指定,则定义的是user对象的一个引用,如过是java的基本类型,则会自动生成包装类的对象引用。出此之外还有两个属性是与范围有关的,一个是scope属性,它指定应该从哪些地方去找name属性值所表示的bean对象。而toScope属性则是指定新定义的变量应该存储在那个作用域中。<bean:write> 标签的scope也是一样,如果指定了则只会去指定的地方查找,如果没有指定则会在四个作用域中都查找一遍,直到找到为止,否则将会报告异常。总的来说,<bean:define>标签就是从已有的变量或者变量属性定义一个新的标量,而<bean:write>则把作用域中相应的变量或者属性的值输出到客户端。