struts2-第一天

框架搭建

    1.jar包的准备

    2.配置web.xml,配置struts2核心控制器,接收所有的请求(可在dispatcher.ng.filter包下拷贝,把.class去掉)。

    3.拷贝struts.xml和log4j到src目录下。

        3.1写个package包,给个名字:user,包就相当于一个模块,再添加extends="struts-default"

        3.2里面写action标签,写name和实体类

        3.3里面写result标签,写name和页面

执行的过程:请求url满足了/*,就交给了核心控制器,它启动会把struts.xml文件的配置全部读到内存中,用一个对象来保存,会在这里面找有没有login的配置,接着会找到对应的类,当action配置里没有配method属性,它就执行业务逻辑控制器类里的execute(),方法完成后会返回字符串,这个字符串会交给核心控制器,再找里对应的字符串,匹配就会用这个页面生成响应到客户端。

struts2-core-2.3.15.1.jar里org/apaqi/struts有配置文件default.properties,

    1.更改请求后缀

    2.开启开发模式

ActionSupport类

    struts.xml里,配置extends="struts-default"的好处是,如果action里没有配置class属性,将使用struts-default.xml(在核心jar包里)中配置的默认类com.opensymphony.xwork2.ActionSupport(最后面),如果没有配置method,就使用execute(),如果result里没有配置name,默认是success

请求参数接收

    一、标量值方式接收参数

        struts对于提交到action的参数,会当作这个action有这个属性,就会调用这个参数set方法来接收(保存)提交的参数。

    二、复合类型方式接收参数(常用)

    三、模型驱动方式获取参数(少用)

        1.业务逻辑控制器类要实现ModelDriven接口

        2.预先创建user,并提供方法返回user

        3.代码不需要写getset方法

    四、servlet API方式获取参数(需掌握)

        1.业务逻辑控制器类要继承ActionSupport

        2.通过ServletActionContext.getRequest()得到HttpServletRequest

        3.就可以用以前getParameter()

Servlet APi 获取

    一、ServletActionContext类(重点)

        ServletActionContext.getRequest().getSession()

    二、Struts2Aware拦截器IOC模式(重点)

        1.实现ServletRequestAware接口,重写setServletRequest(HttpServletRequest request),把参数赋值给成员变量HttpServletRequest request,后面就可以使用request。

    三、四、ActionContext类的get方法

Action动态方法

    需要开启动态方法调用支持,

    一、login!login.do叹号方式.注意:用感叹号动态调用时,配置文件的action是不写!的,在提交地址那里写,如不写!指定调用的方法,默认调用execute方法。

    二、login_*统配

命名空间

    1.命名空间前面加/

        规则是:1.1如果命名空间存在,进入命名空间搜索action,action存在就执行,不存在就报异常

    1.2如果命名空间不存在,自动删除最后的命名空间,再进行搜索

    2.加命名空间后,提交地址要加前面那段(不能/开头),设置了后缀加后缀,但配置那里的action的name属性不加后缀(这里必须注意)。

    3.当配置文件struts.xml的用了命名空间时,响应页面一般要加/。而提交地址要加命名空间.

六、类型转换

    2013-1-15默认会转换?月份有0吗?

    自定义类型转换器的实现

        方式1.继承DefaultTypeConverter类

        1.1如上,UserAction类要继承ActionSupport类(如不继承,无法显示异常等)

        1.2重写convertValue方法

        1.3在action包下新建一个同名的UserAction-conversion.properties,文件内容:user.loginTime属性 = org.fkjava.converter.MyConverter转换器

            全局的跟struts.xml配置文件放在一起

    方式2.继承StrutsTypeConverter类(抽象类)(推荐使用)

        --有两个要实现的方法,主要实现前台到后台convertFromString(Map context,String[] values,Class toType)方法,第一个参数是上下文,第二个是提交的实际数据,第三个是提交数据的类型

            方法实现逻辑:判断values不为空后,如果写的是转换时间的转换器,判断toType==Date.class,一旦涉及到时间对象,simpleDateFormat,从字符串转换为Date类型用sdf.parse(values[0])

    全局:在src下xwork-conversion.properties,java类型=自定义转换器

    转换错误显示:

        1.默认:

        1.1<%@taglib prefix="s" uri="/struts-tags"%>,

    2.局部类型转换失败自定义信息

        2.1在action包下新建一个UserAction.properties文件,内容是invalid.fieldvalue.属性名(表单提交的name属性user.loginTime)=提示语句

        2.2throw new TypeConstraintException("日期类型转换失败!");

    3.全局类型转换失败自定义信息

        3.1 src根目录下,fkjava.properties国际化资源文件:xwork.default.invalid.fieldvalue={0},提示信息

        3.2 struts.xml下配置常量name="struts.custom.i18n.resources" value="fkjava"/>

七、后台验证

      如果希望使用struts2提供的验证框架,必须extends ActionSupport

      调用步骤:

      1.先类型转换

      2.验证

      3.调用目标action方法

      方式一:代码方式实现输入验证

          a.对action所有方法进行验证

          方式1:重写ActionSupport中的validate方法

          //针对本action的所有action方法进行验证

    public void validate(){

        System.out.println("-------validate()--------");

        if(user == null || "".equals(user.getUserName())){

            /**一旦addFieldError()加了东西,就会返回INPUT*/

            this.addFieldError("user.userName","请输入用户名");

        }

    }

    --输出错误信息:

      b.对单个方法进行验证,只需要在这个方法的后面加你要验证的方法,如login方法要验证,validateLogin()

      方式二:配置xml方式实现输入验证(比较常用)

          xml文件名写法:NoticeAction-addNotice-validation.xml针对一个action请求做后台验证(中间是里name的值)

                     NoticeAction-validation.xml针对整个NoticeAction处理类都做后台验证

      例子:

      

    "http://struts.apache.org/dtds/xwork-validator-1.0.dtd">

    

        

            

                true

                请输入用户名3!

            

            

                4

                6

                请输入${minLength}~${maxLength}范围的用户名3

            

        

    

国际化

    表单:

    1.写fkjava.properties国际化文件,依次再写其他语言的properties。说明:里面写的就是需要替换的字眼

    2.用struts2标签库写表单(先引入),表单里的每一项多一项key的属性,写的就是properties里面的key

    3.如果想动态改变语言环境,加一个带request_locale参数的表单,如直接提交到jsp不行,就配置一个最简单的action把表单提交到action,再到jsp

    页面:

    1.使用i18n标签,name=资源文件前缀,,再里层标签${username}

    

        

            ${user.userName}

        

    

    代码中:

    1.put之后,利用ActionContext.getContext.put("msgs",this.getText("国际化资源里的key")),页面上取出:${msgs}

result的type属性

    服务器重定向

        1.dispatcher(默认),转到资源(jsp html 其他视图技术)

    2.chain,转到一个action,参数有actionName,nameSpace,method等。

    客户端重定向(参数不会自动传递,如需传递,在actionName拼接,或加123456)

    动态跳转:定义动态结果页面(如果登录名等于tom,跳到tom.html)定义成员变量typePath,并提供getset方法

    全局result

        1.包里配置。当局部没有找到返回的字符串时,会去找全局,如果全局也找不到就生成默认错误响应。

    2.如果局部全局都有,局部起作用。

异常处理

    1.局部

    2.全局

        

    注意:当局部异常处理找不到才会找全局

    3.异常信息显示

        方式一:引用struts标签库,

    方式二:直接EL表达式:${exception.message}和${exceptionStack}

拦截器

   自定义拦截器

    1.写一个类继承AbstractInterceptor,重写intercept方法。

    2.invocation.invoke()把控制权限交给下一个拦截器,没有的话交给action,返回值String就是提交给action执行的方法执行完以后返回的字符串

    3.配置拦截器在package里,引用(使用)是在action里。

    4.一旦自定了拦截器,默认的就不起作用。

    5.拦截器的定义顺序决定了调用的顺序,最好先配置好默认的拦截器

    6.如果有一堆的拦截器要用,可以配置一个拦截器栈

    7.如果在一个package中不想每一个action都写引用拦截器,可以在package里定义默认拦截器(本包有效)

   方法拦截器

        1.写一个类继承MethodFilterIntercepter,重写doIntercept方法。

    2.引用时多一项参数login,logout,指定哪些会调用拦截器(白名单)

    3.如果白名单和黑名单冲突,白取胜(邪不压正)。

   内置拦截器

       timer:统计action方法执行耗时的拦截器

       token:防止表单重复提交

           1.在表单提交的action上调用默认拦截器

       2.配置当出现重复提交时到什么页面error.html

       3.页面上用struts标签库,在form里加上,其他不变

   登录检查

       1.自定义一个拦截器

       String result = "login";

    if(flag){

        HttpSession session = ServletActionContext.getRequest().getSession();

        User u = (User)session.getAttribute("loginUser");

        if(u != null){

            result = invocation.invoke();

        }

    }else{

        result = invocation.invoke();

    }

    return result;

       2.配置(声明)拦截器

       3.调用拦截器(先调用系统默认),里面还可以给拦截器参数(拦截器的成员变量要有getset方法)

freemarker

    使用要引入一个jar包和要在web.xml文件中做一个配置。

文件上传下载(注意这里:配置跟default.properties有关!)开始是在struts2-core-2.3.15.1.jar这个jar文件里的

    一、单个文件上传

        上传的form表单的method属性必须是post,enctype必须是multipart/form-data

        1.页面的表单

            

            

            

    这时要配置action:

         

              

            success.jsp

            error.jsp

          

         

    注意这里action配置没有命名空间,如果有,表单提交action要加命名空间。??

    2.UserAction里

         2.1增加属性

            private File headImg;//接收文件用的属性(可以跟表单的不一致,因调的是set方法)

            private String headImgFileName;

            private String headImgContentType;

            //三个属性要增加getset方法

            说明:这样写才能获取到文件名和文件类型

         2.2.upload方法里

            //获取服务器的资源(存储)路径

        String path = ServletActionContext.getServletContext().getRealPath("p_w_picpaths");

        File file = new File(path,headImgFileName);

        if(!file.getParentFile().exists()){

             file.getParentFile().mkdirs();

        }

        FileUtils.copyFile(headImg, file);

         2.3如想方便查看上传的文件,可设置上传路径:双击tomcat,在ServerLocations那里,

               选中间那一栏(使用tomcat安装路径)。

    二、多个文件上传

    属性改为数组,循环new File,其他基本不用变。

    上传约束配置

        1.全局大小限制:struts.xml里,配置整个工程:

    2.局部大小限制:局部的大小限制必须小于全局大小限制!在对应的action下配置拦截器,拦截器里可以设置参数:

         数值

    注意点:建议把默认的拦截器放在上传约束拦截器下面。

    3.类型约束:p_w_picpath/pjpeg,p_w_picpath/x-png

    4.后缀约束:.jpg,.png,.bmp

    三、下载

        1.struts-user.xml文件配置下载的action:

        

            //没配method默认执行execute方法

            

                application/octet-stream

                fileStream(要与Action类getset方法对应)

                p_w_upload;filename="${fileName}"//对应action类fileName属性get方法

            

        

        

    2.在UserAction类增加getFileStream方法

    public InputStream getFileStream(){

          return ServletActionContext.getServletContext().getResourceAsStream("/p_w_picpaths/"+fileName);

    }

    还要增加fileName属性,提供getset方法,在页面上增加这个参数。

    3.中文乱码:在取流的方法里,return之前加上这句(getResource里的变量毫无疑问改成s):

    String s = new String(fileName.getBytes("ISO-8859-1"),"UTF-8");

    4.下载页面:

    下载1

OGNL表达式

     标签:用来调试程序

     值栈(valueStack):取值栈里的值:${user.userName}或者

     栈(stack)中获取数据要加#号:或者${requestScope.r}或者${r}(先找小范围,再找大范围,如果小范围找到,不会再找大范围)

     访问对象属性中还是对象:即:对象.对象.属性

     访问方法:调用值栈中对象的普通方法:

     开启允许静态方法调用:

         

取值栈的一个例子:

Struts2标签

     1.控制标签

          1.1-iterator标签操作Map:

      方式一:操作简单的Map:

      value是json数据,var是临时变量,显示用,

      方式二:后台准备数据,

      Map request = ac.getContextMap();

      Map maps = new HashMap<>();

      maps.put("A","中国");

      maps.put("B","美国");

      maps.put("C","英国");

      request.put("maps",maps);

      页面:value="#request.maps",其他不变

      1.2—iterator标签操作List:

           方式一:这时value不用#号{'a','b','c'},显示就去掉.key和.value,其他一样。

           方式二:List userList = new ArrayList<>();

           userList.add(new User("admin",12,new Date()));

           userList.add(new User("admin2",13,new Date()));

           request.put("userList",userList);

           页面:value="#request.userList" var="l",显示

      iterator标签进行数据过滤操作

           ?获取满足条件的所有数据

           value="#request.userList.{?#this.userPass %2 != 0}"//意思是判断当前迭代对象的userPass与2取余不为0就输出

           ^获取满足条件的第一条数据

           value="#request.userList.{^#this.userPass %2 != 0}"

           $获取满足条件的最后一条数据

           value="#request.userList.{$#this.userPass %2 != 0}"

     if...else if...else

          

               输出语句

          

          

               输出语句

          

          

               输出语句

          

     append集合合并标签:把两个list拼接在一起放在newList里

          

               

           

          

          

               

          

     generator字符串分割标签:分割完是一个数组g

          

          

               

          

     subset获取子集合

        方式一:在里面迭代

          

               

                    

           

          

        方式二:在其他地方迭代

          

          

           

          

    2.数据标签

         set标签:指定把某值用var的变量名字设置到某个范围

          

          

     push标签:将某个值置于值栈的顶部,标签结束后,将从值栈中移除。

          

               

          

     bean标签:可以在页面创建一个对象

          

               tom

               123456

              

          --

     date标签:

          <%

               request.setAttribute("now",new java.util.Date());

          %>

          

     include标签

================================

4、struts2的处理流程

a、browser-->struts2控制器-->查找action(在配置文件找)-->(回到)struts2控制器-->拦截器1,2,3...-->动作Action-->(request)struts2控制器-->查找视图(配置文件找)-->struts2控制器-->视图-->browser

一个请求在Struts2框架中的处理大概分为以下几个步骤 

1 客户端初始化一个指向Servlet容器(例如Tomcat)的请求 

2 这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助,例如:SiteMesh Plugin)

3 接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper来决定这个请是否需要调用某个Action 

4 如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy 

5 ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类 

6 ActionProxy创建一个ActionInvocation的实例。 

7 ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。 

8 一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可 能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts2 框架中继承的标签。在这个过程中需要涉及到ActionMapper

在上述过程中所有的对象(Action,Results,Interceptors,等)都是通过ObjectFactory来创建的。

5、Struts2配置文件

a、可以给每个模块定义一个包(Package元素的namesapce属性)

b、继承某个package(Package元素的extends属性)

c、为了让大型应用的struts.xml更好管理,可以把它分成几个较小的文件ps:

6、拦截器是什么?struts-default.xml

是将控制器不做的事情封装在另外一个地方

a标签路径最好是通过绝对路径来:request.getContextPath()

接收参数三种方式:

1.Action属性来接收

2.用VO来封装表单属性

3.利用ModelDriven模型驱动来接收

要实现 implements ModelDriven接口,Action里面重写getModel()方法。

==========填充下拉列表==========

第一种:

第二种:

先定义private List> jobs;

第三种:

$.ajax({

    url : "${ctx}/dept/loadDeptAjax.action",

    type:"post",

    dataType:"json",

    async : true,

    success:function(data){

        //获取选中的

        var deptId = "${employee.dept.id}";

        alert();

        $.each(data,function(){

            $("

        });

    }

});

List>dept = deptMapper.find(null);

========================Struts2========================

namespace

1、命名空间一般是以“/”开头

2.当namespace=""时,它会匹配所有的。

request.getScheme()+request.getServletName()+request.getServletPort()+path;

动态方法调用(DMI):

意思就是不配置method属性,在请求的时候这样:user!add

    /student{1}_success.jsp

    /{1}_{2}_success.jsp

参数接收:

1.普通类型

2.用DTO来接收

public class UserDTO{

    private String name;

    private String pwd;

    private String cpwd;

}

3.模型驱动:

public class UserAction implements ModelDriven{

    private User user = new User();

    public String add(){

        return SUCCESS;

    }

    public User getModel(){

        return user;

    }

}

参数校验:

addFieldError("name","name is error!");

页面:

(Map)ActionContext.getContext().get("request");

session = ActionContext.getContext().getSession();

在页面上拿,要用#key这种方式。

Result的配置

forward到另外一个action

全局result

    /main.jsp

动态结果集

${r}

遍历操作:

   |

   |

  遍历过的总数:

  遍历的元素索引

  当前是偶数:

  当前是奇数:

  是第一个元素吗:

  是最后一个元素吗:

遍历map

   | 

   | 

struts2错误标签自动有样式: errorMessage

可以.fielderror ul li{ list-style-type:none;  }解决

struts2Filter -> 拦截器 -> xxAction

                                             ↓

struts2Filter <- 拦截器 <- xxAction

默认拦截器都配置在struts-default.xml

拦截器也是配置在struts.xml文件里,