【Struts2】三_ServletAPI、标签、校验、验证框架失效原因、拦截器等使用教程(代码)

Struts2


五、ServletAPI

所谓Servlet APl,即我们常用的Request、Session、Application等Sevlet对象。Struts2访问Servlet API有解耦耦合两种方式。

5.1、解耦方式:

解耦方式:Struts2将部分Servlet API中的对象封装成Map,可以通过ActionContext获取。获取到的Servlet API对象全部是Map。

示例:

//Action类中的方法
   public String execute() throws Exception {
        ActionContext actionContext = ActionContext.getContext();
        Map request = (Map) actionContext.get("request");   //获取request
        Map application = actionContext.getApplication();   //获取app1ication
        Map session = actionContext.getSession();   //获取session
        session.put("session_object","我是session~~");   //向session中存值

        System.out.println("hello struts2~~~struts构建完成");
        System.out.println("接收到的name是===="+name);
        message="----message----";

        System.out.println("user==="+user);
        return "OK";  //返回的结果
    }
<%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" language="java" %>
<html>
<body>
<h2>struts2</h2>
<br/>
<%--前端取值--%>
<span>session:${sessionScope.session_object}</span>
</body>
</html>

在这里插入图片描述

5.2、解耦方式:

解耦方式:依赖原生servlet中的对象,直接获取servlet中的Request、Session、Application等Sevlet对象。


耦合方式需要导入servlet-api的jar包:

<dependency>
	<groupId>javax.servlet</groupId>
	<artifactId>servlet-api</artifactId>
	<version>2.5</version>
</dependency>
    public String execute() throws Exception {
//        ActionContext actionContext = ActionContext.getContext();
//        Map request = (Map) actionContext.get("request");
//        Map application = actionContext.getApplication();
//        Map session = actionContext.getSession();
//        session.put("session_object","我是session~~");

        HttpServletRequest request = ServletActionContext.getRequest();
        HttpSession session = request.getSession();
        HttpServletResponse response = ServletActionContext.getResponse();
        request.setAttribute("request_object","我是request对象");
        return "OK";  //返回的结果
    }
<span>耦合反式的request对象:${requestScope.request_object}</span>

在这里插入图片描述

六、Struts标签

6.1、UI标签:

  • 与JSTL标签类似,Struts2提供了强大的标签库。
  • Struts2标签分为UI标签和通用标签。
  • 使用Struts2标签需要在页面上引入标签库:<% @taglib uri="/struts-tags" prefix="s" %>
<h4>struts中的表单标签,语法如下:</h4>
<s:form action=" " method="POST">
    <s:textfield name="username" label="用户名" />
    <s:password name="password" label="密码" />
    <s:submit value="登录"/>
</s:form>
以上代码等同于:
<form action=" " method="post">
    中名: <input type="text" name="username" /><br/>
    密码: <input type="password" name="password" /><br/>
    <input type="submit" value="登录"/>
</form>

在这里插入图片描述

运行发现,我们没有给表单换行,但是其标签内部是有样式的。
可以去掉样式,加全局配置:

<!--去掉ui标签的主题-->
<constant name="struts.ui.theme" value="simple" />

在这里插入图片描述


6.2、通用标签:(业务逻辑判断)

【s:if标签用于条件判断】
<s:if test=""></s:if>
<s:elseif test=""></s:elseif>
<s:e1se></s:else>
s:if标签用于条件判断,相当于jstl中的
<c:if test=""></c:if>

示例:

<action name="tags" class="com.wxy.action.TagsAction" >
    <result name="success">tags.jsp</result>
</action>
package com.wxy.action;

import com.opensymphony.xwork2.Action;
import lombok.Getter;
import lombok.Setter;

public class TagsAction implements Action {
    @Setter
    @Getter
    private String username;

    public String execute() throws Exception {
        return SUCCESS;
    }
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="/struts-tags" prefix="s" %>
<html>
<head>
    <title>标签练习页面</title>
</head>
<body>
    <h4>struts中的表单标签,语法如下:</h4>
    <s:form action="/tags.action" method="POST">
        <s:textfield name="username" label="用户名"/>
        <s:password name="password" label="密码"/>
        <s:submit value="提交"/>
    </s:form>
    
    <s:if test="username=='admin'">管理员</s:if>
    <s:elseif test="username=='user'">用户</s:elseif>
    <s:else>不是管理员</s:else>
</body>
</html>

输入相应的身份,输出不同的身份
在这里插入图片描述


【s:iterator用于集合的遍历】
<s:jterator value="" var="" status=""></s:iterator>
s:iterator用于集合的遍历,相当于jstl中的
<c:forEach items="" var="" varStatus=""></c:forEach>

遍历泛型是基本数据类型的集合,如List,需要通过id属性访问当前的元素。

    <table>
        <!--遍历基本数据类型的集合需要借助ia属性-->
        <s:iterator value="strList" id="str" status="status">
            <!-- status属性可以访问对象的索引或奇偶-->
            <s:if test="#status.even">	<!-- even代表奇数,注意#。此时从索引0开始-->
            <tr style="background-color: green">
                <td><s:property value="str"/></td>
            </tr>
        </s:if>
            <s:else>
                <tr><td><s:property value="str"/></td></tr>
            </s:else>
        </s:iterator>
    </table>

遍历泛型是对象类型的集合,如List,不需要使用id,输出的时候直接写对象中的属性名即可:

<table>
	<s:iterator value="userLis" status="status">
	    <!-- odd代表偶数-->
	    <tr <s:if test="#status.odd">style="background-color: green"</s:if>>
	    	<td><s:property value="userName"/></td>
	    </tr>
    </s:iterator>
</table>

注意:
奇偶是正常的,只是对应的索引是从零开始
基本类型的遍历除了用id,还可以用var

具体示例:一个数组,一个对象:
@Setter
@Getter
public class TagsAction implements Action {
    private String username;
    private List<String> userList = new ArrayList<String>();
    private List<User> users = new ArrayList<User>();

    public String execute() throws Exception {
        for(int i = 0; i<10; i++) {
            userList.add("str"+i);
        }
        users.add(new User(1,"张三"));
        users.add(new User(2,"李四"));
        return "OK";
    }
}
    <s:iterator value="userList" var="str">
        <s:text name="s"/>
    </s:iterator>
<br/>
    <s:iterator value="users">
        <s:property value="id"/>===<s:property value="userName"/><br/>
    </s:iterator>

遍历正确应该是下图,但是我的数组遍历出了问题,遍历了十个“S” ??????
在这里插入图片描述
在这里插入图片描述

七、校验:

7.1、通用验证:
  • Action类继承ActionSupport,ActionSupport中有一个validate方法进行数据校验。
  • addFieldError要求必须给result配置一个input类型的结果。所以在调用login方法时,会报找不到result input。
    在这里插入图片描述
  • 直接范例演示:
    • 要继承ActionSupport ,登录和注册方法之前都会先去执行验证方法
public class ValidateAction extends ActionSupport {
    @Getter
    @Setter
    private String username;

    @Override
    public void validate()
    {
        if (username==null || username.trim().length()==0) {
            //向页面中添加错误信息
            addFieldError("username", "用户名不能为空");
        }
    }

    public String login(){
        return SUCCESS;
    }
    public String register(){
        return SUCCESS;
    }
}

<!--验证-->
<action name="validateLogin" class="com.wxy.action.ValidateAction" method="login">
     <result name="success">validate.jsp</result>
     <!--要添加input类型的result,否则会报错-->
     <result name="input">validate.jsp</result>   
 </action>
 <action name="validateReg" class="com.wxy.action.ValidateAction" method="register">
     <result name="success">validate.jsp</result>
     <result name="input">validate.jsp</result>
 </action>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="/struts-tags" prefix="s" %>
<html>
<head>
    <title>验证页面</title>
</head>
<body>
<form action="/validateLogin" method="post">
  <input name="username">
  <input type="submit" value="提交">
</form>

<form action="/validateReg" method="post">
    <input name="username">
    <input type="submit" value="提交">
</form>

<s:fielderror/>   <%--返回错误提示结果--%>
<s:fielderror name="username"/>  <%--只返回关于name的错误结果--%>
</body>
</html>

执行结果:
在这里插入图片描述


7.2、方法验证:

validate()方法会验证当前Action类中所有的方法,如果只想验证其中的一个方法,自己设置方法:可以使用validateXxx()方法,其中Xxx是被验证的方法名的首字母大写

//只验证login方法,不验证其它方法
public void validateLogin() {
if (username == null || username.1ength() == 0){
	//向页面中添加错误信息
	addFieldError( "username""用户名不能为空");
	}
}
7.3、校验框架:

验证框架是把验证信息都写在xml文件中,对某一个Action类进行验证,需要在Action类的同一个包下创建xml文件,文件命名为Action类的类名-validation.xml
在这里插入图片描述

在这里插入图片描述

多放两个头部,有人的失效是因为头部问题:
【但是我找了所有框架失效的方法也没解决为啥我的框架失效~~】

<!DOCTYPE validators PUBLIC
        "-//Apache Struts//XWork Validator 1.0.2//EN"
        "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN" 
		"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">

<validators>
<field name="username">
    <field-validator type="requiredstring">
    	<message>用户名不可以为空</message>
    </field-validator>
</field>
<field name="password">
    <field-validator type="required">
        <message>密码不能为空</message>
    </field-validator>
    <field-validator type="stringlength">
        <param name="maxLength">10</param>
        <param name="minLength">6</param>
        <message>密码必须在${minLength}和${maxLength}</message>
    </field-validator>
</field>
<field name="repwd">
	<field-validator type="fieldexpression">
		<param name="expression">password=repwd</param>
		<message>两次密码不一致</message>
	</field-validator>
</field>
</validators>
  • validators标签:在校验框架中,所有的验证都写在validators标签中。
  • field标签:每一个需要验证的属性都是一个field标签,name指定要验证那个属性
  • field-validator标签:代表一种验证规则,通过type指定规则。

| 值 | 说明 |
|-required-|-必填-|
| requiredstring | 必填字符串,长度大于0,可使用trim参数去除空格 |
|-stringlength-|-限制字符串长度,指定maxLength和minLength-|
| regex| 正则表达式,通过参数regex指定正则表达式 |
|-fieldexpression-|-字段之间的逻辑关系-|

  • param标签:给校验器传递的参数
  • message标签:给页面的提示信息。
  • 校验框架和validate()方法一样,会验证action中所有的方法,如果只验证某一个方法,需要将xml文件的名字命名为action类名-动作名-validation.xml。其中的动作名是指struts.xml中对应此方法的action的name。
  • 多种验证方式并存时,执行顺序是:校验框架--->validateXxx()---->validate()
7.4、验证框架失效原因:

1. 命名是否符合约定:
2. validation.xml的标签是否正确,比如是否关闭所有标签(或者有错误的标签),是否多一个关闭标签等。注意:这方面错误没有任何提示, 只是验证不起作用。
3. fieldName 命名是否和jsp以及 action中的属性一致 如:

  • action中有userName属性,
  • jsp 中有标签:<s:textfield name=“userName”/>
  • validation.xml中需有:< field name=“userName” >…< /field>
  • 上述的三个userName一定要一致。

4.检查是否在同一个field里面配置了重复的参数,重复的参数也可能会使你的信息显示不出来
5.要记得验证框架所产生的错误信息被是写入到了fielderror里面去了,所以在需要显示错误信息的页面要用<s:fielderror/>
6.LoginAction-validation.xml文件必须与Action类放在相同的目录下
7.在struts.xml文件中的<action>标签中,必须包含<result name="input"><result name="success",否则会报找不到result的错误。 validation.xml校验不通过后,会默认返回 input所在 页面
8.最主要的一个可能:如果你的Action类没有继承ActionSupport类,就不会进行页面流程的自动跳转。

八、拦截器

拦截器可以在请求进入action之前做预处理,比如判断用户是否登录。也可以在action执行之后进行处理。

8.1、拦截器配置:

例如:利用拦截器计算action的执行时间------->在interceptor包下创建TimeInterceptor类

package com.wxy.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

public class TimeInterceptor implements Interceptor {
    /**
     * 销毁方法
     */
    public void destroy() {
    }

    /**
     * 初始化方法
     */
    public void init() {
    }

    /**
     * 核心方法
     * @param actionInvocation
     * @return
     * @throws Exception
     */
    public String intercept(ActionInvocation actionInvocation) throws Exception {
        long start = System.currentTimeMillis();
        String result = actionInvocation.invoke();  //将请求放行,进入action;result是action中方法返回的字符串string 
        long end = System.currentTimeMillis();
        System.out.println("运行时间===="+(end-start));
        return result ;
    }
}

ResultTest 是之前使用过的一个类,现在用来给他加载拦截器:

public class ResultTest extends ActionSupport {
    @Setter
    @Getter
    private String page;

    public String goPage() {
        System.out.println("page===="+page);
        return page;
    }

}

拦截器配置与设置拦截器:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <package name="default" extends="struts-default">
    	<!--拦截器配置-->
       <interceptors>
            <interceptor name="time" class="com.wxy.interceptor.TimeInterceptor"></interceptor>
       </interceptors>
       <action name="page" class="com.wxy.action.ResultTest" method="goPage">
            <result name="success">${page}.jsp</result>
            <interceptor-ref name="time"/> <!--引用上面设置的拦截器-->
            <interceptor-ref name="defaultStack"/>  <!--默认拦截器-->
        </action>
    </package>
</struts>

拦截器:

  • 在action的内部,有一个默认拦截器,<interceptor-ref name="defaultStack"/>
  • 注意:使用自己的拦截器时,内部拦截器需要自己配置上,否则自己的拦截器会覆盖内部拦截器。
8.2、拦截器栈:
    <package name="default" extends="struts-default">
        <interceptors>
            <interceptor name="time" class="com.wxy.interceptor.TimeInterceptor"/>
            <!--设置拦截器栈:-->
            <interceptor-stack name="time-stack">
                <interceptor-ref name="time"/>
                <interceptor-ref name="defaultStack"/>
            </interceptor-stack>
        </interceptors>
        <action name="page" class="com.wxy.action.ResultTest" method="goPage">
            <result name="success">${page}.jsp</result>
            <interceptor-ref name="time-stack"/> <!--直接引用栈名-->
        </action>
    </package>
</struts>
8.3、登录拦截器(servlet中登录过滤去):

【判断登录的时候,session中是否已有用户】
写一个登录页面login.jsp,其他几个页面(可以使用之前我们写过的那几个页面),一个登录拦截器,配置拦截器

LoginInterceptor .java登录拦截器:

public class LoginInterceptor implements Interceptor {
    public void destroy() {
    }

    public void init() {
    }

    public String intercept(ActionInvocation actionInvocation) throws Exception {
        ActionContext actionContext = ActionContext.getContext();
        Map session = actionContext.getSession();
        if(session.get("user_session")==null){  //没有登录
            return "login";
        }
        return actionInvocation.invoke();
    }
}

struts.xml 配置登录拦截器,只要访问其他页面就调到登录页面,看注释,下面配置算是小练习的全部配置:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
    <!--去掉ui标签的主题-->
    <constant name="struts.ui.theme" value="simple" />
    <!--所有的action都放在package中,必须继承struts-default-->
    <!--struts-default中有默认的拦截器配置,能处理参数等信息-->
    <package name="default" extends="struts-default">
        <!--有很多时候一个<result>可供很多<action>使用,这时可以使用<global-results>标签来定义全局的<result>。
    执行顺序:当一个Action返回的String没有相应的<result>与之对应,Struts2就会查找全局的<result>。-->


<!--        <interceptors>-->
<!--            <interceptor name="time" class="com.wxy.interceptor.TimeInterceptor"></interceptor>-->
<!--        </interceptors>-->
        <interceptors>
            <interceptor name="time" class="com.wxy.interceptor.TimeInterceptor"/>
            <interceptor name="login" class="com.wxy.interceptor.LoginInterceptor"/>
            <interceptor-stack name="time-stack">
                <interceptor-ref name="time"/>
                <interceptor-ref name="login"/>
                <interceptor-ref name="defaultStack"/>
            </interceptor-stack>
        </interceptors>
        <!--没有登录都回到login.jsp-->
        <global-results>
            <result name="login">/login.jsp</result>
        </global-results>
    <!--=====-->  
        <action name="hello" class="com.wxy.action.HelloAction">
            <result name="OK">hello.jsp</result>
        </action>
	<!--=====-->
        <action name="login" class="com.wxy.action.TestAction" method="login">
            <result name="success">/index.jsp</result>
        </action>
        <action name="register" class="com.wxy.action.TestAction" method="register">
            <result name="success">/index.jsp</result>
        </action>
	<!--动态结果-->
        <action name="page" class="com.wxy.action.ResultTest" method="goPage">
            <result name="success">${page}.jsp</result>
            <interceptor-ref name="time-stack"/> <!--引用上面设置的拦截器-->
        </action>
    <!--标签-->
        <action name="tags" class="com.wxy.action.TagsAction" >
            <result name="OK">tags.jsp</result>
        </action>
    <!--验证-->
        <action name="validateLogin" class="com.wxy.action.ValidateAction" method="login">
            <result name="success">validate.jsp</result>
            <result name="input">validate.jsp</result>
        </action>
        <action name="validateReg" class="com.wxy.action.ValidateAction" method="register">
            <result name="success">validate.jsp</result>
            <result name="input">validate.jsp</result>
        </action>
    </package>
</struts>

在这里插入图片描述

九、文件上传下载

9.1、文件上传:

直接上代码使用,跟以前的流方法一样

@Setter
@Getter
public class FileAction extends ActionSupport {

    private File upload;  //与表单name属性的值一致
    private String uploadFileName;  //与文件属性名+FileName

    public String upload() {
        System.out.println("文件名===="+uploadFileName);
        try {
            String ext = uploadFileName.substring(uploadFileName.lastIndexOf("."));
            byte[] buffer = new byte[1024];
            FileInputStream fis = new FileInputStream(upload);  //读取文件
            FileOutputStream fos = new FileOutputStream("E:/upload/" + System.currentTimeMillis()+ext);  //文件以当前时间戳+后缀命名
            int length = fis.read(buffer);
            while (length != -1) {
                fos.write(buffer);
                length = fis.read(buffer);
            }
            fos.close();
            fis.close();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return SUCCESS;
    }
}

可能会上传两个同名文件,可以将文件名字:以当前时间戳+文件原后缀命名

//得到文件后缀
String ext = uploadFileName.substring(uploadFileName.lastIndexOf(".")); 
//文件以当前时间戳+后缀命名
FileOutputStream fos = new FileOutputStream("E:/upload/" + System.currentTimeMillis()+ext);  
 <action name="upload" class="com.wxy.action.FileAction" method="upload">
     <result name="success">/upload.jsp</result>
 </action>

9.2、文件下载:

……


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朱尔斯Jules

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值