詳解Spring學(xué)習(xí)總結(jié)——Spring實(shí)現(xiàn)AOP的多種方式
目錄
一、基于XML配置的Spring AOP
二、使用注解配置AOP
三、AspectJ切點(diǎn)函數(shù)
四、AspectJ通知注解
五、零配置實(shí)現(xiàn)Spring IoC與AOP
AOP(Aspect Oriented Programming)面向切面編程,通過預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的橫向多模塊統(tǒng)一控制的一種技術(shù)。AOP是OOP的補(bǔ)充,是spring框架中的一個(gè)重要內(nèi)容。利用AOP可以對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時(shí)提高了開發(fā)的效率。AOP可以分為靜態(tài)織入與動(dòng)態(tài)織入,靜態(tài)織入即在編譯前將需織入內(nèi)容寫入目標(biāo)模塊中,這樣成本非常高。動(dòng)態(tài)織入則不需要改變目標(biāo)模塊。Spring框架實(shí)現(xiàn)了AOP,使用注解配置完成AOP比使用XML配置要更加方便與直觀。
一、基于XML配置的Spring AOP
在講注解實(shí)現(xiàn)AOP功能前先用前面學(xué)習(xí)過的使用xml配置Spring AOP功能,這樣是為了對(duì)比以便更好的理解。
1.1、新建一個(gè)Maven項(xiàng)目,添加引用,項(xiàng)目的pom.xml文件如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zhangguo</groupId> <artifactId>Spring052</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>Spring052</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>4.3.0.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> <version>4.10</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.9</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.4</version> </dependency> </dependencies> </project>
1.2、創(chuàng)建要被代理的Math類,代碼如下:
package com.zhangguo.Spring052.aop01; /** * 被代理的目標(biāo)類 */ public class Math{ //加 public int add(int n1,int n2){ int result=n1+n2; System.out.println(n1+"+"+n2+"="+result); return result; } //減 public int sub(int n1,int n2){ int result=n1-n2; System.out.println(n1+"-"+n2+"="+result); return result; } //乘 public int mut(int n1,int n2){ int result=n1*n2; System.out.println(n1+"X"+n2+"="+result); return result; } //除 public int div(int n1,int n2){ int result=n1/n2; System.out.println(n1+"/"+n2+"="+result); return result; } }
1.3、編輯AOP中需要使用到的通知類Advices.Java代碼如下:
package com.zhangguo.Spring052.aop01; import org.aspectj.lang.JoinPoint; /** * 通知類,橫切邏輯 * */ public class Advices { public void before(JoinPoint jp){ System.out.println("----------前置通知----------"); System.out.println(jp.getSignature().getName()); } public void after(JoinPoint jp){ System.out.println("----------最終通知----------"); } }
1.4、配置容器初始化時(shí)需要的XML文件,aop01.xml文件內(nèi)容如下:
<?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <!-- 被代理對(duì)象 --> <bean id="math" class="com.zhangguo.Spring052.aop01.Math"></bean> <!-- 通知 --> <bean id="advices" class="com.zhangguo.Spring052.aop01.Advices"></bean> <!-- aop配置 --> <aop:config proxy-target-class="true"> <!--切面 --> <aop:aspect ref="advices"> <!-- 切點(diǎn) --> <aop:pointcut expression="execution(* com.zhangguo.Spring052.aop01.Math.*(..))" id="pointcut1"/> <!--連接通知方法與切點(diǎn) --> <aop:before method="before" pointcut-ref="pointcut1"/> <aop:after method="after" pointcut-ref="pointcut1"/> </aop:aspect> </aop:config> </beans>
1.5、測(cè)試代碼Test.java如下:
package com.zhangguo.Spring052.aop01; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("aop01.xml"); Math math = ctx.getBean("math", Math.class); int n1 = 100, n2 = 5; math.add(n1, n2); math.sub(n1, n2); math.mut(n1, n2); math.div(n1, n2); } }
運(yùn)行結(jié)果:
二、使用注解配置AOP
2.1、在上一個(gè)示例中修改被代理的類Math,為了實(shí)現(xiàn)IOC掃描在Math類上注解了@Service并命名bean為math。相當(dāng)于上一個(gè)示例中在xml配置文件中增加了一個(gè)bean,<!-- 被代理對(duì)象 --><bean id="math" class="com.zhangguo.Spring052.aop01.Math"></bean>,Math類的代碼如下:
package com.zhangguo.Spring052.aop02; import org.springframework.stereotype.Service; /** * 被代理的目標(biāo)類 */ @Service("math") public class Math{ //加 public int add(int n1,int n2){ int result=n1+n2; System.out.println(n1+"+"+n2+"="+result); return result; } //減 public int sub(int n1,int n2){ int result=n1-n2; System.out.println(n1+"-"+n2+"="+result); return result; } //乘 public int mut(int n1,int n2){ int result=n1*n2; System.out.println(n1+"X"+n2+"="+result); return result; } //除 public int div(int n1,int n2){ int result=n1/n2; System.out.println(n1+"/"+n2+"="+result); return result; } }
2.2、修改通知類Advices,代碼中有3個(gè)注解,@Component表示該類的實(shí)例會(huì)被Spring IOC容器管理;@Aspect表示聲明一個(gè)切面;@Before表示before為前置通知,通過參數(shù)execution聲明一個(gè)切點(diǎn),Advices.java代碼如下所示:
package com.zhangguo.Spring052.aop02; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; /** * 通知類,橫切邏輯 * */ @Component @Aspect public class Advices { @Before("execution(* com.zhangguo.Spring052.aop02.Math.*(..))") public void before(JoinPoint jp){ System.out.println("----------前置通知----------"); System.out.println(jp.getSignature().getName()); } @After("execution(* com.zhangguo.Spring052.aop02.Math.*(..))") public void after(JoinPoint jp){ System.out.println("----------最終通知----------"); } }
上面的代碼與下面的配置基本等同
<!-- 通知 --> <bean id="advices" class="com.zhangguo.Spring052.aop01.Advices"></bean> <!-- aop配置 --> <aop:config proxy-target-class="true"> <!--切面 --> <aop:aspect ref="advices"> <!-- 切點(diǎn) --> <aop:pointcut expression="execution(* com.zhangguo.Spring052.aop01.Math.*(..))" id="pointcut1"/> <!--連接通知方法與切點(diǎn) --> <aop:before method="before" pointcut-ref="pointcut1"/> <aop:after method="after" pointcut-ref="pointcut1"/> </aop:aspect> </aop:config>
2.3、新增配置文件aop02.xml,在配置IOC的基礎(chǔ)上增加了aop:aspectj-autoproxy節(jié)點(diǎn),Spring框架會(huì)自動(dòng)為與AspectJ切面配置的Bean創(chuàng)建代理,proxy-target-class="true"屬性表示被代理的目標(biāo)對(duì)象是一個(gè)類,而非實(shí)現(xiàn)了接口的類,主要是為了選擇不同的代理方式。
<?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <context:component-scan base-package="com.zhangguo.Spring052.aop02"> </context:component-scan> <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> </beans>
2.4、測(cè)試運(yùn)行代碼Test.java如下:
package com.zhangguo.Spring052.aop02; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("aop02.xml"); Math math = ctx.getBean("math", Math.class); int n1 = 100, n2 = 5; math.add(n1, n2); math.sub(n1, n2); math.mut(n1, n2); math.div(n1, n2); } }
運(yùn)行結(jié)果:
三、AspectJ切點(diǎn)函數(shù)
切點(diǎn)函數(shù)可以定位到準(zhǔn)確的橫切邏輯位置,在前面的示例中我們只使用過execution(* com.zhangguo.Spring052.aop02.Math.*(..)),execution就是一個(gè)切點(diǎn)函數(shù),但該函數(shù)只什么方法一級(jí),如果我們要織入的范圍是類或某個(gè)注解則execution就不那么好用了,其實(shí)一共有9個(gè)切點(diǎn)函數(shù),有不同的針對(duì)性。
@AspectJ使用AspectJ專門的切點(diǎn)表達(dá)式描述切面,Spring所支持的AspectJ表達(dá)式可分為四類:
方法切點(diǎn)函數(shù):通過描述目標(biāo)類方法信息定義連接點(diǎn)。
方法參數(shù)切點(diǎn)函數(shù):通過描述目標(biāo)類方法入?yún)⑿畔⒍x連接點(diǎn)。
目標(biāo)類切點(diǎn)函數(shù):通過描述目標(biāo)類類型信息定義連接點(diǎn)。
代理類切點(diǎn)函數(shù):通過描述代理類信息定義連接點(diǎn)。
常見的AspectJ表達(dá)式函數(shù):
- execution():滿足匹配模式字符串的所有目標(biāo)類方法的連接點(diǎn)
- @annotation():任何標(biāo)注了指定注解的目標(biāo)方法鏈接點(diǎn)
- args():目標(biāo)類方法運(yùn)行時(shí)參數(shù)的類型指定連接點(diǎn)
- @args():目標(biāo)類方法參數(shù)中是否有指定特定注解的連接點(diǎn)
- within():匹配指定的包的所有連接點(diǎn)
- target():匹配指定目標(biāo)類的所有方法
- @within():匹配目標(biāo)對(duì)象擁有指定注解的類的所有方法
- @target():匹配當(dāng)前目標(biāo)對(duì)象類型的執(zhí)行方法,其中目標(biāo)對(duì)象持有指定的注解
- this():匹配當(dāng)前AOP代理對(duì)象類型的所有執(zhí)行方法
最常用的是:execution(<修飾符模式>?<返回類型模式><方法名模式>(<參數(shù)模式>)<異常模式>?)切點(diǎn)函數(shù),可以滿足多數(shù)需求。
為了展示各切點(diǎn)函數(shù)的功能現(xiàn)在新增一個(gè)類StrUtil,類如下:
package com.zhangguo.Spring052.aop03; import org.springframework.stereotype.Component; @Component("strUtil") public class StrUtil { public void show(){ System.out.println("Hello StrUtil!"); } }
測(cè)試代碼如下:
package com.zhangguo.Spring052.aop03; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("aop03.xml"); IMath math = ctx.getBean("math", Math.class); int n1 = 100, n2 = 5; math.add(n1, n2); math.sub(n1, n2); math.mut(n1, n2); math.div(n1, n2); StrUtil strUtil=ctx.getBean("strUtil",StrUtil.class); strUtil.show(); } }
3.1、切點(diǎn)函數(shù)execution,通知與切面的定義如下:
package com.zhangguo.Spring052.aop03; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; /** * 通知類,橫切邏輯 * */ @Component @Aspect public class Advices { @Before("execution(* com.zhangguo.Spring052.aop03.Math.*(..))") public void before(JoinPoint jp){ System.out.println("----------前置通知----------"); System.out.println(jp.getSignature().getName()); } //execution切點(diǎn)函數(shù) //com.zhangguo.Spring052.aop03包下所有類的所有方法被切入 @After("execution(* com.zhangguo.Spring052.aop03.*.*(..))") public void after(JoinPoint jp){ System.out.println("----------最終通知----------"); } }
運(yùn)行結(jié)果如下:
execution(<修飾符模式>?<返回類型模式><方法名模式>(<參數(shù)模式>)<異常模式>?)
3.2、切點(diǎn)函數(shù)within
//within切點(diǎn)函數(shù) //com.zhangguo.Spring052.aop03包下所有類的所有方法被切入 @After("within(com.zhangguo.Spring052.aop03.*)") public void after(JoinPoint jp){ System.out.println("----------最終通知----------"); }
3.3、this切點(diǎn)函數(shù)
//this切點(diǎn)函數(shù) //實(shí)現(xiàn)了IMath接口的代理對(duì)象的任意連接點(diǎn) @After("this(com.zhangguo.Spring052.aop03.IMath)") public void after(JoinPoint jp){ System.out.println("----------最終通知----------"); }
3.4、args切點(diǎn)函數(shù)
//args切點(diǎn)函數(shù) //要求方法有兩個(gè)int類型的參考才會(huì)被織入橫切邏輯 @After("args(int,int)") public void after(JoinPoint jp){ System.out.println("----------最終通知----------"); }
如果參數(shù)類型不是基本數(shù)據(jù)類型則需要包名。
3.5、@annotation切點(diǎn)函數(shù)
先自定義一個(gè)可以注解在方法上的注解
package com.zhangguo.Spring052.aop03; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyAnno { } //@annotation切點(diǎn)函數(shù) //要求方法必須被注解com.zhangguo.Spring052.aop03.MyAnno才會(huì)被織入橫切邏輯 @After("@annotation(com.zhangguo.Spring052.aop03.MyAnno)") public void after(JoinPoint jp){ System.out.println("----------最終通知----------"); }
package com.zhangguo.Spring052.aop03; import org.springframework.stereotype.Component; @Component("strUtil") public class StrUtil { @MyAnno public void show(){ System.out.println("Hello StrUtil!"); } }
運(yùn)行結(jié)果:
其它帶@的切點(diǎn)函數(shù)都是針對(duì)注解的
四、AspectJ通知注解
AspectJ通知注解共有6個(gè),常用5個(gè),引介少用一些。
先解決定義切點(diǎn)復(fù)用的問題,如下代碼所示,切點(diǎn)函數(shù)的內(nèi)容完全一樣:
package com.zhangguo.Spring052.aop04; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; /** * 通知類,橫切邏輯 * */ @Component @Aspect public class Advices { @Before("execution(* com.zhangguo.Spring052.aop04.Math.*(..))") public void before(JoinPoint jp){ System.out.println("----------前置通知----------"); System.out.println(jp.getSignature().getName()); } @After("execution(* com.zhangguo.Spring052.aop04.Math.*(..))") public void after(JoinPoint jp){ System.out.println("----------最終通知----------"); } }
可以先定義一個(gè)切點(diǎn)然后復(fù)用,如下所示:
package com.zhangguo.Spring052.aop04; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /** * 通知類,橫切邏輯 */ @Component @Aspect public class Advices { //切點(diǎn) @Pointcut("execution(* com.zhangguo.Spring052.aop04.Math.*(..))") public void pointcut(){ } @Before("pointcut()") public void before(JoinPoint jp){ System.out.println("----------前置通知----------"); System.out.println(jp.getSignature().getName()); } @After("pointcut()") public void after(JoinPoint jp){ System.out.println("----------最終通知----------"); } }
修改Advices.java文件,增加各種通知類型如下:
package com.zhangguo.Spring052.aop04; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /** * 通知類,橫切邏輯 */ @Component @Aspect public class Advices { //切點(diǎn) @Pointcut("execution(* com.zhangguo.Spring052.aop04.Math.a*(..))") public void pointcut(){ } //前置通知 @Before("pointcut()") public void before(JoinPoint jp){ System.out.println(jp.getSignature().getName()); System.out.println("----------前置通知----------"); } //最終通知 @After("pointcut()") public void after(JoinPoint jp){ System.out.println("----------最終通知----------"); } //環(huán)繞通知 @Around("execution(* com.zhangguo.Spring052.aop04.Math.s*(..))") public Object around(ProceedingJoinPoint pjp) throws Throwable{ System.out.println(pjp.getSignature().getName()); System.out.println("----------環(huán)繞前置----------"); Object result=pjp.proceed(); System.out.println("----------環(huán)繞后置----------"); return result; } //返回結(jié)果通知 @AfterReturning(pointcut="execution(* com.zhangguo.Spring052.aop04.Math.m*(..))",returning="result") public void afterReturning(JoinPoint jp,Object result){ System.out.println(jp.getSignature().getName()); System.out.println("結(jié)果是:"+result); System.out.println("----------返回結(jié)果----------"); } //異常后通知 @AfterThrowing(pointcut="execution(* com.zhangguo.Spring052.aop04.Math.d*(..))",throwing="exp") public void afterThrowing(JoinPoint jp,Exception exp){ System.out.println(jp.getSignature().getName()); System.out.println("異常消息:"+exp.getMessage()); System.out.println("----------異常通知----------"); } }
運(yùn)行結(jié)果:
五、零配置實(shí)現(xiàn)Spring IoC與AOP
為了實(shí)現(xiàn)零配置在原有示例的基礎(chǔ)上我們新增一個(gè)類User,如下所示:
package com.zhangguo.Spring052.aop05; public class User { public void show(){ System.out.println("一個(gè)用戶對(duì)象"); } }
該類并未注解,容器不會(huì)自動(dòng)管理。因?yàn)闆]有xml配置文件,則使用一個(gè)作為配置信息,ApplicationCfg.java文件如下:
package com.zhangguo.Spring052.aop05; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration //用于表示當(dāng)前類為容器的配置類,類似<beans/> @ComponentScan(basePackages="com.zhangguo.Spring052.aop05") //掃描的范圍,相當(dāng)于xml配置的結(jié)點(diǎn)<context:component-scan/> @EnableAspectJAutoProxy(proxyTargetClass=true) //自動(dòng)代理,相當(dāng)于<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> public class ApplicationCfg { //在配置中聲明一個(gè)bean,相當(dāng)于<bean id=getUser class="com.zhangguo.Spring052.aop05.User"/> @Bean public User getUser(){ return new User(); } }
該類的每一部分內(nèi)容基本都與xml 配置有一對(duì)一的關(guān)系,請(qǐng)看注釋,這樣做要比寫xml方便,但不便發(fā)布后修改。測(cè)試代碼如下:
package com.zhangguo.Spring052.aop05; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { // 通過類初始化容器 ApplicationContext ctx = new AnnotationConfigApplicationContext(ApplicationCfg.class); Math math = ctx.getBean("math", Math.class); int n1 = 100, n2 = 0; math.add(n1, n2); math.sub(n1, n2); math.mut(n1, n2); try { math.div(n1, n2); } catch (Exception e) { } User user=ctx.getBean("getUser",User.class); user.show(); } }
advices.java 同上,沒有任何變化,運(yùn)行結(jié)果如下:
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
mybatis自動(dòng)生成@Table、@Column、@Id注解的方法
這篇文章主要介紹了mybatis自動(dòng)生成@Table、@Column、@Id注解的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12SpringBoot搭配AOP實(shí)現(xiàn)自定義注解
這篇文章主要為大家詳細(xì)介紹了SpringBoot如何搭配AOP實(shí)現(xiàn)自定義注解,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-12-12Hadoop集成Spring的使用詳細(xì)教程(快速入門大數(shù)據(jù))
這篇文章主要介紹了Hadoop集成Spring的使用詳細(xì)教程(快速入門大數(shù)據(jù)),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01Java使用LinkedHashMap進(jìn)行分?jǐn)?shù)排序
這篇文章主要介紹了Java使用LinkedHashMap進(jìn)行分?jǐn)?shù)排序的相關(guān)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05解讀controller層,service層,mapper層,entity層的作用與聯(lián)系
這篇文章主要介紹了關(guān)于controller層,service層,mapper層,entity層的作用與聯(lián)系,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11Java實(shí)現(xiàn)滑動(dòng)驗(yàn)證碼生成(后端工具類)
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)滑動(dòng)驗(yàn)證碼生成功能中的后端工具類部分,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-10-10Spring框架JdbcTemplate數(shù)據(jù)庫事務(wù)管理完全注解方式
這篇文章主要介紹了Spring框架JdbcTemplate數(shù)據(jù)庫事務(wù)管理及完全注解方式,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05