Java增加自定義注解進(jìn)行校驗(yàn)入?yún)⒃斀?/h1>
更新時(shí)間:2023年04月13日 09:46:45 作者:奔跑的毛球
這篇文章主要為大家詳細(xì)介紹了Java如何通過(guò)增加自定義注解實(shí)現(xiàn)校驗(yàn)入?yún)⒐δ?,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下
背景
客戶使用我們系統(tǒng)的時(shí)候,查詢不帶任何查詢條件,查詢就返回全部數(shù)據(jù),500多萬(wàn)條數(shù)據(jù)啊,然后直接導(dǎo)出,數(shù)據(jù)量龐大,接口超時(shí),這可苦了我們這些開(kāi)發(fā)人員,一邊優(yōu)化,一邊挨噴。這么多數(shù)據(jù)就算導(dǎo)成功了,Excel也打不開(kāi)呀。迫不得已,決定強(qiáng)制讓客戶至少傳入一個(gè)參數(shù)進(jìn)行查詢來(lái)緩解服務(wù)器以及開(kāi)發(fā)人員的壓力。
首先想到的,最簡(jiǎn)單的,就是增加一個(gè)靜態(tài)方法,在每個(gè)方法入口調(diào)一下,來(lái)校驗(yàn)以及拋出錯(cuò)誤。但是轉(zhuǎn)念一想,更優(yōu)美的解決方案是在調(diào)用的方法上加一個(gè)注解,使用注解來(lái)完成這個(gè)功能,這豈不是很棒。
再一句話說(shuō)下需求:
增加注解對(duì)入?yún)⑦M(jìn)行校驗(yàn),保證至少有一個(gè)參數(shù)不為空,若是有時(shí)間參數(shù),則起始時(shí)間和結(jié)束時(shí)間之間的距離不能超過(guò)30天。
接下來(lái),Show Time
注解類
這里有三個(gè)參數(shù),分別是三個(gè)參數(shù)名稱,起始時(shí)間參數(shù)名稱,結(jié)束時(shí)間參數(shù)名稱,需要校驗(yàn)的參數(shù)名稱
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface VerifyParameters {
/**
* 起始時(shí)間參數(shù)名稱
*/
String startTimeParamName() default "startTime";
/**
* 結(jié)束時(shí)間參數(shù)名稱
*/
String endTimeParamName() default "endTime";
/**
* 需要校驗(yàn)的參數(shù)名稱
*/
String paramName() default "";
}
注解的Aspect類
這里貼一個(gè)完整的,目的是有的小伙伴想用的話,貼過(guò)去就能用。
@Component
@Aspect
public class VerifyParametersAspect {
private static final Logger logger = LoggerFactory.getLogger(VerifyParametersAspect.class);
/**
* 切點(diǎn)
*/
@Pointcut("@annotation(com.guava.mall.app.annotation.VerifyParameters)")
public void serviceAspect() {
}
/**
* service 方法前調(diào)用
*
* @param joinPoint
*/
@Before("serviceAspect()")
public void doBeforeService(JoinPoint joinPoint) {
try {
//獲取方法參數(shù)名
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//獲取方法
Method method = signature.getMethod();
//獲取參數(shù)名
LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
String[] parameterNames = u.getParameterNames(method);
Map<String, Object> params = new HashMap<>(8);
params = getParamMap(joinPoint, method, parameterNames, params);
//獲取注解
VerifyParameters verifyParameters = method.getAnnotation(VerifyParameters.class);
//參數(shù)名
String paramName = verifyParameters.paramName();
Object o = params.get(paramName);
ValidationUtils.validate(o == null, "參數(shù)不能為空");
ValidationUtils.validate(!atLeastOnePropertyNotNull(o), "請(qǐng)至少輸入一個(gè)查詢條件進(jìn)行查詢和導(dǎo)出");
//開(kāi)始時(shí)間和結(jié)束時(shí)間的參數(shù)名
String s = verifyParameters.startTimeParamName();
String e = verifyParameters.endTimeParamName();
Map<?, ?> map = JSONUtils.bean2Map(o);
Object startTime = map.get(s);
Object endTime = map.get(e);
if (startTime != null || endTime != null) {
ValidationUtils.validate(startTime == null || endTime == null, "開(kāi)始時(shí)間和結(jié)束時(shí)間必須同時(shí)存在");
ValidationUtils.validate(Integer.parseInt(String.valueOf(endTime)) - Integer.parseInt(String.valueOf(startTime)) > 30 * 24 * 60 * 60, "時(shí)間間隔不能超過(guò)一個(gè)月");
}
} catch (NumberFormatException ex) {
logger.error(ex.getMessage(), ex);
}
}
private Map<String, Object> getParamMap(JoinPoint joinPoint, Method method, String[] parameterNames, Map<String, Object> params) {
int i = 0;
if (parameterNames != null && parameterNames.length > 0) {
for (String parameterName : parameterNames) {
params.put(parameterName, joinPoint.getArgs()[i]);
i++;
}
}
return params;
}
public static boolean atLeastOnePropertyNotNull(Object obj) {
for (Field field : obj.getClass().getDeclaredFields()) {
//忽略serialVersionUID
if ("serialVersionUID".equals(field.getName())) {
continue;
}
field.setAccessible(true);
try {
if (field.get(obj) != null && !field.get(obj).toString().isEmpty()) {
return true;
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return false;
}
/**
* 方法后調(diào)用
*/
@After("serviceAspect()")
public void doAfterInService(JoinPoint joinPoint) {
}
}
然后,解釋一下
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
這是我們的第一行代碼,這里的joinPoint對(duì)象表示應(yīng)用建議的程序執(zhí)行點(diǎn),getSignature()方法則會(huì)返回正在執(zhí)行的方法的方法簽名,簽名里就包含了該方法名稱、返回類型和參數(shù)類型。然后再?gòu)?qiáng)制轉(zhuǎn)換成MethodSignature
對(duì)象,便于訪問(wèn)方法相關(guān)的信息。
MethodSignature是一個(gè)對(duì)象,它表示正在執(zhí)行的方法的簽名,包括方法名稱、返回類型和參數(shù)類型。它是Spring AOP框架中的一個(gè)類,用于在切面中獲取方法的信息。
Method method = signature.getMethod();獲取方法
這個(gè)則是從MethodSignature中獲取到了正在執(zhí)行的方法信息。
LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
LocalVariableTableParameterNameDiscoverer是一個(gè)類,它可以用于在運(yùn)行時(shí)獲取方法參數(shù)的名稱。它是Spring框架中的一個(gè)類,通常與反射一起使用,以便在運(yùn)行時(shí)獲取有關(guān)方法參數(shù)的信息。
通過(guò) String[] parameterNames = u.getParameterNames(method);
可以獲取到目前方法的入?yún)⒚Q。
getParamMap();
方法則會(huì)返回一個(gè)key是參數(shù)名稱,value是參數(shù)本身的map對(duì)象。 我們可以從中取出我們需要的那個(gè)參數(shù)對(duì)象。
VerifyParameters verifyParameters = method.getAnnotation(VerifyParameters.class);
上邊這行代碼則會(huì)獲取到方法上注解的注解對(duì)象本身,和我們傳入的參數(shù)值,因?yàn)槊總€(gè)方法的入?yún)⒉槐M相同,里邊時(shí)間的字段也不盡相同,需要主動(dòng)傳入來(lái)做處理。
這里再解釋下atLeastOnePropertyNotNull()
方法,這個(gè)方法的作用是判斷參數(shù)內(nèi)的屬性是否至少有一個(gè)不為空,這里我們忽略了serialVersionUID
。
serialVersionUID是Java中的一個(gè)序列化機(jī)制,用于在反序列化期間驗(yàn)證發(fā)送方和接收方的對(duì)象是否具有兼容的序列化版本。如果發(fā)送方和接收方的serialVersionUID不同,則反序列化將失敗。如果未指定serialVersionUID,則Java運(yùn)行時(shí)將根據(jù)類的特定方面自動(dòng)生成它。
之后的方法就很簡(jiǎn)單了,拿出值根據(jù)我們的需要做處理即可
controller
再看看是如何使用的吧,添加@VerifyParameters
注解,傳入時(shí)間的屬性名稱,和需要校驗(yàn)的參數(shù)名稱,這里傳入?yún)?shù)名稱的原因是,可能和我這里一樣還有其他的參數(shù)影響,而我們只想校驗(yàn)我們需要的參數(shù)。
@ApiOperation(value = "查詢列表")
@GetMapping("/test")
@VerifyParameters(startTimeParamName = "beginTime", endTimeParamName = "endTime",paramName = "orderRequest")
public Page<Map<String, Object>> findOrderTestList(Pageable pageable, ERPOrderRequest orderRequest) {
log.info("模擬邏輯處理");
return null;
}
這樣我們就實(shí)現(xiàn)了通過(guò)一個(gè)自定義注解對(duì)方法的入?yún)⑦M(jìn)行了校驗(yàn),在取到入?yún)⒑头椒ǖ母鱾€(gè)值之后,我們其實(shí)可以做各種各樣的操作,各位小伙伴可以任意發(fā)揮。
到此這篇關(guān)于Java增加自定義注解進(jìn)行校驗(yàn)入?yún)⒃斀獾奈恼戮徒榻B到這了,更多相關(guān)Java自定義注解校驗(yàn)入?yún)?nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
-
SpringBoot+Mybatis+Vue 實(shí)現(xiàn)商品模塊的crud操作
這篇文章主要介紹了SpringBoot+Mybatis+Vue 實(shí)現(xiàn)商品模塊的crud操作,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧 2020-10-10
-
基于Java實(shí)現(xiàn)經(jīng)典蜘蛛紙牌游戲
《蜘蛛紙牌》(Ancient?Spider)?是由Oberon?Games開(kāi)發(fā)的一款休閑益智類游戲。本文將利用Java語(yǔ)言實(shí)現(xiàn)這一經(jīng)典游戲,需要的可以參考一下 2022-05-05
-
MyBatis-Flex實(shí)現(xiàn)分頁(yè)查詢的示例代碼
在MyBatis-Flex中實(shí)現(xiàn)分頁(yè)查詢時(shí),需要注意維護(hù)一個(gè)獲取數(shù)據(jù)庫(kù)總數(shù)的方法,詳細(xì)介紹了UserService、UserServiceImpl類以及Mapper.xml配置,感興趣的可以了解一下 2024-10-10
-
SpringBoot獲取不到用戶真實(shí)IP的解決方法
最近遇到個(gè)問(wèn)題,項(xiàng)目部署后發(fā)現(xiàn)服務(wù)端無(wú)法獲取到客戶端真實(shí)的IP地址,本文就來(lái)介紹一下這個(gè)問(wèn)題的解決方法,感興趣的可以了解一下 2023-08-08
-
SpringBoot使用@PostConstruct注解導(dǎo)入配置方式
這篇文章主要介紹了SpringBoot使用@PostConstruct注解導(dǎo)入配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教 2021-11-11
-
使用java代碼實(shí)現(xiàn)保留小數(shù)點(diǎn)的位數(shù)
因?yàn)閭€(gè)人應(yīng)用的需要,所以就寫(xiě)個(gè)簡(jiǎn)單點(diǎn)的了。希望大家都給給建議,共同學(xué)習(xí)。需要的朋友也可以參考下
2013-07-07
-
java出現(xiàn)no XXX in java.library.path的解決及eclipse配
這篇文章主要介紹了java出現(xiàn)no XXX in java.library.path的解決及eclipse配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教 2023-12-12
-
Spring引入外部屬性文件配置數(shù)據(jù)庫(kù)連接的步驟詳解
這篇文章主要介紹了Spring引入外部屬性文件配置數(shù)據(jù)庫(kù)連接的步驟詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下 2021-01-01
-
Spring Bean Scope 有狀態(tài)的Bean與無(wú)狀態(tài)的Bean
這篇文章主要介紹了Spring Bean Scope 有狀態(tài)的Bean與無(wú)狀態(tài)的Bean,每個(gè)用戶有自己特有的一個(gè)實(shí)例,在用戶的生存期內(nèi),bean保持了用戶的信息,下面來(lái)了解有狀態(tài)和無(wú)狀態(tài)的區(qū)別吧 2022-01-01
最新評(píng)論
背景
客戶使用我們系統(tǒng)的時(shí)候,查詢不帶任何查詢條件,查詢就返回全部數(shù)據(jù),500多萬(wàn)條數(shù)據(jù)啊,然后直接導(dǎo)出,數(shù)據(jù)量龐大,接口超時(shí),這可苦了我們這些開(kāi)發(fā)人員,一邊優(yōu)化,一邊挨噴。這么多數(shù)據(jù)就算導(dǎo)成功了,Excel也打不開(kāi)呀。迫不得已,決定強(qiáng)制讓客戶至少傳入一個(gè)參數(shù)進(jìn)行查詢來(lái)緩解服務(wù)器以及開(kāi)發(fā)人員的壓力。
首先想到的,最簡(jiǎn)單的,就是增加一個(gè)靜態(tài)方法,在每個(gè)方法入口調(diào)一下,來(lái)校驗(yàn)以及拋出錯(cuò)誤。但是轉(zhuǎn)念一想,更優(yōu)美的解決方案是在調(diào)用的方法上加一個(gè)注解,使用注解來(lái)完成這個(gè)功能,這豈不是很棒。
再一句話說(shuō)下需求:
增加注解對(duì)入?yún)⑦M(jìn)行校驗(yàn),保證至少有一個(gè)參數(shù)不為空,若是有時(shí)間參數(shù),則起始時(shí)間和結(jié)束時(shí)間之間的距離不能超過(guò)30天。
接下來(lái),Show Time
注解類
這里有三個(gè)參數(shù),分別是三個(gè)參數(shù)名稱,起始時(shí)間參數(shù)名稱,結(jié)束時(shí)間參數(shù)名稱,需要校驗(yàn)的參數(shù)名稱
@Target({ElementType.PARAMETER, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface VerifyParameters { /** * 起始時(shí)間參數(shù)名稱 */ String startTimeParamName() default "startTime"; /** * 結(jié)束時(shí)間參數(shù)名稱 */ String endTimeParamName() default "endTime"; /** * 需要校驗(yàn)的參數(shù)名稱 */ String paramName() default ""; }
注解的Aspect類
這里貼一個(gè)完整的,目的是有的小伙伴想用的話,貼過(guò)去就能用。
@Component @Aspect public class VerifyParametersAspect { private static final Logger logger = LoggerFactory.getLogger(VerifyParametersAspect.class); /** * 切點(diǎn) */ @Pointcut("@annotation(com.guava.mall.app.annotation.VerifyParameters)") public void serviceAspect() { } /** * service 方法前調(diào)用 * * @param joinPoint */ @Before("serviceAspect()") public void doBeforeService(JoinPoint joinPoint) { try { //獲取方法參數(shù)名 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); //獲取方法 Method method = signature.getMethod(); //獲取參數(shù)名 LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer(); String[] parameterNames = u.getParameterNames(method); Map<String, Object> params = new HashMap<>(8); params = getParamMap(joinPoint, method, parameterNames, params); //獲取注解 VerifyParameters verifyParameters = method.getAnnotation(VerifyParameters.class); //參數(shù)名 String paramName = verifyParameters.paramName(); Object o = params.get(paramName); ValidationUtils.validate(o == null, "參數(shù)不能為空"); ValidationUtils.validate(!atLeastOnePropertyNotNull(o), "請(qǐng)至少輸入一個(gè)查詢條件進(jìn)行查詢和導(dǎo)出"); //開(kāi)始時(shí)間和結(jié)束時(shí)間的參數(shù)名 String s = verifyParameters.startTimeParamName(); String e = verifyParameters.endTimeParamName(); Map<?, ?> map = JSONUtils.bean2Map(o); Object startTime = map.get(s); Object endTime = map.get(e); if (startTime != null || endTime != null) { ValidationUtils.validate(startTime == null || endTime == null, "開(kāi)始時(shí)間和結(jié)束時(shí)間必須同時(shí)存在"); ValidationUtils.validate(Integer.parseInt(String.valueOf(endTime)) - Integer.parseInt(String.valueOf(startTime)) > 30 * 24 * 60 * 60, "時(shí)間間隔不能超過(guò)一個(gè)月"); } } catch (NumberFormatException ex) { logger.error(ex.getMessage(), ex); } } private Map<String, Object> getParamMap(JoinPoint joinPoint, Method method, String[] parameterNames, Map<String, Object> params) { int i = 0; if (parameterNames != null && parameterNames.length > 0) { for (String parameterName : parameterNames) { params.put(parameterName, joinPoint.getArgs()[i]); i++; } } return params; } public static boolean atLeastOnePropertyNotNull(Object obj) { for (Field field : obj.getClass().getDeclaredFields()) { //忽略serialVersionUID if ("serialVersionUID".equals(field.getName())) { continue; } field.setAccessible(true); try { if (field.get(obj) != null && !field.get(obj).toString().isEmpty()) { return true; } } catch (IllegalAccessException e) { e.printStackTrace(); } } return false; } /** * 方法后調(diào)用 */ @After("serviceAspect()") public void doAfterInService(JoinPoint joinPoint) { } }
然后,解釋一下
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
這是我們的第一行代碼,這里的joinPoint對(duì)象表示應(yīng)用建議的程序執(zhí)行點(diǎn),getSignature()方法則會(huì)返回正在執(zhí)行的方法的方法簽名,簽名里就包含了該方法名稱、返回類型和參數(shù)類型。然后再?gòu)?qiáng)制轉(zhuǎn)換成MethodSignature
對(duì)象,便于訪問(wèn)方法相關(guān)的信息。
MethodSignature是一個(gè)對(duì)象,它表示正在執(zhí)行的方法的簽名,包括方法名稱、返回類型和參數(shù)類型。它是Spring AOP框架中的一個(gè)類,用于在切面中獲取方法的信息。
Method method = signature.getMethod();獲取方法
這個(gè)則是從MethodSignature中獲取到了正在執(zhí)行的方法信息。
LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
LocalVariableTableParameterNameDiscoverer是一個(gè)類,它可以用于在運(yùn)行時(shí)獲取方法參數(shù)的名稱。它是Spring框架中的一個(gè)類,通常與反射一起使用,以便在運(yùn)行時(shí)獲取有關(guān)方法參數(shù)的信息。
通過(guò) String[] parameterNames = u.getParameterNames(method);
可以獲取到目前方法的入?yún)⒚Q。
getParamMap();
方法則會(huì)返回一個(gè)key是參數(shù)名稱,value是參數(shù)本身的map對(duì)象。 我們可以從中取出我們需要的那個(gè)參數(shù)對(duì)象。
VerifyParameters verifyParameters = method.getAnnotation(VerifyParameters.class);
上邊這行代碼則會(huì)獲取到方法上注解的注解對(duì)象本身,和我們傳入的參數(shù)值,因?yàn)槊總€(gè)方法的入?yún)⒉槐M相同,里邊時(shí)間的字段也不盡相同,需要主動(dòng)傳入來(lái)做處理。
這里再解釋下atLeastOnePropertyNotNull()
方法,這個(gè)方法的作用是判斷參數(shù)內(nèi)的屬性是否至少有一個(gè)不為空,這里我們忽略了serialVersionUID
。
serialVersionUID是Java中的一個(gè)序列化機(jī)制,用于在反序列化期間驗(yàn)證發(fā)送方和接收方的對(duì)象是否具有兼容的序列化版本。如果發(fā)送方和接收方的serialVersionUID不同,則反序列化將失敗。如果未指定serialVersionUID,則Java運(yùn)行時(shí)將根據(jù)類的特定方面自動(dòng)生成它。
之后的方法就很簡(jiǎn)單了,拿出值根據(jù)我們的需要做處理即可
controller
再看看是如何使用的吧,添加@VerifyParameters
注解,傳入時(shí)間的屬性名稱,和需要校驗(yàn)的參數(shù)名稱,這里傳入?yún)?shù)名稱的原因是,可能和我這里一樣還有其他的參數(shù)影響,而我們只想校驗(yàn)我們需要的參數(shù)。
@ApiOperation(value = "查詢列表") @GetMapping("/test") @VerifyParameters(startTimeParamName = "beginTime", endTimeParamName = "endTime",paramName = "orderRequest") public Page<Map<String, Object>> findOrderTestList(Pageable pageable, ERPOrderRequest orderRequest) { log.info("模擬邏輯處理"); return null; }
這樣我們就實(shí)現(xiàn)了通過(guò)一個(gè)自定義注解對(duì)方法的入?yún)⑦M(jìn)行了校驗(yàn),在取到入?yún)⒑头椒ǖ母鱾€(gè)值之后,我們其實(shí)可以做各種各樣的操作,各位小伙伴可以任意發(fā)揮。
到此這篇關(guān)于Java增加自定義注解進(jìn)行校驗(yàn)入?yún)⒃斀獾奈恼戮徒榻B到這了,更多相關(guān)Java自定義注解校驗(yàn)入?yún)?nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot+Mybatis+Vue 實(shí)現(xiàn)商品模塊的crud操作
這篇文章主要介紹了SpringBoot+Mybatis+Vue 實(shí)現(xiàn)商品模塊的crud操作,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10基于Java實(shí)現(xiàn)經(jīng)典蜘蛛紙牌游戲
《蜘蛛紙牌》(Ancient?Spider)?是由Oberon?Games開(kāi)發(fā)的一款休閑益智類游戲。本文將利用Java語(yǔ)言實(shí)現(xiàn)這一經(jīng)典游戲,需要的可以參考一下2022-05-05MyBatis-Flex實(shí)現(xiàn)分頁(yè)查詢的示例代碼
在MyBatis-Flex中實(shí)現(xiàn)分頁(yè)查詢時(shí),需要注意維護(hù)一個(gè)獲取數(shù)據(jù)庫(kù)總數(shù)的方法,詳細(xì)介紹了UserService、UserServiceImpl類以及Mapper.xml配置,感興趣的可以了解一下2024-10-10SpringBoot獲取不到用戶真實(shí)IP的解決方法
最近遇到個(gè)問(wèn)題,項(xiàng)目部署后發(fā)現(xiàn)服務(wù)端無(wú)法獲取到客戶端真實(shí)的IP地址,本文就來(lái)介紹一下這個(gè)問(wèn)題的解決方法,感興趣的可以了解一下2023-08-08SpringBoot使用@PostConstruct注解導(dǎo)入配置方式
這篇文章主要介紹了SpringBoot使用@PostConstruct注解導(dǎo)入配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11使用java代碼實(shí)現(xiàn)保留小數(shù)點(diǎn)的位數(shù)
因?yàn)閭€(gè)人應(yīng)用的需要,所以就寫(xiě)個(gè)簡(jiǎn)單點(diǎn)的了。希望大家都給給建議,共同學(xué)習(xí)。需要的朋友也可以參考下2013-07-07java出現(xiàn)no XXX in java.library.path的解決及eclipse配
這篇文章主要介紹了java出現(xiàn)no XXX in java.library.path的解決及eclipse配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12Spring引入外部屬性文件配置數(shù)據(jù)庫(kù)連接的步驟詳解
這篇文章主要介紹了Spring引入外部屬性文件配置數(shù)據(jù)庫(kù)連接的步驟詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01Spring Bean Scope 有狀態(tài)的Bean與無(wú)狀態(tài)的Bean
這篇文章主要介紹了Spring Bean Scope 有狀態(tài)的Bean與無(wú)狀態(tài)的Bean,每個(gè)用戶有自己特有的一個(gè)實(shí)例,在用戶的生存期內(nèi),bean保持了用戶的信息,下面來(lái)了解有狀態(tài)和無(wú)狀態(tài)的區(qū)別吧2022-01-01