Spring实现银行业务介绍(loc控制反转、AOP编程、事务、标签)

2022-07-31,,,

Spring总结

Spring

Spring是什么?经过验证,具有一定功能的半成品框架
学习高级编程思想,学习技术 ,学习怎么使用(配置文件,注解 ,API)
Spring框架不属于任何一层,但存在于每一层
实现高内聚低耦合
两大核心
LoC :Inverse of Control 控制反转
AOP:面向切面编程

核心:解耦

Loc 控制反转

控制的是Bean对象
反转的是Bean对象的获取方式以及对象之间的依赖关系
原来是new对象,现在要对象从Spring容器中要,创建过程交给Spring,把创建对象的权力做了个反转
同时Bean对象的依赖关系也做了反转(解耦)

AOP 面向切面编程

AOP是一种编程规范,弥补OOP(面向对象)的不足,基于OOP基础之上进行横向开发
提高代码复用性,业务代码更简洁,维护更搞笑,扩展更便捷

目标(target):被增强的类
代理(proxy):通过动态代理技术生成的代理对象

连接点(joinpoint):目标类中的所有方法
切入点(pointcut):目标类中真正被增强的方法
通知/增强(advice):增强类
切面(aspect):切入点+通知
织入(weaving):把通知类动态的加入到切入点位置的过程

目标和增强类需要自己写
配置AOP切面时

  1. 需要告诉Spring目标类是谁
  2. 增强类是谁
  3. 要增强目标类中的哪个方法(切入点)

事务

事务是数据库中多个操作合并在一起形成的操作序列
声明式事务管理的实现过程其实就是AOP的应用

作用
1.当数据库操作序列中个别操作失败时,提供一种方式使数据库状态恢复到正常状态(A),保障数据库即使在异常状态下仍能保持数据一致性(C)(要么操作前状态,要么操作后状态)。
2.当出现并发访问数据库时,在多个访问间进行相互隔离,防止并发访问操作结果互相干扰(I)。

传播行为

这个传播行为简单理解为两个方法间相互调用
A调用B,B的管理事务行为
记住两个
Required A中有事务,B加入,A中没有事务,B自己生成一个(管好自己)
Supports A中有事务,B加入,A中没有事务,B也没有(不管)

标签总结

依赖

 <dependencies> <!--无mybatis配置坐标--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> <scope>compile</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.21</version> <scope>compile</scope> </dependency> </dependencies> 

读取XML

 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //3.获取资源 UserService userService = (UserService) ctx.getBean("userService"); userService.save(); 

读取注解

AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(SpringConfig.class); AccountService bean = annotationConfigApplicationContext.getBean(AccountService.class); bean.findById("1"); 

把对象导入容器

<bean id="" class="com.ybb.Serivce.ServiceImpl"> id唯一标识   class要管理的对象的全限定类名

@compont
@Controller
@Service
@Repository 

引入配置文件

 <context:property-placeholder location="classpath:*.properties"/> @PropertySource("classpath:jdbc.properties") 

设置属性

基本类型设置属性 <property name="propertyName" value="propertyValue" ref="beanId"/> <property name="propertyName" value="${propertiesName}"/> ref是引用

@Value
一般配合引入配置文件使用
@Value("${jdbc.username}") private String username; 引用类型设置属性
@Autowired、@Qualifier
@Autowired默认按类型装配,指定@Qualifier后可以指定自动装配的bean的id 

引入

<beans> <import /> </beans> @Import 

@Bean 把返回值导入容器,多用于载入第三方,xml更方便些

@Component
@PropertySource("classpath:jdbc.properties") public class DBConfig { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean
    public DruidDataSource getdruidDataSource(){ DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setDriverClassName(driver); druidDataSource.setUrl(url); druidDataSource.setUsername(username); druidDataSource.setPassword(password); return druidDataSource; } @Bean
    public PlatformTransactionManager getTx(DataSource dataSource){ return new DataSourceTransactionManager(dataSource); } 

包扫描

ComponentScan("com.ybb") @Configuration  //指定是核心配置文件
@ComponentScan(“包名”)  //扫描 

映射配置

 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="dao"/> </bean> @Bean
    public MapperScannerConfigurer getMapperScannerConfigurer(){ MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); mapperScannerConfigurer.setBasePackage("com.ybb.Dao"); return mapperScannerConfigurer; } 

开始注解驱动

<context:annotation-config> @EnableAspectJAutoProxy 

开启代理

<aop:aspectj-autoproxy/> <aop:config> <!--配置公共切入点--> <aop:pointcut id="pt1" expression="execution(* *(..))"/> <aop:aspect ref="myAdvice"> <!--配置局部切入点--> <aop:pointcut id="pt2" expression="execution(* *(..))"/> <!--引用公共切入点--> <aop:before method="logAdvice" pointcut-ref="pt1"/> <!--引用局部切入点--> <aop:before method="logAdvice" pointcut-ref="pt2"/> <!--直接配置切入点--> <aop:before method="logAdvice" pointcut="execution(* *(..))"/> </aop:aspect> </aop:config> 记得在需要代理的地方配置
@EnableTransactionManagement
@Transactional( readOnly = false, timeout = -1,
    isolation = Isolation.DEFAULT,
    rollbackFor = {ArithmeticException.class, IOException.class},
    noRollbackFor = {},
    propagation = Propagation.REQUIRES_NEW ) 不写使用默认 

事务

@Aspect //事务类
@Component  //加容器
public class LogTrade { @Autowired
    private TradeService tradeService; @Pointcut("execution(* com.ybb.Service.ServiceImpl.AccountServiceImpl.*(..))") public void pt(){} @Around("pt()") //环绕增强要增强的方法
    public void xxx(){} 

Junit测试

@RunWith(SpringJUnit4ClassRunner.class) //spring接管junit
@ContextConfiguration(classes = SpringConfig.class) //加载容器
public class App { @Autowired
    private StudentService studentService; @Test
    public void xxx() { System.out.println(studentService.findAll()); } } 

银行业务 简单实现

存款余额查询(账户查询)(7分)
功能简介
查询账户的存款余额信息。

点击菜单栏的“交易记录查询”,输入起始日期,终止日期,点击“确定”按钮即可显示您的网上银行交易日志明细。
注意事项

  1. 本交易只可查询您的网银交易。(5分)
  2. 处理用户选择日期超出的错误。(5分)
  3. 只能查询一个月内的网银交易。(5分)
    (四)本行单笔转账(转账业务处理)(7分)
    功能描述
    登录网银系统后,选择“行内单笔转账”功能,按页面要求填写转账信息,完成您的单笔转账业务。
    当您的单笔转账金额大于当前账户可用余额时,系统自动跳出“账号余额不足” 页面,点击“关闭”按钮返回转账页面,调低转账金额后完成本次转账。
    当转入的账号错误时给出相应的提示信息“转入账号错误!”。点击“关闭”按钮返回转账页面,修改转入账号后完成本次转账。
    操作说明
    点击菜单栏“行内单笔转账”,输入或选择转入账号,输入转账金额、转出账户密码、摘要,点击“确定”按钮,完成交易。
    注意事项
    1.单笔转账金额必顺小于当前账户可用余额。(5分)
    2.处理转入账号不存在错误的情况。(5分)
    3.本行转账手续费标准:按照每笔转账金额的0.5%收取,最低人民币2元,
    最高人民币20元,即要求在帐户的余额中扣除手续费。(5分)
  4. 记录“转出”交易日志,交易类型为“转出”,交易摘要为“接收账号:xxxxxxxx”。(5分)
    帐户表Account

字段名称 字段说明 类型 属性
AccountID 帐号 varchar(50) 主键
Password 密码 Varchar(6)
Remaining 余额 Decimal(7,2)

交易表 Trade
字段名称 字段说明 类型 属性
ID 流水号 Integer 主键,自动增长
AccountID 帐号 varchar(50) 外键,关联到帐户表Account主键AccountID
TradeType 交易类型 Varchar(10) 交易类型有3种,分别为:存款、取款和转出
TradeMoney 交易金额 Decimal(7,2)
TradeTime 交易时间 Date
TradeDigest 交易摘要 varchar(1024)

Aop

package com.ybb.Aop; import com.ybb.Service.TradeService; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Date; /**
 * Created by Administrator
 * <p> * Date :2020/8/8
 * <p> * Description : * <p> * Version :1.0
 */
@Aspect
@Component
public class LogTrade { @Autowired
    private TradeService tradeService; @Pointcut("execution(* com.ybb.Service.ServiceImpl.AccountServiceImpl.*(..))") public void pt(){} @Around("pt()") public Object around(ProceedingJoinPoint pjp) throws Throwable { Signature signature = pjp.getSignature(); String methodName = signature.getName(); Object[] args = pjp.getArgs(); if ("transfer".equals(methodName)){ //根据方法名去判断传入的参数值
            tradeService.LogTrade(null,(String) args[0],signature.getName(),(Double) args[2],new Date(),signature.toString()); } else if ("saveMoney".equals(methodName)||"outMoney".equals(methodName)) { tradeService.LogTrade(null,(String) args[0],signature.getName(),(Double) args[1],new Date(),signature.toString()); }else { tradeService.LogTrade(null,(String) args[0],signature.getName(),0d,new Date(),signature.toString()); } Object proceed = pjp.proceed(); return proceed; } } 

Config
Db

package com.ybb.Config; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.PropertySource; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.stereotype.Component; import org.springframework.transaction.PlatformTransactionManager; import javax.sql.DataSource; /**
 * Created by Administrator
 * <p> * Date :2020/8/7
 * <p> * Description : * <p> * Version :1.0
 */
@Component
@PropertySource("classpath:jdbc.properties") public class DBConfig { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean
    public DruidDataSource getdruidDataSource(){ DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setDriverClassName(driver); druidDataSource.setUrl(url); druidDataSource.setUsername(username); druidDataSource.setPassword(password); return druidDataSource; } @Bean
    public PlatformTransactionManager getTx(DataSource dataSource){ return new DataSourceTransactionManager(dataSource); } } 

Mybatis

package com.ybb.Config; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.mapper.MapperScannerConfigurer; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import javax.sql.DataSource; /**
 * Created by Administrator
 * <p> * Date :2020/8/7
 * <p> * Description : * <p> * Version :1.0
 */
@Component
public class MybatisConfig { @Bean
    public SqlSessionFactoryBean getSqlSessionFactoryBean(DataSource dataSource){ SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setTypeAliasesPackage("com.ybb.domain"); sqlSessionFactoryBean.setDataSource(dataSource); return sqlSessionFactoryBean; } @Bean
    public MapperScannerConfigurer getMapperScannerConfigurer(){ MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); mapperScannerConfigurer.setBasePackage("com.ybb.Dao"); return mapperScannerConfigurer; } } 

Spring

package com.ybb.Config; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.mapper.MapperScannerConfigurer; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import javax.sql.DataSource; /**
 * Created by Administrator
 * <p> * Date :2020/8/7
 * <p> * Description : * <p> * Version :1.0
 */
@Component
public class MybatisConfig { @Bean
    public SqlSessionFactoryBean getSqlSessionFactoryBean(DataSource dataSource){ SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setTypeAliasesPackage("com.ybb.domain"); sqlSessionFactoryBean.setDataSource(dataSource); return sqlSessionFactoryBean; } @Bean
    public MapperScannerConfigurer getMapperScannerConfigurer(){ MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); mapperScannerConfigurer.setBasePackage("com.ybb.Dao"); return mapperScannerConfigurer; } } 

DAO
AccountDao

package com.ybb.Dao; import com.ybb.domain.Account; import com.ybb.domain.Trade; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import java.util.List; /**
 * Created by Administrator
 * <p> * Date :2020/8/7
 * <p> * Description : * <p> * Version :1.0
 */
public interface AccountDao { @Select("select * from Account where AccountID=#{AccountID}") Account findAccount(String AccountID); @Select("select Remaining from Account where AccountID=#{AccountID}") Double findRemaining(String AccountID); @Select("select * from Trade where AccountID=#{AccountID} and TradeTime BETWEEN #{StartTime} and #{EndTime};") List<Trade>findByBirthday(@Param("AccountID") String AccountID, @Param("StartTime") String StartTime, @Param("EndTime") String EndTime); @Update("update Account set Remaining = Remaining + #{Remaining} where AccountID = #{AccountID} ") void inMoney(@Param("AccountID") String AccountID, @Param("Remaining") Double Remaining); @Update("update Account set Remaining = Remaining - #{Remaining} where AccountID = #{AccountID} ") void outMoney(@Param("AccountID") String AccountID, @Param("Remaining") Double Remaining); } 

TradeDao

package com.ybb.Dao; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Param; import java.util.Date; /**
 * Created by Administrator
 * <p> * Date :2020/8/7
 * <p> * Description : * <p> * Version :1.0
 */
public interface TradeDao { @Insert("INSERT INTO Trade VALUES (ID,AccountID,TradeType,TradeMoney,TradeTime,TradeDigest)") void LogTrade(@Param("ID") Integer ID, @Param("AccountID")String AccountID, @Param("TradeType")String TradeType, @Param("TradeMoney")Double TradeMoney, @Param("TradeTime")Date TradeTime,@Param("TradeDigest")String TradeDigest); } 

domain

package com.ybb.domain; /**
 * Created by Administrator
 * <p>
 * Date :2020/8/7
 * <p>
 * Description :
 * <p>
 * Version :1.0
 */ public class Account { private String AccountID;//账号 private Double Remaining;//余额 public String getAccountID() { return AccountID; } public void setAccountID(String accountID) { AccountID = accountID; } public Double getRemaining() { return Remaining; } public void setRemaining(Double remaining) { Remaining = remaining; } public Account() { } @Override public String toString() { return "Account{" + "AccountID='" + AccountID + '\'' + ", Remaining='" + Remaining + '\'' + '}'; } } 
package com.ybb.domain; import java.util.Date; /**
 * Created by Administrator
 * <p>
 * Date :2020/8/7
 * <p>
 * Description :
 * <p>
 * Version :1.0
 */ public class Trade { private Integer ID;//流水号 private String AccountID;//账号 private String TradeType;//交易类型 private Double TradeMoney;//交易金额 private Date TradeTime;//交易时间 private String TradeDigest;//交易摘要 public Integer getID() { return ID; } public void setID(Integer ID) { this.ID = ID; } public String getAccountID() { return AccountID; } public void setAccountID(String accountID) { AccountID = accountID; } public String getTradeType() { return TradeType; } public void setTradeType(String tradeType) { TradeType = tradeType; } public Double getTradeMoney() { return TradeMoney; } public void setTradeMoney(Double tradeMoney) { TradeMoney = tradeMoney; } public Date getTradeTime() { return TradeTime; } public void setTradeTime(Date tradeTime) { TradeTime = tradeTime; } public String getTradeDigest() { return TradeDigest; } public void setTradeDigest(String tradeDigest) { TradeDigest = tradeDigest; } @Override public String toString() { return "Trade{" + "ID=" + ID + ", AccountID='" + AccountID + '\'' + ", TradeType='" + TradeType + '\'' + ", TradeMoney='" + TradeMoney + '\'' + ", TradeTime=" + TradeTime + ", TradeDigest='" + TradeDigest + '\'' + '}'; } } 

money

package com.ybb.Factory; /**
 * Created by Administrator
 * <p>
 * Date :2020/8/8
 * <p>
 * Description :
 * <p>
 * Version :1.0
 */ public class Money { public static double charge(Double Remaining){ //计算手续费 Double charge= Remaining*0.5*0.01; if (charge<2){ charge=2d; }else if (charge>20){ charge=20d; } return charge; } } 

核心业务
Service

package com.ybb.Service; import com.ybb.domain.Account; import com.ybb.domain.Trade; import java.util.Date; import java.util.List; /**
 * Created by Administrator
 * <p>
 * Date :2020/8/7
 * <p>
 * Description :
 * <p>
 * Version :1.0
 */ public interface AccountService { //查用户是否存在 Account findAccount(String AccountID); //指定用户id,查余额 Double findById(String AccountID); //指定用户id,查日期 List<Trade> findByBirthday(String AccountID, Date date); //转账了 String transfer(String outAccountID, String inAccountID, Double Remaining); //存钱咯 String saveMoney(String inAccountID, Double Remaining); //取钱 String outMoney(String outAccountID, Double Remaining); } 
package com.ybb.Service.ServiceImpl; import com.ybb.Dao.AccountDao; import com.ybb.Factory.Money; import com.ybb.Service.AccountService; import com.ybb.domain.Account; import com.ybb.domain.Trade; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.List; /**
 * Created by Administrator
 * <p>
 * Date :2020/8/7
 * <p>
 * Description :
 * <p>
 * Version :1.0
 */ @Service public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; public Account findAccount(String AccountID) { return accountDao.findAccount(AccountID); } public Double findById(String AccountID){ Double byId = accountDao.findRemaining(AccountID); return byId; } public List<Trade> findByBirthday(String AccountID, Date date) { if (accountDao.findAccount(AccountID)==null){ return null; } if (date.after(new Date())){ return null; } SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd"); String EndTime = format.format(date);//当前时间 Calendar c=Calendar.getInstance(); c.setTime(date);//当前时间 c.add(Calendar.MONTH,-1);//当前时间减一个月 String StartTime = format.format(c.getTime()); List<Trade> byBirthday = accountDao.findByBirthday(AccountID, StartTime, EndTime); return byBirthday; } @Transactional public String transfer(String outAccountID, String inAccountID, Double Remaining) { //钱不够,转不了 if (accountDao.findRemaining(outAccountID)<Remaining){ return "要转出的钱大于了余额,无法操作,请检查后再看"; }else { if (accountDao.findAccount(inAccountID)!=null) { //拿到手续费 accountDao.inMoney(inAccountID, Remaining); /* int i=1/0;*/ accountDao.outMoney(outAccountID, Remaining); //求在帐户的余额中扣除手续费 double charge = Money.charge(Remaining); accountDao.outMoney(outAccountID,charge); //感觉这有个bug,要是转出的人钱不够扣手续费。也不会出现负的情况 return "转账成功"; }else { return "要转账的用户不存在"; } } } public String saveMoney(String inAccountID, Double Remaining) { accountDao.inMoney(inAccountID,Remaining); return "存入成功,继续加油"; } public String outMoney(String outAccountID, Double Remaining) { //判断一下金额大小 if (accountDao.findRemaining(outAccountID)<Remaining){ return "要转出的钱大于了余额,无法操作,请检查后再看"; }else { accountDao.outMoney(outAccountID, Remaining); return "余额成功取出,消费要适度喔"; } } } 
package com.ybb.Service; import org.apache.ibatis.annotations.Param; import java.util.Date; /**
 * Created by Administrator
 * <p>
 * Date :2020/8/8
 * <p>
 * Description :
 * <p>
 * Version :1.0
 */ public interface TradeService { void LogTrade(@Param("ID") Integer ID, @Param("AccountID")String AccountID, @Param("TradeType")String TradeType, @Param("TradeMoney")Double TradeMoney, @Param("TradeTime") Date TradeTime, @Param("TradeDigest")String TradeDigest); } 
package com.ybb.Service.ServiceImpl; import com.ybb.Dao.TradeDao; import com.ybb.Service.TradeService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Date; /**
 * Created by Administrator
 * <p>
 * Date :2020/8/8
 * <p>
 * Description :
 * <p>
 * Version :1.0
 */ @Service public class TradeServiceImpl implements TradeService { @Autowired private TradeDao tradeDao; public void LogTrade(Integer ID, String AccountID, String TradeType, Double TradeMoney, Date TradeTime, String TradeDigest) { tradeDao.LogTrade(ID, AccountID, TradeType, TradeMoney, TradeTime, TradeDigest); } } 

本文地址:https://blog.csdn.net/m0_46690280/article/details/107883922

《Spring实现银行业务介绍(loc控制反转、AOP编程、事务、标签).doc》

下载本文的Word格式文档,以方便收藏与打印。