Retrofit2 详解和使用(一)

Retrofit2 详解和使用(一)前言 要么出击 要么出局 命运女神总会眷顾拼尽全力的一方 一 概述 1 什么是 retrofitretr 是现在比较流行的网络请求框架 可以理解为 okhttp 的加强版 底层封装了 Okhttp 准确来说 Retrofit 是一个 RESTful 的 http 网络请求框架的封装 因为网络请求工作本质上是由 okhttp 来完成 而 Retrofit 负责网络请求接口的封装 本质过

前言:要么出击,要么出局,命运女神总会眷顾拼尽全力的一方。

一、概述

1、什么是retrofit

        retrofit是现在比较流行的网络请求框架,可以理解为okhttp的加强版,底层封装了Okhttp。准确来说,Retrofit是一个RESTful的http网络请求框架的封装。因为网络请求工作本质上是由okhttp来完成,而Retrofit负责网络请求接口的封装。

本质过程:App应用程序通过Retrofit请求网络,实质上是使用Retrofit接口层封装请求参数、Header、Url等信息,之后由okhttp来完成后续的请求工作。在服务端返回数据后,okhttp将原始数据交给Retrofit,Retrofit根据用户需求解析。(源码在文章最后给出)

2、Retrofit的优点

  • 超级解耦 ,接口定义、接口参数、接口回调不在耦合在一起
  • 可以配置不同的httpClient来实现网络请求,如okhttp、httpclient
  • 支持同步、异步、Rxjava
  • 可以配置不同反序列化工具类来解析不同的数据,如json、xml
  • 请求速度快,使用方便灵活简洁

二、注解

Retrofit使用大量注解来简化请求,Retrofit将okhttp请求抽象成java接口,使用注解来配置和描述网络请求参数。大概可以分为以下几类,我们先来看看各个注解的含义,再一一去实践解释。

1、请求方法注解

请求方法注解 说明
@GET get请求
@POST post请求
@PUT put请求
@DELETE delete请求
@PATCH patch请求,该请求是对put请求的补充,用于更新局部资源
@HEAD head请求
@OPTIONS options请求
@HTTP 通过注解,可以替换以上所有的注解,它拥有三个属性:method、path、hasBody

2、请求头注解

请求头注解 说明
@Headers 用于添加固定请求头,可以同时添加多个,通过该注解的请求头不会相互覆盖,而是共同存在
@Header 作为方法的参数传入,用于添加不固定的header,它会更新已有请求头

3、请求参数注解

请求参数注解 说明
@Body 多用于Post请求发送非表达数据,根据转换方式将实例对象转化为对应字符串传递参数,比如使用Post发送Json数据,添加GsonConverterFactory则是将body转化为json字符串进行传递
@Filed 多用于Post方式传递参数,需要结合@FromUrlEncoded使用,即以表单的形式传递参数
@FiledMap 多用于Post请求中的表单字段,需要结合@FromUrlEncoded使用
@Part 用于表单字段,Part和PartMap与@multipart注解结合使用,适合文件上传的情况
@PartMap 用于表单字段,默认接受类型是Map

,可用于实现多文件上传
@Path 用于Url中的占位符
@Query 用于Get请求中的参数
@QueryMap 与Query类似,用于不确定表单参数
@Url 指定请求路径

4、请求和响应格式(标记)注解

标记类注解 说明
@FromUrlCoded 表示请求发送编码表单数据,每个键值对需要使用@Filed注解
@Multipart 表示请求发送form_encoded数据(使用于有文件上传的场景),每个键值对需要用@Part来注解键名,随后的对象需要提供值
@Streaming 表示响应用字节流的形式返回,如果没有使用注解,默认会把数据全部载入到内存中,该注解在下载大文件时特别有用

三、retrofit的使用

1、注解详解

我们先来解释注解的使用和需要注意的问题(具体的使用步骤后面会给出)。上面提到注解是用来配置和描述网络请求参数的,我们来逐个讲解一下,首先创建网络接口类:

  • Retrofit将okhttp请求抽象成java接口,采用注解描述和配置网络请求参数,用动态代理将该接口的注解“翻译”成一个Http请求,最后执行Http请求。
  • 注意:接口中的每个方法的参数都要用注解标记,否则会报错。

(1)@GET、@Query、@QueryMap的使用

public interface Api { //get请求 @GET("user") Call 
  
    getData(); } 
  
  • @GET                              请求方法注解,get请求,括号内的是请求地址,Url的一部分
  • Call<*>                           返回类型,*表示接收数据的类,一般自定义
  • getData()                        接口方法名称,括号内可以写入参数

上面的网络接口最简单的一种形式,我们先从简单的开始,一步步深入了解。这是一个没有网络参数的get请求方式,需要在方法头部添加@GET注解,表示采用get方法访问网络请求,括号内的是请求的地址(Url的一部分) ,其中返回类型是Call<*>,*表示接收数据的类,如果想直接获取ResponseBody中的内容,可以定义网络请求返回值为Call

,ResponseBody是请求网络后返回的原始数据,如果网络请求没有参数,不用写。

这里特别说明Url的组成(下面会讲解到),retrofit把网络请求的Url分成两部分设置:第一部分在创建Retrofit实例时通过.baseUrl()设置,第二部分在网络接口注解中设置,比如上面接口的”/user”,网络请求的完整地址Url = Retrofit实例.baseUrl()+网络请求接口注解()。

下面我们来看看有参数的get请求方法:

 @GET("user") Call 
  
    getData2(@Query("id") long idLon, @Query("name") String nameStr); 
  
  •  @Query                         请求参数注解,用于Get请求中的参数
  • “id”/”name”                    参数字段,与后台给的字段需要一致
  • long/String                     声明的参数类型
  • idLon/nameStr               实际参数

添加参数在方法括号内添加@Query,后面是参数类型和参数字段,表示后面idLon的取值作为”id”的值,nameStr的取值作为”name”的值,其实就是键值对,Retrofit会把两个字段拼接到接口中,追加到”/user”后面。比如:baseUrl为https://api.github.com/,那么拼接网络接口注解中的地址后变为:https://api.github.com/user,我们需要传入的id=10006,name=”刘亦菲”,那么拼接参数后就是完整的请求地址:https://api.github.com/user?id=10006&name=刘亦菲

 @GET("user") Call 
  
    getData3(@QueryMap Map 
   
     map); 
    
  
  • @QueryMap                             请求参数注解,与@Query类似,用于不确定表单参数
  • Map

    map       
    通过Map将不确定的参数传入,相当于多个Query参数

如果有不确定的把表单参数我们可以使用@QueryMap注解来添加参数,通过Map将不确定的参数存入,然后在方法体中带给网络接口,相当于多个Query参数,看看下面的使用:

 Map 
  
    map = new HashMap<>(); map.put("id", 10006); map.put("name", "刘亦菲"); Call 
   
     call = retrofit.create(Api.class).getData3(map); 
    
  

(2)@POST、@FormUrlEncoded、@File、@FileMap、@Body的使用

我们来看看没有参数的post方法的请求:

@POST("user/emails") Call 
  
    getPostData(); 
  
  • @POST                       请求方法注解,表示采用post方法访问网络请求,括号后面是部分的URL地址

post请求网络方法,需要在方法头部添加@POST注解,表示采用post方法访问网络请求,这里是没有参数的,那有参数的Post请求方法该怎样写呢?

@FormUrlEncoded @POST("user/emails") Call 
  
    getPostData2(@Field("name") String nameStr, @Field("sex") String sexStr); 
  
  • @FormUrlEncoded        请求格式注解,请求实体是一个From表单,每个键值对需要使用@Field注解
  • @Field                           请求参数注解,提交请求的表单字段,必须要添加,而且需要配合@FormUrlEncoded使用
  • “name”/”sex”                 参数字段,与后台给的字段需要一致
  • String                             声明的参数类型
  • nameStr/sexStr              实际参数,表示后面nameStr的取值作为”name”的值,sexStr的取值作为”sex”的值

Post请求如果有参数需要在头部添加@FormUrlEncoded注解,表示请求实体是一个From表单,每个键值对需要使用@Field注解,使用@Field添加参数,这是发送Post请求时,提交请求的表单字段,必须要添加的,而且需要配合@FormUrlEncoded使用

 @FormUrlEncoded @POST("user/emails") Call 
  
    getPsotData3(@FieldMap Map 
   
     map); 
    
  
 Map 
  
    fieldMap = new HashMap<>(); map.put("name", "刘亦菲"); map.put("sex", "女"); Call 
   
     psotData3 = retrofit.create(Api.class).getPostData3(map); 
    
  
  • @FieldMap                              请求参数注解,与@Field作用一致,用于不确定表单参数
  • Map

    map       
    通过Map将不确定的参数传入,相当于多个Field参数

当有多个不确定参数时,我们可以使用@FieldMap注解,@FieldMap与@Field的作用一致,可以用于添加多个不确定的参数,类似@QueryMap,Map的key作为表单的键,Map的value作为表单的值。

适用于Post请求的还有一个注解@Body,@Body可以传递自定义类型数据给服务器,多用于post请求发送非表单数据,比如用传递Json格式数据,它可以注解很多东西,比如HashMap、实体类等,我们来看看它用法:

@POST("user/emails") Call 
  
    getPsotDataBody(@Body RequestBody body); 
  
  • @Body                          上传json格式数据,直接传入实体它会自动转为json,这个转化方式是GsonConverterFactory定义的

特别注意:@Body注解不能用于表单或者支持文件上传的表单的编码,即不能与@FormUrlEncoded和@Multipart注解同时使用,否则会报错,如下图:

Retrofit2 详解和使用(一)

我们找到@Body的源码发现,isFormEncoded为true或者isMultipart为ture时,满足其中任何一个条件都会抛出该异常,通过变量名字可以看出使用@ FormUrlEncoded 或者@Multipart 标签。

 if (annotation instanceof Body) { if (isFormEncoded || isMultipart) { throw parameterError(method, p, "@Body parameters cannot be used with form or multi-part encoding."); } }

(3)@HTTP

@HTTP注解的作用是替换@GET、@POST、@PUT、@DELETE、@HEAD以及更多拓展功能

@HTTP(method = "GET", path = "user/keys", hasBody = false) Call 
  
    getHttpData(); 
  
  • method              表示请求的方法,区分大小写,这里的值retrofit不会再做任何处理,必须要保证正确
  • path                   网络请求地址路径
  • hasBody            是否有请求体,boolean类型

@HTTP注解可以通过method字段灵活设置具体请求方法,通过path设置网络请求地址,用的比较少。@HTTP替换@POST、@PUT、@DELETE、@HEAD等方法的用法类似,这里就不一一讲解了。

(4)@Path

 @GET("orgs/{id}") Call 
  
    getPathData(@Query("name") String nameStr, @Path("id") long idLon); 
  
  • @Query                    get请求方法参数的注解,上面已经解释了,这里就不重复讲
  • @Path                      请求参数注解,用于Url中的占位符{},所有在网址中的参数

@Path注解用于Url中的占位符{},所有在网址中的参数,如上面 @GET(“orgs/{id}”)的id,通过{}占位符来标记id,使用@Path注解传入idLon的值,注意有的Url既有占位符又有”?”后面的键值对,其实@Query和@Path两者是可以共用的。在发起请求时,{id}会被替换为方法中第二个参数的值idLon。

(5)@Url

如果需要重新地址接口地址,可以使用@Url,将地址以参数的形式传入即可。如果有@Url注解时,GET传入的Url可以省略。

@GET Call 
  
    getUrlData(@Url String nameStr, @Query("id") long idLon); 
  
  • @Url                         表示指定请求路径,可以当做参数传入

(6)@Header、@Headers

我们可以在方法参数内添加请求头,@Header用于添加不固定的请求头,作用于方法的参数,作为方法的参数传入,该注解会更新已有的请求头。

 @GET("user/emails") Call 
  
    getHeaderData(@Header("token") String token); 
  
  • @header                      请求头注解,用于添加不固定请求头

我们想对某个方法添加固定请求头时可以参考下面的写法,@headers用于添加固定的请求头,作用于方法,可以同时添加多个,通过该注解添加的请求头不会相互覆盖,而是共同存在。

 @Headers({"phone-type:android", "version:1.1.1"}) @GET("user/emails") Call 
  
    getHeadersData(); 
  
  • @headers                      请求头注解,用于添加固定请求头,可以添加多个

(7)@Streaming

 @Streaming @POST("gists/public") Call 
  
    getStreamingBig(); 
  
  • @Streaming                 表示响应体的数据用流的方式返回,使用于返回数据比较大,该注解在下载大文件时特别有用

我们在使用下载比较大的文件的时候需要添加@Streaming注解

(8)@Multipart、@part、@PartMap

@Multipart @POST("user/followers") Call 
  
    getPartData(@Part("name") RequestBody name, @Part MultipartBody.Part file); 
  
  • @Multipart                表示请求实体是一个支持文件上传的表单,需要配合@Part和@PartMap使用,适用于文件上传
  • @Part                       用于表单字段,适用于文件上传的情况,@Part支持三种类型:RequestBody、MultipartBody.Part、                                       任意类型
  • @PartMap               用于多文件上传, 与@FieldMap和@QueryMap的使用类似

上面的使用是一个上传文字和文件的写法,在使用@Part注解时需要在头部添加@Multipart注解,实现支持文件上传,我们来看看上面代码怎么使用:

//声明类型,这里是文字类型 MediaType textType = MediaType.parse("text/plain"); //根据声明的类型创建RequestBody,就是转化为RequestBody对象 RequestBody name = RequestBody.create(textType, "这里是你需要写入的文本:刘亦菲"); //创建文件,这里演示图片上传 File file = new File("文件路径"); if (!file.exists()) { file.mkdir(); } //将文件转化为RequestBody对象 //需要在表单中进行文件上传时,就需要使用该格式:multipart/form-data RequestBody imgBody = RequestBody.create(MediaType.parse("image/png"), file); //将文件转化为MultipartBody.Part //第一个参数:上传文件的key;第二个参数:文件名;第三个参数:RequestBody对象 MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), imgBody); Call 
  
    partDataCall = retrofit.create(Api.class).getPartData(name, filePart); 
  

首先声明类型,然后根据类型转化为RequestBody对象,返回RequestBody或者转化为MultipartBody.Part,需要在表单中进行文件上传时,就需要使用该格式:multipart/form-data。

@PartMap的使用与@FieldMap和@QueryMap的使用类似,用于多文件上传,我们直接看代码:

 @Multipart @POST("user/followers") Call 
  
    getPartMapData(@PartMap Map 
   
     map); 
    
  
 File file1 = new File("文件路径"); File file2 = new File("文件路径"); if (!file1.exists()) { file1.mkdir(); } if (!file2.exists()) { file2.mkdir(); } RequestBody requestBody1 = RequestBody.create(MediaType.parse("image/png"), file1); RequestBody requestBody2 = RequestBody.create(MediaType.parse("image/png"), file2); MultipartBody.Part filePart1 = MultipartBody.Part.createFormData("file1", file1.getName(), requestBody1); MultipartBody.Part filePart2 = MultipartBody.Part.createFormData("file2", file2.getName(), requestBody2); Map 
  
    mapPart = new HashMap<>(); mapPart.put("file1",filePart1); mapPart.put("file2",filePart2); Call 
   
     partMapDataCall = retrofit.create(Api.class).getPartMapData(mapPart); 
    
  

上面的(@PartMap Map

map)方法参数中的MultipartBody.Part可以是RequestBody、String、MultipartBody.Part等类型,可以根据个人需要更换,这里就不一一说明了。

2、retrofit在项目中简单使用(get请求)

下面我们正式在项目简单使用retrofit,需要以下几个步骤:

(1)在清单文件中添加网络权限

retrofit是网络请求框架,毫无疑问必须要在AndroidManifest.xml文件中添加网络权限

 
  

(2)添加retrofit的依赖库

在build.gradle文件中添加Retrofit依赖库,由于Retrofit已经封装有okhttp所以不需要再添加okhttp的库

Retrofit2 详解和使用(一)

implementation 'com.squareup.retrofit2:retrofit:2.5.0'

(3)创建接受服务器返回数据的类

在正式的请求网络数据中,返回的数据的外嵌套部分都是一样的,携带状态码、状态信息、实体数据一起返回,我们可以将它封装一个统一的数据回调类。

public class Data 
  
    { private int code; private String message; private T data; public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public T getData() { return data; } public void setData(T data) { this.data = data; } } 
  

(4)创建用于描述网络接口的类

这个类就是Retrofit将okhttp请求抽象成java的接口类,用注解描述和配置网络请求参数,封装Url地址和网络数据请求

public interface Api { //get请求 @GET("api/rand.music") Call 
  
    > getJsonData(@Query("sort") String sort, @Query("format") String format); } 
  

在方法头部添加@GET注解,表示采用get方法访问网络请求,括号内的是请求的地址(Url的一部分) ,其中返回类型是Call<*>,*表示接收数据的类,Data是上面封装的一个接收数据的统一公共类,添加参数在方法括号内添加@Query,后面是参数类型和参数字段,其实就是键值对的形式。

(5)创建Retrofit实例

 //构建Retrofit实例 Retrofit retrofit = new Retrofit.Builder() //设置网络请求BaseUrl地址 .baseUrl("https://api.uomg.com/") //设置数据解析器 .addConverterFactory(GsonConverterFactory.create()) .build(); 
.baseUrl("https://api.uomg.com/")

就是上面的这个地址会和方法请求注解上面的地址拼接在一起,baseUrl地址必须以“/”结尾,否则会报错,                               

第二部分:在网络请求接口的注解设置,就是在上面的APi接口中用GET注解的字符串:

 @GET("api/rand.music")

上面地址拼接后的完整地址为:https://api.uomg.com/api/rand.music?sort=&format=,然后通过addConverterFactory设置数据解释器,这里添加的是Gson解释器。这是为了使来自接口的json结果会自动解析成定义好的字段和类型都相符的json对象接受类,在Retrofit 2.0中已经没有Converter,需要自己创建一个Converter, 不然Retrofit只能接收字符串结果,最后需要自己去解析。

在build.gradle中添加Converter依赖:

implementation 'com.squareup.retrofit2:converter-gson:2.0.2'

Retrofit支持多种数据解析,需要在Gradle添加依赖:

数据解析器 Gradle依赖
Gson com.squareup.retrofit2:converter-gson:2.0.2
Jackson com.squareup.retrofit2:converter-jackson:2.0.2
Simple XML com.squareup.retrofit2:converter-simplexml:2.0.2
Protobuf com.squareup.retrofit2:converter-protobuf:2.0.2
Moshi com.squareup.retrofit2:converter-moshi:2.0.2
Wire com.squareup.retrofit2:converter-wire:2.0.2
Scalars com.squareup.retrofit2:converter-scalars:2.0.2

(6)创建网络请求接口实例

//创建网络请求接口对象实例 Api api = mRetrofit.create(Api.class); //对发送请求进行封装 Call 
  
    > dataCall = api.getJsonData("新歌榜", "json"); 
  

调用Retrofit实例对象create()方法,传入网络接口类,得到接口对象实例,调用接口类中的方法。

(7)发送网络请求(同步/异步)

//异步请求 dataCall.enqueue(new Callback 
  
    >() { //请求成功回调 @Override public void onResponse(Call 
   
     > call, Response 
    
      > response) { } //请求失败回调 @Override public void onFailure(Call 
     
       > call, Throwable t) { } }); 
      
     
    
  
//同步请求 Response 
  
    > data= dataCall.execute(); 
  

(8)处理返回的数据

 dataCall.enqueue(new Callback 
  
    >() { @Override public void onResponse(Call 
   
     > call, Response 
    
      > response) { Toast.makeText(MainActivity.this, "get回调成功:异步执行", Toast.LENGTH_SHORT).show(); Data 
     
       body = response.body(); if (body == null) return; Info info = body.getData(); if (info == null) return; mTextView.setText("返回的数据:" + "\n\n" + info.getName() + "\n" + info.getPicurl()); } @Override public void onFailure(Call 
      
        > call, Throwable t) { Log.e(TAG, "回调失败:" + t.getMessage() + "," + t.toString()); Toast.makeText(MainActivity.this, "回调失败", Toast.LENGTH_SHORT).show(); } }); 
       
      
     
    
  

对异步返回的数据进行处理,网络加载完成。get的请求地址为:https://api.uomg.com/api/rand.music?sort=%E6%96%B0%E6%AD%8C%E6%A6%9C&format=json

Retrofit2 详解和使用(一)

效果如下图所示:

Retrofit2 详解和使用(一)

点击执行get请求按钮,代码执行get请求,一段时间后返回了请求的结果。

3、post请求的简单使用

参照上面get请求的实例,重复步骤部分就不一一再讲了,我们来看一下不同样的部分:

创建网络请求接口:

public interface Api { //post请求,如果有参数需要添加 @FormUrlEncoded注解,即和@Field配合使用 @FormUrlEncoded @POST("api/comments.163") Call  postDataCall(@Field("format") String format); } 

调用网络请求接口实例,处理返回数据:

 //步骤4:创建Retrofit对象 Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.uomg.com/") // 设置网络请求baseUrl .addConverterFactory(GsonConverterFactory.create()) //设置使用Gson解析 .build(); // 步骤5:创建网络请求接口的实例 Api request = retrofit.create(Api.class); //步骤6:对发送请求进行封装: Call 
  
    call = request.postDataCall("JSON"); //步骤7:发送网络请求(异步) call.enqueue(new Callback 
   
     () { //请求成功时回调 @Override public void onResponse(Call 
    
      call, Response 
     
       response) { //步骤8:请求处理,输出结果 Object body = response.body(); if (body == null) return; mTextView.setText("返回的数据:" + "\n\n" + response.body().toString()); Toast.makeText(MainActivity.this, "post回调成功:异步执行", Toast.LENGTH_SHORT).show(); } //请求失败时回调 @Override public void onFailure(Call 
      
        call, Throwable throwable) { Log.e(TAG, "post回调失败:" + throwable.getMessage() + "," + throwable.toString()); Toast.makeText(MainActivity.this, "post回调失败", Toast.LENGTH_SHORT).show(); } }); 
       
      
     
    
  

对异步返回的数据进行处理,网络加载完成。post的请求地址和参数打印如下:

Retrofit2 详解和使用(一)

数据打印效果如下:

Retrofit2 详解和使用(一)

点击执行post请求按钮,代码执行post请求,一段时间后返回了请求的结果。

源码地址

点关注,不迷路


好了各位,以上就是这篇文章的全部内容了,能看到这里的人呀,都是人才。有关Retrofit更深入的了解以及配合RxJava的使用在后面的篇幅会讲解到!

我是suming,感谢各位的支持和认可,您的点赞就是我创作的最大动力,我们下篇文章见!

如果本篇博客有任何错误,请批评指教,不胜感激 !

要想成为一个优秀的安卓开发者,这里有必须要掌握的Andorid知识架构,Keep Moving!

相关文章:

Retrofit2详解和使用(一)

  • Retrofit2的介绍和简单使用

OKHttp3的使用和详解

  • OKHttp3的用法介绍和解析

OKHttp3源码详解

  • 从源码角度解释OKHttp3的关键流程和重要操作

RxJava2详解(一)

  • 详细介绍了RxJava的使用(基本创建、快速创建、延迟创建等操作符)

RxJava2详解(二)

  • RxJava转换、组合、合并等操作符的使用

RxJava2详解(三)

  • RxJava延迟、do相关、错误处理等操作符的使用

RxJava2详解(四)

  • RxJava过滤、其他操作符的使用

上述几篇都是android开发必须掌握的,后续会完善其他部分!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/201901.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月20日 上午8:21
下一篇 2026年3月20日 上午8:21


相关推荐

  • 数据仓库之电商数仓– 3.1、电商数据仓库系统(ODS层、DIM层、DWD层)

    数据仓库之电商数仓– 3.1、电商数据仓库系统(ODS层、DIM层、DWD层)目录一、数仓分层1.1为什么要分层1.2数据集市与数据仓库概念1.3数仓命名规范1.3.1表命名1.3.2脚本命名1.3.3表字段类型二、数仓理论2.1范式理论2.1.1范式概念2.1.2函数依赖2.1.3三范式区分2.2关系建模与维度建模2.2.1关系建模2.2.2维度建模⭐️2.3维度表和事实表⭐️2.3.1维度表2.3.2事实表2.4维度模型分类2.5数据仓库建模⭐️????2.5.1ODS层2.5.2DIM层和DWD层2.5.3DWS层与DWT层2.5.4

    2022年6月26日
    31
  • markdown字体颜色设置_markdown红色字体

    markdown字体颜色设置_markdown红色字体 Markdown是一种可以使用普通文本编辑器编写的标记语言,通过类似HTML的标记语法,它可以使普通文本内容具有一定的格式。但是它本身是不支持修改背景色功能的!  从HTMLEditor转到CSDN-markdown编辑器的很多朋友可能有些不适应,明明很简单的背景色功能,这里却找不到了。  CSDN-markdown编辑器是其衍生版本,扩展了Markdown的功能(如表格、脚注、内嵌HTML等等)!对,就是内嵌HTML,接下来要讲的功能就需要使用内嵌HTML的方法来实现。  背景色由.

    2025年8月20日
    5
  • 百度离线地图开发

    百度离线地图开发离线地图开发

    2026年3月17日
    2
  • LM优化算法_lm算法内参计算

    LM优化算法_lm算法内参计算LM算法理论知识梯度下降高斯牛顿Levenberg–Marquardt算法框架算法的整体流程求解器update流程说明算法实现头文件cpp算法调用LM优化算法,是一种非线性优化算法,其可以看作是梯度下降和高斯牛顿法的结合。综合了梯度下降对初值不敏感和高斯牛顿在最优值附近收敛速度快的特点。本人非数学专业,且对算法理解可能不到位,详细的算法推导及各个优化算法之间的关系,非常推荐看**《METHODSFORNON-LINEARLEASTSQUARESPROBLEMS》**,其介绍更详细也更专业。

    2022年9月30日
    4
  • 现货黄金贵金属投资入门基础知识

    现货黄金贵金属投资入门基础知识现货黄金贵金属投资入门知识:  很多中小投资者对证券投资都比较熟悉,但对现货黄金贵金属投资还不是很熟悉。现货吧给大家做一些简单的介绍。希望能为大家进入现货黄金贵金属投资的市场提供一些有益的参考和帮助。  现货黄金.jpg  黄金贵金属投资分为实物黄金和合约式黄金,投资实物黄金的可靠性较强,但买卖过程比较麻烦,而且还要自己承担保管的成本和风险,投资起来明显不如合约

    2022年5月8日
    28
  • JavaScript常用基础算法「建议收藏」

    JavaScript常用基础算法「建议收藏」一、字符串1.字符串中出现最多次数的字符functionfindMaxDuplicateChar(str){varcnt={},//用来记录所有的字符的出现频次c="";//用来记录最大频次的字符for(vari=0;i<str.length;i++){varci=str[i];if(!cnt[ci]){

    2022年10月5日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号