Struts2
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'"/>
 
                    
                     
                    
                 
                    
                

 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号