Struts2框架01

1.1 Struts2框架的MVC

M:JavaBean + ModelDriven
		V:JSP + OGNL
		C:Action

1.2 Struts2的两个重要组成部分

Struts2的两个重要组成部分是:核心控制器和业务控制器

1.2.1 核心过滤器:StrutsPrepareAndExecuteFilter

作用:负责拦截所有用户的请求,该Filter在过滤用户请求后,将请求都交给Struts2框架处理。
拦截器会默认拦截扩展名为.action的请求,什么后缀都不写也可以。
例如:hello.action或者hello都会被拦截;hello.jsp就不会进行拦截,直接放行。

1.2.2.业务控制器:Action

业务控制器就是用户实现的Action类,Action类中通常包含一个execute方法,该方法返回一个字符串
(即结果码),字符串与struts.xml中的result的name相对应,跳转到不同页面。
每次实例化对象,线程安全;Servlet是单实例的,所以线程不安全

2.Action中获取Web对象

Action获取Web对象有三种方式:ActionContext类、ServletActionContext类、ServletXxxAware接口。
其中:前者为解耦方式,推荐;后两者为耦合方式,不推荐。

解耦方式——即struts2测试时不需要启动服务器,提高开发效率。

2.1 使用ActionContext类(解耦)

Web应用中通常需要访问的Servlet API就是HttpServletRequest、HttpSession和ServletContext,这三个接口分别代表JSP内置对象中的request、session和application。

Struts2提供了一个ActionContext类(com.opensymphony.xwork.ActionContext),它是Action执行时的上下文,上下文可以看作是一个容器(其实我们这里的容器就是一个Map而已),它存放的是Action在执行时需要用到的对象。可以通过下面方法访问Servlet API:在这里插入图片描述

ActionContext ac = ActionContext.getContext();
//2.直接获取请求参数
Map<String, Object> paramsMap = Ac.getParameters();
//参数被封装成String[]
String[] methodNameParam = (String[])paramsMap.get(“methodName”);
for(String s : methodNameParam){
System.out.println(s);
}
//3.获得HttpServletRequest对象的attribute(解耦)
Map<String, Parameter> paramsMap =context.getParameters(); //获得上下文中所有的参数值
String type = paramsMap.get(“type”).toString(); //从获得的参数值中查找某个

案例1:使用ActionContext获得JSP表单中的数据

(1)创建表单,提交表单到action里面

<form action=”/register” method=”post”>
			用户名:<input type=”text” name=”uname” />
			手机号:<input type=”text” name=”moblie” />
			性  别:<input type=”radio” name=”sex” value=”1” />男 
			<input type=”radio” name=”sex” value=”0” />女
            <input type=”submit” value=”提交” />
</form>

(2)在action使用ActionContext获取表单数据:

ActionContext context = ActionContext.getContext();
			// map的key就是表单项的各name
			Map<String, Object> map = comtext.getParameters();
			//查看Map中的数据
			Set<String> keys = map.keyset();
			for(String key : keys){
			    Object[] obj = (Object[])map.get(key);
			System.out.println(Arrays.toString(obj));
}

2.2.使用ServletActionContext类(耦合)

在Action中通过ServletActionContext类也能获得Web对象,但不建议直接访问Servlet的API,这样做不利于项目的移植。

HttpServletRequest request = ServletActionContext.getRequest();
//System.out.println(request.getParameter("uname"));
request.setAttribute("request", "1");
				
HttpSession session = request.getSession();
session.setAttribute("session", "2");

ServletContext application = request.getSession().getServletContext();
application.setAttribute("application", "3");

2.3 使用ServletXxxAware接口注入(耦合)

使用ServletContextAware、ServletRequestAware、ServletResponseAware三个接口可直接获得Servlet API。
Step1:类实现ServletResponseAware接口(或其它两个接口)。
Step2:重写相应的方法:

3.Action数据封装(属性驱动、模型驱动)
案例:表单数据提交
对应数据在前台与后台中的交互,Struts2框架替我们做了很大部分的数据封装工作。既可以封装单个对象,也可以封装集合。

实现Action有两大方式:属性驱动、模型驱动。

(1)属性驱动
使用属性作为贯穿MVC流程的信息携带者,依附于Action实例,Action实例封装请求参数和处理结果。
属性驱动有三种:普通POJO类、实现Action接口、继承ActionSupport(推荐)

(2)模型驱动
就是使用单独的JavaBean实例来贯穿整个MVC流程,JavaBean实例封装请求参数和处理结果。
模型驱动有一种:ModelDriven

3.1.普通POJO类
思路:在Action中封装表单属性。

实现一个登录Action:
在这里插入图片描述

public String execute() throws Exception {
        if("admin".equals(getuserName()) && "123456".equals(getpassword())){
            return "success";
        }else{
            return "error";
        }
    }
}

3.2.实现Action接口

思路:
(1)Action类实现Action接口,重写execute()方法,返回时使用Action接口中的常量;
(2)在Action中声明成员变量,成员变量名与表单项name属性一致;
(3) 封装。
在这里插入图片描述

3.3继承ActionSupport类(推荐)
实现步骤:
(1)继承ActionSupport,重写execute()方法。不继承也可以,直接写execute()方法;
(2)在Action中声明成员变量,成员变量名与表单项name属性一致;
(3)封装。

在这里插入图片描述
3.4 模型驱动封装:ModelDriven(推荐)
模型驱动:就是使用单独的JavaBean实例来贯穿整个MVC流程,JavaBean实例封装请求参数和处理结果。

实现步骤:
(1)Action类实现ModelDriven接口;
(2)实现接口的getModel()方法,并把创建对象返回;
(3)在Action中创建实体类对象;
(4)execute()一样法中使用实体类对象名即可。

案例:
在这里插入图片描述
User类:属性名要与表单控件名字相同,否则报错。在这里插入图片描述

4.1 封装数据到List集合
List集合使用‘变量名[索引].属性’的形式。

前台:
			<form method="post" action="userAction_addStuList">  
			学生1   
			编号:<input type="text" name="stuList[0].stuNo" />  
			姓名:<input type="text" name="stuList[0].stuName" />  
			年龄:<input type="text" name="stuList[0].stuAge" /><br/>  
			学生2   
			编号:<input type="text" name="stuList[1].stuNo" />  
			姓名:<input type="text" name="stuList[1].stuName" />  
			年龄:<input type="text" name="stuList[1].stuAge" /><br/>  
			学生3   
			编号:<input type="text" name="stuList[2].stuNo" />  
			姓名:<input type="text" name="stuList[2].stuName" />  
			年龄:<input type="text" name="stuList[2].stuAge" /><br/>  
			<input type="submit" value="提交" />  
			</form>  

实例类:
			public class Student implements Serializable{  
			private Integer stuId;
			private String stuNo;
			private String stuName;
			private String stuAge;
			// 此处省略set和get方法
			public Student() {  }
			    public Student(int stuId, String stuNo, String stuName, String stuAge) {  
			        super();  
			        this.stuId = stuId;  
			        this.stuNo = stuNo;  
			        this.stuName = stuName;  
			        this.stuAge = stuAge;  
			    }
			}
Action类:
				public class UserAction extends ActionSupport {
				@Element(Student.class)
				private List<Student> stuList;
				public void setStuList(List<Student> stuList){
				    this.stuList = stuList;
				}
				public List<Student> getStuList(){
				    return this.stuList;
				}
				
				public String addStuList(){  
				    for (Student stu : stuList) {  
				        System.out.println(stu);  
				    }  
				    return SUCCESS;  
				}
				}

4.2 封装数据到Map集合
Map集合使用的是‘变量名.key名.属性’ 也可以是‘变量名[‘key’].属性’。

前台:
<form method="post" action="userAction_addStuMap">  
学生1   
编号:<input type="text" name="stuMap['stu1'].stuNo" />  
姓名:<input type="text" name="stuMap['stu1'].stuName" />  
年龄:<input type="text" name="stuMap['stu1'].stuAge" /><br/>  
学生2   
编号:<input type="text" name="stuMap.stu2.stuNo" />  第二种写法
姓名:<input type="text" name="stuMap.stu2.stuName" />  
年龄:<input type="text" name="stuMap.stu2.stuAge" /><br/>  
学生3   
编号:<input type="text" name="stuMap.stu3.stuNo" />  
姓名:<input type="text" name="stuMap.stu3.stuName" />  
年龄:<input type="text" name="stuMap.stu3.stuAge" /><br/>  
<input type="submit" value="提交" />  
</form>  

实体类:同上

Action类:
public class UserAction extends ActionSupport { 
    @Key(String.class)  
    @Element(Student.class)  
private Map<String, Student> stuMap = new HashMap<>();
//此处省略公开setList的set和get方法

public String addStuMap(){  
        for (String key : stuMap.keySet()) {  
            System.out.println(key + "----" + stuMap.get(key));  
        }  
        return SUCCESS;  
}
}

4.3 封装数据到Set集合
Set集合比较特殊,必须使用到OGNL中makeNew的运算符来表示。格式:变量名.makeNew[索引].属性

前台:
<form method="post" action="userAction_addStuSet">  
学生1   
编号:<input type="text" name="stuSet.makeNew[0].stuNo" />  
姓名:<input type="text" name="stuSet.makeNew[0].stuName" />  
年龄:<input type="text" name="stuSet.makeNew[0].stuAge" /><br/>  
学生2   
编号:<input type="text" name="stuSet.makeNew[1].stuNo" />  
姓名:<input type="text" name="stuSet.makeNew[1].stuName" />  
年龄:<input type="text" name="stuSet.makeNew[1].stuAge" /><br/>  
学生3   
编号:<input type="text" name="stuSet.makeNew[2].stuNo" />  
姓名:<input type="text" name="stuSet.makeNew[2].stuName" />  
年龄:<input type="text" name="stuSet.makeNew[2].stuAge" /><br/>  
<input type="submit" value="提交" />  
</form>  

实体类:同上

Action类:
public class UserAction extends ActionSupport { 
    // Student中的标识字段,该字段需要get方法,该配置不可少
    @KeyProperty("stuNo")    
    @Element(Student.class)    
    private Set<Student> stuSet = new HashSet<>(); 
//此处省略公开setList的set和get方法

public String addStuSet(){ 
        System.out.println(stuSet);  
        for (Student stu : stuSet) {  
            System.out.println(stu);  
        }  
        return SUCCESS;  
}
}