Javaweb学习笔记day07---项目二阶段

本文详细记录了JavaWeb项目第二阶段的搭建过程,包括使用base标签统一管理路径,实现静态数据登录功能,三层架构的概述与实现,UserDao和BaseDao类的创建,以及MD5和MD5+SALT加密在注册登录功能中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目二阶段搭建

  • 项目搭建
    • v1 -> v2
  • 开发步骤
    • ①创建javaweb项目
    • ②将bookstore-v1中的页面资源拷贝到bookstore-v2中
      • 修改vue.js路径,解决404问题

02-base标签

  • 概述
    • 因为在页面中有很多的a标签、表单以及Ajax请求(以后会学)都需要写访问路径,推荐大家写绝对路径,要求最前面是项目的访问路径,一旦项目的访问路径发生改变,要修改的地方特别多,那么, 能不能对项目的访问路径进行统一管理?可以使用base标签
  • 开发步骤
    • ①在login.html页面,使用base标签
    • ②在regist.html页面,使用base标签
  • ①在login.html页面,使用base标签
<head>
    <meta charset="UTF-8"/>
    <base href="/bookstore/">
    <title>尚硅谷会员登录页面</title>
    <link type="text/css" rel="stylesheet" href="static/css/style.css"/>
</head>

②在regist.html页面,使用base标签

<head>
    <meta charset="UTF-8"/>
    <base href="/bookstore/">
    <title>尚硅谷会员注册页面</title>
    <link type="text/css" rel="stylesheet" href="static/css/style.css"/>
    <link rel="stylesheet" href="static/css/register.css"/>
    <style type="text/css">
        .login_form {
            height: 420px;
            margin-top: 25px;
        }
    </style>
</head>

注意事项

  • base标签只会拼接到"相对路径"前面。

使用静态数据完成登录功能

  • 概述
    • 使用假数据完成登录功能
      • 如果登录成功,跳转到login_success.html
      • 如果登录失败,跳转回login.html
  • 代码实现
<form action="login" @submit="checkLogin()">
    <label>用户名称:</label>
    <input
            class="itxt"
            type="text"
            placeholder="请输入用户名"
            autocomplete="off"
            tabindex="1"
            name="username"
            id="username"
            @change="checkUsername()"
            v-model="username"
    />
    <br/>
    <br/>
    <label>用户密码:</label>
    <input
            class="itxt"
            type="password"
            placeholder="请输入密码"
            autocomplete="off"
            tabindex="1"
            name="password"
            id="password"
            @change="checkPassword()"
            v-model="password"
    />
    <br/>
    <br/>
    <input type="submit" value="登录" id="sub_btn"/>
</form>
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取登录表单中的用户输入数据
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if ("root".equals(username) && "root".equals(password)) {
            //登录成功 , 跳转到login_success.html (重定向)
            response.sendRedirect("/bookstore/pages/user/login_success.html");
        } else {
            //登录失败 , 跳转回login.html (请求转发)
            request.getRequestDispatcher("/pages/user/login.html").forward(request, response);
        }

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

三层架构概述

  • 存在问题
    • Servlet中要做的事太多了:处理请求、业务处理、操作数据库、调度页面(渲染页面)
    • 解决以上问题,就得使用三层架构
  • 三层架构
    • image-20211206151635355
    • 控制层 : controller
      • 处理请求、调度页面/渲染页面
    • 业务层 : service
      • 处理业务
    • 持久层 : dao
      • 操作数据库
  • 两个问题
    • 浏览器输入的数据如何传递给持久层?
      • 通过方法传参
    • 持久层封装的数据库结果如何传递给控制层?
      • 通过方法返回值

三层架构实现

  • 开发步骤
    • ①编写controller层代码
    • ②编写service层代码
    • ③编写dao层代码
  • ①编写controller层代码
/**
 * 控制层:处理请求、调度页面/渲染页面
 */
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //处理请求
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        UserService userService = new UserServiceImpl();
        try {
            User user = userService.login(username, password);
            //调度页面
            if (null != user) {
                //登录成功 , 跳转到login_success.html (重定向)
                response.sendRedirect("/bookstore/pages/user/login_success.html");
            } else {
                //登录失败 , 跳转回login.html (请求转发)
                request.getRequestDispatcher("/pages/user/login.html").forward(request, response);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }



    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

②编写service层代码

/**
 * 业务层:业务处理
 */
public class UserServiceImpl implements UserService {
    @Override
    public User login(String username, String password) throws Exception {
        UserDao userDao = new UserDaoImpl();
        User user = userDao.login(username, password);
        return user;
    }
}

③编写dao层代码

/**
 * 持久层:操作数据库
 */
public class UserDaoImpl implements UserDao {
    @Override
    public User login(String username, String password) throws Exception {
        if ("root".equals(username) && "root".equals(password)) {
            //登录成功,返回有效结果(User对象)给controller层
            return new User(username, password);
        } else {
            //登录失败,返回无效结果(null)给controller层
            return null;
        }
    }
}

UserDao类

  • DAO
    • data access object : 数据访问对象,用来操作数据库的对象
  • 开发步骤
    • ①引入sql备份文件
    • ②引入和数据库相关jar包
      • dbutils、druid、mysql
    • ③定义UserDao接口及其实现子类
      • CRUD
  • ①引入sql备份文件
  • ②引入和数据库相关jar包
  • ③定义UserDao接口及其实现子类

BaseDao类

  • 概述
    • 开发过程中,经常会对数据进行增删改查,比如说对学生的增删改查,老师的增删改查等 等。然而这时你会发现你所写的很多代码都是重复的,这时你就会考虑到代码的优化问题
  • 代码实现
public class BaseDao<T> {


    /**
     * 增加、删除、修改的通用方法
     *
     * @param sql  : sql语句
     * @param args : 输入参数
     */
    public int update(String sql, Object... args) {
        Connection connection = null;
        try {
            connection = JDBCUtils.getConnection();
            return new QueryRunner().update(
                    connection,
                    sql,
                    args
            );
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.release(connection, null);
        }
        return -1;
    }


    /**
     * 查询单条记录的通用方法
     *
     * @param sql   : sql语句
     * @param clazz : 字节码对象
     * @param args  : 输入参数
     * @return : 单条记录的对象
     */
    public T getBean(String sql, Class<T> clazz, Object... args) {
        Connection connection = null;
        try {
            connection = JDBCUtils.getConnection();
            return new QueryRunner().query(
                    connection,
                    sql,
                    new BeanHandler<>(clazz),
                    args
            );
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.release(connection, null);
        }
        return null;
    }


    /**
     * 查询多条记录的通用方法
     * @param sql : sql语句
     * @param clazz : 字节码对象
     * @param args : 输入参数
     * @return : 多条记录的集合
     */
    public List<T> getBeanList(String sql, Class<T> clazz, Object... args) {
        Connection connection = null;
        try {
            connection = JDBCUtils.getConnection();
            return new QueryRunner().query(
                    connection,
                    sql,
                    new BeanListHandler<>(clazz),
                    args
            );
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.release(connection, null);
        }
        return null;
    }

}
/**
 * 持久层:操作数据库
 */
public class UserDaoImpl extends BaseDao<User> implements UserDao {


    @Override
    public User login(String username, String password) throws Exception {
        if ("root".equals(username) && "root".equals(password)) {
            //登录成功,返回有效结果(User对象)给controller层
            return new User(1, username, password, "5415551@qq.com");
        } else {
            //登录失败,返回无效结果(null)给controller层
            return null;
        }
    }

    @Override
    public int addUser(User user) throws Exception {
        return update(
                "insert into t_user values(null,?,?,?)",
                user.getUserName(),
                user.getUserPwd(),
                user.getEmail()
        );
    }

    @Override
    public int deleteUserById(Integer userId) throws Exception {
        return update(
                "delete from t_user where user_id = ?",
                userId
        );

    }

    @Override
    public int updateUserById(User user) throws Exception {
        return update(
                "update t_user set user_name = ? , user_pwd = ? , email = ? where user_id = ?",
                user.getUserName(),
                user.getUserPwd(),
                user.getEmail(),
                user.getUserId()
        );
    }

    @Override
    public User selectUserById(Integer userId) throws Exception {
        return getBean(
                "select user_id userId , user_name userName , user_pwd  userPwd , email from t_user where user_id = ?",
                User.class,
                userId
        );
    }

    @Override
    public List<User> selectUserList() throws Exception {


        return getBeanList(
                "select user_id userId , user_name userName , user_pwd  userPwd , email from t_user ",
                User.class
        );
    }
}

注册功能的完成

  • 需求
    • 使用数据库完成注册功能
      • 如果注册成功,跳转到regist_success.html
      • 如果注册失败
        • 如果用户名已经存在,在页面上给出"用户名已经存在!"的错误提示
        • 其他错误,跳转回regist.html
  • 代码实现
<form action="regist" @submit="checkRegist()">
    <div class="form-item">
        <div>
            <label>用户名称:</label>
            <input type="text" placeholder="请输入用户名" @change="checkUsername()" v-model="username" name="userName"/>
        </div>
        <span class="errMess" v-text="usernameErrorMsg">用户名应为6~16位数字和字母组成</span>
    </div>
    <div class="form-item">
        <div>
            <label>用户密码:</label>
            <input type="password" placeholder="请输入密码" @change="checkPassword()" v-model="password" name="userPwd"/>
        </div>
        <span class="errMess" v-text="passwordErrorMsg">密码的长度至少为5位</span>
    </div>
    <div class="form-item">
        <div>
            <label>确认密码:</label>
            <input type="password" placeholder="请输入确认密码" @change="checkRePassword()" v-model="repassword"/>
        </div>
        <span class="errMess" v-text="repasswordErrorMsg">密码两次输入不一致</span>
    </div>
    <div class="form-item">
        <div>
            <label>用户邮箱:</label>
            <input type="text" placeholder="请输入邮箱" @change="checkEmail()" v-model="email" name="email"/>
        </div>
        <span class="errMess" v-text="emailErrorMsg">请输入正确的邮箱格式</span>
    </div>
    <div class="form-item">
        <div>
            <label>验证码:</label>
            <div class="verify">
                <input type="text" placeholder="" @change="checkCode()" v-model="code" name="code"/>
                <img src="static/img/code.bmp" alt=""/>
            </div>
        </div>
        <span class="errMess" v-text="codeErrorMsg">请输入正确的验证码</span>
    </div>
    <button class="btn">注册</button>
</form>
@WebServlet("/regist")
public class RegistServlet extends HttpServlet {


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //使用BeanUtils自动封装
        User inputUser = new User();
        try {
            BeanUtils.populate(inputUser, req.getParameterMap());
            System.out.println("inputUser = " + inputUser);
            UserService userService = new UserServiceImpl();
            //校验用户名是否存在
            User dbUser = userService.selectUserByUsername(inputUser.getUserName());
            if (null != dbUser) {
                //用户名已经存在
                resp.setContentType("text/html;charset=utf-8");
                resp.getWriter().write("<font color='red'>用户名已经存在!</font>");
                return;
            }

            int addUser = userService.addUser(inputUser);
            if (addUser > 0) {
                //添加成功 , 跳转到regist_success.html (重定向)
                resp.sendRedirect(req.getContextPath() + "/pages/user/regist_success.html");
            } else {
                //添加失败 , 跳转回regist.html (转发)
                req.getRequestDispatcher("/pages/user/regist.html").forward(req, resp);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
public class UserServiceImpl implements UserService {


    @Override
    public int addUser(User inputUser) throws Exception {
        UserDao userDao = new UserDaoImpl();
        return userDao.addUser(inputUser);
    }

    @Override
    public User selectUserByUsername(String userName) throws Exception {
        UserDao userDao = new UserDaoImpl();

        return userDao.selectUserByUsername(userName);
    }
}
public class UserDaoImpl extends BaseDao<User> implements UserDao {


    @Override
    public int addUser(User user) throws Exception {
        return update(
                "insert into t_user values(null,?,?,?)",
                user.getUserName(),
                user.getUserPwd(),
                user.getEmail()
        );
    }


    @Override
    public User selectUserByUsername(String userName) throws Exception {
        return getBean(
                "select user_id userId , user_name userName , user_pwd  userPwd , email from t_user where user_name = ?",
                User.class,
                userName
        );
    }
}

登录功能的完成(掌握)

  • 需求
    • 使用数据库完成登录功能
      • 登录成功,跳转到login_success.html
      • 登录失败,跳转到login.html
  • 代码实现
public class UserDaoImpl extends BaseDao<User> implements UserDao {


    @Override
    public User login(String username, String password) throws Exception {
        return getBean(
                "select user_id userId , user_name userName , user_pwd  userPwd , email from t_user where user_name = ? and user_pwd = ?",
                User.class,
                username,
                password
        );
    }
}

加密概述

  • 概述
    • 数据库密码不能存储明文,必须存储密文。
  • 分类
    • MD5
    • MD5+SALT

MD5加密

  • 概述
    • 一种被广泛使用的密码散列函数,可以产生出一个32字符的散列值(hash value)
  • 特点
    • 压缩性:任意长度的数据,算出的MD5值长度都是固定的。
    • 容易计算:从原数据计算出MD5值很容易。
    • 抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
    • 强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据是非常困难的。
  • 代码实现
public class Demo01 {

    public static void main(String[] args) {

        login();
        // regist();

    }

    private static void login() {
        //①获取明文
        String password = "xiaoqiu";
        //②获取MD5密文
        String md5Password = MD5Utils.generateMD5(password);
        //③现在MD5密文 和 存储在数据库的md5密文 匹配
        String dbPassword = "884f5b0b1bc2c720f886e25369a4320a";
        System.out.println(md5Password.equals(dbPassword) ? "登录成功!" : "登录失败!");


    }

    private static void regist() {
        //①获取明文
        String password = "oldqiu";
        //②获取MD5密文
        String md5Password = MD5Utils.generateMD5(password);
        //③存储MD5密文 : 884f5b0b1bc2c720f886e25369a4320a
        System.out.println("md5Password = " + md5Password);

    }

}

存在问题

  • 可以暴力破解MD5 : https://www.cmd5.com/

MD5+SALT加密

  • 概述
    • 在原有明文密码基础上加盐(salt),再进行MD5加密
  • 代码实现
public class Demo02 {

    public static void main(String[] args) {

        //regist();

        login();



    }

    private static void login() {
        //①获取明文密码
        System.out.println("请输入密码:");
        String password = new Scanner(System.in).nextLine();
        //②获取数据库中的密文
        String dbPassword = "04ec37510244b92d09532e7816c544156c0108e48d442301";
        //③明文密码 和 密文密码 匹配
        System.out.println(MD5Utils.verify(password,dbPassword) ? "登录成功!" : "登录失败!");


    }

    /**
     * 04ec37510244b92d09532e7816c544156c0108e48d442301
     * d4e86720b597f0936f361214e9119c884236169313d0ac31
     */
    private static void regist() {
        //①获取明文密码
        System.out.println("请输入密码:");
        String password = new Scanner(System.in).nextLine();
        //②获取随机盐值
        String salt = MD5Utils.generateSalt();
        //③根据明文密码和盐值生成MD5密文
        String saltMD5Password = MD5Utils.generateMD5AndSalt(password, salt);
        //④存储MD5密文
        System.out.println("saltMD5Password = " + saltMD5Password);
    }

}

注册功能引入加密

  • 需求
    • 在注册功能中,引入加密功能
  • 代码实现
public class UserServiceImpl implements UserService {
    @Override
    public int addUser(User inputUser) throws Exception {
        //获取盐值
        String salt = MD5Utils.generateSalt();
        //获取加盐后的MD5密文
        String md5Password = MD5Utils.generateMD5AndSalt(inputUser.getUserPwd(), salt);
        inputUser.setUserPwd(md5Password);
        UserDao userDao = new UserDaoImpl();
        return userDao.addUser(inputUser);
    }
}

登录功能引入加密

  • 需求
    • 在登录功能中,引入加密功能
  • 代码实现
public class UserServiceImpl implements UserService {
    @Override
    public User login(String username, String password) throws Exception {
        UserDao userDao = new UserDaoImpl();
        //①根据username查询用户记录 (验证账户)
        User dbUser = userDao.selectUserByUsername(username);
        if (null == dbUser) {
            //登录失败
            return null;
        }
        //②username是正确的,需要验证密码 :输入明文 和 数据库密文 匹配 (验证密码)
        boolean verify = MD5Utils.verify(password, dbUser.getUserPwd());
        return verify ? dbUser : null;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值