ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

JSP&三层架构

2022-02-05 20:32:56  阅读:162  来源: 互联网

标签:转账 架构 String get money request connection JSP 三层


第一章-EL表达式

1.1 EL表达式概述

什么是El表达式

​ Expression Language:表达式语言, jsp2.0之后内置在jsp里面

​ 目的:为了使JSP写起来更加简单, 取值(取的域对象里面存的值)更加简单。(代替脚本 <% %>)

EL语法

${el表达式}

EL表达式的用途

​ 1.获取数据. 获取的是域(request,session,ServletContext)对象中存储的数据

​ 2.EL执行运算

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>01_EL表达式体验</title>
</head>
<body>
<%--el: 就是用来取域对象中的值,或者执行运算--%>
<%--格式: ${el表达式}--%>
<%--JSP-->翻译成Servlet-->翻译后里面内置了很多对象()--%>
<%--jsp内置对象:request(HttpServletRequest),response(HttpServletResponse),session(HttpSession),application(ServletContext),config(ServletConfig)--%>

<%
    // 请求域对象中存值
    request.setAttribute("username","zhangsan");
%>

<h1>jsp方式:</h1>
<%= request.getAttribute("username") %><br/>

<%--el里面的内置对象: requestScope,sessionScope,applicationScope,pageScope,cookie--%>
<h1>el方式:</h1>
${requestScope.get("username")}<br/>

<h1>el简单方式:</h1>
${username}<br/>

</body>
</html>

1.2 El获取数据

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

获取简单数据类型数据

​ 语法:${requestScope|sessionScope|applicationScope.属性名};

​ 快捷写法:${属性名}, 属性名就是存在域对象里面的key

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>02_el获取简单数据类型数据</title>
</head>
<body>
    
     <%--使用EL获取简单类型数据
        使用:
            1.在域对象中存储数据
            2.使用EL表达式获取数据
        注意:
            1.使用EL表达式从域对象中获取数据,如果使用简写方式,默认从作用域范围小的到大的【request-session-application】进行获取,
                获取到就直接返回,获取不到返回空字符串""
    --%>
    
<%
    //request是jsp的内置对象 无需创建,在jsp中可以直接使用  jsp9大内置对象:request、session、application【ServletContext】、out【response.getWriter()】、response
    /*往请求域对象中存值*/
    request.setAttribute("akey","aaa");

    /*往session域对象中存值*/
    session.setAttribute("bkey","bbb");

    /*往application域对象中存值(ServletContext)*/
    application.setAttribute("ckey","ccc");

    /*同时往请求域对象,session域对象,application域对象中存储一个同名的键与值*/
    //request.setAttribute("rkey","rrr");
    //session.setAttribute("rkey","rrrr");
    //application.setAttribute("rkey","rrrrr");
%>

<h1>取请求域对象中的值:</h1>
jsp方式:<br/>
<%= request.getAttribute("akey") %><br/>
el方式:<br/>
${requestScope.get("akey")}


<h1>取session域对象中的值:</h1>
jsp方式:<br/>
<%= session.getAttribute("bkey")%><br/>
el方式:<br/>
${sessionScope.get("bkey")}<br/>

<h1>取application域对象中的值:</h1>
jsp方式:<br/>
<%= application.getAttribute("ckey")%><br/>
el方式:<br/>
${applicationScope.get("ckey")}<br/>

<%--el表达式简单获取域对象值的方式: ${键名}--%>
<%--从小到大的范围进行查找:  request-->session-->application --%>
<h1>el简单方式</h1>
${akey}<br/>
${bkey}<br/>
${ckey}<br/>
${rkey}<br/>


</body>
</html>

获取数组

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

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>03_EL获取数组</title>
</head>
<body>
<%
    /*请求域对象中存数组*/
    String[] arr = {"china","hello","java"};
    request.setAttribute("array",arr);
%>

<h1>jsp方式取值:</h1>
<%= ((String[])request.getAttribute("array"))[0]%><br/>
<%= ((String[])request.getAttribute("array"))[1]%><br/>
<%= ((String[])request.getAttribute("array"))[2]%><br/>

<%--语法:${数组名[索引]}--%>
<h1>el方式取值: </h1>
${requestScope.get("array")[0]}<br/>
${requestScope.get("array")[1]}<br/>
${requestScope.get("array")[2]}<br/>
${array[0]}<br/>
${array[1]}<br/>
${array[2]}<br/>

</body>
</html>

获取list

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

<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>04_EL获取list集合</title>
</head>
<body>
<%
    ArrayList<String> list = new ArrayList<>();
    list.add("china");
    list.add("hello");
    list.add("java");
    request.setAttribute("list",list);
%>

<h1>jsp方式:</h1>
<%= ((ArrayList<String>)request.getAttribute("list")).get(0)%><br/>
<%= ((ArrayList<String>)request.getAttribute("list")).get(1)%><br/>
<%= ((ArrayList<String>)request.getAttribute("list")).get(2)%><br/>

<h1>el方式:</h1>
${requestScope.get("list").get(0)}<br/>
${requestScope.get("list").get(1)}<br/>
${requestScope.get("list").get(2)}<br/>
${list.get(0)}<br/>
${list.get(1)}<br/>
${list.get(2)}<br/>
${list[0]}<br/>
${list[1]}<br/>
${list[2]}<br/>

</body>
</html>

获取Map

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

<%@ page import="java.util.HashMap" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>05_EL获取Map</title>
</head>
<body>
<%
    HashMap<String,String> map = new HashMap<>();
    map.put("k1","v1");
    map.put("k2","v2");
    map.put("k3","v3");
    request.setAttribute("m",map);
%>

<%--语法: ${域对象的key.map集合的key} 或者 ${域对象的key.get(map集合的key)}--%>
<h1>EL方式:</h1>
${m.k1}<br/>
${m.k2}<br/>
${m.k3}<br/>

${m.get("k1")}<br/>
${m.get("k2")}<br/>
${m.get("k3")}<br/>

</body>
</html>

获取bean

语法:${key.javabean属性}

​ 依赖getxxx()方法; eg: getPassword()—去掉get–>Password()----首字母小写—>password

<%@ page import="com.geekly.bean.User" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>06_EL获取bean</title>
</head>
<body>
<%
    User user = new User("zs","123456");
    request.setAttribute("u",user);
%>
<h1>el方式:</h1>
${u.username}<br/>
${u.password}<br/>

</body>
</html>

注意事项

  • 能获取到则获取,获取不到返回" "字符串 ,不是返回null

  • ${域中属性名}:依次从requestScope|sessionScope|applicationScope中查找指定的属性

    ​ 若找到,立即返回,且结束该次查找

    ​ 若找不到返回""

  • []和.方式的区别: 有特殊字符的要用[]

    • 若属性名中出现了".""+""-"等特殊的符号的时候,快捷获取的方式不好使,必须使用以下方式:

    ​ ${xxxScope[“属性名”]}

特殊情况:

<%@ page import="java.util.HashMap" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>07_EL取值注意事项.jsp</title>
</head>
<body>
<%--能获取到则获取,获取不到返回" "字符串 ,不是返回null--%>
${akey}<br/>

<%--${域中属性名}:依次从requestScope|sessionScope|applicationScope中查找指定的属性--%>
<%
    /*同时往请求域对象,session域对象,application域对象中存储一个同名的键与值*/
    //request.setAttribute("rkey","rrr");
    //session.setAttribute("rkey","rrrr");
    //application.setAttribute("rkey","rrrrr");
%>
${rkey}<br/>

<%
    request.setAttribute("a.b.c.d","abcd");

    HashMap<String,String> map = new HashMap<>();
    map.put("a.k1","v1");
    map.put("k2","v2");
    map.put("k3","v3");
    request.setAttribute("m",map);

%>
<%--
[]和.方式的区别: 有特殊字符的要用[]
- 若属性名中出现了".""+""-"等特殊的符号的时候,快捷获取的方式不好使,必须使用以下方式:
${xxxScope["属性名"]}
${key["属性名"]}
--%>
<h1>el方式:</h1>
${a.b.c.d} -- ${requestScope.get("a.b.c.d")} -- ${requestScope["a.b.c.d"]}<br/>
${m.a.k1} -- ${requestScope.get("m").get("a.k1")} -- ${m["a.k1"]}<br/>

</body>
</html>

1.3 EL执行运算

2.1算术运算

+,-,*,/,%

+:加号在EL表达式中代表加运算,不作拼接使用,如果是数字的字符串形式,则EL表达式会自动进行类型转换,然后再进行算术运算

  • +不能拼接字符串.

    <body>
    <%
        request.setAttribute("num",10);
    %>
    
    <h1>EL执行运算: 与java中操作一样</h1>
    ${10 + 20}<br/>
    ${10 > 20}<br/>
    ${num + 20}<br/>
    
    <h1>EL执行运算: 与java中操作不一样</h1>
    <%--算术运算符的+号运算符--%>
    <%--java中基本类型和字符串相加是拼接--%>
    <%--EL中基本类型和字符串相加不能拼接,如果是数组加字符串,并且字符串是数字,会自动格式化,否则会报异常--%>
    ${num +  "20"}<br/>
    ${num +  "abc"}<br/>
    
    
    </body>
    

2.2关系运算

> < >= <= != ==

2.3逻辑运算

&& || !

2.4非空判断【重点】

​ empty,

​ **1. 判断一个对象是否为null,为null返回true **

2. 判断集合长度是否为0,集合为null或长度为0返回true

​ 3. 判断一个字符串是否为 null或"",如果是则返回true

​ not empty

​ 语法: ${empyt 属性名};属性名 就是域对象里面的key值

<%--empty:  判断一个对象是否为null;  判断集合长度是否为0;   判断一个字符串是否为 ""--%>
<%
    User u1 = new User();
    User u2 = null;
    ArrayList<String> list1 = new ArrayList<>();
    ArrayList<String> list2 = null;
    String str1 = "";
    String str2 = null;

    request.setAttribute("u1",u1);
    request.setAttribute("u2",u2);
    request.setAttribute("list1",list1);
    request.setAttribute("list2",list2);
    request.setAttribute("str1",str1);
    request.setAttribute("str2",str2);
%>

${empty u1}<br/>
${empty u2}<br/>
${empty list1}<br/>
${empty list2}<br/>
${empty str1}<br/>
${empty str2}<br/>
<hr/>
${not empty u1}<br/>
${not empty u2}<br/>
${not empty list1}<br/>
${not empty list2}<br/>
${not empty str1}<br/>
${not empty str2}<br/>

第二章-JSTL标签库

2.1 JSTL标签库概述

什么是JSTL标签库

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

JSTL标签库的作用

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

JSTL和EL是黄金搭档:JSTL作逻辑处理,EL获取数据展示。

JSTL标签库的类别

标签库功能描述标签库的uri建议前缀
核心标签库http://java.sun.com/jsp/jstl/corec
XML标签库http://java.sun.com/jsp/jstl/xmlx
国际化/格式化标签库http://java.sun.com/jsp/jstl/fmtfmt
数据库标签库http://java.sun.com/jsp/jstl/sqlsql
EL自定义函数http://java.sun.com/jsp/jstl/functionsfn

小结

  1. JSTL:JSP标准标签库,用作逻辑处理,可以代替java小脚本,简化jSP开发
  2. 作用:判断数据 遍历数据
  3. 使用:由于JSTL没有被集成到JSP中,使用时需要导入jar包

2.2 JSTL核心标签库

核心标签库使用步骤

  1. 导入jar包(jstl.jar与standard.jar)

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

if标签

属性名是否支持EL属性类型属性描述
testtrueboolean决定是否处理标签体中的内容的条件表达式
varfalseString用于指定将test属性的执行结果保存到某个Web域中的某个属性的名称
scopefalseString指定将test属性的执行结果保存到哪个Web域中
  • 语法
<c:if test="el表达式${..}" [var="给之前的表达式的结果起个名字"] [scope="将结果保存在那个域中 默认page"]>
</c:if>
  • 实例
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%
        //域对象存储数据
        request.setAttribute("age",6);
    %>
    <%--
        if标签:用于判断  test属性值为true,则执行if标签体中的内容,为false,不执行
            test:设置判断条件 可以使用EL表达式进行判断 返回一个boolean类型的结果true|false
            var:声明一个变量 存储判断结果
            scope:将判断结果变量存入到一个作用域中  方便后期使用
    --%>
    <c:if test="${age >= 7}" var="flag" scope="request">
        <h4>可以上小学了</h4>
    </c:if>
    <c:if test="${age<7}">
        <h4>回家玩泥巴去吧</h4>
    </c:if>
    <h3>if判断结果:${requestScope.flag}</h3>
</body>
</html>

choose标签—if.else if

  • 语法:

    • <c:choose>
    • <c:when test=“el表达式”>
    • <c:otherwise> else
  • 实例

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%
        //域对象存储数据
        request.setAttribute("age",15);
        //需求:大于6岁可以上小学 大于13岁可以上中学  大于18岁可以上大学  如果小于等于6岁回家玩泥巴
        //分析:使用多重if判断实现
        //实现:
    %>
    <%--c:choose表示的就是多重if选择结构  c:when表示的就是if判断  c:otherwise表示的就是else--%>
    <c:choose>
        <c:when test="${age>18}">
            上大学
        </c:when>
        <c:when test="${age>13}">
            上中学
        </c:when>
        <c:when test="${age>6}">
            上小学
        </c:when>
        <c:otherwise>
            回家玩泥巴
        </c:otherwise>
    </c:choose>
</body>
</html>

foreach标签

属性名是否支持EL属性类型属性描述
varfalseString指定将当前迭代到的元素保存到page这个Web域中的属性名称
itemstrue任何支持的类型将要迭代的集合对象
varStatusfalseString指定将代表当前迭代状态信息的对象保存到page这个Web域中的属性名称
begintrueint如果指定items属性,就从集合中的第begin个元素开始进行迭代,begin的索引值从0开始编号;如果没有指定items属性,就从begin指定的值开始迭代,直到end值时结束迭代
endtrueint参看begin属性的描述
steptrueint指定迭代的步长,即迭代因子的迭代增量
  • 简单的使用:

    <%--forEach标签的简单使用
            需求:使用foreach标签遍历1-10 每个数字显示字题为红色
            forEach标签:用于遍历数据
                var:迭代变量 在foreach标签体中获取迭代变量数据 需要使用el表达式
                begin:开始 从第几个开始遍历
                end:结束  遍历到第几个结束
                step:步长 间隔
                varStatus:记录迭代变量的状态信息
    --%>
    
    <c:foreach begin="从哪里开始" end="到哪里结束" var="每次遍历的赋值变量" step="步长">
    	//每遍历一次 foreach里面就执行一次
    </c:foreach>		
    
  • 复杂的使用:

    <c:foreach items="使用el从域对象里面取出集合" var="每次遍历的赋值变量" varStatus="遍历的状态">
    	//每遍历一次 foreach里面就执行一次
    </c:foreach>
    
  • c:forEach中的varStatus属性。

    这个对象记录着当前遍历的元素的一些信息:

    index:返回索引。从0开始

    count:返回计数。从1开始

    last:是否是最后一个元素

    first:是否是第一个元素

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>04_forEach标签</title>
</head>
<body>
<%--普通循环: 循环打印10次hello jsp...--%>
<%--begin: 循环起始位置--%>
<%--end: 循环结束位置--%>
<%--step:步长--%>
<%--var: 存储遍历的变量(域,默认page)--%>
<c:forEach begin="1" end="10" step="1" var="i">
    <font color="red">hello jsp...${i}</font><br/>
</c:forEach>

<%--增强for循环: 循环遍历集合中的元素--%>
<%
    ArrayList<String> list = new ArrayList<>();
    list.add("china");
    list.add("hello");
    list.add("java");
    request.setAttribute("l",list);
%>
    
<%--items:要迭代的集合或者数组...--%>
<%--varStatus:记录迭代过程中的状态()--%>
<%--
c:forEach中的varStatus属性。
这个对象记录着当前遍历的元素的一些信息:
       		   index:返回索引。从0开始
        		count:返回计数。从1开始
       		    last:是否是最后一个元素
        		first:是否是第一个元素
--%>
<c:forEach items="${l}" var="e" varStatus="status">
    ${e}<br/>
    当前循环的索引:${status.index}<br/>
    当前循环的次数:${status.count}<br/>
    当前迭代出来的元素是否是最后一个元素:${status.last}<br/>
    当前迭代出来的元素是否是第一个元素:${status.first}<br/>
    <hr/>
</c:forEach>

</body>
</html>

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

案例-完成转账的案例v1

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

1.案例的准备工作

  • 数据库的准备

    create database day26;
    use day26;
    create table account(
        id int primary key auto_increment,
        name varchar(20),
        money double
    );
    
    insert into account values (null,'zs',1000);
    insert into account values (null,'ls',1000);
    insert into account values (null,'ww',1000);
    
  • 页面

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <title>Insert title here</title>
    </head>
    
    <body>
    <form  action="ServletTransfer" method="post">
      <table border="1px" width="500px" align="center">
        <tr>
          <td>付款方</td>
          <td><input type="text" name="from"></td>
        </tr>
        <tr>
          <td>收款方</td>
          <td><input type="text" name="to"></td>
        </tr>
        <tr>
          <td>金额</td>
          <td><input type="text" name="money"></td>
        </tr>
        <tr>
          <td colspan="2"><input type="submit"></td>
        </tr>
      </table>
    </form>
    
    </body>
    </html>
    
  • jar包

  • 工具类

  • 配置文件

2.代码实现

  • UserServlet
@WebServlet("/ServletTransfer")
public class ServletTransfer extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            // 1.处理乱码
            request.setCharacterEncoding("utf-8");
            response.setContentType("text/html;charset=utf-8");

            //2.获得请求参数(付款方,收款方,转账金额)
            String fromUsername = request.getParameter("from");
            String toUsername = request.getParameter("to");
            String moneyStr = request.getParameter("money");
            double money = Double.parseDouble(moneyStr);

            //3.业务逻辑判断(余额是否够转账,收款方的名字是否合法,.....)
            //3.创建QueryRunner对象
            QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());

            //4.执行sql语句
            String sql1 = "update account set money = money - ? where name = ?";
            int rows1 = qr.update(sql1, money, fromUsername);

            String sql2 = "update account set money = money + ? where name = ?";
            int rows2 = qr.update(sql2, money, toUsername);

            //5.判断结果,然后响应结果到页面(转账成功,转账失败)
            if (rows1 > 0 && rows2 > 0){
                // 转账成功
                response.getWriter().println("转账成功!");
            }else{
                // 转账失败
                response.getWriter().println("转账失败!");
            }

        } catch (SQLException e) {
            e.printStackTrace();
            // 转账失败
            response.getWriter().println("转账失败!");
        }
    }

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

开发模式

JSP的开发模式一

jsp+javabean:实现

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

1.浏览器请求服务器jsp

2.jsp处理请求响应浏览器

所有代码都在jsp中

问题:

​ 1.所有的代码都在jsp中 会存在大量代码冗余 不利于代码维护修改

​ 2.jsp已经属于上个时代的技术了 过时了 jsp执行效率非常低 jsp–>翻译成java代码–>编译class文件–>执行

JSP的开发模式二

​ JSP + Servlet + JavaBean 称为MVC的开发模式.

MVC:开发模式

​ M:model 模型 (javaBean:封装数据)

​ V:View 视图  (JSP:展示数据)

​ C:controller 控制器 (Servlet:处理逻辑代码,做为控制器)

模式三: 三层架构

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

  • 不同层次包名的命名

分层包名
表现层(web层)com.geekly.web 编写Servlet
业务层(service层)com.geekly.service 编写Service类
持久层(数据库访问层)com.geekly.dao 编写Dao类
JavaBeancom.geekly.bean 封装数据
工具类com.geekly.utils 编写工具类
  • 分层的意义:
    1. 解耦:降低层与层之间的耦合性。
    2. 可维护性:提高软件的可维护性,对现有的功能进行修改和更新时不会影响原有的功能。
    3. 可扩展性:提升软件的可扩展性,添加新的功能的时候不会影响到现有的功能。
    4. 可重用性:不同层之间进行功能调用时,相同的功能可以重复使用。

缺点:代码量增多,结构复杂,当新增功能时,需要web、service、dao分别写一次。

案例-完成转账的案例v2-三层架构

  • 使用三层架构改写转账案例
@WebServlet("/transfer")
public class TransferServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            //0.中文乱码处理
            request.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;charset=UTF-8");
            //1.获取请求参数【付款方、收款方、金额】
            String from = request.getParameter("from"); //付款方
            String to = request.getParameter("to");     //收款方
            double money = Double.parseDouble(request.getParameter("money"));     //转账金额
            //2.调用业务处理
            TransferService transferService = new TransferService();
            boolean flag = transferService.transfer(from,to,money);
            //3.响应
            if(flag){
                response.getWriter().print("转账成功!");
            }else{
                response.getWriter().print("转账失败!");
            }
        } catch (Exception e) {
            e.printStackTrace();
            response.getWriter().print("服务器异常!");
        }
    }

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

    /**
     * 转账业务
     * @param from  付款方
     * @param to    收款方
     * @param money 转账金额
     * @return 转账是否成功  true|false
     */
    public boolean transfer(String from, String to, double money) throws SQLException {
        //1.处理业务【判断付款方 收款方是否存在 转账金额是否合理  假设一切正常】
        //2.调用dao
        TransferDao transferDao = new TransferDao();
        //2.1:付款方钱减少
        int rows1 = transferDao.reduceMoney(from,money);

        //2.2:收款方钱增加
        int rows2 = transferDao.addMoney(to,money);
        //3.根据dao处理结果判断转账是否成功 并返回
        if(rows1>0 && rows2>0){
            return true;
        }
        return false;
    }
}
public class TransferDao {

    /**
     * 付款方钱减少
     * @param from
     * @param money
     * @return
     */
    public int reduceMoney(String from, double money) throws SQLException {
        //1.操作数据库
        QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
        String sql = "update account set money = money-? where name=?";
        return queryRunner.update(sql,money,from);
    }

    /**
     * 收款方钱增加
     * @param to
     * @param money
     * @return
     */
    public int addMoney(String to, double money) throws SQLException {
        //1.操作数据库
        QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
        String sql = "update account set money = money+? where name=?";
        return queryRunner.update(sql,money,to);
    }
}

案例-完成转账的案例v3-事务控制

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

DBUtils实现事务管理

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

    /**
     * 转账业务
     * @param from  付款方
     * @param to    收款方
     * @param money 转账金额
     * @return 转账是否成功  true|false
     * 需求:转账包含两个操作:一个钱减少,一个钱增加,只有当钱减少和钱增加两个操作都执行成功时,才表示转账成功,如果有一个失败,则转账失败,付款方和收款方的金额应该不变
     * 分析:要将转账的两个操作封装成为一个整体,使用事务  事务的特性:将多个操作作为一个整体执行,要成功,都成功,要失败,都失败
     * 事务的使用:
     *      1.开启事务          :connection.setAutoCommit(false);
     *      2.执行操作          :钱减少、钱增加
     *      3.事务提交或事务回滚  :true:connection.commit();     false|exception:connection.rollback();
     * 事务使用细节:执行操作所有的connection连接对象要是同一个,如果不是同一个,则不能进行事务控制
     * 事务使用的地方:
     *      事务使用在service层,将多个数据库操作作为一个整体执行。
     */
    public boolean transfer(String from, String to, double money) throws Exception {

        /********1.开启手动事务*******/
        Connection connection = C3P0Utils.getConnection();
        connection.setAutoCommit(false);


        try {
            //1.处理业务【判断付款方 收款方是否存在 转账金额是否合理  假设一切正常】
            //2.调用dao
            TransferDao transferDao = new TransferDao();
            //2.1:付款方钱减少
            int rows1 = transferDao.reduceMoney(connection,from,money);

            //人为制作异常 用于测试
            //int i = 1/0;

            //2.2:收款方钱增加
            int rows2 = transferDao.addMoney(connection,to,money);
            //3.根据dao处理结果判断转账是否成功 并返回
            if(rows1>0 && rows2>0){
                //转账成功 提交事务
                connection.commit();
                return true;
            }else{
                //转账失败 回滚事务
                connection.rollback();
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            //发生异常 回滚事务
            connection.rollback();
            return false;
        }
    }
}
public class TransferDao {

    /**
     * 付款方钱减少
     * @param from
     * @param money
     * @return
     */
    public int reduceMoney(Connection connection, String from, double money) throws SQLException {
        //1.操作数据库
        //注意:多个操作使用同一个connection时,才能进行事务控制  所以此时创建QueryRunner对象时使用无参构造方法
        QueryRunner queryRunner = new QueryRunner();
        String sql = "update account set money = money-? where name=?";
        return queryRunner.update(connection,sql,money,from);
    }

    /**
     * 收款方钱增加
     * @param to
     * @param money
     * @return
     */
    public int addMoney(Connection connection, String to, double money) throws SQLException {
        //1.操作数据库
        QueryRunner queryRunner = new QueryRunner();
        String sql = "update account set money = money+? where name=?";
        return queryRunner.update(connection,sql,money,to);
    }
}
  1. 事务使用步骤
    1. 手动开启事务:connection.setAutoCommit(false);
    2. 执行操作:多个操作需要使用同一个连接对象connection
    3. 事务提交或事务回滚:connection.commit(); connection.rollback();
  2. 事务使用位置:使用在Service层【一个业务功能包含多个操作作为一个整体】
  3. 通过在Service层获取connection对象 传递到dao层进行使用操作数据库。

案例-完成转账的案例v4-事务控制增强

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

ThreadLocal

​ 在“事务传递参数版”中,我们必须修改方法的参数个数,传递连接对象,才可以完成整个事务操作。如果不传递参数,是否可以完成?在JDK中给我们提供了一个工具类:ThreadLocal,此类可以在一个线程中共享数据。

​ java.lang.ThreadLocal,该类提供了线程局部 (thread-local) 变量,用于在当前线程中共享数据。ThreadLocal工具类底层就是一个Map,key存放的当前线程,value存放需要共享的数据

//模拟ThreadLocal类 
public class ThreadLocal{
	private Map<Thread,Object> map = new HashMap<Thread,Object>();
	
	public void set(Connection conn){
		map.put(Thread.currentThread(),conn); //以当前线程对象作为key
	}
		
	public Object get(){
		return map.get(Thread.currentThread()); //只有当前线程才能取出value数据
	}
}
ThreadLocal:实现在当前线程下共享数据【范围小很多】  
类似于ServletContext在当前应用下共享数据【范围大一些】
结论:向ThreadLocal对象中添加的数据只能在当前线程下使用。
  • ConnectionManager
public class ConnectionManager {
    // 创建ThreadLocal对象
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();

    // 提供一个方法获得连接对象
    public static Connection getConnection() throws Exception{
        // 获取ThreadLocal中的值(连接对象)
        Connection connection = threadLocal.get(); 

        // 没有获取到Connection对象,就添加一个Connection对象。第一次获取的时候ThreadLocal中还没有存储connection对象  因此获取之后,将connection存入到ThreadLocal中,这样后面同一个线程就可以获取到了
        if (connection == null){
            connection = C3P0Utils.getConnection();
            threadLocal.set(connection);
        }

        // 返回连接对象
        return connection;
    }
}
public class TransferService {

    /**
     * 转账业务
     * @param from  付款方
     * @param to    收款方
     * @param money 转账金额
     * @return 转账是否成功  true|false
	*/
    public boolean transfer(String from, String to, double money) throws Exception {

        /********1.手动开启事务*******/
        Connection connection = ConnectionManager.getConnection();
        connection.setAutoCommit(false);

        try {
            //1.处理业务【判断付款方 收款方是否存在 转账金额是否合理  假设一切正常】
            //2.调用dao
            TransferDao transferDao = new TransferDao();
            //2.1:付款方钱减少
            int rows1 = transferDao.reduceMoney(from,money);

            //人为制作异常 用于测试
            //int i = 1/0;

            //2.2:收款方钱增加
            int rows2 = transferDao.addMoney(to,money);
            //3.根据dao处理结果判断转账是否成功 并返回
            if(rows1>0 && rows2>0){
                //转账成功 提交事务
                connection.commit();
                return true;
            }else{
                //转账失败 回滚事务
                connection.rollback();
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            //发生异常 回滚事务
            connection.rollback();
            return false;
        }

    }
}
public class TransferDao {

    /**
     * 付款方钱减少
     * @param from
     * @param money
     * @return
     */
    public int reduceMoney(String from, double money) throws Exception {
        //1.操作数据库
        //注意:多个操作使用同一个connection时,才能进行事务控制  所以此时创建QueryRunner对象时使用无参构造方法
        QueryRunner queryRunner = new QueryRunner();
        String sql = "update account set money = money-? where name=?";
        return queryRunner.update(ConnectionManager.getConnection(),sql,money,from);
    }

    /**
     * 收款方钱增加
     * @param to
     * @param money
     * @return
     */
    public int addMoney(String to, double money) throws Exception {
        //1.操作数据库
        QueryRunner queryRunner = new QueryRunner();
        String sql = "update account set money = money+? where name=?";
        return queryRunner.update(ConnectionManager.getConnection(),sql,money,to);
    }
}
  1. TheadLocal: jdk提供的一个对象. 只要是在同一个线程里面, 数据是可以共用的.
  2. 抽取了ConnectionManager, service和Dao里面的Connection都是从ConnectionManager里面获得的

总结

	1.EL获取域对象中的数据
    2.EL执行运算
    3.JSTL----if标签,forEach标签
    4.转账案例---->案例4
        
- 能够说出el表达式的作用
    为了使JSP写起来更加简单,  取值(取的域对象里面存的值)更加简单。(代替脚本 <% %>)
    
- 能够使用el表达式获取javabean的属性
    简单类型: ${属性名}
	数组类型: ${属性名[索引]}
	List集合: ${属性名[索引]}  或者 ${属性名.get(索引)}
	Map集合: ${属性名.键}  或者 ${属性名.get(键)}
	JavaBean: ${属性名.JavaBean属性名}

- 能够使用jstl标签库的if标签
<c:if test="el表达式${..}" [var="给之前的表达式的结果起个名字"] [scope="将结果保存在那个域中 默认page"]>
</c:if>
    
- 能够使用jstl标签库的foreach标签
<c:foreach begin="从哪里开始" end="到哪里结束" var="每次遍历的赋值变量" step="步长">
	//每遍历一次 foreach里面就执行一次
</c:foreach>
    
<c:foreach items="使用el从域对象里面取出集合" var="每次遍历的赋值变量" varStatus="遍历的状态">
	//每遍历一次 foreach里面就执行一次
</c:foreach>  
    
- 能够使用三层架构模式完成显示用户案例
    web
	service
    dao
    utils
    bean
- 能够使用ThreadLocal
    保证同一条线程中使用的对象是同一个
    
- 能够完成转账案例

标签:转账,架构,String,get,money,request,connection,JSP,三层
来源: https://blog.csdn.net/LyonBlog/article/details/122792941

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有