第一章 自定义MVC框架

第一章  自定义MVC框架
1.1 MVC模式设计
    组成;Model:模型,用于数据和业务的处理
          View :视图,用于数据的显示
          Controller:控制器,用于进行流程控制
    特点:1.一个模型可以对应多个视图
          2.显示与逻辑控制的分离
          3.分层控制,减低了代码间的耦合
1.2 DTD验证XML文档
        声明:<!DOCTYPE 根元素 [定义内容]>
            例:<!DOCTYPE poem [
                    <!ELEMENT poem (author,title,content)>
                    <!ELEMENT author (#PCDATA)>
                    <!ELEMENT title (#PCDATA)>
                    <!ELEMENT content (#PCDATA)>
                ]>
                <peom>
                    <author>王维</author>
                    <title>鹿柴</title>
                    <content>空山不见人,但闻人语声。返景入深林,复照青苔上</content>
                </peom>
        使用外部DTD验证XML
                myStruts.dtd:
                <!ELEMENT poems (poem*)>
                    <!ELEMENT poem (title,author,year,content)>
                    <!ELEMENT title (#PCDATA)>
                    <!ELEMENT author (#PCDATA)>
                    <!ELEMENT year (#PCDATA)>
                    <!ELEMENT content (#PCDATA)>
                    
                myMvc.xml:
                <!DOCTYPE poems SYSTEM "myStruts.dtd">
                <poems>
                    <poem>
                        <title>春晓</title>
                        <author>孟浩然</author>
                        <content>春眠不觉晓......</content>
                    </poem>
                </poems>
        DTD元素
            <!ELEMENT name CONTENT>
            ELEMENT:关键字
            name:元素名称
            CONTENT:元素类型
                      #PCDATA:任何字符数据,不能在其中包含任何子元素
                      纯元素类型:只包含子元素,且这些子元素外没有文本
            符号:():表示分成几组
                   | :必须选其一
                   ,:按顺序出现
                   * :可以出现0到多次
                   ?:可出现也可不出现,出现且只有一次
                   + :必须出现,且可以出现多次
        DTD属性
            <!ATTLIST 元素名称  属性名称  属性类型  属性默认值>
            属性类型描述:
                        CDATA:字符数据
                        ID:唯一ID
                        IDREFS:另一个ID
                        ENTITY:实体
                        ENTITIES:实体列表
            属性值描述:
                        #REQUIRED:属性值是必须的
                        #IMPLIED:属性值不是必须的
                        #FIXED:属性值是固定的
                        例:<!DOCTYPE mystruts[
                            <!ELEMENT mystruts (actions)>
                            <!ELEMENT actions (action*)>
                            <!ELEMENT action (result*)>
                            <!ATTLIST auction
                                name CDATA #REQUIRED
                                CLASS CDATA #REQUIRED>
                            <!ATTLIST result
                                name CDATA #IMPLIED
                                redirect (true|false) "false">
                        ]>
                        <mystruts>
                            <actions>
                                <action name="register" class="cn.jbit.action.RegisterAction">
                                    <result name="success">page/login.jsp</result>
                                    <result name="input">page/register.jsp</result>
                                </action>
                                <action name="login" class="cn.jbit.mvc.LoginAction">
                                    <result name="success">page/guanli.jsp</result>
                                    <result name="input">page/login.jsp</result>
                                </action>
                            </actions>
                        </mystruts>
1.3 XML文档解析

        获取root节点     ELement root
        1、获取节点名称  root.getName()
        2、获取节点属性  root.attribute("dname")
        3、获取节点中的text  root.getText()
        4、获取子节点
        
        使用DOM4J操作XML数据(如:dom4j-1.6.1.jar)
        例:student.xml:
                <?xml version="1.0" encoding="gb2312"?>
                <students>
                    <student age="31"><!-- 如果没有固定的age 默认为20  -->
                        <name>崔卫兵</name>
                        <college>pc学院</college>
                        <telephone>6234666</telephone>
                        <notes>男,1985年出生,硕士</notes>
                    </student>
                    <student>
                        <name>张洪泽</name>
                        <!-- 如果没有固定的leader 默认为leader  -->
                        <college leader="Leader">pc学院</college>
                        <telephone>6238888</telephone>
                        <notes>男,1987年出生,硕士</notes>
                    </student>
                </students>
            Dom4jReadExmple.java:
                public class Dom4jReadExmple {
                    public void iterateWholeXML(String filename,HashMap<String,String> hm){
                        SAXReader saxReader=new SAXReader();
                        try {
                            Document document=saxReader.read(new File(filename));
                            Element root=document.getRootElement();
                            int num=-1;//记录学生编号的变量
                            //遍历根元素(students)的所有子节点(student)
                            for(Iterator iter=root.elementIterator();iter.hasNext();){
                                Element element=(Element) iter.next();
                                num++;
                                //获取person节点的age属性
                                Attribute ageAttribute=element.attribute("age");
                                if(ageAttribute!=null){
                                    String age=ageAttribute.getValue();
                                    if(age!=null && !age.equals("")){
                                        hm.put(element.getName()+"-"+ageAttribute.getName()+num, age);
                                    }else{
                                        hm.put(element.getName()+"-"+ageAttribute.getName()+num, "20");
                                    }
                                }else{
                                    hm.put(element.getName()+"-age"+num, "20");
                                }
                                //遍历student节点下的所有子节点(name,college,telephone,notes)
                                for(Iterator iterInner=element.elementIterator();iterInner.hasNext();){
                                    Element elementInner=(Element) iterInner.next();
                                    if(elementInner.getName().equals("college")){
                                        hm.put(elementInner.getName()+num,elementInner.getText());
                                        //获取college节点的leader属性
                                        Attribute leaderAttr=elementInner.attribute("leader");
                                        if(leaderAttr!=null){
                                            String leader=leaderAttr.getValue();
                                            if(leader!=null && !leader.equals("")){
                                                hm.put(elementInner.getName()+"-"+leaderAttr.getName()+num,leader);
                                            }else{
                                                hm.put(elementInner.getName()+"-"+leaderAttr.getName()+num,"leader");
                                            }
                                        }else{
                                            hm.put(elementInner.getName()+"-leader"+num, "leader");
                                        }
                                    }else{
                                        hm.put(elementInner.getName()+num, elementInner.getText());
                                    }
                                }
                            }
                        } catch (DocumentException e) {
                            // TODO: handle exception
                            e.printStackTrace();
                        }
                    }
                }
            TestDom4jReadExmple.java:
                    public class TestDom4jReadExmple {
                    public static void main(String[] args) {
                        try {
                            //获取解析后的解析信息
                            HashMap<String, String> hashMap;
                            Dom4jReadExmple dre=new Dom4jReadExmple();
                            //遍历xml文件
                            hashMap=new HashMap<String, String>();
                            String n=System.getProperty("user.dir");
                            //获取xml文件
                            dre.iterateWholeXML(n+"\\src\\cn\\jbit\\action\\Student.xml", hashMap);
                            for (int i = 0; i < hashMap.size(); i++) {
                                int j=i/6;
                                System.out.print(hashMap.get("name"+j)+"\t");
                                System.out.print(hashMap.get("student-age"+j)+"\t");
                                System.out.print(hashMap.get("college"+j)+"\t");
                                System.out.print(hashMap.get("college-leader"+j)+"\t");
                                System.out.print(hashMap.get("telephone"+j)+"\t");
                                System.out.println(hashMap.get("notes"+j)+"\t");
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    }
        输出结果:崔卫兵    31    pc学院    leader    6234666    男,1985年出生,硕士    
                  张洪泽    20    pc学院    Leader    6238888    男,1987年出生,硕士
                
        关键操作如下:
            1、Document对象相关
                SAXReader saxReader=new SAXReader();
                Document document=saxReader.read(new File("index.xml"));
            2、节点相关    
                1、获取文档的根节点
                    Element root=document.getRootElement();
                2、获取某节点的单个子节点
                    Element meberElm=root.element("Member");
                3、取得节点的文字
                    String text=MemberElm.getText();
                4、取得某节点下名为:Member的所有子节点并进行遍历
                    List nodes=rootElm.elements("Member");
                5、对某节点下的所有子节点进行遍历
                    for(Iterator iterInner=element.elementIterator();iterInner.hasNext();){
                        Element elementInner=(Element) iterInner.next();
                        //...
                    }
                6、在某节点下添加子节点
                    Element ageElm=newMemberElm.addElement("age");
                7、设置节点文字
                    ageElm.setText("19");
                8、删除某节点
                    parentElm.remove(childElm);//childElm是待删除的节点,parentElm是父节点
                9、添加一个CDATA节点
                    Element contentElm=infoElm.addElement(content);
                    contentElm.addCDATA(diary.getContent());
                    contentElm.getText();
                    contentElm.clearContent();
            3、属性相关
                1、取得某节点下的属性
                    Element root=document.getRootElement();
                    Attribute ageAttribute=root.attribute("age");
                2、取得属性的文字
                    String text=ageAttribute.getText();
                3、遍历某节点的所有属性
                    Element root=document.getRootElement();
                    for(Iterator it=root.elementIterator();it.hasNext();){
                        Attribute attribute=(Attrinute) it.next();
                        String text=ageAttribute.getText();
                        System.out.print(text);
                    }
                4、设置某节点的属性和文字
                    newMemberElm.addAttribute("name","sitinspring');
                5、设置属性的文字
                    Attribute attribute=root.attribute("age");
                    attribute.setText("sitinspring");
1.4 反射机制
        反射的3个动态性质
            1.运行时伸出对象实例
            2.运行期间调用对象
            3.运行时更改对象
            
        反射常用API
            Class类:反射核心类
            Field类:类的属性
            Method类:类的方法
            Constructor类:类的构造方法
            
        使用反射的步骤
            1、导入jar包
            2、获得需要操作的类的java.lang.CLass对象
            3、调用Class的方法获取Field、Method等对象
            4、使用反射API进行操作
            
        反射的应用
            1、获取Class对象
                例;
                Class clazz=Class.forName("java.lang.String");//正确
                Class clazz=Class.forName("String");//错误
            2、从Class对象获取信息
                访问类信息的常用方法
                    Constructor[] getConstructors()//返回所表示的类的public构造方法
                    Constructor[] getDeclaredConstructors()//返回所表示的类的构造方法
                    Method [] getMethods()//返回所表示的类的public方法
                    Method [] getDeclaredMethods()//返回所表示的类的全部方法
                    Field[] getFields()//返回所表示的类的public属性
                    field[] getDeclaredFields()//返回所表示的类的全部属性
                    Object get(Object obj)//得到引用类属性值
                    void set(Object obj,Object val)//将Obj对象的属性设置val值,针对引用类型
                    Object invoke(Object obj,Object args)//调用类的方法obj是执行方法的对象,args是执行方法时传入的参数
            3、创建对象
                newInstance():
                例:Object retBean=defaultCtor.newInstance();
1.5 构建基于MVC模式的框架(Controller为MVC的核心)                
        1.5.1、Controller的设计
            1、定义Action接口
                public interface Action {
                    public String execute(HttpServletRequest request,HttpServletResponse response)throws Exception;
                }
                实现接口:
                public class LoginAction implements Action {
                    @Override
                    public String execute(HttpServletRequest request,
                            HttpServletResponse response) throws Exception {
                        String name=request.getParameter("name");
                        String password=request.getParameter("password");
                        //业务处理                        
                        UserBiz userBiz=new UserBizImpl();
                        User user=userBiz.login(name,password);                    
                        //判断是否登录成功
                        if(user==null){
                            request.setAttribute("message","用户名或密码错误!");
                            return "/page/login.jsp";
                        }else{
                            request.getSession().setAttribute("login", user);
                            return "/page/guanli.jsp";
                        }                        
                        return null;
                    }
                }
            2、实现Controller类
                public class ActionFilter implements Filter {
                    private FilterConfig config;
                    private ActionMappingManager mappingManager;
                    @Override
                    public void destroy() {
                    }

                    @Override
                    public void doFilter(ServletRequest request, ServletResponse response,
                            FilterChain chain) throws IOException, ServletException {
                        //将请求装换成HttpServletRequest
                        HttpServletRequest hsr=(HttpServletRequest) request;
                        HttpServletResponse hsp=(HttpServletResponse) response;
                        //调用Action的execute方法
                        
                         Action action=this.getAction(hsr);
                         String resultView=null;
                        try {
                            resultView=action.execute(hsr, hsp);
                        } catch (Exception e) {
                            // TODO: handle exception
                            e.printStackTrace();
                        }
                        //页面跳转
                        if(resultView!=null){
                            request.getRequestDispatcher(resultView).forward(request, response);
                        }
                    }

                    @Override
                    public void init(FilterConfig conf) throws ServletException {
                        this.config=conf;
                        String conStr=config.getInitParameter("config");
                        //可包含多个配置文件
                        String[] configFiles=null;
                        if(conStr==null||conStr.isEmpty()){
                            configFiles=new String[]{"myMvc.xml"};
                        }else{
                            //拆分配置文件名称字符串
                            configFiles=conStr.split(",");
                        }
                        this.mappingManager=new ActionMappingManager(configFiles);
                    }
                    private Action getAction(HttpServletRequest request) {
                        //获取请求的uri
                        String uri = request.getRequestURI();
                        //获取上下文路径
                        String contextPath=request.getContextPath();
                        //截取上下文路劲后面的部分
                        String actionPath=uri.substring(contextPath.length());
                        //获取Action名称
                        String actionName=actionPath.substring(1,actionPath.lastIndexOf(".")).trim();
                        Action action=null;
                        //添加新功能时在这里添加
                        if("login".equals(actionName)){
                            action=new LoginAction();
                        }
                        return null;
                    }
                }
        web.xml配置:
            <?xml version="1.0" encoding="UTF-8"?>
            <web-app version="3.0"
                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_3_0.xsd">
              <display-name></display-name>    
              <welcome-file-list>
                <welcome-file>login.jsp</welcome-file>
              </welcome-file-list>
              <filter>
                <filter-name>requestFilter</filter-name>
                <filter-class>cn.jbit.mvc.ActionFIlter</filter-class>
              </filter>
              <filter-mapping>
                <filter-name>requestFilter</filter-name>
                <url-pattern>*.action</url-pattern>
              </filter-mapping>
            </web-app>
1.6 升级Controller控制器
        1、配置文件
            myStruts.xml
            <?xml version="1.0" encoding="UTF-8"?>
                <!DOCTYPE mystruts[
                    <!ELEMENT mystruts (actions)>
                    <!ELEMENT actions (action*)>
                    <!ELEMENT action (result*)>
                    <!ATTLIST auction
                        name CDATA #REQUIRED
                        CLASS CDATA #REQUIRED>
                    <!ATTLIST result
                        name CDATA #IMPLIED
                        redirect (true|false) "false">
                ]>
                <mystruts>
                    <actions>
                        <action name="register" class="cn.jbit.action.RegisterAction">
                            <result name="success">page/login.jsp</result>
                            <result name="input">page/register.jsp</result>
                        </action>
                        <action name="login" class="cn.jbit.mvc.LoginAction">
                            <result name="success">page/guanli.jsp</result>
                            <result name="input">page/login.jsp</result>
                        </action>
                    </actions>
                </mystruts>
            2、保存Action信息
                public class ActionMapping {
                    //action元素的name属性
                    private String name;
                    //action元素的className属性
                    private String className;
                    //保存配置爱的result属性信息
                    private Map<String, String > resultMap=new HashMap<String, String>();
                    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 Map<String, String> getResultMap() {
                        return resultMap;
                    }
                    public void setResultMap(Map<String, String> resultMap) {
                        this.resultMap = resultMap;
                    }
                    /*
                     * 根据result-name返回Result实例
                     */
                    public String getResult(String name,String result){
                        return resultMap.get(name);
                    }
                    public String getResult(String name){
                        return resultMap.get(name);
                    }
                    /*
                     * 向Map中添加一个View
                     */
                    public void addResult(String name,String result){
                        this.resultMap.put(name, result);
                    }
                }
            3、读取配置文件
                public class ActionMappingManager {
                    //保存所有Action的ActionMapping
                    private static Map<String,ActionMapping> actionMappings=new HashMap<String, ActionMapping>();
                    /**
                     * init方法用来加载Action配置文件
                     * @param configureFileName 配置文件名
                     */
                    public void init(String configureFileName){
                        try {
                            if(configureFileName==null || configureFileName.isEmpty()){
                                throw new Exception("ConfigureFileName为空");
                            }
                            InputStream is=this.getClass().getResourceAsStream("/"+configureFileName);
                            Document doc=new SAXReader().read(is);
                            Element root=doc.getRootElement();
                            Iterator<Element> actionsIt=root.elements("actions").iterator();
                            Element actions =actionsIt.next();
                            for(Iterator<Element> actionIt=actions.elementIterator("action");actionIt.hasNext();){
                                Element action=actionIt.next();
                                ActionMapping mapping=new ActionMapping();
                                mapping.setName(action.attributeValue("name"));
                                mapping.setClassName(action.attributeValue("class"));
                                for(Iterator<Element> resultIt=action.elementIterator("result");resultIt.hasNext();){
                                    Element resultElement=resultIt.next();
                                    String name=resultElement.attributeValue("name");
                                    String result=resultElement.getText();
                                    if(name==null || "".equals(name)){
                                        name="success";
                                    }
                                    mapping.addResult(name, result);
                                }
                                actionMappings.put(mapping.getName(), mapping);
                            }
                        } catch (Exception e) {
                            // TODO: handle exception
                            e.printStackTrace();
                        }
                    }
                    /**
                     * 加载Action配置文件
                     * @param configureFileNames 配置文件名的数组
                     */
                    public ActionMappingManager(String[] configureFileNames){
                        for(String configureFileName:configureFileNames){
                            init(configureFileName);
                        }
                    }
                    /**
                     * 根据actionName查询对应的ActionMapping实例
                     * @param actionName
                     * @return
                     * @throws Exception
                     */
                    public ActionMapping getActionMappingByName(String actionName)throws Exception{
                        if(actionName==null || actionName.isEmpty()){
                            return null;
                        }
                        
                        ActionMapping mapping=this.actionMappings.get(actionName);
                        if(mapping==null){
                            throw new Exception("mapping为空:["+actionName+"]");
                        }
                        return mapping;
                    }
                }
            4、反射生成Action
                public class ActionManager {
                    public static Action createAction(String className)throws Exception{
                        try {
                            return (Action)loadClass(className).newInstance();
                        }catch (ClassNotFoundException e) {
                                e.printStackTrace();
                        }catch (InstantiationException e) {
                            e.printStackTrace();
                        }catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                        return null;
                    }

                    private static Class loadClass(String className) throws ClassNotFoundException {
                        Class clazz=null;
                        clazz=Class.forName(className);
                        return clazz;
                    }
                }
            5、完善Controller
                web.xml:
                <filter>
                    <display-name>requestFilter</display-name>
                    <filter-name>requestFilter</filter-name>
                    <filter-class>cn.jbit.mvc.ActionFIlter</filter-class>
                    <init-param>
                        <param-name>config</param-name>
                        <param-value>myMvc.xml</param-value>
                    </init-param>
                  </filter>
            ActionFilter.java修改:    
                    public class ActionFilter implements Filter {
                        private FilterConfig config;
                        private ActionMappingManager mappingManager;
                        @Override
                        public void destroy() {
                        }

                        @Override
                        public void doFilter(ServletRequest request, ServletResponse response,
                                FilterChain chain) throws IOException, ServletException {
                            //将请求装换成HttpServletRequest
                            HttpServletRequest hsr=(HttpServletRequest) request;
                            HttpServletResponse hsp=(HttpServletResponse) response;
                            try {
                                ActionMapping mapping=this.getActionMapping(hsr);
                                Action action=ActionManager.createAction(mapping.getName());
                                //得到结果的逻辑名
                                String resultName=action.execute(hsr, hsp);
                                //根据逻辑名返回实际跳转的视图名,也就是跳转的路径
                                String result=mapping.getResult(resultName);
                                if(result==null){
                                    return;
                                }
                                //页面跳转
                                hsp.sendRedirect(result);
                            } catch (Exception e) {
                                // TODO: handle exception
                                e.printStackTrace();
                            }
                            
                        }

                        @Override
                        public void init(FilterConfig conf) throws ServletException {
                            this.config=conf;
                            String conStr=config.getInitParameter("config");
                            //可包含多个配置文件
                            String[] configFiles=null;
                            if(conStr==null||conStr.isEmpty()){
                                configFiles=new String[]{"myMvc.xml"};
                            }else{
                                //拆分配置文件名称字符串
                                configFiles=conStr.split(",");
                            }
                            this.mappingManager=new ActionMappingManager(configFiles);
                        }
                        private ActionMapping getActionMapping(HttpServletRequest request) throws Exception {
                            //获取请求路径
                            String uri=((HttpServletRequest)request).getRequestURI();
                            String contextPath=((HttpServletRequest)request).getContextPath();
                            //截取上下文路劲后面的部分
                            String actionPath=uri.substring(contextPath.length());
                            //获取Action名称
                            String actionName=actionPath.substring(1,actionPath.lastIndexOf(".")).trim();
                            ActionMapping mapping=null;
                            mapping=mappingManager.getActionMappingByName(actionName);
                            return mapping;
                            
                        }
                    }

上一篇:Kubernetes概览


下一篇:VC++程序员如何做好界面