学习目标:

1、掌握并理解自定义的三层架构

学习过程:

要实现上面这个MVC框架,我们需要新建立一个项目,在这个项目里,我们已经实现了dao层的框架,数据库自己根据jdbc.properties建立一个。项目源码下载:

一、建立中转站——核心的servlet类。现在我们建立一个包com.mvc,在这个包下面建立一个ActionServlet。

public class ActionServlet extends HttpServlet {
    // 初始化方法
    public void init() throws ServletException {

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

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        doGet(request, response);// 调用doget方法
    }
}

由于这个servlet将会拦截所有需要进入后台控制器(我们现在成为Action类),这里我们约定所有的Action的url访问路径的后缀名是do,当然你也可以约定其他的。所以在web.xml的配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <display-name></display-name>

    <servlet>
        <servlet-name>ActionServlet</servlet-name>
        <servlet-class>com.mvc.ActionServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>ActionServlet</servlet-name>
        <!-- 凡是以.do后缀名才拦截 -->
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

二、设计配置文件。我们需要一个配置文件沟通url、action控制类和执行方法的文件,一般配置文件我们会使用xml进行配置,我们在src目录下建立一个actions.xml文件。文件的内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<actions>
    <action url="listtypes" clz="com.action.GoodsTypesAction" method="listGoodsTypes"></action>
</actions>

三、解析xml。接下来我们需要解析这个xml并把信息保存在服务器的内容中,为了保证运行效率,这个xml只会解析一次,所以我们在核心类ActionServlet的初始化方法中解析。为了解析后能保存,我们在com.mvc包中设计一个Action类与xml对应。

public class Action {

    private String url;
    private String clz;
    private String method;
    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getClz() {
        return clz;
    }

    public void setClz(String clz) {
        this.clz = clz;
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }
}

在类ActionServlet中解析actions.xml,解析xml我们之前讲过有多种方式,这里我们使用dom4j,所以首先,我们需要先导入dom4j包。然后修改ActionServlet代码如下:

public class ActionServlet extends HttpServlet {
    Map<String, Action> actions = new HashMap<String, Action>();//记录配置文件信息
    public void init() throws ServletException {
        // 读取所有的配置信息
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(this.getClass().getClassLoader()
                    .getResourceAsStream("actions.xml"));
            Element rootElement = document.getRootElement();
            List<Element> actionElements = rootElement.elements("action");
            for (Element actionElement : actionElements) {
                Action action = new Action();
                String url = actionElement.attributeValue("url");
                String clz = actionElement.attributeValue("clz");
                String method = actionElement.attributeValue("method");

                action.setUrl(url);
                action.setClz(clz);
                action.setMethod(method);
                actions.put(url, action);
            }
        } catch (DocumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

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

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);// 调用doget方法
    }
}

四、反射执行action的方法。接下来我们可以使用反射的技术调用Action的方法就行了。因为所有Action都必须有request和response这个两个变量,所以这里我们就在com.mvc包下设计一个BaseAction类。代码如下:

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public abstract class BaseAction {
    protected HttpServletRequest request;
    protected HttpServletResponse response;
    public void setRequest(HttpServletRequest request) {
        this.request = request;
    }

    public void setResponse(HttpServletResponse response) {
        this.response = response;
    }
}

同时修改ActionServlet的goGet方法,代码如下:

public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    // 1、获得用户的url
    String url = request.getServletPath();
    url = url.substring(1, url.lastIndexOf("."));

    // 2、根据url从配置文件获得对应Action和method
    Action action = actions.get(url);

    // 3、执行Action和method
    try {
        Class clazz = Class.forName(action.getClz());
        BaseAction baseAction = (BaseAction) clazz.newInstance();
        baseAction.setRequest(request);
        baseAction.setResponse(response);

        Method method = clazz.getDeclaredMethod(action.getMethod());
        // 4、根据返回值跳去其他页面
        method.invoke(baseAction);

    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

五、完成跳转。下面我们还差跳转这一步。我们在com.mvc包中专门设计一个跳转类ActionForward。同时约定所有的Action类的所有的方法都必须要返回ActionForward类型。代码如下:

/**
 * 跳转
 */
public class ActionForward {
    //true 重定向  false 转发
    private boolean isRedirect;//
    private String path;
    public ActionForward(boolean isRedirect,String path){
        this.isRedirect=isRedirect;
        this.path=path;
    }

    public boolean getRedirect() {
        return isRedirect;
    }

    public String getPath() {
        return path;
    }
}

再次修改ActionServlet的doGet方法。

//4、根据返回值跳去其他页面
    ActionForward actionForward = (ActionForward) method
                    .invoke(baseAction);
    if (actionForward.getRedirect()) {
        // 重定向
        response.sendRedirect(actionForward.getPath());
    } else {
        // 转发
        request.getRequestDispatcher(actionForward.getPath()).forward(request, response);
    }

六、建立action类。好,大功告成了,现在我们可以测试一下我们这个mvc框架了。新建一个GoodsTypesAction类,必须继承BaseAction类。然后写一个listGoodsTypes方法,这个方法返回值必须是ActionForward。GoodsTypesAction的信息应该和上面的actions.xml的文件信息相对应。代码如下:

/**
 * 控制层
 * 
 * @author Administrator
 *
 */
public class GoodsTypesAction  extends BaseAction{
    private GoodsTypesDao goodsTypesDao=new GoodsTypesDao();
    // 遍历商品类别
    public ActionForward listGoodsTypes() {
        // 1、获得页面的输入
        String abc=request.getParameter("abc");
        System.out.println(abc);
        // 2、调用业务逻辑
        List<GoodsTypes> types=goodsTypesDao.getAllTypes();
        request.setAttribute("goodsTypeses", types);

        // 3、返回数据
        ActionForward actionForward=new ActionForward(false, "goodstypeslist.jsp");
        return actionForward;
    }
}

在index.jsp中添加一个超链接<a href="listtypes.do?abc=liu">商品的类别</a>,代码如下:

!-- 这个url对应actions.xml的url -->
<a href="listtypes.do?abc=liu">商品的类别</a>

七、部署和测试项目。在主页上面点击这个超链接,查看后台能否打印abc的信息,同时转发到goodstypeslist.jsp页面。如果没有意外应该可以跳转成功。