• (MVC — — Demo)客户管理系统的开发日志


    点击一下


    目录


    第一步:搭建开发环境

    将一众需要的jar包导入开发环境中 ;

    WEB 项目中,WEB-INF 目录下面创建一个 lib 目录,将需要的 jar 包放到这里,并添加到库中;


    第二步:层次包(按照三层架构思想写)

    主要把握住 MVC 思想,按照层次写开发包;

    再加一些自己需要的包,包括但不限于:工具包(utils)、自定义异常包(exception)、工厂包(factory)、实体包(domain)、bean包(bean)。。。


    第四步:开发(utils)工具包

    这个包,必须开发出来;

    里面封装着项目中,需要经常用到的操作;

    例如:JDBC操作数据库,每次都要获取连接、关闭连接;我们不可能每次都手动写一遍获取、关闭连接的代码;最好的做法,就是在工具包里面写一个 JdbcUtils 工具类,在里面写上获取与关闭连接的代码;在项目中需要用到JDBC操作数库,就直接调用工具类的方法 ;

    JDBC工具类部分代码

    /**
     * 利用jdbc操控数据库
     *
     * @author An
     */
    @SuppressWarnings("unused")
    public class JdbcUtils {
        private static Properties config = new Properties();
    
    
        static {
            try {
    //            读取配置文件
                config.load(JdbcUtils.class.getResourceAsStream("/ijava/xin/utils/db.properties"));
    //            加载数据库驱动类
                Class.forName(config.getProperty("driver"));
            } catch (IOException e) {
                e.printStackTrace();
                throw new JdbcException("读取配置文件出错");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                throw new JdbcException("配置文件路径有问题");
            }
        }
    
        /**
         * @return 返回数据库的连接
         */
        public static Connection getConnection() throws SQLException {
            return DriverManager.getConnection(config.getProperty("url"), config.getProperty("username"), config.getProperty("password"));
        }
    
        public static void closedConnection(ResultSet resultSet, Statement statement, Connection connection) {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
    
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
    
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    
    
    }

    第四步:开发 Dao

    先写 daoImpl 类,在里面实现对数据库的操作方法,最后提取出 dao 接口 ;


    第五步:开发 services

    先写 servicesImpl 类,在里面 实现 项目对外提供的服务,最后提取出 services 接口 ;


    第六步:开发 factory(工厂)

    工厂包,是为了解耦;

    services层需要dao层的方法时候,不能直接在services层里面直接 new dao 层对象,这样就是硬编码了;将 services层 和 dao 层 紧紧的绑定在一起 ; 以后改动dao层,会牵扯到services 层;

    因此,我们需要让他们之间出现一个桥梁,让他们不直接通信,让这个桥梁起个媒介的作用;

    我们就用工厂来解耦,就是在工厂包里面,为dao层做一个 daoFactory 工厂类,里面提供静态方法;

    示例代码:

    /**
     * 静态工厂解耦
     *
     * @author An
     */
    @SuppressWarnings("unused")
    public class CustomerDaoFactory {
        private static CustomerDao customerDao = new CustomerDaoImpl();
    
        public static CustomerDao getCustomerDao() {
            return customerDao;
        }
    }
    

    我们在services层,就直接问工厂来要 dao层的实例;这样即使dao层改变了,甚至推倒重来了,我们也只需要在工厂中对其进行修改,根本不影响services层 ;

    这里我用的是 静态工厂 ,是工厂中最简单的一种了。缺点也很明显,要为每一层增加一个新的实现,我都要为其写一个工厂类;懒得写简单工厂,我写的这个demo的业务逻辑很简单。

    当然也可以 写一个 泛型工厂 一劳永逸 ;

    备注:我web是从 servlet+JSP + tomcat 学起的;现在学到了JDBC的事物,对那些 spring 等框架,我都没学到;

    但是从对群里的群友对话,他说用了sprig的框架以后,没考虑过工厂,说spring会解耦,services层如果需要dao层对象,spring会根据字段给它一个;

    霎时,吾觉 spring 莫不是一个工厂吧;后百度之,果不其然,乃一大工厂也 ;

    从上面的经历,可以看出,从最初的学起,还是很有好处的;


    第七步:开发web

    • <iframe> 标签实现分帧页面

      
      // 写上target属性,属性值是我们的画中画标签名
      <a href="${pageContext.request.contextPath}/Demo.jsp" target="showForm">添加客户</a>
      <a href="${pageContext.request.contextPath}/Demo2.jsp" target="showForm">查看客户</a>
      <hr>
      
      
      <iframe src="" name="showForm" style="text-align: center" scrolling="auto" frameborder="0" height="85%" width="100%"></iframe>
      
      
    • 用全局类来管理 伪静态数据

      在程序开发过程中,我们在表单中有一项性别要用户填写;常规操作是用 <radio> 标签给出两个性别,供选择;

      这样,其实也就是性别,被我们写死了;假如,系统以后卖到泰国,性别就会不只有男、女,两个选项;我们就需要去更改当初的表单的性别设置,可能表单的性别设置也会关联到其他。

      这样一下,就需要改动许多东西;因此,我们最开始开发的时候,就应该考虑到数据以后会改变的情况;写一个程序来控制这些数据显示;

      表单中的爱好一栏,也是同样的操作,由程序控制显示,因为,每年都会有新的爱好出来;

      我把这种在一段时间内是静态的,但是长久看,确实动态的数据,称为伪静态数据


    常用try catch

    对我们的代码,要常用 try catch 包起来,因为我们在服务器端可能会出现一些错误,我们不能将这些错误直接显示在网页上,我们就要捕捉它们,跳准到全局页面(500),在后台打印log;


    从请求中获取请求参数,封装进bean

    现在学过的有2种方法:

    1. 第一种,就是将它们读取进一个枚举中,然后迭代枚举,然后使用beanUtils的方法,将它们封装进bean里面;

      
      //            获取请求的参数的名字
                  Enumeration<String> enumeration = request.getParameterNames();
      //            循环获取参数名字,对应的值
                  while (enumeration.hasMoreElements()) {
                      String name = enumeration.nextElement();
      //            根据名字从域中拿值
                      String value = request.getParameter(name);
      //            将数据封装到对象中,使用BeanUtils,或者直接使用反射
                      BeanUtils.setProperty(classbean, name, value);
      
    2. 第二种,就是将请求参数封装进Map里面,再封装进bean里面 ;假如Map里面的关键字在bean里面没有,则不进行赋值 ;

       Map<String, String[]> map = request.getParameterMap();
      
       BeanUtils.populate(t, map);
      

    分帧显示页面

    分帧页面

    比如,我们想实现这样一个页面,上下分帧,各自显示自己的画面,点击上半部分页面的超链接,在下半部分页面显示超链接指向的窗口页面;

    我们只需要在上半部分的页面中加入一个画中画标签<iframe>即可;然后在超链接上指明超链接打开的窗口地址;这样设置以后,打开超链接,就会在我们指定的下面的页面显示;

    示例代码

    <h1 style="color: darkcyan">客户管理系统</h1>
    
    <audio autoplay="autoplay" loop="loop" src="${pageContext.request.contextPath}/Music/cuoguo.mp3"></audio>
    <a href="${pageContext.request.contextPath}/addcustomer.html" target="showForm">添加客户</a>
    <a href="${pageContext.request.contextPath}/showAll.html" target="showForm">查看客户</a>
    <hr>
    
    <iframe name="showForm" style="text-align: center" scrolling="auto" frameborder="0" height="85%" width="100%"></iframe>

    这样做以后,还有一个好处,点击超链接,上半部分的页面是不会刷新的,它们相当于一个全局页面了,我们可以在里面设置背景音乐,这样背景音乐就成了全局音乐,下部分页面切换。不会影响音乐的播放 ;


    制作分页

    我们这个小项目中,需要对数据库的用户进行展示;这就需要用分页技术了 ;

    • 分页逻辑
    ---------------------------------分页实现逻辑:--------------------------

    1、对于页面上的 页码,上一页、下一页 等都是超链接,它们对应着一个个的 servlet

    2、servlet接受到请求以后,将请求信息封装为一个对象(QueryInfo

    3、QueryInfo 对象字段设计

    
        int currentPage ; // 查询页
    
        int pageSize ; // 每页显示数据的条数
    
        int startIndex ; // 查询页的数据开始的下标 ,根据查询页和每页显示数据,可以算出来
    
    

    4、web层的servlet将请求信息封装为 QueryInfo 对象以后,然后将请求跳准services层,将 QueryInfo 对象作为services层方法的参数 ;

    5、services层,根据QueryInfo对象的信息,调用dao层,查询出需要的数据,数据的总数、;

    6、dao层将查询到的信息,封装为一个对象(QueryResult 对象),存进域里面;

    7、QueryResult 对象设计

    
    List list ; // 保存页面显示的数据
    
    int totalRecord ; // 数据库中的数据总数
    

    8、services层封装一个PageBean对象 ;这个对象字段设计,根据JSP页面中显示的数据,来设计,这个对象,其实也就是页面;

    9、PageBean对象设计

    
    List list ;  // 保存页面显示的数据
    
    int totalRecord ; // 数据库中数据的总数
    
    int pagaSize ;  // 每页显示多少条数据 
    
    int currentPage ;  // 当前显示的页码
    
    int previousPage ; // 前一页
    
    int nextPage ;  // 下一页
    
    int[] pageBar = new int[] ; // 页码条,根据信息算出来的
    

    10、services层将 pageBean 对象,保存进域里面,然后交给最初的 servlet 处理;

    11、最初的 servlet 跳准到自己,页面用 el表达式 取值 ;

    分页的逻辑就是这么一回事;还是比较简单的;
    

    开发分页对象的实体

    设计出三个java类,很简单,没啥讲的;

    但是有一些字段,明明是自己根据信息算出来的,而不是从外界获取到的,那么这样的字段就不要有set方法 ;


    页码条

    根据实际情况生成页码条;

    示例代码:

    
    public int[] getPageBar() {
    
            int startIndex = 0;
            int endIndex = 0;
    
    //        先判断当前一共多少页,默认最多显示5个页码条
            if (getTotalPage() < 5) {
    //            根据实际情况生成数组长度
                pageBar = new int[getTotalPage()];
                startIndex = 1;
                endIndex = getTotalPage() ;
            } else {
                pageBar = new int[5];
                startIndex = currentPage - 2;
                endIndex = currentPage + 2;
    
                if (startIndex < 1) {
                    startIndex = 1;
                    endIndex = 5;
                }
    
                if (endIndex > getTotalPage()) {
                    endIndex = getTotalPage();
                    startIndex = getTotalPage() - 4;
                }
    
            }
    
    //      为数组填充值
            int index = 0;
            for (int i = startIndex; i <= endIndex; i++) {
                pageBar[index++] = i;
            }
    
    
            return pageBar;
        }
    

    坑点

    拼接浏览器url地址的时候,不能在里面随便写上空格;例如:'&pageSize=' 不能写成 '&pageSize = ' ;

    class属性是可以el表达式的:class="${status.count%2 == 0}" ;el表达式可以写在JSP页面中的任何地方,


    更新客户信息

    // 开发修改用户信息模块。难点在于将数据库中的信息,复原到表格里面;

    可以使用了body上的onload监听方法,调用JS函数,在JS里面通过DOM操作,取值赋值,这是我首先想出来的方法;不会jQuery,就只能这么做了;

    后来发现,其实对一般的输入项使用 value和el表达式就可以完成;

    对于选项(<radio> <checkbox>)使用三元表达式,和el表达式,也可以完成;

    对于<textarea> 对他设置value属性,value的值是不会显示在页面中,只能在标签体上用el表达式取值,或者DOM操作,用innertHtml 进行赋值 ;

    其实是 valueinnetHTML 的区别value是属性值,而innerHtml则是赋人眼可见的值 ,也就是标签体的值,只不过一些标签,没有标签体,它们的值就是 value的值;


    JS的一些坑

    JS比较值是否相等的时候,如果是字符串,则应该用单引号括起来,不论它是字面值还是变量值,但是变量做参数的时候,不需要括号括起来;

    JS 中非0 都是真,跟C一样,用IF的时候要注意

            // 这里必须判断是否等于 -1 否则表达式永真
                if ('${customer.preference}'.indexOf(pre[i].value)!=-1) { 
                    pre[i].checked = 'true';
                }

    JS中字符串的contain方法,不好用,不是所有浏览器都支持 ;

    JS 函数,有时候获取不到传进去的参数,可以试着在参数上加上单引号;


    乱码问题!

    再次说一下乱码的问题 ;

    response没设置编码的原因是,servlet里面没做输出,都是跳准到JSP 里面输出

    JSP页面的pageEncoding='UTF-8',就已经改变了JSP翻译为servlet的response的码表;

    所以JSP输出中文不会出现乱码;但是你要是在servlet做输出,就必须改变其response的码表了 ;

  • 相关阅读:
    数组中,奇数放前偶数放后
    回溯法
    java+selenium的helloworld
    我为什么反对纯算法面试题
    算法面试题
    关于算法
    伴随开发人员成长的问题:工程重要,还是算法重要?细节重要,还是架构重要?
    数据结构和算法为什么这么重要?
    JSP网站开发基础总结《三》
    JSP网站开发基础总结《二》
  • 原文地址:https://www.cnblogs.com/young-youth/p/11665706.html
Copyright © 2020-2023  润新知