Struts2 & SSH整合
执行流程
简化的执行流程:
- 请求到达服务器,经过过滤器,再经过前端控制器 (Struts2的前端控制器是一个filter的xml文件而不是java文件)
- 查找映射器,当前请求是否需要后端控制器处理,找到结果
- 然后调用后端控制器Action,处理请求,返回数据和视图
- 再然后找到视图并渲染
- 最后将结果响应回客户端
https://blog.csdn.net/wjw0130/article/details/46371847
初识
package是整个配置的核心部分。每个package代表一个独立的模块。
1.name属性:是package的唯一标识;
2.namespace属性:对action配置进行逻辑划分。
如果不给package指定namespace,struts2会默认使用一个空字符串(即什么都没有)作为默认的namespace。
3.extends属性:制定本package继承另外一个package的所有配置。
Action配置中,配置项的默认值
1.如果没有指定Action的class,默认值为ActionSupport。
2.如果没有指定Action的method属性,默认值为execute()方法。
3.如果没有指定result的name属性,默认值为“success“
struts配置文件中包的使用说明
在Struts2中使用包来管理Action的,包的作用于java中包的作用非常类似,主要管理一族业务功能相关的action。在实际应用中,我们把一族业务功能相关的action放在同一个包下。图片链接https://blog.csdn.net/qq_32971807/article/details/52785891struts2命名空间namespace和访问路径的关系: https://blog.csdn.net/menghuannvxia/article/details/47169991
注意当package中使用命名空间时,页面的url也要随之改变,result还和以前一样,struts2中采用的都是转发或包含,所以可以直接访问WEB-INF下的文件.前端控制器中namespace属性要加 /
后端控制器类的第一种实现方式: 继承ActionSupport类
后端控制器类的第二种实现方式:实现Action接口
后端控制器实现的第三种方式,自定义类,推荐这种方式,因为上面两种方法都是一个请求对应一个类,比较麻烦,自定义类可以实现一个请求对应一个方法,我们只需要写一个类就够了
URL的设计
为了简化核心配置文件中action的配置,那么URL采用带有下划线(_)特殊符号的格式,那么文件中配置就可以添加通配符,而且method属性可以使用下标,注意下标默认是从1开始的,例如
前台向后台传值
要求后台控制类中要有前台传来的值的属性,并且有对应的getter,setter方法,不然也赋不上值,配置文件不变
注:struts2在实现参数操作的时候,由于设置的是全局性质的变量,因此Action对象必须是多例的
页面复选框性质的传参,后台是集合性质的属性接收
使用对象传递参数
- jsp页面不变
- 前端控制器不变
- 创造要接受参数对应的实体类
- 后端控制器类要求:
- 后端控制器类实现ModelDriven类
- 首先要创造接受参数的实体类的对象,注意是创造出对象,而不只是创造出引用
- 重写ModelDriven类中的getModel方法,返回我们创造出来接受参数的那个对象
- 写前端控制器类对应的方法(和前面的一样)
原生态方式传递参数
- jsp页面没有变化
- 前端控制器没有变化
- 后端控制器
- 首先要获取request对象, 我们可以通过ServletActionContext来获取,注意他获取的httpHttpServletRequest对象属于javax包中的,我们还需要导包
- 获取到request对象后,我们就可以通过getParameter方法获取各种参数了
-
通过ServletActionContext工具类,可以获取到request对象、response对象、pageContext对象、application对象、valueStack对象(狭义值栈)
后台到页面的传参
-
原生态传参到页面, 就是用我们之前学的获取request对象,向作用域中放值,然后到页面通过EL表达式取值
-
值栈传参
什么是值栈
1、之前 Web 阶段,是在 Servlet 中把数据放到域对象,再在页面中使用 EL 表达式获取数据「域对象的主要作用:在一定范围内,存值和取值」
2、Struts2 本身也提供了一种存储机制,称之为 值栈(ValueStack)值栈分为广义值栈(Stack Context)和狭义值栈(Value Stack Contents)两种,广义值栈通过ActionContext.getContext()方法获取,狭义值栈可以通过先获取request,然后再将request作为参数通过ServletActionContext.getRequest()方法获得,也可以通过广义值栈直接获取
(1)值栈类似于域对象,可以存值和取值
(2)在 Action 中把数据放到值栈,再在页面中获取值栈数据
3、Servlet 和 Action 的区别
(1)Servlet:默认在第一次访问时创建,且只创建一次,是单实例对象
(2)Action:访问时创建,且每次访问都会创建,创建多次,是多实例对象
4、值栈的存储位
(1)每次访问 Action 时,都会创建 Action 对象
(2)在每个 Action 对象中都会有一个值栈对象(且只有一个)
从网页查看值栈信息:需要用到s标签中的debug标签
拦截器
intercept方法的return值有什么作用?
Struts机制:
只要调用了 invoke()方法,如果能成功的调用对应的Action类中的方法,struts就会按照该方法的返回值去找对应的result,从而忽略拦截器的返回值;
如果不调用 invoke() 方法,那么 struts 就会按照 intercept()的返回值去找对应的result。
扩展:
这种方法常用于权限认证,当符合要求的时候才会调用 invoke() 方法,执行Action中的方法当满足权限要求的时候,直接返回错误界面,这就用到了拦截器中的返回值
拦截器的执行顺序
参考链接:https://takeme.iteye.com/blog/1651498
如果一个系统中配置了多个拦截器,根据拦截器配置的顺序不同,执行拦截器的顺序也不一样。通常认为,先配置的拦截器,会先获得执行的机会,但是实际情况不是这样。execute()方法执行之前,配置在前面的拦截器,会先对用户的请求起作用。execute()方法执行之后,配置在后面的拦截器,会先对用户的请求起作用。(两头向中间靠拢的执行)
SSH整合
SSH整合就是Struts2,Spring和Hibernate整合,有时候也可以叫做s2sh整合
为什么Struts2的后端控制器类Action要用多例
很简单的道理,就跟你自来水一样,有很多的水龙头,但水管只有一个。
为啥要很多水龙头,因为有多个人同时用;为了避免长队,只能这样来分担压力为啥只有一个水管,易维护,集中处理。
使用单例,是由于没必要每个请求都新建一个对象,这样既浪费CPU又浪费内存;之所以用多例,是为了防止并发问题;即一个请求改变了对象的状态,此时对象又处理另一个请求,而之前请求对对象状态的改变导致了对象对另一个请求做了错误的处理。
先来说说Java web中的单例应用场景:数据库连接池就是单例模式,有且仅有一个连接池管理者,管理多个连接池对象。我们常用的service和dao层的对象通常都是单例的(由于其所有的请求都用一个对象来处理),而struts2中的action则是多例,由于每个请求是用一个新的对象来处理的(因为action本 身含有请求参数的值,即可改变的状态)。 log4j日志记录也是单例模式,因为从始至终都仅维护一个对象。(应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因此只能有一个实例去操作,否则内容不好追加)。