尚硅谷书城项目总结

  • Post author:
  • Post category:其他




尚硅谷书城项目



跟着课程讲的思路来做项目,一步一步梳理的都很清晰,小黄记性不太好,决定边做边总结,本片文章持续更新

先附上尚硅谷的JavaWeb视频链接,对我帮助极大,有兴趣的小伙伴也可以跟着一起学习,一起进步

https://www.bilibili.com/video/BV1Y7411K7zz



第一阶段:表单验证

大部分网站都会有登录注册功能,而在这些用户可以进行操作的板块中,我们需要通过JS将用户填写的内容进行一个判断,在前端先检查,避免将无用的数据传到服务器对服务器造成负担


操作流程(我们拿注册来举例说明)

  1. 给注册按钮绑定单击事件
  2. 获取用户输入在输入框中的内容
  3. 按照规则进行判断(可能用到正则表达式)
  4. 输入不合法返回提示信息


先来看一下表单(为了全篇文章的可读性,我只会贴一小部分实例代码)

<%--span.errorMsg用于显示返回的错误信息--%>
<span class="errorMsg"></span>
<form>
	<input type="hidden" name="function" value="regist">
	<label>用户名称:</label>
	<input class="itxt" type="text" placeholder="请输入用户名"
			autocomplete="off" tabindex="1" name="username" id="username"/>
	<br />
    <input type="submit" value="注册" id="sub_btn" />
</form>

我们的要求是用户名必须由字母、数字、下划线组成,并且长度在5-12之间,这个需求我们需要使用正则表达式

$(function () {
	// 给注册绑定单击事件
	$("#sub_btn").click(function () {
		// 验证用户名:必须由字母,数字下划线组成,并且长度为5到12位
		//1 获取用户名输入框里的内容
		var usernameText = $("#username").val();
		//2 创建正则表达式对象
		var usernamePatt = /^\w{5,12}$/;
		//3 使用test方法验证
		if (!usernamePatt.test(usernameText)) {
			//4 提示用户结果
			$("span.errorMsg").text("用户名不合法!");
            //返回false代表验证不通过时,不会跳转页面
			return false;
		}
    });
});



第二阶段:搭建书城项目环境

第二阶段我们开始着手搭建书城项目的环境,并且实现用户登录、注册的功能


先来看一下JavaEE的三层架构

在这里插入图片描述


一般我们的项目都会有以下几个包,先来介绍一下这些包的用处

  • dao:dao层是专门用来与数据库打交道的,这里存放到dao接口包
  • daoImpl:dao接口的实现类
  • pojo:Javabean对象
  • service:service接口包
  • serviceImpl:service接口实现类
  • servlet:servlet类
  • test:测试类
  • utils:工具类

在这里插入图片描述


实际开发中,我们应该从数据库一层一层的往外写


  • 编写JdbcUtils类,用于连接数据库(采用德鲁伊数据库连接池)

    public class JdbcUtils {
        private static DataSource dataSource = null;
        static{
            try {
                Properties prop = new Properties();
                InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
                prop.load(is);
                dataSource = DruidDataSourceFactory.createDataSource(prop);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        /**
         * 从数据库连接池中拿出一条链接
         * @return
         */
        public static Connection getConnection(){
            Connection conn = null;
            try {
                conn = dataSource.getConnection();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            return conn;
        }
        /**
         * 关闭一条连接
         * @param conn
         */
        public static void close(Connection conn){
            if(conn != null){
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
    }
    


    每一个小demo编写完成,都需要进行测试,测试代码放在test目录下,我就不贴出来了


  • 编写BaseDao类,用于与数据库的交互,执行CRUD操作

    public class BaseDAO {
        private QueryRunner queryRunner = new QueryRunner();
    
        /**
         * update():用于执行insert、update、delete语句
         * @param conn
         * @param sql 执行的sql语句
         * @param args 填充sql的占位符
         * @return 返回值为影响的行数,返回-1代表失败
         */
        public int update(Connection conn,String sql,Object... args){
            int rows = -1;
            try {
                rows = queryRunner.update(conn, sql, args);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            return rows;
        }
    
        /**
         * queryByOne():用于查询一行数据
         * @param type 返回值类型
         * @param conn
         * @param sql 执行的sql
         * @param args 填充占位符
         * @param <T> 返回值类型的泛型
         * @return
         */
        public <T> T queryByOne(Class<T> type,Connection conn,String sql,Object... args){
            T t = null;
            try {
                t = queryRunner.query(conn, sql, new BeanHandler<>(type), args);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            return t;
        }
    
        /**
         * queryByList():用于返回多条数据
         * @param type 返回值类型
         * @param conn
         * @param sql 执行的sql
         * @param args 填充占位符
         * @param <T> 返回值类型的泛型
         * @return
         */
        public <T>List<T> queryByList(Class<T> type,Connection conn,String sql,Object... args){
            List<T> list = null;
            try {
                list = queryRunner.query(conn, sql, new BeanListHandler<>(type), args);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            return list;
        }
    
        /**
         * queryForSingleValue():用于查询函数语句
         * @param conn
         * @param sql
         * @param args
         * @return
         */
        public Object queryForSingleValue(Connection conn,String sql,Object... args){
            Object result = null;
            try {
                result = queryRunner.query(conn, sql, new ScalarHandler(), args);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            return result;
        }
    }
    

  • 编写UserDao接口

    这里我们要结合业务来看,登录注册需要的操作有:

    • 判断用户名是否重复(注册):根据用户名查询数据库中的数据
    • 判断用户名密码是否存在(登录):根据用户名密码查询数据库中的数据
    • 保存用户信息(注册):将用户输入的数据保存到数据库
    public interface UserDAO {
        //根据用户名查询数据库中的数据
        User queryUserByUsername(String username);
        //根据用户名密码查询数据库中的数据
        User queryUserByUsernameAndPassword(String username,String password);
        //将用户输入的数据保存到数据库
        void saveUser(User user);
    }
    

  • 编写UserDaoImpl类实现UserDao接口

    public class UserDAOImpl extends BaseDAO implements UserDAO {
    
        @Override
        public User queryUserByUsername(String username) {
            Connection conn = JdbcUtils.getConnection();
            String sql = "select id,username,password,email from t_user where username = ?";
            User user = queryByOne(User.class, conn, sql, username);
            JdbcUtils.close(conn);
            return user;
        }
    
        @Override
        public User queryUserByUsernameAndPassword(String username, String password) {
            Connection conn = JdbcUtils.getConnection();
            String sql = "select id,username,password,email from t_user where username = ? and password = ?";
            User user = queryByOne(User.class, conn, sql, username,password);
            JdbcUtils.close(conn);
            return user;
        }
    
        @Override
        public void saveUser(User user) {
            Connection conn = JdbcUtils.getConnection();
            String sql = "insert into t_user(username,password,email) values (?,?,?)";
            update(conn, sql, user.getUsername(), user.getPassword(), user.getEmail());
        }
    }
    


    以上dao层的操作我们算是做完了,需要做一个小测试,接下来我们看一下service如何处理


  • 编写UserService接口

    service接口我们就需要更具体的去调用dao中的方法

    public interface UserService {
        User login(String username,String password);
        void regist(User user);
        /**
         * 判断用户名是否存在
         * @param username
         * @return 返回true代表用户名存在,不可用,反之亦然
         */
        boolean existUsername(String username);
    }
    
    

  • 编写UserServiceImpl类实现UserService接口

    public class UserServiceImpl implements UserService {
        UserDAO userDAO = new UserDAOImpl();
        @Override
        public User login(String username, String password) {
            User user = userDAO.queryUserByUsernameAndPassword(username, password);
            return user;
        }
        @Override
        public void regist(User user) {
            userDAO.saveUser(user);
        }
        @Override
        public boolean existUsername(String username) {
            User user = userDAO.queryUserByUsername(username);
            if(user == null){
                return false;
            }
            return true;
        }
    }
    


    以上完成之后,我们开始编写servlet程序,来实现需求


  • 编写登录的servlet程序

    public class UserLoginServlet extends HttpServlet {
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String username = req.getParameter("username");
            String password = req.getParameter("password");
            UserService userService = new UserServiceImpl();
            if(userService.login(username, password) != null){
                //使用请求重定向,成功之后跳转页面
                req.getRequestDispatcher("pages/user/login_success.jsp").forward(req,resp);
            }else {
                //登录失败
                req.setAttribute("msg","用户名或密码错误");
                req.setAttribute("username",username);
                req.getRequestDispatcher("pages/user/login.jsp").forward(req,resp);
            }
        }
    }
    

  • 编写注册的servlet程序

    public class UserRegistServlet extends HttpServlet {
        @Override
        protected void doPost(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");
            //判断用户名是否存在
            UserService userService = new UserServiceImpl();
            if(!userService.existUsername(username)){
                //用户名可用
                if("abcde".equals(code)){
                    //验证码正确
                    userService.regist(new User(null,username,password,email));
                    req.getRequestDispatcher("pages/user/regist_success.jsp").forward(req,resp);
                }else {
                    //回到注册页面
                    req.setAttribute("msg","验证码错误");
                    req.setAttribute("username",username);
                    req.setAttribute("email",email);
                    req.getRequestDispatcher("pages/user/regist.jsp").forward(req,resp);
                }
            }else {
                //回到注册页面
                req.setAttribute("msg","用户名已存在");
                req.setAttribute("username",username);
                req.setAttribute("email",email);
                req.getRequestDispatcher("pages/user/regist.jsp").forward(req,resp);
            }
        }
    }
    



第三阶段:对以上代码进行优化

一般来说,我们一个功能只会有一个servlet程序,比如书城项目,操作用户的是一个userServlet,操作书的是一个BookServlet,我们需要对以上的servlet进行优化,将他整合到一个servlet程序中

思路:运用input:hidden 隐藏表单,将客户端功能传输给服务器,在服务器判断应该执行哪条程序


  • 编写UserServlet

    public class UserServlet extends HttpServlet {
       
         @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            if("login".equals(req.getParameter("function"))){
                login(req,resp);
            }else if ("regist".equals(req.getParameter("function"){
                regist(req,resp);
            }
        }
    
        private void login(HttpServletRequest req,HttpServletResponse resp) throws Exception{
            String username = req.getParameter("username");
            String password = req.getParameter("password");
            UserService userService = new UserServiceImpl();
            if(userService.login(username, password) != null){
                req.getRequestDispatcher("pages/user/login_success.jsp").forward(req,resp);
            }else {
                //登录失败
                req.setAttribute("msg","用户名或密码错误");
                req.setAttribute("username",username);
                req.getRequestDispatcher("pages/user/login.jsp").forward(req,resp);
            }
        }
    
        private void regist(HttpServletRequest req,HttpServletResponse resp) throws Exception{
            String code = req.getParameter("code");
            User user = ServletUtils.getParamToBean(req.getParameterMap(),new User());
    
            //判断用户名是否存在
            UserService userService = new UserServiceImpl();
            if(!userService.existUsername(user.getUsername())){
                //用户名可用
                if("abcde".equals(code)){
                    //验证码正确
                    userService.regist(user);
                    req.getRequestDispatcher("pages/user/regist_success.jsp").forward(req,resp);
                }else {
                    //回到注册页面
                    req.setAttribute("msg","验证码错误");
                    req.setAttribute("username",user.getUsername());
                    req.setAttribute("email",user.getEmail());
                    req.getRequestDispatcher("pages/user/regist.jsp").forward(req,resp);
                }
            }else {
                //回到注册页面
                req.setAttribute("msg","用户名已存在");
                req.setAttribute("username",user.getUsername());
                req.setAttribute("email",user.getEmail());
                req.getRequestDispatcher("pages/user/regist.jsp").forward(req,resp);
            }
        }
    }
    

  • 利用反射,去除繁琐的if else

    在实际开发过程中,我们可能不只是登录、注册,可能还有修改信息等等功能,如果我们使用if else,会让代码看上去非常的冗余。我们发现从前端得到的字符串,与我们的方法名相同,这时候我们可以使用反射技术,动态的调用相对于的方法

    public class UserServlet extends HttpServlet {
         @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String function = req.getParameter("function");
            //利用反射,动态调用操作用户的方法,避免大量的if else
            try {
                Method method =  this.getClass().getDeclaredMethod(function,HttpServletRequest.class,HttpServletResponse.class);
                method.setAccessible(true);
                method.invoke(this,req,resp);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //重复的login和regist方法就
    }
    

  • 编写BaseServlet

    除了操作用户,操作书籍等功能都需要使用到反射技术,所以我们这些代码提取出来,UserServlet只需继承BaseServlet即可

    public abstract class BaseServlet extends HttpServlet {
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String function = req.getParameter("function");
            //利用反射,动态调用操作用户的方法,避免大量的if else
            try {
                Method method =  this.getClass().getDeclaredMethod(function,HttpServletRequest.class,HttpServletResponse.class);
                method.setAccessible(true);
                method.invoke(this,req,resp);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    



版权声明:本文为Yellow_Star___原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。