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