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

Spring?Framework六種常見(jiàn)設(shè)計(jì)模式

 更新時(shí)間:2023年06月26日 10:27:57   作者:江帥帥  
設(shè)計(jì)模式是軟件開(kāi)發(fā)的重要組成部分,本文借助spring來(lái)講解這個(gè)框架的設(shè)計(jì)模式,通過(guò)本文我們探討了spring如何利用這些模式來(lái)提供這些豐富的功能,對(duì)本文感興趣的朋友跟隨小編一起看看吧

在實(shí)際開(kāi)發(fā)工作中,我們每天都在自己的工作中依賴(lài)了別人的代碼。包括了你正在用的編程語(yǔ)言、你正在構(gòu)建的框架,或者一些很前沿的開(kāi)源產(chǎn)品。

它們都做得很好,用起來(lái)真的很爽,但你自己有沒(méi)有想過(guò)自己也要去實(shí)現(xiàn)它?哈哈,可能大概率是沒(méi)想過(guò)的,是吧?

如果你沒(méi)有嘗試過(guò)自己去實(shí)現(xiàn)類(lèi)似的功能,或者是深挖過(guò)這些優(yōu)秀三方框架的話,對(duì)技術(shù)人來(lái)說(shuō),其實(shí)是隱含相當(dāng)大一個(gè)風(fēng)險(xiǎn)的。

如果運(yùn)氣很不好,當(dāng)你在生產(chǎn)中碰到了分崩離析的事情,出現(xiàn)了生產(chǎn)事故,又不得不去調(diào)試您不熟悉的第三方庫(kù)的實(shí)現(xiàn)時(shí),對(duì)你來(lái)說(shuō)至少可以說(shuō)是相當(dāng)棘手的,毫無(wú)頭緒的,搞不好真的就是想原地提離職……

推薦一個(gè) Lightrun,它是一種新型的調(diào)試器。

它是專(zhuān)門(mén)針對(duì)現(xiàn)實(shí)生活中的生產(chǎn)環(huán)境。使用 Lightrun,您可以向下鉆取到正在運(yùn)行的應(yīng)用程序,包括第三方依賴(lài)項(xiàng),以及實(shí)時(shí)日志、快照和指標(biāo)。

這不是重點(diǎn),重點(diǎn)是我們借助 Spring 來(lái)聊聊這個(gè)如此受歡迎的框架的設(shè)計(jì)模式,以此打開(kāi)你研究三方框架的道路。

1、簡(jiǎn)介

設(shè)計(jì)模式是軟件開(kāi)發(fā)的重要組成部分。這些解決方案不僅可以解決反復(fù)出現(xiàn)的問(wèn)題,還可以通過(guò)識(shí)別常見(jiàn)模式來(lái)幫助開(kāi)發(fā)人員了解框架的設(shè)計(jì)。

接下來(lái)呢,我們將介紹 Spring 框架中使用的四種最常見(jiàn)的設(shè)計(jì)模式:

  • Singleton pattern 單例模式
  • Factory Method pattern 工廠方法模式
  • Proxy pattern 代理模式
  • Template pattern 模板模式

我們還將研究 Spring 如何使用這些模式來(lái)減輕開(kāi)發(fā)人員的負(fù)擔(dān)并幫助用戶(hù)快速執(zhí)行繁瑣的任務(wù)。

2、單例模式(Singleton Pattern)

單一實(shí)例模式是一種機(jī)制,可確保每個(gè)應(yīng)用程序僅存在對(duì)象的一個(gè)實(shí)例。在管理共享資源或提供橫切服務(wù)(如日志記錄)時(shí),此模式非常有用。

2.1 單例 Beans(Singleton Beans)

通常,單例對(duì)于應(yīng)用程序是全局唯一的,但在 Spring 中,此約束是寬松的。相反,Spring 將單個(gè)實(shí)例限制為每個(gè) Spring IoC 容器一個(gè)對(duì)象。在實(shí)踐中,這意味著 Spring 只會(huì)為每個(gè)應(yīng)用程序上下文的每種類(lèi)型創(chuàng)建一個(gè) bean。

Spring 的方法與單例的嚴(yán)格定義不同,因?yàn)橐粋€(gè)應(yīng)用程序可以有多個(gè) Spring 容器。因此,如果我們有多個(gè)容器,則同一類(lèi)的多個(gè)對(duì)象可以存在于單個(gè)應(yīng)用程序中。

Singleton

默認(rèn)情況下,Spring 將所有 bean 創(chuàng)建為單例。

2.2 自動(dòng)注入單例(Autowired Singletons)

例如,我們可以在單個(gè)應(yīng)用程序上下文中創(chuàng)建兩個(gè)控制器,并將相同類(lèi)型的 bean 注入到每個(gè)控制器中。

首先,我們創(chuàng)建一個(gè) BookRepository 來(lái)管理我們的 Book 域?qū)ο蟆?/p>

接下來(lái),我們創(chuàng)建 LibraryController,它使用 BookRepository 返回庫(kù)中的書(shū)籍?dāng)?shù)量:

@RestController
public class LibraryController {
    @Autowired
    private BookRepository repository;
    @GetMapping("/count")
    public Long findCount() {
        System.out.println(repository);
        return repository.count();
    }
}

最后,我們創(chuàng)建一個(gè) BookController,它專(zhuān)注于特定于書(shū)籍的操作,例如按 ID 查找書(shū)籍:

@RestController
public class BookController {
    @Autowired
    private BookRepository repository;
    @GetMapping("/book/{id}")
    public Book findById(@PathVariable long id) {
        System.out.println(repository);
        return repository.findById(id).get();
    }
}

然后我們啟動(dòng)這個(gè)應(yīng)用程序,并對(duì) /count 和 /book/1 執(zhí)行 GET 請(qǐng)求訪問(wèn):

curl -X GET http://localhost:8080/count
curl -X GET http://localhost:8080/book/1

在應(yīng)用程序輸出中,我們看到兩個(gè) BookRepository 對(duì)象具有相同的對(duì)象 ID:

com.baeldung.spring.patterns.singleton.BookRepository@3ea9524f
com.baeldung.spring.patterns.singleton.BookRepository@3ea9524f

LibraryController 和 BookController 中的 BookRepository 對(duì)象 ID 是相同的,這證明 Spring 將相同的 bean 注入到兩個(gè)控制器中。

我們可以通過(guò)使用 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) 注釋將 bean 范圍從單例更改為原型來(lái)創(chuàng)建 BookRepository bean 的單獨(dú)實(shí)例。

這樣做會(huì)指示 Spring 為它創(chuàng)建的每個(gè) BookRepository bean 創(chuàng)建單獨(dú)的對(duì)象。因此,如果我們?cè)俅螜z查每個(gè)控制器中 BookRepository 的對(duì)象 ID,我們會(huì)發(fā)現(xiàn)它們不再相同。

3、工廠方法模式(Factory Method Pattern)

工廠方法模式需要一個(gè)工廠類(lèi),其中包含用于創(chuàng)建所需對(duì)象的抽象方法。

通常,我們希望根據(jù)特定的上下文創(chuàng)建不同的對(duì)象。

例如,我們的應(yīng)用程序可能需要車(chē)輛對(duì)象。在航海環(huán)境中,我們想制造船只,但在航空航天環(huán)境中,我們想制造飛機(jī):

Factory pattern

為此,我們可以為每個(gè)所需對(duì)象創(chuàng)建一個(gè)工廠實(shí)現(xiàn),并從具體的工廠方法返回所需的對(duì)象。

3.1 應(yīng)用上下文(Application Context)

Spring 在其依賴(lài)注入(DI)框架的根中使用這種技術(shù)。

從根本上說(shuō),Spring 將 Bean 容器視為生產(chǎn) Beans 的工廠。

因此,Spring 將 BeanFactory 接口定義為 bean 容器的抽象:

public interface BeanFactory {
    getBean(Class<T> requiredType);
    getBean(Class<T> requiredType, Object... args);
    getBean(String name);
    // ...
}

每個(gè) getBean 方法都被視為工廠方法,它返回與提供給該方法的條件匹配的 Bean,例如 Bean 的類(lèi)型和名稱(chēng)。

然后,Spring 使用 ApplicationContext 接口擴(kuò)展了 BeanFactory,該接口引入了額外的應(yīng)用程序配置。Spring 使用此配置根據(jù)某些外部配置(例如 XML 文件或 Java 注釋?zhuān)﹩?dòng) Bean 容器。

使用 ApplicationContext 類(lèi)實(shí)現(xiàn)(如 AnnotationConfigApplicationContext),我們可以通過(guò)從 BeanFactory 接口繼承的各種工廠方法創(chuàng)建 bean。

首先,我們創(chuàng)建一個(gè)簡(jiǎn)單的應(yīng)用程序配置:

@Configuration
@ComponentScan(basePackageClasses = ApplicationConfig.class)
public class ApplicationConfig {
}

接下來(lái),我們創(chuàng)建一個(gè)簡(jiǎn)單的類(lèi) Foo,它不接受構(gòu)造函數(shù)參數(shù):

@Component
public class Foo {
}

然后創(chuàng)建另一個(gè)接受單個(gè)構(gòu)造函數(shù)參數(shù)的類(lèi) Bar:

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Bar {
    private String name;
    public Bar(String name) {
        this.name = name;
    }
    // Getter ...
}

最后,我們通過(guò) ApplicationContext 的 AnnotationConfigApplicationContext 實(shí)現(xiàn)創(chuàng)建我們的 bean:

@Test
public void whenGetSimpleBean_thenReturnConstructedBean() {
    ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
    Foo foo = context.getBean(Foo.class);
    assertNotNull(foo);
}
@Test
public void whenGetPrototypeBean_thenReturnConstructedBean() {
    String expectedName = "Some name";
    ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
    Bar bar = context.getBean(Bar.class, expectedName);
    assertNotNull(bar);
    assertThat(bar.getName(), is(expectedName));
}

使用 getBean 工廠方法,我們可以?xún)H使用類(lèi)類(lèi)型和(在 Bar 的情況下)構(gòu)造函數(shù)參數(shù)來(lái)創(chuàng)建配置的 bean。

3.2 外部配置(External Configuration)

此模式是通用的,因?yàn)槲覀兛梢愿鶕?jù)外部配置完全更改應(yīng)用程序的行為。

如果我們希望更改應(yīng)用程序中自動(dòng)連線對(duì)象的實(shí)現(xiàn),我們可以調(diào)整我們使用的 ApplicationContext 實(shí)現(xiàn)。

Factory 1

例如,我們可以將 AnnotationConfigApplicationContext 更改為基于 XML 的配置類(lèi),例如 ClassPathXmlApplicationContext:

@Test 
public void givenXmlConfiguration_whenGetPrototypeBean_thenReturnConstructedBean() { 
    String expectedName = "Some name";
    ApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
    // Same test as before ...
}

4、代理模式(Proxy Pattern)

代理在我們的數(shù)字世界中是一種方便的工具,我們經(jīng)常在軟件(例如網(wǎng)絡(luò)代理)之外使用它們。在代碼中,代理模式是一種技術(shù),它允許一個(gè)對(duì)象(代理)控制對(duì)另一個(gè)對(duì)象(主體或服務(wù))的訪問(wèn)。

Proxy class diagram

4.1 事務(wù)

為了創(chuàng)建代理,我們創(chuàng)建一個(gè)對(duì)象,該對(duì)象實(shí)現(xiàn)與我們的主題相同的接口,并包含對(duì)主題的引用。

然后,我們可以使用代理代替主題。

在 Spring 里,bean 被代理以控制對(duì)底層 bean 的訪問(wèn)。我們?cè)谑褂檬聞?wù)時(shí)看到這種方法:

@Service
public class BookManager {
    @Autowired
    private BookRepository repository;
    @Transactional
    public Book create(String author) {
        System.out.println(repository.getClass().getName());
        return repository.create(author);
    }
}

在我們的 BookManager 類(lèi)中,我們使用 @Transactional 注釋注釋創(chuàng)建方法。這個(gè)注釋指示 Spring 原子地執(zhí)行我們的創(chuàng)建方法。如果沒(méi)有代理,Spring 將無(wú)法控制對(duì) BookRepository bean 的訪問(wèn)并確保其事務(wù)一致性。

4.2 CGLib 代理(CGLib Proxies)

相反,Spring 創(chuàng)建了一個(gè)代理來(lái)包裝我們的 BookRepository bean,并檢測(cè)我們的 bean 以原子方式執(zhí)行我們的 create 方法。

當(dāng)我們調(diào)用 BookManager#create 方法時(shí),我們可以看到輸出:

com.baeldung.patterns.proxy.BookRepository$$EnhancerBySpringCGLIB$$3dc2b55c

通常,我們希望看到一個(gè)標(biāo)準(zhǔn)的 BookRepository 對(duì)象 ID;相反,我們看到一個(gè) EnhancerBySpringCGLIB 對(duì)象 ID。

在底層,Spring 將我們的 BookRepository 對(duì)象包裝在里面作為 EnhancerBySpringCGLIB 對(duì)象。因此,Spring 控制了對(duì) BookRepository 對(duì)象的訪問(wèn)(確保事務(wù)一致性)。

Proxy

通常,Spring 使用兩種類(lèi)型的代理:

  • CGLib 代理 – 在代理類(lèi)時(shí)使用;
  • JDK 動(dòng)態(tài)代理 – 在代理接口時(shí)使用

雖然我們使用事務(wù)來(lái)公開(kāi)底層代理,但 Spring 將在必須控制對(duì) bean 的訪問(wèn)的任何場(chǎng)景中使用代理。

5、模版方法模式(Template Method Pattern)

在許多框架中,代碼的很大一部分是樣板代碼。

例如,在數(shù)據(jù)庫(kù)上執(zhí)行查詢(xún)時(shí),必須完成相同的一系列步驟:

  • Establish a connection 建立連接
  • Execute query 執(zhí)行查詢(xún)
  • Perform cleanup 執(zhí)行清理
  • Close the connection 關(guān)閉連接

這些步驟是模板方法模式的理想方案。

5.1 模版和回調(diào)(Templates & Callbacks)

模板方法模式是一種技術(shù),用于定義某些操作所需的步驟,實(shí)現(xiàn)樣板步驟,并將可自定義的步驟保留為抽象。然后,子類(lèi)可以實(shí)現(xiàn)此抽象類(lèi),并為缺少的步驟提供具體的實(shí)現(xiàn)。

我們可以在數(shù)據(jù)庫(kù)查詢(xún)的情況下創(chuàng)建一個(gè)模板:

public abstract DatabaseQuery {
    public void execute() {
        Connection connection = createConnection();
        executeQuery(connection);
        closeConnection(connection);
    } 
    protected Connection createConnection() {
        // Connect to database...
    }
    protected void closeConnection(Connection connection) {
        // Close connection...
    }
    protected abstract void executeQuery(Connection connection);
}

或者,我們可以通過(guò)提供回調(diào)方法來(lái)提供缺失的步驟。

回調(diào)方法是一種方法,它允許主體向客戶(hù)端發(fā)出信號(hào),表明某些所需的操作已完成。

在某些情況下,主體可以使用此回調(diào)來(lái)執(zhí)行操作,例如映射結(jié)果。

Template

例如,我們可以為執(zhí)行方法提供一個(gè)查詢(xún)字符串和一個(gè)回調(diào)方法來(lái)處理結(jié)果,而不是一個(gè) executeQuery 方法。

首先,我們創(chuàng)建一個(gè)回調(diào)方法,該方法采用 Result 對(duì)象并將其映射到 T 類(lèi)型的對(duì)象:

public interface ResultsMapper<T> {
    public T map(Results results);
}

然后我們更改我們的 DatabaseQuery 類(lèi)以利用此回調(diào):

public abstract DatabaseQuery {
    public <T> T execute(String query, ResultsMapper<T> mapper) {
        Connection connection = createConnection();
        Results results = executeQuery(connection, query);
        closeConnection(connection);
        return mapper.map(results);
    ]
    protected Results executeQuery(Connection connection, String query) {
        // Perform query...
    }
}

這種回調(diào)機(jī)制正是 Spring 在 JdbcTemplate 類(lèi)中使用的方法。

5.2 JDBC 模版(JdbcTemplates)

JdbcTemplate 類(lèi)提供查詢(xún)方法,該方法接受查詢(xún)字符串和 ResultSetExtractor 對(duì)象:

public class JdbcTemplate {
    public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException {
        // Execute query...
    }
    // Other methods...
}

ResultSetExtractor 將 ResultSet 對(duì)象(表示查詢(xún)結(jié)果)轉(zhuǎn)換為類(lèi)型 T 的域?qū)ο螅?/p>

@FunctionalInterface
public interface ResultSetExtractor<T> {
    T extractData(ResultSet rs) throws SQLException, DataAccessException;
}

Spring 通過(guò)創(chuàng)建更具體的回調(diào)接口進(jìn)一步減少了樣板代碼。

例如,RowMapper 接口用于將單行 SQL 數(shù)據(jù)轉(zhuǎn)換為 T 類(lèi)型的域?qū)ο蟆?/p>

@FunctionalInterface
public interface RowMapper<T> {
    T mapRow(ResultSet rs, int rowNum) throws SQLException;
}

為了使 RowMapper 接口適應(yīng)預(yù)期的 ResultSetExtractor,Spring 創(chuàng)建了 RowMapperResultSetExtractor 類(lèi):

public class JdbcTemplate {
    public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException {
        return result(query(sql, new RowMapperResultSetExtractor<>(rowMapper)));
    }
    // Other methods...
}

我們可以提供如何轉(zhuǎn)換單個(gè)行的邏輯,而不是提供轉(zhuǎn)換整個(gè) ResultSet 對(duì)象的邏輯,包括對(duì)行的迭代:

public class BookRowMapper implements RowMapper<Book> {
    @Override
    public Book mapRow(ResultSet rs, int rowNum) throws SQLException {
        Book book = new Book();
        book.setId(rs.getLong("id"));
        book.setTitle(rs.getString("title"));
        book.setAuthor(rs.getString("author"));
        return book;
    }
}

使用此轉(zhuǎn)換器,我們可以使用 JdbcTemplate 查詢(xún)數(shù)據(jù)庫(kù)并映射每個(gè)結(jié)果行:

JdbcTemplate template = // create template...
template.query("SELECT * FROM books", new BookRowMapper());

除了JDBC數(shù)據(jù)庫(kù)管理之外,Spring 還使用模板:

  • Java Message Service (JMS)
  • Java Persistence API (JPA)
  • Hibernate(現(xiàn)已棄用)
  • Transactions 事務(wù)

6、結(jié)論

上面,我們研究了 Spring 框架中應(yīng)用的四種最常見(jiàn)的設(shè)計(jì)模式。

我們還探討了Spring如何利用這些模式來(lái)提供豐富的功能,同時(shí)減輕開(kāi)發(fā)人員的負(fù)擔(dān)。

到此這篇關(guān)于Spring Framework六種常見(jiàn)設(shè)計(jì)模式的文章就介紹到這了,更多相關(guān)Spring設(shè)計(jì)模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Windows?10卸載JDK1.8超詳細(xì)圖文教程

    Windows?10卸載JDK1.8超詳細(xì)圖文教程

    這篇文章主要介紹了Windows?10卸載JDK1.8超詳細(xì)圖文教程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03
  • MyBatis高級(jí)映射ResultMap解決屬性問(wèn)題

    MyBatis高級(jí)映射ResultMap解決屬性問(wèn)題

    對(duì)于數(shù)據(jù)庫(kù)中對(duì)表的增刪改查操作,我們知道增刪改都涉及的是單表,而只有查詢(xún)操作既可以設(shè)計(jì)到單表操作又可以涉及到多表操作,所以對(duì)于輸入映射parameterType而言是沒(méi)有所謂的高級(jí)映射的,也就是說(shuō)高級(jí)映射只針對(duì)于輸出映射
    2023-02-02
  • Json字符串轉(zhuǎn)Java對(duì)象和List代碼實(shí)例

    Json字符串轉(zhuǎn)Java對(duì)象和List代碼實(shí)例

    這篇文章主要介紹了Json字符串轉(zhuǎn)Java對(duì)象和List代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Java整合Jackson實(shí)現(xiàn)反序列化器流程

    Java整合Jackson實(shí)現(xiàn)反序列化器流程

    Jackson是一個(gè)開(kāi)源的Java序列化和反序列化工具,可以將Java對(duì)象序列化為XML或JSON格式的字符串,以及將XML或JSON格式的字符串反序列化為Java對(duì)象。由于其使用簡(jiǎn)單,速度較快,且不依靠除JDK外的其他庫(kù),被眾多用戶(hù)所使用
    2023-01-01
  • IDEA無(wú)法創(chuàng)建JDK1.8版本的Springboot項(xiàng)目問(wèn)題解決(2種方法)

    IDEA無(wú)法創(chuàng)建JDK1.8版本的Springboot項(xiàng)目問(wèn)題解決(2種方法)

    本文主要介紹了IDEA無(wú)法創(chuàng)建JDK1.8版本的Springboot項(xiàng)目問(wèn)題解決,包含兩種解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-07-07
  • Springboot常用注解及配置文件加載順序詳解

    Springboot常用注解及配置文件加載順序詳解

    這篇文章主要介紹了Springboot常用注解及配置文件加載順序,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-11-11
  • ThreadLocal內(nèi)存泄漏常見(jiàn)要點(diǎn)解析

    ThreadLocal內(nèi)存泄漏常見(jiàn)要點(diǎn)解析

    這篇文章主要介紹了ThreadLocal內(nèi)存泄漏常見(jiàn)要點(diǎn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11
  • SpringBoot導(dǎo)入Druid運(yùn)行失敗問(wèn)題

    SpringBoot導(dǎo)入Druid運(yùn)行失敗問(wèn)題

    這篇文章主要介紹了SpringBoot導(dǎo)入Druid運(yùn)行失敗,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • SpringBoot利用ThreadPoolTaskExecutor批量插入百萬(wàn)級(jí)數(shù)據(jù)

    SpringBoot利用ThreadPoolTaskExecutor批量插入百萬(wàn)級(jí)數(shù)據(jù)

    在處理大量數(shù)據(jù)時(shí),為了提高效率和性能,通常需要采用批量插入的方式,本文主要介紹了SpringBoot利用ThreadPoolTaskExecutor批量插入百萬(wàn)級(jí)數(shù)據(jù),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • SpringBoot 統(tǒng)一請(qǐng)求返回的實(shí)現(xiàn)

    SpringBoot 統(tǒng)一請(qǐng)求返回的實(shí)現(xiàn)

    這篇文章主要介紹了SpringBoot 統(tǒng)一請(qǐng)求返回的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07

最新評(píng)論