typora-copy-images-to: img

JSP&三层架构

教学目标

  • 能够说出el表达式的作用
  • 能够使用el表达式获取javabean的属性
  • 能够使用jstl标签库的if标签
  • 能够使用jstl标签库的foreach标签
  • 能够使用三层架构模式完成显示用户案例
  • 能够使用ThreadLocal
  • 能够完成转账案例

第一章-EL表达式

知识点-EL表达式概述

1.目标

  • 能够说出el表达式的作用

2.讲解

2.1.什么是El表达式

  1. Expression Language:表达式语言, jsp2.0之后内置在jsp里面
  2. 目的:为了使JSP写起来更加简单, 取值(取的域对象里面存的值)更加简单。(代替脚本 <% %>)

2.2. EL语法

  1. ${el表达式}

2.3. EL表达式的用途

  1. 1.获取数据. 获取的是**域(request,session,ServletContext)对象**中存储的数据
  2. 2.EL执行运算

3.小结

  1. EL表达式:表达式语言
  2. 语法:${el表达式}
  3. 作用:1. 获取域对象里面的数据 2. 执行运算

知识点-El获取数据

1.目标

  • 能够使用el表达式域里面的数据(先要把数据存到域对象里面)

2.路径

  • 获取简单数据类型数据(基本类型,字符串)
  • 获取数组
  • 获取list
  • 获取Map
  • 获取bean

3.讲解

3.1获取简单数据类型数据

  1. 语法:${requestScope|sessionScope|applicationScope.属性名};
  2. 快捷写法:${属性名}, 属性名就是存在域对象里面的key
  1. <%--
  2. Created by IntelliJ IDEA.
  3. User: Fanyi Xiao
  4. Date: 2020/7/15
  5. Time: 8:52
  6. To change this template use File | Settings | File Templates.
  7. --%>
  8. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  9. <html>
  10. <head>
  11. <title>使用EL表达式获取域对象中的简单类型的数据</title>
  12. </head>
  13. <body>
  14. <%
  15. //往域对象存值
  16. application.setAttribute("msg","applicationValue");
  17. //session.setAttribute("msg","sessionValue");
  18. //request.setAttribute("msg","requestValue");
  19. //在我们开发过程中,是否会往多个域对象中存放同一个key??? 这是不会的
  20. //所以我们用el表达式获取域对象里面的数据,还可以简化成${key} 获取范围最小的域对象中的这个key对应的值
  21. %>
  22. 获取的application域对象中的msg=${applicationScope.msg}<br>
  23. 获取session域对象中的msg=${sessionScope.msg}<br>
  24. 获取request域对象中的msg=${requestScope.msg}<br>
  25. 获取存放在域对象中的msg=${msg}
  26. </body>
  27. </html>

3.2获取数组

  1. 语法: ${key[下标]} key就是域对象里面存的key

3.3获取list

  1. `语法:${list属性名[index]}或者${list属性名.get(index)};list属性名就是存入域对象里面的key`

3.4获取Map

  1. `语法:${map属性名.键}或者${map属性名.get("键")},map属性名就是存入域对象里面的key`

3.5 获取bean

  1. 语法:${key.javabean属性}
  2. 依赖getxxx()方法; eg: getPassword()---去掉get-->Password()----首字母小写--->password
  1. <%@ page import="java.util.ArrayList" %>
  2. <%@ page import="java.util.HashMap" %>
  3. <%@ page import="java.util.List" %>
  4. <%@ page import="java.util.Map" %>
  5. <%@ page import="com.itheima.pojo.User" %><%--
  6. Created by IntelliJ IDEA.
  7. User: Fanyi Xiao
  8. Date: 2020/7/15
  9. Time: 9:05
  10. To change this template use File | Settings | File Templates.
  11. --%>
  12. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  13. <html>
  14. <head>
  15. <title>使用EL表达式获取存储在域对象中的复杂类型的数据</title>
  16. </head>
  17. <body>
  18. <%
  19. //往域对象中存放数组类型的数据
  20. String[] arr = {"张三","李四","王五","赵六","田七","狗娃"};
  21. request.setAttribute("arr", arr);
  22. //往域对象中存放一个集合
  23. List<String> list = new ArrayList<String>();
  24. list.add("张三");
  25. list.add("李四");
  26. list.add("王五");
  27. list.add("赵六");
  28. list.add("田七");
  29. request.setAttribute("list", list);
  30. //往域对象中存放一个map
  31. Map<String,String> map = new HashMap<String,String>();
  32. map.put("name", "张三");
  33. map.put("password", "123456");
  34. map.put("nickname", "张三丰");
  35. request.setAttribute("map", map);
  36. //往域对象中存放一个pojo对象
  37. User user = new User(1, "jay", "台湾省");
  38. request.setAttribute("user",user);
  39. %>
  40. 获取存放在request域对象中的数组中的第三个元素:${arr[2]}<br>
  41. <%--
  42. el表达式中,只要是根据下标获取元素,都可以写[index]
  43. --%>
  44. 获取存放在request域对象中的集合中的第四个元素:${list[3]}<br>
  45. <%--
  46. el表达式中,只要是根据对应的属性的get方法去获取数据,都可以写成".属性名" 或者 ["属性名"]
  47. --%>
  48. 获取存储在request域对象中的map中的nickname:${map.nickname}<br>
  49. 获取存放在request域对象中的user的address属性的值:${user.address}
  50. </body>
  51. </html>

4.小结

4.1语法

  1. 获得简单类型的
  1. ${key}
  1. 获得数组类型的
  1. ${key[下标]}
  1. 获得List类型的
  1. ${key.get(index)} 或者${key[index]}
  1. 获得Map类型的
  1. ${key.get(键)} 或者${key.键} key是存到域对象里面的key
  1. 获得JavaBean类型的
  1. ${key.javaBean属性}

知识点-EL执行运算

1.目标

  • 掌握EL执行运算

2.讲解

JSP&三层架构 - 图1

2.1算数运算

  1. +,-,*,/
  • +不能拼接字符串,如果+两端是字符串,那么会将字符串转换成数字之后再进行加法运算,如果+两端的字符串无法转换成数字,则会报错

2.2逻辑运算

  1. < >= <= != ==

2.3关系运算

  1. && || !

2.4非空判断【重点】

  1. empty1. 判断一个对象是否为null, 2. 判断集合长度是否为0, 3. 判断一个字符串是否为 ""
  2. not empty
  3. 语法: ${empyt 属性名};属性名 就是域对象里面的key
  1. <%@ page import="java.util.ArrayList" %>
  2. <%@ page import="java.util.List" %>
  3. <%@ page import="com.itheima.pojo.User" %><%--
  4. Created by IntelliJ IDEA.
  5. User: Fanyi Xiao
  6. Date: 2020/7/15
  7. Time: 9:35
  8. To change this template use File | Settings | File Templates.
  9. --%>
  10. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  11. <html>
  12. <head>
  13. <title>empty 运算符的介绍</title>
  14. </head>
  15. <body>
  16. <%
  17. //el表达式中的empty可以判断一个字符串是否为空字符串,一个对象是否为null,一个集合的长度是否为0
  18. List<String> list = new ArrayList<String>();
  19. list.add("张三丰");
  20. request.setAttribute("list", list);
  21. request.setAttribute("msg","requestValue");
  22. User user = new User();
  23. request.setAttribute("u",user);
  24. %>
  25. 判断域对象中的list集合的长度是否为0: ${empty list}<br>
  26. 判断域对象中的msg字符串是否为空字符串: ${empty msg}<br>
  27. 判断域对象中的user是否为null : ${empty u}<br>
  28. </body>
  29. </html>

3.小结

  1. 注意的地方: +只能做加法运算,不能拼接字符串

  2. empty【重点】

    • 语法

      • ${empty key}
      • ${not empty key}
  • 作用

    • 判断一个对象是否为null
    • 判断一个集合长度是否为0
    • 判断一个字符串是否是””
    • 注意

      • 如果是集合, 集合为null 是empty
      • 如果是集合, 集合不为null 但是长度为0 还是empty

知识点-使用EL表达式获取存放在cookie中的数据(扩展)

  1. 语法:${cookie.cookiename.value}
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>使用el表达式获取存储在cookie中的数据</title>
  5. </head>
  6. <body>
  7. <%--
  8. jsp里面是内置session对象,有了session对象,那么浏览器就会携带一个名为"JSESSIONID"cookie
  9. 我们的目标就是获取"JSESSIONID"的值
  10. --%>
  11. <%
  12. Cookie[] cookies = request.getCookies();
  13. String cookieValue = null;
  14. if (cookies != null) {
  15. for (Cookie cookie : cookies) {
  16. if (cookie.getName().equals("JSESSIONID")) {
  17. cookieValue = cookie.getValue();
  18. }
  19. }
  20. }
  21. %>
  22. 使用原始方式获取的JSESSIONID的值为: <%=cookieValue%><br>
  23. <%--
  24. ${cookie}表示获取这次请求中的所有cookie对象
  25. ${cookie.JSESSIONID}表示获取名为"JSESSIONID"cookie对象
  26. ${cookie.JSESSIONID.value}表示获取名为"JSESSIONID"cookie对象的value
  27. --%>
  28. 使用EL表达式获取JSESSIONID的值为: ${cookie.JSESSIONID.value}
  29. </body>
  30. </html>

第二章-JSTL标签库

知识点-JSTL标签库概述

1.目标

  • 掌握什么是JSTL标签库

2.讲解

2.1 什么是JSTL标签库

  1. JSTLJSP Standard Tag LibraryJSP标准标签库)是一个不断完善的开放源代码的JSP标签库,是由apachejakarta小组来维护的。这个JSTL标签库没有集成到JSP的, 要使用的话, 需要导jar包.

2.2 JSTL标签库的作用

  1. 为了简化在jsp页面上操作数据; eg: 遍历数据 判断数据等

2.3 JSTL标签库的类别

JSP&三层架构 - 图2

3.小结

  1. JSTL: JSP标准的标签库. 也就意味着我们可以在jsp里面使用除了html以外的其它的标签
  2. 作用: 遍历, 判断…. 代替脚本

知识点-JSTL核心标签库

1.目标

  • 掌握if,foreach标签的使用

2.讲解

2.1核心标签库使用步骤

  1. 导入jar包 JSP&三层架构 - 图3

  2. 在JSP页面上导入核心标签库<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

2.3if标签

JSP&三层架构 - 图4

  • 语法
  1. <c:if test="el表达式${..}">
  2. </c:if>
  • 实例
  1. <%--
  2. Created by IntelliJ IDEA.
  3. User: Fanyi Xiao
  4. Date: 2020/7/15
  5. Time: 9:51
  6. To change this template use File | Settings | File Templates.
  7. --%>
  8. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  9. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  10. <html>
  11. <head>
  12. <title>jstl的if标签</title>
  13. </head>
  14. <body>
  15. <%
  16. //往域对象中存储age
  17. request.setAttribute("age",19);
  18. %>
  19. <%--
  20. 判断age是否大于等于18,如果大于等于18则输出:已成年,否则输出未成年
  21. --%>
  22. <%--
  23. 第一种方式:使用el表达式的三元运算符
  24. ${age >= 18 ? "已成年" : "未成年"}
  25. --%>
  26. <%--
  27. 第二种方式:使用jstlif标签
  28. jstl的使用步骤:
  29. 1. 导入jar
  30. 2. 通过taglib指令:引入jstl
  31. 3. 使用标签库中的标签
  32. if标签的test属性,表示判断表达式通常是和el表达式结合使用
  33. --%>
  34. <c:if test="${age >= 18}">
  35. 已成年
  36. </c:if>
  37. <c:if test="${age < 18}">
  38. 未成年
  39. </c:if>
  40. </body>
  41. </html>
  • 小结

    • 语法

      1. <c:if test="${} "></c:if>
    • 特点

      • 如果test里面的是true, if标签体里面的就会执行
      • 如果test里面的是false, if标签体里面的就不会执行
      • 没有else的

2.4choose标签

  • 实例
  1. <%--
  2. Created by IntelliJ IDEA.
  3. User: Fanyi Xiao
  4. Date: 2020/7/15
  5. Time: 9:59
  6. To change this template use File | Settings | File Templates.
  7. --%>
  8. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  9. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  10. <html>
  11. <head>
  12. <title>jstl中的choose标签的使用介绍</title>
  13. </head>
  14. <body>
  15. <%
  16. request.setAttribute("course","PHP");
  17. %>
  18. <c:choose>
  19. <%--
  20. 一个when标签表示一个条件
  21. --%>
  22. <c:when test="${course == 'Java'}">
  23. 学习Java
  24. </c:when>
  25. <c:when test="${course == 'Android'}">
  26. 学习Android
  27. </c:when>
  28. <c:when test="${course == 'C++'}">
  29. 学习C++
  30. </c:when>
  31. <c:otherwise>
  32. 学习,学个屁!!!
  33. </c:otherwise>
  34. </c:choose>
  35. </body>
  36. </html>

2.5foreach标签

JSP&三层架构 - 图5

  • 简单的使用:
  1. <%--
  2. jstl中的forEach标签是用来代替for循环语句
  3. 目标1: 在浏览器上显示0-9的数字
  4. begin属性: 从哪个下标开始遍历, 如果不写默认是从0开始
  5. end属性: 到哪个下标结束遍历,如果不写默认是遍历到集合/数组的最后一个元素
  6. step属性: 表示遍历时候的步长,默认步长是1
  7. var属性: 表示将遍历的结果存放进域对象时候的key
  8. --%>
  9. <c:forEach begin="0" end="9" step="1" var="i">
  10. ${i}
  11. </c:forEach><br>
  • 复杂的使用遍历集合: ```jsp <% //往域对象存储一个集合 List list = new ArrayList(); list.add(“张三”); list.add(“李四”); list.add(“王五”); list.add(“赵六”); list.add(“田七”); request.setAttribute(“list”, list); %>

${i}

  1. <%--
  2. 通过items属性指定遍历域对象里面的list
  3. 通过var属性指定遍历出来的每个数据存储到域对象时候的key
  4. --%>

${username}

  1. -
  2. c:forEach中的varStatus属性。
  3. <br />指向一个字符串,该字符串引用一个对象。 map.put("vs",一个对象);
  4. <br />这个对象记录着当前遍历的元素的一些信息:
  5. <br />index:返回索引。从0开始
  6. <br />count:返回计数。从1开始
  7. <br />last:是否是最后一个元素
  8. <br />first:是否是第一个元素
  9. ```jsp
  10. <%@ page import="java.util.ArrayList" %>
  11. <%@ page import="java.util.List" %><%--
  12. Created by IntelliJ IDEA.
  13. User: Fanyi Xiao
  14. Date: 2020/7/15
  15. Time: 10:15
  16. To change this template use File | Settings | File Templates.
  17. --%>
  18. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  19. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  20. <html>
  21. <head>
  22. <title>forEach 标签的varStatus属性的介绍</title>
  23. </head>
  24. <body>
  25. <%
  26. //往域对象存储一个集合
  27. List<String> list = new ArrayList<String>();
  28. list.add("张三");
  29. list.add("李四");
  30. list.add("王五");
  31. list.add("赵六");
  32. list.add("田七");
  33. request.setAttribute("list", list);
  34. %>
  35. <%--
  36. forEach标签的varStatus属性:指定将遍历出来的每一个元素的状态存储进域对象时候的key
  37. 遍历出来的每一个元素都有一些状态(属性),比如:
  38. 下标 index:
  39. 计数 count:
  40. 当前元素的值 current:
  41. 是否是第一个元素:
  42. 是否是最后一个元素
  43. --%>
  44. <table border="1" cellspacing="0" width="700" align="center">
  45. <tr>
  46. <th>下标</th>
  47. <th>计数</th>
  48. <th>姓名</th>
  49. <th>是否是第一个元素</th>
  50. <th>是否是最后一个元素</th>
  51. </tr>
  52. <c:forEach items="${list}" varStatus="vst">
  53. <tr>
  54. <td>${vst.index}</td>
  55. <td>${vst.count}</td>
  56. <td>${vst.current}</td>
  57. <td>${vst.first}</td>
  58. <td>${vst.last}</td>
  59. </tr>
  60. </c:forEach>
  61. </table>
  62. </body>
  63. </html>

3.小结

  1. foreach标签
  • 简单使用
  1. <c:foreach begin="从哪里开始" end="到哪里结束" var="每次遍历的赋值变量" step="步长">
  2. //每遍历一次 foreach里面就执行一次
  3. </c:foreach>
  • 复杂使用
  1. <c:foreach items="使用el从域对象里面取出集合" var="每次遍历的赋值变量" varStatus="遍历的状态">
  2. //每遍历一次 foreach里面就执行一次
  3. </c:foreach>

第三章-综合案例和开发模式

案例-完成转账的案例v1

一.需求

  • 当单击提交按钮,付款方向收款方安照输入的金额转账。

JSP&三层架构 - 图6

二,分析

JSP&三层架构 - 图7

三,实现

1.案例的准备工作

  • 数据库的准备 ``` create database day27; use day27; create table account( id int primary key auto_increment, name varchar(20), money double );

insert into account values (null,’jay’,1000); insert into account values (null,’aobama’,1000); insert into account values (null,’ww’,1000);

  1. -
  2. 页面
  3. ```jsp
  4. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  5. <html>
  6. <head>
  7. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  8. <title>Insert title here</title>
  9. </head>
  10. <body>
  11. <form method="post" action="">
  12. <table border="1px" width="500px" align="center">
  13. <tr>
  14. <td>付款方</td>
  15. <td><input type="text" name="from"></td>
  16. </tr>
  17. <tr>
  18. <td>收款方</td>
  19. <td><input type="text" name="to"></td>
  20. </tr>
  21. <tr>
  22. <td>金额</td>
  23. <td><input type="text" name="money"></td>
  24. </tr>
  25. <tr>
  26. <td colspan="2"><input type="submit"></td>
  27. </tr>
  28. </table>
  29. </form>
  30. </body>
  31. </html>
  • jar包

  • 工具类

  • 配置文件

2.代码实现

  • AccountServlet
  1. package com.itheima.web.servlet;
  2. import com.itheima.utils.DruidUtil;
  3. import org.apache.commons.dbutils.QueryRunner;
  4. import javax.servlet.ServletException;
  5. import javax.servlet.annotation.WebServlet;
  6. import javax.servlet.http.HttpServlet;
  7. import javax.servlet.http.HttpServletRequest;
  8. import javax.servlet.http.HttpServletResponse;
  9. import java.io.IOException;
  10. /**
  11. * 包名:${PACKAGE_NAME}
  12. *
  13. * @author Leevi
  14. * 日期2020-07-15 10:55
  15. */
  16. @WebServlet("/account")
  17. public class AccountServlet extends HttpServlet {
  18. @Override
  19. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  20. doGet(request, response);
  21. }
  22. @Override
  23. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  24. request.setCharacterEncoding("UTF-8");
  25. response.setContentType("text/html;charset=UTF-8");
  26. //1. 获取请求参数
  27. String fromName = request.getParameter("from");
  28. String toName = request.getParameter("to");
  29. Double money = Double.valueOf(request.getParameter("money"));
  30. //2. 执行转账的SQL语句
  31. //2.1 转出账户扣款
  32. QueryRunner queryRunner = new QueryRunner(DruidUtil.getDataSource());
  33. String sql1 = "update account set money=money-? where name=?";
  34. try {
  35. queryRunner.update(sql1,money,fromName);
  36. //2.2 转入账户收款
  37. String sql2 = "update account set money=money+? where name=?";
  38. queryRunner.update(sql2,money,toName);
  39. //3. 转账成功
  40. response.getWriter().write("转账成功!!!");
  41. } catch (Exception e) {
  42. e.printStackTrace();
  43. //转账失败
  44. response.getWriter().write("转账失败!!!");
  45. }
  46. }
  47. }

四.小结

  1. 转账: 一个用户的钱减少, 一个用户的钱增加

知识点-开发模式

1.目标

  • 理解模式二(MVC)和模式三(三层架构)

2.讲解

2.1JSP的开发模式一【了解】

  1. javaBean:实体类。特点:私有化的属性、公共的getter setter方法、无参的构造。

JSP&三层架构 - 图8

2.2 JSP的开发模式二

  1. JSP + Servlet + JavaBean 称为MVC的开发模式.
  2. **MVC:开发模式**
  3. Mmodel 模型 javaBean:封装数据)
  4. VView 视图 JSP:展示数据)
  5. Ccontroller 控制器 Servlet:处理逻辑代码,做为控制器)

JSP&三层架构 - 图9

2.3模式三: 三层架构

  • 软件中分层:按照不同功能分为不同层,通常分为三层:表现层(web层),业务层,持久(数据库)层。
    JSP&三层架构 - 图10

  • 不同层次包名的命名

分层 包名(公司域名倒写)
表现层(web层) com.itheima.web
业务层(service层) com.itheima.service
持久层(数据库访问层) com.itheima.dao
JavaBean com.itheima.bean
工具类 com.itheima.utils
  • 分层的意义:

    1. 解耦:降低层与层之间的耦合性。 (以后面向接口编程)
    2. 可维护性:提高软件的可维护性,对现有的功能进行修改和更新时不会影响原有的功能。
    3. 可扩展性:提升软件的可扩展性,添加新的功能的时候不会影响到现有的功能。
    4. 可重用性:不同层之间进行功能调用时,相同的功能可以重复使用。

JSP&三层架构 - 图11

3.小结

  1. 模式一: JSP+JavaBean【了解】

  2. 模式二: MVC

    • M model JavaBean
    • V View JSP
    • C Controller Servlet
  3. 三层架构

    • WEB层

      • 获得请求参数
      • 调用业务
      • 响应
    • 业务层

      • 处理业务
      • 调用Dao
    • 持久层

      • 操作数据库
    • 三层架构中的包名:

      • 表现层: web
      • 业务层: service
      • 数据访问层/持久层: dao

案例-完成转账的案例v2

一.需求

  • 使用三层架构改写转账案例

JSP&三层架构 - 图12

二,分析

JSP&三层架构 - 图13

三,实现

  • UserServlet
  1. package com.itheima.web.servlet;
  2. import com.itheima.service.AccountService;
  3. import javax.servlet.ServletException;
  4. import javax.servlet.annotation.WebServlet;
  5. import javax.servlet.http.HttpServlet;
  6. import javax.servlet.http.HttpServletRequest;
  7. import javax.servlet.http.HttpServletResponse;
  8. import java.io.IOException;
  9. /**
  10. * 包名:${PACKAGE_NAME}
  11. *
  12. * @author Leevi
  13. * 日期2020-07-15 10:55
  14. */
  15. @WebServlet("/account")
  16. public class AccountServlet extends HttpServlet {
  17. @Override
  18. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  19. doGet(request, response);
  20. }
  21. @Override
  22. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  23. request.setCharacterEncoding("UTF-8");
  24. response.setContentType("text/html;charset=UTF-8");
  25. //1. 获取请求参数
  26. String fromName = request.getParameter("from");
  27. String toName = request.getParameter("to");
  28. Double money = Double.valueOf(request.getParameter("money"));
  29. try {
  30. //2. 调用业务层的AccountService的方法处理请求执行转账
  31. AccountService accountService = new AccountService();
  32. accountService.transfer(fromName,toName,money);
  33. //3. 转账成功
  34. response.getWriter().write("转账成功!!!");
  35. } catch (Exception e) {
  36. e.printStackTrace();
  37. //转账失败
  38. response.getWriter().write("转账失败!!!");
  39. }
  40. }
  41. }
  • AccountService
  1. package com.itheima.service;
  2. import com.itheima.dao.AccountDao;
  3. import java.sql.SQLException;
  4. /**
  5. * 包名:com.itheima.service
  6. *
  7. * @author Leevi
  8. * 日期2020-07-15 11:19
  9. */
  10. public class AccountService {
  11. private AccountDao accountDao = new AccountDao();
  12. public void transfer(String fromName,String toName,Double money) throws SQLException {
  13. //2.1 调用AccountDao的方法进行转出账户扣款
  14. accountDao.updateAccount(fromName,-money);
  15. //2.2 调用AccountDao的方法进行转入账户收款
  16. accountDao.updateAccount(toName,money);
  17. }
  18. }
  • UserDao
  1. package com.itheima.dao;
  2. import com.itheima.utils.DruidUtil;
  3. import org.apache.commons.dbutils.QueryRunner;
  4. import java.sql.SQLException;
  5. /**
  6. * 包名:com.itheima.dao
  7. *
  8. * @author Leevi
  9. * 日期2020-07-15 11:19
  10. */
  11. public class AccountDao {
  12. private QueryRunner queryRunner = new QueryRunner(DruidUtil.getDataSource());
  13. /**
  14. * 修改账户信息
  15. */
  16. public void updateAccount(String name,Double money) throws SQLException {
  17. String sql = "update account set money=money+? where name=?";
  18. queryRunner.update(sql,money,name);
  19. }
  20. }

四.小结

  • WEB层 com.itheima.web

    • 获得请求参数
    • 调用业务
    • 响应
  • 业务层 com.itheima.service xxService

    • 处理业务
    • 调用Dao
  • 持久层 com.itheima.dao xxDao

    • 操作数据库

案例-完成转账的案例v3

一.需求

  • 当单击提交按钮,付款方向收款方安照输入的金额转账。 使用手动事务进行控制

JSP&三层架构 - 图14

二,分析

1.DBUtils实现事务管理

API 说明
QueryRunner() 创建QueryRunner对象. 手动提交事务时使用
query(connection,String sql, Object[] params, ResultSetHandler rsh) 查询(需要传入Connection)
update(connection,String sql, Object… params) 更新

2.思路

JSP&三层架构 - 图15

三,实现

  • UserService
  1. package com.itheima.service;
  2. import com.itheima.dao.AccountDao;
  3. import com.itheima.utils.DruidUtil;
  4. import java.sql.Connection;
  5. import java.sql.SQLException;
  6. /**
  7. * 包名:com.itheima.service
  8. *
  9. * @author Leevi
  10. * 日期2020-07-15 11:19
  11. */
  12. public class AccountService {
  13. private AccountDao accountDao = new AccountDao();
  14. public void transfer(String fromName,String toName,Double money) {
  15. Connection conn = null;
  16. try {
  17. //逻辑操作开始之前开启事务: connection.setAutoCommit(false)
  18. conn = DruidUtil.getDataSource().getConnection();
  19. conn.setAutoCommit(false);
  20. //2.1 调用AccountDao的方法进行转出账户扣款
  21. accountDao.updateAccount(conn,fromName, -money);
  22. //模拟转账过程中出现异常
  23. int num = 10 / 0;
  24. //2.2 调用AccountDao的方法进行转入账户收款
  25. accountDao.updateAccount(conn,toName, money);
  26. //逻辑操作执行完毕没有异常,提交事务: connection.commit()
  27. conn.commit();
  28. } catch (Exception e) {
  29. e.printStackTrace();
  30. //逻辑操作执行过程中遇到异常,则在catch里面回滚事务: connection.rollback()
  31. try {
  32. conn.rollback();
  33. } catch (SQLException ex) {
  34. ex.printStackTrace();
  35. }
  36. throw new RuntimeException("转账失败");
  37. }
  38. }
  39. }
  • UserDao
  1. package com.itheima.dao;
  2. import com.itheima.utils.DruidUtil;
  3. import org.apache.commons.dbutils.QueryRunner;
  4. import java.sql.Connection;
  5. import java.sql.SQLException;
  6. /**
  7. * 包名:com.itheima.dao
  8. *
  9. * @author Leevi
  10. * 日期2020-07-15 11:19
  11. */
  12. public class AccountDao {
  13. private QueryRunner queryRunner = new QueryRunner(DruidUtil.getDataSource());
  14. /**
  15. * 修改账户信息
  16. * 指定使用某个连接Connection执行SQL语句
  17. */
  18. public void updateAccount(Connection connection,String name, Double money) throws SQLException {
  19. String sql = "update account set money=money+? where name=?";
  20. queryRunner.update(connection,sql,money,name);
  21. }
  22. }

四.小结

  1. 思想1: service层将异常try起来了,怎么才能让servlet还能够获取异常呢?
  1. catch里面抛运行时异常
  1. 思想2: 如果在service和dao共享一个Connection对象
    1. 通过调用方法的时候将connection作为参数传递给Dao
  1. 技术点1 : 怎么开启、提交、回滚事务
    1. connection.setAutoCommit(false)开启事务
    2. connection.commit()提交事务
    3. connection.rollback()回滚事务
    4. 注意: 开启事务的连接和执行SQL语句的连接要是同一个
  1. 技术点2 : 在使用DBUtils执行SQL语句的时候,怎么才能指定使用哪个连接呢?
    1. 调用queryRunner对象的update或者query方法的时候,可以传入connection

案例-完成转账的案例v4

一.需求

  • 当单击提交按钮,付款方向收款方安照输入的金额转账。 使用事务进行控制

JSP&三层架构 - 图16

二,分析

1.ThreadLocal

  1. 在“事务传递参数版”中,我们必须修改方法的参数个数,传递链接,才可以完成整个事务操作。如果不传递参数,是否可以完成?在JDK中给我们提供了一个工具类:ThreadLocal,此类可以在一个线程中共享数据。
  2. java.lang.ThreadLocal,该类提供了线程局部 (thread-local) 变量,用于在当前线程中共享数据。ThreadLocal工具类底层就是一个Mapkey存放的当前线程,value存放需要共享的数据
  1. package com.itheima;
  2. /**
  3. * 包名:com.itheima
  4. *
  5. * @author Leevi
  6. * 日期2020-07-15 14:58
  7. * ThreadLocal是线程本地变量,它的作用是用于在保证同一个线程中的对象使用的是同一份数据
  8. */
  9. public class TestMain {
  10. public static void main(String[] args) {
  11. //ThreadLocal的使用
  12. ThreadLocal<String> threadLocal = new ThreadLocal<>();
  13. //在主线程中往ThreadLocal对象中存储一个字符串"jay"
  14. threadLocal.set("jay");
  15. //在主线称重往ThreadLocal中存入一个字符串"aobama"
  16. threadLocal.set("aobama");
  17. //新线程
  18. new Thread(new Runnable() {
  19. @Override
  20. public void run() {
  21. //在新线程中,往ThreadLocal中存入"jay"
  22. threadLocal.set("jay");
  23. //在新线程中获取ThreadLocal中的值
  24. String s = threadLocal.get();
  25. System.out.println("在新线程中获取ThreadLocal中的值为:" + s);
  26. }
  27. }).start();
  28. //在主线程中取出ThreadLocal中的值
  29. String str = threadLocal.get();
  30. System.out.println("在主线程中获取ThreadLocal对象中的值:" + str);
  31. }
  32. }

2.思路

JSP&三层架构 - 图17

三,代码

  • DruidUtil
  1. package com.itheima.utils;
  2. import com.alibaba.druid.pool.DruidDataSourceFactory;
  3. import javax.sql.DataSource;
  4. import java.io.InputStream;
  5. import java.sql.Connection;
  6. import java.sql.SQLException;
  7. import java.util.Properties;
  8. /**
  9. * 包名:com.itheima.utils
  10. *
  11. * @author Leevi
  12. * 日期2020-07-06 11:45
  13. */
  14. public class DruidUtil {
  15. private static DataSource dataSource;
  16. private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
  17. static {
  18. try {
  19. //1. 创建Properties对象
  20. Properties properties = new Properties();
  21. //2. 将配置文件转换成字节输入流
  22. InputStream is = DruidUtil.class.getClassLoader().getResourceAsStream("druid.properties");
  23. //3. 使用properties对象加载is
  24. properties.load(is);
  25. //druid底层是使用的工厂设计模式,去加载配置文件,创建DruidDataSource对象
  26. dataSource = DruidDataSourceFactory.createDataSource(properties);
  27. } catch (Exception e) {
  28. e.printStackTrace();
  29. }
  30. }
  31. public static DataSource getDataSource(){
  32. return dataSource;
  33. }
  34. public static Connection getConnectionFromThreadLocal() throws SQLException {
  35. Connection connection = threadLocal.get();
  36. if (connection == null) {
  37. //说明ThreadLocal中还没有连接对象
  38. connection = dataSource.getConnection();
  39. //将connection存入到ThreadLocal
  40. threadLocal.set(connection);
  41. }
  42. return connection;
  43. }
  44. }
  • AccountService
  1. package com.itheima.service;
  2. import com.itheima.dao.AccountDao;
  3. import com.itheima.utils.DruidUtil;
  4. import java.sql.Connection;
  5. import java.sql.SQLException;
  6. /**
  7. * 包名:com.itheima.service
  8. *
  9. * @author Leevi
  10. * 日期2020-07-15 11:19
  11. */
  12. public class AccountService {
  13. private AccountDao accountDao = new AccountDao();
  14. public void transfer(String fromName,String toName,Double money) {
  15. Connection conn = null;
  16. try {
  17. //从ThreadLocal中获取连接对象
  18. //逻辑操作开始之前开启事务
  19. conn = DruidUtil.getConnectionFromThreadLocal();
  20. conn.setAutoCommit(false);
  21. //2.1 调用AccountDao的方法进行转出账户扣款
  22. accountDao.updateAccount(fromName, -money);
  23. //模拟转账过程中出现异常
  24. //int num = 10 / 0;
  25. //2.2 调用AccountDao的方法进行转入账户收款
  26. accountDao.updateAccount(toName, money);
  27. //逻辑操作执行完毕没有异常,提交事务: connection.commit()
  28. conn.commit();
  29. } catch (Exception e) {
  30. e.printStackTrace();
  31. //逻辑操作执行过程中遇到异常,则在catch里面回滚事务: connection.rollback()
  32. try {
  33. conn.rollback();
  34. } catch (SQLException ex) {
  35. ex.printStackTrace();
  36. }
  37. throw new RuntimeException("转账失败");
  38. }
  39. }
  40. }
  • AccountDao
  1. package com.itheima.dao;
  2. import com.itheima.utils.DruidUtil;
  3. import org.apache.commons.dbutils.QueryRunner;
  4. import java.sql.Connection;
  5. import java.sql.SQLException;
  6. /**
  7. * 包名:com.itheima.dao
  8. *
  9. * @author Leevi
  10. * 日期2020-07-15 11:19
  11. */
  12. public class AccountDao {
  13. private QueryRunner queryRunner = new QueryRunner(DruidUtil.getDataSource());
  14. /**
  15. * 修改账户信息
  16. * 指定使用某个连接Connection执行SQL语句
  17. */
  18. public void updateAccount(String name, Double money) throws SQLException {
  19. //从ThreadLocal对象中获取一个连接
  20. Connection connection = DruidUtil.getConnectionFromThreadLocal();
  21. String sql = "update account set money=money+? where name=?";
  22. queryRunner.update(connection,sql,money,name);
  23. }
  24. }

四.小结

  1. TheadLocal: jdk提供的一个对象. 只要是在同一个线程里面, 是可以共用的.
  2. 抽取了DruidUtil的getConnectionFromThreadLocal()方法, service和Dao里面的Connection都是从getConnectionFromThreadLocal()方法获取

补充案例:显示所有用户

目标

在list.jsp页面中显示user表中的所有用户的信息

分析

JSP&三层架构 - 图18

实现

  1. 拷贝jar、配置文件、工具类
  2. 创建index.jsp和list.jsp
  3. 创建包结构、pojo类
  4. 创建ShowAllServlet、UserService、UserDao

index.jsp代码

  1. <%--
  2. Created by IntelliJ IDEA.
  3. User: Fanyi Xiao
  4. Date: 2020/7/15
  5. Time: 12:08
  6. To change this template use File | Settings | File Templates.
  7. --%>
  8. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  9. <html>
  10. <head>
  11. <title>首页</title>
  12. </head>
  13. <body>
  14. <a href="/showAll">查看所有用户信息</a>
  15. </body>
  16. </html>
  1. **ShowAllServlet代码**
  1. package com.itheima.web.servlet;
  2. import com.itheima.pojo.User;
  3. import com.itheima.service.UserService;
  4. import javax.servlet.ServletException;
  5. import javax.servlet.annotation.WebServlet;
  6. import javax.servlet.http.HttpServlet;
  7. import javax.servlet.http.HttpServletRequest;
  8. import javax.servlet.http.HttpServletResponse;
  9. import java.io.IOException;
  10. import java.util.List;
  11. /**
  12. * 包名:${PACKAGE_NAME}
  13. *
  14. * @author Leevi
  15. * 日期2020-07-15 12:08
  16. */
  17. @WebServlet("/showAll")
  18. public class ShowAllServlet extends HttpServlet {
  19. @Override
  20. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  21. doGet(request, response);
  22. }
  23. @Override
  24. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  25. try {
  26. //1. 调用业务层的方法,处理查询所有用户的请求
  27. UserService userService = new UserService();
  28. List<User> userList = userService.findAll();
  29. //2. 将user的集合存储到request域对象中
  30. request.setAttribute("list",userList);
  31. //3. 跳转到list.jsp页面
  32. request.getRequestDispatcher("/list.jsp").forward(request, response);
  33. } catch (Exception e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. }

UserService代码

  1. package com.itheima.service;
  2. import com.itheima.dao.UserDao;
  3. import com.itheima.pojo.User;
  4. import java.sql.SQLException;
  5. import java.util.List;
  6. /**
  7. * 包名:com.itheima.service
  8. *
  9. * @author Leevi
  10. * 日期2020-07-15 12:09
  11. */
  12. public class UserService {
  13. private UserDao userDao = new UserDao();
  14. public List<User> findAll() throws SQLException {
  15. //调用dao对象的findAll()方法查询所有用户信息
  16. List<User> userList = userDao.findAll();
  17. return userList;
  18. }
  19. }

UserDao代码

  1. package com.itheima.dao;
  2. import com.itheima.pojo.User;
  3. import com.itheima.utils.DruidUtil;
  4. import org.apache.commons.dbutils.QueryRunner;
  5. import org.apache.commons.dbutils.handlers.BeanListHandler;
  6. import java.sql.SQLException;
  7. import java.util.List;
  8. /**
  9. * 包名:com.itheima.dao
  10. *
  11. * @author Leevi
  12. * 日期2020-07-15 12:09
  13. */
  14. public class UserDao {
  15. private QueryRunner queryRunner = new QueryRunner(DruidUtil.getDataSource());
  16. public List<User> findAll() throws SQLException {
  17. String sql = "select * from user";
  18. List<User> userList = queryRunner.query(sql, new BeanListHandler<>(User.class));
  19. return userList;
  20. }
  21. }

list.jsp代码

  1. <%--
  2. Created by IntelliJ IDEA.
  3. User: Fanyi Xiao
  4. Date: 2020/7/15
  5. Time: 12:08
  6. To change this template use File | Settings | File Templates.
  7. --%>
  8. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  9. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  10. <html>
  11. <head>
  12. <title>展示页面</title>
  13. </head>
  14. <body>
  15. <table border="1" cellspacing="0" width="800px" align="center">
  16. <tr>
  17. <th>序号</th>
  18. <th>用户名</th>
  19. <th>密码</th>
  20. <th>地址</th>
  21. <th>昵称</th>
  22. <th>性别</th>
  23. <th>邮箱</th>
  24. </tr>
  25. <%--
  26. 遍历出域对象里面的list中的每一个user
  27. --%>
  28. <c:forEach items="${list}" var="user" varStatus="vst">
  29. <tr>
  30. <td>${vst.count}</td>
  31. <td>${user.username}</td>
  32. <td>${user.password}</td>
  33. <td>${user.address}</td>
  34. <td>${user.nickname}</td>
  35. <td>${user.gender}</td>
  36. <td>${user.email}</td>
  37. </tr>
  38. </c:forEach>
  39. </table>
  40. </body>
  41. </html>

注册登录案例改成三层架构

RegisterServlet代码

  1. package com.itheima.web.servlet;
  2. import com.itheima.pojo.User;
  3. import com.itheima.service.UserService;
  4. import org.apache.commons.beanutils.BeanUtils;
  5. import javax.servlet.ServletException;
  6. import javax.servlet.annotation.WebServlet;
  7. import javax.servlet.http.HttpServlet;
  8. import javax.servlet.http.HttpServletRequest;
  9. import javax.servlet.http.HttpServletResponse;
  10. import java.io.IOException;
  11. import java.util.Map;
  12. /**
  13. * 包名:${PACKAGE_NAME}
  14. *
  15. * @author Leevi
  16. * 日期2020-07-12 16:15
  17. */
  18. @WebServlet("/register")
  19. public class RegisterServlet extends HttpServlet {
  20. @Override
  21. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  22. doGet(request, response);
  23. }
  24. @Override
  25. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  26. //在最前面解决乱码问题:请求参数的中文乱码,响应的中文乱码
  27. request.setCharacterEncoding("UTF-8");
  28. response.setContentType("text/html;charset=UTF-8");
  29. //1. 获取所有的请求参数
  30. Map<String, String[]> parameterMap = request.getParameterMap();
  31. //2. 使用BeanUtils 将parameterMap中的数据,存储到User对象中
  32. User user = new User();
  33. //设置默认的status为"0"
  34. user.setStatus("0");
  35. try {
  36. BeanUtils.populate(user,parameterMap);
  37. //3. 调用业务层的方法处理注册请求
  38. UserService userService = new UserService();
  39. userService.register(user);
  40. //如果存储的时候没有出现问题,则说明注册成功,使用重定向跳转到登录页面
  41. response.sendRedirect("/userDemo/login.jsp");
  42. } catch (Exception e) {
  43. e.printStackTrace();
  44. //如果注册失败,则向浏览器响应一句"注册失败"
  45. response.getWriter().write("注册失败");
  46. }
  47. }
  48. }

LoginServlet代码

  1. package com.itheima.web.servlet;
  2. import com.itheima.pojo.User;
  3. import com.itheima.service.UserService;
  4. import com.itheima.utils.CookieUtil;
  5. import javax.servlet.ServletException;
  6. import javax.servlet.annotation.WebServlet;
  7. import javax.servlet.http.*;
  8. import java.io.IOException;
  9. /**
  10. * 包名:${PACKAGE_NAME}
  11. *
  12. * @author Leevi
  13. * 日期2020-07-12 16:44
  14. */
  15. @WebServlet("/login")
  16. public class LoginServlet extends HttpServlet {
  17. @Override
  18. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  19. doGet(request, response);
  20. }
  21. @Override
  22. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  23. try {
  24. //1. 解决乱码
  25. request.setCharacterEncoding("UTF-8");
  26. response.setContentType("text/html;charset=UTF-8");
  27. //2. 获取请求参数username和password
  28. String username = request.getParameter("username");
  29. String password = request.getParameter("password");
  30. //获取浏览器传入的验证码(用户输入的验证码)
  31. String checkCode = request.getParameter("checkCode");
  32. //获取是否记住用户名,等待登录成功的时候再判断是否需要记住用户名
  33. String remember = request.getParameter("remember");
  34. //获取服务器生成的验证码,从session里面根据key "code"取出
  35. HttpSession session = request.getSession();
  36. String code = (String) session.getAttribute("code");
  37. //3. 校验验证码
  38. if (code.equalsIgnoreCase(checkCode)) {
  39. //验证码校验通过
  40. //调用业务层校验登录
  41. UserService userService = new UserService();
  42. User user = userService.login(username, password);
  43. //判断是否登录成功
  44. if (user != null) {
  45. //登录成功
  46. //判断是否记住用户名
  47. Cookie cookie = CookieUtil.createAndSetCookie("username", username, 7 * 24 * 60 * 60, request.getContextPath());
  48. if (remember == null) {
  49. //不需要记住用户名
  50. cookie.setMaxAge(0);
  51. }
  52. response.addCookie(cookie);
  53. //将user存储到session中
  54. session.setAttribute("user",user);
  55. //跳转到成功页面success.jsp
  56. response.sendRedirect("/userDemo/success.jsp");
  57. }else {
  58. //往request域对象中存放"用户名或密码错误"
  59. request.setAttribute("msg","用户名或密码错误");
  60. //请求转发跳转到login.jsp页面
  61. request.getRequestDispatcher("/login.jsp").forward(request, response);
  62. }
  63. }else {
  64. //往request域对象中存放"验证码错误"
  65. request.setAttribute("msg","验证码错误");
  66. //请求转发跳转到login.jsp页面
  67. request.getRequestDispatcher("/login.jsp").forward(request, response);
  68. }
  69. } catch (Exception e) {
  70. e.printStackTrace();
  71. //往request域对象中存放"服务器异常请稍后再试"
  72. request.setAttribute("msg","服务器异常请稍后再试");
  73. //请求转发跳转到login.jsp页面
  74. request.getRequestDispatcher("/login.jsp").forward(request, response);
  75. }
  76. }
  77. }

UserService代码

  1. package com.itheima.service;
  2. import com.itheima.dao.UserDao;
  3. import com.itheima.pojo.User;
  4. import java.sql.SQLException;
  5. /**
  6. * 包名:com.itheima.service
  7. *
  8. * @author Leevi
  9. * 日期2020-07-15 11:41
  10. */
  11. public class UserService {
  12. private UserDao userDao = new UserDao();
  13. public void register(User user) throws SQLException {
  14. //调用dao层的方法,添加用户信息
  15. userDao.addUser(user);
  16. }
  17. public User login(String username,String password) throws SQLException {
  18. //调用dao层的方法进行用户名和密码的校验
  19. User user = userDao.findUser(username,password);
  20. return user;
  21. }
  22. }

UserDao代码

  1. package com.itheima.dao;
  2. import com.itheima.pojo.User;
  3. import com.itheima.utils.DruidUtil;
  4. import org.apache.commons.dbutils.QueryRunner;
  5. import org.apache.commons.dbutils.handlers.BeanHandler;
  6. import java.sql.SQLException;
  7. /**
  8. * 包名:com.itheima.dao
  9. *
  10. * @author Leevi
  11. * 日期2020-07-15 11:41
  12. */
  13. public class UserDao {
  14. public void addUser(User user) throws SQLException {
  15. QueryRunner queryRunner = new QueryRunner(DruidUtil.getDataSource());
  16. String sql = "insert into user values (null,?,?,?,?,?,?,?)";
  17. queryRunner.update(sql,user.getUsername(),user.getPassword(),user.getAddress(),
  18. user.getNickname(),user.getGender(),user.getEmail(),user.getStatus());
  19. }
  20. public User findUser(String username, String password) throws SQLException {
  21. //连接数据库校验用户名和密码,也就是执行查询的SQL语句
  22. QueryRunner queryRunner = new QueryRunner(DruidUtil.getDataSource());
  23. String sql = "select * from user where username=? and password=?";
  24. //执行查询,查询一条数据,封装到User中
  25. User user = queryRunner.query(sql, new BeanHandler<>(User.class), username, password);
  26. return user;
  27. }
  28. }