day03-功能实现02
家居网购项目实现02
5.功能04-会员登录
5.1需求分析/图解
需求如图:
- 输入用户名、密码后提交
- 判断该用户是否存在
- 如果存在,显示登录成功页面
- 否则返回登录页面,要求重新登录
- 要求改进登录密码为md5加密
5.2思路分析
5.3代码实现
根据上述分析图,在对应的层添加方法
5.3.1dao层
修改MemberDAO接口,声明queryMemberByUsernameAndPassword()方法
//提供一个通过用户名和密码返回对应的Member的方法
public Member queryMemberByUsernameAndPassword(String username,String password);
修改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);
}
在utils包中的MemberDAOImplTest类中增加测试方法
@Test
public void queryMemberByUsernameAndPassword() {
Member member = memberDAO.queryMemberByUsernameAndPassword
("king", "king");
System.out.println("member=" + member);
}
代码测试通过
5.3.2service层
修改MemberService接口,声明login方法
//登录用户
//相比于直接传递用户名和密码,传递一个Member对象拓展性会比较好一些
public Member login(Member member);
修改MemberServiceImpl接口实现类,实现login方法
/**
* 根据登录传入的member信息,返回对应的在数据库中的member对象
*
* @param member
* @return 返回的是数据库中的member对象,若不存在则返回null
*/
@Override
public Member login(Member member) {
return memberDAO.queryMemberByUsernameAndPassword
(member.getUsername(), member.getPassword());
}
在utils包中的MemberServiceImplTest类中增加测试方法
@Test
public void login() {
Member member = memberService.login
(new Member(null, "admin", "admin", null));
System.out.println("member=" + member);
}
代码测试通过
5.3.3web层
配置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>
创建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需求分析/图解
- 输入用户名,密码后提交
- 如果输入有误,则给出提示
- 在登录表单回显用户名
6.2思路分析
在5.2分析图的基础上修改如下两处:
6.3代码实现
6.3.1web层
修改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);
}
}
}
将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需求分析/图解
- 如图,一个请求对应一个Servlet,会造成Servlet太多,不利于管理
- 在项目开发中,同一个业务(模块),一般对应一个Servlet即可,比如LoginServlet和RegisterServlet都处理和会员相关的业务,应当合并
7.2方案一-if-else
前端页面两个表单login和register的action都提交到MemberServlet中
- 分别给两个表单添加hidden元素,分别表示注册和登录
- 当信息提交到MemberServlet后,获取action参数值
- 再根据不同的值来调用对应的方法即可(将原来的业务分别封装到login方法和Register方法中)
7.3方案一代码实现
修改login.jsp,分别在login和register表单中添加hidden,两个表单都提交到MemberServlet处理
在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>
实现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方案二代码实现
修改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);
}
}
}
创建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的更多相关文章
- ECMAScript es6新功能讲解视频教程
下载链接:https://www.yinxiangit.com/1.html 目录: 01.课程介绍-ECMAScript 新功能.mp402.块的作用域-let.mp403.恒量-const.mp4 ...
- 【Centos】Centos7.5取消自动锁屏功能
目录 00. 目录 01. 问题描述 02. 问题分析 03. 解决办法 04. 附录 00. 目录 @ 参考博客:[Centos]Centos7.5取消自动锁屏功能 01. 问题描述 Centos7 ...
- Java中FilterInputStream和FilterOutputStream的用法
FilterInputStream FilterInputStream 的作用是用来"封装其它的输入流,并为它们提供额外的功能".它的常用的子类有BufferedInputStre ...
- JAVA IO 字节流与字符流
文章出自:听云博客 题主将以三个章节的篇幅来讲解JAVA IO的内容 . 第一节JAVA IO包的框架体系和源码分析,第二节,序列化反序列化和IO的设计模块,第三节异步IO. 本文是第一节. ...
- 从下拉菜单拖拽一个元素 出来,插入到页面中的app 列表中
1,实现功能:从下拉菜单拖拽一个元素 出来,插入到页面中的app 列表中 并实现app向后移动一个元素的位置: 2.实现思路: 01.遍历下拉菜单,添加拖拽方法,实现位置移动功能: 02.遍历app列 ...
- ThinkPHP项目CMS内容管理系统开发视频教程【20课】(3.02GB)
ThinkPHP背景介绍: ThinkPHP是一个免费开源的,快速.简单的面向对象的轻量级PHP开发框架,遵循Apache2开源协议发布,是为了敏捷WEB应用开发和简化企业级应用开发而诞生的. ...
- Sharepoint中有关文件夹的操作
1.GetItemsWithUniquePermissions根据返回数量和是否返回文件夹获取唯一权限的列表项集合 对于SharePoint对象模型中SPList的GetItemsWithUnique ...
- IaaS层市场科普
简介 这是本博客系列云计算相关文章中的第二篇,所有文章请参考: 博客所有文章 本文主要介绍了一下当前IaaS层市场上的几个主要角色,这几个角色的历史发展以及现状. 开源市场 CloudStack 一句 ...
- 23种设计模式全解析 (java版本)
转自:http://blog.csdn.net/longyulu/article/details/9159589 其中PHP常用的五种设计模式分别为:工厂模式,单例模式,观察者模式,策略模式,命令模式 ...
- nodejs+websocket制作聊天室视频教程
本套教程主要讲解了node平台的安装,node初级知识.node 服务器端程序响应http请求,通过npm安装第三方包,websocket即时通讯.聊天页面界面制作.拖动原理.拖动效果.遮罩效果.定位 ...
随机推荐
- python csv写入多列
import csv import os def main(): current_dir = os.path.abspath('.') file_name = os.path.join(current ...
- 面试突击87:说一下 Spring 事务传播机制?
Spring 事务传播机制是指,包含多个事务的方法在相互调用时,事务是如何在这些方法间传播的. 既然是"事务传播",所以事务的数量应该在两个或两个以上,Spring 事务传播机制的 ...
- 基于纯前端类Excel表格控件实现在线损益表应用
财务报表也称对外会计报表,是会计主体对外提供的反映企业或预算单位一定时期资金.利润状况的会计报表,由资产负债表.损益表.现金流量表或财务状况变动表.附表和附注构成.财务报表是财务报告的主要部分,不包括 ...
- 使用 Apache Hudi 实现 SCD-2(渐变维度)
数据是当今分析世界的宝贵资产. 在向最终用户提供数据时,跟踪数据在一段时间内的变化非常重要. 渐变维度 (SCD) 是随时间推移存储和管理当前和历史数据的维度. 在 SCD 的类型中,我们将特别关注类 ...
- LOJ2325「清华集训 2017」小Y和恐怖的奴隶主
题目链接 首先dp很显然,\(f(i,s)\)表示到了第i轮,各种血量人数的情况为s今后的期望攻击boss次数.那么有\(f(i,s)=\frac{1}{num+1}*\sum_{s->s'}( ...
- Linux基础_4_文件夹管理
文件路径 . #表示当前目录,同./ .. #表示上级目录,同../ ../../ #表示上上级目录 / #表示根目录 注:文件名长度不超过255个字符 注:.开头为隐藏文件 切换目录 cd #默认切 ...
- 构建Springboot项目、实现简单的输出功能、将项目打包成可以执行的JAR包(详细图解过程)
1.构建SpringBoot项目 大致流程 1.新建工程 2.选择环境配置.jdk版本 3.选择 依赖(可省略.后续要手动在pom文件写) 4.项目名 1.1 图解建立过程 1.2 项目结构 友情提示 ...
- 记一个深层的bug
1. 业务场景 产品需要每隔几天进行一次组件的更新,在自动化测试中,每隔30s检测一次更新源上的某个文件MD5值是否与本地一致,不一致代表有更新的版本,开始更新. 2. 问题出现 一个再平常不过的繁忙 ...
- 齐博X1-栏目的调用2
fun('sort@fathers',$fid,'cms') 获取上层多级栏目这样的,比如我们现在所属第三级栏目,现在可以利用这个函数获取第二级和第一级的栏目,当然自身也会被调用出来,所以此函数用的 ...
- 【第1篇】人工智能(AI)语音测试原理和实践---宣传
前言 本文主要介绍作者关于人工智能(AI)语音测试的各方面知识点和实战技术. 本书共分为9章,第1.2章详细介绍人工智能(AI)语音测试各种知识点和人工智能(AI)语音交互原理:第3.4章介绍人工智 ...