今天来看一下Struts1的相关知识,其实Struts现在是出名的,每个Web开发者都会知道的,也是现在比较流行的框架,下面就来看一下我们为什么要用Struts框架呢?
1.建立在mvc这种好的模式上的,Struts在m,v,c上都有涉及,但主要的是提供一个好的控制器和一套定制的标签库上也就是说它在这里体现在c和v上,有mvc的一系列的优点,如:结构层次分明,高重用性,增加了程序的健壮性和可伸缩性,便于开发与设计分工,提供集中统一的权限的控制,校验,国际化,日志等等
2.开源项目,得到了包括它的发明者Craig R.McClanahan在内的一些程序大师和高手持续而细心的呵护,并且经受了实战的检验,使其功能越来越强大。
3.其他技术和框架具有很好的融合性,如与Spring,hibernate等框架的整合
4.大大提高了开发速度
1.新建web工程
2.加入必要的jar包
当然还可能需要其他的jar,这个在实际应用用遇到问题或者报错,我们可以添加相应的jar,而没必要刻意的去记住哪些jar
3.在WEB-INF下加入配置文件struts-config.xml
主要在这里我们需要配置我们定义的ActionForm,和Action
4.配置web.xml
配置Struts中的总控制器ActionServlet,把配置文件作为一个实例化参数的值传进来的(这里可以传递多个配置文件的,中间使用逗号进行分割的,具体可以查看源码ActionServlet),而且我们还看到这个servlet的启动优先级是0,也就是最高的优先级,这个只是我们在之前JavaWeb学习篇中的Servlet中说过,还有就是要配置访问的映射url,这里是只要后缀名是.do的就可以
action
org.apache.struts.action.ActionServlet
config
/WEB-INF/struts-config.xml
0
action
*.do
index.jsp
2) 注册,修改strutrs-config.xml
Path:指明调用者(jsp)能通过中心控制器ActionServlt找到该Action
Type:指明该Action的类名Name:该Action应用的Form名称
package cn.com.hewei.Bean;
import org.apache.struts.action.ActionForm;
public class LoginForm extends ActionForm {
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;
}
}
package cn.com.hewei.Action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import cn.com.hewei.Bean.LoginForm;
public class LoginAction extends Action {
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
// 转换成LoginForm
LoginForm login = (LoginForm) form;
if (login.getUserName().equals("admin")) {
return mapping.findForward("loginSuccess");
} else {
return mapping.findForward("loginFail");
}
}
}
我们要注意一点所有的path=都要以“/”开头
Login.jsp
Login Success
Login Fail
1)在浏览器的地址栏中输入index.jsp
2)输入用户名密码后点击提交,跳转到Login.do、
3)因为是.do结尾的所以会被web.xml的ActionServlet解析到,ActionServlet会查看struts-config.xml文件,根据action标签的path和跳 转到LoginAction这个Servlet目录
4)跳转时,会根据action的name属性带着ActionForm中的内容交给LoginAction处理
5)LoginAction处理好后根据findForward将跳转的关键字带给ActionServlet处理,ActionServlet会查看Struts-config.xml文件根据forward标签,和name属性(那么属性判断带来的关键字)跳转到path指定的路径
1.读取配置(初始化ModuleConfig对象)
Struts框架总控制器(ActionServlet)是一个Servelt,在web.xml中配置成自动启动的Servlet,在Web.xml中配置成自动启动的Servlet。读取配置文件(Struts-config.xml)的配置文件信息,为不同的Struts模块初始化响应的ModuleCofig对象:ActionConfig,ControlConfig,FormBeanConfig,ForwardConfig,MessageResourcesConfig(一定要记得看源码)
2.发送请求
用户提交表单或调用URL向web应用的程序器提交一个请求,请求的数据用HTTP协议上传给Web服务器
3.填充Form(实例化,复位,填充数据,校验,保存)
(*.do请求)从ActionConfig中找到对应该请求的Action的子类,如没有对应的Action,控制器直接转化给Jsp或静态的页面。如有对应的Action且这个Action有一个对应的ActionForm,ActionForm被实例化并用HTTP请求的数据填充其属性,并且保存在ServletConfig中(request或session中),这样他们就可以被其他的Action对象或者Jsp调用了。这个后面会说到如何保存这个form到各个域中
4.派发请求
控制器根据配置信息ActionConfig将请求派发到具体的Action,相应的FormBean一并传给这个Action的execute()方法
5.处理业务
Action一般只包含一个execute()方法,它负责执行相应的业务逻辑(调用其他业务模块)。完毕返回一个ActionFoward对象,控制器通过这个AcationForward对象进行转发工作。
6.返回响应
Action根据业务逻辑处理的不同结果返回一个目标响应对象总控制器,该目标响应对象给总控制器,该目标响应对象对应一个具体的Jsp页面或另一Action
7.查找响应(翻译响应)
总控制器根据业务功能Action返回的目标响应对象,找到对应的资源对象,通常是一个具体的jsp页面.
8.响应客户
目标响应对象结果展现给用户目标响应对象(JSP)将结果页面展现给用户。
ActionServlet
Acation Classes,
Action Mapping(此包括ActionForward)
ActionForm Bean。
定义:继承自javax.servelt.http.HttpServlet类,是中心控制器(总控制器)。它提供了一个中心位置来处理全部的终端请求
1)作用:接受请求,填充数据,派发请求,响应用户
2)配置:在web配置文件(web.xml)声明:
org.apache.struts.action.ActionServlet
config
/WEB-INF/struts-config.xml
0
action
*.do
实例:设计一个实例变量count,统计访问的次数
package cn.com.hewei.Action;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
public class CountAction extends Action{
int count=0;
@Override
//每个访问一个execute方法
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
response.setCharacterEncoding("gbk");
request.setCharacterEncoding("gbk");
synchronized (this) {
count++;
}
PrintWriter out=response.getWriter();
out.print("访问的次数"+count);
return null;
}
}
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
// 获得Action的name
String name=mapping.getName();
// 获得Action的type
String type=mapping.getType();
// 获得Action的path
String path=mapping.getPath();
String []forwardNames=mapping.findForwards();
System.out.println("name "+name);
System.out.println("path "+path);
System.out.println("type "+type);
for(String forwardName:forwardNames ){
ActionForward forward=mapping.findForward(forwardName);
String forwardPath=forward.getPath();
System.out.println("forwardName "+forwardName);
System.out.println("forwardPath "+forwardPath);
}
}
redirect:控制转发还是重定向
注意:
1.无参构造函数必须要有(通过读取配置文件中的信息进行实例化)
2.Scope缺省值为session
我们怎么查看是否往scope中添加了元素了呢?我们可以使用监听器来做(这个我们在前面说到Servlet中的监听器和过滤器)
1)监听HttpSessionAttributeListener,
ServletRequestAttributeListener接口
package cn.com.hewei.listener;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import org.apache.struts.action.ActionForm;
public class ActionListener implements HttpSessionAttributeListener,ServletRequestAttributeListener {
public void attributeAdded(HttpSessionBindingEvent event) { //得到session中的name
String attributeName=event.getName();
//得到session中的value,判断是否是struts的类
if(event.getValue() instanceof ActionForm){
System.out.println("Add a Session Attribute");
System.out.println("name="+attributeName+",value="+event.getValue());
}
}
public void attributeReplaced(HttpSessionBindingEvent event) {
String attributeName=event.getName();
if(event.getValue() instanceof ActionForm){
System.out.println("Replace a Session Attribute");
System.out.println("name="+attributeName+",value="+event.getValue());
}
}
public void attributeAdded(ServletRequestAttributeEvent event) {
String attributeName=event.getName();
if(event.getValue() instanceof ActionForm){
System.out.println("Add a Request Attribute");
System.out.println("name="+attributeName+",value="+event.getValue());
}
}
public void attributeReplaced(ServletRequestAttributeEvent event) {
String attributeName=event.getName();
if(event.getValue() instanceof ActionForm){
System.out.println("Replace a Request Attribute");
System.out.println("name="+attributeName+",value="+event.getValue());
}
}
}
2)注册监听器
cn.com.hewei.listener.ActionListener
3.reset方法,是让表当中的数据恢复默认值
4.调用setter方法,实际上是调用对应的标准set方法,比如username有setUsername()
5.
6.配置文件中的属性
1)
2)
所描述的是将特定的请求路径和一个相应的Action类之间的映射关系,有以下的属性
attribute:设置和Action关联的formbean在request/session内的属性key,通过request/session的getAttribute(attribute)方法返回该formbean实例(用来存取form的关键字,缺省值和formbean标签中的name一样的)
validate:用来控制是否校验表单,(校验表单时,当返回null或者ActionErrors没有带ActionMessage信息时,校验成功)
input:当表单验证失败时请求转发的URL,一般结合validate=“true“使用
public ActionErrors validate(ActionMapping mapping,
HttpServletRequest request) {
ActionErrors errors=new ActionErrors();
ActionMessage m=new ActionMessage("ss");
errors.add("error",m);
return errors;
}
我们在jsp中可以通过
查找响应
set()/get()
reset()validate()
Execute(ActionMapping,ActionForm,HttpServletRequest,HttpServletResponse)
属性:path,type,name,validate,forwards(HashMap)
name,path
分析:
1)创建AddstudentForm对象----根据类的全名进行反射(Class.forName)
2)需要把页面的参数提取出来(request.getParameterNames()----Enumeration)
3)把参数名与bean的属性名进行匹配:如果能匹配就把取出来的值填充到bean中(借助BeanUtils)
4)保存form
设计一个FormUtil完成以上描述的功能
package cn.com.hewei.util;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.struts.action.ActionForm;
public class FormUtil {
public static void fillForm(HttpServletRequest request,
String formClassFullName, String ClassName)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException, InvocationTargetException {// 实例化实体
ActionForm form = (ActionForm) Class.forName(formClassFullName).newInstance();
// 得到所有从网页传来的参数
Map parameters = request.getParameterMap();
// 得到所有bean中的参数
Field[] fields = Class.forName(formClassFullName).getDeclaredFields();
// 填充bean
BeanUtils.populate(ClassName, parameters);
// 往session中传数
request.getSession().setAttribute(ClassName, form);
}
}
1)Bean标记:用来在Jsp页中管理bean
2)逻辑标记:用来在Jsp页中控制流程3)Html标记:用来生成HTML标记,在表单中显示数据,使用会话的ID对URL进行编程
Struts提供了很多表单相关的自定义标签,如:
这些标签除用于生成相应的html标签外,最大的好处在于它在产生html标签时,会自动检索相应formbean的数据予以显示,这样,当表单校验失败时,表单数据的回显struts帮我们干了,开发人员就不需要再编码去取了。
使用Struts的html标签完成数据回显时注意的问题:
html标签回显数据时,会以org.apache.struts.taglib.html.BEAN为关键字,从各个域中查找bean,找不到则抛空指针异常。所以使用html标签时域中须有以org.apache.struts.taglib.html.BEAN为关键字的对象。
这个工作可以交给html:form标签做,html:form标签在执行时,会查找域中已有的formbean,并以org.apache.struts.taglib.html.BEAN为关键字把formbean存在域中。如果html:form标签在域中找不到formbean,则html:form标签会实例化一个空bean,然后存储到域中。因此,为了在页面中使用struts的html标签回显数据,这些标签需要配合html:form标签使用。(查看html:form标签的源文件可以看到这点)。
对于复选框中的数据,Html:checkbox标签不能完成数据回显,复选框的数据回显需要使用html:multibox。
Struts中的html:password标签也会回显数据,如果不想password回显,需要把其redisplay属性置为false。
4)tiles标记:使用动态模块构造普通格式的的页
<%@ page language="java" import="java.util.*" pageEncoding="gbk"%>
<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="b"%>
My JSP 'BeanUtil.jsp' starting page
<%String userName="ss";request.setAttribute("userName",userName);%>
${sessionScope.name}
这里注意的是scope是从哪个域中进行取值,toScope是将取出来的值放到哪个域中
com.itcast.AlliacationRescources.properties
com.itcast. AlliacationRescources_zh-CN.properties
下面是AlliacationRescources_zh-CN.properties的内容:
这个是UTF-8编码之后的内容了
在struts-config中添加
这里的填写的就是资源文件的全称地址,但是要注意不需要后缀名的,而且这里可以配置多个资源文件的
页面中使用
注意:上面配置的key=”myKey”和这里的bundle=”myKey”可以不写
package cn.com.hewei.Action;
import java.sql.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;
public class DynAddStudentAction extends Action {
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
DynaActionForm dynform = (DynaActionForm) form;
// 获得信息
String name = (String) dynform.get("sname");
Date birthday = (Date) dynform.get("birthday");
String major = (String) dynform.get("major");
Float score = (Float) dynform.get("score");
System.out.println("name=" + name + "birthday=" + birthday + "score="
+ score);
return null;
}
}
这里的path是要跳转的页面,type是异常的类型,key是异常的关键字,相应action中execute抛出异常就会跳到这里处理
2.全局异常的配置
<%@taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
调用
输出所有的异常信息
package cn.com.hewei.plugin;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class SessionFactoryManager {
private static String hibernateConfigFile = null;
public static String getHibernateConfigFile() {
return hibernateConfigFile;
}
public static void setHibernateConfigFile(String hibernateConfigFile) {
SessionFactoryManager.hibernateConfigFile = hibernateConfigFile;
}
private static Configuration con = null;
private static SessionFactory sessionFactory = null;
public static SessionFactory getSessionFactory() {
con = new Configuration().configure(hibernateConfigFile);
sessionFactory = con.buildSessionFactory();
return sessionFactory;
}
public static void closeSessionFactory() {
if (sessionFactory != null && sessionFactory.isClosed() == false)
sessionFactory.close();
}
}
package cn.com.hewei.plugin;
import javax.servlet.ServletException;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.PlugIn;
import org.apache.struts.config.ModuleConfig;
public class HibernatePlugin implements PlugIn {
private String hibernateConfigFile;
public String getHibernateConfigFile() {
return hibernateConfigFile;
}
public void setHibernateConfigFile(String hibernateConfigFile) {
this.hibernateConfigFile = hibernateConfigFile;
}
public void destroy() {
// 关闭sessionFactory
System.out.println("closeSessionFactory");
SessionFactoryManager.closeSessionFactory();
}
public void init(ActionServlet arg0, ModuleConfig arg1)
throws ServletException {
System.out.println("openSessionFactory");
// 1.读取hibernate配置文件
SessionFactoryManager.setHibernateConfigFile(hibernateConfigFile);
// 2.打开sessionFactory
SessionFactoryManager.getSessionFactory();
}
}
在action标签中使用parameter属性:
调用:http://localhost:8081/Mystruts/SrudentAction?method=update
实例:
1,继承DispathAction
package cn.com.hewei.Action;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;
public class StudentAction extends DispatchAction{
public ActionForward addStudent(ActionMapping arg0, ActionForm arg1,
HttpServletRequest arg2, HttpServletResponse arg3) throws Exception {
PrintWriter out=arg3.getWriter();
out.println("addStudent");
return null;
}
public ActionForward deleteStudent(ActionMapping arg0, ActionForm arg1,
HttpServletRequest arg2, HttpServletResponse arg3) throws Exception {
PrintWriter out=arg3.getWriter();
out.println("deleteStudent");
return null;
}
public ActionForward updateStudent(ActionMapping arg0, ActionForm arg1,
HttpServletRequest arg2, HttpServletResponse arg3) throws Exception {
PrintWriter out=arg3.getWriter();
out.println("updateStudent");
return null;
}
}
输出:updateStudent
public class StudentAction extends MappingDispatchAction{
public ActionForward addStudent(ActionMapping arg0, ActionForm arg1,
HttpServletRequest arg2, HttpServletResponse arg3) throws Exception {
PrintWriter out=arg3.getWriter();
out.println("addStudent");
return null;
}
public ActionForward deleteStudent(ActionMapping arg0, ActionForm arg1,
HttpServletRequest arg2, HttpServletResponse arg3) throws Exception {
PrintWriter out=arg3.getWriter();
out.println("deleteStudent");
return null;
}
public ActionForward updateStudent(ActionMapping arg0, ActionForm arg1,
HttpServletRequest arg2, HttpServletResponse arg3) throws Exception {
PrintWriter out=arg3.getWriter();
out.println("updateStudent");
return null;
}
}
http://localhost:8080/Mystruts/updateStudent.do
Struts的
代码如下:
package cn.com.ambow.struts.day3;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.MappingDispatchAction;
public class TokenAction extends MappingDispatchAction {
public ActionForward toLogin(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
ActionForward forward = null;
// 生成随机数
saveToken(request);
return mapping.findForward("login");
}
public ActionForward login(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
ActionForward forward = null;
try {
String name = request.getParameter("userName");
String password = request.getParameter("password");
IUserDao dao = new UserDaoImpl();
// 比较token
if (!isTokenValid(request, true)) {
request.setAttribute("message", "Token Error!!");
forward = mapping.findForward("error");
} else {
User user = dao.findByNameAndPassword(name, password);
if (user != null) {
request.setAttribute("user", user);
forward = mapping.findForward("success");
} else {
request.setAttribute("message", "Login Error!!");
forward = mapping.findForward("error");
}
}
} catch (Exception e) {
e.printStackTrace();
request.setAttribute("message", "Login Error!!");
forward = mapping.findForward("error");
}
return forward;
}
}
<%@ page language="java" import="java.util.*" pageEncoding="gbk"%>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%>
My JSP 'login.jsp' starting page
测试Srtuts1 Token
userName:
password:
访问toLogin.do会带来jsessionid,跳到登录页面,登录页面跳转到login.do执行,isTokenValid(request, true)判断是否重复提交。
Validator(验证器)框架是一个 Struts 插件,它支持采用声明式的方式对表单进行校验,而不需要用户编写一行Java代码。集成validate框架 ,Struts那哥们他帮你校验了表单,而且客户端也校验,比如javascript校验他也帮你校验了使用 Validator 框架的好处:
更好的可维护性
校验实现标准化
正确的实现
更少的代码重复
自动客户端验证
解压Struts的例子struts-cookbook-1.3.8,部署到web服务器中,查看例子体验。
在工程中集成validate框架,你需要查看org.apache.struts.validator包下的validator-rules.xml文件,它是validate框架的校验规则文件,这个文件说明了如何在struts工程中集成validate框架:
1、在struts-config.xml文件中配置validate插件。
2、创建资源文件,并复制validate框架工作需要的信息。
3、把struts-cookbook-1.3.8例程自带的、validate框架的配置文件validation.xml,复制到当前web工程的WEB-INF目录下。
validate框架环境搭建好后,就可以采用配置的方式对formbean的属性进行校验,但需要注意:
1、formbean要想使用validate框架校验,不能直接继承 ActionForm, 而要继承其子类 ValidatorForm。
2、如果是DynaActionForm,就必须要继承DynaValidatorForm
Validation.xml文件详解
:为表单配置验证规则,它的 name 属性指定了表单的名字.