如何利用Java?Agent?做Spring?MVC?Controller?層的出參入?yún)⒋蛴∪罩?/h1>
更新時(shí)間:2024年11月11日 10:40:59 作者:筆墨登場(chǎng)說(shuō)說(shuō)
本文介紹了如何使用JavaAgent進(jìn)行Spring?MVC?Controller層的出參入?yún)⒋蛴∪罩?首先,建立了一個(gè)包含javassist和fastJSON依賴的Agent?jar工程,并創(chuàng)建了一個(gè)Agent類,然后,編譯并部署了這個(gè)Agent?jar,最后,在Demo?Web工程中啟用Agent以實(shí)現(xiàn)日志打印
許多開(kāi)發(fā)使用的spring aop來(lái)做切面 今天嘗試一下使用JVM層面的切面
1、建立 agent jar工程
創(chuàng)建工程 logging-agent 使用POM為 javassist 日志
如下:使用了字節(jié)碼 javassist
如果想處理springaop 代理的請(qǐng)?jiān)黾右蕾嚪駝t就不需要
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.21</version> <!-- 確保使用最新版本 -->
</dependency>
<!-- AspectJ Weaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version> <!-- 確保使用最新版本 -->
</dependency>
為了方便使用fastJSON 做序列化
完整POM如下
<?xml version="1.0" encoding="UTF-8"?>
<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>org.example</groupId>
<artifactId>logging-agent</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.28.0-GA</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.21</version> <!-- 確保使用最新版本 -->
</dependency>
<!-- AspectJ Weaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version> <!-- 確保使用最新版本 -->
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version> <!-- 確保使用最新版本 -->
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.logging.LoggingAgent</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<!--自動(dòng)添加META-INF/MANIFEST.MF -->
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestEntries>
<Premain-Class>org.logging.LoggingAgent</Premain-Class>
<Agent-Class>org.logging.LoggingAgent</Agent-Class>
<Can-Redefine-Classes>true</Can-Redefine-Classes>
<Can-Retransform-Classes>true</Can-Retransform-Classes>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
2、建立一個(gè)Agent類
package org.logging;
import com.alibaba.fastjson.JSON;
import javassist.*;
import org.springframework.aop.framework.AopProxyUtils;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import java.util.*;
public class LoggingAgent {
public static void premain(String agentArgs, Instrumentation inst) {
inst.addTransformer(new LoggingTransformer());
}
static Set<Class<?>> skipLogClassSet = new HashSet<>();
static Map<Class<?>, Boolean> decisionSkipClassMap = new HashMap<>();
static {
skipLogClassSet.add(forName("org.apache.catalina.connector.RequestFacade"));
skipLogClassSet.add(forName("javax.servlet.ServletRequest"));
skipLogClassSet.add(forName("javax.servlet.ServletResponse"));
}
public static Class<?> forName(String clazz) {
try {
return Class.forName(clazz);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return Void.class;
}
public static String toJSONString(Object[] a) {
if (a == null)
return "null";
int iMax = a.length - 1;
if (iMax == -1)
return "[]";
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
// b.append(String.valueOf(a[i]));
Class<?> clazz = a[i].getClass();
System.out.println(clazz);
if (!decisionSkipClassMap.containsKey(clazz)) {
// 檢查類是否實(shí)現(xiàn)了每個(gè)接口
for (Class<?> interfaceClass : skipLogClassSet) {
if (interfaceClass.isAssignableFrom(clazz)) {
System.out.println("myObject 的類實(shí)現(xiàn)了 " + interfaceClass.getName() + " 接口");
decisionSkipClassMap.put(clazz, true);
} else {
System.out.println("myObject 的類沒(méi)有實(shí)現(xiàn) " + interfaceClass.getName() + " 接口");
if (decisionSkipClassMap.containsKey(clazz) && decisionSkipClassMap.get(clazz)) {
//nothing
System.out.println("myObject 的類沒(méi)有實(shí)現(xiàn) " + interfaceClass.getName() + " 接口 但是實(shí)現(xiàn)了其他忽略接口");
} else {
decisionSkipClassMap.put(clazz, interfaceClass.isAssignableFrom(clazz));
}
}
}
}
if (!decisionSkipClassMap.get(clazz)) {
b.append(JSON.toJSONString(a[i]));
}
if (i == iMax)
return b.append(']').toString();
b.append(", ");
}
}
public static class LoggingTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
// 忽略不需要處理的類
if (!className.startsWith("com/xdx/interfaces/facade")) {
return null;
}
// Skip Spring CGLIB proxy classes
if (className.contains("$$EnhancerBySpringCGLIB$$")) {
return null;
}
// Skip Spring CGLIB FastClass proxy classes
if (className.contains("$$FastClassBySpringCGLIB$$")) {
return null;
}
try {
String finalClassName = getFinalClassName(className.replace("/", "."));
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(this.getClass()));
CtClass ctClass = pool.get(finalClassName);
// 獲取類的所有聲明字段
CtField[] fields = ctClass.getDeclaredFields();
String logger = null;
// 打印字段的名稱和類型
for (CtField field : fields) {
System.out.println("Field Name: " + field.getName() + ", Field Type: " + field.getType().getName());
if ("org.slf4j.Logger".equals(field.getType().getName())) {
logger = field.getName();
}
}
for (CtMethod method : ctClass.getDeclaredMethods()) {
try {
addLogging(method, logger);
} catch (Exception e) {
System.err.println("Failed to instrument method: " + method.getName());
e.printStackTrace();
}
}
return ctClass.toBytecode();
} catch (NotFoundException e) {
// Log exception and continue without instrumentation
System.err.println("Class not found: " + className + " - " + e.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
return classfileBuffer;
}
private String getFinalClassName(String className) {
if (className.contains("$$EnhancerBySpringCGLIB$$") || className.contains("$$FastClassBySpringCGLIB$$")) {
try {
Class<?> proxyClass = Class.forName(className);
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(proxyClass);
return targetClass.getName();
} catch (ClassNotFoundException e) {
// Handle exception and return the original className
e.printStackTrace();
}
}
return className;
}
private void addLogging(CtMethod method, String logger) throws CannotCompileException {
if (Objects.isNull(logger)) {
addLogging2(method);
} else {
addLogging1(method, logger);
}
}
private void addLogging1(CtMethod method, String logger) throws CannotCompileException {
// method.insertBefore("System.out.println(\"[ENTER] Method: " + method.getName() + " Arguments: \" + java.util.Arrays.toString($args));");
method.insertBefore(logger + ".info(\"[ENTER1] Method: " + method.getName() + " Arguments: \" +org.logging.LoggingAgent.toJSONString($args));");
// method.insertBefore("log.info(org.logging.LoggingAgent.toJSONString($args));");
method.insertAfter(logger + ".info(\"[EXIT1] Method: " + method.getName() + " Return: \" + $_);");
// method.insertBefore(logger + ".info(\"[EXIT] Method: " + method.getName() + " Return: \" + org.logging.LoggingAgent.toJSONString($_));");
}
private void addLogging2(CtMethod method) throws CannotCompileException {
method.insertBefore("org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(this.getClass());"
+ "logger.info(\"[ENTER2] Method: " + method.getName() + " Arguments: \" + org.logging.LoggingAgent.toJSONString($args));");
// method.insertBefore("org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(this.getClass());" +
// "logger.info(\"[ENTER] Method: " + method.getName() + " Arguments: \" + java.util.Arrays.toString($args));");
method.insertAfter(
"logger.info(\"[EXIT2] Method: " + method.getName() + " Return: \" + $_);", true);//src:表示插入的代碼,這是一段 Java 源代碼的 String。
// asFinally:這是一個(gè) boolean 值,決定了插入的代碼塊是在正常返回后執(zhí)行,還是在方法的正常返回和異常返回后都執(zhí)行。
// method.insertAfter("org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(this.getClass());" +
// "logger.info(\"[EXIT] Method: " + method.getName() + " Return: \" + logger.info(org.logging.LoggingAgent.toJSONString($_)));", true);
}
private void addLogging3(CtMethod method) throws CannotCompileException {
method.insertBefore("System.out.println(\"[ENTER] Method: " + method.getName() + " Arguments: \" + java.util.Arrays.toString($args));");
method.insertAfter("System.out.println(\"[EXIT] Method: " + method.getName() + " Return: \" + $_);");
}
}
}
3、打agent jar

4、創(chuàng)建一個(gè)demoWeb工程
-javaagent:D:\code\logging-agent\target\logging-agent-1.0-SNAPSHOT.jar

為了能調(diào)試需要增加jar

到此這篇關(guān)于利用Java Agent 做Spring MVC Controller 層的出參入?yún)⒋蛴∪罩镜奈恼戮徒榻B到這了,更多相關(guān)Spring MVC Controller 層出參入?yún)⒋蛴∪罩緝?nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
-
Gradle修改本地倉(cāng)庫(kù)的位置方法實(shí)現(xiàn)
這篇文章主要介紹了Gradle修改本地倉(cāng)庫(kù)的位置方法實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧 2020-07-07
-
基于Java實(shí)現(xiàn)圖形驗(yàn)證碼工具類
這篇文章主要為大家詳細(xì)介紹了如何基于Java實(shí)現(xiàn)圖形驗(yàn)證碼工具類,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下 2024-11-11
-
Java實(shí)戰(zhàn)小技巧之?dāng)?shù)組與list互轉(zhuǎn)
在Java中,經(jīng)常遇到需要List與數(shù)組互相轉(zhuǎn)換的場(chǎng)景,下面這篇文章主要給大家介紹了關(guān)于Java實(shí)戰(zhàn)小技巧之?dāng)?shù)組與list互轉(zhuǎn)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下 2021-08-08
-
解決mybatisplus的分頁(yè)插件和條件構(gòu)造器自定義SQL遇到的BUG
這篇文章主要介紹了解決mybatisplus的分頁(yè)插件和條件構(gòu)造器自定義SQL遇到的BUG,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教 2024-08-08
-
Java通過(guò)接口實(shí)現(xiàn)匿名類的實(shí)例代碼
這篇文章介紹了Java通過(guò)接口實(shí)現(xiàn)匿名類的實(shí)例代碼,有需要的朋友可以參考一下 2013-10-10
-
java.text.DecimalFormat類十進(jìn)制格式化
這篇文章主要為大家詳細(xì)介紹了java.text.DecimalFormat類十進(jìn)制格式化的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下 2018-03-03
最新評(píng)論
許多開(kāi)發(fā)使用的spring aop來(lái)做切面 今天嘗試一下使用JVM層面的切面
1、建立 agent jar工程
創(chuàng)建工程 logging-agent 使用POM為 javassist 日志
如下:使用了字節(jié)碼 javassist
如果想處理springaop 代理的請(qǐng)?jiān)黾右蕾嚪駝t就不需要
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.3.21</version> <!-- 確保使用最新版本 --> </dependency> <!-- AspectJ Weaver --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.7</version> <!-- 確保使用最新版本 --> </dependency>
為了方便使用fastJSON 做序列化
完整POM如下
<?xml version="1.0" encoding="UTF-8"?> <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>org.example</groupId> <artifactId>logging-agent</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.28.0-GA</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.3.21</version> <!-- 確保使用最新版本 --> </dependency> <!-- AspectJ Weaver --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.7</version> <!-- 確保使用最新版本 --> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> <!-- 確保使用最新版本 --> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <executions> <execution> <id>attach-sources</id> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>org.logging.LoggingAgent</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.1.0</version> <configuration> <archive> <!--自動(dòng)添加META-INF/MANIFEST.MF --> <manifest> <addClasspath>true</addClasspath> </manifest> <manifestEntries> <Premain-Class>org.logging.LoggingAgent</Premain-Class> <Agent-Class>org.logging.LoggingAgent</Agent-Class> <Can-Redefine-Classes>true</Can-Redefine-Classes> <Can-Retransform-Classes>true</Can-Retransform-Classes> </manifestEntries> </archive> </configuration> </plugin> </plugins> </build> </project>
2、建立一個(gè)Agent類
package org.logging; import com.alibaba.fastjson.JSON; import javassist.*; import org.springframework.aop.framework.AopProxyUtils; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.Instrumentation; import java.security.ProtectionDomain; import java.util.*; public class LoggingAgent { public static void premain(String agentArgs, Instrumentation inst) { inst.addTransformer(new LoggingTransformer()); } static Set<Class<?>> skipLogClassSet = new HashSet<>(); static Map<Class<?>, Boolean> decisionSkipClassMap = new HashMap<>(); static { skipLogClassSet.add(forName("org.apache.catalina.connector.RequestFacade")); skipLogClassSet.add(forName("javax.servlet.ServletRequest")); skipLogClassSet.add(forName("javax.servlet.ServletResponse")); } public static Class<?> forName(String clazz) { try { return Class.forName(clazz); } catch (ClassNotFoundException e) { e.printStackTrace(); } return Void.class; } public static String toJSONString(Object[] a) { if (a == null) return "null"; int iMax = a.length - 1; if (iMax == -1) return "[]"; StringBuilder b = new StringBuilder(); b.append('['); for (int i = 0; ; i++) { // b.append(String.valueOf(a[i])); Class<?> clazz = a[i].getClass(); System.out.println(clazz); if (!decisionSkipClassMap.containsKey(clazz)) { // 檢查類是否實(shí)現(xiàn)了每個(gè)接口 for (Class<?> interfaceClass : skipLogClassSet) { if (interfaceClass.isAssignableFrom(clazz)) { System.out.println("myObject 的類實(shí)現(xiàn)了 " + interfaceClass.getName() + " 接口"); decisionSkipClassMap.put(clazz, true); } else { System.out.println("myObject 的類沒(méi)有實(shí)現(xiàn) " + interfaceClass.getName() + " 接口"); if (decisionSkipClassMap.containsKey(clazz) && decisionSkipClassMap.get(clazz)) { //nothing System.out.println("myObject 的類沒(méi)有實(shí)現(xiàn) " + interfaceClass.getName() + " 接口 但是實(shí)現(xiàn)了其他忽略接口"); } else { decisionSkipClassMap.put(clazz, interfaceClass.isAssignableFrom(clazz)); } } } } if (!decisionSkipClassMap.get(clazz)) { b.append(JSON.toJSONString(a[i])); } if (i == iMax) return b.append(']').toString(); b.append(", "); } } public static class LoggingTransformer implements ClassFileTransformer { @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { // 忽略不需要處理的類 if (!className.startsWith("com/xdx/interfaces/facade")) { return null; } // Skip Spring CGLIB proxy classes if (className.contains("$$EnhancerBySpringCGLIB$$")) { return null; } // Skip Spring CGLIB FastClass proxy classes if (className.contains("$$FastClassBySpringCGLIB$$")) { return null; } try { String finalClassName = getFinalClassName(className.replace("/", ".")); ClassPool pool = ClassPool.getDefault(); pool.insertClassPath(new ClassClassPath(this.getClass())); CtClass ctClass = pool.get(finalClassName); // 獲取類的所有聲明字段 CtField[] fields = ctClass.getDeclaredFields(); String logger = null; // 打印字段的名稱和類型 for (CtField field : fields) { System.out.println("Field Name: " + field.getName() + ", Field Type: " + field.getType().getName()); if ("org.slf4j.Logger".equals(field.getType().getName())) { logger = field.getName(); } } for (CtMethod method : ctClass.getDeclaredMethods()) { try { addLogging(method, logger); } catch (Exception e) { System.err.println("Failed to instrument method: " + method.getName()); e.printStackTrace(); } } return ctClass.toBytecode(); } catch (NotFoundException e) { // Log exception and continue without instrumentation System.err.println("Class not found: " + className + " - " + e.getMessage()); } catch (Exception e) { e.printStackTrace(); } return classfileBuffer; } private String getFinalClassName(String className) { if (className.contains("$$EnhancerBySpringCGLIB$$") || className.contains("$$FastClassBySpringCGLIB$$")) { try { Class<?> proxyClass = Class.forName(className); Class<?> targetClass = AopProxyUtils.ultimateTargetClass(proxyClass); return targetClass.getName(); } catch (ClassNotFoundException e) { // Handle exception and return the original className e.printStackTrace(); } } return className; } private void addLogging(CtMethod method, String logger) throws CannotCompileException { if (Objects.isNull(logger)) { addLogging2(method); } else { addLogging1(method, logger); } } private void addLogging1(CtMethod method, String logger) throws CannotCompileException { // method.insertBefore("System.out.println(\"[ENTER] Method: " + method.getName() + " Arguments: \" + java.util.Arrays.toString($args));"); method.insertBefore(logger + ".info(\"[ENTER1] Method: " + method.getName() + " Arguments: \" +org.logging.LoggingAgent.toJSONString($args));"); // method.insertBefore("log.info(org.logging.LoggingAgent.toJSONString($args));"); method.insertAfter(logger + ".info(\"[EXIT1] Method: " + method.getName() + " Return: \" + $_);"); // method.insertBefore(logger + ".info(\"[EXIT] Method: " + method.getName() + " Return: \" + org.logging.LoggingAgent.toJSONString($_));"); } private void addLogging2(CtMethod method) throws CannotCompileException { method.insertBefore("org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(this.getClass());" + "logger.info(\"[ENTER2] Method: " + method.getName() + " Arguments: \" + org.logging.LoggingAgent.toJSONString($args));"); // method.insertBefore("org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(this.getClass());" + // "logger.info(\"[ENTER] Method: " + method.getName() + " Arguments: \" + java.util.Arrays.toString($args));"); method.insertAfter( "logger.info(\"[EXIT2] Method: " + method.getName() + " Return: \" + $_);", true);//src:表示插入的代碼,這是一段 Java 源代碼的 String。 // asFinally:這是一個(gè) boolean 值,決定了插入的代碼塊是在正常返回后執(zhí)行,還是在方法的正常返回和異常返回后都執(zhí)行。 // method.insertAfter("org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(this.getClass());" + // "logger.info(\"[EXIT] Method: " + method.getName() + " Return: \" + logger.info(org.logging.LoggingAgent.toJSONString($_)));", true); } private void addLogging3(CtMethod method) throws CannotCompileException { method.insertBefore("System.out.println(\"[ENTER] Method: " + method.getName() + " Arguments: \" + java.util.Arrays.toString($args));"); method.insertAfter("System.out.println(\"[EXIT] Method: " + method.getName() + " Return: \" + $_);"); } } }
3、打agent jar
4、創(chuàng)建一個(gè)demoWeb工程
-javaagent:D:\code\logging-agent\target\logging-agent-1.0-SNAPSHOT.jar
為了能調(diào)試需要增加jar
到此這篇關(guān)于利用Java Agent 做Spring MVC Controller 層的出參入?yún)⒋蛴∪罩镜奈恼戮徒榻B到這了,更多相關(guān)Spring MVC Controller 層出參入?yún)⒋蛴∪罩緝?nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Gradle修改本地倉(cāng)庫(kù)的位置方法實(shí)現(xiàn)
這篇文章主要介紹了Gradle修改本地倉(cāng)庫(kù)的位置方法實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07基于Java實(shí)現(xiàn)圖形驗(yàn)證碼工具類
這篇文章主要為大家詳細(xì)介紹了如何基于Java實(shí)現(xiàn)圖形驗(yàn)證碼工具類,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-11-11Java實(shí)戰(zhàn)小技巧之?dāng)?shù)組與list互轉(zhuǎn)
在Java中,經(jīng)常遇到需要List與數(shù)組互相轉(zhuǎn)換的場(chǎng)景,下面這篇文章主要給大家介紹了關(guān)于Java實(shí)戰(zhàn)小技巧之?dāng)?shù)組與list互轉(zhuǎn)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-08-08解決mybatisplus的分頁(yè)插件和條件構(gòu)造器自定義SQL遇到的BUG
這篇文章主要介紹了解決mybatisplus的分頁(yè)插件和條件構(gòu)造器自定義SQL遇到的BUG,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08Java通過(guò)接口實(shí)現(xiàn)匿名類的實(shí)例代碼
這篇文章介紹了Java通過(guò)接口實(shí)現(xiàn)匿名類的實(shí)例代碼,有需要的朋友可以參考一下2013-10-10java.text.DecimalFormat類十進(jìn)制格式化
這篇文章主要為大家詳細(xì)介紹了java.text.DecimalFormat類十進(jìn)制格式化的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03