第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

全部開發(fā)者教程

實戰(zhàn) - 業(yè)務(wù)實現(xiàn) 2

這一小節(jié),是 Java 基礎(chǔ)教程的最后一節(jié),很感謝大家能夠堅持看到這里。本小節(jié)我將帶領(lǐng)大家優(yōu)化用戶鑒權(quán)服務(wù),并完成商品模塊的實現(xiàn)。為了檢驗大家的學習成果,分類模塊的實現(xiàn)將交給大家自行來完成。

1. 用戶密碼加密

上一小節(jié)的最后,我們提到用戶鑒權(quán)服務(wù)是需要優(yōu)化的。大家可以看到我們數(shù)據(jù)庫存儲的是明文密碼,這是非常不推薦的,在實際的項目中,明文存儲用戶的密碼是非常不安全的,也是不負責任的行為。我們在設(shè)計 imooc_user表時,給password設(shè)置的類型為固定長度類型char(32),32 位正好是MD5算法加密后的長度。

本系統(tǒng)使用 MD5 算法對密碼進行加密,下面在 util包下新建一個 MD5Util類并寫入如下內(nèi)容(可直接復制粘貼代碼):

package com.colorful.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5Util {

    public static String md5(String source) {
        StringBuilder stringBuilder = new StringBuilder();
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            // 將一個byte數(shù)組進行加密操作,返回的是一個加密的byte數(shù)組,二進制的哈西計算,md5加密的第一步
            byte[] digest = messageDigest.digest(source.getBytes());
            for (byte b : digest) {
                int result = b & 0xff;
                // 將得到的int類型的值轉(zhuǎn)化為16進制的值
                String hexString = Integer.toHexString(result);
                if (hexString.length() < 2) {
                    //系統(tǒng)會自動把0省略,所以添加0
                    stringBuilder.append("0");
                }
                stringBuilder.append(hexString);
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return stringBuilder.toString();
    }

    public static void main(String[] args) {
        String password = "123456";
        String s = MD5Util.md5(password);
        System.out.println(s);
    }

}

在主方法中,我們編寫了調(diào)用md5()加密方法的邏輯,運行代碼,屏幕上得到123456加密后的字符串:

e10adc3949ba59abbe56e057f20f883e

下面我們將imooc_user表中存儲的明文密碼,更新為上面的結(jié)果,大家可以使用SQL語句來進行更新:

 UPDATE `imooc_user` SET `password` = 'e10adc3949ba59abbe56e057f20f883e' WHERE `id` = 1;

這里我直接通過 MySQL 客戶端進行更新,如下是操作過程的截圖:
圖片描述
數(shù)據(jù)庫存儲的密碼更新后,我們就無法直接通過原本的驗證邏輯來驗證密碼了,需要修改用戶鑒權(quán)邏輯 —— 將用戶輸入的密碼加密后,再與數(shù)據(jù)庫的密碼進行對比。那么這段邏輯要寫在service層還是dao層呢?答案肯定是service層,此時service層用于處理業(yè)務(wù)的特性得到了體現(xiàn),修改UserService下的login方法,將參數(shù)password加密:

public User login(String username, String password) {
    String md5Password = MD5Util.md5(password);
    return userDAO.selectByUserNameAndPassword(username, md5Password);
}

再次啟動應(yīng)用程序,驗證改寫的邏輯是否正確:

至此,我們就完成了對用戶鑒權(quán)服務(wù)的優(yōu)化。

2. 控制臺(儀表盤)

用戶登錄成功后,應(yīng)該顯示控制臺面板,我們下面稱之為儀表盤,它主要包含 3 個選項,分別是管理商品、管理分類以及退出登錄。下面我們編寫一個dashboard()方法,該方法用來打印儀表盤的相關(guān)操作提示,以及根據(jù)用戶的輸入來執(zhí)行相應(yīng)的操作。如下是部分代碼:

/**
 * 主流程方法
 */
public static void run() {
    // ... 已省略前面的鑒權(quán)代碼
    // 登錄成功后,跳轉(zhuǎn)到儀表盤頁面
    dashboard();
}

/**
 * 儀表盤操作
 */
private static void dashboard() {
    Scanner scanner = new Scanner(System.in);
    int code1 = 0, code2 = 0;
    while (true) {
        printDashboardTips();
        code1 = scanner.nextInt();
        if (code1 == 0) {
            System.out.println("您已退出登錄");
            break;
        }
        switch (code1) {
            case 1:
                System.out.println("正在查詢商品列表...");
                // TODO 實現(xiàn)商品模塊
                break;
            case 2:
                System.out.println("正在查詢分類列表...");
                // TODO 實現(xiàn)分類模塊
                break;
            default:
                System.out.println("不存在您輸入的選項,請重新輸入");
                break;
        }
    }
}

/**
 * 輸出儀表盤操作提示
 */
private static void printDashboardTips() {
    System.out.println("請輸入對應(yīng)數(shù)字以進行操作:");
    System.out.println("(1. 管理商品 | 2. 管理分類 | 0. 退出登錄)");
}

我們把向控制臺輸出的操作提示,封裝成了一個方法printDashboardTips(),這樣使代碼更簡潔易讀。

dashboard()方法內(nèi)部,實例化了一個Scanner類,初始化的code1變量接收用戶的輸入,根據(jù)輸入的數(shù)值用來操作儀表盤,關(guān)于code2變量,我們將在實現(xiàn)商品模塊代碼的時候使用。緊接著有一個while循環(huán),其條件始終為true,當用戶輸入的code登錄 0 的時候,就跳出循環(huán),也就是退出了應(yīng)用程序。

完成上面的代碼編寫后,我們啟動應(yīng)用程序,來驗證一下:

至此,我們已實現(xiàn)展示儀表盤以及退出登錄的代碼編寫。

3. 商品模塊實現(xiàn)

3.1 商品管理主流程

當用戶輸入的code1變量為數(shù)字 1 的時候,就要顯示商品管理相關(guān)的操作。我們再封裝一個printGoodsListTips()方法,用于打印商品管理模塊的相關(guān)操作提示。方法的代碼如下:

/**
 * 輸出商品列表頁操作提示
 */
private static void printGoodsListTips() {
    System.out.println("請輸入對應(yīng)數(shù)字以進行操作:");
    System.out.println("(1. 新增商品 | 2. 編輯商品 | 3. 查看商品詳情 | 4. 刪除商品 | 5. 搜索商品 | 6. 按分類查詢商品 | 0. 返回上一級菜單)");
}

向屏幕打印這些提示后,下面還是一個條件始終為truewhile循環(huán),當用戶輸入的code登錄 0 的時候,就跳出當前層循環(huán),也就是返回上一級儀表盤的菜單。

已知了商品管理模塊的所有操作,下面我們在switch(code1)case 1條件分支加入如下邏輯代碼(部分偽代碼):

case 1:
    while (true) {
        System.out.println("正在查詢商品列表...");
        // TODO 查詢并顯示商品列表
        printGoodsListTips();
        code2 = scanner.nextInt();
        if (code2 == 0) {
            // 返回上一級,即跳出本層循環(huán)
            System.out.println("返回上一級");
            break;
        }
        switch (code2) {
            case 1:
                System.out.println("新增商品");
                break;
            case 2:
                System.out.println("編輯商品");
                break;
            case 3:
                System.out.println("商品詳情");
                break;
            case 4:
                System.out.println("刪除商品");
                break;
            case 5:
                System.out.println("搜索商品");
                break;
            case 6:
                System.out.println("按分類查詢");
                break;
            default:
                System.out.println("不存在您輸入的選項,請重新輸入");
        }
    }
    break;

上面我們提到,code2變量用于接收用戶對于管理商品操作的輸入,此處又是一個switch case結(jié)構(gòu),每一個條件分支,都對應(yīng)到用戶輸入的數(shù)字,如果用戶輸入的數(shù)字找不到對應(yīng)的分支,那么就重復執(zhí)行循環(huán)體中的代碼。

接下來我們就要實現(xiàn)這些操作。

3.2 查詢商品列表

dao包下新建一個GoodsDAO類,并寫入一下內(nèi)容:

package com.colorful.dao;

import com.colorful.model.Goods;
import com.colorful.util.JDBCUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

public class GoodsDAO {

    private Connection connection = null;
    private PreparedStatement preparedStatement = null;
    private ResultSet resultSet = null;
    boolean executeResult;
    
    public List<Goods> selectGoodsList() {
        List<Goods> goodsList = new ArrayList<>();
        try {
            // 獲得鏈接
            connection = JDBCUtil.getConnection();
            // 編寫 SQL 語句
            String sql = "SELECT `id`, `name`, `price` FROM `imooc_goods` where `delete_time` is null";
            // 預(yù)編譯 SQL
            preparedStatement = connection.prepareStatement(sql);
            resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
                Goods goods = new Goods();
                goods.setId(resultSet.getInt("id"));
                goods.setName(resultSet.getString("name"));
                goods.setPrice(resultSet.getDouble("price"));
                goodsList.add(goods);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 釋放資源
            JDBCUtil.release(resultSet, preparedStatement, connection);
        }
        return goodsList;
    }

}

selectGoodsList()方法就用于查詢商品列表(由于數(shù)據(jù)量不大,此處我沒有對列表數(shù)據(jù)進行分頁查詢,大家也可以自行加入)。

service包下新建GoodsService,并調(diào)用dao層下封裝好的方法:

package com.colorful.service;

import com.colorful.dao.GoodsDAO;
import com.colorful.model.Goods;

import java.util.List;

public class GoodsService {

    private final GoodsDAO goodsDAO = new GoodsDAO();

    /**
     * 獲取商品列表
     * @return 商品列表
     */
    public List<Goods> getGoodsList() {
        return goodsDAO.selectGoodsList();
    }

}

這樣,我們就完成了查詢商品列表的服務(wù)層代碼編寫。

3.3 刪除商品

新增商品、刪除商品、查看商品詳情等功能都是簡單的SQL語句,這里不再具體寫出實現(xiàn),大家可以參考源碼自行實現(xiàn)。但關(guān)于刪除商品,我要特殊說明一下。對于實際的項目,往往不用對數(shù)據(jù)執(zhí)行DELETE操作,對于數(shù)據(jù)的刪除往往是更新操作,這也是我們設(shè)置了一個公用字段delete_time的意義,當這個delete_time字段不為null的時候,才會被查詢出來。在GoodsDAO類下,新增如下方法:

public boolean deleteGoodsById(Integer id) {
    try {
        // 獲得鏈接
        connection = JDBCUtil.getConnection();
        // 編寫 SQL 語句
        String sql = "UPDATE `imooc_goods` set `delete_time` = ? WHERE id = ?";
        // 預(yù)編譯 SQL
        preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setTimestamp(1, new Timestamp(System.currentTimeMillis()));
        preparedStatement.setInt(2, id);
        executeResult = preparedStatement.execute();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        // 釋放資源
        JDBCUtil.release(preparedStatement, connection);
    }
    return executeResult;
}

大家可以看到,我們的代碼實現(xiàn)沒有使用DELETE語句,而是使用了UPDATE語句,更新了指定id記錄的delete_time字段為系統(tǒng)當前時間。

dao層方法編寫完成后,就可以在service層調(diào)用該方法了:

/**
 * 刪除商品
 * @param id 商品id
 */
public void removeGoodsById(Integer id) {
    goodsDAO.deleteGoodsById(id);
}

3.4 搜索商品

除了刪除商品的實現(xiàn),搜索商品的實現(xiàn)我們也要特殊講解一下。上面我們提到,由于商品的數(shù)據(jù)量不大,在查詢商品列表時,沒有使用LIMIT關(guān)鍵字進行分頁查詢。正是由于數(shù)據(jù)量不大的原因,對于搜索商品,我們沒有使用LIKE關(guān)鍵字進行模糊查詢,而是使用Stream API直接對商品列表進行過濾,希望通過這里的實現(xiàn)來協(xié)助讓大家理解Stream API,直接在GoodsService下添加如下方法:

/**
 * 根據(jù)商品名稱搜索商品
 * @param name 商品名稱
 * @return 商品列表
 */
public List<Goods> searchGoodsByName(String name) {
    List<Goods> goodsList = this.getGoodsList();
    return goodsList.stream().filter(
            goods -> goods.getName().contains(name)
    ).collect(Collectors.toList());
}

該方法先是調(diào)用了getGoodsList()方法獲取了商品列表,然后使用Stream API中的filter()中間操作,對商品進行過濾,filter()接收一個斷言型接口,由于是一個函數(shù)式接口,我們可通過lambda表達式來進行表示。最后調(diào)用collect()終止操作,將流轉(zhuǎn)化為列表。

服務(wù)層的接口完成后,大家就可以在對應(yīng)的case分支編寫的具體的邏輯了,每個分支的邏輯大體相同,主要是接收用戶的輸入,以及服務(wù)層方法的調(diào)用。大家可參考github倉庫的源碼來補全自己的代碼。

4. 作業(yè) - 分類模塊實現(xiàn)

上面,我們已經(jīng)實現(xiàn)了較為復雜的商品模塊,對于分類模塊的實現(xiàn)也大同小異,甚至更加簡單,剩下的功能 ——分類的增刪改查就交由同學們自行實現(xiàn)。希望大家能夠按照我們項目的架構(gòu),將合理的代碼寫到合適的位置,對每個功能點都要將細節(jié)考慮周全,這將有助于降低大家后續(xù)對框架學習的上手成本。

5. 小結(jié)

通過實戰(zhàn)階段的學習,我們知道了數(shù)據(jù)表中的密碼字段,是不能夠明文存儲的,通常使用一些加密算法進行加密,也復習了switch case條件結(jié)構(gòu)的使用,對于商品模糊查詢,我們使用了 Java 8 中的 Stream API。

中間還講解了項目的分層技術(shù)、MySQL 的增刪改查操作、JDBC API 的封裝與使用以及Scanner類的使用等知識,實際的項目基本不會使用Scanner來與用戶進行交互,都是通過優(yōu)美的前端界面與用戶進行交互的,建議大家可以去看看Lin CMS的示例demo,它是一個能夠達到企業(yè)級應(yīng)用標準的內(nèi)容管理系統(tǒng)開發(fā)框架。

當然,想要上手使用Lin CMS,大家還有很長的一段路要走,但是請記住,莫要浮空建高樓,Java 的基礎(chǔ)知識在任何時候都是不能忽視的,希望大家反復學習。Java 基礎(chǔ)的學習到此也就結(jié)束了,再次感謝大家能夠堅持看完!