javaweb实战
一、第一阶段
前端页面编写
二、第二阶段
Dao,Service代码编写等
javaEE三层架构

1、先创建书城需要的数据库和表。
2、编写数据库表对应的 JavaBean 对象
3、编写工具类 JdbcUtils
3.1、导入需要的 jar 包
数据库和连接池需要:
druid-1.1.9.jar
mysql-connector-java-5.1.7-bin.jar
以下是测试需要:
hamcrest-core-1.3.jar
junit-4.12.jar
3.2、在 src 源码目录下编写 jdbc.properties 属性配置文件:
1 2 3 4 5 6
| username=root password=root url=jdbc:mysql: driverClassName=com.mysql.jdbc.Driver initialSize=5 maxActive=10
|
3.3、编写 JdbcUtils 工具类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| public class JdbcUtils { private static DruidDataSource dataSource; static { try { Properties properties = new Properties(); InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties"); properties.load(inputStream); dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties); } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection(){ Connection conn = null; try { conn = dataSource.getConnection(); } catch (Exception e) { e.printStackTrace(); } return conn; }
public static void close(Connection conn){ if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
|
3.4、JdbcUtils 测试:
1 2 3 4 5 6 7 8 9 10
| public class JdbcUtilsTest { @Test public void testJdbcUtils(){ for (int i = 0; i < 100; i++){ Connection connection = JdbcUtils.getConnection(); System.out.println(connection); JdbcUtils.close(connection); } } }
|
4、编写 BaseDao
导入 DBUtils 的 jar 包commons-dbutils-1.3.jar
BaseDao:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| public abstract class BaseDao { private QueryRunner queryRunner = new QueryRunner();
public int update(String sql, Object... args) { Connection connection = JdbcUtils.getConnection(); try { return queryRunner.update(connection, sql, args); } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtils.close(connection); } return -1; }
public <T> T queryForOne(Class<T> type, String sql, Object... args) { Connection con = JdbcUtils.getConnection(); try { return queryRunner.query(con, sql, new BeanHandler<T>(type), args); } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtils.close(con); } return null; }
public <T> List<T> queryForList(Class<T> type, String sql, Object... args) { Connection con = JdbcUtils.getConnection(); try { return queryRunner.query(con, sql, new BeanListHandler<T>(type), args); } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtils.close(con); } return null; }
public Object queryForSingleValue(String sql, Object... args){ Connection conn = JdbcUtils.getConnection(); try { return queryRunner.query(conn, sql, new ScalarHandler(), args); } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtils.close(conn); } return null; } }
|
5、编写 UserDao 和测试
userDao:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public interface UserDao {
public User queryUserByUsername(String username);
public User queryUserByUsernameAndPassword(String username,String password);
public int saveUser(User user); }
|
UserDaoImpl 实现类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class UserDaoImpl extends BaseDao implements UserDao { @Override public User queryUserByUsername(String username) { String sql = "select `id`,`username`,`password`,`email` from t_user where username = ?"; return queryForOne(User.class, sql, username); } @Override public User queryUserByUsernameAndPassword(String username, String password) { String sql = "select `id`,`username`,`password`,`email` from t_user where username = ? and password = ?"; return queryForOne(User.class, sql, username,password); } @Override public int saveUser(User user) { String sql = "insert into t_user(`username`,`password`,`email`) values(?,?,?)"; return update(sql, user.getUsername(),user.getPassword(),user.getEmail()); } }
|
UserDao 测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class UserDaoTest { UserDao userDao = new UserDaoImpl(); @Test public void queryUserByUsername() { if (userDao.queryUserByUsername("admin1234") == null ){ System.out.println("用户名可用!"); } else { System.out.println("用户名已存在!"); } } @Test public void queryUserByUsernameAndPassword() { if ( userDao.queryUserByUsernameAndPassword("admin","admin1234") == null) { System.out.println("用户名或密码错误,登录失败"); } else { System.out.println("查询成功"); } } @Test public void saveUser() { System.out.println( userDao.saveUser(new User(null,"wzg168", "123456", "wzg168@qq.com")) ); } }
|
6、编写 UserService 和测试
UserService 接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public interface UserService {
public void registUser(User user);
public User login(User user);
public boolean existsUsername(String username); }
|
UserServiceImpl 实现类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class UserServiceTest { UserService userService = new UserServiceImpl(); @Test public void registUser() { userService.registUser(new User(null, "bbj168", "666666", "bbj168@qq.com")); userService.registUser(new User(null, "abc168", "666666", "abc168@qq.com")); } @Test public void login() { System.out.println( userService.login(new User(null, "wzg168", "123456", null)) ); } @Test public void existsUsername() { if (userService.existsUsername("wzg16888")) { System.out.println("用户名已存在!"); } else { System.out.println("用户名可用!"); } } }
|
Test
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class UserServiceTest { UserService userService = new UserServiceImpl(); @Test public void registUser() { userService.registUser(new User(null, "bbj168", "666666", "bbj168@qq.com")); userService.registUser(new User(null, "abc168", "666666", "abc168@qq.com")); } @Test public void login() { System.out.println( userService.login(new User(null, "wzg168", "123456", null)) ); } @Test public void existsUsername() { if (userService.existsUsername("wzg16888")) { System.out.println("用户名已存在!"); } else { System.out.println("用户名可用!"); } } }
|
7、编写 web 层
7.1、实现用户注册的功能

servlet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class RegistServlet extends HttpServlet { private UserService userService = new UserServiceImpl(); @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"); if ("abcde".equalsIgnoreCase(code)) { if (userService.existsUsername(username)) { System.out.println("用户名[" + username + "]已存在!"); req.getRequestDispatcher("/pages/user/regist.html").forward(req, resp); } else { userService.registUser(new User(null, username, password, email)); req.getRequestDispatcher("/pages/user/regist_success.html").forward(req, resp); } } else { System.out.println("验证码[" + code + "]错误"); req.getRequestDispatcher("/pages/user/regist.html").forward(req, resp); } } }
|
7.3、用户登录功能的实现

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class LoginServlet extends HttpServlet { private UserService userService = new UserServiceImpl(); @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username"); String password = req.getParameter("password"); User loginUser = userService.login(new User(null, username, password, null)); if (loginUser == null) { req.getRequestDispatcher("/pages/user/login.html").forward(req, resp); } else { req.getRequestDispatcher("/pages/user/login_success.html").forward(req, resp); } } }
|
三、第三阶段
页面 jsp 动态化
- 在 html 页面顶行添加 page 指令。
- 修改文件后缀名为:.jsp
- 使用 IDEA 搜索替换.html 为.jsp(快捷键:Ctrl+Shift+R}
抽取页面中相同的内容(用静态包含)

要求动态basePath
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <% String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/"; %> <%=basePath%> <!--写 base 标签,永远固定相对路径跳转的结果--> <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>
|
注册错误提示,及表单回显


BaseServlet 的抽取
在实际的项目开发中,一个模块,一般只使用一个 Servlet 程序。
合并 LoginServlet 和 RegistServlet 程序为 UserServlet 程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| public class UserServlet extends HttpServlet { private UserService userService = new UserServiceImpl();
protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username"); String password = req.getParameter("password"); User loginUser = userService.login(new User(null, username, password, null)); if (loginUser == null) { req.setAttribute("msg","用户或密码错误!"); req.setAttribute("username", username); req.getRequestDispatcher("/pages/user/login.jsp").forward(req, resp); } else { req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req, resp); } }
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"); if ("abcde".equalsIgnoreCase(code)) { if (userService.existsUsername(username)) { System.out.println("用户名[" + 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 { req.setAttribute("msg", "验证码错误!!"); req.setAttribute("username", username); req.setAttribute("email", email); System.out.println("验证码[" + code + "]错误"); req.getRequestDispatcher("/pages/user/regist.jsp").forward(req, resp); } } protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String action = req.getParameter("action"); if ("login".equals(action)) { login(req, resp); } else if ("regist".equals(action)) { regist(req, resp); } }
|
使用反射优化大量 else if 代码
baseServlet:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package com.atguigu.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;
public abstract class BaseServlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String action = req.getParameter("action"); try { Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
method.invoke(this, req, resp); } catch (Exception e) { e.printStackTrace(); } }
}
|
==让userServlet继承BaseServlet==
数据的封装和抽取 BeanUtils 的使用
BeanUtils 工具类,它可以一次性的把所有请求的参数注入到 JavaBean 中。
BeanUtils 工具类,经常用于把 Map 中的值注入到 JavaBean 中,或者是对象属性值的拷贝操作。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class WebUtils {
public static <T> T copyParamToBean( Map value , T bean ){ try { System.out.println("注入之前:" + bean);
BeanUtils.populate(bean, value); System.out.println("注入之后:" + bean); } catch (Exception e) { e.printStackTrace(); } return bean; } }
|
使用map比HttpServletRequest好(第7行),能在dao层和service中也使用

此时一行代码完成注入
四、第四阶段
EL表达式修改表单回显

五、第五阶段
MVC 全称:Model 模型、 View 视图、 Controller 控制器。
MVC 最早出现在 JavaEE 三层中的 Web 层,它可以有效的指导 Web 层的代码如何有效分离,单独工作。
View 视图:只负责数据和界面的显示,不接受任何与显示数据无关的代码,便于程序员和美工的分工合作——JSP/HTML。
Controller 控制器:只负责接收请求,调用业务层的代码处理请求,然后派发页面,是一个“调度者”的角色——Servlet。
转到某个页面。或者是重定向到某个页面。
Model 模型:将与业务逻辑相关的数据封装为具体的 JavaBean 类,其中不掺杂任何与数据处理相关的JavaBean/domain/entity/pojo。
MVC 是一种思想,MVC 的理念是将软件代码拆分成为组件,单独开发,组合使用(目的还是为了降低耦合度)。

添加图书功能的实现BUG:
当用户提交完请求,浏览器会记录下最后一次请求的全部信息。当用户按下功能键 F5,就会发起浏览器记录的最后一次请求。
解决方法:使用重定向
1 2 3 4 5 6 7 8 9 10 11
| protected void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Book book = WebUtils.copyParamToBean(req.getParameterMap(),new Book()); bookService.addBook(book); resp.sendRedirect(req.getContextPath() + "/manager/bookServlet?action=list"); }
|
修改图书

六、第六阶段
分页

分页模型 Page
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class Page<T> { public static final Integer PAGE_SIZE = 4; private Integer pageNo; private Integer pageTotal; private Integer pageSize = PAGE_SIZE; private Integer pageTotalCount; private List<T> items; }
|
分页的初步实现
DAO:
1 2 3 4 5 6 7 8 9 10 11 12
| @Override public Integer queryForPageTotalCount() { String sql = "select count(*) from t_book"; Number count = (Number) queryForSingleValue(sql); return count.intValue(); } @Override public List<Book> queryForPageItems(int begin, int pageSize) { String sql = "select `id` , `name` , `author` , `price` , `sales` , `stock` , `img_path` imgPath from t_book limit ?,?"; return queryForList(Book.class,sql,begin,pageSize); }
|
BookService 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| @Override public Page<Book> page(int pageNo, int pageSize) { Page<Book> page = new Page<Book>(); page.setPageNo(pageNo); page.setPageSize(pageSize); Integer pageTotalCount = bookDao.queryForPageTotalCount(); page.setPageTotalCount(pageTotalCount); Integer pageTotal = pageTotalCount / pageSize; if (pageTotalCount % pageSize > 0) { pageTotal+=1; } page.setPageTotal(pageTotal); int begin = (page.getPageNo() - 1) * pageSize; List<Book> items = bookDao.queryForPageItems(begin,pageSize); page.setItems(items); return page; } BookServlet 程序的代码:
protected void page(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { int pageNo = WebUtils.parseInt(req.getParameter("pageNo"), 1); int pageSize = WebUtils.parseInt(req.getParameter("pageSize"), Page.PAGE_SIZE); Page<Book> page = bookService.page(pageNo,pageSize); req.setAttribute("page",page); req.getRequestDispatcher("/pages/manager/book_manager.jsp").forward(req,resp); }
|
book_manager.jsp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>图书管理</title>
<%-- 静态包含 base标签、css样式、jQuery文件 --%> <%@ include file="/pages/common/head.jsp"%> <script type="text/javascript"> $(function () { $("a.deleteClass").click(function () {
return confirm("你确定要删除【" + $(this).parent().parent().find("td:first").text() + "】?"); }); }); </script>
</head> <body> <div id="header"> <img class="logo_img" alt="" src="../../static/img/logo.gif" > <span class="wel_word">图书管理系统</span>
<%-- 静态包含 manager管理模块的菜单 --%> <%@include file="/pages/common/manager_menu.jsp"%>
</div> <div id="main"> <table> <tr> <td>名称</td> <td>价格</td> <td>作者</td> <td>销量</td> <td>库存</td> <td colspan="2">操作</td> </tr>
<c:forEach items="${requestScope.page.items}" var="book"> <tr> <td>${book.name}</td> <td>${book.price}</td> <td>${book.author}</td> <td>${book.sales}</td> <td>${book.stock}</td> <td><a href="manager/bookServlet?action=getBook&id=${book.id}&pageNo=${requestScope.page.pageNo}">修改</a></td> <td><a class="deleteClass" href="manager/bookServlet?action=delete&id=${book.id}&pageNo=${requestScope.page.pageNo}">删除</a></td> </tr> </c:forEach>
<tr> <td></td> <td></td> <td></td> <td></td> <td></td> <td></td> <td><a href="pages/manager/book_edit.jsp?pageNo=${requestScope.page.pageTotal}">添加图书</a></td> </tr> </table>
<%--静态包含分页条--%> <%@include file="/pages/common/page_nav.jsp"%>
</div>
<%--静态包含页脚内容--%> <%@include file="/pages/common/footer.jsp"%>
</body> </html>
|
manager_menu.jsp 中【图书管理】请求地址的修改:

WEB层:
1 2 3 4 5 6 7 8 9 10 11 12
| protected void page(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { int pageNo = WebUtils.parseInt(req.getParameter("pageNo"), 1); int pageSize = WebUtils.parseInt(req.getParameter("pageSize"), Page.PAGE_SIZE); Page<Book> page = bookService.page(pageNo,pageSize); req.setAttribute("page",page); req.getRequestDispatcher("/pages/manager/book_manager.jsp").forward(req,resp); }
|
首页、上一页、下一页、末页实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <div id="page_nav"> <%--大于首页,才显示--%> <c:if test="${requestScope.page.pageNo > 1}"> <a href="manager/bookServlet?action=page&pageNo=1">首页</a> <a href="manager/bookServlet?action=page&pageNo=${requestScope.page.pageNo-1}">上一页</a> </c:if> <a href="#">3</a> 【${ requestScope.page.pageNo }】 <a href="#">5</a> <%-- 如果已经 是最后一页,则不显示下一页,末页 --%> <c:if test="${requestScope.page.pageNo < requestScope.page.pageTotal}"> <a href="manager/bookServlet?action=page&pageNo=${requestScope.page.pageNo+1}">下一页</a> <a href="manager/bookServlet?action=page&pageNo=${requestScope.page.pageTotal}">末页</a> </c:if> 共${ requestScope.page.pageTotal }页,${ requestScope.page.pageTotalCount }条记录 到第<input value="4" name="pn" id="pn_input"/>页 <input type="button" value="确定"> </div>
|