项目文件结构

Struts 学习笔记3(拦截器、文件上传、下载、xml、json)

Struts 学习笔记3(拦截器、文件上传、下载、xml、json)

Struts 学习笔记3(拦截器、文件上传、下载、xml、json)

 

Struts2应用的分层体系架构

要点:

1.将处理逻辑放到service里,如Action层不准许出现在sql语句,session、request不允许传到service层去。

 

示例:

LoginAction.java

package com.struts2.struts2;

……该导入的包……

public class LoginAction extends ActionSupport

{

    private String username;

    private String password;

    private int age;

    private Date date;

    private LoginService loginService = new LoginServiceImpl();

    

……Setget方法……

    

    public String execute() throws Exception

    {    //业务逻辑不写到Action

//        if(!"hello".equals(username))

//        {

//            throw new UsernameException("username invalid");

//        }

//        if(!"world".equals(password))

//        {

//            throw new PasswordException("password invalid");

//        }

//        return SUCCESS;

        

//利用ServletActionContext,获得HttpServletRequest请求

        HttpServletRequest request = ServletActionContext.getRequest();

        HttpSession session = request.getSession();

        

        session.setAttribute("hello", "helloworld");

        

        ActionContext actionContext = ActionContext.getContext();

        Map<String, Object> map = actionContext.getSession();    //获取session

        

        Object object = map.get("hello");    //打印出session的信息

        System.out.println(object);    

        if(this.loginService.isLogin(username, password))

        {

            return SUCCESS;

        }

        

        return INPUT;

    }

………………

}

 

LoginService.java

package com.struts2.service;

public interface LoginService

{

    public boolean isLogin(String username, String password);

}

 

LoginServiceImpl.java

package com.struts2.service.impl;

import com.struts2.service.LoginService;

public class LoginServiceImpl implements LoginService

{

    public boolean isLogin(String username, String password)

    {

        if("hello".equals(username) && "world".equals(password))

        {

            return true;

        }

        return false;

    }

}

 

编辑struts2.xml文件

    …………

<action name="login" class="com.struts2.struts2.LoginAction">

        <result name="success" type="dispatcher">/result.jsp</result>

        <result name="input">/login.jsp</result>

    </action>

    …………

 

Struts2的模型驱动(model driven)

要点:

  1. 属性驱动(propertity driven)与模型驱动的区别:之前的都是属性驱动,属性驱动与模型驱动的处理方式差不多,但它们导致的结果却不同,属性驱动是在接收的请求后,将对象里的值一个一个的 set 好,此时并没有new 出一个整的对象。而模型驱动是在接收到用户提交表单请求后,就将对象创建好了,并把对象的值也设定好了,可以直接拿对象来用了。
  2. 实现了ModelDriven接口的Action的执行过程

1).首先调用getModel()方法,返回一个person对象

2).模型查找提交过来的表单中有没有username、password等属性名是否匹配,如果匹配,则将对应的值自动设置到对象中,放到模型当中。

3).当在结果页面,以request.getAttribute()或requestScope取值时,同样通过Action从模型当中取值。

  1. 属性驱动与模型驱动的比较

1)属性驱动灵活,准确;模型驱动不灵活,因为很多时候,页面所提交过来的参数并不属于模型中的属性,也就是说页面所提交过来的参数与模型中的属性并不一致,这是很常见的情况。

2)模型驱动更加符合面向对象的编程风格,使得我们获得的是对象而不是一个个离散的值。

小结:推荐使用属性驱动编写 Action

  1. Preparable接口的作用是让 Action完成一些初始化工作,这些初始化工作是放在 Preparable接口的prepare方法中完成的,该方法会在execute方法执行之前得到调用。

 

示例:

Person.java

package com.struts2.bean;

import java.util.Date;

public class Person

{

    private String username;

    private String password;

    private int age;

    private Date date;

    ……getset方法……

}

LoginAction2.java

package com.struts2.struts2;

import com.opensymphony.xwork2.ActionSupport;

import com.opensymphony.xwork2.ModelDriven;

import com.opensymphony.xwork2.Preparable;

import com.struts2.bean.Person;

public class LoginAction2 extends ActionSupport implements ModelDriven<Person>, Preparable

{    //模型驱动

    private Person person = new Person();

    

    //1.首先调用getModel()方法,返回一个person对象

    //2.模型查找提交过来的表单中有没有usernamepassword等属性值,如果有,则模型自动设置到对象中

    public Person getModel()

    {

        System.out.println("getModel invoked!");

        return person;    //返回生成的person

    }

 

//调用这个方法让action准备自身

    public void prepare() throws Exception

    {

        System.out.println("prepare invoked!!");

    }

public String execute() throws Exception

    {

        System.out.println("execute invoked!");

        //System.out.println(person.getUsername());

        return SUCCESS;

    }

}

 

struts.xml

向struts.xml文件中,添加一个action,如下:

    <action name="login2" class="com.struts2.struts2.LoginAction2">

        <result name="success">/result.jsp</result>

    </action>

 

login.jsp

…………

<form action="login2.action">

username: <input type="text" name="username"><br>

password: <input type="password" name="password"><br>

age: <input type="text" name="age"><br>

date: <input type="text" name="date"><br>

<input type="submit" value="submit">

</form>

…………

result.jsp

…………

<body>

username: ${requestScope.username }<br><!-- requestScope相当于request.getAttribute() -->

password: ${requestScope.password }<br>

age: ${requestScope.age }<br>

date: ${requestScope.date }<br>

session: ${sessionScope.hello }<!-- 取得通过ServletActionContext方式获取的session -->

</body>

…………

 

服务器端代码的单元测试

要点:

1) 容器内测试(Jetty)

2) Mock 测试 ( 继承 HttpServletRequest 、 HttpSession 、HttpServletResponse等Servlet API) 。

 

防止表单重复提交

要点:

1) 通过重定向

2) 通过Session Token(Session令牌):当客户端请求页面时,服务器会通过token标签生成一个随机数,并且将该随机数放置到 session当中,然后将该随机数发向户端;如果客户第一次提交,那么会将该随机数发往服务器端,服务器会接收到该随机数并且与 session 中所保存的随机数进行比较,这时两者的值是相同的,服务器认为是第一次提交,并且将更新服务器端的这个随机数值;如果此时再次重复提交,那么客户端发向服务器端的随机数还是之前的那个,而服务器端的随机数则已经发生了变化,两者不同,服务器就认为这是重复提交,进而转向invalid.token所指向的结果页面。

 

Struts-default.xml中定义的结果类型

打开struts2-core-2.2.1.1.jar下的struts-default.xml文件,其中定义了的结果类型,如下:

<package name="struts-default" abstract="true">

<result-types>

<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>

<result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/>

<result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>

<result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/>

<result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/>

<result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/>

<result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>

<result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/>

<result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/>

<result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult" />

</result-types>

    ………………

 

页面重定向与请求转发的设定

在struts.xml文件中,设置Action中的result元素的type属性即可,如下:

    <action name="login" class="com.struts2.struts2.LoginAction">

        <!--

        <result name="success" type="dispatcher">/result.jsp</result>

-->

<result name="success" type="redirect">/result.jsp</result>

        <result name="input">/login.jsp</result>

    </action>

 

重定向到Action (redirectAction)

action1.jsp

…………

<body>

<form action="action1.action">

username: <input type="text" name="username"><br>

password: <input type="password" name="password"><br>

<input type="submit" value="submit">

</form>

</body>

…………

action2.jsp

…………

<body>

username: <s:property value="username"/><br>

password: <s:property value="password"/><br>

usernameAndPassword: <s:property value="usernameAndPassword"/>

</body>

…………

Action1.java

package com.struts2.struts2;

import com.opensymphony.xwork2.ActionSupport;

public class Action1 extends ActionSupport

{

    private String username;

    private String password;

    private String usernameAndPassword;

    ……setget方法……

    @Override

    public String execute() throws Exception

    {

        this.usernameAndPassword = this.username + this.password;

        

        return SUCCESS;

    }

}

 

Action2.java

package com.struts2.struts2;

import com.opensymphony.xwork2.ActionSupport;

public class Action2 extends ActionSupport

{

    private String username;

    private String password;

    private String usernameAndPassword;

    ………getset方法………

    @Override

    public String execute() throws Exception

    {

        return SUCCESS;

    }

}

 

struts.xml

    …………

<action name="action1" class="com.struts2.struts2.Action1">

            <result name="success" type="redirectAction">

                <!--如果不传参数,可把action2直接写到resulttext域中 -->

<param name="actionName">action2</param>

                <param name="username">${username}</param><!-- 获取Action1的成员变量 -->

                <param name="password">${password}</param>

                <param name="usernameAndPassword">${usernameAndPassword}</param>

            </result>

        </action>

        

        <action name="action2" class="com.struts2.struts2.Action2">

            <result name="success">/action2.jsp</result>

        </action>

    …………

 

chain结果类型(Action之间的请求转发)

要点:直接修改struts.xml文件中的action的result的type属性的值为 chain ,如下:

    …………

<action name="action1" class="com.vvvv.struts2.Action1">

            <result name="success" type=chain">

                <!--如果不传参数,可把action2直接写到resulttext域中 -->

<param name="actionName">action2</param>

                <param name="username">${username}</param><!-- 获取Action1的成员变量 -->

                <param name="password">${password}</param>

                <param name="usernameAndPassword">${usernameAndPassword}</param>

            </result>

    …………

运行可以发现,这种方式不是以重定向的形式转发,且action2.jsp页面拿不到usernameAndPassword的信息。因为由Action1转发到到Action2,是在服务器内部进行了,是在一个客户端页面(action1.jsp)请求范围内,而请求中只包含usernamepassword两个参数。所以拿不到usernameAndPassword的值。

 

Struts2 Session Token机制

token.jsp

…………

<body>

<s:form action="token.action" theme="simple">

username: <s:textfield name="username"></s:textfield><br>

password: <s:password name="password"></s:password><br>

<s:token></s:token>

<s:submit value="submit"></s:submit>

</s:form>

</body>

…………

TokenAction.java

package com.struts2.struts2;

 

import com.opensymphony.xwork2.ActionSupport;

 

public class TokenAction extends ActionSupport

{

    private String username;

    private String password;

    ……getset方法……

    @Override

    public String execute() throws Exception

    {

        return SUCCESS;

    }

}    

 

tokenSuccess.jsp

…………

<body>

username: <s:property value="username"/><br>

password: <s:property value="password"/>

</body>

…………

 

tokenFail.jsp

…………

<body>

不要重复提交表单

</body>

…………

 

struts.xml

…………

        <action name="token" class="com.struts2.struts2.TokenAction">

            <result name="success">/tokenSuccess.jsp</result>

            <result name="invalid.token">/tokenFail.jsp</result>

            

            <interceptor-ref name="token"></interceptor-ref>

            <interceptor-ref name="defaultStack"></interceptor-ref>

        </action>

…………

 

struts2拦截器

要点:

拦截器的配置

1)编写实现Interceptor 接口的类。

2)在struts.xml 文件中定义拦截器。

3)在action中使用拦截器

首先编写拦截器类(TheInterceptor1)

package com.struts2.interceptor;

import com.opensymphony.xwork2.ActionInvocation;

import com.opensymphony.xwork2.interceptor.Interceptor;

public class TheInterceptor1 implements Interceptor

{

    private String test;

    public String getTest()

    {

        return test;

    }

    public void setTest(String test)

    {

        System.out.println("setTest invoked!");    //set方法先于init方法执行

        this.test = test;

    }

    public void destroy()

    {

    }

    public void init()

    {

        System.out.println("init invoked!");

        System.out.println("test: " + this.test);

    }

    //服务器永远不会去执行挂截器,只不过是在执行拦截器之前,执行一个invoke方法

    public String intercept(ActionInvocation invocation) throws Exception

    {

        System.out.println("before");

        String result = invocation.invoke();

        System.out.println("after");

        return result;

    }

}

struts.xml

<struts>

    <package name="struts2" extends="struts-default">

        <interceptors>

            <interceptor name="theInterceptor1" class="com.vvvv.interceptor.TheInterceptor1">

                <param name="test">vvvv</param>

            </interceptor>

        </interceptors>

    ………………

        <action name="token" class="com.struts2.struts2.TokenAction">

            <result name="success">/tokenSuccess.jsp</result>

            <result name="invalid.token">/tokenFail.jsp</result>

            <interceptor-ref name="token"></interceptor-ref>

            <interceptor-ref name="defaultStack"></interceptor-ref>

        </action>

    </package>

</struts>

 

一旦定义了自己的拦截器,将其配置到 action上后,我们需要在action的最后加上默认的拦截器栈:defaultStack。

 

示例2

项目源包 : struts2sd

要点:

 

TheInterceptor2.java

package com.vvvv.interceptor;

 

import com.opensymphony.xwork2.ActionInvocation;

import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

 

public class TheInterceptor2 extends AbstractInterceptor

{

    @Override

    public String intercept(ActionInvocation invocation) throws Exception

    {

        System.out.println("interceptor before...");

        System.out.println("interceptor2: " + invocation.getAction().getClass());

        String result = invocation.invoke();

        System.out.println("interceptor after...");

        return result;

    }

}

 

struts.xml

…………

<interceptors>

    <interceptor name="theInterceptor1" class="com.vvvv.interceptor.TheInterceptor1">

        <param name="test">vvvv</param>

    </interceptor>

    

    <interceptor name="theInterceptor2" class="com.vvvv.interceptor.TheInterceptor2">

    </interceptor>

    

    <interceptor name="theInterceptor3" class="com.vvvv.interceptor.TheInterceptor3">

    </interceptor>

    

    <interceptor name="loginInterceptor" class="com.vvvv.interceptor.LoginInterceptor">

    </interceptor>

</interceptors>

…………

<action name="action1" class="com.vvvv.struts2.Action1" method="myExecute">

    <result name="success" type="chain">

        <param name="actionName">action2</param>

        <param name="username">${username}</param>

        <param name="password">${password}</param>

        <param name="usernameAndPassword">${usernameAndPassword}</param>

    </result>

    

    <interceptor-ref name="theInterceptor1"></interceptor-ref>

    <interceptor-ref name="theInterceptor2"></interceptor-ref>

    <!-- 方法过滤拦截器 -->

    <interceptor-ref name="theInterceptor3">

        <param name="includeMethods">execute, myExecute</param>

        <!-- 不包含以下拦截器,使其不执行 --><!--

        <param name="excludeMethods">myExecute</param>

         -->

    </interceptor-ref>

    <interceptor-ref name="defaultStack"></interceptor-ref>

</action>

…………

TheInterceptor3

package com.vvvv.interceptor;

 

import com.opensymphony.xwork2.ActionInvocation;

import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;

import com.vvvv.listener.TheListener;

 

public class TheInterceptor3 extends MethodFilterInterceptor

{

    @Override

    protected String doIntercept(ActionInvocation invocation) throws Exception

    {

        invocation.addPreResultListener(new TheListener());

        System.out.println("before interceptor3");

        String result = invocation.invoke();

        System.out.println("after interceptor3");

        

相关文章:

  • 2021-12-25
  • 2022-01-02
  • 2022-12-23
  • 2023-03-21
  • 2022-12-23
  • 2021-07-13
  • 2021-12-22
猜你喜欢
  • 2021-07-24
  • 2022-01-14
  • 2021-10-29
  • 2021-10-20
  • 2021-10-30
  • 2022-12-23
  • 2022-01-08
相关资源
相似解决方案