Struts2入门这一篇就够了

前言

这是Strtus的开山篇,主要是引入struts框架...为什么要引入struts,引入struts的好处是什么,以及对Struts2一个简单的入门....

为什么要引入struts?

既然Servlet能够完成的事,我们为啥要用框架呢??

  • 框架帮我们封装了很多常用的功能

    • 把Web带过来的参数自动封装到JavaBean中[以前,我们刚开始学的时候是单个单个来获取参数的,后来我们又使用了BeanUtils写工具方法来帮我们封装]。现在,我们使用了Struts2的话,那么框架内部就能帮我们封装了。
  • 更加灵活[不用把路径等信息写死在程序上],对于路径我们使用配置文件来进行管理,如果目录发生了变化,也不用一个一个去修改每个程序的路径。
  • 每个Servlet中都有doGet和doPost这样的方法,没必要的。我们抽取出来,通过配置文件来把这两个方法替换掉,那么我们的程序就会更加优雅了。

于是乎,struts2就应运而生了。


自定义struts

在正式讲解struts之前,我们来看一下,以我们现在的水平,能够怎么优化它。。

以用户的登陆注册案例来进行说明

传统的用户登陆注册

  • dao
public class UserDao {

    public User login(User user) {

        if ("aaa".equals(user.getUsername()) && "123".equals(user.getPsd())) {

            System.out.println("登陆成功!");
            return user;

        } else {
            System.out.println("登陆失败!");
            return null;
        }
    }

    public void register(User user) {

        System.out.println("注册成功!" + user.getUsername());
    }


}
  • service

public class UserService {

    private UserDao userDao = new UserDao();

    public User longin(User user) {
        return userDao.login(user);
    }

    public void register(User user) {
        userDao.register(user);
    }

}
  • loginServlet

@javax.servlet.annotation.WebServlet(name = "LoginServlet",urlPatterns = "/LoginServlet")
public class LoginServlet extends javax.servlet.http.HttpServlet {
    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

        //得到用户带过来的数据,封装到Bean对象中
        String username = request.getParameter("username");
        String psd = request.getParameter("psd");

        User user = new User();
        user.setPsd(psd);
        user.setUsername(username);

        try {
            //调用Service方法
            UserService userService = new UserService();
            userService.longin(user);

            //登陆成功跳转到首页
            request.getRequestDispatcher("/index.jsp").forward(request, response);

        } catch (Exception e) {
            e.printStackTrace();

            //登陆失败,跳转到相关的提示页面
            request.setAttribute("message","登陆失败了!!!");
            request.getRequestDispatcher("/message.jsp").forward(request, response);
        }

    }

    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

        this.doPost(request, response);

    }
}
  • registerServlet

@javax.servlet.annotation.WebServlet(name = "RegisterServlet",urlPatterns = "/RegisterServlet")
public class RegisterServlet extends javax.servlet.http.HttpServlet {
    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

        //得到用户带过来的数据,封装到Bean对象中
        String username = request.getParameter("username");
        String psd = request.getParameter("psd");

        User user = new User();
        user.setPsd(psd);
        user.setUsername(username);

        try {
            //调用Service方法
            UserService userService = new UserService();
            userService.register(user);

            //注册成功跳转到登陆界面
            request.getRequestDispatcher("/login.jsp").forward(request, response);

            //注册成功,我也可以跳转到首页
            //request.getRequestDispatcher("/index.jsp").forward(request, response);

        } catch (Exception e) {
            e.printStackTrace();

            //注册失败,跳转到相关的提示页面
            request.setAttribute("message","注册失败了!!!");
            request.getRequestDispatcher("/message.jsp").forward(request, response);
        }

    }

    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

        this.doPost(request, response);

    }
}
  • login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>


  <form action="${pageContext.request.contextPath}/LoginServlet" method="post">

    用户名:<input type="text " name="username">
    密码:<input type="password " name="psd">
    <input type="submit" value="登陆">
  </form>
  </body>
</html>
  • register.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>


  <form action="${pageContext.request.contextPath}/RegisterServlet" method="post">

    用户名:<input type="text " name="username">
    密码:<input type="password " name="psd">
    <input type="submit" value="注册">
  </form>
  </body>
</html>

上面的代码已经经过了测试,是可以跑起来的。


①:跳转页面的路径是写死的。我在注册成功了以后,我可以跳转到首页上,也可以跳转到登陆的界面上。如果我要选择其中的一个,就必须修改源代码...

②:一个功能对应一个Servlet,太麻烦了...写了LoginServlet,还要写RegisterServlet....


新型的用户登陆注册

我们会发现,无论什么Servlet上最终还是跳转到相对应的JSP页面的...也就是说,第一和第二步骤【封装数据、调用Service】我们可以封装起来...只要返回uri给Servlet跳转到JSP页面就好了


LoginAction

返回的uri分两种情况:

  • 如果是转发,那么返回的是RequestDispatcher对象
  • 如果是重定向,那么返回的是字符串

/**
 * Created by ozc on 2017/4/26.
 * <p>
 * 一个Action对应一个Servlet,Action负责处理具体的请求
 */
public class LoginAction {


    public Object login(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

        Object uri ;

        //得到用户带过来的数据,封装到Bean对象中
        String username = request.getParameter("username");
        String psd = request.getParameter("psd");

        User user = new User();
        user.setPsd(psd);
        user.setUsername(username);

        try {
            //调用Service方法
            UserService userService = new UserService();
            userService.longin(user);

            //登陆成功跳转到首页
            request.getSession().setAttribute("user", user);

            //跳转到首页的时候需要重定向
            //response.sendRedirect(request.getContextPath() + "/index.jsp");

            //如果是重定向,那么返回的是字符串
            uri = "/index.jsp";
            return uri;

        } catch (Exception e) {
            e.printStackTrace();

            //登陆失败,跳转到相关的提示页面
            request.setAttribute("message","登陆失败了!!!");
            //request.getRequestDispatcher("/message.jsp").forward(request, response);

            //如果是转发,那么返回的是RequestDispatcher对象
            uri = request.getRequestDispatcher("/message.jsp");
            return uri;
        }
    }
}
  • LoginServlet就可以写成这样了:

    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

        //得到LoginAction对象
        LoginAction loginAction = new LoginAction();
        Object uri = loginAction.login(request, response);


        //是重定向
        if (uri instanceof String) {
            response.sendRedirect(request.getContextPath() + uri);
        } else {

            //是转发,强转成是RequestDispatcher对象
            ((RequestDispatcher) uri).forward(request, response);
        }
    }

RegisterAction

  • RegisterAction


/**
 * Created by ozc on 2017/4/26.
 * 
 * 一个Action对应一个Servlet,Action负责处理具体的请求
 */
public class RegisterAction {


    public Object register(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

        Object uri ;

        //得到用户带过来的数据,封装到Bean对象中
        String username = request.getParameter("username");
        String psd = request.getParameter("psd");

        User user = new User();
        user.setPsd(psd);
        user.setUsername(username);

        try {
            //调用Service方法
            UserService userService = new UserService();
            userService.register(user);

            //登陆成功跳转到登陆页面
            uri = request.getRequestDispatcher("/login.jsp");
            return uri;

        } catch (Exception e) {
            e.printStackTrace();

            //注册失败,跳转到相关的提示页面
            request.setAttribute("message","注册失败了!!!");
            //request.getRequestDispatcher("/message.jsp").forward(request, response);

            uri = request.getRequestDispatcher("/message.jsp");
            return uri;
        }
    }
}
  • RegisterServlet

    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

        //得到RegisterAction
        RegisterAction registerAction = new RegisterAction();

        Object uri = registerAction.register(request, response);

        //是重定向
        if (uri instanceof String) {
            response.sendRedirect(request.getContextPath() + uri);
        } else {

            //是转发,强转成是RequestDispatcher对象
            ((RequestDispatcher) uri).forward(request, response);
        }
    }

思考

到目前为止,我们搞了两个Action类来封装Servlet的逻辑代码,我们再次看回Servlet的代码。

这里写图片描述

这里写图片描述

可以很清楚地发现:两个实现不同功能的Servlet仅仅是调用的Action不同....如果是仅仅调用的Action不同【通过反射来调用不同的Action】,那么我们应该想到使用一个Servlet来管理整个项目,也就是说:整个web项目只有一个核心的控制器

问题:

①:我们在之前是直接指明Servlet的映射路径了,现在要ActionServlet处理所有的请求,我们只要定一个规则:只要后缀为.action的,那么都交由核心控制器ActionServlet来控制....

②:现在全部的请求已经交由ActionServlet控制,那怎么知道调用的是哪个Action???我们可以通过请求的uri,比如:http://localhost:8080/login.action,其中login就代表的是调用LoginAction..也就是说login=LoginAction,我们可以通过properties文件来配置..

③:现在我们已经知道了调用的是哪个Action了,但是Action可能不仅仅只有一个方法,我们还要在调用的时候,指定的方法名是什么.这很简单,一般我们都是职责分工明确的,method=login....并且,调用的Action和具体的方法也是有关系的,不可能是孤立存在的。因此,我们的配置文件是不能使用properties的,需要使用XML

④:在调用方法的时候,是返回一个Object的uri的,uri的类型可能是String、也可以能是RequestDispatcher、并且返回的结果可能有几种情况的【可能跳转到首页,也可能跳转到登陆界面】

⑤:Action调用的方法和返回的uri也是是有关系的!.....不同的Action调用不同的方法,返回的uri也是不同的....

⑥:要跳转到哪个页面上,可以通过标识量来识别....比如:success表示成功执行,如果要重定向那么多加个type类型,如果不重定向就没有type类型..路径使用path来表示..因此,在具体的Action中,就不需要返回具体的uri,只要返回一个标识量即可


画一张图来梳理一下思路:

这里写图片描述


XML配置

我们可以写出这样的XML配置,当ActionServlet初始化的时候,读取XML配置文件,就知道调用的是什么Action,Action中的什么方法,以及跳转到哪个页面上了

<?xml version="1.0" encoding="UTF-8" ?>
<mystruts>
    <package>

        <action name="login" className="zhongfucheng.servlet.LoginServlet" method="login">
            <!--是否存在type属性,存在则是重定向,不存在则是转发-->
            <!--result的值表示的就是跳转的路径-->
            <result name="success" type="redirect">/index.jsp</result>
            <result name="fail">/message.jsp</result>

        </action>
        <action name="register" className="zhongfucheng.servlet.RegisterServlet" method="register">
            <!--是否存在type属性,存在则是重定向,不存在则是转发-->
            <!--result的值表示的就是跳转的路径-->
            <result name="success">/message.jsp</result>
            <result name="fail">/message.jsp</result>
        </action>
    </package>

</mystruts>

为了更好地管理这些信息,我们应该使用JavaBean来对它们封装

  • ActionMappingManager-------管理全部的Action
/**
 * Created by ozc on 2017/4/26.
 * 
 * 该类管理着全部的Action
 *
 * 要管理全部的Action,就需要用一个容器来装载这些Action
 *
 * 选择Map集合是最合适的,可以通过key来得到Action,key就是<action name=><action/>中的name属性
 *
 */
public class ActionMappingManager {

    private Map<String, ActionMapping> map = new HashMap<>();
    
    //注意:外界都是通过name来得到对应的Action的,并不会获取得到整个Manager
    public ActionMapping getActionMapping(String name) {
        return map.get(name);
    }

}
  • ActionMapping----表示单个的Action

public class ActionMapping {

    //所有的results
    private Map<String, Results> results;

    //关键字name
    private String name;

    //要调用的Action路径
    private String className;

    //Action中的方法
    private String method;

    public Map<String, Results> getResults() {
        return results;
    }

    public void setResults(Map<String, Results> results) {
        this.results = results;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }
}
  • Results---表示的是结果视图


/**
 * Created by ozc on 2017/4/26.
 *
 * 该类表示的是结果视图
 *
 *
 *
 */
public class Results {

    //方法返回的标识
    private String name;

    //要跳转的方式
    private String type;

    //要跳转的页面
    private String page;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getPage() {
        return page;
    }

    public void setPage(String page) {
        this.page = page;
    }
}

ActionMappingManager读取配置文件

在ActionMappingManager中,应该读取配置文件,然后把信息全部封装到里边去...


/**
 * Created by ozc on 2017/4/26.
 *
 * 该类管理着全部的Action
 *
 * 要管理全部的Action,就需要用一个容器来装载这些Action
 *
 * 选择Map集合是最合适的,可以通过key来得到Action,key就是<action name=><action/>中的name属性
 *
 */
public class ActionMappingManager {
    private Map<String, ActionMapping> allAction ;

    public ActionMappingManager() {
        this.allAction = new HashMap<>();

        //读取配置文件信息
        init();

    }


    public void init() {
        /********通过DOM4J读取配置文件信息*********/

        try {
            //得到解析器
            SAXReader saxReader = new SAXReader();

            //读取在类目录下的mystruts.xml文件
            InputStream stream = ActionMappingManager.class.getClassLoader().getResourceAsStream("mystruts.xml");

            //得到代表XML文件的Document对象
            Document document = saxReader.read(stream);

            //通过XPATH直接得到所有的Action节点
            List list = document.selectNodes("//action");

            //得到每个Action节点
            for (int i = 0; i < list.size(); i++) {
                Element action = (Element) list.get(i);

                //把得到每个Action的节点信息封装到ActionMapping中
                ActionMapping actionMapping = new ActionMapping();

                String name = action.attributeValue("name");
                String method = action.attributeValue("method");
                String className = action.attributeValue("className");
                actionMapping.setName(name);
                actionMapping.setMethod(method);
                actionMapping.setClassName(className);

                //得到action节点下的所有result节点
                List results = action.elements("result");

                //得到每一个result节点
                for (int j = 0; j < results.size(); j++) {
                    Element result = (Element) results.get(j);

                    //把得到每个result节点的信息封装到Results中
                    Results results1 = new Results();

                    //得到节点的信息
                    String name1 = result.attributeValue("name");
                    String type = result.attributeValue("type");
                    String page = result.getText();

                    results1.setName(name1);
                    results1.setType(type);
                    results1.setPage(page);

                    //把result节点添加到ActionMapping的集合中
                    actionMapping.getResults().put(name1, results1);
                }

                //最后把得到每个ActionMapping的信息添加到ActionMappingManager中
                allAction.put(name, actionMapping);

            }



        } catch (DocumentException e) {

            new RuntimeException("初始化的时候出错了!“" + e);
        }
    }

    //注意:外界都是通过name来得到对应的Action的,并不会获取得到整个Manager
    public ActionMapping getActionMapping(String name) {
        return allAction.get(name);
    }
}

ActionServlet

使用init()方法只加载创建一个ActionManagerMapping对象,并设置在Web容器启动了该Servlet就启动


/**
 * Created by ozc on 2017/4/26.
 *
 *
 * Web容器一启动的时候,该类就应该加载了,在web.xml文件中配置onloadStart
 */

public class ActionServlet extends HttpServlet {


    //该对象封装了所有的XML信息
    ActionMappingManager actionMappingManager ;
    @Override
    public void init() throws ServletException {

        //让ActionMappingManager对象只有一个!
        actionMappingManager = new ActionMappingManager();
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        try {
            //得到用户的uri
            String uri = request.getRequestURI();

            //截取uri的关键部分-----截完应该是login
            uri = uri.substring(uri.lastIndexOf("/") + 1, uri.lastIndexOf("."));

            //通过uri得到配置文件中的action信息
            ActionMapping actionMapping = actionMappingManager.getActionMapping(uri);

            //得到action的类名,方法名
            String className = actionMapping.getClassName();
            String method = actionMapping.getMethod();

            //通过反射创建出Action的对象,调用对应的方法
            Class t = Class.forName(className);
            Object o = t.newInstance();

            //注意:这里的参数是接口的class,不是单纯的request的class,单纯的class是实现类
            Method m = t.getMethod(method, HttpServletRequest.class, HttpServletResponse.class);

            //调用方法,得到标记
            String returnFlag = (String) m.invoke(o, request, response);


            //通过标记得到result的具体信息
            Results result = actionMapping.getResults().get(returnFlag);
            String type = result.getType();
            String page = result.getPage();

            //判断是重定向还是转发,为空就是转发,反则是重定向
            if (type == null) {
                response.sendRedirect(page);
            } else {
                request.getRequestDispatcher(request.getContextPath() + page).forward(request, response);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        this.doPost(request, response);

    }
}

具体的Action的方法只要返回一个标识量即可,我们通过标识量来得到具体的跳转页面url和跳转的方法的。。。


效果:

这里写图片描述


自定义MyStruts总结:

由于传统web的Controller模块存在弊端:

  • 一些功能重复使用,代码过于重复了。
  • 跳转的页面写死了。改变需求的时候需要更改源代码

本博文主要模拟Struts的开发流程

  • 使用一个ActionServlet核心控制器来管理全部的Web请求,写XML配置文件,读取配置文件。
  • ActionMapping封装了Action的基本信息,在XML配置文件中就是读取Action的基本信息,封装到JavaBean上,最后使用ActionMapping类的集合统一管理起来。
  • 当用户访问的时候,我们根据url也就是Action的名称反射出对应的类,来对其进行操作
  • 根据XML文件的配置信息来确定跳转方法、跳转的url

我们现在学习的是Struts2,其实Struts1和Struts2在技术上是没有很大的关联的。 Struts2其实基于Web Work框架的,只不过它的推广没有Struts1好,因此就拿着Struts这个名气推出了Struts2框架。

因此,学习Struts2的时候,不了解Struts1是没有任何关系的。

在前面,已经说明了为什么要引入Struts框架,其实就是为了提高开发效率...

Struts2框架预先实现了一些功能:

  • 请求数据自动封装
  • 文件上传的功能
  • 对国际化功能的简化
  • 数据效验功能.......等等

Struts2开发步骤

我们就直接来讲解Struts2的开发步骤是什么吧....在了解它的细节之前,先要把配置环境搭好!

引入jar文件

完整的struts中的jar包有80多个,我们日常开发是不需要那么多个的。一般我们导入的jar包有8个:

  • commons-fileupload-1.2.2.jar 【文件上传相关包】
  • commons-io-2.0.1.jar【文件上传相关包】
  • struts2-core-2.3.4.1.jar 【struts2核心功能包】
  • xwork-core-2.3.4.1.jar 【Xwork核心包】
  • ognl-3.0.5.jar 【Ognl表达式功能支持表】
  • commons-lang3-3.1.jar 【struts对java.lang包的扩展】
  • freemarker-2.3.19.jar 【struts的标签模板库jar文件】
  • javassist-3.11.0.GA.jar 【struts对字节码的处理相关jar】

这里写图片描述


配置web.xml

在web.xml中配置的过滤器,其实就是在为struts进行初始化工作

值得注意的是:如果该web.xml配置了多个fileter,那么struts的filter需要在最后面!


<!-- 引入struts核心过滤器 -->
    <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>

开发Action

开山篇我们已经说了,Servlet的业务代码,我们都使用Action来代替...Action类一般继承着ActionSupport

Action类也叫动作类,处理请求的类。


public class HelloAction extends ActionSupport {

    @Override
    public String execute() throws Exception {

        System.out.println("helloworld");
        
        return "success";
    }
}

至于execute()方法是什么,我们先不要去管它,为啥要返回一个String,我们也不要去管它....只要记住开发步骤,并且,我们的Action类是要继承ActionSupport类的

配置struts.xml

至于配置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="hello" extends="struts-default">
    <action name="hello" class="action.HelloAction" method="execute">
        <result name="success">/index.jsp</result>

    </action>
</package>
</struts>

看完上面的配置文件,是非常像我们开山篇写的struts框架的配置文件的....

效果:

在地址栏中直接输入hello,就跳转到index.jsp页面了。并且,execute()中的语句被执行了...

这里写图片描述


Struts2执行流程

我们来简单地了解一下Struts的执行流程,然后再慢慢对上面的开发步骤的部分进行讲解....

服务器启动

下边我说的都是struts流程的重点:

  • 加载web.xml文件
  • 找到我们配置的filter中的StrutsPrepareAndExecuteFilter
  • StrutsPrepareAndExecuteFilter在里边执行init()方法
  • 一直到Dispatcher dispatcher = init.initDispatcher(config);,初始化dispatcher
  • 在初始化dispatcher的时候加载struts-default.xml和我们配置的struts.xml

下面用GIF图来看看它的执行过程:

这里写图片描述

细心的朋友可能会发现,我们在struts.xml的package节点下,extends了struts-default....那struts-default究竟是什么东西呢?

我们找到它的源码:

这里写图片描述

我们发现了一大堆的Bean,interceptor,result-type,interceptor-stack...下边我来讲解一下它们是干嘛用的...

  • bean指定了struts在运行的时候需要创建的对象类型

    • 在运行struts的时候,可能需要创建一些对象,那么就通过Bean来指定
  • interceptor是struts定义的拦截器,一共有32个

    • 前边已经说了,Struts为我们实现了一些功能,就是通过拦截器来实现的
  • result-type是跳转结果的类型

    • Action业务方法中的返回值,我们发现几个实用的:redirect【重定向】、dispatcher【转发】、redirectAction【重定向到Action资源】、stream【文件下载的时候用】...跳转结果的类型也在这里定义了
  • interceptor-stack是拦截器的栈

    • 拦截器有32个,我们可能会使用很多的拦截器,不可能一个一个来调用,于是提供了拦截器栈...其实可以简单看成文件夹和文件之间的关系
  • default-interceptor-ref是默认执行的拦截器栈
  • default-class-ref class是默认的执行Action类

还要补充的就是:默认的拦截器栈有18个拦截器....


拦截器和过滤器

拦截器和过滤器都是拦截资源的

拦截器只拦截Action请求,是struts的概念...

过滤器拦截web的所有资源,是Servlet的概念...


小总结

服务器启动的时候,其实就是加载了web.xml文件,然后调用init()方法去加载struts.xml和struts-default.xml之类的文件.....

注意:此时的拦截器是还没有被调用的


访问阶段

服务器启动的阶段,仅仅是加载了各种的xml文件...那么当我们访问Action的时候,它的执行流程是怎么的呢?

  • 首先,它会创建我们在struts.xml中配置的Action对象
  • 接着,它会按照默认的顺序执行18个拦截器【也就是调用默认拦截器栈】
  • 最后,它会执行Action的业务方法【也就是execute(),我们在struts.xml文件中配置了什么,就执行什么业务方法】

值得注意的是:每访问Action一次,它就会创建一个对象...它并不是和Servlet一样只有一个对象...因此它是线程安全的.


深入讲解struts.xml

这是我们的struts.xml的内容,相信现在对它也不会太陌生了...


<struts>
<package name="hello" extends="struts-default">
    <action name="hello" class="action.HelloAction" method="execute">
        <result name="success">/index.jsp</result>
    </action>
</package>
</struts>

package

package其实就是包,那包用来干什么?包就是用来管理Action

通常来说,我们都是一个业务模版对应一个package

name

name是包的名字,值得注意的是,包的名称是不能重复的。


extends

extends代表的是当前包继承着哪个包。在struts中,包一定要继承着struts-default


abstract

在package中还有abstract这个属性,使用该属性时:表明当前包被其他的包继承...并且,在package下不能有action,否则会出错!


namespace

在package中还有namespace这个属性---名称空间....它是作为路径的一部分的,默认是"/"


actoin

action:配置请求路径与Action类的映射关系


name

name是请求路径的名字


class

class是处理action类的全名


method

method是调用的方法名称


result

result代表的是Action中业务方法返回的值


name

name是action处理返回的值


type

type是跳转的类型


文本值

文本值是跳转的路径


细节

前边已经说了,一个package应该对应一个业务模块..目的就是把职能细分出来...

struts为了让我们更好地管理xml文件,它还可以这样做:在不同的模块中用不同的xml文件进行描述...

这里写图片描述

最后在struts.xml文件中将其引入即可..


<!--struts在运行的时候总会加载这个文件-->
<!--总配置文件总引入其他的文件-->
<struts>
    <include file="privilegeaction/privilege.xml"/>
    <include file="useraction/hello.xml"/>
</struts>

如果文章有错的地方欢迎指正,大家互相交流。 习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
简介 ecshop系统logo ECShop是上海商派网络科技有限公司(ShopEx)旗下——B2C独立网店系统,适合企业及个人快速构建个性化网上商店。系统是基于PHP语言及MYSQL数据库构架开发的跨平台开源程序。 ECShop悉心听取每一位商家的需求与建议,不仅设计了人性化的网店管理系统帮助商家快速上手,还根据中国人的购物习惯改进了购物流程,实现更好的用户购物体验。 经过近两年的发展,ECShop网店系统无论在产品功能、稳定性、执行效率、负载能力、安全性和SEO支持(搜索引擎优化)等方面都居国内同类产品领先地位,成为国内最流行的购物系统之一。 服务 灵活的模版机制 ECShop开发了独有的高效模板引擎(2.15以前版本使用smarty模板引擎),并结合了Dreamweaver的模板和库功能,使得编辑制作模板变得更简单。 开放的插件机制 支付、配送,会员整合都是以插件形式实现。商家可以随时增加或变更的支付方式和配送体系。ecshop支持大部分php开发的论坛系统,包括discuz,phpwind等,只需在后台做简单参数配置,即可完成会员整合。 功能 AJAX 化 ECSHOP 使用流行的 AJAX 技术,批量数据编辑变得更迅速,方便。 促销功能 ECSHOP提供了积分、红包、赠品,夺宝奇兵等多种促销方法。 高效率的代码和执行性能 通过优化代码与数据库结构,配合ecshop独家设计的缓存机制,在不考虑网速的情况下,网店动态页面与纯静态页面访问速度相当。 常规功能的更完善实现 针对常规功能尤其是后台管理和购物流程,ECShop进行了更简洁的设计,实现更好的用户体验。 搜索引擎优化 在 SEO (搜索引擎优化)上,ECShop独家支持两种 URL 重写方式,并且是同类软件中第一家支持 google / yahoo / microsoft 三家共同发布的 sitemaps 0.9 网站索引规范,能够为站点被搜索引擎收录做到最大限度的支持和帮助。 内置手机短信网关 ECShop内置手机短信网关,支持会员信息,订单提醒等功能。 多语言支持 支持简体,繁体,英文。 源代码开放 用户可根据自己的需求对ECSHOP进行定制,扩展。 随着3G网络的普及,智能手机的大量使用,手机上网的用户越来越多,使手机购物成为可能,手机购物势必会成为一种趋势,ECshop2.7.2版本新增手机浏览html功能。并且新增商品规格分库存功能,方便商家管理不同规格货品的库存。在商品详情页新增购买记录,提高网店的活跃性。html编辑器上传图片后增加水印功能。改进编辑快递单功能,增加可视化编辑,方便管理员修改打印快递单。商品分类页排序按钮变更为更流行的按钮样式,使之更加人性化。上传商品相册图片,使之能够支持外链图片。 历史 ECShop 2005年底,2006年初,高春辉和李梁(时任手机之家总经理),因为在给朋友建网上商城的时候,发现没有一个好用的商城软件,萌生了自己制作一个商城软件的想法。 2006年3月,从零开始招兵买马,组建团队,2006年6月,ECShop推出第一个版本1.0,但因为功能比较单一,最终使用的用户没有超过10个。 2006年6~7月,高春辉开始全面介入ECShop的开发管理工作,大大的加速了ECShop的开发进度,在推出 2.0版本之后,陆续推出了2.0.1,2.1,2.1.1.,2.1.2,2.1.3等版本后,用户群逐步扩大,安装量突破5万。 2007年5~6月,ECShop管理层与康盛世纪接触,最终确定,将ECShop卖给康盛世纪。 2007年6~7月,ECShop完成了一个重要的项目摩托罗拉手机商城。 2007年9月,ECShop团队全部迁至康盛世纪上班,交易完成。 2007年9月,ECShop分为两个团队,ECShop|(买否网), (卖否网);ECMall。 2008年10月10日,ECShop系列软件(包括Ecshop、Ecmall、Maifou等),被上海商派网络科技有限公司(ShopEx)整体收购。 2009年3月,发布2.6.2版本,这是其加入上海商派网络科技有限公司(ShopEx)之后的最新版本。 2010年6月,发布 ECShop v2.7.2 Release 0604。 2012年4月,发布 ECShop v2.7.3 Release 0411。 2012年11月,发布ECShop v2.7.3 Release 1106。 编辑本段 团队介绍 原团队介绍 高春辉 著名第一代互联网人,1989年接触电脑,1997年创建了当时访问量最高的个人主页“ 高春辉的个人网站”,被评为中国十大个人网站第一名。1999年受金山公司邀请,共同发起金山卓越网并担任总经理。2002年创立手机之家。ECShop创始人,ECShop灵魂,主要负
.版本 2 .程序集 程序集1 .程序集变量 图标句柄, 整数型 .程序集变量 hbmAbout, 整数型 .程序集变量 hbmAboutHover, 整数型 .程序集变量 hbmAboutDown, 整数型 .程序集变量 hbmGenerate, 整数型 .程序集变量 hbmGenerateHover, 整数型 .程序集变量 hbmGenerateDown, 整数型 .程序集变量 hbmExit, 整数型 .程序集变量 hbmExitHover, 整数型 .程序集变量 hbmExitDown, 整数型 .程序集变量 prev_proc, 整数型 .程序集变量 bMouseOverGenerateButton, 逻辑型 .程序集变量 bMouseOverAboutButton, 逻辑型 .程序集变量 bMouseOverExitButton, 逻辑型 .程序集变量 rExit, RECT .程序集变量 rAbout, RECT .程序集变量 rGenerate, RECT .程序集变量 rWindow, RECT .程序集变量 hExit, 整数型 .程序集变量 hAbout, 整数型 .程序集变量 hGenerate, 整数型 .程序集变量 hWindow, 整数型 .程序集变量 实例句柄, 整数型 .程序集变量 lf, LOGFONT .程序集变量 hKeygen, 整数型 .程序集变量 hSerial, 整数型 .子程序 _启动子程序, 整数型, , 本子程序在程序启动后最先执行 实例句柄 = GetModuleHandle (0) 图标句柄 = LoadIcon (实例句柄, #FFF_ICON) InitCommonControls () ' 这个是初始化共用控件API,凡是用到月历框,选择夹,XP风格等等扩展组件的,都必须调用这个API ' 这里调用的是资源对话框模板来创建窗口,在易的调试模式下无效 DialogBoxParam (实例句柄, #IDD_KEYGEN, 0, &DlgProc, 0) ' 这个API内部有消息循环泵,直到对话框被关闭才返回 返回 (0) ' 可以根据您的需要返回任意数值 .子程序 DlgProc, 整数型 .参数 hwnd, 整数型 .参数 msg, 整数型 .参数 wparam, 整数型 .参数 lparam, 整数型 .局部变量 点击控件ID, 整数型 .局部变量 lpdis, DRAWITEMSTRUCT .局部变量 hdc, 整数型 .局部变量 hdcMem, 整数型 .局部变量 hFont, 整数型 .局部变量 hFontOld, 整数型 .局部变量 szProgname, 文本型 .局部变量 hdcSerial, 整数型 .局部变量 xmid, 整数型 .判断开始 (msg = #WM_INITDIALOG) ' 初始化对话框 置随机数种子 (取启动时间 ()) ' 因为大鸟的黑月不支持播放MIDI、XM格式的音乐,所以用偶写的DLL播放吧先~~。等大鸟支持了改下就OK了。 xmid = 取随机数 (1, 40) .如果 (xmid > 20) playxm (#XM音乐2, 取字节集长度 (#XM音乐2)) .否则 playxm (#XM音乐1, 取字节集长度 (#XM音乐1)) .如果结束 SendMessage (hwnd, #WM_SETICON, 0, 图标句柄) ' 设置标题栏上的图标 SendMessage (hwnd, #WM_SETICON, 1, 图标句柄) SetWindowText (hwnd, “only test”) AnimateWindow (hwnd, 1000, 524288) hGenerate = GetDlgItem (hwnd, #IDC_GENERATE) hAbout = GetDlgItem (hwnd, #IDC_ABOUT) hExit = GetDlgItem (hwnd, #IDC_EXIT) GetWindowRect (hwnd, rWindow) GetWindowRect (hGenerate, rGenerate) GetWindowRect (hAbout, rAbout)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值