欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java項(xiàng)目實(shí)現(xiàn)統(tǒng)一打印入?yún)⒊鰠⒌热罩?/h1>
 更新時(shí)間:2023年03月31日 09:52:58   作者:Yuhei001  
這篇文章主要介紹了java項(xiàng)目實(shí)現(xiàn)統(tǒng)一打印入?yún)⒊鰠⒌热罩痉绞剑哂泻芎玫膮⒖純r(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

1.背景   

SpringBoot項(xiàng)目中,之前都是在controller方法的第一行手動(dòng)打印 log,return之前再打印返回值。有多個(gè)返回點(diǎn)時(shí),就需要出現(xiàn)多少重復(fù)代碼,過多的非業(yè)務(wù)代碼顯得十分凌亂。  

本文將采用AOP 配置自定義注解實(shí)現(xiàn) 入?yún)ⅰ⒊鰠⒌娜罩敬蛴。ǚ椒ǖ娜雲(yún)⒑头祷刂刀疾捎?fastjson 序列化)。

2.設(shè)計(jì)思路    

將特定包下所有的controller生成代理類對象,并交由Spring容器管理,并重寫invoke方法進(jìn)行增強(qiáng)(入?yún)?、出參的打?.

3.核心代碼

3.1 自定義注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({InteractRecordBeanPostProcessor.class})
public @interface EnableInteractRecord {

? ? /**
? ? ?* app對應(yīng)controller包名
? ? ?*/
? ? String[] basePackages() default {};

? ? /**
? ? ?* 排除某些包
? ? ?*/
? ? String[] exclusions() default {};

}

3.2 實(shí)現(xiàn)BeanFactoryPostProcessor接口

作用:獲取EnableInteractRecord注解對象,用于獲取需要?jiǎng)?chuàng)建代理對象的包名,以及需要排除的包名

@Component
public class InteractRecordFactoryPostProcessor implements BeanFactoryPostProcessor {

? ? private static Logger logger = LoggerFactory.getLogger(InteractRecordFactoryPostProcessor.class);

? ? private EnableInteractRecord enableInteractRecord;

? ? @Override
? ? public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
? ? ? ? try {
? ? ? ? ? ? String[] names = beanFactory.getBeanNamesForAnnotation(EnableInteractRecord.class);
? ? ? ? ? ? for (String name : names) {
? ? ? ? ? ? ? ? enableInteractRecord = beanFactory.findAnnotationOnBean(name, EnableInteractRecord.class);
? ? ? ? ? ? ? ? logger.info("開啟交互記錄 ", enableInteractRecord);
? ? ? ? ? ? }
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? logger.error("postProcessBeanFactory() Exception ", e);
? ? ? ? }
? ? }

? ? public EnableInteractRecord getEnableInteractRecord() {
? ? ? ? return enableInteractRecord;
? ? }

}

3.3 實(shí)現(xiàn)MethodInterceptor編寫打印日志邏輯

作用:進(jìn)行入?yún)?、出參打印,包含是否打印邏?/p>

@Component
public class ControllerMethodInterceptor implements MethodInterceptor {
? ? private static Logger logger = LoggerFactory.getLogger(ControllerMethodInterceptor.class);
? ? // 請求開始時(shí)間
? ? ThreadLocal<Long> startTime = new ThreadLocal<>();
? ? private String localIp = "";

? ? @PostConstruct
? ? public void init() {
? ? ? ? try {
? ? ? ? ? ? localIp = InetAddress.getLocalHost().getHostAddress();
? ? ? ? } catch (UnknownHostException e) {
? ? ? ? ? ? logger.error("本地IP初始化失敗 : ", e);
? ? ? ? }
? ? }

? ? @Override
? ? public Object invoke(MethodInvocation invocation) {
? ? ? ? pre(invocation);
? ? ? ? Object result;
? ? ? ? try {
? ? ? ? ? ? result = invocation.proceed();
? ? ? ? ? ? post(invocation, result);
? ? ? ? ? ? return result;
? ? ? ? } catch (Throwable ex) {
? ? ? ? ? ? logger.error("controller 執(zhí)行異常: ", ex);
? ? ? ? ? ? error(invocation, ex);
? ? ? ? }

? ? ? ? return null;

? ? }

? ? public void error(MethodInvocation invocation, Throwable ex) {
? ? ? ? String msgText = ex.getMessage();
? ? ? ? logger.info(startTime.get() + " 異常,請求結(jié)束");
? ? ? ? logger.info("RESPONSE : " + msgText);
? ? ? ? logger.info("SPEND TIME : " + (System.currentTimeMillis() - startTime.get()));
? ? }

? ? private void pre(MethodInvocation invocation) {
? ? ? ? long now = System.currentTimeMillis();
? ? ? ? startTime.set(now);
? ? ? ? logger.info(now + " 請求開始");
? ? ? ? ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
? ? ? ? HttpServletRequest request = attributes.getRequest();

? ? ? ? logger.info("URL : " + request.getRequestURL().toString());
? ? ? ? logger.info("HTTP_METHOD : " + request.getMethod());
? ? ? ? logger.info("REMOTE_IP : " + getRemoteIp(request));
? ? ? ? logger.info("LOCAL_IP : " + localIp);
? ? ? ? logger.info("METHOD : " + request.getMethod());
? ? ? ? logger.info("CLASS_METHOD : " + getTargetClassName(invocation) + "." + invocation.getMethod().getName());

? ? ? ? // 獲取請求頭header參數(shù)
? ? ? ? Map<String, String> map = new HashMap<String, String>();
? ? ? ? Enumeration<String> headerNames = request.getHeaderNames();
? ? ? ? while (headerNames.hasMoreElements()) {
? ? ? ? ? ? String key = (String) headerNames.nextElement();
? ? ? ? ? ? String value = request.getHeader(key);
? ? ? ? ? ? map.put(key, value);
? ? ? ? }
? ? ? ? logger.info("HEADERS : " + JSONObject.toJSONString(map));
? ? ? ? Date createTime = new Date(now);
? ? ? ? // 請求報(bào)文
? ? ? ? Object[] args = invocation.getArguments();// 參數(shù)
? ? ? ? String msgText = "";
? ? ? ? Annotation[][] annotationss = invocation.getMethod().getParameterAnnotations();

? ? ? ? for (int i = 0; i < args.length; i++) {
? ? ? ? ? ? Object arg = args[i];
? ? ? ? ? ? if (!(arg instanceof ServletRequest)
? ? ? ? ? ? ? ? ? ? && !(arg instanceof ServletResponse)
? ? ? ? ? ? ? ? ? ? && !(arg instanceof Model)) {
? ? ? ? ? ? ? ? RequestParam rp = null;
? ? ? ? ? ? ? ? Annotation[] annotations = annotationss[i];
? ? ? ? ? ? ? ? for (Annotation annotation : annotations) {
? ? ? ? ? ? ? ? ? ? if (annotation instanceof RequestParam) {
? ? ? ? ? ? ? ? ? ? ? ? rp = (RequestParam) annotation;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if (msgText.equals("")) {
? ? ? ? ? ? ? ? ? ? msgText += (rp != null ? rp.value() + " = " : " ") + JSONObject.toJSONString(arg);
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? msgText += "," + (rp != null ? rp.value() + " = " : " ") + JSONObject.toJSONString(arg);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? logger.info("PARAMS : " + msgText);
? ? }

? ? private void post(MethodInvocation invocation, Object result) {
? ? ? ? logger.info(startTime.get() + " 請求結(jié)束");
? ? ? ? if (!(result instanceof ModelAndView)) {
? ? ? ? ? ? String msgText = JSONObject.toJSONString(result);
? ? ? ? ? ? logger.info("RESPONSE : " + msgText);
? ? ? ? }
? ? ? ? logger.info("SPEND TIME : " + (System.currentTimeMillis() - startTime.get()));

? ? }


? ? private String getRemoteIp(HttpServletRequest request) {
? ? ? ? String remoteIp = null;
? ? ? ? String remoteAddr = request.getRemoteAddr();
? ? ? ? String forwarded = request.getHeader("X-Forwarded-For");
? ? ? ? String realIp = request.getHeader("X-Real-IP");
? ? ? ? if (realIp == null) {
? ? ? ? ? ? if (forwarded == null) {
? ? ? ? ? ? ? ? remoteIp = remoteAddr;
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? remoteIp = remoteAddr + "/" + forwarded.split(",")[0];
? ? ? ? ? ? }
? ? ? ? } else {
? ? ? ? ? ? if (realIp.equals(forwarded)) {
? ? ? ? ? ? ? ? remoteIp = realIp;
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? if (forwarded != null) {
? ? ? ? ? ? ? ? ? ? forwarded = forwarded.split(",")[0];
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? remoteIp = realIp + "/" + forwarded;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return remoteIp;
? ? }

? ? private String getTargetClassName(MethodInvocation invocation) {
? ? ? ? String targetClassName = "";
? ? ? ? try {
? ? ? ? ? ? targetClassName = AopTargetUtils.getTarget(invocation.getThis()).getClass().getName();
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? targetClassName = invocation.getThis().getClass().getName();
? ? ? ? }
? ? ? ? return targetClassName;
? ? }

}

AopTargetUtils:

public class AopTargetUtils { ?
??
? ? ??
? ? /**?
? ? ?* 獲取 目標(biāo)對象?
? ? ?* @param proxy 代理對象?
? ? ?* @return ?
? ? ?* @throws Exception?
? ? ?*/ ?
? ? public static Object getTarget(Object proxy) throws Exception { ?
? ? ? ? ??
? ? ? ? if(!AopUtils.isAopProxy(proxy)) {
? ? ? ? ? ? return proxy;//不是代理對象 ?
? ? ? ? } ?
? ? ? ? ??
? ? ? ? if(AopUtils.isJdkDynamicProxy(proxy)) {
? ? ? ? ? ? return getJdkDynamicProxyTargetObject(proxy); ?
? ? ? ? } else { //cglib ?
? ? ? ? ? ? return getCglibProxyTargetObject(proxy); ?
? ? ? ? } ?
? ? ? ? ??
? ? ? ? ??
? ? ? ? ??
? ? } ?
??
??
? ? private static Object getCglibProxyTargetObject(Object proxy) throws Exception { ?
? ? ? ? Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0"); ?
? ? ? ? h.setAccessible(true);
? ? ? ? Object dynamicAdvisedInterceptor = h.get(proxy); ?
? ? ? ? ??
? ? ? ? Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised"); ?
? ? ? ? advised.setAccessible(true); ?
? ? ? ? ??
? ? ? ? Object target = ((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
? ? ? ? ??
? ? ? ? return getTarget(target);
? ? } ?
??
??
? ? private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception { ?
? ? ? ? Field h = proxy.getClass().getSuperclass().getDeclaredField("h"); ?
? ? ? ? h.setAccessible(true); ?
? ? ? ? AopProxy aopProxy = (AopProxy) h.get(proxy);
? ? ? ? ??
? ? ? ? Field advised = aopProxy.getClass().getDeclaredField("advised"); ?
? ? ? ? advised.setAccessible(true); ?
? ? ? ? ??
? ? ? ? Object target = ((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget();
? ? ? ? ??
? ? ? ? return getTarget(target);?
? ? } ?
? ? ??
}

3.4 實(shí)現(xiàn)BeanPostProcessor接口

作用:篩選出需要生成代理的類,并生成代理類,返回給Spring容器管理。

public class InteractRecordBeanPostProcessor implements BeanPostProcessor {

? ? private static Logger logger = LoggerFactory.getLogger(InteractRecordBeanPostProcessor.class);

? ? @Autowired
? ? private InteractRecordFactoryPostProcessor interactRecordFactoryPostProcessor;

? ? @Autowired
? ? private ControllerMethodInterceptor controllerMethodInterceptor;

? ? private String BASE_PACKAGES[];//需要攔截的包

? ? private String EXCLUDING[];// 過濾的包

? ? //一層目錄匹配
? ? private static final String ONE_REGEX = "[a-zA-Z0-9_]+";

? ? //多層目錄匹配
? ? private static final String ALL_REGEX = ".*";

? ? private static final String END_ALL_REGEX = "*";

? ? @PostConstruct
? ? public void init() {
? ? ? ? EnableInteractRecord ir = interactRecordFactoryPostProcessor.getEnableInteractRecord();
? ? ? ? BASE_PACKAGES = ir.basePackages();
? ? ? ? EXCLUDING = ir.exclusions();
? ? }

? ? @Override
? ? public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
? ? ? ? try {
? ? ? ? ? ? if (interactRecordFactoryPostProcessor.getEnableInteractRecord() != null) {
? ? ? ? ? ? ? ? // 根據(jù)注解配置的包名記錄對應(yīng)的controller層
? ? ? ? ? ? ? ? if (BASE_PACKAGES != null && BASE_PACKAGES.length > 0) {
? ? ? ? ? ? ? ? ? ? Object proxyObj = doEnhanceForController(bean);
? ? ? ? ? ? ? ? ? ? if (proxyObj != null) {
? ? ? ? ? ? ? ? ? ? ? ? return proxyObj;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? logger.error("postProcessAfterInitialization() Exception ", e);
? ? ? ? }
? ? ? ? return bean;
? ? }

? ? @Override
? ? public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
? ? ? ? return bean;
? ? }

? ? private Object doEnhanceForController(Object bean) {
? ? ? ? String beanPackageName = getBeanPackageName(bean);
? ? ? ? if (StringUtils.isNotBlank(beanPackageName)) {
? ? ? ? ? ? for (String basePackage : BASE_PACKAGES) {
? ? ? ? ? ? ? ? if (matchingPackage(basePackage, beanPackageName)) {
? ? ? ? ? ? ? ? ? ? if (EXCLUDING != null && EXCLUDING.length > 0) {
? ? ? ? ? ? ? ? ? ? ? ? for (String excluding : EXCLUDING) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? if (matchingPackage(excluding, beanPackageName)) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return bean;
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? Object target = null;
? ? ? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? ? ? target = AopTargetUtils.getTarget(bean);
? ? ? ? ? ? ? ? ? ? } catch (Exception e) {
? ? ? ? ? ? ? ? ? ? ? ? logger.error("AopTargetUtils.getTarget() exception", e);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? if (target != null) {
? ? ? ? ? ? ? ? ? ? ? ? boolean isController = target.getClass().isAnnotationPresent(Controller.class);
? ? ? ? ? ? ? ? ? ? ? ? boolean isRestController = target.getClass().isAnnotationPresent(RestController.class);
? ? ? ? ? ? ? ? ? ? ? ? if (isController || isRestController) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ProxyFactory proxy = new ProxyFactory();
? ? ? ? ? ? ? ? ? ? ? ? ? ? proxy.setTarget(bean);
? ? ? ? ? ? ? ? ? ? ? ? ? ? proxy.addAdvice(controllerMethodInterceptor);
? ? ? ? ? ? ? ? ? ? ? ? ? ? return proxy.getProxy();
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }

? ? ? ? }
? ? ? ? return null;
? ? }

? ? private static boolean matchingPackage(String basePackage, String currentPackage) {
? ? ? ? if (StringUtils.isEmpty(basePackage) || StringUtils.isEmpty(currentPackage)) {
? ? ? ? ? ? return false;
? ? ? ? }
? ? ? ? if (basePackage.indexOf("*") != -1) {
? ? ? ? ? ? String patterns[] = StringUtils.split(basePackage, ".");
? ? ? ? ? ? for (int i = 0; i < patterns.length; i++) {
? ? ? ? ? ? ? ? String patternNode = patterns[i];
? ? ? ? ? ? ? ? if (patternNode.equals("*")) {
? ? ? ? ? ? ? ? ? ? patterns[i] = ONE_REGEX;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if (patternNode.equals("**")) {
? ? ? ? ? ? ? ? ? ? if (i == patterns.length - 1) {
? ? ? ? ? ? ? ? ? ? ? ? patterns[i] = END_ALL_REGEX;
? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? patterns[i] = ALL_REGEX;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? String basePackageRegex = StringUtils.join(patterns, "\\.");
? ? ? ? ? ? Pattern r = Pattern.compile(basePackageRegex);
? ? ? ? ? ? Matcher m = r.matcher(currentPackage);
? ? ? ? ? ? return m.find();
? ? ? ? } else {
? ? ? ? ? ? return basePackage.equals(currentPackage);
? ? ? ? }
? ? }

? ? private String getBeanPackageName(Object bean) {
? ? ? ? String beanPackageName = "";
? ? ? ? if (bean != null) {
? ? ? ? ? ? Class<?> beanClass = bean.getClass();
? ? ? ? ? ? if (beanClass != null) {
? ? ? ? ? ? ? ? Package beanPackage = beanClass.getPackage();
? ? ? ? ? ? ? ? if (beanPackage != null) {
? ? ? ? ? ? ? ? ? ? beanPackageName = beanPackage.getName();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return beanPackageName;
? ? }

}

3.5 啟動(dòng)類配置注解

@EnableInteractRecord(basePackages = “com.test.test.controller”,exclusions = “com.test.demo.controller”)

以上即可實(shí)現(xiàn)入?yún)?、出參日志統(tǒng)一打印,并且可以將特定的controller集中管理,并不進(jìn)行日志的打印(及不進(jìn)生成代理類)。

4.出現(xiàn)的問題(及其解決辦法)

實(shí)際開發(fā)中,特定不需要打印日志的接口,無法統(tǒng)一到一個(gè)包下。大部分需要打印的接口,和不需要打印的接口,大概率會參雜在同一個(gè)controller中,根據(jù)以上設(shè)計(jì)思路,無法進(jìn)行區(qū)分。

解決辦法:

自定義排除入?yún)⒋蛴∽⒔?/p>

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExcludeReqLog {
}

自定義排除出參打印注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExcludeRespLog {
}

增加邏輯

// 1.在解析requestParam之前進(jìn)行判斷
?? ??? ?Method method = invocation.getMethod();
? ? ? ? Annotation[] declaredAnnotations = method.getDeclaredAnnotations();
? ? ? ? boolean flag = true;
? ? ? ? for (Annotation annotation : declaredAnnotations) {
? ? ? ? ? ? if (annotation instanceof ExcludeReqLog) {
? ? ? ? ? ? ? ? flag = false;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if (!flag) {
? ? ? ? ? ? logger.info("該方法已排除,不打印入?yún)?);
? ? ? ? ? ? return;
? ? ? ? }
// 2.在解析requestResp之前進(jìn)行判斷
?? ??? ?Method method = invocation.getMethod();
? ? ? ? Annotation[] declaredAnnotations = method.getDeclaredAnnotations();
? ? ? ? boolean flag = true;
? ? ? ? for (Annotation annotation : declaredAnnotations) {
? ? ? ? ? ? if (annotation instanceof ExcludeRespLog) {
? ? ? ? ? ? ? ? flag = false;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if (!flag) {
? ? ? ? ? ? logger.info("該方法已排除,不打印出參");
? ? ? ? ? ? return;
? ? ? ? }

使用方法

// 1.不打印入?yún)?
? ? @PostMapping("/uploadImg")
? ? @ExcludeReqLog
? ? public Result<List<Demo>> uploadIdeaImg(@RequestParam(value = "imgFile", required = false) MultipartFile[] imgFile) {
? ? ? ? return demoService.uploadIdeaImg(imgFile);
? ? }
//2.不打印出參
? ? @PostMapping("/uploadImg")
? ? @ExcludeRespLog?
? ? public Result<List<Demo>> uploadIdeaImg(@RequestParam(value = "imgFile", required = false) MultipartFile[] imgFile) {
? ? ? ? return demoService.uploadIdeaImg(imgFile);
? ? }

問題解決

5.總結(jié)

以上即可兼容包排除和注解排除兩種方式,進(jìn)行入?yún)?、出參統(tǒng)一打印的控制。除此之外,還可以根據(jù)需求,進(jìn)行其他增強(qiáng)。

這些僅為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • spring+html5實(shí)現(xiàn)安全傳輸隨機(jī)數(shù)字密碼鍵盤

    spring+html5實(shí)現(xiàn)安全傳輸隨機(jī)數(shù)字密碼鍵盤

    這篇文章主要為大家詳細(xì)介紹了spring html5實(shí)現(xiàn)安全傳輸隨機(jī)數(shù)字密碼鍵盤,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • java貪心算法初學(xué)感悟圖解及示例分享

    java貪心算法初學(xué)感悟圖解及示例分享

    這篇文章主要為大家介紹了本人在初學(xué)java貪心算法的感悟,并通過圖解及示例代碼的方式分享給大家,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2021-11-11
  • Java基礎(chǔ)之垃圾回收機(jī)制詳解

    Java基礎(chǔ)之垃圾回收機(jī)制詳解

    這篇文章主要介紹了Java基礎(chǔ)之垃圾回收機(jī)制詳解,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • 源碼解析Java類加載器

    源碼解析Java類加載器

    這篇文章主要給大家介紹了Java類加載器源碼解析的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Java實(shí)現(xiàn)簡單樹結(jié)構(gòu)

    Java實(shí)現(xiàn)簡單樹結(jié)構(gòu)

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)簡單樹結(jié)構(gòu)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • RocketMQ事務(wù)消息機(jī)制詳解

    RocketMQ事務(wù)消息機(jī)制詳解

    這篇文章主要介紹了RocketMQ事務(wù)消息機(jī)制詳解,RocketMQ服務(wù)端將消息持久化之后,向發(fā)送方返回Ack確認(rèn)消息已經(jīng)發(fā)送成功,由于消息為半事務(wù)消息,在未收到生產(chǎn)者對該消息的二次確認(rèn)前,此消息被標(biāo)記成"暫不能投遞"狀態(tài),需要的朋友可以參考下
    2024-01-01
  • Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(60)

    Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(60)

    下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望可以幫到你
    2021-08-08
  • java如何實(shí)現(xiàn)嵌套對象轉(zhuǎn)大map(扁平化)

    java如何實(shí)現(xiàn)嵌套對象轉(zhuǎn)大map(扁平化)

    這篇文章主要介紹了java如何實(shí)現(xiàn)嵌套對象轉(zhuǎn)大map(扁平化),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • Spring DevTools的介紹

    Spring DevTools的介紹

    今天小編就為大家分享一篇關(guān)于Spring DevTools的介紹,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • Javaweb中使用Jdom解析xml的方法

    Javaweb中使用Jdom解析xml的方法

    Jdom是一個(gè)開源項(xiàng)目,基于樹形結(jié)構(gòu),利用純java的技術(shù)對XML文檔實(shí)現(xiàn)解析,生成,序列化以及多種操作.這篇文章主要介紹了Javaweb中使用Jdom解析xml的方法的相關(guān)資料,需要的朋友可以參考下
    2016-09-09

最新評論