Struts2 自定义MVC框架

一、Model1与Model2:

Model1:就是一种纯jsp开发技术,将业务逻辑代码和视图渲染代码杂糅在一起。

Model2:Model2是在Model1的基础上,将业务逻辑的代码分离开来,单独形成一个Servlet,Model2也是基于MVC开发

二、MVC设计模式:

由3个部分组成,各部分作用如下:

Model:模型,主要用于数据和业务的处理

View:视图,用于数据的显示

Controller:控制器,用于进行流程控制

MVC设计模式的特点:

①一个模型可以对应多个视图

②显示与逻辑控制的分离

③分层控制,减轻了代码间的耦合


自定义MVC框架只需dom4j.jar包即可!

 

 三、准备XML文档Framework.xml

注意点:

<!-- ELEMENT 表示元素 -->
<!-- ATTLIST 表示属性 -->
<!-- CDATA 表示字符串类型 -->
<!-- REQUIRED 表示此属性必须的写 -->
<!-- *代表多个 -->
<!-- IMPLIED 表示此属性可写 -->

复制代码
<!DOCTYPE Framework[
<!ELEMENT Framework (actions)>
<!ELEMENT actions (action*)>
<!ELEMENT action (result*)>

<!ATTLIST action name CDATA #REQUIRED
                 class CDATA #REQUIRED
>


<!ATTLIST RESULT name CDATA #IMPLIED
                 redirect (true|false) "false"
>

]>

<Framework>
<actions>
<action name="loginAction" class="cn.happy.action.LoginAction">
<result name="success">success.jsp</result>
<result name="login">index.jsp</result>
</action>
</actions>
</Framework>
复制代码


四、定义自己的Action接口,用于存放结果集和要执行的方法

复制代码
public interface Action {
    //定义两个静态字符串常量(逻辑视图名)
    public static final String SUCCESS="success";
    public static final String LOGIN="login";
    //定义一个抽象方法execute
    public String execute(HttpServletRequest request,HttpServletResponse response)throws Exception;

}
复制代码

五、定义ActionMapping类用于存放Action节点,即一个ActionMapping类可以视为配置文件中的一个action节点

复制代码
public class ActionMapping {
    //根据action节点中的属性 以及action节点中的<result></result>节点定义三个私有属性
    
    private String name;//action的名称
    private String classname;//action对应程序中的类
    private Map<String,String> results=new HashMap<String,String>();
    
    //向results集合中添加数据的方法
    public void addResult(String name,String value){
        results.put(name, value);
    }

    //根据名称获取的方法
    public String getResults(String name){
        return results.get(name);
    }
    
    public Map<String, String> getResults() {
        return results;
    }
    public void setResults(Map<String, String> 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;
    }
    
复制代码

六、定义ActionMappingManager类用于管理ActionMapping,并通过dom4j解析Framework.xml配置文件。从而获取根节点,以及actions节点,并通过for循环遍历actions节点下的action节点拿到name和class的属性值,由于一个action节点下有多个result节点 及遍历action下所有的result节点,分别存入到actionMapping中的双列集合中,最后得到所有action节点的集合

复制代码
public class ActionMappingManager {
    //actionMapping类的集合
    private Map<String,ActionMapping> maps=new HashMap<String,ActionMapping>();

    public ActionMapping getActionMapping(String name){
        return maps.get(name);
    }
    
    //解析src下所有配置文件
    public ActionMappingManager(String[]files){
        for (String filename : files) {
            init(filename);
        }
    }
    
    //创建初始化方法,使用dom4j解析配置文件
    public void init(String path){
        try {
             //getResourceAsStream取得该资源输入流的引用保证程序可以从正确的位置抽取数据
            InputStream is=this.getClass().getResourceAsStream("/"+path);
            //解析XML
            Document doc=new SAXReader().read(is);
            //获取根节点
            Element root = doc.getRootElement();
            //获取actions节点
             Element actions =(Element)root.elementIterator("actions").next();
             //使用for循环来
             //遍历actions节点下的所有action节点
             for (Iterator<Element> action=actions.elementIterator("action");action.hasNext();) {
                //获取到action节点
                 Element actionnext = action.next();
                //分别获取到action节点中的name属性和class属性
                 String name=actionnext.attributeValue("name");
                 String classname=actionnext.attributeValue("class");
                 //将以上两个属性保存到ActionMapping类中
                 ActionMapping mapp=new ActionMapping();
                 mapp.setClassname(classname);
                 mapp.setName(name);
                 //由于一个action节点下有多个result节点 遍历action下所有的result节点
                 for (Iterator<Element> result=actionnext.elementIterator("result");result.hasNext();){
                     //获取到result节点
                     Element resultnext = result.next();
                     //提取result节点的name属性值和result节点中的值
                     String resultname= resultnext.attributeValue("name");
                    String resultvalue= resultnext.getText();
                     //将其分别存入到actionMapping中的双列集合中去,方便调用actionMapping类(actionMapping类中就有数据了!)
                    mapp.addResult(resultname, resultvalue);
                 }
                //得到所有action节点的集合
                 maps.put(mapp.getName(), mapp);
             }
        
        } catch (Exception e) {
            
        }
    }
复制代码

七、使用反射机制根据字符串类型的类名获取到具体的类--ActionManager

复制代码
public class ActionManager {

    public static Action getActionClass(String classname){
        Class clazz=null;
        Action action=null;
        //获取当前线程的加载类
        try {
            clazz=Thread.currentThread().getContextClassLoader().loadClass(classname);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        
        if(clazz==null){
            try {
                //如果该线程中没有,那么使用class.forname方法获取
                clazz=Class.forName(classname);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        
        if(action==null){
            //将获取到的类型转换为action,调用无参构造函数,某种程度上相当于new,不过new需要指定类型
            try {
                action =(Action)clazz.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return action;
    }
复制代码

八、定义Servlet类,详情见注释!注意点在web.xml中添加 <load-on-startup>节点,让程序一开始就初始化servlet

 

 

复制代码
public class MyServlet extends HttpServlet {

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

    ActionMappingManager man=null;
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
          //获取到ActionMapping对象
        ActionMapping actionMapping=man.getActionMapping(getname(request));
        //获取action接口利用反射机制
        Action action = ActionManager.getActionClass(actionMapping.getClassname());
        try {
            String message=action.execute(request, response);
            String results=actionMapping.getResults(message);
            response.sendRedirect(results);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
        //获取请求路径名
        public String getname(HttpServletRequest request)
        {
            //项目+请求地址
            String requestURI =request.getRequestURI();
            //项目名称
            String contextPath=request.getContextPath();
            //具体的请求
            String path=requestURI.substring(contextPath.length());
            String filename=path.substring(1,path.lastIndexOf(".")).trim();
            return filename;
        
        }
    
    //重写servlet的init方法,让程序一开始就初始化servlet
    //由于一个项目src根目录下有可能有多个配置文件,不止一个,所以逐个解析
        
    @Override
    public void init(ServletConfig config) throws ServletException {
        
        //初始化参数信息
        String filename = config.getInitParameter("config");
        String [] filenames=null;
        
        if(filename==null){
            //如果没有别的参数信息,就将已经配好的放入数组中
            filenames=new String[]{"Framework.xml"};
        }
        else{
            //拆分配置文件名称字符串
            filenames=filename.split(",");
        }
        //使用init方法初始化
        man=new ActionMappingManager(filenames);
    }
复制代码

 


九、业务逻辑Action并实现Action接口,并重写自定义的execute方法

复制代码
public class LoginAction implements Action{

    public String execute(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        String name=request.getParameter("name");
        String pwd=request.getParameter("pwd");
        if(name.equals("1")&&pwd.equals("1")){
            return SUCCESS;
        }
        else{
            return LOGIN;
        }
    }
复制代码

十、编写登录界面

复制代码
  <body>
     <form action="loginAction.action" method="post">
    姓名:<input type="text" name="name"/><br/>
    密码:<input type="text" name="pwd"/><br/>
    <input type="submit" value="登录">
    </form>
  </body>
复制代码

 

 实现效果:

posted @ 2016-10-23 11:21  Monodrama  阅读(238)  评论(0编辑  收藏  举报