高级第三天:Spring框架

主要内容

1.SpringAOP之Aspectj实现方式

2.SpringTX的介绍

3.SpringTX代码实现

4.SpringTX的详解

5.Spring中常见的注解

6.银行转账案例

7.Spring内容总结

一.SpringAOP的Aspectj方式实现

[1]SpringAOP的Aspectj介绍

问题:

    目前我们已经能够使用SrpingAOP的Schema-based方式来实现功能扩展.在使用Schema-based方式实现功能扩展时,发现一个扩展代码就需要声明对应的实现了指定的接口的类,这样造成代码的结构体系过于繁杂.一个通知一个类.

解决:    

    在一个类中声明所有的通知方法.这样又会造成Srping容器无法区分该类中的方法哪些是前置,哪些是后置,哪些是环绕,哪些是异常了,怎么办?在配置文件中的切面配置中,指明哪些方法是前置,哪些是后置即可.

实现:

    SpringAOP的AspectJ方式

使用:

    1)创建一个web项目并导入AOP的相关jar包

    2)在src下声明mvc的包结构

    3)在src下创建并配置applicationcontext.xml

        a.切点的bean

        b.扩展类的bean

        c.配置切面

            声明切点

            声明前置通知

            声明后置通知

            声明环绕通知

            声明异常通知

    4)获取Spring容器中的扩展对象完成功能操作

[2]SpringAOP的代码实现

    通知类:

applicationcontext.xml

[3]Acspectj和SchemaBased的异同

1.相同点:

    在不修改源码的情况下都能实现功能的扩展

2.不同点

(1)SchemaBased方式基于接口来区别前置和后置和环绕和异常通知的,而AspectJ方式是在配置文件中使用标签来区分

(2)AspectJ方式在配置中的配置方式发现其切点的声明以及对应的通知组装中,切点只在Aop:aspect标签下有效.而SchemaBased方式声明的切点在全局有效.SchemaBased的切点的通用性比AspectJ方式要好

(3)AspectJ方式扩展涉及参数的流程:

    1)切点方法中声明形参完成数据处理

    2)修改通知方法声明形参接受对应的实参

    3)修改配置文件中的切点声明,切点中的方法上声明对应的参数类型.同时还要声明参数的形参名

    4)在通知的配置上声明参数名

(4)在SchemaBased方式涉及形参的流程:

1)在切点方法上声明形参完成功能处理

2)在配置文件中修改切点的路径为带有参数的切点

3)直接在通知方法中的形参中的Object[]中获取参数是用即可

总结:不涉及到参数问题使用AspectJ方式完成功能扩展比较方便,但是涉及到参数后使用SchemaBased方式比较方便

二.SpringTX的介绍

[1]问题

在学习了Spring整合mybatis后,我们可以直接从Spring容器中获取mapper层的实例化对象完成数据库操作.二在业务层方法中很多时候因为业务逻辑的复杂性,会出现在业务层方法中调用多个数据库操作.而之前我们学习过十五的管理,在前同一个业务中只要有一个数据库操作执行失败,其他的就锁执行成功也会一并回滚.但是在Srping整合MyBatis后,我们获取的直接是Mapper接口的实例化对象,而事务的管理需要使用connection对象来完成或者SqlSession对象来完成.那么在Spring整合MyBatis后如何声明事务管理代码呢?

[2]解决

    假如我们能够从Spring容器中获取SqlSession对象,那么在业务方法A中调用了多次的数据库操作,我们就需要在A业务方法中的业务逻辑代码之前开启事物管理,在逻辑代码之后进行提交或者回滚.假如有10个业务方法需要声明式事务管理,则需要声明10次,过于麻烦,而且需要修改业务方法的源码.基于以上的流程我们发现,该扩展流程完全符合AOP的基本规范,考虑使用SpringAOP的方式来对业务方法进行扩展,声明环绕通知,在环绕通知中声明事务管理代码,切点为要进行事务管理的业务方法.

但是我们又无法直接获取到SqkSession对象,造成无法在环绕通知中声明管理代码,有发现事务管理的代码时重复的代码,那么能不能让Spring官方给我们直接提供一个和Spring容器直接整合好的事务管理类.答案是可以的

[3]实现

[4]概念

    编程是事务

        事务管理代码由程序员自己编写

    声明式事务:

        事务管理代码由第三方直接提供,程序员直接将其组装到功能中即可

[5]理论图

三.SpringTX实现

[1]SpringTX的使用流程

1)导入相关jar包

    a.SpringIOC的jar

    b.SpringAOP的jar

    c.SpringTX的jar

    d.Spring整合MyBatis的jar

    e.MyBatis的jar

    f.数据库的驱动的jar

2)搭建Spring整合MyBatis的项目

3)在applicationcontext.xml文件中配置事务管理bean

4)确定切点:增加事务的方法

5)通知:事务通知

6)织入成事务切面

[2]代码实现

<!--进行userMapper值的注入-->

<bean id="users" class="com.bjsxt.service.impl.UserServiceImpl" autowire="byName"></bean>

<!--声明事务管理的对象-->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource"></property>

</bean>

<!--事务的通知-->

<tx:advice id="advice" transaction-manager="transactionManager">

    <tx:attributes>

        <tx:method name="login"/>

    </tx:attributes>

</tx:advice>

<!--配置TX声明式事务-->

<aop:config>

    <aop:pointcut id="pt2" expression="execution(*com.bjsxt.service.impl.UserServiceImpl.*(..))"></aop:pointcut>

    <aop:advisor advice-ref="advice" pointcut-ref></aop:advisor>

</aop:config>

四.声明式事务中属性解释

[1]name

哪些方法需要有事务控制 支持*通配符

[2]readonly="boolean"

是否是只读事务

1)如果为true,告诉数据库此事务为只读事务,数据化优化,会对性能有一定提升,所以只要是查询的方法,建议使用次数据

2)如果为false(默认值)事务需要提交的事务,建议新增,删除,修改

[3]propagation

控制事务传播行为

3.1当一个具有事务控制的方法被另一个有事务控制的方法调用后,需要如何管理事务(新建事务?在事务中执行?把事务挂起?包异常)

3.2REQUIRED(默认值):如果当前有事务就在事务中执行,如果当前没有事务,新建一个事务

3.3SUPPORTS:如果当前有事务就在事务中执行,如果当前没有事务,就在非事务状态下执行

3.4MANDATORY:必须在事务内部执行,如果当前有事务,就在事务中执行,如果没有事务,报错

3.5REQUIRES_NEW:必须在事务中执行,如果当前没有事务,新建事务,如果当前有事务,把当前事务挂起

3.6NOT_SUPPORTED:必须在事务下执行,如果当前没有事务,正常执行,如果当前有事务,把当前事务挂起

3.7NEVER:必须在非事务状态下执行,如果当前没有事务,正常执行,如果当前有事务,报错

3.8NESTED:必须在事务状态下执行,如果没有事务,新建事务,如果当前有事务,创建一个嵌套事务

[4]isolation

事务隔离级别

4.1在多线程或并发访问下如何保证访问到的数据具有完整性的

4.2脏读:

4.3不可重复读

4.4幻读

注意:不可重复读和幻读的区别是,前者是指读到了已经提交的事务的更改数据(修改或删除),后者是指读到了其他已经提交事务的新增数据

对于这两种问题解决采用不同的办法,防止读到更改数据,只需对操作的数据添加行级锁,防止操作中的数据发生变化;而防止读到新增数据,往往需要添加表级锁,将整张表锁定,防止新增数据(oracle采用多版本数据的方式实现)

4.5DEFAULT:默认值,由底层数据库自动判断应该使用什么隔离级别

4.6READ_UNCOMMITTED:可以读取未提交数据,可能出现脏读,不重复读,幻读.

    4.6.1效率最高

4.7READ_COMMITTED:只能读取其他事物已提交数据,可以防止脏读,可能出现不可重复读和幻读

4.8REPEATABLE_READ:读取的数据被添加锁,防止其他事物修改此数据,可以防止不可重复读,脏读,可能出现幻读

4.9SERIALIZABLE:排队操作,对整个表添加锁,一个事务在操作数据时,另一个事务等待事务操作完成后才能操作这个表

    4.9.1最安全

    4.9.2效率最低的

[5]rollback-for="异常类型全限定路径"

5.1当出现什么异常时需要进行回滚

5.2建议:给定该属性值

    5.2.1手动抛出异常一定要给该属性值

[6]no-rollback-for=""

6.1当出现什么异常时不回滚事务

五.Spring的properties属性配置文件

问题:

    在学习了Spring的知识后,需要被Spring管理的资源都是通过配置的文件的形式来告诉Spring容器对象管理谁以及如何管理.但是随着使用次数的增多,我们发现配置文件中配置的标签越来越多,每次我们创建一个新的项目时,将配置好的配置文件在该项目中只需要修改一下数据库连接参数即可正常使用,但是因为配置文件的内容越来越多,造成配置文件的阅读星越来越差,数据库连接参数的修改不太好找到,怎么办?

解决:

    将数据库相关参数提取到一个新的文件中专门配置,然后在applicationcontext.xml配置文件中获取数据库连接参数,配置文件中的配置信息,说白了就是将数据库连接参数和Spring的配置文件之间解耦

    实现:

        Spring的属性配置文件配置数据库;连接参数

    使用:

        (1)在src下创建db.properties文件,声明数据库连接参数

            注意:配置的为键值对数据

        (2)在applicationcontext.xml中配置属性文件的扫描

        (3)在数据源bean中使用${键名}的方式获取属性文件中的数据库连接参数

注意:    

    将factory的bean和mapper扫描的bean之间的依赖注入变为普通的属性注入,因为依赖注入>属性文件扫描>属性注入.如果不将factory和mapper扫描之间的依赖注入变为属性注入,会造成数据库参数还没有从配置文件中读取到容器中,就去进行mapper扫描了,会包数据库参数异常的错误

六.Spring的常用注解

[1]@Component

使用在普通java类上

    作用:声明一个类的对象为bean对象,相当于配置了bean标签

    注意:相当于使用的是无参数构造器来创建对象

[2]@Service

    作用:使用在业务层类上SpringMVC

    声明一个类的对象为bean对象,相当于配置了bean标签

    使用:在业务层上使用

[3]@Controller

作用:使用在控制器类上SpringMVC

声明一个类的对象为bean对象,相当于配置了bean标签

使用:在SpringMVC的控制器类上使用

[4]@Repository

作用:声明一个类的对象为bean对象,相当于配置了bean标签

使用:在数据库功能类上使用.比如Dao层对象

[5]@Resource

作用:替换在配置文件的依赖注入的

使用:在由依赖关系的属性上使用,比如A中有B属性,则在B属性上声明,告诉Spring容器对象将B的bean对象注入到A的bean对象中

注意:此注解是jqk官方的注解,不是Spring的注解,会先按照byName的方式注入,如果没有则按照byType的方式继续注入,如果都没有则不注入.并且不需要提供get/set方法

[6]@Autowired

作用:和@Resource相同,都是替换依赖注入的配置的

使用:在需要依赖注入的属性上声明

注意:该注解是Spring官方提供的,默认使用byType

    并且不需要提供get/set方法

[7]@Value

    作用:用来替换配置文件中的属性注入的.

    使用:在属性上声明,值为${"键名"}

    示例:@Value(${"name"})

    注意:使用此注解的注入,无需提供get/set方法

示例:

[8]@pointcut

    作用:声明切点

    使用:在切点方法上使用

    示例:

[9]@Aspect

作用:声明该类为通知类

使用:结合@Component在通知类上使用

示例:

[10]@Before

    作用:声明方法为前置通知方法

    使用:在前置通知方法上声明

    注意:需要在其他声明对应的切点的全限定路径

[11]@After

    作用:声明方法为后置通知方法

    使用:在后置通知方法上声明

    注意:需要在其中声明对应的切点的全限定路径

[12]@Around

    作用:声明方法为环绕通知的方法

    使用:在环绕通知方法上声明

    注意:需要在其中声明对应的切点的全限定路径

[13]@AfterThrowing

    作用:声明方法为异常通知方法

    使用:在异常通知方法上声明

    注意:需要在其中声明对应的切点的全限定路径

注意:

    需要在Spring的配置文件中声明AOP注解生效

注意:

    需要在Spring的配置文件中声明AOP注解生效

[14]@Transactional

   作用:替代了声明式事务配置

    使用:声明在需要增加事务的业务层方法上

    注意:需要进行扫描配置

七.银行转账案例

[1]案例需求

用户访问的呢轮毂页面,在页面中输入用户名和密码点击登录,登录成功后进入到主页中.如果登录失败,则在登录页面中提示用户用户名或密码错误.在主页面中,用户在填写银行转账信息,包括转账账户,转账账户密码,转账金额,收款账号,收款人姓名.点击开始转账,完成转账.但是有如下特殊需求:

(1)需要用户的登录日志

(2)当转账账户的密码失去焦点时,检验转账账户信息是否存在

(3)在转账金额失去焦点时,检验收款人信息是否正确

(4)收款人姓名失去焦点时,校验收款人信息是否正确

(5)当所有的信息验证无误后,才能转账

[2]案例页面效果图

(1)登录页面效果图

(2)转账主页面效果图

[3]功能分析

(1)创建登录页面

(2)用户登录以及登录是啊比提示语

(3)登录日志

(4)创建银行转账页面

(5)转账账户信息校验

(6)金额校验

(7)入账账户信息校验

(8)转账功能

[4]数据库设计

(1)用户信息表:t_user

(2)银行账户信息表:t_account

[5]功能实现

1.完成数据库的变现

--Table structure for t_account

DROP TABLE IF EXISTS t_account;

CREATE TABLE t_account(

    aid int(10) NOT NULL AUTO_INCREMENT,

    apwd varchar(100) NOT NULL,

    money double DEFAULT NULL,

    uid int(10) NOT NULL,

    PRIMARY KEY (aid)

)ENDINE=InnoDB auto_increment=3 default charset=UTF-8;

--Records of t_account

INSERT INTO t_account VALUES("1","123","10000","1");

INSERT INTO t_account VALUES("2","456","10000","2");

--Table structure for t_user

DROP TABLE IF EXISTS t_user;

CREATE TABLE t_user(

    uid int(10) NOT NULL AUTO_INCREMENT,

    uname varchar(100) NOT NULL,

    pwd varchar(100) NOT NULL,

    PRIMARY KEY(uid)

)ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf-8;

--Records of t_user

INSERT INTO t_user VALUES("1","张三","123");

INSERT INTO t_user VALUES("2","李四",456"");

2.搭建Spring+Mybatis项目开发的环境

(1)创建web项目

(2)在web-inf下创建lib文件夹,并导入整合的jar包

(3)在src创建MVC的包结构

    注意:将表的实体类文件创建

(4)在src下创建sprign的配置文件

(5)在web.xml文件中配置Spring文件路径和监听器

3.创建登录页面

效果图

代码示例:

<%

    String path = request.getContextPath();

    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

%>

<%@ page contentType="text/html;charset=UTF-8" language="java"%>

<html>

<head>

    <base href="<%=basePath%>"/>

    <title>Title</title>

</head>

<body>

    <h3 align="center">欢迎登录s106班级银行转账系统</h3>

    <hr>

    <div style="width:400px;margin:auto">

        <form action="userLogin" method="post">

            <table style="margin:auto;margin-top:30px;cellpadding="10px">

                <tr>

                    <td>用户名:</td>

                    <td>

                        <input type="text" name="uname" value="">

                    </td>

                </tr>

                <tr>

                    <td>密码:</td>

                    <td>

                        <input type="password" name="pwd" value="">

                    </td>

                </tr>

                <tr>

                    <td colspan="2">

                        <input type="submit" value="点击登录">

                    </td>

                </tr>

            </table>

        </form>

    </div>

</body>

</html>

4.完成登录功能

(1)创建UserServlet,处理登录请求

@WebServlet(value="/userLogin",loadOnStartup=1)

public class UserServlet extends HttpServlet{

    //声明init方法,完成Spring资源的初始化加载

    private UserService us;

    @Override

    public void init() throws ServletException{

        //获取Spring容器对象

        ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());

        //获取业务层对象

        us=(UserService)ac.getBean("us");

    }

    //声明service方法,完成请求的处理

    @Override

    protected void service(HttpServletRequest req,HttpServletResponse resp)throws ServletException,IOException{

        //设置请求编码格式

        req.setCharacterEncoding("utf-8");

        //设置响应编码格式

        resp.setContentType("text/html;charset=utf-8");

        resp.setCharacterEncoding("utf-8");

        //获取请求信息

        String uname = req.getParameter("uname");

        String pwd = req.getParameter("pwd");

        //处理请求

            //调用业务层方法根据用户名和密码获取用户信息

            User user = us.userLoginService(uname,pwd);

        //响应处理结果

            //获取Session对象

            HttpSession session = req.getSession();

            //响应

            if(user!=null){

                //将用户信息存储到session中

                session.setAttribute("user",user);

                //重定向到主页面

                resp.sendRedirect(req.getContextPath()+"/main.jsp");

            }else{

                //增加失败标记

                session.setAttribute("flag","userFail");

                //重定向到登录页面

                resp.sendRedirect(req.getContextPath()+"/login.jsp");

            }

    }

}

(2)创建UserService处理登录请求

public class UserServiceImpl implements UserService{

    //声明mapper层属性

    private UserMapper userMapper;

    public UserMapper getUserMapper(){

        return userMapper;

    }

    public void setUserMapper(UserMapper userMapper){

        this.userMapper = userMapper;

    }

    //用户登录

    @Override

    public User userLoginService(String uname,String pwd){

        return userMapper.userLoginMapper(uname,pwd);

    }

}

(3)创建UserMapper,根据用户名和密码获取用户信息

public interface UserMapper{

    //根据用户名和密码获取用户信息

    @Select("select * from t_user where uname=#{uname} and pwd="{pwd}")

    User userLoginMapper(@Param("uname")String uname,@Param("pwd")String pwd);

}

(4)在applicationcontext.xml文件中配置业务层bean

<!--配置业务层bean-->

<bean id="us" class="com.bjsxt.service.impl.UserServiceImpl">

    <property name="userMapper" ref="userMapper"></property>

</bean>

5.创建main.jsp主页面

(1)页面示例图

(2)代码示例:

<%

String path=request.getContextPath();

String basePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

%>

<%@pagr cpntentType="text/html;charset=UTF-8" language="java"%>

<html>

<head>

    <base href="<%=basePath%>"/>

    <title>Ttile</title>

    <%--引入jquery文件--%>

    <script type="text/javascript" src="js/j.js"></script>

    <%--声明js代码域--%>

    <script type="text/javascript">

        //声明页面加载事件

        $(function(){

            //创建颜色数组

            var colors=["red","yellow","black","green","gray","blue","brown","darhorchid"];

            //使用间隔执行

            window.setInterval(function(){

                //获取0-8的碎甲整数,含0不含8

                var index = Math.floor(Math.random()*colors.length);

                //设置标题颜色

                $("#title").css("color",colors[index]);

            },100)

        })

    </script>

</head>

<body>

    <%--网页的主题--%>

    <h3 align="center">

        <%--跑马灯效果--%>

        <marquee with=400 behavior=alternate direction=left align=middle>

            <font color="r" id="title">欢迎${sessionScope.user.uname}登录s106班级银行转账系统</font>

        </marquee>

    </h3>

    <%--水平线--%>

    <hr>

    <%--银行转账表单--%>

    <div style="width:400px;margin:auto;">

        <form action="">

            <table style="margin:auto;margin-top:30px;" cellpadding="10px">

                <tr>

                    <td>转账系统:</td>

                    <td>

                        <input type="text" name="outId" value="">

                    </td>

                </tr>

                <tr>

                    <td>转账账户密码:</td>

                    <td>

                        <input type="password" name="outPwd" value="">

                    </td>

                </tr>

                <tr>

                    <td>全额:</td>

                    <td>

                        <input type="text" name="money" vlaue="">

                    </td>

                </tr>

                <tr>

                    <td>收款账号:</td>

                    <td>

                        <input type="text" name="inId" value="">

                    </td>

                </tr>

                <tr>

                    <td>收款人姓名:</td>

                    <td>

                        <input type="text" name="inName" vaue="">

                    </td>

                </tr>

                <tr>

                    <td colspan="2">

                        <input type="submit" value="开始转账">

                    </td>

                </tr>

            </table>

        </form>

    </div>

</body>

</html>

6.完成转账账户信息的校验

(1)功能点需求:

用户在输入账户以及密码后,在密码失去焦点后,触发校验.如果正确则在密码框后显示√,错误显示×

(2)功能点分析:

通过需求我们发现,检验的结果是在当前页面中继续显示的.相当于我们在当前页面中显示新的响应结果,确定该功能使用ajax技术来实现

(3)前台分析:

1)ajax请求的触发时机:在密码框失去焦点时触发

2)ajax请求的请求地址:Servlet的别名,checkAccount

3)ajax请求的请求数据:账户和密码

4)ajax请求的响应数据:true或者false的字符串

(4)前台代码实现:

//给密码框添加焦点事件,完成校验

$(function(){

    $("#outdPwd").blur(function(){

        //发起ajax请求

        $.post("checkAccount",{outIct:$("#outId").val(),outPwdt:$("#outdPwd").val(),methodName="checkOutInfo"},function(data){

            if(eval(data)){

                $("#outSpan").html("√").css("color","green");

            }else{

                $("#outSpan").html("X").css("color","red");

            }

        })

    })

})

(5)后台分析:

1)创建Servlet,处理转账账户信息校验.checkAccount

    注意:有,响应"true",没有,响应"false"

2)创建Service,处理账户信息校验

3)创建mapper,根据账户ID和密码获取账户信息

(6)后台代码实现

参照源码即可

7.Servlet的优化

(1)问题:

    目前我们每实现一个功能点,就需要在后台声明一个对应的Servlet进行请求的处理.这样造成Servlet声明过多,代码繁琐

(2)解决:

    Servlet只声明一个,让所有的相关请求,都请求该Servlet.在该Servelt中的service方法中,不做具体的请求处理.在Service中,根据请求,调用对应的逻辑代码来处理请求即可

类似:main方法的机制

(3)实现:

在Servlet中将不同请求的处理逻辑代码封装成对应的逻辑功能方法然后在service方法中,根据请求调用对应的逻辑方法处理请求.每次请求都需要在请求数据中携带要请求的方法的方法名.后台service中根据请求数据中的方法名调用对应的逻辑方法即可

@WebServlet(value="/checkAccount",loadOnStartup=2)

public class CheckAccountServlet extends HttpServlet{

    //声明业务层属性

    private CheckAccountService checkAccountService;

    //重写init方法

    @Override

    public void init() throws ServletException{

        //获取Spring容器对象

        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationcontext.xml");

        //获取业务层对象

        checkAccountService = (CheckAccountService)ac.getBean("checkAccountService");

    }

    //重写service方法

    @Override

    protected void service(HttpServletRequest req,HttpServletResponse resp)throws ServletException,IOException{

        //设置请求编码格式

        req.setCharacterEncoding("utf-8");

        //设置响应编码格式

        resp.setCharacterEncoding("utf-8");

        resp.setContentType("text/html;charset=utf-8");

        //获取请求数据中的方法名

        String methodName = req.getParameter("methodName");

        //根据请求调用对应的逻辑代码

        if("checkOutInfo".equals(methodName)){

            checkOutInfo(req,resp);

        }else if("checkMoneyInfo".equals(methodName)){

            checkMoneyInfo(req,resp);

        }else if("checkInfo".equals(methodName)){

            checkInInfo(req,resp);

        }else if("transferInfo".equals(methodName)){

            transferInfo(req,resp);

        }else{

            System.out.println("没有对应的逻辑方法:"+methodName);

        }

    }

    //转账

    private void transferInfo(HttpServletRequest req,HttpServletResponse resp){

    }

    //校验收款人信息

    private void checkInInfo(HttpServletRequest req,HttpServletResponse resp){

    }

    //检验金额

    private void checkMoneyInfo(HttpServletRequest req,HttpServletResponse resp){

    }

    //声明方法:校验转账账户信息

    private void checkOutInfo(HttpServletRequest req,HttpServletResponse)throws IOException{

        //获取请求信息

        String outId = req.getParameter("outId");

        String outPwd = req.getParameter("outPwd");

        //处理请求

        //调用业务层方法

        Account accoount = checkAccountService.checkOutAccountService(outId,outPwd);

        //响应结果

        resp.getWrite().write(account!=null?"true":"false");

    }

}

8.校验金额

(1)功能点需求:

用户在金额框中输入要转账的金额信息后,失去焦点时,完成金额信息的校验

余额足够则在金额框后显示√,否则显示×

(2)功能分析:

使用ajax技术

1)前台分析

    a.给金额框增加焦点事件

    b.发起ajax请求

    c.请求数据为金额,转账账户Id,后台逻辑方法名

    d.响应数据为true或者false的字符串

实例代码:

--转账金额校验

$(function(){

    $("#money").blur(function(){

        //发起ajax请求

        $.post("checkAccount",{outId:$("#outId").val(),money:$("#money").val(),methodName:"checkMoneyInfo"},function(data){

            if(eval(data)){

                $(#moneySpan").html("√").css("color","green");

            }else{

                $("#moneySpan").html("X").css("color","red");

            }

        })

    })

})

(2)

后台分析:功能参照源码

    1).在CheckAccountServlet中声明金额校验逻辑方法,并在service方法完成调用

    2)在CheckAccountService中新增金额校验的业务方法

    3)在CheckAccountMapper中新增金额校验的数据库操作

9.收款人信息校验

(1)功能点需求:

    用户在收款人姓名失去焦点时,校验收款人信息.存在,则在收款人姓名框后显示√,不存在显示×

(2)功能分析

    1)前台分析

        a.给收款人姓名框增加焦点事件

        b.发起ajax请求完成校验

        c请求数据为收款人账户ID,收款人姓名,后台逻辑方法名

        d.响应数据true或者false的字符串

代码示例:

--收款人信息校验

$(function(){

    $("#inName").blur(function(){

        //发起ajax请求

        $.post("checkAccount",{inId:$("#inId").val(),inName:$("#inName").val(),methodName:"checkInfo"},function(data){

            if(eval(data)){

                $("#inNameSpan").html("√").css("color","green");

            }else{

                $("#inNameSpan").html("X").css("color","red");

            }

        });

    })

})

2.后台分析

    1)在CheckAccoundServlet中声明对应的逻辑方法完成校验

    2)在CheckAccoundService中声明业务方法

    3)在CheckAccoundMapper中声明数据库操作

10.开始转账

(1)功能点需求:

点击开始转账时,保证所有的转账信息是正确的,如果有错误的转账信息提示用户,请填写正确的信息.如果全部都是正确的,则直接发起转账请求,完成转账

(2)功能分析:

1)前台分析

    a.给转账按钮事件增加单击事件

    b.校验转账信息是否全部正确

    c.提交转账请求

代码示例:

--转账账户信息校验

//给密码框天啊及焦点事件,完成校验

$(function(){

    $("#outdPwd").blur(function(){

        //发起ajax请求

        $.post("checkAccount",{outId:${"#outId"}.val(),outPwd:$("#outdPwd").val(),methodName:"checkOutInfo"},function(data){

            if(eval(data)){

                $("#outSpan").html("√").css("color","green").addClass("success").removeClass("error");

            }else{

                $("#outSpan").html("X").css("color","red").addClass("error").removeClass("success");

            }

        })

    })

})

--转账金额校验

$(function(){

    $("#money").blur(function(){

        //发起ajax请求

        $.post("checkAccount",{outId:("#outId").val(),money:$("#money").val(),methodName:"checkMoneyInfo"},function(data){

            if(eval(data)){

                $("#moneySpan").html("√").css("color","green").addClass("success").removeClass("error");

            }else{

                $("#moneySpan").html("X").css("color","red").addClass("error").removeClass("success");

            }

        })

    })

})

--收款人信息校验

$(function(){

    $("#inName").blur(function(){

        //发起ajax请求

           $.post("checkAccount",{inId:$("#inId").val(),inName("#inName").val(),methodName:"checkInfo"},function(data){

                if(evla(data)){

$("#inNameSpan").html("√").css("color","green").addClass("success").removeClass("error");

                }else{

$("#inNameSpan").html("X").css("color","red").addClass("error").removeClass("success");

                }

            })

        })

})

--转账功能

$(function(){

    $("#btn").click(function(){

        //检验转账信息是否正确

        if($(".success").length==3){

            //提及表单

            $("#fm").submit();

        }else{

            alert("请填写正确的账户信息");

        }

    })

})

2)后台分析

    a.在CheckAccountServlet中声明转账的逻辑方法

    b.在CheckAccountService中声明转账的业务方法

    c.在CheckAccountMapper中完成转账的数据库操作

11.登录日志

(1)功能点需求:

我们的银行转账功能,在刚开始运行营的时候,并没有用户登录的日志信息的记录.后来,某天某个客户他的账号被登录了,但是给该客户又不知道是什么时间进行的登录,造成调查有困扰,怎么办?在当前登录功能的基础上,增加登录日志,来记录用户的登录信息.便于我们后期的排查

(2)功能分析:

在保留当前登录功能的基础上,完成对登录功能的扩展.但是又不希望改变原有的功能代码逻辑.开率使用SpringAOP

    前置通知:在日志文件中输出xxx在xxx时间发起了登录请求

    切点:登录的业务方法

    后置通知:在日志文件中输入xxx在xxx时间登录成功

建议使用SchemaBased方式实现

(3)功能实现:

    a.在lib下导入AOP的jar包

    b.在src下创建com.bjsxt.advice的包

    c.在advice包中创建前置通知和后置通知

    d.在src下声明log4j.properties配置文件

    e.在applicationcontext.xml文件中配置通知bean以及组装规则

八.Spring重点知识梳理

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345