day03-功能實現02

来源:https://www.cnblogs.com/liyuelian/archive/2022/12/16/16988506.html
-Advertisement-
Play Games

家居網購項目實現02 5.功能04-會員登錄 5.1需求分析/圖解 需求如圖: 輸入用戶名、密碼後提交 判斷該用戶是否存在 如果存在,顯示登錄成功頁面 否則返回登錄頁面,要求重新登錄 要求改進登錄密碼為md5加密 5.2思路分析 5.3代碼實現 根據上述分析圖,在對應的層添加方法 5.3.1dao層 ...


家居網購項目實現02

5.功能04-會員登錄

5.1需求分析/圖解

需求如圖:

image-20221216165739849 image-20221216165757967

  1. 輸入用戶名、密碼後提交
  2. 判斷該用戶是否存在
  3. 如果存在,顯示登錄成功頁面
  4. 否則返回登錄頁面,要求重新登錄
  5. 要求改進登錄密碼為md5加密

5.2思路分析

5.3代碼實現

根據上述分析圖,在對應的層添加方法

5.3.1dao層

  1. 修改MemberDAO介面,聲明queryMemberByUsernameAndPassword()方法

    //提供一個通過用戶名和密碼返回對應的Member的方法
    public Member queryMemberByUsernameAndPassword(String username,String password);
    
  2. 修改MemberDAOImpl實現類,實現queryMemberByUsernameAndPassword()方法

    /**
     * 通過用戶名和密碼返回對應的Member對象
     *
     * @param username 用戶名
     * @param password 密碼
     * @return 返回值為對應的Member對象,如果不存在則返回null
     */
    @Override
    public Member queryMemberByUsernameAndPassword(String username, String password) {
        String sql = "SELECT * FROM `member` WHERE `username`=? AND `password`=MD5(?);";
        return querySingle(sql, Member.class, username, password);
    }
    
  3. 在utils包中的MemberDAOImplTest類中增加測試方法

    @Test
    public void queryMemberByUsernameAndPassword() {
        Member member = memberDAO.queryMemberByUsernameAndPassword
                ("king", "king");
        System.out.println("member=" + member);
    }
    
    image-20221216183533442

    代碼測試通過

5.3.2service層

  1. 修改MemberService介面,聲明login方法

    //登錄用戶
    //相比於直接傳遞用戶名和密碼,傳遞一個Member對象拓展性會比較好一些
    public Member login(Member member);
    
  2. 修改MemberServiceImpl介面實現類,實現login方法

    /**
     * 根據登錄傳入的member信息,返回對應的在資料庫中的member對象
     *
     * @param member
     * @return 返回的是資料庫中的member對象,若不存在則返回null
     */
    @Override
    public Member login(Member member) {
        return memberDAO.queryMemberByUsernameAndPassword
                (member.getUsername(), member.getPassword());
    }
    
  3. 在utils包中的MemberServiceImplTest類中增加測試方法

    @Test
    public void login() {
        Member member = memberService.login
                (new Member(null, "admin", "admin", null));
        System.out.println("member=" + member);
    }
    
    image-20221216185341949

    代碼測試通過

5.3.3web層

  1. 配置loginServlet

    <servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>com.li.furns.web.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/loginServlet</url-pattern>
    </servlet-mapping>
    
  2. 創建LoginServlet

    package com.li.furns.web;
    
    import com.li.furns.entity.Member;
    import com.li.furns.service.MemberService;
    import com.li.furns.service.impl.MemberServiceImpl;
    
    import javax.servlet.*;
    import javax.servlet.http.*;
    import java.io.IOException;
    
    public class LoginServlet extends HttpServlet {
        private MemberService memberService = new MemberServiceImpl();
    
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request, response);
        }
    
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //1.接收用戶名和密碼
            //如果前端輸入的是null,後臺接收的數據為空串""
            String username = request.getParameter("username");
            String password = request.getParameter("password");
    
            //構建一個member對象
            Member member = new Member(null, username, password, null);
            //2.調用MemberServiceImpl的login方法
            if (memberService.login(member) == null) {//資料庫中沒有該用戶,返回登錄頁面
                //註意路徑
                request.getRequestDispatcher("/views/member/login.html")
                        .forward(request, response);
            } else {
                //否則,跳轉到登錄成功頁面
                request.getRequestDispatcher("/views/member/login_ok.html")
                        .forward(request, response);
            }
        }
    }
    

5.4完成測試

image-20221216192022479 image-20221216191948442

6.功能05-登錄錯誤提示,表單回顯

6.1需求分析/圖解

image-20221216191834383
  1. 輸入用戶名,密碼後提交
  2. 如果輸入有誤,則給出提示
  3. 在登錄表單回顯用戶名

6.2思路分析

在5.2分析圖的基礎上修改如下兩處:

image-20221216193057250

6.3代碼實現

6.3.1web層

  1. 修改LoginServlet,將錯誤提示和用戶名放入request域中

    package com.li.furns.web;
    
    import com.li.furns.entity.Member;
    import com.li.furns.service.MemberService;
    import com.li.furns.service.impl.MemberServiceImpl;
    
    import javax.servlet.*;
    import javax.servlet.http.*;
    import java.io.IOException;
    
    public class LoginServlet extends HttpServlet {
        private MemberService memberService = new MemberServiceImpl();
    
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request, response);
        }
    
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //1.接收用戶名和密碼
            //如果前端輸入的是null,後臺接收的數據為空串""
            String username = request.getParameter("username");
            String password = request.getParameter("password");
    
            //構建一個member對象
            Member member = new Member(null, username, password, null);
    
            //2.調用MemberServiceImpl的login方法
            if (memberService.login(member) == null) {//資料庫中沒有該用戶,返回登錄頁面
                //登錄失敗,將錯誤信息和登錄會員名放入request域中
                request.setAttribute("errInfo", "登錄失敗,用戶名或者密碼錯誤");
                request.setAttribute("username", username);
                //註意路徑
                request.getRequestDispatcher("/views/member/login.jsp")
                        .forward(request, response);
            } else {
                //否則,跳轉到登錄成功頁面
                request.getRequestDispatcher("/views/member/login_ok.html")
                        .forward(request, response);
            }
        }
    }
    
  2. 將login.html改為login.jsp(文件右鍵Refactor-->Rename,在彈窗中點擊Do Refactor,會把其他文件引用login.html的信息自動改為login.jsp)

    部分代碼,詳細代碼請看 https://github.com/liyuelian/furniture_mall.git

    <div class="login-register-form">
        <%--提示錯誤信息--%>
        <span class="errorMsg" 
              style="float: right; font-weight: bold; font-size: 20pt; margin-left: 10px;">
            ${requestScope.errInfo}
        </span>
        <form action="loginServlet" method="post">
            <input type="text" name="username" placeholder="Username" value="${requestScope.username}"/>
            <input type="password" name="password" placeholder="Password"/>
            <div class="button-box">
                <div class="login-toggle-btn">
                    <input type="checkbox"/>
                    <a class="flote-none" href="javascript:void(0)">Remember me</a>
                    <a href="#">Forgot Password?</a>
                </div>
                <button type="submit"><span>Login</span></button>
            </div>
        </form>
    

6.4完成測試

image-20221216201148932 image-20221216201221612

7.功能06-web層servlet減肥

7.1需求分析/圖解

image-20221216204810122
  1. 如圖,一個請求對應一個Servlet,會造成Servlet太多,不利於管理
  2. 在項目開發中,同一個業務(模塊),一般對應一個Servlet即可,比如LoginServlet和RegisterServlet都處理和會員相關的業務,應當合併

7.2方案一-if-else

image-20221216210835186

前端頁面兩個表單login和register的action都提交到MemberServlet中

  1. 分別給兩個表單添加hidden元素,分別表示註冊和登錄
  2. 當信息提交到MemberServlet後,獲取action參數值
  3. 再根據不同的值來調用對應的方法即可(將原來的業務分別封裝到login方法和Register方法中)

7.3方案一代碼實現

  1. 修改login.jsp,分別在login和register表單中添加hidden,兩個表單都提交到MemberServlet處理

    image-20221216211107418 image-20221216211200389
  2. 在web.xml中配置MemberServlet

    <servlet>
        <servlet-name>MemberServlet</servlet-name>
        <servlet-class>com.li.furns.web.MemberServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MemberServlet</servlet-name>
        <url-pattern>/memberServlet</url-pattern>
    </servlet-mapping>
    
  3. 實現MemberServlet

    package com.li.furns.web;
    
    import com.li.furns.entity.Member;
    import com.li.furns.service.MemberService;
    import com.li.furns.service.impl.MemberServiceImpl;
    
    import javax.servlet.*;
    import javax.servlet.http.*;
    import java.io.IOException;
    
    public class MemberServlet extends HttpServlet {
        private MemberService memberService = new MemberServiceImpl();
    
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request, response);
        }
    
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //獲取提交表單的hidden元素值,判斷進行login還是register業務
            String action = request.getParameter("action");
            if ("login".equals(action)) {
                //進入登錄業務
                login(request, response);
    
            } else if ("register".equals(action)) {
                //進入註冊業務
                register(request, response);
            }
        }
    
        public void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //1.接收用戶名和密碼
            //如果前端輸入的是null,後臺接收的數據為空串""
            String username = request.getParameter("username");
            String password = request.getParameter("password");
    
            //構建一個member對象
            Member member = new Member(null, username, password, null);
    
            //2.調用MemberServiceImpl的login方法
            if (memberService.login(member) == null) {//資料庫中沒有該用戶,返回登錄頁面
                //登錄失敗,將錯誤信息和登錄會員名放入request域中
                request.setAttribute("errInfo", "登錄失敗,用戶名或者密碼錯誤");
                request.setAttribute("username", username);
                //註意路徑
                request.getRequestDispatcher("/views/member/login.jsp")
                        .forward(request, response);
            } else {
                //否則,跳轉到登錄成功頁面
                request.getRequestDispatcher("/views/member/login_ok.html")
                        .forward(request, response);
            }
        }
    
        public void register(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //接收用戶註冊信息--參數名要以前端頁面的變數名為準
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            String email = request.getParameter("email");
    
            //如果返回false,說明該用戶信息可以註冊
            if (!memberService.isExistsUsername(username)) {
                //構建一個member對象
                Member member = new Member(null, username, password, email);
                if (memberService.registerMember(member)) {
                    //如果註冊成功,請求轉發到register_ok.html
                    request.getRequestDispatcher("/views/member/register_ok.html")
                            .forward(request, response);
                } else {
                    //註冊失敗,請求轉發到register_fail.html
                    request.getRequestDispatcher("/views/member/register_fail.html")
                            .forward(request, response);
                }
            } else {//否則不能進行註冊
                //請求轉發到login.html
                //後面可以加入提示信息
                request.getRequestDispatcher("/views/member/login.jsp")
                        .forward(request, response);
            }
        }
    }
    

7.4方案二-反射+模板設計模式+動態綁定

雖然方案一也可以實現業務需求,但是隨著業務的增加,if-else語句也會隨之增多,代碼可讀性變差,因此這裡使用第二種方案實現,思想如下:

image-20221216220943007 image-20221216220928145

每一個業務Servlet類中都會有doPost和doGet方法,現在創建一個BasicServlet抽象類,其他的業務Servlet類都繼承BasicServlet抽象類。

將業務類中的doPost和doGet方法抽象到BasicServlet中,當http請求到業務類時,因為業務類中沒有重寫doPost和doGet,就會到父類BasicServlet中找並調用。

同時在父類BasicServlet的doPost()方法中使用動態綁定,通過反射去獲取到子類中的某個業務方法,然後調用。

7.5方案二代碼實現

  1. 修改MemberServlet,將doPost方法抽象到父類BasicServlet中:

    package com.li.furns.web;
    
    import com.li.furns.entity.Member;
    import com.li.furns.service.MemberService;
    import com.li.furns.service.impl.MemberServiceImpl;
    
    import javax.servlet.*;
    import javax.servlet.http.*;
    import java.io.IOException;
    
    /**
     * 該Servlet處理和Member相關的請求
     *
     * @author 李
     * @version 1.0
     */
    public class MemberServlet extends BasicServlet {
        private MemberService memberService = new MemberServiceImpl();
    
        /**
         * 處理會員登錄業務
         *
         * @param request
         * @param response
         * @throws ServletException
         * @throws IOException
         */
        public void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //1.接收用戶名和密碼
            //如果前端輸入的是null,後臺接收的數據為空串""
            String username = request.getParameter("username");
            String password = request.getParameter("password");
    
            //構建一個member對象
            Member member = new Member(null, username, password, null);
    
            //2.調用MemberServiceImpl的login方法
            if (memberService.login(member) == null) {//資料庫中沒有該用戶,返回登錄頁面
                //登錄失敗,將錯誤信息和登錄會員名放入request域中
                request.setAttribute("errInfo", "登錄失敗,用戶名或者密碼錯誤");
                request.setAttribute("username", username);
                //註意路徑
                request.getRequestDispatcher("/views/member/login.jsp")
                        .forward(request, response);
            } else {
                //否則,跳轉到登錄成功頁面
                request.getRequestDispatcher("/views/member/login_ok.html")
                        .forward(request, response);
            }
        }
    
        /**
         * 處理會員註冊業務
         *
         * @param request
         * @param response
         * @throws ServletException
         * @throws IOException
         */
        public void register(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //接收用戶註冊信息--參數名要以前端頁面的變數名為準
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            String email = request.getParameter("email");
    
            //如果返回false,說明該用戶信息可以註冊
            if (!memberService.isExistsUsername(username)) {
                //構建一個member對象
                Member member = new Member(null, username, password, email);
                if (memberService.registerMember(member)) {
                    //如果註冊成功,請求轉發到register_ok.html
                    request.getRequestDispatcher("/views/member/register_ok.html")
                            .forward(request, response);
                } else {
                    //註冊失敗,請求轉發到register_fail.html
                    request.getRequestDispatcher("/views/member/register_fail.html")
                            .forward(request, response);
                }
            } else {//否則不能進行註冊
                //請求轉發到login.html
                //後面可以加入提示信息
                request.getRequestDispatcher("/views/member/login.jsp")
                        .forward(request, response);
            }
        }
    }
    
  2. 創建BasicServlet,在該抽象類中使用使用模板模式+反射+動態綁定

    package com.li.furns.web;
    
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.lang.reflect.Method;
    
    /**
     * 業務servlet的共同父類
     * BasicServlet 是供子類去繼承的,不需要在web.xml中配置
     * 使用模板模式+反射+動態綁定===>簡化了多個if-else的語句
     *
     * @author 李
     * @version 1.0
     */
    public abstract class BasicServlet extends HttpServlet {
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //獲取提交表單的隱藏域元素的值
            //如果我們使用模板模式+反射+動態綁定,要滿足action的值要和方法名一致
            String action = req.getParameter("action");
    
            //使用反射,獲取到當前對象的方法
            //1.this就是請求的業務Servlet,即運行類型
            //2.declaredMethod 方法對象就是當前請求的業務servlet對應的action名稱的方法
            try {
                /**
                 * public Method getDeclaredMethod(){}
                 * 該方法返回一個Method對象,它反射此Class對象所表示的類或介面的指定已聲明方法。
                 * 參數:此方法接受兩個參數:
                 * -方法名稱,這是要獲取的方法。
                 * -參數類型 這是指定的方法的參數類型的數組。
                 * 返回值:此方法以 Method 對象的形式返回此類的指定方法。
                 */
                Method declaredMethod =
                        this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
                //使用方法對象進行反射調用
                //public Object invoke(Object obj, Object... args){}
                declaredMethod.invoke(this, req, resp);
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

之後再去開發業務類,只需要繼承BasicServlet即可,推薦使用方案二

7.6完成測試

註冊業務:

image-20221216212506916 image-20221216212521536

image-20221216212552315

登錄業務:

image-20221216212830237 image-20221216212847672


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Kerberos,在古希臘神話故事中,指的是一隻三頭犬守護在地獄之門外,禁止任何人類闖入地獄之中。 那麼在現實中,Kerberos指的是什麼呢? 一、Kerberos介紹 01 Kerberos是什麼 根據百度詞條釋義,Kerberos是一種電腦網路授權協議,用來在非安全網路中,對個人通信以安全的 ...
  • 近日,華為分析服務6.9.0版本發佈,正式上線探索能力。開發者可自由定義與配置分析模型,支持報告實時預覽,數據洞察體驗更加靈活與便捷。 新上線的探索能力中,有漏斗分析、事件歸因、會話路徑分析三個高級分析模型。在原有能力的基礎上,時效性進一步增強,開發者在完成配置與報告創建後,即能查看具體內容。通過低 ...
  • 隨著新一代信息技術與汽車產業的深度融合,智能網聯汽車正逐漸成為汽車產業發展的戰略制高點,無論是傳統車企還是新勢力都瞄準了“智能座艙”這種新一代人機交互方式。面對競爭如此激烈的車機市場,華為鴻蒙車機系統的出現,給消費者帶來了不同凡響的便捷使用感受,這得益於華為在硬體、軟體和場景優化上的技術優勢,用戶只 ...
  • 好家伙,本篇為《JS高級程式設計》第六章“集合引用類型”學習筆記 1.數組的複製和填充 批量複製方法 copyWithin(),以及填充數組方法fill()。 這兩個方法的函數簽名類似,都需要指定既有數組實例上的一個範圍,包含開始索引,不包含結束索引。 使用這個方法不會改變數組的大小。 1.1.fi ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 介紹 可曾想過我們每次創建新項目,或者換地方寫程式,都要把之前寫過的工具類找出來又要複製粘貼一遍有些麻煩,尤其是寫uni-app自定義模板主要還是開發工具完成的。這時為什麼不自己做一款自己的uni-app工具箱,每次用直接從商城導入就行了 ...
  • 在學習 jsp 的過程中,使用 IDEA 軟體新建 web 文件,右擊新建 jsp 時,沒有找到 jsp 文件。可能是沒有添加 web 路徑,該如何解決呢? ...
  • 作者:倪新明 ADR是一種性價比非常高的架構決策文檔化實踐,團隊引入和實踐成本很低,卻能為團隊帶來極大收益! 1 團隊研發麵臨的問題 不論是在傳統的IT行業,還是互聯網行業,研發團隊在架構決策層面或多或少的都會面臨以下問題或挑戰: •新成員加入團隊,對系統現有的架構決策可能會盲目遵守,只知其然,不知 ...
  • 1、設計想法 原理與之前的串口發送模塊一樣,1位的數據位和8位的數據位再加上1位的停止位。唯一不同的是在接收的時候要考慮到有干擾的情況下,為了避免干擾,我們對每位數據進行多次採樣,按出現概率大的值為該數據位的值。 如果按照通常想法在每bits位中間取值的話,bit3位出現圖中的干擾很有可能會讀出錯誤 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...