Struts2Day02(属性和模型驱动获取数据 拦截器定义配置和使用 拦截未登录用户)

回顾
1、Struts2框架的概述,前端控制器的模式,核心的过滤器
2、入门 编写 struts.xml配置文件
3、配置文件
    配置文件的加载
4、Action类的编写和访问

在Struts2框架中使用Servlet的API
1、在Action类中也可以获取到Servlet一些常用的API
    提供JSP的表单页面的数据,在Action中使用Servlet的API接收到,然后保存到三个域对象中,最后显示到JSP的页面上
        提供JSP注册的页面
            <form action="${pageContext.request.contextPath }/demo1Action.action" method="post">
                姓名:<input type="text" name="username"/><br/>
                密码:<input type="password" name="password"/><br/>
                <input type="submit" value="注册"/>
            </form>
2、完全解耦合的方式
    Struts2框架提供了一个类,ActionContext类,提供了一些方法,通过方法获取Servlet的API
    常用的方法
        static.ActionContext.getContext()           获取ActionContext对象实例
        Map<String,Object>getParameters()           获取请求参数,相当于request.getParameterMap()
        Map<String,Object>getSession()              获取的代表session域的Map集合,相当于操作session域
        Map<String,Object>getApplication()          获取的代表application域的Map集合
        void put(String key,Object value)           向request域存入值

3、使用原生Servlet的API的方式
    Struts2框架提供了一个类,ServletActionContext 提供了一些静态的方法
        getPageContext()
        getRequest()
        getResponse()
        getServletContext()

页面的跳转
1、结果页面存在两种方式
    全局结果页面
        条件:如果<package>包中deec一些action都返回success,并且返回的页面都是同一个JSP页面,这样就可以配置全局的结果页面
        全局结果页面针对的当前的包中的所有的Action,但是如果局部还有结果页面,会优先局部的,使用的标签
            <global-results>
                <result name="success">/demo1/suc.jsp</result>
            </global-results>
    局部结果页面
        <result name="success">/demo1/suc.jsp</result>
2、结果页面的类型
    结果页面使用<result>标签进行配置,包含两个属性
        name    逻辑视图的名称
        type    跳转的类型,一些常用的类型,常见的结果类型在struts-default.xml查找[重定向请求的参数没了 2个请求了]
            dispatcher      转发,type的默认值.Action-->JSP
            redirect        重定向Action-->JSP
            chain           多个action之间跳转,从一个action转发到另一个Action。Action-->Action
            redirectAction  多个action之间跳转,从一个action重定向到另一个Action。Action-->Action
            stream          文件下载时使用

框架的数据封装
1、使用的原因
    作为MVC框架,必须要负责解析HTTP请求参数,并将其封装到Model对象中
    封装数据为开发提供了很多方便
    Struts2框架提供了很强大的数据封装的功能,不再需要使用Servlet的API完成手动封装了

2、Struts2提供了两类数据封装的方式
    第一种:属性驱动
        提供对应属性的set方法进行数据封装
            表单的哪些属性需要封装数据,那么在对应的Action类中提供该属性的set方法即可
            表单中的数据提交,最终找到Action类的setXxx的方法,最后赋值给全局变量

            Struts2框架采用的拦截器完成数据的封装
            方式不是很好,因为属性很多,提供特别多的set方法,而且还需要手动将数据存入到对象中
            这种情况下,Action类就相当于一个JavaBean,没有体现MVC的思想,Action类又封装数据,又接受请求处理,耦合性较高
        在页面上使用OGNL表达式进行数据封装
            页面中使用OGNL表达式进行数据的封装,就可以直接把属性封装到某一个JavaBean的对象中
            在页面中定义一个JavaBean,并且提供set方法:例如 private User user;
            页面中的编写发生了变化,需要使用OGNL的方式,表单中的写法<input type="text" name="user.username">

            只提供一个set方法还不够,必须还需要提供user属性的get和set方法
                先调用set方法,判断一下是否有user对象的实例对象,如果没有,调用set方法把拦截器创建的对象注入进来

    第二种方式:模型驱动
        使用模型驱动的方式,也可以把表单中的数据直接封装到一个JavaBean的对象中,并且表单的写法和之前的写法没有区别
        编写的页面不需要任何变化,正常编写name属性的值
        模型驱动的编写步骤
            手动实例化JavaBean:private User user = new User();
            实现ModelDriver<T>接口,实现getModel()方法,在getModel()方法中返回user

数据封装到集合中
1、封装复杂类型的参数(集合类型Collection、Map接口等)
2、页面中可能想批量添加一些数据,那么就可以使用集合。把数据封装到集合中
3、把数据封装到Collection中
    因为Collection接口都会有下标值,所以页面的下标会有一些区别  
        <input type="text" name="products[0].name"/>
    在Action中的写法 需要提供products的集合,并且提供get和set方法

4、把数据封装到Map中
    Map集合是键值对的形式,页面的写法
        <input type="text" name="map['1'].username"/>
    Action中提供map集合,并且提供get和set方法

Struts2的拦截器
1、概述
    拦截器就是AOP(Aspect-Oriented Programming)的一种实现,(AOP是指用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作)
    过滤器:过滤从客户端发送到服务器请求的

    拦截器:拦截对目标Action中的某些方法进行拦截
        拦截器不能拦截JSP
        拦截到Action中某些方法

2、拦截器和过滤器的区别
    拦截器是基于JAVA反射机制的,过滤器是基于函数回调的
    过滤器依赖于Servlet容器,而拦截器不依赖于Servlet容器
    拦截器只能对Action请求起作用(Action中的方法)而过滤器可以对几乎所有的请求起作用(CSS JSP JS)

    拦截器采用责任链模式
        在责任链模式里,很多镀锡由每一个对象对其下家的引用而连接起来形成一条链
        责任链每一个节点,都可以继续调用下一个节点,也可以阻止流程继续执行

    在Struts2中可以定义多个拦截器,将多个拦截器按照特点顺序 组成拦截器栈(顺序调用 栈中的每一个拦截器)
3、在Struts2的核心是拦截器,运行流程
web.xml->org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter->#doFilter->execute.executeAction->dispatcher.serviceAction->创建代理对象->proxy.execute()->invocation.invoke() 迭代调用拦截器

自定义拦截器和配置
1、编写拦截器,需要实现Interceptor接口 实现接口中的三个方法
    interceptor接口有很多的实现类,编写最简单的方式就是继承AbstractInterceptor实现类
    public String intercept(ActionInvocation invocation){
        User user = ServletActionContext.getRequest().getSession.getAttribute("existUser");
        if(user == null){

        } else{
            //放行
            return invocation.invoke();
        }
    }
2、需要在struts.xml中进行拦截器的配置,一共有两种方式
    第一种
        在<package>包中定义拦截器,出现在<package>包的上方
            <interceptors>
            //调用了拦截器
            <interceptor name="DemoInterceptor" class="my.interceptor.DemoInterceptor"></interceptor>
            </interceptors>

        在某个action中加入拦截器
            <interceptor-ref name="DemoInterceptor"/>
            如果引入了自己定义的拦截器,那么Struts2框架默认的拦截器就不会再执行了,所以需要引入Struts2默认的拦截器
                <interceptor-ref name="defaultStack"/>
    第二种
        在<package>包中定义拦截器的时候,自己直接定义一个拦截器栈
            <interceptors>
                <interceptor name="DemoInterceptor" class="my.interceptor.DemoInterceptor"></interceptor>
                <!-- 定义拦截器栈 -->
                <interceptor-stack name="myStack">
                    <interceptor-ref name="DemoInterceptor"></interceptor-ref>
                    <interceptor-ref name="defaultStack"/>
                </interceptor-stack>
            </interceptors>

        在Action包中引入自己定义的拦截器栈        
            <interceptor-ref name="myStack"></interceptor-ref>

使用拦截器判断用户是否已经登录

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
struts.xml

<struts>
   <package name="demo1" namespace="/" extends="struts-default">
        <!-- 配置全局的结果页面 -->
        <!-- <global-results>
            <result name="success" type="redirect">/demo1/suc.jsp</result>
        </global-results> -->

        <!-- 完全解耦合的方式 -->
        <action name="demo1Action" class="my.demo1.Demo1Action">
            <result name="success" >/demo1/suc.jsp</result>
        </action>
        <!-- 原生的方式 -->
        <action name="demo2Action" class="my.demo1.Demo2Action">
            <!-- <result name="success">/demo1/suc.jsp</result> -->
        </action>

        <!-- 重定向到Action -->
        <action name="demo3Action_*" class="my.demo1.Demo3Action" method="{1}">
            <result name="success" type="redirectAction">demo3Action_update</result>
        </action>


   </package>

   <package name="demo2" namespace="/" extends="struts-default">
        <!-- 属性驱动的方式 -->
        <action name="regist1" class="my.demo2.Regist1Action"/>
        <!-- 属性驱动方式,把数据封装到JavaBean对象中 -->
        <action name="regist2" class="my.demo2.Regist2Action"/>
        <!-- 模型驱动的方式 -->
        <action name="regist3" class="my.demo2.Regist3Action"/>
        <!-- 把数据封装到List集合 -->
        <action name="regist4" class="my.demo2.Regist4Action"/>
        <!-- 把数据封装到Map集合 -->
        <action name="regist5" class="my.demo2.Regist5Action"/>

   </package>

  <package name="demo3" namespace="/" extends="struts-default">
        <!-- 定义了拦截器的第一种方式
        <interceptors>
            调用了拦截器
            <interceptor name="DemoInterceptor" class="my.interceptor.DemoInterceptor"></interceptor>
        </interceptors> -->
        <!-- 
            第二种方式,定义拦截器栈
         -->
        <interceptors>
            <interceptor name="DemoInterceptor" class="my.interceptor.DemoInterceptor"></interceptor>
            <!-- 定义拦截器栈 -->
            <interceptor-stack name="myStack">
                <interceptor-ref name="DemoInterceptor"></interceptor-ref>
                <interceptor-ref name="defaultStack"/>
            </interceptor-stack>
        </interceptors>
        <action name="userAction" class="my.demo3.UserAction">
            <!-- 只要是引用了自己的拦截器,默认栈的拦截器就不执行了。必须要手动引入默认栈 否则封装数据等功能都不能用了 -->
            <!-- <interceptor-ref name="DemoInterceptor"/>
            <interceptor-ref name="defaultStack"/> -->

            <!-- 引入拦截器栈 -->
            <interceptor-ref name="myStack"></interceptor-ref>
        </action>
  </package>
</struts>
/**
 * 完全解耦合的方式 使用Servlet的API
 * @author Administrator
 *
 */
public class Demo1Action extends ActionSupport {

    private static final long serialVersionUID = -894949390421537212L;
    public String execute() {
        //完全解耦合的方式
        ActionContext context =ActionContext.getContext();
        //获取到请求的参数,封装所有请求的参数
        Map<String,Object> map = context.getParameters();
        //遍历获取数据
        Set<String> keys = map.keySet();
        for (String string : keys) {
            //通过key来获取到值
            String[] vals = (String[]) map.get(string);
            System.out.println(string+":"+Arrays.toString(vals));
        }
        //如果向request对象中存入值
        context.put("msg", "东东");
        //获取其他map集合
        context.getSession().put("msg", "大哥");
        context.getApplication().put("msg", "小弟");

        return SUCCESS;
    }
}
/**
 * 原生的API
 * @author Administrator
 *
 */
public class Demo2Action extends ActionSupport{

    private static final long serialVersionUID = -8870547619062626755L;

    public String execute() {
        //获取到request对象
        HttpServletRequest request = ServletActionContext.getRequest();
        request.setAttribute("msg", "小弟");
        request.getSession().setAttribute("msg","小弟2");
        ServletActionContext.getServletContext().setAttribute("msg", "大哥");

        HttpServletResponse response = ServletActionContext.getResponse();
        //使用输出流,输出内容


        return SUCCESS;
    }
}
public class Demo3Action extends ActionSupport{

    private static final long serialVersionUID = 8482710457471965754L;
    public String save() {
        System.out.println("save。。");
        return SUCCESS;
    }

    //访问demo3Action_update
    public String update() {
        System.out.println("update。。。");
        return NONE;
    }
}
/**
 * 属性驱动
 * @author Administrator
 *
 */
public class Regist1Action extends ActionSupport {
    private static final long serialVersionUID = -2605442413925139136L;
    private String username;
    private String password;
    private Integer age;

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
    //获取值set方法 往外传值get
    public String execute() throws Exception {
        System.out.println(username+":"+password+":"+age);
        return NONE;
    }

}
/**
 * 属性驱动方式,把数据封装到JavaBean的对象中
 * @author Administrator
 *
 */
public class Regist2Action extends ActionSupport {

    private static final long serialVersionUID = 1524512405660914227L;
    //注意二:属性驱动的方式
    private User user; 

    public User getUser() {
        System.out.println("getUser");
        return user;
    }
    //set 帮你new个 直接get/set都出来算了
    public void setUser(User user) {
        System.out.println("setUser");
        this.user = user;
    }

    public String execute() throws Exception {

        System.out.println(user.toString());
        return NONE;
    }
}
/**
 * 模型驱动的方式
 *  实现ModelDrivern接口
 *  必须手动实例化对象(需要自己new)
 * @author Administrator
 *
 */
public class Regist3Action extends ActionSupport implements ModelDriven<User> {

    private static final long serialVersionUID = 1524512405663214227L;
    //必须要手动实例化
    private User user = new User();


    //获取模型对象
    public User getModel() {
        return user;
    }

    public String execute() throws Exception {
        System.out.println(user);
        return NONE;
    }
}
/**
 * 属性驱动的方式,把数据封装到List集合中
 * @author Administrator
 *
 */
public class Regist4Action extends ActionSupport  {

    private static final long serialVersionUID = 1524512405663214227L;

    private List<User> list;


    public List<User> getList() {
        return list;
    }


    public void setList(List<User> list) {
        this.list = list;
    }


    public String execute() throws Exception {
        for (User user : list) {
            System.out.println(user);
        }
        return NONE;
    }
}
/**
 * 属性驱动的方式,把数据封装到Map集合中
 * @author Administrator
 *
 */
public class Regist5Action extends ActionSupport  {

    private static final long serialVersionUID = 1524512405663214227L;

    private Map<String,User> map;


    public Map<String, User> getMap() {
        return map;
    }


    public void setMap(Map<String, User> map) {
        this.map = map;
    }


    public String execute() throws Exception {
        System.out.println(map);
        return NONE;
    }
}

Demo1.jsp

<h1>Servlet API的第一种方式[完全解耦合的方式]</h1>
<form action="${pageContext.request.contextPath }/demo1Action.action" method="post">
姓名:<input type="text" name="username"/><br/>
密码:<input type="password" name="password"/><br/>
<input type="submit" value="注册"/>
</form>

suc.jsp

<h1>使用EL表达式获取值</h1>
${msg }
${requestScope.msg }
${sessionScope.msg }
${applicationScope.msg }

Demo2.jsp

<h1>属性驱动的方式</h1>
<form action="${pageContext.request.contextPath }/regist1.action" method="post">
姓名:<input type="text" name="username"/><br/>
<input type="submit" value="注册"/>
</form>
<!-- 注意一:页面的编写规则,发生了变化,使用OGNL表达式的写法一 -->
<h1>属性驱动的方式(把数据封装到JavaBean的对象中)</h1>
<form action="${pageContext.request.contextPath }/regist2.action" method="post">
姓名:<input type="text" name="user.username"/><br/>
<input type="submit" value="注册"/>
</form>

<h1>模型驱动方式</h1>
<form action="${pageContext.request.contextPath }/regist3.action" method="post">
姓名:<input type="text" name="username"/><br/>
<input type="submit" value="注册"/>
</form>

<h1>向List集合封装数据(默认情况下,采用的是属性驱动的方式)</h1>
<!-- 后台 List<User> list -->
<form action="${pageContext.request.contextPath }/regist4.action" method="post">
    姓名:<input type="text" name="list[0].username"/><br/>
    姓名:<input type="text" name="list[1].username"/><br/>
<input type="submit" value="注册"/>
</form>

<h1>向Map集合封装数据(默认情况下,采用的是属性驱动的方式)</h1>
<form action="${pageContext.request.contextPath }/regist5.action" method="post">
    姓名:<input type="text" name="map['1'].username"/><br/>
    姓名:<input type="text" name="map['two'].username"/><br/>
<input type="submit" value="注册"/>
</form>
    /**
     * intercept用来进行拦截
     */
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        System.out.println("Action方法执行之前");
        //执行下一个拦截器 需要返回值
        String result = invocation.invoke();
        System.out.println("Action方法执行之后");
        return result;
    }

}
<struts>
    <package name="crm" namespace="/" extends="struts-default">

        <!-- 配置拦截器 -->
        <interceptors>
            <interceptor name="UserInterceptor" class="my.interceptor.UserInterceptor"></interceptor>
        </interceptors>

        <global-results>
            <result name="login">/login.htm</result>
        </global-results>

        <!-- 配置用户的模块 -->
        <action name="user_*" class="my.action.UserAction" method="{1}">
            <!-- <result name="login">/login.htm</result> -->
            <result name="success">/index.htm</result>
            <interceptor-ref name="UserInterceptor">
                <!-- login方法不拦截 -->
                <param name="excludeMethods">login</param>
            </interceptor-ref>
            <interceptor-ref name="defaultStack"></interceptor-ref>
        </action>
        <!-- 客户的模块 -->
        <action name="customer_*" class="my.action.CustomerAction" method="{1}">
            <interceptor-ref name="UserInterceptor"></interceptor-ref>
            <interceptor-ref name="defaultStack"></interceptor-ref>
        </action>

    </package>    

</struts>
/**
 * 自定义拦截器,判断当前是否已经登录,如果登录,继续执行。如果没有登录,跳转到登录页面
 * @author Administrator
 *
 */
public class UserInterceptor extends MethodFilterInterceptor{

    private static final long serialVersionUID = -5152960937504606199L;
    /**
     * 进行拦截的方法
     */
    protected String doIntercept(ActionInvocation invocation) throws Exception {
        //获取session对象
        User user = (User) ServletActionContext.getRequest().getSession().getAttribute("existUser");
        if(user == null) {
            //没登录
            return "login";
        } 
        return invocation.invoke();
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值