首页 > 其他分享 >基于若依框架进行TestNG接口自动化框架搭建(二)

基于若依框架进行TestNG接口自动化框架搭建(二)

时间:2025-01-17 14:32:06浏览次数:3  
标签:return String 框架 TestNG 若依 import null config response

目录

一.前言

二. 引入TestNg

三. 创建接口自动化目录结构

三. 引入okhttp3

四. 开始编写第一条接口用例


一.前言

        在上一章节跟着操作把代码成功运行起来,就可以跟着本章节进行接口自动化代码编写,接口自动化使用的测试框架是TestNG,大家跟着我的步骤一步步往下操作即可(* ̄︶ ̄)

二. 引入TestNg

  • 点击hima-admin,进入pom.xml,引入TestNg依赖
    <!-- 接口自动化测试相关-->
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>7.4.0</version>
<!--            <scope>test</scope>-->
        </dependency>

三. 创建接口自动化目录结构

  • 引入成功后,我们创建相关的目录结构,开始编写接口自动化代码。

       下方图片是我创建的接口自动化相关目录结构:

       注意: 大家也可根据自己业务要求进行分层,整体思路就是用例、逻辑和数据要分离,不要写在一起。

        hima-admin下方创建testng软件包,后期所有接口用例均在testng软件包下方维护

        testcas文件夹: 里边写的文件用于编写接口用例

        data文件夹:      里边写的文件用于存放用例所需的数据,实现代码和数据分离

        utils文件夹:       用于存放各种自己编写的工具类

        config文件夹:  用于存放一些基本配置

        common文件夹: 用于存放通用类(暂时没有用到)

下方图片是目录结构详细版本

三. 引入okhttp3

到这一步了,想要开始编写代码了,但是怎么写,不知道如何下手,先别着急,我们先理理,平时大家在测试接口是怎么测得呢? 以postman为例子:

1. 登录接口地址是什么(url)

2. 请求方式是什么

3. 入参具体有哪些

4. 点击发送进行接口请求

5. 接口返回对应状态码和message

代码实现是一样的道理,那我们用什么才能够把对应的数据进行发送,并且数据要组装成什么样的类型呢,才会像postman一样,点击发送后给出对应的返回信息,这时我们需要引入okhttp3,,okhttp3是一个请求网络工具,想要详细了解,大家自行百度即可。

  •  在hima-admin下的pom.xml文件添加okhttps依赖
<dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
  </dependency>
在com.hima.testng.utils下,直接把下方对应的HttpClientUtils代码放入,这个工具类我也是直接在网上copy下来,删除或者修改了一小部分代码,直接使用的。
package com.hima.testng.utils;

import cn.hutool.core.lang.func.Supplier2;
import cn.hutool.json.JSONUtil;
import com.hima.testng.config.HttpClientConfig;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.*;
import java.io.IOException;
import java.math.BigInteger;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import static okhttp3.ConnectionSpec.CLEARTEXT;

/**
 * @version 1.0
 * @Author:张爱婷
 * @Package:com.hima.common.utils
 * @Date:2024/12/19 下午4:22
 */
public class HttpClientUtils {
    private static final Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);
    private static final Map<String, OkHttpClient> map_clients = new ConcurrentHashMap<>();
    private static OkHttpClient okHttpClient2;

    private HttpClientUtils() {
    }

    /**
     * 饿汉式单例
     */
    private static OkHttpClient getInstance(final HttpClientConfig config) {
        if (map_clients.containsKey(md5Key(config))) {
            return map_clients.get(md5Key(config));
        }
        OkHttpClient okHttpClient = createHttpClient(config);
        map_clients.put(md5Key(config), okHttpClient);
        return okHttpClient;
    }

    /**
     * 懒汉式单例
     */
    private static OkHttpClient getOkHttpClient(HttpClientConfig config) {
        if (okHttpClient2 == null) {
            okHttpClient2 = createHttpClient(config);
        }
        return okHttpClient2;
    }

    private static String md5Key(HttpClientConfig config) {
        return getMD5InHex(config.getMasterUrl() + "/" + config.getUsername() + "/" + config.getPassword() + "/");
    }

    private static String getMD5InHex(String data) {
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.update(data.getBytes());
            byte[] result = messageDigest.digest();
            return new BigInteger(1, result).toString(16);
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }

    private static OkHttpClient createHttpClient(final HttpClientConfig config) {
        try {
            OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();

            // Follow any redirects
            httpClientBuilder.followRedirects(true);
            httpClientBuilder.followSslRedirects(true);

            if (config.isTrustCerts()) {
                httpClientBuilder.hostnameVerifier((s, sslSession) -> true);
            }

            TrustManager[] trustManagers = buildTrustManagers();
            httpClientBuilder.sslSocketFactory(createSSLSocketFactory(trustManagers), (X509TrustManager) trustManagers[0]);

            if (config.getConnectionTimeout() > 0) {
                httpClientBuilder.connectTimeout(config.getConnectionTimeout(), TimeUnit.MILLISECONDS);
            }

            if (config.getRequestTimeout() > 0) {
                httpClientBuilder.readTimeout(config.getRequestTimeout(), TimeUnit.MILLISECONDS);
            }

            if (config.getWebsocketPingInterval() > 0) {
                httpClientBuilder.pingInterval(config.getWebsocketPingInterval(), TimeUnit.MILLISECONDS);
            }

            if (config.getMaxConcurrentRequestsPerHost() > 0) {
                Dispatcher dispatcher = new Dispatcher();
                dispatcher.setMaxRequestsPerHost(config.getMaxConcurrentRequestsPerHost());
                httpClientBuilder.dispatcher(dispatcher);
            }

            if (config.getMaxConnection() > 0) {
                ConnectionPool connectionPool = new ConnectionPool(config.getMaxConnection(), 60, TimeUnit.SECONDS);
                httpClientBuilder.connectionPool(connectionPool);
            }

            // Only check proxy if it's a full URL with protocol
            if (config.getMasterUrl().toLowerCase().startsWith(HttpClientConfig.HTTP_PROTOCOL_PREFIX) || config.getMasterUrl().startsWith(HttpClientConfig.HTTPS_PROTOCOL_PREFIX)) {
                try {
                    URL proxyUrl = getProxyUrl(config);
                    if (proxyUrl != null) {
                        httpClientBuilder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyUrl.getHost(), proxyUrl.getPort())));

                        if (config.getProxyUsername() != null) {
                            httpClientBuilder.proxyAuthenticator((route, response) -> {

                                String credential = Credentials.basic(config.getProxyUsername(), config.getProxyPassword());
                                return response.request().newBuilder().header("Proxy-Authorization", credential).build();
                            });
                        }
                    }


                } catch (MalformedURLException e) {
                    throw new RuntimeException("Invalid proxy server configuration", e);
                }
            }

            if (config.getUserAgent() != null && !config.getUserAgent().isEmpty()) {
                httpClientBuilder.addNetworkInterceptor(chain -> {
                    Request agent = chain.request().newBuilder().header("User-Agent", config.getUserAgent()).build();
                    return chain.proceed(agent);
                });
            }

            if (config.getTlsVersions() != null && config.getTlsVersions().length > 0) {
                ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
                        .tlsVersions(config.getTlsVersions())
                        .build();
                httpClientBuilder.connectionSpecs(Arrays.asList(spec, CLEARTEXT));
            }
            return httpClientBuilder.build();
        } catch (Exception e) {
            throw new RuntimeException("创建OKHTTPClient错误", e);
        }
    }

    /**
     * 生成安全套接字工厂,用于https请求的证书跳过
     */
    private static SSLSocketFactory createSSLSocketFactory(TrustManager[] trustAllCerts) {
        SSLSocketFactory ssfFactory = null;
        try {
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new SecureRandom());
            ssfFactory = sc.getSocketFactory();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ssfFactory;
    }

    private static TrustManager[] buildTrustManagers() {
        return new TrustManager[]{
                new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(X509Certificate[] chain, String authType) {
                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] chain, String authType) {
                    }

                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[]{};
                    }
                }
        };
    }


    private static URL getProxyUrl(HttpClientConfig config) throws MalformedURLException {
        URL master = new URL(config.getMasterUrl());
        String host = master.getHost();
        if (config.getNoProxy() != null) {
            for (String noProxy : config.getNoProxy()) {
                if (host.endsWith(noProxy)) {
                    return null;
                }
            }
        }
        String proxy = config.getHttpsProxy();
        if (master.getProtocol().equals("http")) {
            proxy = config.getHttpProxy();
        }
        if (proxy != null) {
            return new URL(proxy);
        }
        return null;
    }

    /** -----------------------------------------------具体请求方法----------------------------------------------------**/

    /**
     * 发送post请求
     *
     * @param isJsonPost       true等于json的方式提交数据,类似postman里post方法的raw,false等于普通的表单提交
     * @param httpClientConfig httpclient配置类
     * @param paramMap         参数map
     * @return 返回的数据
     */
    public static String doPost(boolean isJsonPost, HttpClientConfig httpClientConfig, Map<String, Object> paramMap) {
        Response response = null;
        try {
            OkHttpClient client = getInstance(httpClientConfig);
            RequestBody requestBody;

            String json = JSONUtil.toJsonStr(paramMap);
            requestBody = RequestBody.create(MediaType.parse("application/json"), json);
            HashMap<String, String> extraHeaders = new HashMap<>();
            extraHeaders.put("istoken", "false");
            extraHeaders.put("repeatsubmit", "false");
            extraHeaders.put("Content-Type", "application/json;charset=UTF-8");
            Request request = new Request.Builder()
                    .headers(extraHeaders == null ? new Headers.Builder().build() : Headers.of(extraHeaders))//extraHeaders 是用户添加头
                    .url(httpClientConfig.getMasterUrl())
                    .post(requestBody)
                    .build();

            response = client.newCall(request).execute();
            if (response.isSuccessful() && response.body() != null) {
                return response.body().string();
            } else if (response.body() != null) {
                logger.info(response.body().string());
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return null;
    }

    /**
     * 发送post请求(发送json格式的不是form表单格式的)
     *
     * @param httpClientConfig httpclient配置类
     * @param map              参数map
     * @return 返回的数据
     */
    public static String doPost(HttpClientConfig httpClientConfig, Map<String, String> map) {
        Response response = null;
        try {
            OkHttpClient client = getInstance(httpClientConfig);

            String json = "";
            if (map != null) {
                json = JSONUtil.toJsonStr(map);
            }
            RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), json);

            Request.Builder builder = new Request.Builder();
            Request request = builder.url(httpClientConfig.getMasterUrl()).post(requestBody).build();
            response = client.newCall(request).execute();
            if (response.isSuccessful() && response.body() != null) {
                return response.body().string();
            } else if (response.body() != null) {
                logger.info(response.body().string());
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return null;
    }


    /**
     * 携带token的post请求
     *
     * @param isJsonPost       true等于json的方式提交数据,类似postman里post方法的raw,false等于普通的表单提交
     * @param httpClientConfig httpclient配置类
     * @param paramMap         参数map
     * @param token            token
     * @return 返回的数据
     */
    public static String doPostByToken(boolean isJsonPost, HttpClientConfig httpClientConfig, Map<Object, Object> paramMap, String token) {
        Response response = null;
        try {
            OkHttpClient client = getInstance(httpClientConfig);
            RequestBody requestBody;

            if (isJsonPost) {
                String json = "";
                if (paramMap != null) {
                    json = JSONUtil.toJsonStr(paramMap);
                }
                requestBody = RequestBody.create(MediaType.parse("application/json"), json);
            } else {
                FormBody.Builder formBody = new FormBody.Builder();
                if (paramMap != null) {
                    //paramMap.replaceAll((key, value) -> String.valueOf(value));
                    for (Map.Entry<Object, Object> entry : paramMap.entrySet()) {
                        String key = (String) entry.getKey();
                        String value = entry.getValue().toString();
                        Supplier2<FormBody.Builder, String, String> add = formBody::add;
                    }

                }
                requestBody = formBody.build();
            }

            Request.Builder builder = new Request.Builder();
            Request request = builder.url(httpClientConfig.getMasterUrl()).header("Authorization", token).post(requestBody).build();
            response = client.newCall(request).execute();
            if (response.isSuccessful() && response.body() != null) {
                return response.body().string();
            } else if (response.body() != null) {
                logger.info(response.body().string());
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return null;
    }

    /*发送PUT请求*/
    public static String doPutByToken(boolean isJsonPost, HttpClientConfig httpClientConfig, Map<Object, Object> paramMap, String token) {
        Response response = null;
        try {
            OkHttpClient client = getInstance(httpClientConfig);
            RequestBody requestBody;

            if (isJsonPost) {
                String json = "";
                if (paramMap != null) {
                    json = JSONUtil.toJsonStr(paramMap);
                }
                requestBody = RequestBody.create(MediaType.parse("application/json"), json);
            } else {
                FormBody.Builder formBody = new FormBody.Builder();
                if (paramMap != null) {
                    //paramMap.replaceAll((key, value) -> String.valueOf(value));
                    for (Map.Entry<Object, Object> entry : paramMap.entrySet()) {
                        Object key = entry.getKey();
                        Object value = entry.getValue().toString();
                        Supplier2<FormBody.Builder, String, String> add = formBody::add;
                    }
                }
                requestBody = formBody.build();
            }

            Request.Builder builder = new Request.Builder();
            Request request = builder.url(httpClientConfig.getMasterUrl()).header("Authorization", token).put(requestBody).build();
            response = client.newCall(request).execute();
            if (response.isSuccessful() && response.body() != null) {
                return response.body().string();
            } else if (response.body() != null) {
                logger.info(response.body().string());
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return null;
    }

    // 删除
    public static String doDeleteByToken(HttpClientConfig httpClientConfig, Object uniqueValue, String token) {
        Response response = null;
        try {
            OkHttpClient client = getInstance(httpClientConfig);
            Request.Builder builder = new Request.Builder();
            Request request = builder.url(httpClientConfig.getMasterUrl() + uniqueValue).header("Authorization", token).delete().build();
            response = client.newCall(request).execute();
            if (response.isSuccessful() && response.body() != null) {
                return response.body().string();
            } else if (response.body() != null) {
                logger.info(response.body().string());
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return null;
    }

    // get请求
    public static String doListByToken(HttpClientConfig httpClientConfig, String token) {
        Response response = null;
        try {
            OkHttpClient client = getInstance(httpClientConfig);
            Request.Builder builder = new Request.Builder();
            Request request = builder.url(httpClientConfig.getMasterUrl()).header("Authorization", token).get().build();
            response = client.newCall(request).execute();
            if (response.isSuccessful() && response.body() != null) {
                return response.body().string();
            } else if (response.body() != null) {
                logger.info(response.body().string());
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return null;
    }


    /**
     * 返回请求头
     *
     * @param config   httpclient配置类
     * @param paramMap 参数map
     * @return 响应头
     */
    public static Headers doLoginRequest(boolean isJsonPost, HttpClientConfig config, Map<String, String> paramMap) {
        Response response = null;
        try {
            OkHttpClient client = getInstance(config);
            RequestBody requestBody;

            if (isJsonPost) {
                String json = "";
                if (paramMap != null) {
                    json = JSONUtil.toJsonStr(paramMap);
                }
                requestBody = RequestBody.create(MediaType.parse("application/json"), json);
            } else {
                FormBody.Builder formBody = new FormBody.Builder();
                if (paramMap != null) {
                    paramMap.forEach(formBody::add);
                }
                requestBody = formBody.build();
            }

            Request request = new Request.Builder().url(config.getMasterUrl()).post(requestBody).build();
            response = client.newCall(request).execute();
            if (response.isSuccessful() && response.body() != null) {
                return response.headers();
            } else if (response.body() != null) {
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                ((Response) response).close();
            }
        }
        return null;
    }
}

在com.hima.testng.config下,直接把下方对应的HttpClientConfig代码放入.

package com.hima.testng.config;

import lombok.Data;
import okhttp3.TlsVersion;
import org.springframework.context.annotation.Configuration;

import static okhttp3.TlsVersion.TLS_1_2;

/**
 * @version 1.0
 * @Author:张爱婷
 * @Package:com.hima.common.config
 * @Date:2024/12/20 上午9:31
 */
@Data
@Configuration //告诉SpringBoot这是一个配置类 == 配置文件
public class HttpClientConfig {
    private String masterUrl;
    private boolean trustCerts;
    private String username;
    private String password;
    private int connectionTimeout;
    private int requestTimeout;
    private int websocketPingInterval;
    private int maxConcurrentRequestsPerHost;
    private int maxConnection;
    private String httpProxy;
    private String httpsProxy;
    private String proxyUsername;
    private String proxyPassword;
    private String userAgent;
    private TlsVersion[] tlsVersions = new TlsVersion[]{TLS_1_2};
    private String[] noProxy;
    public static final String HTTP_PROTOCOL_PREFIX = "http://";
    public static final String HTTPS_PROTOCOL_PREFIX = "https://";
    /**   token 暂存  质量管理系统*/
    public  String qmToken ;
    public String token;

    //省略get、set方法

//    @Bean  //给容器中添加组件。以方法名作为组件id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
//    public  TlsVersion[] tlsVersions(){
//        return new  TlsVersion[]{TlsVersion.valueOf("TLSv1.3")};
//    }


}

至此,基于若依框架进行接口自动化框架粗糙版搭建完成(TestNG+OKHTTP),可以进行相关的用例编写及请求发送,能够实现基本的接口自动化功能了。下来实战吧

四. 开始编写第一条接口用例

用例1: 输入正确的用户名和错误的密码,验证密码错误场景接口验证。

上边的用例大家都应该很清楚,非常基础,是验证登录异常的场景,也是测试登录需求必须要验证的场景。

注意: 我这边是以若依这个框架本身的登录举例,并且关掉了验证码功能,大家关掉验证码功能后,刷新退出。

(1)  testcase文件夹下方创建对应的项目文件夹(例:demoproject),并创建登录用例

     点击相关项目文件夹,选择新建->java类,创建LoginTest类,创建方法public void loginUserName() {},在方法中编写测试用例。

     

 (2)   在方法上方直接添加@Test注解,选择testng的@Test,这就表明该方法是一个测试方法。里边写的内容就是测试用例,并且可以点击左侧按钮直接运行啦。

(3) 编写用例代码,直接复制下方代码即可。

       1. 登录接口(默认端口号是80,我改过端口号,所以是82)

       2.入参数据

       3.给接口发送请求(true表示入参是json格式)

       4. 对接口返回的信息进行断言,看是否和需求一致。

package com.hima.testng.testcase.demoproject;

import com.hima.testng.config.HttpClientConfig;
import com.hima.testng.data.BaseData;
import com.hima.testng.data.demoproject.InterAutoData;
import com.hima.testng.data.demoproject.LoginData;
import com.hima.testng.utils.HttpClientUtils;
import org.testng.Assert;
import org.testng.annotations.Test;

import java.util.HashMap;
import java.util.Map;

/**
 * @version 1.0
 * @Author:张爱婷
 * @Package:com.hima.testng.testcase.demoproject
 * @Date:2025/1/17 上午10:35
 * @DESC:
 */
public class LoginTest {
    @Test(description = "输入正确的用户名和错误的密码,验证密码错误场景接口验证。")
    public void loginUserName() {
        // 1. 登录接口(默认端口号是80,我改过端口号,所以是82)
        HttpClientConfig config = new HttpClientConfig();
        config.setMasterUrl("http://127.0.0.1:82/dev-api/login");
        //2.入参数据,由于HttpClientUtils.doPost要求的入参数据类型是map,所以我们入参编写为map类型
        Map<String, Object> loginmap = new HashMap<>() ;
        loginmap.put("username","admin");
        loginmap.put("password","admin1234");
        loginmap.put("uuid","");
        loginmap.put("code","");
        //3.给接口发送请求(true表示入参是json格式)
        String logintest = HttpClientUtils.doPost(true, config, loginmap);
        //4. 对接口返回的信息进行断言,看是否和需求一致。
        Assert.assertEquals(logintest,  "{\"msg\":\"用户不存在/密码错误\",\"code\":500}");

    }
}

(4)  点击方法左侧的运行按钮,成功运行。

是不是很简单,这样一条接口自动化用例就完成了,不过大家有没有觉得很乱,数据,断言都在一起,下一章节,我们会把数据和用例代码进行分离。

标签:return,String,框架,TestNG,若依,import,null,config,response
From: https://blog.csdn.net/qq_38932687/article/details/145199255

相关文章

  • Flyte工作流(Workflow)平台调研(六)——跟Ray框架对比
    系列文章:Flyte工作流(Workflow)平台调研(一)——整体架构Flyte工作流(Workflow)平台调研(二)——核心概念说明Flyte工作流(Workflow)平台调研(三)——核心组件原理Flyte工作流(Workflow)平台调研(四)——服务部署Flyte工作流(Workflow)平台调研(五)——扩展集成Flyte工作流(Workflo......
  • pytest测试框架集成钉钉机器人、邮件,并实现持续集成部署
    要结合多系统并存的架构,使用YAML文件编写测试用例,并集成钉钉、邮件通知功能以及CI/CD流程,以下是完整的实现方案。整体功能架构多系统测试支持:使用YAML文件定义测试用例,支持多系统间的模块化、分层管理。测试框架根据YAML文件动态加载测试用例,支持灵活扩展。......
  • 基于JAVA中的spring框架和jsp实现驾驶知识学习和评测系统项目【附项目源码+论文说明】
    摘要在21世纪这个信息高度发达,并且高速流通的时代,计算机的普及以及计算机网络技术的应用,让大量普通人能够有机会接触到比以往更多的知识。作为一个以传播知识为主要职能的机构——学校,建立一个自己的精品课程网站是十分必要的事情,这不仅能使更多的人享用宝贵的教育资料源,同时......
  • 基于JAVA中的spring框架和jsp实现大学生综合测评系统项目【内附项目源码+论文说明】
    摘要大学生综合测评系统是一款以大学生德智体等综合成绩进行评测的系统, 其开发基于B/S模式的网上评测的实现,采用的是JSP+sqlserver数据库为主要模式。在线评测平台是凌架于互联网系统上的一个评测平台,是地面评测系统的一种延伸和互补,也是实现无纸化评测的主要工具。当下在......
  • SpringCloudAlibaba:从0搭建一套快速开发框架-03 Nacos下载及使用
    序言:上篇安装了Docker并运行MySql5.7,本篇主要介绍Nacos的下载以及使用Nacos简介Nacos(DynamicNAmingandCOnfigurationService)是阿里巴巴开源的一款集服务发现、配置管理和动态DNS服务于一体的解决方案,广泛用于微服务架构。Nacos支持分布式系统中的动态配置和服务管......
  • 【前端框架】2025 React 状态管理终极指南!
    全文约10800字,预计阅读需要30分钟。React作为当下最受欢迎的前端框架,在构建复杂且交互丰富的应用时,状态管理无疑是至关重要的一环。从简单的本地状态,到能让多个组件协同工作的全局状态,再到涉及服务器通信、导航切换、表单操作以及持久化存储等不同场景下的状态管理,每一个方面......
  • Pytorch框架与经典卷积神经网络学习Day4|VGG原理与实战
    目录跟学视频1.原理1.1VGG网络诞生背景 1.2VGG网络结构 1.3VGG总结2.实战2.1model.py2.2model_train.py2.3model_test.py跟学视频炮哥带你学_Pytorch框架与经典卷积神经网络与实战1.原理VGG(VisualGeometryGroup)是一个深度卷积神经网络架构,广泛应用于计算机......
  • 计算机毕业设计Springboot运动健康APP 基于Spring Boot框架的健身与健康管理移动应用
    计算机毕业设计Springboot运动健康APPu8mr9vrk(配套有源码程序mysql数据库论文)本套源码可以先看具体功能演示视频领取,文末有联xi可分享随着科技的飞速发展和人们对健康生活方式的追求,运动健康APP应运而生,成为现代生活中不可或缺的健康管理工具。这类APP不仅能够帮助用户记......
  • 计算机毕业设计Springboot云聚合支付平台 基于SpringBoot的云聚合支付解决方案 Spring
    计算机毕业设计Springboot云聚合支付平台6noy0741(配套有源码程序mysql数据库论文)本套源码可以先看具体功能演示视频领取,文末有联xi可分享随着电子商务和移动互联网的飞速发展,支付方式和支付渠道日益多样化,用户对支付体验的要求也越来越高。商户为了满足不同用户的需求,需......
  • 计算机毕业设计Springboot校园点餐系统 基于Spring Boot的高校在线订餐平台开发 Sprin
    计算机毕业设计Springboot校园点餐系统670075a9(配套有源码程序mysql数据库论文)本套源码可以先看具体功能演示视频领取,文末有联xi可分享随着校园生活的日益数字化,传统的食堂点餐方式已逐渐无法满足师生的快节奏生活需求。为了提升用餐体验,减少排队时间,同时为校园餐饮服务......