struts2——入门介绍

一、引入

1、servlet中的缺点

  • 一种请求对应一个servlet,代码比较拥挤
  • 在web.xml中,配置比较麻烦,并且不适合团队开发
  • servlet中doGet方法和doPost方法中的两个参数reqeust,response拥有严重的容器依赖性(服务器不启动,程序就无法测试)
  • 如果页面上表单中的元素比较复杂,则在servlet的方法中获取表单元素的数据比较繁琐
  • servlet是单线程的,只要在servlet中的属性中声明一个数据,该数据就是全局数据了,有线程安全问题。
  • 在servlet中处理异常,如果servlet中有5个方法,则这5个方法必须都要try  catch
  • 如果一个servlet中有很多个方法,则必须采用传递参数的形式,分解到每一个方法中。

2、重构

1.基本原理

     在web.xml中,配置一个servlet或者配置一个过滤器(在这里用过滤器),过滤器完成的内容:

        1、过滤.do的所有的请求

        2、利用java的反射机制动态的调用方法

        3、service的方法返回一个jsp,然后利用转发或者重定向到相应的页面

2.具体实现

1.访问

http://localhost:8080/struts2_st1/userService.do?method=insert 

2.分析

     如果采用servlet(userService)方法,需要在doXXX方法中通过判断方法method来调用相应的service方法

public void doPost(request,response){
   if(method.equals("insert")){
      //调用service相应的方法
   }if else(method.equals("update"))
   {}
}

     如果通过反射机制来获取方法需要知道的内容为:方法名称,类的全名称,传递的参数为reqeust,response

3.实现

     首先要配置一个过滤器来拦截.do的url(这里是userService.do)

  <filter>
    <filter-name>servletFilter</filter-name>
    <filter-class>com.shen.web.filter.ServletFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>servletFilter</filter-name>
    <url-pattern>*.do</url-pattern>
  </filter-mapping>

     这里的service为:

public class UserService {
​
    public void insert(HttpServletRequest request,HttpServletResponse response){
        System.out.println("UserService insert");
    }
}

     通过map集合来通过url传递的”userService“ 获取相对应的service(全名)

public class ServletConfig {
    //userService?method=insert key与userService相对应,value为其全名
    public static Map<String,String> serviceMap=new HashMap<String, String>();
    
    static{
        serviceMap.put("userService", "com.shen.service.UserService");
    }
}

     其中过滤器如下:

    @Override
    public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain arg2) throws IOException, ServletException {
        // TODO Auto-generated method stub
​
        /**
         * 1、获取Request,Response,然后通过方法的调用传递到service层
         * 2、获取service的全名和方法名称
         * 3、根据service的方法的名称利用java的反射机制创建service层
         * 4、根据method的invoke方法动态的调用service
         */
        HttpServletRequest request=(HttpServletRequest) res;
        HttpServletResponse response=(HttpServletResponse) req;

        String uri=request.getRequestURI();// :/struts2_st1/userService.do
        String[] strings=uri.split("/");// :userService.do
        String doString=strings[strings.length-1];
        String url=doString.substring(0,doString.indexOf("."));// :userService

        String serviceName=ServletConfig.serviceMap.get(url);//根据userService来获取全名
        String methodName=request.getParameter("method");//获取方法的名称

        try {
            Object obj=Class.forName(serviceName).newInstance();
            Method method=obj.getClass().getMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);
            method.invoke(obj, request,response);//调用该方法
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

4.总结

     如果在UserService中添加一个方法

public class UserService {
    public void insert(HttpServletRequest request,HttpServletResponse response){
        System.out.println("UserService insert");
    }
        public void update(HttpServletRequest request,HttpServletResponse response){
        System.out.println("UserService update");
    }
}

那么访问http://localhost:8080/struts2_st1/userService.do?method=update 即可调用该方法。  

二、入门

1、第一个案例

     新建一个struts2的web工程,其自动生成的web.xml文件如下:

  <!-- 在浏览器中只要发送.action就拦截 -->
  <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>*.action</url-pattern>
  </filter-mapping>

说明:该过滤器过滤所有的.action请求

     现在先写一个HelloWorldAction

public class HelloWorldAction {
​
    public String execute(){
        return "index";
    }
}

     在struts.xml文件中对其进行配置:

<struts>
   <!-- package为包,name为包名(是唯一的)namespace与url相对应 -->
   <package name="helloWorld" namespace="/" extends="struts-default">
      <!-- action是用来描述一个类的,name为名称(与url相对应[即访问该action的url地址,与servlet的映射类似]) -->
      <action name="helloWorldAction" class="com.shen.action.HelloWorldAction">
         <!-- result为结果,name中的内容和当前请求action方法的返回值对应 -->
         <result name="index">index.jsp</result>
      </action>
   </package>
</struts>  

说明:即如果返回值是"index"就执行index.jsp  

   有test.jsp页面:

  <body>
    测试struts2,有命名空间helloWorld<br/>
    <a href="${pageContext.request.contextPath}/helloWorldAction.action">测试</a>
  </body>

注意:该处地址与action对应,点击超链接转发到index页面

2、分析案例

1.struts.xml文件的加载

  • 当tomcat服务器启动的时候,会去classpath下加载struts-default.xml,struts-plugin.xml,struts.xml,并且按照先后顺序进行加载,其中struts-default.xml,struts-plugin.xml文件会在jar包中。
  • 这三个xml文件的dtd约束都一样,数据结构一样
  • 如果在这三个配置文件中,出现了后者和前者一样,那么后者覆盖前者
  • struts2容器与其他框架是以插件的形式结合的,而struts-plugin.xml文件就是结合的入口点,所以将来会有很多个

       struts-plugin.xml

2.包的继承

     现将struts.xml文件改动如下:

   <!-- package为包,name为包名(是唯一的) -->
   <package name="helloWorld" namespace="/" extends="struts-default">
      <!-- action是用来描述一个类的,name为名称(与url相对应[即访问该action的url地址,与servlet的映射类似]) -->
      <action name="helloWorldAction" class="com.shen.action.HelloWorldAction">
         <!-- result为结果,name中的内容和当前请求action方法的返回值对应 -->
         <result name="index">index.jsp</result>
      </action>
   </package>
   <package name="hello" namespace="/base" extends="helloWorld"></package>

说明:即包hello继承helloWorld,此处访问http://localhost:8080/mystruts2/base/helloWorldAction.action (会报错,因为命名空间)时同样可以执行。因为包hello继承于helloWorld,所以helloWorld中的所有功能也被继承过来了(包struts-default是最基础的包)

3.继承ActionSupport类

     现令action继承ActionSupport类:

public class ActionSupportAction extends ActionSupport {
    @Override
    public String execute() throws Exception {
        System.out.println("action support");
        return SUCCESS;
    }
}

其配置如下:

<action name="actionSupportAction" class="com.shen.action.ActionSupportAction">
   <result name="success">index.jsp</result>
</action>

说明:在action中返回的是SUCCESS,在struts2中是"success",是因为在ActionSupport中定义了常量SUCCESS=“success”(还有一些其他常量,如ERROR)。并且在ActionSupport中还实现了Validateable(验证)TextProvider(国际化)等功能。

4.不配class属性

     action标签中的class属性是可以不写的,因为action标签肯定在一个包中,该包继承了struts-defualt,在struts-default包中有这么一段配置:

    <default-class-ref class="com.opensymphony.xwork2.ActionSupport" />

如果在action标签中没有class属性,则默认查找ActionSupport,并且必须返回success

<action name="defaultAction">
   <result name="success">index.jsp</result>
</action>

同样跳转到index.jsp中

5.配置文件的包含

     即一个struts配置文件是可以包含其他的文件的。现除了src下有struts.xml文件,在com.shen.include包下有IncludeAction.java和struts-include.xml。其中struts-include.xml内容如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
   <package name="include" namespace="/" extends="struts-default">
      <action name="includeAction" class="com.shen.include.IncludeAction">
         <result name="success">index.jsp</result>
      </action>
   </package>
</struts>    

则在struts.xml文件要包含struts-include.xml需要:

   <include file="com/shen/include/struts-include.xml"></include>

6.命名空间  

     namespace是package标签中的属性,在写namespace的时候,一定要加上"/",namespace的值要体现在url中:

【<package namespace="/base">】那么在访问一个action的时候,在action前面要加上/base:

   <package name="ns" namespace="/ns" extends="struts-default">
      <action name="nsAction" class="com.shen.action.ns.NameSpaceAction">
         <result name="success">../index.jsp</result>
      </action>
   </package>

说明:在访问http://localhost:8080/struts2_st1/ns/nsAction.action 时action将会被执行,返回结果跳转到index页面时【index.jsp在webroot下】,因为有命名空间ns,故会在webroot下找文件夹ns中的index.jsp,但是并未该文件,所以要在index前面加../(其实改为/index.jsp也行(该“/”代表web根目录),但是不能写为index.jsp)

注意:

1.如果在一个url访问中有好几层命名空间:http://localhost:8080/sturts2/a/b/c/d/AAction.action  在配置文件中如下:

   <package name="ns" namespace="/a/b" extends="struts-default">
      <action name="AAction" class="com.shen.action.ns.NameSpaceAction">
         <result name="success">/index.jsp</result>
      </action>
   </package>

其查找步骤:

             1、会去a/b/c/d下查找有没有相对应的AAction,如果找到,则执行action

             2、如果找不到,则会去a/b/c下查找,如果找到,则执行action

             3、按照这样的查找方法,直到查找到根目录下,如果还没有找到,则报错,没有找到相应的action

显然会在/a/b下找到,并执行NameSpaceAction

7.返回结果

     标签result表示对action在执行方法后返回的结果进行处理,其中name表示返回的值,type表示要对该返回结果的操作类型。其中type的值有:

<result-types>
      <result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
      <result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/>
      <result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>
      <result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/>
      <result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/>
      <result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/>
      <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>
      <result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/>
      <result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/>
      <result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult" />
</result-types>

举例:

对返回结果进行转发:

<!-- name的值默认为success type默认为转发(dispatcher)方法默认为execute方法-->
<result>/index.jsp</result>

对结果进行重定向:

 <!-- 重定向-->
 <result type="redirect">/index.jsp</result>

对结果重定向到action:

<result type="redirectAction">
    <param name="actionName">nsAction</param><!--重定向到的action-->
    <param name="namespace">/ns</param><!--重定向到的action的命名空间-->
    <param name="method">execute</param><!--重定向到的action的执行方法-->
</result> 

此外还有一个方法:

<!-- 方法默认是execute方法 -->
<result type="redirectAction">/ns/nsAction.action</result>

注意:结果集是可以自定义的如果自定义的,结果集需要获取result标签中的内容,则继承抽象类,如果自定义的结果集不需要获取result标签中的内容,则实现接口。自定义结果集的步骤:

  • 写一个类,该类有两种方式:1、实现Result接口   2、继承StrutsResultSupport
  • 在配置文件中
<package name="myresult" namespace="/" extends="struts-default">
    <result-types>
       <result-type name="myresult" class="cn.itheima02.struts2.result.MyDispatcher"></result-type>
    </result-types>
</package>
  •  使用
<package name="testMyResult" namespace="/" extends="myresult">
    <action name="resultAction_*" method="{1}" class="cn.itheima02.struts2.result.ResultAction">
       <result type="myresult" name="aaa">index.jsp</result>
    </action>
 </package>

8.调用的方法

     如果没有配置action执行的方法时默认执行execute,当然也可以自己配置(在PatternAction中有方法pattern):

<action name="patternAction" class="com.shen.action.patter.PatterAction" method="pattern">
    <result>/index.jsp</result>
</action>

除了在文件中配置方法外还可以在url中指定调用哪个方法:http://localhost:8080/struts2_st2/patternAction!pattern.action 也会执行方法 pattern

猜你喜欢

转载自blog.csdn.net/qq_22172133/article/details/83574736