当前位置: 首页 > 编程日记 > 正文

Spring学习笔记:3(面向切面AOP)

AOP:Aspect Oriented Program(面向切面)

我们再回顾一下AOP的一些术语:

  • 通知(Advice)
      就是你想要的功能,也就是的安全、事物、日志等。先定义好,然后在想用的地方用一下。

  • 连接点(JoinPoint)
      就是spring允许你使用通知的地方,基本每个方法的前、后(两者都有也行),或抛出异常时都可以是连接点,spring只支持方法连接点,只要记住,和方法有关的前前后后(抛出异常),都是连接点。

  • 切入点(Pointcut)
      上面说的连接点的基础上,来定义切入点,你的一个类里,有十几个方法,那就有几十个连接点了,但是你并不想在所有方法附近都使用通知(使用叫织入),你只想让其中的几个,在调用这几个方法之前,之后或者抛出异常时干点什么,那么就用切点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法。切入点一定是连接点,连接点不一定是切入点。

  • 切面(Aspect)
      切面是通知和切入点的结合。通知说明了干什么和什么时候干(什么时候通过方法名中的before、after、around等就能知道),而切入点说明了在哪干(指定到底是哪个方法),这就是一个完整的切面定义。

  • 引入(introduction)
      允许我们向现有的类添加新方法属性。

  • 目标(target)
      引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被咱们织入切面。而自己专注于业务本身的逻辑。

  • 代理(proxy)
      怎么实现整套aop机制的,都是通过代理。

  • 织入(weaving)
      把切面应用到目标对象来创建新的代理对象的过程。

上述内容引用于:https://blog.csdn.net/qukaiwei/article/details/50367761

理解:

简单的说就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,在我们想要使用的地方上来调用它。

作用:

为了更清晰的逻辑,可以让你的业务逻辑去关注自己本身的业务,而不去想一些其他的事情,这些其他的事情包括:安全,事物,日志等。

优势:

减少重复代码、提高开发效率、维护方便

spring中基于XML的AOP配置步骤

  1. 把通知Bean也交给spring来管理
  2. 使用aop:config标签表明开始AOP的配置
  3. 使用aop:aspect标签表明配置切面
    id属性:是给切面提供一个唯一标识
    ref属性:是指定通知类bean的id
  4. 在aop:aspect标签的内部使用对应标签来配置通知的类型
    我们的示例是让printLog方法在切入点方法执行之前之前:所以是前置通知
    aop:before:表示配置前置通知
    method属性:用于指定Logger类中哪个方法是前置通知
    pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强

例:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 配置srping的Ioc,把service对象配置进来--><bean id="accountService" class="com.serrvice.impl.AccountServiceImpl"></bean><!-- 配置Logger类(日志类) --><bean id="logger" class="com.utils.Logger"></bean><!--配置AOP--><aop:config><!--配置切面 --><aop:aspect id="logAdvice" ref="logger"><!-- 配置通知的类型,并且建立通知方法和切入点方法的关联--><aop:before method="printLog" pointcut="execution(public void com.serrvice.impl.AccountServiceImpl.saveAccount())"></aop:before></aop:aspect></aop:config>
</beans>

关键字:execution(表达式)
表达式:访问修饰符 返回值 包名.包名.包名…类名.方法名(参数列表)
切入表达式可以有各种花里胡哨的写法,如下:

  • 标准的表达式写法:
public void com.service.impl.AccountServiceImpl.saveAccount()
  • 访问修饰符可以省略
void com.service.impl.AccountServiceImpl.saveAccount()
  • 返回值可以使用通配符,表示任意返回值
* com.service.impl.AccountServiceImpl.saveAccount()
  • 包名可以使用通配符,表示任意包。但是有几级包,就需要写几个*.
* *.*.*.*.AccountServiceImpl.saveAccount())
  • 包名可以使用…表示当前包及其子包
* *..AccountServiceImpl.saveAccount()
  • 类名和方法名都可以使用*来实现通配
* *..*.*()
  • 关于参数
  1. 可以直接写数据类型
    基本类型直接写名称:int
    引用类型写包名.类名的方式:java.lang.String
  2. 可以使用通配符表示任意类型,但是必须有参数
  3. 可以使用…表示有无参数均可,有参数可以是任意类型

实际开发中切入点表达式的通常写法:
切到业务层实现类下的所有方法

 * com.itheima.service.impl.*.*(..)

业务层接口

package com.serrvice;/*** 账户的业务层接口*/
public interface AccountService {/*** 模拟保存账户*/void saveAccount();/*** 模拟更新账户* @param i*/void updateAccount(int i);/*** 删除账户* @return*/int  deleteAccount();
}

业务层实体类

package com.serrvice.impl;import com.serrvice.AccountService;/*** 账户的业务层实现类*/
public class AccountServiceImpl implements AccountService {@Overridepublic void saveAccount() {System.out.println("执行了保存");}@Overridepublic void updateAccount(int i) {System.out.println("执行了更新"+i);}@Overridepublic int deleteAccount() {System.out.println("执行了删除");return 0;}
}

工具类

package com.utils;/*** 用于记录日志的工具类,它里面提供了公共的代码*/
public class Logger {/*** 用于打印日志:计划让其在切入点方法执行之前执行(切入点方法就是业务层方法)*/public  void printLog(){System.out.println("Logger类中的pringLog方法开始记录日志了。。。");}
}

测试类

package com;import com.serrvice.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** 测试AOP的配置*/
public class AOPTest {public static void main(String[] args) {//1.获取容器ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");//2.获取对象AccountService as = (AccountService) ac.getBean("accountService");//3.执行方法as.saveAccount();as.updateAccount(1);as.deleteAccount();}
}

结果:
在这里插入图片描述

四种常用的通知类型

  • 前置通知:在切入点方法执行之前执行
  • 后置通知:在切入点方法正常执行之后值。它和异常通知永远只能执行一个
  • 异常通知:在切入点方法执行产生异常之后执行。它和后置通知永远只能执行一个
  • 最终通知:无论切入点方法是否正常执行它都会在其后面执行

将bean.xml文件进行修改

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 配置srping的Ioc,把service对象配置进来--><bean id="accountService" class="com.serrvice.impl.AccountServiceImpl"></bean><!-- 配置Logger类(日志类) --><bean id="logger" class="com.utils.Logger"></bean><!--配置AOP--><aop:config><!--配置切面 --><aop:aspect id="logAdvice" ref="logger"><!-- 配置通知的类型,并且建立通知方法和切入点方法的关联--><!-- 配置前置通知:在切入点方法执行之前执行--><aop:before method="beforePrintLog" pointcut="execution(public void com.serrvice.impl.*.*(..))"></aop:before><!-- 配置后置通知:在切入点方法正常执行之后值。它和异常通知永远只能执行一个--><aop:after-returning method="afterReturningPrintLog" pointcut="execution(* com.serrvice.impl.*.*(..))"></aop:after-returning><!-- 配置异常通知:在切入点方法执行产生异常之后执行。它和后置通知永远只能执行一个--><aop:after-throwing method="afterThrowingPrintLog" pointcut="execution(* com.serrvice.impl.*.*(..))"></aop:after-throwing><!-- 配置最终通知:无论切入点方法是否正常执行它都会在其后面执行--><aop:after method="afterPrintLog" pointcut="execution(* com.serrvice.impl.*.*(..))"></aop:after></aop:aspect></aop:config>
</beans>

将工具类进行修改

package com.utils;/*** 用于记录日志的工具类,它里面提供了公共的代码*/
public class Logger {/*** 用于打印日志:计划让其在切入点方法执行之前执行(切入点方法就是业务层方法)*/public  void beforePrintLog(){System.out.println("Logger类中的beforePrintLog方法开始记录日志了。。。");}/*** 后置通知*/public  void afterReturningPrintLog(){System.out.println("后置通知Logger类中的afterReturningPrintLog方法开始记录日志了。。。");}/*** 异常通知*/public  void afterThrowingPrintLog(){System.out.println("异常通知Logger类中的afterThrowingPrintLog方法开始记录日志了。。。");}/*** 最终通知*/public  void afterPrintLog(){System.out.println("最终通知Logger类中的afterPrintLog方法开始记录日志了。。。");}
}

运行结果:
在这里插入图片描述
我们可以看到,还有一个异常通知没有出现,我们可以修改业务层实体类来测试一下,如下:

package com.serrvice.impl;import com.serrvice.AccountService;/*** 账户的业务层实现类*/
public class AccountServiceImpl implements AccountService {@Overridepublic void saveAccount() {System.out.println("执行了保存");int i=1/0;          //此处为异常}@Overridepublic void updateAccount(int i) {System.out.println("执行了更新"+i);}@Overridepublic int deleteAccount() {System.out.println("执行了删除");return 0;}
}

运行结果:
在这里插入图片描述

切入点表达式的通用化

我们注意到上面每写一次通知都要写一遍切入点表达式,为了减少需要重复书写的代码,我们可以进行如下操作:

  • aop:pointcut标签
    属性:
    id:用于指定表达式的唯一标识。
    expression:用于指定表达式内容
    此标签写在aop:aspect标签内部只能在当前切面使用;写在aop:aspect外面,就变成了所有切面可用。

例:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 配置srping的Ioc,把service对象配置进来--><bean id="accountService" class="com.serrvice.impl.AccountServiceImpl"></bean><!-- 配置Logger类(日志类) --><bean id="logger" class="com.utils.Logger"></bean><!--配置AOP--><aop:config><!--配置切入点表达式--><aop:pointcut id="pt1" expression="execution(public void com.serrvice.impl.*.*(..))"/><!--配置切面 --><aop:aspect id="logAdvice" ref="logger"><!-- 配置通知的类型,并且建立通知方法和切入点方法的关联--><!-- 配置前置通知:在切入点方法执行之前执行--><aop:before method="beforePrintLog" pointcut-ref="pt1"></aop:before><!-- 配置后置通知:在切入点方法正常执行之后值。它和异常通知永远只能执行一个--><aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"></aop:after-returning><!-- 配置异常通知:在切入点方法执行产生异常之后执行。它和后置通知永远只能执行一个--><aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing><!-- 配置最终通知:无论切入点方法是否正常执行它都会在其后面执行--><aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after></aop:aspect></aop:config>
</beans>

环绕通知

spring中的环绕通知,它是spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式,相当于拦截所有的方法并自定义代理增强的内容
Spring框架为我们提供了一个接口:ProceedingJoinPoint。该接口有一个方法proceed(),此方法就相当于明确调用切入点方法。该接口可以作为环绕通知的方法参数,在程序执行时,spring框架会为我们提供该接口的实现类供我们使用。

例:
修改工具类

package com.utils;import org.aspectj.lang.ProceedingJoinPoint;/*** 用于记录日志的工具类,它里面提供了公共的代码*/
public class Logger {/*** 用于打印日志:计划让其在切入点方法执行之前执行(切入点方法就是业务层方法)*/public  void beforePrintLog(){System.out.println("Logger类中的beforePrintLog方法开始记录日志了。。。");}/*** 后置通知*/public  void afterReturningPrintLog(){System.out.println("后置通知Logger类中的afterReturningPrintLog方法开始记录日志了。。。");}/*** 异常通知*/public  void afterThrowingPrintLog(){System.out.println("异常通知Logger类中的afterThrowingPrintLog方法开始记录日志了。。。");}/*** 最终通知*/public  void afterPrintLog(){System.out.println("最终通知Logger类中的afterPrintLog方法开始记录日志了。。。");}/*** 环绕通知*/public Object aroundPringLog(ProceedingJoinPoint pjp){Object rtValue = null;try{Object[] args = pjp.getArgs();//得到方法执行所需的参数System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。前置");rtValue = pjp.proceed(args);//明确调用业务层方法(切入点方法)System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。后置");return rtValue;}catch (Throwable t){System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。异常");throw new RuntimeException(t);}finally {System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。最终");}}
}

修改xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 配置srping的Ioc,把service对象配置进来--><bean id="accountService" class="com.serrvice.impl.AccountServiceImpl"></bean><!-- 配置Logger类(日志类) --><bean id="logger" class="com.utils.Logger"></bean><!--配置AOP--><aop:config><!-- 配置切入点表达式--><aop:pointcut id="pt1" expression="execution(public void com.serrvice.impl.*.*(..))"/><!--配置切面 --><aop:aspect id="logAdvice" ref="logger"><!-- 配置环绕通知--><aop:around method="aroundPringLog" pointcut-ref="pt1"></aop:around></aop:aspect></aop:config>
</beans>

运行结果:
在这里插入图片描述

基于注解的AOP配置

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!-- 配置spring创建容器时要扫描的包--><context:component-scan base-package="com"></context:component-scan><!-- 配置spring开启注解AOP的支持 --><aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

业务层实体类注解创建Bean对象

package com.service.impl;import com.service.AccountService;
import org.springframework.stereotype.Service;/*** 账户的业务层实现类*/
@Service("accountService")
public class AccountServiceImpl implements AccountService {@Overridepublic void saveAccount() {System.out.println("执行了保存");
//        int i=1/0;          //此处为异常}@Overridepublic void updateAccount(int i) {System.out.println("执行了更新"+i);}@Overridepublic int deleteAccount() {System.out.println("执行了删除");return 0;}
}

工具类

package com.utils;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;/*** 用于记录日志的工具类,它里面提供了公共的代码*/
@Component("logger")
@Aspect//表示当前类是一个切面类
public class Logger {@Pointcut("execution(* com.service.impl.*.*(..))")private void pt1(){}//    /**
//     * 用于打印日志:计划让其在切入点方法执行之前执行(切入点方法就是业务层方法)
//     */
//    @Before("pt1()")
//    public  void beforePrintLog(){
//        System.out.println("Logger类中的beforePrintLog方法开始记录日志了。。。");
//    }
//
//    /**
//     * 后置通知
//     */
//    @AfterReturning("pt1()")
//    public  void afterReturningPrintLog(){
//        System.out.println("后置通知Logger类中的afterReturningPrintLog方法开始记录日志了。。。");
//    }
//
//    /**
//     * 异常通知
//     */
//    @AfterThrowing("pt1()")
//    public  void afterThrowingPrintLog(){
//        System.out.println("异常通知Logger类中的afterThrowingPrintLog方法开始记录日志了。。。");
//    }
//
//    /**
//     * 最终通知
//     */
//    @After("pt1()")
//    public  void afterPrintLog(){
//        System.out.println("最终通知Logger类中的afterPrintLog方法开始记录日志了。。。");
//    }@Around("pt1()")public Object aroundPringLog(ProceedingJoinPoint pjp){Object rtValue = null;try{Object[] args = pjp.getArgs();//得到方法执行所需的参数System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。前置");rtValue = pjp.proceed(args);//明确调用业务层方法(切入点方法)System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。后置");return rtValue;}catch (Throwable t){System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。异常");throw new RuntimeException(t);}finally {System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。最终");}}
}

运行结果:
在这里插入图片描述

相关文章:

Blender全流程制作真实感3D产品学习教程

MP4 |视频:h264&#xff0c;1280720 |音频:AAC&#xff0c;44.1 KHz&#xff0c;2 Ch 语言&#xff1a;英语中英文字幕&#xff08;根据原英文字幕机译更准确&#xff09; |时长:41节课(4h 29m) |大小解压后:4.53 GB 仅使用blender 2.8进行建模、纹理、光照和渲染&#xff0c;…

如何给iOS应用添加原生的二维码扫描功能

之前总觉得二维码扫描很高大上&#xff0c;其实apple工程师早就为我们提供了便捷的方法。二维码扫描第三方的库也挺多的&#xff0c;不过效率高的当属系统提供的扫描方法。 二维码扫描主要用到了以下几个类&#xff1a;AVCaptureDevice,AVCaptureDeviceInput,AVCaptureMetadata…

2021-2027年中国市医疗电子场投资分析及前景预测报告

【报告类型】产业研究 【报告价格】4500起 【出版时间】即时更新&#xff08;交付时间约3个工作日&#xff09; 【发布机构】智研瞻产业研究院 【报告格式】PDF版 本报告介绍了中国医疗电子行业市场行业相关概述、中国医疗电子行业市场行业运行环境、分析了中国医疗电子行…

RabbitMQ入门(4)--路由

2019独角兽企业重金招聘Python工程师标准>>> ###路由 ###&#xff08;使用Java客户端&#xff09; 在先前的指南中&#xff0c;我们建立了一个简单的日志系统。我们可以将我们的日志信息广播到多个接收者。 在这部分的指南中&#xff0c;我们将要往其中添加一个功能…

从一个数组中寻找出现奇数次的数字

假设给定了数组nums为[0,1,2,3,4,5,6,7,8,9,10,10,9,8,7,6,5,4,1,2,3,3,0] 其中3出现了3次 而其他数字都出现了两次 则我们应该得到结果为3 第一种方式&#xff1a;使用Hash 1 /**2 * 使用hash3 * */4 public static int singleNumber_1(int[] nums) {5 …

Blender写实建筑场景制作学习教程 Exterior Visualization in Blender 2.9

MP4 |视频:h264&#xff0c;1280720 |音频:AAC&#xff0c;44.1 KHz&#xff0c;2 Ch 语言&#xff1a;英语中英文字幕&#xff08;根据原英文字幕机译更准确&#xff09; |时长:26节课(3h 41m) |大小:3.3 GB 使用Blender创建惊人的外部渲染。 你会学到: Blender中的建模、着色…

Postman增删改查接口测试

查 一.选择Get方式 二.点击Send开始测试&#xff0c;得出结果 增 一.选择Post方式 二.输入需要增添的数据 三.点击Send测试 四.没有报错&#xff0c;添加成功 查看一下&#xff0c;发现确实添加进去了 删 一.选择Delete方式 二.根据id删除&#xff0c;在请求路径下直接写出…

新安装Ubuntu加载时提示“为/检查磁盘时发生严重错误”的解决方法

本文部分内容转载自&#xff1a; http://jingyan.baidu.com/article/0aa22375bbffbe88cc0d6419.html http://www.aichengxu.com/view/35086 解决方法&#xff1a; 1. 进入Ubuntu启动菜单时按e 键进入启动项编辑模式&#xff1a; 2. 找到代码【ro rootflagsync】&#xff0c;将其…

android binder机制之——(创建binder服务)

Binder机制编程前面的几篇文章具体介绍了android中binder机制的方方面面&#xff0c;相信你对binder机制已经有了较深刻的理解。俗话说得好“学以致用”&#xff0c;以下我们就通过在android系统中创建一个我们自己的binder服务&#xff0c;来加深对binder机制的理解。&#xf…

通过NSProxy来解决NSTimer使用不当造成内存泄漏的问题

NSTimer的一般使用: 1 interface ViewController : UIViewController2 property (nonatomic, strong) NSTimer *timer;3 end4 5 implementation ViewController6 - (void)viewDidLoad {7 [super viewDidLoad];8 [self startTimer];9 } 10 11 - (void)startTimer { 12 …

Blender 2.9中的真实感三维产品全流程制作学习教程

MP4 |视频:h264&#xff0c;1280720 |音频:AAC&#xff0c;44.1 KHz&#xff0c;2 Ch 语言&#xff1a;英语中英文字幕&#xff08;根据原英文字幕机译更准确&#xff09; |时长:41节课(6h 23m) |大小:5.83 GB 含课程文件 使用blender 2.9建模、纹理、光照和渲染真实的吉他 …

SpringBoot中的SFL4J日志

SpringBoot&#xff1a;底层是Spring框架&#xff0c;Spring框架默认使用的是JCL日志的抽象层 SpringBoot选用SLF4J和logback 如何系统地在系统中使用SLF4J 在开发的使用&#xff0c;日志记录方法的调用&#xff0c;不应该来直接调用日志的实现类&#xff0c;而是调用日志抽象…

web开发性能优化---用户体验篇

怎样从技术角度怎样增强用户体验。都是非常多平台都在做的事情&#xff0c;依据个人实际经验碰到几种体验做下总结。1、降低页面刷新白屏适当使用ajax技术。改善刷新白屏现象。2、信息提醒&#xff0c;邮件、站内信、短信在购物流程、售后流程适当添加信息温馨提醒环节&#xf…

linux命令2--cd和pwd

2019独角兽企业重金招聘Python工程师标准>>> cd是linux中最为常见的一个命令&#xff0c;其作用就是切换到某一个路径下 例子1 到自己的用户目录下 cd ~ 也可以直接cd 例子2 返回进入当前目录之前的目录 cd - 例子3 把上一个命令作为cd的参数命令 cd !$ 参考文档&am…

COALESCE语句解救sql的sum问题

mysqlmybatis有一个sql语句是统计用的 <select id"getNum" resultType"map"> 结果是一个map&#xff0c; select语句的结果是一些sum select sum(t.anum),sum(t.bnum)from tableSum twhere t.id #{id} 调试发现&#xff0c;数据库明明记录已经落入&…

在UE5创造一个多山的松树森林场景学习教程

UE5游戏场景设计制作视频教程 大小解压后&#xff1a;4.37G 1920X1080 mp4 语言&#xff1a;英语中英字幕&#xff08;机译&#xff09;时长&#xff1a;5小时 20分 课程获取&#xff1a;在UE5创造一个多山的松树森林场景学习教程

编写纳新网站后端的相关知识总结

使用HSSFWorkbook导出数据库中的数据 导入Apache POI Maven jar包 <!-- Apache POI --> <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.6</version> </dependency>在控制层编…

IOSUIcontrol事件

UIKit提供了一组控件&#xff1a;UISwitch开关、UIButton按钮、UISegmentedControl分段控件、UISlider滑块、UITextField文本字段控件、UIPageControl分页控件。 控件是对UIView派生类的实用增强及补充&#xff0c;并可以直接附着于导航栏、表格单元&#xff0c;甚至更大的对象…

Xcode Debugging

程序员日常开发中有大量时间都会花费在 debug 上&#xff0c;从事 iOS 开发不可避免地需要使用 Xcode。这篇博客就主要介绍了 Xcode 中几种能够大幅提升代码调试效率的方式。“If debugging is the process of removing bugs, then programming must be the process of putting…

css小技巧 -- 单标签实现单行文字居中,多行文字居左

可能出现的尺寸场景: 代码如下&#xff1a; <!DOCTYPE html> <html lang"zh"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv&q…

Unity游戏开发大师班

大小解压后&#xff1a;8.63G 持续时间19h 包含项目文件 1280X720 MP4 语言&#xff1a;英语中英文字幕&#xff08;根据原英文字幕机译更准确&#xff09; Unity游戏开发大师班 信息: 要求 –没有课程要求&#xff0c;展示了开发过程的每一步(包括解释的每一行代码) 这门课…

GC处理的分析

GC处理的深入分析 在Java中针对垃圾收集也提供了多种不同的处理分类 1.引用计数&#xff1a; 一个实例化对象&#xff0c;如果有程序使用了这个引用对象&#xff0c;引用计数加一&#xff0c;当一个对象使用完毕&#xff0c;引用计数减一&#xff0c;当引用计数为0时&#x…

2016.1.20 dubbo启动之后机器ip有问题

环境 100.0.4.222 zookerper 2182 100.0.4.221 dubbo 20871 1.问题 dubbo 对应的机器ip 是202.106.199.37 不是100.0.4.221 2.解决 说明 主机名有问题 修改主机名 使之生效 重启zookeeper服务 和dubbo服务 搞定 转载于:https://www.cnblogs.com/huawei306/p…

在Eclipse或MyEclipse中安装findbugs插件

2019独角兽企业重金招聘Python工程师标准>>> 我们都知道&#xff0c;在Eclipse或MyEclipse中安装插件有两种方式&#xff0c;一种是在线安装&#xff0c;第二种是先下载插件然后在本地安装。 在这里我们先介绍第一种在线安装。 Eclipse上在线安装findbugs(具体步骤如…

Jboss解决只能通过localhost访问而不能使用IP访问项目的问题

jboss的配置文件&#xff0c;如 E:\downloadChrome\wildfly-10.1.0.Final\standalone\configuration\shandalone.xml <interfaces> <interface name"management"> <inet-address value"${jboss.bind.address.management:127.0.0.1}"/>…

一.JDBC概述

第1章&#xff1a;JDBC概述 1.1 数据的持久化 持久化(persistence)&#xff1a;把数据保存到可掉电式存储设备中以供之后使用。大多数情况下&#xff0c;特别是企业级应用&#xff0c;数据持久化意味着将内存中的数据保存到硬盘上加以”固化”&#xff0c;而持久化的实现过程大…

在Blender中创建惊人的低多边形动画

大小解压后&#xff1a;13.5G 持续时间10小时 包括项目文件 1920X1080 MP4 语言&#xff1a;英语中英文字幕&#xff08;根据原英文字幕机译更准确&#xff09; 标题:CGBoost学院–立方体世界在Blender中创建惊人的低多边形动画 信息: 创建漂亮的3D动画&#xff0c;就像玩乐高…

开发Eclipse自定义控件

摘自&#xff1a;http://www.ibm.com/developerworks/cn/opensource/os-eclipcntl/ 我们在开发自定义控件时主要考虑以下问题&#xff1a; 1、 自定义控件的绘制&#xff1a;通常我们需要自己对控件的形状或图案进行绘制&#xff1b; 2、 控件对键盘事件的响应&#xff1a;当焦…

小米手机无法连接eclipse调试案例

按照参考博客2的方法 小米2S手机在Eclipse真机调试时&#xff0c;设备选择列表无法显示手机&#xff0c;DDMS也连接不上设备&#xff0c;解决步骤&#xff1a; 1.打开手机设置中开发者选项 - USB调试开启&#xff1b; 2.保证小米2S手机Windows下设备驱动已安装&#xff0c;可…

手机号码格式验证和 FASTDFS 工具类

常见大陆和香港号码格式验证 import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException;public class PhoneFormatCheckUtils {// 大陆号码或香港号码均可public static boolean isPhoneLegal(String str) throws Patt…