Struts2
https://blog.csdn.net/qq_35064774/article/details/64934709
基础。配置,action,拦截器,Struts2UI标签,数据回显,资源国际化(省略),OGNL表达式,valueStack
基础1.为什么要引入struts?
既然Servlet能够完成的事,我们为啥要用框架呢??因为框架帮我们封装了很多常用的功能,更加灵活[不用把路径等信息写死在程序上],每个Servlet中都有doGet和doPost这样的方法,没必要的。我们抽取出来,通过配置文件来把这两个方法替换掉,那么我们的程序就会更加优化。
基础2.struts流程:
- 加载web.xml文件
- 找到我们配置的filter中的StrutsPrepareAndExecuteFilter拦截器
- 调用init()方法,同时访问struts.xml
- action方法返回页面
配置1 .路径配置:
- 如果配置后缀为
action
。那么后缀一定要写action - 如果配置后缀为
action,do,
。那么后缀可以是action,可以是do,也可以不写 - 如果配置后缀为
action,,
。那么后缀可以是action,可以不写
配置2.全局视图
<global-results>
<result name="success">/index.jsp</result> </global-results>
配置3.
<!-- 什么情况不配置class? 即处理的aciton -->
答案: 当只是需要跳转到WEB-INF下资源的时候。 -->
<action name="test2"> <result name="success" >/WEB-INF/index.jsp</result> </action>
action 1:为什么继承ActionSupport
ActionSupport类实现了VlidationAware等数据校验功能的类。
在Action类中需要用到Struts为我们提供的数据校验等Struts已经帮我们实现的功能,我们就继承着ActionSupport类
- 如果我们使用到了Struts2一些特用的功能,我们就需要继承ActionSupport
- 如果我们没用到Struts2的特殊功能,只要平凡写一个Java类行了。
- 大多情况下,我们还是会继承ActionSupport的。
action 2: 数据封装
方法1. 表达式封装(params拦截器来实现)
Struts预先帮我们完成了对数据封装的功能,它是通过params拦截器来实现数据封装的
- 创建一个User类,基本的信息和JSP页面是相同的。提供get/set方法
-
- 在JSP页面,提交的name要写成
user.username
之类的(
)用户名:<input type="text" name="user.username"><br>
方法2.模型驱动 ,实现 ModeDriven 接口
前提:当我们使用params拦截器完成数据自动封装的时候,如果要封装的是JavaBean对象,那么在web表单中就必须的name写上javaBean.属性名
....
这样的话,web层和Action层就耦合。因为在web层必须要知道封装的JavaBean对象是什么才能够实现自动封装!而模型驱动就解决了这个问题!即时不知道Action层的JavaBean对象是什么,也能够完成数据自动封装!
操作:实现ModelDriven接口,
- 实现ModelDriven接口,重写方法....实现接口时,要封装的对象是什么,形参类型就给什么。
- JSP提交页面,直接写上JavaBean对象的属性就行了..不需要写上JavaBean对象的名称!(
)<td>用户名:<input type="text" name="username"></td>
3.属性方法:
属性封装
在 action 中设置成员变量,变量名与表单中的 name 属性值相同
生成变量的 set 方法
action 3: 得到域对象
Struts怎么把数据保存在域对象中呢???Struts提供了三种方式
1.通过ServletActionContext得到Servlet API
//通过ServletActionContext得到Servlet API
javax.servlet.ServletContext context = ServletActionContext.getServletContext();
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession();
HttpServletResponse response = ServletActionContext.getResponse();
2.通过ActionContext类来得到request、response、session、application被Struts封装的Map集合
//得到ActionContext 对象
ActionContext context = ActionContext.getContext();
Map<String, Object> session = context.getSession();
Map<String, Object> application = context.getApplication();
//这是request的Map
Map<String, Object> request = context.getContextMap();
3.实现接口
当web容器发现该Action实现了Aware接口,会把相对应的资源通过Aware接口注射进去,实际上就是一种IOC。
Aware实际就是一种拦截器,拦截代码在执行Action之前执行、将资源注射到Action中.
小结:
如果我们需要使用到对象的其他方法,类似getContextPath()之类的,那么只能使用第一种
如果我们就按照平常的开发,我们就使用第二种【获取简单,没有耦合】
至于第三种,当我们将来可能开发BaseAction的时候,就使用它!
action 4: 日期转换问题
action 5: 文件上传和下载
Interceptor
拦截器 1:为什么我们要使用拦截器
Struts为我们实现了很多的功能,比如数据自动封装阿..文件上传功能阿....Struts为我们提供的这些功能都是通过拦截器完成的
- 数据自动封装通过
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
这个拦截器。 - 文件上传通过
<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
这个拦截器
值得注意的是:Struts2默认执行的是默认拦截器栈,一旦用户有指定执行哪些拦截器,那么默认的拦截器栈就不会被执行!
拦截器 2:自定义拦截器:
Struts2提供了Interceptor这个拦截器接口,只要我们实现这个接口,那么这就算是自定义开发拦截器
public class MyInterceptor implements Interceptor { @Override public void destroy() { } @Override public void init() { } @Override public String intercept(ActionInvocation actionInvocation) throws Exception {
//拦截方法案例:
//得到正在执行的代理对象
ActionProxy proxy = actionInvocation.getProxy();
//通过代理对象得到正在执行的方法
String method = proxy.getMethod();
//如果方法的名字不是login,那么就让他们返回到login页面上
if (!method.equals("login")) { //查看用户是否登陆了 Object user = ActionContext.getContext().getSession().get("user"); //如果没有登陆,回到login页面 if (user == null) { return "input"; } else { //登陆了,那么就让它访问具体的用户信息页面 return actionInvocation.invoke(); } } else { //如果是访问login方法,那么就让它执行 return actionInvocation.invoke(); }
// return null; } }
由于我们配置了自定义拦截器,那么struts默认的拦截器栈是不会执行的。如果我们想要使用默认拦截器栈的功能,就必须把它配置在我们自定义的栈中!
<package name="xxx" extends="struts-default" > <interceptors> <!--配置用户自定义的拦截器--> <interceptor name="MyInterceptor" class="TestAction"/> <!--自定义拦截器栈,我们配置了自定义的拦截器,默认的拦截器栈就不会被执行,因此,想要使用默认的拦截器功能,就要配置进来--> <interceptor-stack name="mystack"> <!--引用默认的拦截器栈,一定要放在第一行--> <interceptor-ref name="defalutStack"/> <!--引用自定义的拦截器--> <interceptor-ref name="MyInterceptor"/> </interceptor-stack> </interceptors> <!--上面配置了拦截器栈,但是没有被执行...下面配置执行拦截器--> <default-interceptor-ref name="mystack"/> <action name="TestAction" class="TestAction" method="execute"> <result name="success">/index.jsp</result> </action> </package>
拦截器执行顺序:
- 当服务器开启的时候,会执行拦截器的init()方法
- 当访问Action时,Action实例被创建
- 创建完Action实例,会调用拦截器的interceptor()方法
- 最后,执行Action的execute()方法
拦截器 3: 其他拦截器
计时拦截器:
执行等待拦截器:
Struts2防止表单重复提交拦截器:通过拦截器来实现,在需要提交的表单上使用token标签,<s:token></s:token>,
<table border="1"> <s:token></s:token> <tr> <td>用户名:<input type="text" name="username"></td> </tr>
在struts配置文件中配置拦截器,token拦截器默认是不会启动的,也就是说:需要我们手动配置.
<action name="user_*" class="zhongfucheng.action.UserAction" method="{1}"> <interceptor-ref name="defaultStack"/> <interceptor-ref name="token"> <!-- 要拦截的方法! --> <param name="includeMethods">register</param> </interceptor-ref> <!--如果是list,那么就跳转到list的JSP页面--> <result name="list"> /list.jsp</result>
Struts2UI标签:
显示页面的标签
<%--我们发现,Struts2UI标签用起来和HTML是差不多的--%>
<s:form id="form1" name="form1" method="POST" action="#"> <%--输入框数据,lable就相当于我们以前外边写的数据--%> <s:textfield label="用户名" name="user.username"/> <%--密码框--%> <s:password label="密码" name="user.password"/> <%--提交按钮--%> <s:submit value="提交"/> </s:form>
数据回显:
EL表达式的时候就已经用过了数据回显,Struts2也提供了数据回显的支持,并且,使用数据回显必须要使用Struts2的标签。有两种方法,表达方式的区别
方法1:
- 把数据放到request域中存储,跳转到对应的JSP页面...
public String login() { //把数据存储到域中 Map<String, Object> request = ActionContext.getContext().getContextMap(); request.put("username", "zhongfucheng"); request.put("password", "123"); return SUCCESS; }
- JSP页面使用Struts2标签,设置value属性就可以进行数据回显了
<s:form id="form1" name="form1" method="POST" action="" > <%--输入框数据,lable就相当于我们以前外边写的数据--%> <s:textfield label="用户名" name="user.username" value="%{#request.username}"/> <%--密码框--%> <s:password label="密码" name="user.password"/> <%--提交按钮--%> <s:submit value="提交"/> </s:form>
方法2:
- 直接放在值栈的数据就是根元素数据
//得到值栈对象
ValueStack valueStack = ActionContext.getContext().getValueStack();
valueStack.set("username","zhongfucheng");
- 在JSP就可以直接获取了
<s:textfield label="用户名" name="username"/>
资源国际化:
OGNL表达式:
操作对象属性的开源表达式。
- 支持对象方法调用,如xxx.doSomeSpecial()
- 支持类静态的方法调用和值访问,表达式的格式【例如:"@@floor(10.9)"就是调用Math.floor()的方法了】
- 支持赋值操作和表达式串联【这个其实EL表达式也能做】
- 访问OGNL上下文(OGNL context)和ActionContext
- 操作集合对象【EL只能遍历集合,OGNL可以创建集合】
1.valueStack对象 (值栈对象)
valueStack是Struts2数据存储的核心..ValueStack 实际是一个接口
.首先要知道数据是怎么存的,存到哪里,然后才讲解OGNL表达式是怎么取出数据的。
- 当用户访问Action,都会创建一个Action对象,ActionContext对象、valueStack对象..
- Struts2把Action对象放进valueStack对象之中。
- 将valueStack放进request域中,传入JSP页面(key: struts.valueStack)
- JSP页面就可以使用OGNL表达式获取值栈中的数据了!
在Action中我们可以手动获取值栈对象,有两种方式获取
// 获取值栈对象,方式1:
HttpServletRequest request = ServletActionContext.getRequest();
ValueStack vs1 = (ValueStack) request.getAttribute("struts.valueStack");
// 获取值栈对象,方式2: ActionContext ac = ActionContext.getContext(); ValueStack vs2 = ac.getValueStack();
CompoundRoot保存着这样的数据:
- Action对象以及Action对象的成员属性数据
- 使用ValueStack对象.push()进去的数据
- 使用ValueStack对象.set()进去的数据
- 其他代理对象的数据
- list存储结构
OgnlContext保存着这样的数据:
- 维护了CompoundRoot中所有的数据
- request、response等域对象所有的数据
- map存储结构
2.OGNL表达式取值
- Struts2会将valueStack对象封装进request对象域中,传入JSP页面。
- valueStack存储着OgnlContext对象。
- OgnlContext对象维护了CompoundRoot对象的数据
- CompoundRoot存储着Action等数据
也就是说通过OgnlContext对象可以获取大部分我们需要的数据了。
构建一个OGNL表达式,再解析表达式
- 如果是CompoundRoot类的数据,表达式不需要带#号
- 如果不是CompoundRoot类的数据,表达式需要带#号
例如:
<!-- 页面: 必须要拿到ValueStack -->
<br/>1. 取根元素的值<br/> <s:property value="user.id"/> <s:property value="user.name"/> <br/>2. 取非根元素的值<br/> <s:property value="#request.cn"/> <s:property value="#session.Session_data"/> <s:property value="#application.Application_data"/> <br/> <!-- 自动找request/session/application,找到后立刻返回 --> <s:property value="#request_data"/> <s:property value="#attr.Session_data"/> <s:property value="#attr.Application_data"/> <br/> <!-- 获取请求的参数数据 --> <s:property value="#parameters.userName"/> <!-- struts的调试标签:可以观测值栈数据 --> <s:debug></s:debug>
(此处不确定是否正确,待完善)
3.在 jsp 中使用 OGNL 需要引入 struts tag lib。
<%@ taglib prefix="s" uri="/struts-tags" %>
然后使用 标签 s:property:
<s:property value="'hello world'"/>