Java书城项目笔记(01) ── 注册、登录功能的实现





介绍

本套笔记是为了记录Java的学习过程,项目来源;尚硅谷书城项目。该项目的主要功能有:用户注册及登陆、购物车操作、结算及生成订单号、管理员管理图书、管理员管理订单。

修改成jsp页面并且导入JSTL标签库

将所有的html页面全都转换成jsp页面,只需要简单的将后缀名改成jsp,然后加上下述代码即可。修改完成了以后可能有些引入的网址后缀名不会变化,这里不用担心,因为页面比较少,发现一处改一处即可。

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

对公共部分进行抽取

拿到页面以后我们发现有很多公共的部分,我们可以将这些这些公共的部分抽取出来,这样修改的时候只需要修改一份就可以了

head部分

每个页面的head部分都需要引入css文件、jQuery文件以及需要设置标签,我们可以抽成一个jsp然后进行引入就可以
抽取出来的内容:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+ request.getContextPath()+"/";
%>
<base href="<%=basePath%>">
<link type="text/css" rel="stylesheet" href="static/css/style.css" >
<script type="text/javascript" src="static/script/jquery-1.7.2.js"></script>

在其他页面引入:

<%@ include file="/pages/common/head.jsp"%>

底部声明部分

每个页面底部都有声明部分,为了便于管理也可以都抽取出来
抽取部分代码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div id="bottom">
		<span>
			尚硅谷书城.Copyright &copy;2015
		</span>
</div>

引入代码:

<%@ include file="/pages/common/foot.jsp"%>

登录成功后的菜单部分

登录成功以后会有“欢迎xxx光临尚硅谷书城”这部分信息,我们进行抽取
抽取代码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div>
    <span>欢迎<span class="um_span">韩总</span>光临尚硅谷书城</span>
    <a href="pages/order/order.jsp">我的订单</a>
    <a href="index.jsp">注销</a>&nbsp;&nbsp;
    <a href="index.jsp">返回</a>
</div>

引入代码:

<%@ include file="/pages/common/login_sucess_menu.jsp"%>

后台的菜单部分

后台管理有“ 图书管理 订单管理 返回商城”这个菜单栏,我们进行抽取
抽取代码:

在这里插入代码片

引入代码:

<%@ include file="/pages/common/manager_menu.jsp"%>

数据库用户表的创建

想要永久化用户数据,必然是需要用到数据库,在本模块中创建一个b_user表,用来存放用户的id、账号、密码和邮箱信息。
首先创建book_stu数据库及b_user表,创建的sql语句如下:

CREATE DATABASE book_stu;
USE book_stu;

CREATE TABLE b_user(
	`id` INT PRIMARY KEY AUTO_INCREMENT,
	`username` VARCHAR(20) NOT NULL UNIQUE,
	`password` VARCHAR(20) NOT NULL,
	`email` VARCHAR(200)
);

然后我们插入几条数据,然后查询出来,确保数据库能够能正常工作:

INSERT INTO b_user(`username`,`password`,`email`) VALUE('admin','admin','admin@163.com');
INSERT INTO b_user(`username`,`password`,`email`) VALUE('lxy','lxy','lxy@163.com');
SELECT * FROM b_user

对用户提交的表单进行验证

我们拿到本网站的静态页面,打开注册和登录部分,会看到注册的时候需要填写用户名称、用户密码、确认密码、电子邮件、验证码以及登录的时候需要填写用户名称和用户密码。为了更好的用户体验没我们要在前端使用js进行验证,保证确认密码和用户密码要相同,并且其他项不为空。

在这里插入图片描述
在这里插入图片描述

导入jQuery

首先在web目录下的static目录创建一个script目录,用来存放jQuery,然后将jQuery复制进去。然后我们在login.html和regist.html中引入jQuery。

	<script src="../../static/script/jquery-1.7.2.js" type="text/javascript"></script>

js验证

判断确认密码和用户密码是否相同,并且其他项是否不为空,代码如下:
regist中:

$(function () {

			$("#sub_btn").click(function () {
                //验证用户名
                var usernameText = $("#username").val();
                var usernamePatt = /^\w{5,12}$/;
                if(!(usernamePatt.test(usernameText)))
                {
                    $(".errorMsg").text("用户名输入不合法")
                    return false;
                }
                //验证密码
                var passwordText = $("#password").val();
                var passwordPatt = /^\w{5,12}$/;
                if(!(passwordPatt.test(passwordText))){
                    $(".errorMsg").text("密码输入不合法");
                    return false;
                }
                //验证确认密码
                var repwd = $("#repwd").val();
                if(repwd != passwordText)
                {
                    $(".errorMsg").text("确认密码和密码不一致");
                    return false;
                }
                //验证邮箱
                var emailText = $("#email").val();
                var emailPatt = /^[a-z\d]+(\.[a-z\d]+)*@([\da-z](-[\da-z])?)+(\.{1,2}[a-z]+)+$/;
                if (!emailPatt.test(emailText)) {
                    $("span.errorMsg").text("邮箱格式不合法!");

                    return false;
                }

                //验证验证码
                var code = $("#code").val();
                //验证码去前后空格
                code = $.trim(code);
                if(code == null || code=="")
                {
                    $("span.errorMsg").text("验证码不能为空!");
                    return false;
                }

                //都正确的话清空错误提示信息
                $("span.errorMsg").text("");

            });

        });

login中:

		$(function () {
			$("#sub_btn").click(function () {
                //验证用户名
                var usernameText = $("#username").val();
                var usernamePatt = /^\w{5,12}$/;
                if(!(usernamePatt.test(usernameText)))
                {
                    $(".errorMsg").text("用户名输入不合法")
                    return false;
                }
                //验证密码
                var passwordText = $("#password").val();
                var passwordPatt = /^\w{5,12}$/;
                if(!(passwordPatt.test(passwordText))){
                    $(".errorMsg").text("密码输入不合法");
                    return false;
                }
            });
        });

编写pojo、dao、service、servlet

编写pojo

将用户抽象成User类、有id,username、password、email四个属性。再提供空参构造器、无参构造器、get和set方法、tostring方法。

    private Integer id;
    private String username;
    private String password;
    private String email;

编写dao

首先导入duutils和druid两个jar包,然后创建一个BaseDao类,在这个类中实现通用的增删改查功能。
1.首先创建jdbc.properties配置文件,在文件中填写好数据库账号密码等相关关信息。

username=root
password=root
url=jdbc:mysql://localhost:3306/book
driverClassName=com.mysql.jdbc.Driver
initialSize=5
maxActive=10

2.编写JdbcUtil类,主要用来获取数据库连接和关闭数据库连接。

public class JdbcUtils {

    private static DruidDataSource dataSource;

    static {
        try {
            Properties properties = new Properties();
            InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
            properties.load(is);
            dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @return
     * @Author glq
     * @Description 使用德鲁伊获取数据库链接
     * @Date 14:04 2020/4/18
     * @Param
     **/
    public static Connection getConnection()  {
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    /**
     * @Author glq
     * @Description //TODO 关闭数据库链接
     * @Date 14:08 2020/4/18
     * @Param [conn]
     * @return void
     **/
    public static void close(Connection conn){
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

}

3.编写BaseDao类,主要用来实现通用的增删改、查询获取一个JavaBean对象、查询获取JavaBean集合、查询一些特殊的(一行一列)。

public class BaseDao {

    private QueryRunner queryRunner = new QueryRunner();


   /**
    * @Author glq
    * @Description 通用的增删改操作
    * @Date 13:07 2020/4/18
    * @Param [sql, arg]
    * @return 成功返回影响的行数,失败返回-1
    **/
    public int update(String sql,Object... arg){
        Connection connection = JdbcUtils.getConnection();

        try {
            return queryRunner.update(connection,sql,arg);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.close(connection);
        }
        return -1;

    }

    /**
     * @Author glq
     * @Description //TODO 查询一个bean
     * @Date 14:16 2020/4/18
     * @Param [clazz, sql, arg]
     * @return
     **/
    public <T> T queryForOne(Class<T> clazz,String sql,Object... arg){
        Connection connection = JdbcUtils.getConnection();
        try {
            return queryRunner.query(connection,sql,new BeanHandler<T>(clazz),arg);
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.close(connection);
        }
        return null;
    }

    /**
     * @Author glq
     * @Description //TODO 查询获取多个JavaBean
     * @Date 14:20 2020/4/18
     * @Param [clazz, sql, args]
     * @return java.util.List<T>
     **/
    public <T> List<T> queryForList(Class<T> clazz,String sql,Object ... args){
        Connection connection = JdbcUtils.getConnection();
        try {
            return queryRunner.query(connection,sql,new BeanListHandler<T>(clazz),args);
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.close(connection);
        }
        return null;
    }
    /**
     * @Author glq
     * @Description //TODO 查询返回一行一列
     * @Date 14:22 2020/4/18
     * @Param [sql, args]
     * @return java.lang.Object
     **/
    public Object queryForSingleValue(String sql,Object ... args){
        Connection connection = JdbcUtils.getConnection();
        try {
            return queryRunner.query(connection,sql,new ScalarHandler(),args);
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.close(connection);
        }
        return null;

    }

}

4.编写UserDao接口和UserDaoImpl实现类, 主要实现根据用户名查询用户、根据用户名和密码查询用户、保存用户三个功能。

public class UserDaoImpl extends BaseDao implements UserDao {
    /**
     * @Author glq
     * @Description //TODO 根据用户名查询用户
     * @Date 15:33 2020/4/18
     * @Param [username]
     * @return com.glq.pojo.User
     **/
    @Override
    public User queryUserByUsername(String username) {
        String sql = "select * from b_user where username = ?";
        User user = queryForOne(User.class, sql, username);
        return user;
    }

    /**
     * @Author glq
     * @Description //TODO 根据用户名和密码查询用户
     * @Date 15:33 2020/4/18
     * @Param [username, password]
     * @return com.glq.pojo.User
     **/
    @Override
    public User queryUserByUsernameAndPassword(String username, String password) {
        String sql = "select * from b_user where username = ? and password = ?";
        User user = queryForOne(User.class, sql, username, password);
        return user;
    }

    /**
     * @Author glq
     * @Description //TODO 保存用户
     * @Date 15:33 2020/4/18
     * @Param [user]
     * @return int
     **/
    @Override
    public int saveUser(User user) {
        String sql = "insert into b_user(username,password,email) values(?,?,?)";
        int update = update(sql, user.getUsername(), user.getPassword(), user.getEmail());
        return update;
    }
}

编写servic

编写UserService接口和EserServiceImpl实现类,主要实现用户登录、用户注册、查询用户名是否存在三个功能。

public class UserServiceImpl implements UserService {
    private UserDaoImpl userDao = new UserDaoImpl();

    /**
     * @Author glq
     * @Description //TODO 用户注册
     * @Date 15:45 2020/4/18
     * @Param [user]
     * @return void
     **/
    @Override
    public void registUser(User user) {
        userDao.saveUser(user);
    }

    /**
     * @Author glq
     * @Description //TODO 用户登录
     * @Date 15:45 2020/4/18
     * @Param [user]
     * @return com.glq.pojo.User
     **/
    @Override
    public User login(User user) {
        User result_user = userDao.queryUserByUsernameAndPassword(user.getUsername(), user.getPassword());
        return result_user;
    }

    /**
     * @Author glq
     * @Description //TODO 查询用户名是否存在
     * @Date 15:46 2020/4/18
     * @Param [username]
     * @return boolean
     **/
    @Override
    public boolean exitsUsername(String username) {
        User user = userDao.queryUserByUsername(username);
        if(user == null){
            return false;
        }
        return true;
    }
}

测试数据库操作

测试Service中的登录、注册、验证用户名是否正确。若正确则dao中一般也不会出问题。

public class UserServiceImplTest {

    @Test
    public void registUser() {
        UserServiceImpl userService = new UserServiceImpl();
        userService.registUser(new User(null,"test","test","test@163.com"));

    }

    @Test
    public void login() {
        UserServiceImpl userService = new UserServiceImpl();
        User login = userService.login(new User(null, "lxy", "lxy", "sdfsdf"));
        System.out.println(login);
    }

    @Test
    public void exitsUsername() {
        UserServiceImpl userService = new UserServiceImpl();
        boolean lxy = userService.exitsUsername("lxy1");
        System.out.println(lxy);
    }
}

编写Servlet

1.首先编写一个BaseServlet类,让其他的类来继承这个类,然后在这个类中获取action参数,根据这个参数名使用反射的方式获取到同名方法,然后调用通用名方法。这样可以减少大量的if判断。

public class BaseServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html; charset=UTF-8");
        String action = req.getParameter("action");
        System.out.println("BaseServlet被调用,action:"+action);

        try {
            Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
            method.invoke(this,req,resp);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

2.编写UserServlet类,主要实现用户登录、用户注册、判断用户名是否存在、注销用户这四个功能。其中,用户注册的时候要注意判断输入的验证码是否正确,这里借助于谷歌验证码来生成。

public class UserServlet extends BaseServlet {
    private UserServiceImpl userService = new UserServiceImpl();

    /**
     * @Author glq
     * @Description //TODO 登录
     * @Date 17:17 2020/4/18
     * @Param [req, resp]
     * @return void
     **/
    protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        User login = userService.login(new User(null, username, password, null));
        if(login == null){
            req.setAttribute("msg","用户名或者密码错误!");
            req.setAttribute("username",username);
            req.getRequestDispatcher("/pages/user/login.jsp").forward(req,resp);
        }else{
            req.getSession().setAttribute("user",login);
            resp.sendRedirect("/pages/user/login_success.jsp");
        }
    }
    /**
     * @Author glq
     * @Description //TODO 注册
     * @Date 17:25 2020/4/18
     * @Param [req, resp]
     * @return void
     **/
    protected void regist(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String email = req.getParameter("email");
        String code = req.getParameter("code");

        String token = (String) req.getSession().getAttribute(KAPTCHA_SESSION_KEY);
        req.getSession().removeAttribute(KAPTCHA_SESSION_KEY);

        User user = WebUtils.copyParamToBain(req.getParameterMap(), new User());

        if(token!=null && token.equals(code)){
            if(userService.exitsUsername(username)){
                req.setAttribute("msg","用户名已存在!");
                req.setAttribute("username",username);
                req.setAttribute("email",email);
                req.getRequestDispatcher("/pages/user/regist.jsp").forward(req, resp);
            }else {
                userService.registUser(new User(null,username,password,email));
                req.getRequestDispatcher("/pages/user/regist_success.jsp").forward(req, resp);
            }
        }else{
            // 把回显信息,保存到Request域中
            req.setAttribute("msg", "验证码错误!!");
            req.setAttribute("username", username);
            req.setAttribute("email", email);

            System.out.println("验证码[" + code + "]错误");
            req.getRequestDispatcher("/pages/user/regist.jsp").forward(req, resp);
        }

    }

    /**
     * @Author glq
     * @Description //TODO 判断用户名是否存在
     * @Date 18:21 2020/4/18
     * @Param [req, resp]
     * @return void
     **/
    protected void ExitsUsername(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        boolean isExits = userService.exitsUsername(username);
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("existsUsername",isExits);
        Gson gson = new Gson();
        String json = gson.toJson(resultMap);
        resp.getWriter().write(json);

    }
    /**
     * @Author glq
     * @Description //TODO 注销用户
     * @Date 16:44 2020/4/19
     * @Param [req, resp]
     * @return void
     **/
    protected void logout(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("logout被调用");
        req.getSession().invalidate();
        resp.sendRedirect("index.jsp");
    }

}

页面的处理

登陆页面

1.首先要修改form表单的提交信息,修改为:

<form action="userServlet?action=login" method="post">

2.如果登录失败,我们希望页面回显已经输入的用户名信息和错误标签信息。修改后的代码为:

		<span class="errorMsg">${empty requestScope.msg ? "请输入用户名和密码":requestScope.msg}</span>
	</div>
	<div class="form">
		<form action="userServlet?action=login" method="post">
			<label>用户名称:</label>
			<input class="itxt" type="text" placeholder="请输入用户名" autocomplete="off" tabindex="1" name="username" id="username" value="${requestScope.username}"/>
			<br />
			<br />
			<label>用户密码:</label>
			<input class="itxt" type="password" placeholder="请输入密码" autocomplete="off" tabindex="1" name="password" id="password"/>
			<br />
			<br />
			<input type="submit" value="登录" id="sub_btn" />
		</form>
	</div>

注册页面

1.当输入用户名的内容发生改变的时候发送一个AJAX请求,来判断用户名是否存在,并且在错误标签输出相应的提示信息。

$("#username").blur(function () {

	var username = this.value;
	$.getJSON("userServlet","action=ExitsUsername&username="+username,function (data) {
		if(data.existsUsername){
			$(".errorMsg").text("用户名已经存在!");
		}else
		{
			$(".errorMsg").text("用户名可以使用!");

		}
	})

});

2.在点击验证码图片的时候刷新验证码图片的地址

	$("#code_img").click(function () {
			this.src="${basePath}kaptcha.jpg?d="+new Date();
    });

3.修改form表单的提交信息和用户名邮箱的回显

<form action="userServlet?action=regist" method="post">
	<label>用户名称:</label>
	<input class="itxt" type="text" placeholder="请输入用户名" autocomplete="off" tabindex="1" name="username" id="username" value="${requestScope.username}"/>
	<br />
	<br />
	<label>用户密码:</label>
	<input class="itxt" type="password" placeholder="请输入密码" autocomplete="off" tabindex="1" name="password" id="password" />
	<br />
	<br />
	<label>确认密码:</label>
	<input class="itxt" type="password" placeholder="确认密码" autocomplete="off" tabindex="1" name="repwd" id="repwd" />
	<br />
	<br />
	<label>电子邮件:</label>
	<input class="itxt" type="text" placeholder="请输入邮箱地址" autocomplete="off" tabindex="1" name="email" id="email" value="${requestScope.email}"/>
	<br />
	<br />
	<label>&nbsp;&nbsp;&nbsp;&nbsp;码:</label>
	<input class="itxt" type="text" name="code" style="width: 120px;" id="code" value=""/>
	<img id="code_img" alt="" src="kaptcha.jpg" style="float: right; margin-right: 40px; width: 100px; height: 40px;">
	<br />
	<br />
	<input type="submit" value="注册" id="sub_btn" />
	
</form>

注销

修改注销的地址,这里主要有两处,一处是抽取出来的公共部分中的,另一处是index.jsp中的。

<a href="userServlet?action=logout">注销</a>

测试

至此,用户部分的功能都已经完成了,测试一下是否能够正常注册、登录、注销。修改成jsp页面导致的链接错误只需要该一下即可。

谢谢大家的观看,如有错误请指正,谢谢!CSDN记录成长!

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值