注册 登录
重磅消息:开通VIP会员,获取平台所有项目,永久使用,详细请咨询QQ:3376762016
远程服务部署安装,售后服务,请加QQ1:3376762016,QQ2:3597230140(即将满员),QQ3:1399491757(已满)
查看: 797|回复: 0
打印 上一主题 下一主题

struts2学习笔记及使用

[复制链接]

该用户从未签到

3518

主题

3532

帖子

66万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
668970
QQ
跳转到指定楼层
楼主
发表于 2016-10-15 14:28:15 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

   日期: 2012-11-7

  Struts2struts1 对比:
Struts2WebWork2基础发展而来的。和strut1一样,Struts2也属于MVC框架.
                 不过有一点大家需要注意的是:尽管Struts2struts1在名字上的差别不是很大,但
                 Struts2struts1在代码编写风格上几乎不一样的。那么既然有了struts1,为何还要
                 推出strut2。主要是因为struts2有以下优点:
1> 在软件设计上Struts2没有想struts1那样跟ServletAPI(例如:Action中方法参数
         HttpServletRequestHttpServletResponse)strutsAPI(例如 继承Action
         类和方法参数ActionMapping,ActionForm)有着紧密的耦合,Strut2的应用可以不依赖
         ServletAPIstrutsAPIStruts2的这种设计属于无侵入式设计。而struts1却属于
         侵入式设计。

2> Struts2提供了拦截器,利用拦截器可以进行AOP编程,实现如权限拦截等功能。

3> Struts2提供了类型转换器,我们可以把特殊的请求参数转换需要的类型。在struts1中,
    如果我们要实现同样的功能,就必须向Struts1的底层实现BeanUtil注册类型转换器才行.

4> Struts2提供支持多种表现层技术。如:jsp,freeMarket,Velocity等   

5> Struts2输入校验可以对指定方法进行校验,解决了Struts1长久之痛

6> 提供了全局范围,包范围和Action范围的国际化资源文件管理实现





开发第一个Hello word  
1. 导包
1) struts2-core-2.x.x.jar :Struts 2框架的核心类库
2) xwork-2.x.x.jar :XWork类库,Struts 2在其上构建
3) ognl-2.6.x.jar :对象图导航语言(Object Graph Navigation Language),Struts 2框架使用的一种表达式语言
4) freemarker-2.3.x.jar :Struts 2UI标签的模板使用FreeMarker编写
5) commons-logging-1.1.x.jar :ASF出品的日志包,Struts 2框架使用这个日志包来支持Log4JJDK 1.4+的日志记录。
6) Commons-fileupload   拷进去

2. 配置struts 的核心过滤器
      打开web.xml文件
     <filter>
           <filter-name>struts2</filter-name>
           <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
        </filter>

        <filter-mapping>
           <filter-name>struts2</filter-name>
           <url-pattern>/*</url-pattern>
        </filter-mapping>
注意    所有的请求 都会进入这个 核心过滤器


3. StrutsPrepareAndExecuteFilterinit()方法中将会读取src下默认的配置文件struts.xml完成初始化操作
注意:struts2读取到struts.xml的内容后,会将内容封装进javabean对象并存放在内存中,对于用户每次请求的处理将使用内存中的数据,而不是每次请求都读取struts.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>

    <package name="helloword"  extends="struts-default">

       <action  name="helloWordAction" class="com.struts.action.HelloWordAction">

          <result name="success">/WEB-INF/jsp/message.jsp</result>

       </action>

    </package>
</struts>

Package: 包 跟java类似 来管理一组相同功能的类
    Name属性名称 一定要唯一 (因为包可以继承)

Nasepace : 表示命名空间
  注意 : 请求 路劲: http://localhost:8080/struts2_helloword/命名空间/actionName(action名称) .action

   Extends 继承 struts2核心 包 (核心包  struts-default.xml)

Action 表示 action名称  注意: 这个是请求Url一部分


Class 表示 当前的action类 例如: com.struts.action.HelloWordAction

Result 表示: 要跳转的结果页面
    Result中  name属性  与 HelloWordAction execute() 返回的值相同






如何访问 web-inf/jsp/login.jsp 页面
Struts.xml 文件中配置:
  <action name="login" class="com.opensymphony.xwork2.ActionSupport">
           <result name="success">/WEB-INF/jsp/login.jsp</result>

        </action>
如果没有为action指定class,默认是ActionSupport。而ActionSupportexecute() 方法默认处理就是返回一个success字符串。method属性用于指定action中的那个方法,如果没有指定默认执行action中的execute() 方法



1.获得请求路径的URI,例如url是:

2.首先寻找namespace/path1/path2/path3package,如果存在这个package,则在这个package中寻找名字为testaction,如果不存在这个package则转步骤3
3.寻找namespace/path1/path2package,如果存在这个package,则在这个package中寻找名字为testaction,如果不存在这个package,则转步骤4
4.寻找namespace/path1package,如果存在这个package,则在这个package中寻找名字为testaction,如果仍然不存在这个package,就去默认的namaspacepackage下面去找名字为testaction,如果还是找不到,页面提示找不到action






<Result/>标签

   Name=”success”  默认


type="dispatcher" 等价 request.getRequestDispatcher()
   <result type="dispatcher">/WEB-INF/jsp/message.jsp</result>


type="redirect"  等价  response.sendRedirectr()
<result type="redirect">/WEB-INF/jsp/message.jsp</result>


<!--  重新执行那个 命名空间 下  那个 action -->
<result  type="redirectAction">
             <param name="namespace">/reg</param>
             <param name="actionName">regAction</param>
       </result



  <package name="reg" namespace="/reg" extends="struts-default">

         <action name="regAction"   class="com.struts.hello.action.RegAction">
             <result>/WEB-INF/jsp/message.jsp</result>
          </action>
       </package>



属性注入
<param name="message">message属性注入</param>

类似el表达式  ${message}(获取actionmessage属性值)
<result>/WEB-INF/jsp/message.jsp?abc=${message}</result>




Bbs论坛:



日期: 2012-11-10

Struts2的处理流程:




指定多个配置文件:

在大部分应用里,随着应用规模的增加,系统中Action数量也大量增加,导致struts.xml配置文件变得非常臃肿。为了避免struts.xml文件过于庞大、臃肿,提高struts.xml文件的可读性,我们可以将一个struts.xml配置文件分解成多个配置文件,然后在struts.xml文件中包含其他配置文件。下面的struts.xml通过<include>元素指定多个配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
        <include file="struts-user.xml"/>
        <include file="struts-order.xml"/>
</struts>

通过这种方式,我们就可以将Struts 2Action按模块配置在多个配置文件中。



Action的属性注入值:
public class HelloWorldAction{
        private String savePath;

        public String getSavePath() {
                return savePath;
        }
        public void setSavePath(String savePath) {
                this.savePath = savePath;
        }
       ......
}

<package name="test" namespace="/test" extends="struts-default">
        <action name="helloworld" class="cn.action.HelloWorldAction" >
                <param name="savePath">/images</param>
                <result name="success">/WEB-INF/page/hello.jsp</result>
        </action>
</package>
上面通过<param>节点为actionsavePath属性注入“/images”


动态方法调用:
如果Action中存在多个方法时,我们可以使用!+方法名调用指定方法
通常不建议大家使用动态方法调用,我们可以通过常量struts.enable.DynamicMethodInvocation关闭动态方法调用。
<constant name="struts.enable.DynamicMethodInvocation" value="false"/>


使用通配符定义action:
<package name="test" namespace="/test" extends="struts-default">
        <action name="helloworld_*" class="cn.action.HelloWorldAction" method="{1}">
                <result name="success">/WEB-INF/page/hello.jsp</result>
        </action>
</package>
public class HelloWorldAction{
        private String message;
        ....
        public String execute() throws Exception{
                this.message = "我的第一个struts2应用";
                return "success";
        }

        public String other() throws Exception{
                this.message = "第二个方法";
                return "success";
        }
}

要访问other()方法,可以通过这样的URL访问:/test/helloworld_other.action
全局结果:
当多个action中都使用到了相同result,这时我们应该把result定义为全局结果。
<package ....>
        <global-results>
                <result name="message">/message.jsp</result>
        </global-results>
</package>
定义常量:
struts2按如下搜索顺序:
struts-default.xml
struts-plugin.xml
struts.xml
struts.properties
web.xml


#指定默认编码集,作用于HttpServletRequestsetCharacterEncoding方法 和freemarker velocity的输出
struts.i18n.encoding=utf-8
  #设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭
struts.serve.static.browserCache=false
#struts的配置文件修改后,系统是否自动重新加载该文件,默认值为false(生产环境下使用),开发阶段最好打开
struts.configuration.xml.reload=true

#开发模式下使用,这样可以打印出更详细的错误信息
struts.devMode=true

#该属性设置Struts 2是否支持动态方法调用,该属性的默认值是true。如果需要关闭动态方法调用,则可设置该属性为false
#struts.enable.DynamicMethodInvocation=false

#文件上传 设置文件最大为多少  默认2M
struts.multipart.maxSize=10701096
#该属性指定需要Struts 2处理的请求后缀,该属性的默认值是action,即所有匹配*.action的请求都由Struts2处理。如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开。
struts.action.extension=do,action,go
#spring集成时,指定由spring负责action对象的创建
#struts.objectFactory=spring
#默认的视图主题
struts.ui.theme=simple


日期: 2012-11-12

自定义类型转换器:
action中使用到了时间类型Date,当需要将请求参数注入到date属性时,我们必须定义转换器,否则struts2无法自动完成类型转换。(为了测试 类型转换器 默认情况下 date=2010-01-29 是可以转换的 但是 date=20100129 这就不行 会到页面输出原样值(action从缓存中得到的) 控制台出错)

下面定义了一个针对Date类型的类型转换器:
1.
public class DateTypeConverter extends DefaultTypeConverter {

        /**
         * value 表示  前台提交 表单 name对应的 value
         * 例如 : <input name="date" value="2012-12-12"/>
         * 注意  value是数组
         * toType : 表示  action 属性的类型
         *    private Date date;   java.util.Date
         */
        public Object convertValue(Map<String, Object> context, Object value,
                        Class toType) {

                SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                if(toType==Date.class)// 判断action 中的date属性 是否是 Date类型
                {
                        // request.getParameter("date")   
                //        request.getParameterValue("date")  要兼容 <input type="checkbox"/>
                  Object[] params=        (Object[])value;
                        try {
                                return sdf.parse(params[0].toString());
                        } catch (ParseException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                        }
                }        
                return null;
        }

}

2.将上面的类型转换器注册为局部类型转换器:
Action类所在的包下放置ActionClassName-conversion.properties文件,ActionClassNameAction的类名,后面的-conversion.properties是固定写法,对于本例而言,文件的名称应为HelloWorldAction-conversion.properties 。在properties文件中的内容为:
属性名称=类型转换器的全类名
对于本例而言, HelloWorldAction-conversion.properties文件中的内容为:
date= com.struts2.web.util.DateTypeConvert

3 全局类型转换器
将上面的类型转换器注册为全局类型转换器:
src下放置xwork-conversion.properties文件 。在properties文件中的内容为:
待转换的类型=类型转换器的全类名
对于本例而言, xwork-conversion.properties文件中的内容为:
java.util.Date=com.struts2.web.util.DateTypeConvert
(全局 类型转换器 针对 全部的Action中的时间类型 所以不能 把Action中字段名做为key值 要以时间类型 做为key)




自定义拦截器:
例子: 用户没有登录 不允许 回复帖子

1. 自定义拦截器:
public class PermissionInterceptor implements Interceptor {

        public void destroy() {
                // TODO Auto-generated method stub

        }

        public void init() {
                // TODO Auto-generated method stub

        }

        public String intercept(ActionInvocation invocation) throws Exception {


                User user=  (User) ActionContext.getContext().getSession().get("user");
                if(user==null)
                {
                        return "login";
                }


                return invocation.invoke();// 执行目标方法
        }

}

2. Action 注册拦截器

  <interceptors>
          <!--  注册拦截器 -->
            <interceptor name="permissionInterceptor" class="com.struts.bbs.util.PermissionInterceptor"></interceptor>

          <!--  配置拦截器栈 (注意:系统+自定义) -->
              <interceptor-stack name="permissionStack">
                <interceptor-ref name="permissionInterceptor"></interceptor-ref>
                <interceptor-ref name="defaultStack"></interceptor-ref>
              </interceptor-stack>
          </interceptors>


<action name="toAddReplyAction" class="com.struts.bbs.reply.action.ReplyAction" method="toAddReply">

              <result name="login">login.jsp</result>
              <result>/WEB-INF/jsp/reply_post.jsp</result>
             <interceptor-ref name="permissionStack"></interceptor-ref>
          </action>




输入校验:
1. action 继承 ActionSupport


2. 重写 ActionSupportValidate()

/**
         * 这个方法 是针对 action 所有方法进行校验
         */
        public void validate() {

                if(user!=null)
                {
                          if(user.getUname()==null||user.getUname().trim().equals(""))
                          {
                                  this.addFieldError("userName", "用户名不能为空");

                          }
                          if(user.getUpass()==null|| user.getUpass().trim().equals(""))
                          {
                                  this.addFieldError("password", "密码不能为空");

                          }

                }
        }
校验失败 返回  默认   input试图


如果针对单个 方法进行校验
方法名称 : validate+方法名称(注意方法名称首字母大写)
例如:
public void validateLogin()// 针对login方法进行校验
           {
                     if(user!=null)
                                {
                                          if(user.getUname()==null||user.getUname().trim().equals(""))
                                          {
                                                  this.addFieldError("userName", "用户名不能为空");

                                          }
                                          if(user.getUpass()==null|| user.getUpass().trim().equals(""))
                                          {
                                                  this.addFieldError("password", "密码不能为空");

                                          }

                                }
           }



配置全局资源与输出国际化信息:
Src 下创建:
login_zh_CN.properties
login_en_US.properties
其中baseName是资源文件的基本名,我们可以自定义,但languagecountry必须是java支持的语言和国家。如:
中国大陆: baseName_zh_CN.properties
美国: baseName_en_US.properties
对于中文的属性文件,我们编写好后,应该使用jdk提供的native2ascii命令把文件转换为unicode编码的文件。命令的使用方式如下:
native2ascii  源文件.properties  目标文件.properties
使用上面的资源文件,在struts.xml中使用常量加载全局资源文件如下:
<constant name="struts.custom.i18n.resources" value="login" />
login为资源文件的基本名。
l JSP页面中使用<s:text name=“”/>标签输出国际化信息:
<s:text name=user/>name为属性文件中的key
l Action类中,可以继承ActionSupport,使用getText()方法,该方法的第一个参数用于指定属性文件中的key
l 在表单标签中,通过key属性指定属性文件中的key,如:
<s:textfield name="realname" key="user"/>
国际化包范围资源文件:
在一个大型应用中,整个应用有大量的内容需要实现国际化,我们可以针对不同模块、不同的action来组织国际化文件。
java的包下放置package_language_country.properties资源文件,package为固定写法,处于该包及子包下的action都可以访问该资源。当查找指定key的消息时,系统会先从package资源文件查找,当找不到对应的key时,才会从常量struts.custom.i18n.resources指定的资源文件中寻找。
<s:i18n name="cn/struts2/natives/action/package">
<s:text name="helloWorld"></s:text>
</s:i18n>
国际化—Action范围资源文件:
我们也可以为某个action单独指定资源文件,方法如下:
Action类所在的路径,放置ActionClassName_language_country.properties资源文件,ActionClassNameaction类的简单名称。
当查找指定key的消息时,系统会先从ActionClassName_language_country.properties资源文件查找,如果没有找到对应的key,然后沿着当前包往上查基本名为package 的资源文件,一直找到最顶层包。如果还没有找到对应的key,最后会从常量struts.custom.i18n.resources指定的资源文件中寻找。
例如:
<s:i18n name=cn/struts2/acion/LoginAction>
</s:i18n>
OGNL表达式语言:
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wpsE3AD.tmp.png
注意:
1. 值栈: Action中 属性的值 是放在值栈中
使用 struts标签  不需要加上 #
2 放入 request ,session application
使用 struts标签  需要加上 #



Struts2 标签
Iterarot迭代标签:
  <%

        ArrayList<String> nameList=new ArrayList<String>();
        nameList.add("张三");
        nameList.add("李四");
        nameList.add("王五");
        nameList.add("赵六");
        request.setAttribute("nameList",nameList);

        HashMap<String,String> map=new HashMap<String,String>();
        map.put("userName","张三");
        map.put("age","22");
        map.put("address","武汉市新路村特1");

        request.setAttribute("map",map);
      %>

      迭代集合:<br/>
      <s:iterator var="name" value="#request.nameList" >

        ${name }

      </s:iterator>


      迭代Map集合:
      <s:iterator var="entry" value="#request.map">
        ${entry.key }=${entry.value }<br/>
      </s:iterator>




If 标签:
<%
        request.setAttribute("time",22);
      %>

      <s:property value="#request.time"/>
       <s:if test="#request.time gt 6 and #request.time lt 12">
        上午好
      </s:if>
      <s:elseif test="#request.time gt 12 and #request.time lt 18">
        下午好
      </s:elseif>
      <s:else>
      晚上好
      </s:else>


<s:token />标签:
<s:token />标签防止重复提交,用法如下:
第一步:在表单中加入<s:token />
<s:form action="helloworld_other" method="post" namespace="/test">
  <s:textfield name="person.name"/><s:token/><s:submit/>
  </s:form>
第二步:
<action name="helloworld_*" class="cn.action.HelloWorldAction" method="{1}">
       <interceptor-ref name="defaultStack" />
        <interceptor-ref name="token" />
        <result name="invalid.token">/WEB-INF/page/message.jsp</result>  
        <result>/WEB-INF/page/result.jsp</result>               
</action>
以上配置加入了“token”拦截器和“invalid.token”结果,因为“token”拦截器在会话的token与请求的token不一致时,将会直接返回“invalid.token”结果。

debug状态,控制台出现下面信息,是因为Action中并没有struts.tokenstruts.token.name属性,我们不用关心这个错误:
严重: ParametersInterceptor - [setParameters]: Unexpected Exception caught setting 'struts.token' on 'class xxx: Error setting expression 'struts.token' with value '[Ljava.lang.String;@39f16f'
严重: ParametersInterceptor - [setParameters]: Unexpected Exception caught setting 'struts.token.name'





分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
java无忧网(http://www.javawyw.com),专业提供Java大作业,小作业,课程设计,毕业设计源码,答辩辅导,作业排错,bug修复,专业解答,远程部署运行项目等服务
本网站所有源码,保证能运行!
QQ:1399491757
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回列表 返回顶部