尚硅谷书城项目
跟着课程讲的思路来做项目,一步一步梳理的都很清晰,小黄记性不太好,决定边做边总结,本片文章持续更新
先附上尚硅谷的JavaWeb视频链接,对我帮助极大,有兴趣的小伙伴也可以跟着一起学习,一起进步
https://www.bilibili.com/video/BV1Y7411K7zz
第一阶段:表单验证
大部分网站都会有登录注册功能,而在这些用户可以进行操作的板块中,我们需要通过JS将用户填写的内容进行一个判断,在前端先检查,避免将无用的数据传到服务器对服务器造成负担
操作流程(我们拿注册来举例说明)
- 给注册按钮绑定单击事件
- 获取用户输入在输入框中的内容
- 按照规则进行判断(可能用到正则表达式)
- 输入不合法返回提示信息
先来看一下表单(为了全篇文章的可读性,我只会贴一小部分实例代码)
<%--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(); } } }