Struts2知识整理

struts2简介

  • struts2是基于mvc开发模型的框架,属于表现层框架
  • 核心为拦截器

struts2框架的特点

  • 基于MVC,结构清晰
  • 丰富的标签库,提高了开发效率
  • 强大的拦截器
  • 全局异常和全局结果处理
  • 易于扩展的插件化机制
  • Struts2也有IOC和DI的特性

struts2的核心流程

  • 整体执行图
  • 下面是一次请求Action的流程
    • 创建actioncontext, 创建valuestack, 并且把整个ActionContext对象放入到threadlocal中,这样就能保证valueStack的数据的安全性
    • 创建Actionproxy 创建Action
    • 按照顺序执行所有的拦截器
    • 执行Action
    • 执行结果集
    • 按照倒叙的方式执行符合规则的拦截器(return invoke)
    • 清空数据

struts2配置

  • web.xml
  • struts2.xml
  • struts2可以包含多个配置文件(提高了配置文件的安全性和独立性),<include file="">|

struts各种配置的加载顺序

  • default.properties:struts2-core**.jar org.apache.struts包中
  • struts-default.xml:struts2-core**.jar中
  • struts-plugin.xml:在插件的jar包中
  • struts.xml:在应用的构建路径顶端。自己定义的Struts配置文件(推荐)
  • struts.properties:在应用的构建路径顶端。程序员可以编写
  • web.xml:配置过滤器时,指定参数。程序员可以编写
  • 特别注意:顺序是固定的。后面的配置会覆盖前面的同名配置信息。

配置文件中action和package参数意义

  • 访问一次Action就会重新创建一个Action对象(多例)
  • action
    • name: 动作名称,用于用户请求
    • class: 映射类的全名,如果不指定默认值为:ActionSupport
      • 默认类可以修改,默认类在struts-default.xml中进行了声明,可以在配置文件中用来指定自定义默认类
    • method: 指定映射方法, 默认值: execute
  • action内的通配符
    • 通配符配置ACTION
    • 存在多个匹配,匹配的执行顺序:绝对匹配->按照通配符匹配的顺序
    • 地址:add_Customer
    • name="*_" {1}代表第一个所代表的的字符 {2}代表的第二个字符
    • 使用方法:如果请求的是 Customer_add
    • class="com.item.action.{1}Action" method="{2}" // com.item.action.CustomerAction" method="add"
    • result /customer/{1}{2}.jsp // addCustomer.jsp
  • 动态调用
    • http://loaclhost:8080/XXX/demo!m1(不安全,不建议使用)
    • 使用前需要开启动态调用,在struts2.xml中配置:struts.enable.DynamicMethod.Invocation=true
  • package(类似于java类的包)
    • name:唯一
    • extends:struts-default 继承默认包,包内设置了默认的拦截器,如果不继承该包,那么Struts2中的核心功能将无法使用。
    • namespace: 指定命名空间,一般以"/"开头。该包中的动作访问路径:namesapce+动作名称。如果namespace="",这是默认名称空间,和不写该属性是一样的。
    • abstract:没有action子元素的包可以声明为抽象包.

action动作类

  • 编写动作类的三种方式:
    • 单纯POJI
    • 实现Action接口
      • 提供了几个格式化的返回参数
        • String SUCCESS:success。一切正常。
        • String NONE:none。动作方法执行后,不转向任何的结果视图。或者在动作方法中返回null。
        • String ERROR:error。动作方法执行时遇到异常,转向错误提示页面。
        • String INPUT:input。验证、转换失败,转向输入页面。
        • String LOGIN:login。检测用户是否登录,没有登录转向此视图。
    • 实现 ActionSupport(推荐)
      • 这个类实现了Action接口,并且提供了一些基本的功能,比如:验证 国际化提示等
  • action访问ServletAPI
    • 方式一:ServletActionContext静态方法(推荐) ServletActionContext.getRequest(); //struts2 改变了request中的某些功能 ServletActionContext.getResponse(); //apache ServletActionContext.getServletContext(); //apache
    • 方式二:实现接口 ServletRequestAware,ServletResponseAware ,ServletContextAware
      • 执行动作方法前,框架会把HttpServletRequest()对象注入进来
      • 是由一个拦截器负责注入的,servletConfig

自定义结果视图

  • type 到达目标形式 默认:转发,下面是几个重要的
    • chain: 转发到另一个动作
    • 如果对应的action所在的包不在默认空间内,需要用到来设置空间和action名字

    <param name="Namespace">/n2</param> <param name="ActionName">math</param>

    • dispatcher: 用户转发到页面(请求转发 jsp)
    • redirect: 请求重定向到jsp
    • redirectAction: 请求重定向到action
    • stream: 用于文件上传和下载
    • freemarker: 转发到另一个freemarker模板(页面静态化)
    • httpheader: 输出http协议的消息头
    • plainText:原样输出源代码
  • 在struts2.xml中声明结果定义类型
    • 首先编写类,实现com.opensymphony.xwork2.Result接口或者继承StrutsResultSupport(一般为继承),然后里面设置需要输出的内容(输出方式和Servlet内相同)
使用
     <package name="D3" extends="struts-default" namespace="/n3">          
          //**声明类型**         
          <result-types>             
               <result-type name="newresult" class="com.result.result"></result-type>         
          </result-types>          
          //使用         
          <action name="cop">             
               <result name="success" type="newresult"></result>         
          </action>     
       </package>
封装请求参数
  • 表单的的name要与参数名字相同才可以赋值
  • 动态参数赋值
    • 模型类最好实现Serilalizable接口
    • 参数赋值的顺序: 模型对象中找,如果没有对应对象的Set方法,下一步就会从对应的action中寻找.
    • 1.用Action动作类对象作为模型对象,即Javabean内写上action函数
      • jsp页面name和属性名字相同,然后直接访问就可以自动赋值
    • 2.动作类和模型分开
      • 在动作类里面声明模型类,并且设置get,set方法,动作类对象名字为person, 则jsp页面的name要加上前缀,即:person.name才可赋值
    • 3.动作类和模型分开(ModelDriven)
      • 动作类继承ModelDeriven
      • 原因:与Struts2的值栈有关
      • 该功能是由一个叫做modelDriven的拦截器完成的。
  • 静态参数注入
    • <param name="name">游客</param>
  • 动态参数和静态参数注入功能实现
    • 是由两个拦截器来完成。
    • 静态参数注入:staticParams
    • 动态参数注入:params
  • 批量添加表单
模型类中添加List或者Map集合
     private List<Customer> customers = new ArrayList<Customer>();     
     private Map<String, Customer> customers1 = new HashMap<String, Customer>();
jsp页面中:
 List:     
       <input type="text" name="customers[0].username"/> 
 Map:     
       <input type="text" name="customers1['c1'].username"/>   
  • 参数的类型转换
    • struts2内置了转换器,多数情况下不需要自己来编写
    • struts2的发展过程 OGNL-WebWork-struts2 , 所以一些在ONGL或者WebWork时期定义不明确的方法和参数struts2会有一定程度的改正.
    • 自定义转换器:
      • 编写转换器
        • 继承StrutsTypeConverter,重写convertFromString()convertToString() 这两个方法
        • 转换器示例代码
      • 配置转换器
        • 局部转换器
          • 前缀名字一定要和类名相同
          • 对应模型类或者对应动作类下面创建 ClassName-conversion.properties文件, 内容: birthday=com.item.MyDateConverter(转换器类)
        • 全局转换器
          • 位置在src下面,名字为xwork-conversion.properties,所有动作都可以用
          • java.util.Date=com.itheima.convertors.MyDateConverter 内容为需要转换的类型和对应的类
    • 类型转换失败提示
      • 转换失败,会自动转到一个name=input的逻辑视图(需要在result内定义),一般指向输入的那个页面,目的回显(建议使用struts2的表单标签)
      • 错误消息提示中文版本(动作类要继承ActionSupport类)
        • 类名.properties , 内容为invalid.fieldvalue.birthday=输入错误

服务器端表单验证

  • 验证功能是由validation拦截器来负责处理的。回显错误信息是由workflow拦截器来负责处理的。
  • 下面两种方式都需要在struts.xml配置文件中添加<result name="input">/regist.jsp</result>结果视图
  • 编程式验证
    • 针对动作类中所有的方法进行验证
      • 动作类需要实现ActionSupport覆盖掉validate()方法
      • 在validate方法内部编写规则,不正确的情况用addFieldError添加错误信息
      • 动作类就是模型类: addFieldError("name", "请输入用户名");
      • 动作类跟模型类分开: addFieldError("m.name", "请输入用户名");
    • 针对指定方法进行验证
      • 在需要验证的方法上面添加注解@SkipValidation
      • 将validate()方法改写成为public void validateDemo1 后面是指定方法的名字.
  • 声明式验证
    • 在xml文件中配置验证信息,不需要硬编码
    • 在动作类所在的包中建立:动作类名-validation.xml配置文件。
    • xml文件
    • 在模型类和动作类的两种方式, 只需要改一下<field name="m.name"> 中的name要和表单名(jsp/name)一致
    • 针对动作做类的方法进行验证
      • 在动作类所在的包中建立:动作类名-动作名(是请求的struts.xml配置文件中的)-validation.xml配置文件。 action配置文件中可以用method属性来指定执行那个方法
  • 常用内置验证器
    • 提供的声明式验证器在xwork-core-**.jar包的com\opensymphony\xwork2\validator\validators\default.xml配置文件中(查询具体类用CRTL+T)。
    • 内置验证器示例
  • 自定义声明式验证器
    • 编写一个类,继承FieldValidatorSupport
    • 定义验证器,之后就可以和使用内置验证器一样使用
      • src目录下,新建validators.xml
     <?xml version="1.0" encoding="UTF-8"?>     
     <!DOCTYPE validators PUBLIC            
                "-//Apache Struts//XWork Validator Definition 1.0//EN"             
                "http://struts.apache.org/dtds/xwork-validator-definition-1.0.dtd">     
      <validators>         
           <validator name="strongpassword" class="com.itheima.validators.StrongPasswordValidator"/>     
      </validators>

拦截器

  • 是struts2中的核心功能,是一种AOP变成思想的具体应用.
  • 常用的拦截器
    • modelDriven:模型驱动
    • servletConfig:获取ServletAPI
    • staticParams:静态参数注入
    • params:动态参数注入
    • validation:输入验证,声明式验证。
定义简单拦截器如下图所示
     public class Demo1Interceptor extends AbstractInterceptor {         
     //返回值:最终目标的返回值。就是一个结果逻辑视图。对应struts.xml中的result         
     public String intercept(ActionInvocation invocation) throws Exception {             
          System.out.println("拦截前");             
          String rtValue = invocation.invoke();//放行 ,下面执行的方法会有返回值,然后将这个返回值返回     
          System.out.println("拦截后");             
          return rtValue;         
       }     
    }
  • 结果应该是:
    • 拦截前-动作类-jsp-拦截后
    • 即先执行拦截器,然后在执行方法,执行方法返回的逻辑视图,最后再次执行拦截器
  • 使用自定义拦截器
    • 拦截器参数可以用set方法或者在xml中用param来设置, 如果在class中用Set来设置,需要覆盖父类的init()方法.
    • 编写一个类,继承AbstractInterceptor(所有方法都会拦截)
    • 配置拦截器
      • 在pageage里面用<interceptors><interceptor name="" class=""/></interceptors>来声明拦截器
    • 使用拦截器(如果只是在单纯的指定自定义拦截器,则默认拦截器不起作用)
      • 在action里面使用<interceptor-ref name=""></interceptor-ref>来使用拦截器(使用了自定义拦截器,则默认拦截器失效)
      • 代码
    • 指定方法拦截
      • 继承MethodFilterInterceptor方法
      • 使用
        • 通过<param name="excludeMethods">query</param>的形式传递不需要过滤的方法(includeMethods需要包含的方法),参数为需要拦截的方法.
        • 代码
  • 拦截组合
    • 定义组,覆盖默认拦截器, 将拦截器声明为全局的拦截器
    • 代码
  • 简单的登录验证

文件上传

  • 表单域前提: post, enctype="multipart/form-data"
  • struts2中,是fileupload拦截器完成的
  • 单文件上传
    • 存储文件可以用FileUtils.copyFile(file1, target); 方法, file1: file文件域对象 target: 目标文件(创建的文件)
    • 上传文件
  • 多文件上传
    • 参数和单文件相同,不过要改成数组或者List方式来存储
    • 存储文件时需要遍历File数组
  • 文件错误信息提示
    • 修改上传文件默认错误信息
    • 在src文件夹下创建fileupload.properties 文件
    • 配置参数 struts.messages.upload.error.SizeLimitExceededExceptionstruts.messages.error.file.extension.not.allowed 等,可以用{1}来设置系统返回值
    • 示例

文件下载

  • 动作类中需要定义InputStream对象,(名称不能为in)和String Filename
  • <result type="Stream"> Xml配置文件结果视图类型为Stream
  • 需要设置参数
    • inputStream 设置输出流,名字为Action中定义的名字
    • attachment;filename=${@java.net.URLEncoder@encode(fileName,'UTF-8')} ,设置响应头
  • 代码

OGNL表达式

  • 导入标签 <%@ taglib uri="/struts-tags" prefix="s"%>
  • OGNL不仅仅可以在jsp中使用,在其他地方也可以(例如xml配置文件)
     <!-- 调用任意对象的任意方法  -->     
     <s:property value="'abcdefg'.length()"/>     
     <hr/>     
     <!-- 访问静态变量 -->     
     <s:property value="@java.lang.Integer@MAX_VALUE"/>      
     <hr/>     
     <!-- 访问静态方法 配置参数:<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>  xml中-->     
     <s:property value="@java.lang.Math@abs(-100)"/>
  • context上下文
    • ActionContext私有化会使得jsp页面获取不到Context/valuestack中的值
    • ActionContext和ValueStack声明周期都是一次http请求
    • 传输的数据存储在context,数据中心
    • 在jsp页面使用标签可以显示context中的信息
    • context是一个Map,每个域对象对应一个值, 这个值可以是Map也可以是其他的 即Map
    • 动作类的生命周期,每次访问都会创建新的动作类实例,ActionContext和ValueStack, 会一直保持在你的线程中,所以线程安全.
    • ActionContext API
  • ValueStack
    • ValueStack属于Context里面的一个属性,结构为栈
    • 也可以通过ValueStack获得Context,ActionContext中的Context和ValueStack里面的相同
    • 如果ValueStack中有多个名字相同的值<s:property value="[1].month">
    • 获取对象数据的不同:
      • 获取Context中的数据需要用#开头
      • 获取ValueStack中的数据直接写属性名字就可以,会从栈顶一直往下找.
    • 基本方法
      • vs.set("b1", "vb1"); //检测栈顶是不是一个Map,如果不是,创建一个Map,Map中的数据就是p1=pp1,再把这个Map压入栈顶,如果有,则会把数据直接放入
      • vs.setValue("name", "三平");//设置ValueStack中存在属性的值,属性必须存在
      • vs.setValue("#name", "三平"); //向Context中设置key为name, value为三平的Map, key可以不存在
      • vs.findValue(name);//取valuestack中的值不用#,context中的用#,从根中依次寻找对象的属性,没有找到会去Context内找(寻找整个Context),加强EL表达式运用的方法.
  • 对EL表达式的增强
    • EL不仅仅会搜索以前的几个域中的对象,还会通过find.Value()方法去Context中搜索
  • 特殊符号的运用
    • 在ognl表达式内如果需要输出字符串,则字符串需要添加单引号
    • %{} 将字符串当成ognl表达式
    • ${} 在国际化资源文件中引用OGNL表达式,在Struts2配置文件中引用ognl表达式(上次文件示例)数组和数列:${@java.net.URLEncoder@encode(fileName,'UTF-8')}
  • 压栈/弹栈
  • 基本方法
  • OGNL 创建List和Map

struts2标签

  • 内置标签需要导入标签<%@ taglib prefix="s" uri="/struts-tags" %>
  • <s:property value="'name'"/> //将value输出,使用ognl表达式都需要在struts2的标签内才可以
  • <s:set value="'value'" var="v1" scope="session"></s:set> 存放数据,如果没有指定scope, 默认放到contextMap和request中
  • <s:property value="'<hr/>'" escapeHtml="true"/><br/> 是否转译
  • <s:push value="'value3'"></s:push> 将对象压入valuestack栈中,标签结束后弹栈,则操作必须在结束标签之前进行
  • <s:bean name="java.util.Date" var="now"></s:bean> 给一个对象去一个名字,并且放到contextMap中
  • <s:action name="HelloWorldAction" executeResult="true"/> action指向一个动作,将动作结果包含进来,类似于EL标签的include
  • <s:iterator value="#request" var="s"> forEach,将当前遍历的元素存储到contextMap中,key就是var指定的值 m=Map.Entry,如果没有指定var,会将当前元素放到valuestack中
  • <s:radio list="{'man','faman'}" name="username"></s:radio> 如果contextMap中有key和下面连个标签的name相同,则会自动遍历内容,选中对应的选项
  • <s:if test="#grade=='A'"> </if> <s:elseif test="#grade=='B'"></s:elseif> if-else标签
  • <s:url action="demo2" var="u1"> <a href="${u1 }">点我</a> url标签和a标签传递参数是用<s:param name="username" value="'你也好'"> 来传递
  • <s:a action="demo1"></s:a>
  • 具体代码
  • 标签简单实现防止表单重复提交
    • 在jsp页面使用
    • 在xml里面配置 有两种方法 (token, tokenSession)
      • <interceptor-ref name="token"></interceptor-ref> //需要结果视图,如果重复提交会转向结果视图
      • <interceptor-ref name="tokenSession"></interceptor-ref> //不需要结果视图,点多次提交会等待

struts

struts2的插件机制

  • struts2加载配置文件的顺序:
    • struts-default.xml 核心的配置文件
    • struts-plugin.xml 插件的配置文件
    • struts.xml 程序员开发的时候需要写的配置文件
  • objectFactory类 : 生产struts2关键组件, 如拦截器,结果集,action, 可以通过继承这个类来改写方法
  • 插件机制的原理
    • 我们可以通过继承 objectFactory类来编写自己需要的方法,然后通过改变配置文件中的参数,将objectFactory改变为我们自己编写的类.
    • 在工程的Lib下有很多个struts2-plugin-xx.jar包,在这个包下有一个struts-plugin.xml文件,在这个文件中可以配置很多内容,只需要吧这个jar包放到lib下面,当tomact启动的时候被加载了, 如果不需要,只需要把这些jar包移除掉就可以了 这就是插件机制
    • struts2底层用objectFactory.buildAction方法来创建action的,所以我们可以继承objectFactory类改写方法,而在配置文件中可以指定objectFactory是哪一个具体的类,所以我们只需要把jar包放进去和配置好Xml文件就可以了
  • 如果需要在生成Action之前做一些操作,那我们就可以考虑选择重写objectfactory方法.
  • objectfactory说明
    • 该对象称为对象工厂:生成对象的工厂,struts2的很关键的组件都可以是一个对象
    • 在default.properties文件中有一个常量struts.objectFactory,该值就是对象工厂
  • objectfactory的示意图

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏idba

Redis 删除1.2亿指定前缀的key

因为更换IDC的原因,我们需要迁移缓存到新的机房,开发同学提出老的缓存有1.2亿无效(未设置过期时间)的key和正常在用的业务key,在迁移之前可以先指定前缀将...

751
来自专栏java 成神之路

NIO 之 MappedByteBuffer

35811
来自专栏SDNLAB

Ryu:OpenFlow协议源码分析

Ryu支持OpenFlow所有的版本,是所有SDN控制器中对OpenFlow支持最好的控制器之一。这得益于Ryu的代码设计,Ryu中关于OpenFlow协议的代...

38411
来自专栏Python研发

Django|第一部

  注明的MVC模式:所谓MVC就是把web应用分为模型(M),控制器(C),视图(V)三层;他们之间以一种插件似的,松耦合的方式连接在一起.

1093
来自专栏有趣的Python

6- vue django restful framework 打造生鲜超市 -完成商品列表页(下)

Vue+Django REST framework实战 搭建一个前后端分离的生鲜超市网站 Django rtf 完成 商品列表页下 drf中的reque...

30012
来自专栏JMCui

MongoDB系列二(介绍).

一、特点     学习一个东西,至少首先得知道它能做什么?适合做什么?有什么优缺点吧?     传统关系型数据库,遵循三大范式。即原子性、唯一性、每列与主键直接...

2708
来自专栏葡萄城控件技术团队

程序员Web面试之JSON

JSON是什么? JSON(JavaScript对象表示法), 是在网络通信下,常用的一种数据表达格式,它有助于我们于一个自描述的,独立的和轻的方式呈现并交换数...

20210
来自专栏玩转JavaEE

Redis教程

断断续续,Redis教程总算告一段落了,最后一篇其实很早就写好了,一直忘了发,现在总算凑齐了,发出来,做成一个完整的教程,可能还会有遗漏的点,遇到了再慢慢补上。...

993
来自专栏Java学习之路

Struts2学习---result结果集 result type:全局结果集:动态结果集带有参数的结果集

这一章节主要介绍如何配置结果集,分为以下几个知识点: 结果集类型(result type) 全局结果集(global types) 动态结果集(dynamic ...

3074
来自专栏PhpZendo

PHP 生成器入门

PHP 在 5.5 版本中引入了「生成器(Generator)」特性,不过这个特性并没有引起人们的注意。在官方的 从 PHP 5.4.x 迁移到 PHP 5.5...

921

扫码关注云+社区