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;
}
}