【JavaWeb】客戶關係管理系統

Java3y發表於2019-02-27

前言

為了鞏固開發的流程,我們再拿一個客戶關係管理系統來練手...!

成果圖

我們完成的就是下面的專案!

【JavaWeb】客戶關係管理系統


搭建配置環境

  • 配置Tomcat
  • 匯入開發包
  • 建立開發用到的程式包

【JavaWeb】客戶關係管理系統

  • 在資料庫建立相對應的表

	CREATE TABLE customer (
	
	  id          VARCHAR(40) PRIMARY KEY,
	  name        VARCHAR(20) NOT NULL,
	  gender      VARCHAR(10) NOT NULL,
	  birthday    DATE,
	  cellphone   VARCHAR(30) NOT NULL,
	  email       VARCHAR(30),
	  preference  VARCHAR(200),
	  type        VARCHAR(20),
	  description VARCHAR(255)
	
	);



複製程式碼

開發實體

開發實體十分簡單,對照著資料庫的表就行了!


    private String id;
    private String name ;
    private String gender ;
    private Date birthday ;
    private String cellphone ;
    private String eamil ;
    private String preference ;
    private String type ;
    private String description;


	//....各種setter、getter

複製程式碼

開發獲取資料庫連線池的Utils

匯入配置檔案


	<?xml version="1.0" encoding="UTF-8"?>
	<c3p0-config>
		<default-config>
			<property name="driverClass">com.mysql.jdbc.Driver</property>
			<property name="jdbcUrl">jdbc:mysql://localhost:3306/zhongfucheng</property>
			<property name="user">root</property>
			<property name="password">root</property>
		
			<property name="acquireIncrement">5</property>
			<property name="initialPoolSize">10</property>
			<property name="minPoolSize">5</property>
			<property name="maxPoolSize">20</property>
		</default-config>
		
		<named-config name="mysql">
			<property name="driverClass">com.mysql.jdbc.Driver</property>
			<property name="jdbcUrl">jdbc:mysql://localhost:3306/zhongfucheng</property>
			<property name="user">root</property>
			<property name="password">root</property>
		
			<property name="acquireIncrement">5</property>
			<property name="initialPoolSize">10</property>
			<property name="minPoolSize">5</property>
			<property name="maxPoolSize">20</property>
		</named-config>
		
		
		<named-config name="oracle">
			<property name="driverClass">oracle.jdbc.driver.OracleDriver</property>
			<property name="jdbcUrl">jdbc:oracle:thin:@//localhost:1521/事例名...</property>
			<property name="user">使用者名稱</property>
			<property name="password">密碼</property>
		
			<property name="acquireIncrement">5</property>
			<property name="initialPoolSize">10</property>
			<property name="minPoolSize">5</property>
			<property name="maxPoolSize">20</property>
		</named-config>
	</c3p0-config>

複製程式碼

開發提供資料連線池的工具類


	public class Utils2DB {
	
	    private static ComboPooledDataSource comboPooledDataSource = null;
	
	        static {
	
	            //它會自動尋找配置檔案,節點為mysql的資料庫(預設就是Mysql)
	            comboPooledDataSource = new ComboPooledDataSource();
	        }
	
	
	    public static DataSource getDataSource() {
	        return comboPooledDataSource ;
	    }
	
	    public static Connection connection() {
	        try {
	            return comboPooledDataSource.getConnection();
	        } catch (SQLException e) {
	            e.printStackTrace();
	            throw new RuntimeException("資料庫初始化失敗了!");
	        }
	    }
	}


複製程式碼

開發UUID工具類##


	
	public class WebUtils {
	
	    public static String makeId() {
	        return UUID.randomUUID().toString();
	    }
	}

複製程式碼

開發DAO

DAO應該提供增加客戶和查詢使用者的功能

增加使用者



    public void addCustomer(Customer customer)  {

        QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

      
        String sql = "INSERT INTO customer (id,name, gender, birthday, cellphone, preference, type, description) VALUES (?, ?, ?, ?, ?, ?, ?, ?,?)";


        //得到使用者傳遞進來的資料
        String id = customer.getId();
        String name = customer.getName();
        String gender = customer.getGender();
        String cellphone = customer.getCellphone();
        String email = customer.getEmail();
        String preference = customer.getPreference();
        String type = customer.getType();
        String description = customer.getDescription();

        //對於日期,要轉換一下
        Date date = customer.getBirthday();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String birthday = simpleDateFormat.format(date);

        try {
            //向資料庫插入資料
            queryRunner.update(sql, new Object[]{id, name, gender, birthday, cellphone, email, preference, type, description});

            //插入記錄成功!
        } catch (SQLException e) {

            //如果出現了異常,就丟擲Dao異常吧(自定義的異常)
            e.printStackTrace();

            throw new DaoException("新增使用者出錯了!");
        }
    }

複製程式碼

測試增加使用者

寫完一個功能,不要急著去寫其他的功能,先測試一下!


    @Test
    public void add() {

        //為了測試的方便,直接使用建構函式了!
        Customer customer = new Customer("1", "zhongfucheng", "男", new Date(), "1234", "aa@sina.com", "打程式碼", "高貴的使用者", "我是個好人");



        CustomerDao customerDao = new CustomerDao();
        customerDao.addCustomer(customer);
        
    }

複製程式碼
  • 好的,沒有報錯!再看看資料庫-----------只要是中文的資料,都亂碼了!

【JavaWeb】客戶關係管理系統


解決的辦法,看我另外一篇博文:https://zhongfucheng.bitcron.com/post/jie-jue-cuo-wu/mysqlzhong-wen-luan-ma


查詢使用者

將所有的客戶查詢出來就行了!



    //得到所有的使用者
    public List<Customer> getAll() {

        QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());


        String sql = "SELECT * FROM customer";
        try {
            List<Customer> customers = (List<Customer>) queryRunner.query(sql, new BeanListHandler(Customer.class));

            //如果集合大於個數大於0,就返回集合,不大於0,就返回null
            return customers.size() > 0 ? customers : null;
            
        } catch (SQLException e) {
            e.printStackTrace();
            throw new DaoException("獲取所有的使用者出錯了!");
        }
        
    }

複製程式碼

測試查詢使用者


    @Test
    public void find() {

        CustomerDao customerDao = new CustomerDao();
        List<Customer> customers = customerDao.getAll();

        for (Customer customer : customers) {

            System.out.println(customer.getName());
        }
    }

複製程式碼

【JavaWeb】客戶關係管理系統


修改使用者資訊

修改使用者資訊首先要知道使用者的資訊,在web端,只有id能唯一標識使用者,我們需要通過id,獲取使用者全部資訊(也就是Customer物件)


    public Customer find(String id) {

        QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

        String sql = "SELECT * FROM customer WHERE id = ?";

        try {
            Customer customer = (Customer) queryRunner.query(sql, new BeanHandler(Customer.class), new Object[]{id});

            return customer;

        } catch (SQLException e) {
            e.printStackTrace();
            throw new DaoException("查詢使用者失敗了");
        }

    }


複製程式碼

修改使用者都是外邊傳遞個物件進來,Dao層取出物件的資料,從而對資料庫的資料進行修改!



    public void update(Customer customer) {

        QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

        String sql = "UPDATE customer set name=?,gender=?,birthday=?,cellphone=?,email=?,preference=?,type=?,description=?  WHERE id = ?";

        try {
            queryRunner.update(sql, new Object[]{customer.getName(), customer.getGender(), customer.getBirthday(),customer.getCellphone(), customer.getEmail(), customer.getPreference(), customer.getType(), customer.getDescription(), customer.getId()});

        } catch (SQLException e) {

            e.printStackTrace();
            throw new DaoException("更新失敗");
        }
    }

複製程式碼

測試修改使用者


    @Test
    public void update() {

        CustomerDao customerDao = new CustomerDao();

        //我們已經知道了某id,通過id獲取得到使用者資訊(Customer)
        String id = "043f7cce-c6f1-4155-b688-ba386cae1636";
        Customer customer = customerDao.find(id);

        //修改使用者資訊
        customer.setName("看完部落格要點贊");
        customerDao.update(customer);
    }

複製程式碼
  • 原來該使用者的名字是d

【JavaWeb】客戶關係管理系統

  • 測試完之後:

【JavaWeb】客戶關係管理系統


刪除使用者

  • 通過外界傳遞進來的id,就可以刪除資料庫表中的記錄了

    public void delete(String id) {
        QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

        String sql = "DELETE from  customer WHERE id = ?";
        try {
            queryRunner.update(sql, new Object[]{id});
        } catch (SQLException e) {
            e.printStackTrace();
            throw new DaoException("刪除使用者失敗了");
        }
    }

複製程式碼

測試刪除使用者


    @Test
    public void delete() {

        CustomerDao customerDao = new CustomerDao();

        //我們已經知道了某id,通過id刪除資料庫中的記錄
        String id = "043f7cce-c6f1-4155-b688-ba386cae1636";

        customerDao.delete(id);
    }


複製程式碼

資料庫已經查詢不到id為043f7cce-c6f1-4155-b688-ba386cae1636的記錄了!

開發service



	public class BusinessService {
	
	    CustomerDao customerDao = new CustomerDao();
	
	    public List<Customer> getAll() {
	
	        return customerDao.getAll();
	    }
	
	    public void addCustomer(Customer customer) {
	
	        customerDao.addCustomer(customer);
	    }

		public void deleteCustomer(String id) {
	        customerDao.delete(id); 
	    }
	
	    public void updateCustomer(Customer customer) {
	        customerDao.update(customer);
	    }
	
	    public Customer findCustomer(String id) {
	        return customerDao.find(id);
	    }
	}

複製程式碼

開發web 的增加和查詢#

提供UI,增加客戶的Servlet


        //直接跳轉到顯示增加使用者頁面的jsp
        request.getRequestDispatcher("/WEB-INF/addCustomer.jsp").forward(request, response);

複製程式碼

開發顯示新增客戶頁面


<form action="${pageContext.request.contextPath}/addCustomerController">
    <table border="1px">
        <tr>
            <td>使用者名稱:</td>
            <td><input type="text" name="name"></td>
        </tr>
        <tr>
            <td>性別:</td>
            <td>
                <input type="radio" name="gender" value="female"><input type="radio" name="gender" value="male"></td>
        </tr>
        <tr>
            <td>生日:</td>
            <td>
                <select id="year">
                    <option value="1900">1900</option>
                </select>
                <select id="month">
                    <option value="01">01</option>
                </select>
                <select id="day">
                    <option value="01">01</option>
                </select>
            </td>
        </tr>
        <tr>
            <td>電話號碼:</td>
            <td><input type="text" name="cellphone"></td>
        </tr>
        <tr>
            <td>郵箱:</td>
            <td><input type="text" name="email"></td>
        </tr>
        <tr>
            <td>愛好:</td>
            <td>
                <input type="checkbox" name="hobbies" value="唱歌">唱歌
                <input type="checkbox" name="hobbies" value="跳舞">跳舞
                <input type="checkbox" name="hobbies" value="打程式碼">打程式碼
            </td>
        </tr>
        <tr>
            <td>客戶型別</td>
            <td>
                <input type="radio" name="type" value="VIP">VIP
                <input type="radio" name="type" value="普通客戶">普通客戶
                <input type="radio" name="type" value="黑名單客戶">黑名單客戶
            </td>
        </tr>
        <tr>
            <td>描述</td>
            <td>
                <textarea name="description" cols="30" rows="10"></textarea>
            </td>
        </tr>
        <tr>
            <td><input type="submit" value="增添客戶"></td>
            <td><input type="reset" value="重置"></td>
        </tr>

    </table>
</form>

複製程式碼
  • 效果是這樣子的

【JavaWeb】客戶關係管理系統

我們發現,在日期的下拉框中,只有一個資料(因為我們在value中只寫了一個資料)

要想在下拉框中可以選擇很多的資料,那麼value的值就不能單單隻有一個。當然了,也不可能在JSP頁面中寫下面的程式碼


                    <option value="1900">1900</option>
                    <option value="1901">1900</option>
                    <option value="1902">1900</option>
                    <option value="1903">1900</option>

複製程式碼

我們用javaScript生成下拉框的資料就行了!!

  • 獲取年份!

	function makeYear() {
	
	    //得到下拉框的控制元件
	    var year = document.getElementById("year");
	
	    //要想下拉框有更多的資料,就需要有更多的option控制元件
	    //js獲取得到年份是getFullYear(),單單的getYear()只是獲取兩位數
	    for (var i=1901; i<= new Date().getFullYear(); i++) {
	
	
	        //生成option控制元件
	        var option = document.createElement("option");
	
	        //option控制元件的值和文字內容為迴圈生成的年分!
	        option.value = i;
	        option.innerText = i;
	
	        //將生成option控制元件繫結到select控制元件上
	        year.appendChild(option);
	    }
	
	}

複製程式碼
  • 獲取月份和日也類似

	function makeMonth() {
	    var month = document.getElementById("month");
	    for (var i = 2; i <= 12; i++) {
	        var option = document.createElement("option");
	        if (i < 10) {
	            option.value = '0' + i;
	            option.innerText = '0' + i;
	        } else {
	            option.value = i;
	            option.innerText = i;
	        }
	        month.appendChild(option);
	    }
	}
	
	function makeDay()
	{
	    var day = document.getElementById("day");
	    for(var i=2;i<=12;i++)
	    {
	        var option = document.createElement("option");
	        if(i<10)
	        {
	            option.value = '0' + i;
	            option.innerText = '0' + i;
	        }else{
	            option.value = i;
	            option.innerText = i;
	        }
	        day.appendChild(option);
	    }
	}

複製程式碼
  • 在JSP頁面中匯入javascript檔案

  • 注意:javasrcipt檔案不能放在WEB-INF下面!!!!否則是獲取不到的!!!


    <script type="text/javascript" src="${pageContext.request.contextPath}/customer.js" ></script>

複製程式碼
  • 這三個函式都是在頁面載入時就應該被初始化了,所以在body上繫結onload時間即可!!

	function pageInit() {
	    makeYear();
	    makeMonth();
	    makeDay();
	}


	<body onload="pageInit()">

複製程式碼
  • 效果:

【JavaWeb】客戶關係管理系統


JavaScript拼湊資料

表單的資料非常多,毫無疑問,我們會使用BeanUtils來將資料封裝到Bean物件中!

對於表單的資料,還是有些雜亂的。表單中日期的年月日是分開的,我們要麼在客戶端將年月日的資料拼湊起來,要麼在伺服器端將年月日拼湊起來!同理,客戶的喜好可能不單單有一個,但在Customer物件中,喜好單單用一個String型別來表示的。我們也要把客戶的喜好拼湊起來。

顯然,在客戶端用javaScript做拼湊是非常方便的!


	function makeBirthday() {
	
	    //獲取下拉框的資料,把資料拼湊成日期字串
	    var year = document.getElementById("year");
	    var month = document.getElementById("month");
	    var day = document.getElementById("day");
	    var birthday = year + "-" + month + "-" + day;
	
	    //想要將拼湊完的字串提交給伺服器,用隱藏域就行了
	    var input = document.createElement("input");
		input.type = "hidden";
	    input.value = birthday;
	    input.name = "birthday";
	
	    //將隱藏域繫結在form下【為了方便,在form中設定id,id名字為form】
	    document.getElementById("form").appendChild(input);
	
	}
	
	function makePreference() {
	
	    //獲取喜好的控制元件
	    var hobbies = document.getElementsByName("hobbies");
	
	    //定義變數,記住使用者選中的選項
	    var preference = "";
	
	    //遍歷喜好的控制元件,看使用者選上了什麼!
	    for (var i = 0; i < hobbies.length; i++) {
	
	        if (hobbies[i].checked == true) {
	            preference += hobbies[i].value + ",";
	        }
	    }
	
	    //剛才拼湊的時候,最後一個逗號是多餘的,我們要把它去掉
	    preference = preference.substr(0, preference.length - 1);
	
	    //也是用隱藏域將資料帶過去給伺服器
	    var input = document.createElement("input");
		input.type = "hidden";
	    input.value = preference;
	    input.name = "preference";
	    
	    //將隱藏域繫結到form表單上
	    document.getElementById("form").appendChild(input);
	    
	}

複製程式碼
  • 當表單提交的時候,觸發上面兩個函式就行了!所以在form表單上繫結onsumit事件!

	function makeForm() {
	    
	    makeBirthday();
	    makePreference();
	    return true;
	    
	}

	<form action="${pageContext.request.contextPath}/addCustomerController" id="form" onsubmit=" return makeForm()" method="post">

複製程式碼

開發處理表單資料的Servlet

  • 將表單的資料封裝到Bean物件中,要開發工具類

    public static <T> T request2Bean(HttpServletRequest httpServletRequest, Class<T> aClass) {

        try {
            
            //獲取Bean的物件
            T bean = aClass.newInstance();
            
            //獲取表單中所有的名字
            Enumeration enumeration = httpServletRequest.getParameterNames();

            //遍歷表單提交過來的名字
            while (enumeration.hasMoreElements()) {

                //每個名字
                String name = (String) enumeration.nextElement();

                //獲取得到值
                String value = httpServletRequest.getParameter(name);

                //如果使用者提交的資料不為空,那麼將資料封裝到Bean中
                if (!value.equals("") && value != null) {
                    BeanUtils.setProperty(bean, name, value);
                }

              
            }
			  return bean;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("封裝資料到Bean中,失敗了!");
        }
        
    }

複製程式碼
  • 處理表單資料的Servlet程式碼:

        //將表單的資料弄到Bean物件中
        Customer customer = WebUtils.request2Bean(request, Customer.class);


        try {
            //呼叫BusinessService層的方法,新增客戶
            BusinessService businessService = new BusinessService();
            businessService.addCustomer(customer);

            //如果執行到這裡,說明成功了,如果被catch了,說明失敗了。
            request.setAttribute("message", "新增成功!");

        } catch (Exception e) {
            e.printStackTrace();
            request.setAttribute("message", "新增失敗");
        }
        request.getRequestDispatcher("/message.jsp").forward(request, response);


複製程式碼
  • 效果:

【JavaWeb】客戶關係管理系統


提供查詢客戶介面的Servlet


        //跳轉到顯示客戶介面資訊的jsp
        request.getRequestDispatcher("/WEB-INF/lookCustomer.jsp").forward(request, response);

複製程式碼

開發顯示客戶資訊的頁面


	<c:if test="${empty(list)}">
	    對不起,還沒有任何客戶的資訊!
	</c:if>
	
	<c:if test="${!empty(list)}">
	    <table border="1px">
	        <tr>
	            <td>使用者名稱:</td>
	            <td>密碼:</td>
	            <td>性別:</td>
	            <td>生日:</td>
	            <td>電話號碼:</td>
	            <td>郵箱:</td>
	            <td>型別:</td>
	            <td>描述:</td>
	        </tr>
	
	        <c:forEach items="${list}" var="customer">
	            <tr>
	                <td>${customer.name}</td>
	                <td>${customer.gender}</td>
	                <td>${customer.birthday}</td>
	                <td>${customer.cellphone}</td>
	                <td>${customer.email}</td>
	                <td>${customer.preference}</td>
	                <td>${customer.type}</td>
	                <td>${customer.description}</td>
	            </tr>
	        </c:forEach>
	    </table>
	</c:if>

複製程式碼
  • 效果:

【JavaWeb】客戶關係管理系統


將功能拼接在首頁上

採用分貞技術,讓介面更加好看!

index頁面:



  <frameset rows="25%,*">
      <frame src="${pageContext.request.contextPath }/head.jsp" name="head">
      <frame src="${pageContext.request.contextPath }/body.jsp" name="body">
  </frameset>

複製程式碼

head頁面:


	<body style="text-align: center;">
	
	<h1>客戶管理系統!</h1>
	
	<a href="${pageContext.request.contextPath}/AddCustomer" target="body">增添客戶</a>
	<a href="${pageContext.request.contextPath}/LookCustomer" target="body">檢視客戶</a>
	</body>

複製程式碼

body頁面:



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

複製程式碼
  • 效果:

效果圖


改善顯示頁面

現在問題來了,如果我們客戶資訊有非常非常地多,我們不可能把客戶資訊全部都擠在同一個頁面上,如果我們這樣做的話,網頁的長度就會非常的長!

於是乎,我們就需要用到了分頁的技術**,對於分頁技術基礎的講解,在我另一篇博文中有介紹:** https://zhongfucheng.bitcron.com/post/jdbc/jdbcdi-si-pian-shu-ju-ku-lian-jie-chi-dbutilskuang-jia-fen-ye

看完上篇博文,我們知道,首先要做的就是:明確分頁技術中需要用到的4個變數的值!

查詢總記錄數

查詢總記錄數也就是查詢資料庫表的記錄有多少條,這是關於對資料庫資料的操作,所以肯定是在dao層做!


    public Long getTotalRecord() {

        QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

        String sql = "SELECT * FROM customer";
        
        try {
            //獲取查詢的結果
            Long l = (Long) queryRunner.query(sql, new ScalarHandler());
            return l;
           
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException("查詢總記錄數失敗了!");
        }
        
    }

複製程式碼

查詢分頁的資料

獲取分頁的資料也是查詢資料庫的記錄,這也是關於對資料庫的操作,所以也是在Dao層做的!



    /*查詢分頁資料*/
    //獲取分頁的資料是需要start和end兩個變數的【從哪條開始取,取到哪一條】
    public List<Customer> getPageData(int start, int end) {

        QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

        String sql = "SELECT * FROM customer LIMIT ?,?";

        try {
            List<Customer> customers = (List<Customer>) queryRunner.query(sql, new BeanListHandler(Customer.class), new Object[]{start, end});

            return customers;

        } catch (SQLException e) {
            e.printStackTrace();
            throw new DaoException("獲取分頁資料失敗了!");
        }
    }


複製程式碼

分析

現在我們已經可以知道總記錄數了,對於其他3個變數(每頁顯示記錄數【由程式設計師來指定】,當前是多少頁【由使用者來指定】,總頁數【由總記錄數和每頁顯示記錄數來算數來的】)

現在要分析的是,這些變數應該放在哪裡呢???全部放在Dao層??全部放在Dao層是可以實現功能的,但是,這樣MVC結構就被破壞掉了(Dao層只用來對資料進行CRUD操作,4個變數存在Dao層,是不合理的)

最好的做法是這樣的:建立一個實體Page,將分頁用到的資訊全部封裝在Page中實現!Page就代表著分頁的資料這樣就非常符合物件導向的思想了!

將資料封裝到Page中並在頁面上顯示分頁的資料

①:建立Page類



    //儲存著分頁的資料
    private List<Customer> list;

    //總記錄數
    private long totalRecord;

    //每頁顯示記錄數,這裡我規定每頁顯示3條
    private int linesize = 3;

    //總頁數
    private int totalPageCount;

    //當前顯示的頁數
    private long currentPageCount;

	//...各種的setter、getter


複製程式碼

②:BusinessService應該提供獲取分頁資料的服務


    //既然Page物件代表是分頁資料,那麼返回Page物件即可!
    //web層應該傳入想要看哪一頁資料的引數!
    public Page getPageData(String currentPageCount) {

        Page page = new Page();

        //獲取資料庫中有多少條記錄,並封裝到Page物件中
        Long totalRecord = customerDao.getTotalRecord();
        page.setTotalRecord(totalRecord);

        //算出總頁數,並封裝到Page物件中
        int totalPagecount = (int) (totalRecord % page.getLinesize() == 0 ? totalRecord / page.getLinesize() : totalRecord / page.getLinesize() + 1);
        page.setTotalPageCount(totalPagecount);

        int start ;
        int end = page.getLinesize();

        //現在又分兩種情況了,如果傳遞進來的引數是null的,那麼說明外界是第一次查詢的
        if (currentPageCount == null) {

            //第一次查詢,就應該設定當前頁數是第一頁
            page.setCurrentPageCount(1);

            start = (int) ((page.getCurrentPageCount() - 1) * page.getLinesize());

            List<Customer> customers = customerDao.getPageData(start, end);

            page.setList(customers);
        } else {

            //如果不是第一次,就把外界傳遞進來的頁數封裝到Page物件中
            page.setCurrentPageCount(Long.parseLong(currentPageCount));

            start = (int) ((page.getCurrentPageCount() - 1) * page.getLinesize());

            List<Customer> customers = customerDao.getPageData(start, end);

            page.setList(customers);

        }
        return page;

    }


複製程式碼

③:web層呼叫BusinessService層的功能,獲取得到Page物件


        //獲取使用者想要看的頁數,如果是第一次,那肯定為null
        String currentPageCount = request.getParameter("currentPageCount");

        //呼叫BusinessService的方法,獲取得到所有客戶資訊
        BusinessService businessService = new BusinessService();
        Page page  = businessService.getPageData(currentPageCount);

        //把客戶資訊帶過去給jsp頁面
        request.setAttribute("page", page);

        //跳轉到顯示客戶介面資訊的jsp
        request.getRequestDispatcher("/WEB-INF/lookCustomer.jsp").forward(request, response);

複製程式碼

④:在JSP頁面中,使用EL表示式獲取到Page物件,從而輸出資料


        <c:forEach items="${page.list}" var="customer">
            <tr>
                <td>${customer.name}</td>
                <td>${customer.gender}</td>
                <td>${customer.birthday}</td>
                <td>${customer.cellphone}</td>
                <td>${customer.email}</td>
                <td>${customer.preference}</td>
                <td>${customer.type}</td>
                <td>${customer.description}</td>
            </tr>
        </c:forEach>


複製程式碼

⑤:在JSP頁面中顯示頁碼,同時把碼數繫結到超連結去!


    <%--提供頁數的介面--%>
    <c:forEach var="pageNum" begin="1" end="${page.totalPageCount}">
        <a href="${pageContext.request.contextPath}/LookCustomer?currentPageCount=${pageNum}">
            ${pageNum}
        </a>
    </c:forEach>


複製程式碼
  • 效果:

【JavaWeb】客戶關係管理系統


讓分頁的功能更加完善

增加上一步和下一步

一般的分頁不僅僅只有頁碼給你,還有上一步和下一步。我們在JSP頁面上也能新增這樣的功能,其實這是非常簡單的!



    <%--如果當前的頁碼大於1,才顯示上一步--%>
    <c:if test="${page.currentPageCount>1}">

        <%--把傳遞過去的頁碼-1就行了--%>
        <a href="${pageContext.request.contextPath}/LookCustomer?currentPageCount=${page.currentPageCount-1}">
            上一步
        </a>
    </c:if>


    <%--如果當前的頁碼小於總頁數,才顯示下一步--%>
    <c:if test="${page.currentPageCount<page.totalPageCount}">

        <%--把傳遞過去的頁碼-1就行了--%>
        <a href="${pageContext.request.contextPath}/LookCustomer?currentPageCount=${page.currentPageCount+1}">
            下一步
        </a>
    </c:if>


複製程式碼
  • 效果:

【JavaWeb】客戶關係管理系統


顯示當前頁數,總頁數,總記錄數


    當前頁數是:[${page.currentPageCount}]&nbsp;&nbsp;&nbsp;

    總頁數是:${page.totalPageCount}&nbsp;&nbsp;

    總記錄數是:${page.totalRecord}

複製程式碼
  • 效果:

【JavaWeb】客戶關係管理系統


跳轉到某頁上


    <input type="text" id="currentPageCount">
    <input type="button" value="跳轉">

複製程式碼
  • 頁面效果:

【JavaWeb】客戶關係管理系統

我們現在要做的就是:怎麼樣才能輸入框輸入內容,然後點選跳轉按鈕,將輸入框的資料傳送到Servlet上,然後實現跳轉到某頁上功能

明顯地,我們肯定要使用JavaScript程式碼!


<script type="text/javascript">

    /*既然寫上了JavaScript程式碼了,就順便驗證輸入框輸入的資料是否合法吧*/
    function goPage() {

        /*獲取輸入框控制元件*/
        var input = document.getElementById("currentPageCount");

        /*獲取輸入框的資料*/
        var value = input.value;

        if(value==null || value==""){
            alert("請輸入頁碼");
            return false;
        }

        if(!value.match("\\d+")){
            alert("請輸入數字");
            return false;
        }

        if(value<1 || value>${page.totalPageCount}){
            alert("請輸入合法資料");
            return false ;
        }

        window.location.href="${pageContext.request.contextPath}/LookCustomer?currentPageCount="+value;
    }

</script>


複製程式碼
  • 效果:

【JavaWeb】客戶關係管理系統


記錄JSP頁面的開始頁和結束頁

為什麼我們要記錄JSP頁面的開始頁和結束頁呢?經過上面層層地優化,我們感覺不出有什麼問題了。那是因為資料量太少!

我們試著多新增點記錄進資料庫,再回來看看!

【JavaWeb】客戶關係管理系統

從上面的圖我們可以發現**頁數有多少,JSP頁面就顯示多少!**這明顯不合理的,如果有100頁也顯示100頁嗎?

我們做一個規定,一次只能顯示10頁的資料。那麼顯示哪10頁呢?這又是一個問題了,如果我們在看第11頁的資料,應該顯示的是第7到第16頁的資料(顯示11附近的頁數),我們在看第2頁的資料,應該顯示第1到第10頁的資料。使用者想要看的頁數是不明確的,我們顯示附近的頁數也是不明確的!我們應該把使用者想要看的頁數記錄下來,然後根據邏輯判斷,顯示附近的頁數

我們顯示頁數的程式碼是這樣的:

【JavaWeb】客戶關係管理系統

很明顯,我們只要控制了begin和end中的資料,就控制顯示哪10頁了!

①在Page類中多定義兩個成員變數


    //記錄JSP頁面開始的頁數和結束的頁數
    private int startPage;
    private int endPage;

	//Setter,Getter方法


複製程式碼

②開始頁數和結束頁數受使用者想看的頁數影響,在BusinessService的getPageData()加入下面的邏輯


			//第一次訪問
			page.setStartPage(1);
            page.setEndPage(10);
		


			//不是第一次訪問
            if (page.getCurrentPageCount() <= 10) {
                page.setStartPage(1);
                page.setEndPage(10);
            } else {
                page.setStartPage((int) (page.getCurrentPageCount() - 4));
                page.setEndPage((int) (page.getCurrentPageCount() + 5));

                //如果因為加減角標越界了,那麼就設定最前10頁,或者最後10頁
                if (page.getStartPage() < 1) {
                    page.setStartPage(1);
                    page.setEndPage(10);
                }
                if (page.getEndPage() > page.getTotalPageCount()) {
                    page.setEndPage(page.getTotalPageCount());
                    page.setStartPage(page.getTotalPageCount() - 9);
                }
            }


複製程式碼

③:在JSP顯示頁數時,獲取得到開始頁和結束頁就行了


    <%--提供頁數的介面--%>
    <c:forEach var="pageNum" begin="${page.startPage}" end="${page.endPage}">
        <a href="${pageContext.request.contextPath}/LookCustomer?currentPageCount=${pageNum}">
                [${pageNum}]&nbsp;
        </a>
    </c:forEach>


複製程式碼
  • 效果:

【JavaWeb】客戶關係管理系統



重構優化

分頁重構

我們再回頭看看BusinessService中獲取分頁資料的程式碼:


    //既然Page物件代表是分頁資料,那麼返回Page物件即可!
    //web層應該傳入想要看哪一頁資料的引數!
    public Page getPageData(String currentPageCount) {

        Page page = new Page();

        //獲取資料庫中有多少條記錄,並封裝到Page物件中
        Long totalRecord = customerDao.getTotalRecord();
        page.setTotalRecord(totalRecord);

        //算出總頁數,並封裝到Page物件中
        int totalPagecount = (int) (totalRecord % page.getLinesize() == 0 ? totalRecord / page.getLinesize() : totalRecord / page.getLinesize() + 1);
        page.setTotalPageCount(totalPagecount);

        int start ;
        int end = page.getLinesize();

        //現在又分兩種情況了,如果傳遞進來的引數是null的,那麼說明外界是第一次查詢的
        if (currentPageCount == null) {

            //第一次查詢,就應該設定當前頁數是第一頁
            page.setCurrentPageCount(1);

            page.setStartPage(1);
            page.setEndPage(10);

            start = (int) ((page.getCurrentPageCount() - 1) * page.getLinesize());

            List<Customer> customers = customerDao.getPageData(start, end);

            page.setList(customers);
        } else {

            //如果不是第一次,就把外界傳遞進來的頁數封裝到Page物件中
            page.setCurrentPageCount(Long.parseLong(currentPageCount));

            start = (int) ((page.getCurrentPageCount() - 1) * page.getLinesize());

            if (page.getCurrentPageCount() <= 10) {
                page.setStartPage(1);
                page.setEndPage(10);
            } else {
                page.setStartPage((int) (page.getCurrentPageCount() - 4));
                page.setEndPage((int) (page.getCurrentPageCount() + 5));

                //如果因為加減角標越界了,那麼就設定最前10頁,或者最後10頁
                if (page.getStartPage() < 1) {
                    page.setStartPage(1);
                    page.setEndPage(10);
                }
                if (page.getEndPage() > page.getTotalPageCount()) {
                    page.setEndPage(page.getTotalPageCount());
                    page.setStartPage(page.getTotalPageCount() - 9);
                }
            }


            List<Customer> customers = customerDao.getPageData(start, end);

            page.setList(customers);

        }
        return page;

    }

複製程式碼

太太太太太tm複雜,太太太太tm長了!!!!!我們BusinessService要做的僅僅是呼叫Dao層的功能,為web層提供資料,但我們在方法中使用大量了邏輯判斷,而且這些邏輯判斷都是屬於Page類的!

明確一下:只有獲取資料庫總記錄數是在BusinessService中做的,其他的資料變數都是應該在Page類中完成!

在BusinessService獲取了總記錄數之後,我們要對其他變數進行初始化(根據總記錄數,使用者想要看哪一頁的資料),算出其他的資料(JSP記錄開始頁數、結束頁數、總頁數等等),最好的辦法就是通過Page的建構函式來實現初始化!

  • 改良後的BusinessService


    public Page getPageData2(String currentPageCount) {

        //獲取得到總記錄數
        Long totalPageCount = customerDao.getTotalRecord();

        if (currentPageCount == null) {

            //如果是第一次,那麼就將使用者想看的頁數設定為1
            Page page = new Page(1, totalPageCount);

            List<Customer> customers = customerDao.getPageData(page.getStartIndex(), page.getLinesize());

            page.setList(customers);
            return page;

        } else {

            //如果不是第一次,就將獲取得到的頁數傳遞進去
            Page page = new Page(Integer.parseInt(currentPageCount), totalPageCount);

            List<Customer> customers = customerDao.getPageData(page.getStartIndex(), page.getLinesize());

            page.setList(customers);
            return page;
        }
    }


複製程式碼
  • 改良後的Page類(原來的Page類只有成員變數和setter、getter方法)


    public Page(int currentPageCount, long totalRecord) {


        //將傳遞進來的currentPageCount初始化
        this.currentPageCount = currentPageCount;

        //總頁數
        totalPageCount = (int) (totalRecord % linesize == 0 ? totalRecord / linesize : totalRecord / linesize + 1);
        
        //總記錄數
		this.totalRecord = totalRecord;

        //開始取資料的位置
        startIndex = (currentPageCount - 1) * linesize;


        //如果當前頁小於10,那麼開始頁為1,結束頁為10就行了
        if (this.currentPageCount <= 10) {
            this.startPage = 1;
            this.endPage = 10;
        } else {
            startPage = this.currentPageCount - 4;
            endPage = this.currentPageCount + 5;

            //加減後頁數越界的情況
            if (startPage < 1) {
                this.startPage = 1;
                this.endPage = 10;
            }
            if (endPage > totalPageCount) {
                this.startPage = this.currentPageCount - 9;
                this.endPage = this.totalPageCount;
            }
        }

    }

複製程式碼

分頁顯示頁面重構

分頁的顯示頁面都是永恆不變的,我們可以把程式碼重構成一個jsp,需要用到分頁顯示頁面的地方,就包含進去就行了!

  • page.jsp


	<%@ page contentType="text/html;charset=UTF-8" language="java" %>
	<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
	<%--顯示當前頁數--%>
	當前頁數是:[${page.currentPageCount}]&nbsp;&nbsp;&nbsp;
	
	<%--如果當前的頁碼大於1,才顯示上一步--%>
	<c:if test="${page.currentPageCount>1}">
	
	    <%--把傳遞過去的頁碼-1就行了--%>
	    <a href="${pageContext.request.contextPath}/LookCustomer?currentPageCount=${page.currentPageCount-1}">
	        上一步
	    </a>
	</c:if>
	
	<%--提供頁數的介面--%>
	<c:forEach var="page" begin="${page.startPage}" end="${page.endPage}">
	    <a href="${pageContext.request.contextPath}/LookCustomer?currentPageCount=${page}">
	        [${page}]&nbsp;
	    </a>
	</c:forEach>
	
	<%--如果當前的頁碼小於總頁數,才顯示下一步--%>
	<c:if test="${page.currentPageCount<page.totalPageCount}">
	
	    <%--把傳遞過去的頁碼-1就行了--%>
	    <a href="${pageContext.request.contextPath}/LookCustomer?currentPageCount=${page.currentPageCount+1}">
	        下一步
	    </a>&nbsp;&nbsp;
	</c:if>
	
	<input type="text" id="currentPageCount">
	<input type="button" value="跳轉" onclick="goPage()">
	
	總頁數是:${page.totalPageCount}&nbsp;&nbsp;
	
	總記錄數是:${page.totalRecord}
	
	
	<script type="text/javascript">
	
	    /*既然寫上了JavaScript程式碼了,就順便驗證輸入框輸入的資料是否合法吧*/
	    function goPage() {
	
	        /*獲取輸入框控制元件*/
	        var input = document.getElementById("currentPageCount");
	
	        /*獲取輸入框的資料*/
	        var value = input.value;
	
	        if(value==null || value==""){
	            alert("請輸入頁碼");
	            return false;
	        }
	
	        if(!value.match("\\d+")){
	            alert("請輸入數字");
	            return false;
	        }
	
	        if(value<1 || value>${page.totalPageCount}){
	            alert("請輸入合法資料");
	            return false ;
	        }
	
	        window.location.href="${pageContext.request.contextPath}/LookCustomer?currentPageCount="+value;
	    }
	
	</script>


複製程式碼

用需要用到的地方,匯入即可!


    <jsp:include page="page.jsp"></jsp:include>
複製程式碼

為了做到更好的通用性,處理分頁資料的url應該由Servlet傳進去給Page類,讓Page類封裝起來!要使用的時候,再用Page取出來就行了。

下面寫法已經固定了,不夠靈活!也就是說,下面的url地址不應該寫死的


	${pageContext.request.contextPath}/LookCustomer?currentPageCount=${page.currentPageCount+1}

複製程式碼

我們可以這樣做:

  • 在Controller上獲取Servlet的名稱,在傳遞使用者想要看的頁數的同時,把Servlet的url也傳遞進去

        String servletName = this.getServletName();

        //呼叫BusinessService的方法,獲取得到所有客戶資訊
        BusinessService businessService = new BusinessService();

		//把Servlet的url也傳遞進去
        Page page = businessService.getPageData2(currentPageCount, request.getContextPath() + "/" + servletName);


複製程式碼
  • 在Page類上,多增加一個成員變數

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

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

複製程式碼
  • 在BusinessService接受到web層傳遞進來的url,set到Page物件上就行了!

	page.setUrl(url);

複製程式碼

我們在jsp頁面跳轉到處理分頁資料的Servlet上,就再不用寫死了。直接用Page物件中獲取出來就行了!


    <%--把傳遞過去的頁碼-1就行了--%>
    <a href="${page.url}?currentPageCount=${page.currentPageCount-1}">
        上一步
    </a>


複製程式碼

開發web的刪除和修改

在查詢jsp頁面上,增添刪除和修改的操作連結!

【JavaWeb】客戶關係管理系統

【JavaWeb】客戶關係管理系統


開發處理刪除操作的Servlet

超連結繫結要刪除使用者的id,帶過去給Controller

        <a href="${pageContext.request.contextPath}/DeleteCustomer?id=${customer.id}">刪除</a>

複製程式碼

controller的程式碼也十分簡單:


        String id = request.getParameter("id");
        
        //呼叫BusinessService層的功能,就可以完成刪除操作了
        BusinessService businessService = new BusinessService();

        businessService.deleteCustomer(id);

複製程式碼

刪除客戶記錄也是一件非常重要的事情,應該提供JavaSrcript程式碼詢問是否要真的刪除

在超連結控制元件上繫結事件!


       <a href="${pageContext.request.contextPath}/DeleteCustomer?id=${customer.id}" onclick=" return sureDelete()">刪除</a>

複製程式碼

	function sureDelete() {
	    var b = window.confirm("你確定要刪除嗎?");
	    
	    if(b) {
	        return true;
	    }else {
	        return false;
	    }
	}

複製程式碼

測試:

【JavaWeb】客戶關係管理系統


修改操作

修改操作的流程是這樣的:點選修改超連結,跳轉到該使用者的詳細資訊頁面,在詳細資訊頁面中修改資料,再提交修改!【跳轉到使用者詳細資訊頁面時,使用者的id還在的,在提交資料的時候,記得把id也給到伺服器,【id是不包含在表單中的,要我們自己提交過去】!】


   <a href="${pageContext.request.contextPath}/UpdateCustomerUI?=${customer.id}">修改</a>

複製程式碼

開發提供使用者詳細資訊的Servlet


        String id = request.getParameter("id");
        BusinessService businessService = new BusinessService();
        
        //通過id獲取得到使用者的詳細資訊
        Customer customer = businessService.findCustomer(id);

        request.setAttribute("customer", customer);
        //跳轉到顯示使用者詳細資訊的jsp頁面上
        request.getRequestDispatcher("/WEB-INF/customerInformation").forward(request, response);

複製程式碼

開發顯示使用者資訊的JSP【資料回顯】

想要日期能夠選擇,記得匯入JavaScript程式碼,響應事件!

注意:在顯示頁面上,一定要把id傳遞過去給處理表單的Servlet,不然伺服器是不知道你要修改哪一條資料的!

<head>
    <title>使用者詳細資訊</title>
    <script type="text/javascript" src="${pageContext.request.contextPath}/customer.js">

    </script>
</head>
<body onload="pageInit()">

<form action="${pageContext.request.contextPath}/updateCustomer?id=${customer.id}" method="post" onsubmit="makeForm()">
    <table border="1px">
        <tr>
            <td>使用者名稱:</td>
            <td><input type="text" name="name" value="${customer.name}"></td>
        </tr>

        <tr>
            <td>性別</td>
            <td><input type="radio" name="gender" value="male" ${customer.gender=='male'?'checked':''}><input type="radio" name="gender" value="female"${customer.gender=='female'?'checked':''}></td>
        </tr>
        <tr>
            <td>生日</td>
            <td>
                <select id="year">
                    <option value="${fn:split(customer.birthday,'-')[0]}">${fn:split(customer.birthday,'-')[0]}</option>
                </select>
                <select id="month">
                    <option value="${fn:split(customer.birthday,'-')[1]}">${fn:split(customer.birthday,'-')[1]}</option>
                </select>
                <select id="day">
                    <option value="${fn:split(customer.birthday,'-')[2]}">${fn:split(customer.birthday,'-')[2]}</option>
                </select>
            </td>
        </tr>
        <tr>
            <td>電話號碼:</td>
            <td><input type="text" name="cellphone" value="${customer.cellphone}"></td>
        </tr>
        <tr>
            <td>郵箱:</td>
            <td><input type="text" name="email"value="${customer.email}"></td>
        </tr>
        <tr>
            <td>愛好:</td>
            <td>
                <input type="checkbox" name="hobbies" value="唱歌"${fn:contains(customer.preference, '唱歌')==true?'checked':''}>唱歌

                <input type="checkbox" name="hobbies" value="跳舞"${fn:contains(customer.preference, '跳舞')==true?'checked':''}>跳舞
                <input type="checkbox" name="hobbies" value="打程式碼"${fn:contains(customer.preference, '打程式碼')==true?'checked':''}>打程式碼
            </td>
        </tr>
        <tr>
            <td>客戶型別</td>
            <td>
                <input type="radio" name="type" value="VIP" ${customer.type=='VIP'?'checked':''}>VIP
                <input type="radio" name="type" value="普通客戶"${customer.type=='普通客戶'?'checked':''}>普通客戶
                <input type="radio" name="type" value="黑名單客戶"${customer.type=='黑名單客戶'?'checked':''}>黑名單客戶
            </td>
        </tr>
        <tr>
            <td>描述</td>
            <td>
                <textarea name="description" cols="30" rows="10">${customer.description}</textarea>
            </td>
        </tr>
        <tr>
            <td><input type="submit" value="確定修改"></td>
            <td><input type="reset" value="重置"></td>
        </tr>
    </table>
</form>

複製程式碼

效果:

【JavaWeb】客戶關係管理系統

處理修改表單資料的Servlet



        //將資料封裝到Bean中
        Customer customer = WebUtils.request2Bean(request, Customer.class);

		//將id封裝到Customer物件中!!!不要忘了id!!!在表單中獲取到的資料是沒有id的!!!!!記得!!!!
		customer.setId(request.getParameter("id"));
        
        //呼叫Service層的方法,實現修改
        BusinessService businessService = new BusinessService();
        businessService.updateCustomer(customer);
        
        //修改成功就跳回檢視客戶介面
        request.getRequestDispatcher("/LookCustomer").forward(request, response);
複製程式碼
  • 效果:

【JavaWeb】客戶關係管理系統

總結

  1. 在dao層中,我們有新增客戶、通過id查詢使用者、刪除使用者、修改使用者資訊的方法。
  2. 日期我們一般用下拉框來給使用者選取,要想下拉框的資訊有足夠多的資料,我們需要用到JavaScript【DOM程式設計動態增加和修改資料】
  3. javasrcipt檔案不能放在WEB-INF目錄下面
  4. 日期的資料通過下拉框選取,年、月、日是分散的,我們需要把他們拼接,於是我們也用JavaScript來拼接【減低伺服器端的壓力】
  5. 開發工具方法request2Bean,主要用到了BeanUtils框架,這樣就不用在Servlet一個一個封裝了。
  6. 在JSP判斷集合是否有元素時,我們可以用EL表示式**${empty(集合)}**。
  7. 如果記錄數有很多,我們應該使用分頁技術,一般地,我們使用Page類來封裝分頁的資料
  8. 要使用分頁技術,就必須在資料庫用查詢總記錄數,通過總記錄數,就可以算出總頁數了【每頁顯示多少條記錄由我們說了算】
  9. 在dao層還要編寫獲取具體的分頁資料,從哪裡開始,哪裡結束,返回一個List集合,再把List集合封裝到Page物件上
  10. 由於獲取分頁資料需要當前的頁數是多少,(所以在service中要判斷當前頁數是否存在,如果不存在,那麼就設定為1)【更新,我認為在Controller判斷會好一點】
  11. 分頁中,我們還支援上一頁和下一頁的功能,如果頁數大於1,才顯示上一頁,如果頁數小於1,才顯示下一頁。
  12. 給出下拉框進行頁數跳轉,使用JavaScript事件機制,獲取頁數,再提交給Servlet處理即可
  13. 我們還要控制頁數的顯示,因為不可能有100頁,我們就顯示100頁,這樣是不可能的。在Page類中維護兩個變數,startPage,endPage。我們規定每次只能顯示10頁資料,如果第一次訪問就顯示1-10頁。如果當前頁數大於10,那麼就顯示6-15頁。如果角標越界了,那麼就顯示前10頁或者後10頁
  14. 我們把顯示分頁的頁面封裝成單獨的jsp,使用的Servlet連線也可以用url變數來維護。
  15. 前臺資料做拼接,最終都是把拼接好的資料用一個隱藏域封裝起來,隨後讓form表單一起提交

如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章的同學,想要獲取更多的Java資源的同學,可以關注微信公眾號:Java3y

相關文章