家居网购项目实现02

5.功能04-会员登录

5.1需求分析/图解

需求如图:

  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);
    }

    代码测试通过

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);
    }

    代码测试通过

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完成测试


6.功能05-登录错误提示,表单回显

6.1需求分析/图解

  1. 输入用户名,密码后提交
  2. 如果输入有误,则给出提示
  3. 在登录表单回显用户名

6.2思路分析

在5.2分析图的基础上修改如下两处:

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完成测试


7.功能06-web层servlet减肥

7.1需求分析/图解

  1. 如图,一个请求对应一个Servlet,会造成Servlet太多,不利于管理
  2. 在项目开发中,同一个业务(模块),一般对应一个Servlet即可,比如LoginServlet和RegisterServlet都处理和会员相关的业务,应当合并

7.2方案一-if-else

前端页面两个表单login和register的action都提交到MemberServlet中

  1. 分别给两个表单添加hidden元素,分别表示注册和登录
  2. 当信息提交到MemberServlet后,获取action参数值
  3. 再根据不同的值来调用对应的方法即可(将原来的业务分别封装到login方法和Register方法中)

7.3方案一代码实现

  1. 修改login.jsp,分别在login和register表单中添加hidden,两个表单都提交到MemberServlet处理


  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语句也会随之增多,代码可读性变差,因此这里使用第二种方案实现,思想如下:


每一个业务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完成测试

注册业务:

登录业务:

day03-功能实现02的更多相关文章

  1. ECMAScript es6新功能讲解视频教程

    下载链接:https://www.yinxiangit.com/1.html 目录: 01.课程介绍-ECMAScript 新功能.mp402.块的作用域-let.mp403.恒量-const.mp4 ...

  2. 【Centos】Centos7.5取消自动锁屏功能

    目录 00. 目录 01. 问题描述 02. 问题分析 03. 解决办法 04. 附录 00. 目录 @ 参考博客:[Centos]Centos7.5取消自动锁屏功能 01. 问题描述 Centos7 ...

  3. Java中FilterInputStream和FilterOutputStream的用法

    FilterInputStream FilterInputStream 的作用是用来"封装其它的输入流,并为它们提供额外的功能".它的常用的子类有BufferedInputStre ...

  4. JAVA IO 字节流与字符流

    文章出自:听云博客 题主将以三个章节的篇幅来讲解JAVA IO的内容 . 第一节JAVA IO包的框架体系和源码分析,第二节,序列化反序列化和IO的设计模块,第三节异步IO. 本文是第一节.     ...

  5. 从下拉菜单拖拽一个元素 出来,插入到页面中的app 列表中

    1,实现功能:从下拉菜单拖拽一个元素 出来,插入到页面中的app 列表中 并实现app向后移动一个元素的位置: 2.实现思路: 01.遍历下拉菜单,添加拖拽方法,实现位置移动功能: 02.遍历app列 ...

  6. ThinkPHP项目CMS内容管理系统开发视频教程【20课】(3.02GB)

    ThinkPHP背景介绍:     ThinkPHP是一个免费开源的,快速.简单的面向对象的轻量级PHP开发框架,遵循Apache2开源协议发布,是为了敏捷WEB应用开发和简化企业级应用开发而诞生的. ...

  7. Sharepoint中有关文件夹的操作

    1.GetItemsWithUniquePermissions根据返回数量和是否返回文件夹获取唯一权限的列表项集合 对于SharePoint对象模型中SPList的GetItemsWithUnique ...

  8. IaaS层市场科普

    简介 这是本博客系列云计算相关文章中的第二篇,所有文章请参考: 博客所有文章 本文主要介绍了一下当前IaaS层市场上的几个主要角色,这几个角色的历史发展以及现状. 开源市场 CloudStack 一句 ...

  9. 23种设计模式全解析 (java版本)

    转自:http://blog.csdn.net/longyulu/article/details/9159589 其中PHP常用的五种设计模式分别为:工厂模式,单例模式,观察者模式,策略模式,命令模式 ...

  10. nodejs+websocket制作聊天室视频教程

    本套教程主要讲解了node平台的安装,node初级知识.node 服务器端程序响应http请求,通过npm安装第三方包,websocket即时通讯.聊天页面界面制作.拖动原理.拖动效果.遮罩效果.定位 ...

随机推荐

  1. 14. Fluentd输出插件:out_forward用法详解

    out_forward是一个带缓存的输出插件,用于向其他节点转发日志事件,并支持转发节点之间的负载均衡和自动故障切换. out_forward支持至多一次和至少一次传输模式,默认为至多一次. out_ ...

  2. PAT (Basic Level) Practice 1008 数组元素循环右移问题 分数 20

    一个数组A中存有N(>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(≥0)个位置,即将A中的数据由(A0​A1​⋯AN−1​)变换为(AN−M​⋯AN−1​A0​A1​⋯AN ...

  3. Gson的使用与理解

    当今社会下,前后端分离,不同系统的信息交互,消息队列的数据传递,微服务的不同服务之间的数据处理,越来越多地方用到了序列化.序列化作为不同系统不同服务之间的数据桥梁.那么方便快捷的序列化工具还是必要的. ...

  4. 齐博x1如何取消某个标签的缓存时间

    标签默认会有缓存, 如果你要强制取消缓存时间的话, 可以加上下面的参数 time="-1"如下图所示 标签默认缓存时间是10分钟, 你也可以改成其它时间 比如 time=" ...

  5. F118校准(二)-- 操作步骤(使用PX01 PG点屏,并使用PX01 PG校准F118)

    1. 准备工作 硬件连接: CA310通过USB线材连接PC PX01通过USB线材连接PC F118通过灰排线连接PX01左上角的GPIO扩展口(如下图所示) LCM连接PX01 启动LcdTool ...

  6. JDK8下载安装及环境配置

    Java基础知识 Java的三种版本 JavaSE :标准版,主要用于开发桌面程序,控制台开发等等 JavaME:嵌入式开发,主要用于开发手机,小家电等等,目前使用的比较少 JavaEE:企业级开发, ...

  7. 二、Kubernetes 概念介绍

    一.Master ​ Master指的是集群控制节点,在每个Kubernetes集群里都需要有一个Master来负责整个集群的管理和控制,基本上Kubernetes的所有控制命令都发给它,它负责具体的 ...

  8. c语言求输入的任一整数的各位数之和

    c语言求解代码: # include<stdio.h> int main(void){ int a,i=0,sum=0; scanf("%d",&a); if( ...

  9. Nginx四层负载均衡1

    1.Nginx负载均衡Redis 服务器 IP地址 作用 系统版本 Nginx代理服务器 10.0.0.38 负载均衡服务器 Rocky8.6 Redis服务器1 10.0.0.18 Redis服务器 ...

  10. Java Timer使用介绍

    java.util包下提供了对定时任务的支持,涉及2个类: Timer:定时器类 TimerTask:任务抽象类 使用该定时任务我们需要继承TimerTask抽象类,覆盖run方法编写任务执行代码,并 ...