第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定
2.5 href 屬性

定義超鏈接的跳轉(zhuǎn)目標,可以是:絕對 URL: 例如 http://www.baidu.com;相對 URL: 例如 /index.html;錨點 : dom 的 id;JavaScript 表達式:例如 javascript:void(0) 阻止鏈接跳轉(zhuǎn)。955以上代碼定義了幾種鏈接的方式,其中錨點主要應(yīng)用于當頁面滾動條比較長時,用戶可以點擊跳轉(zhuǎn)到首部。

6. Content-MD5

告訴客戶端響應(yīng)內(nèi)容按照 MD5 簽名后的值是什么,客戶端根據(jù)返回內(nèi)容也按照MD5算法生產(chǎn)一個 MD5值。如果兩者的值一樣證明傳輸過程中 Http 的內(nèi)容沒有被篡改過,否則就代表內(nèi)容可能被人偽造過,是不可信的。

2.5 服務(wù)提供者上下線測試

首先我們來測試服務(wù)下線的情況,服務(wù)提供者下線分為兩種情況,一種是服務(wù)出現(xiàn)故障,與 Zookeeper 服務(wù)端斷開連接時,另一種是業(yè)務(wù)需求手動對服務(wù)進行下線處理。服務(wù)停機我們先來測試服務(wù)停機時的情況,這里我們手動關(guān)閉端口為 8092 的服務(wù),模擬服務(wù)停機,等待會話超時,Zookeeper 服務(wù)端就會移除會話失效的臨時節(jié)點,然后再次訪問服務(wù)消費者的接口 http://localhost:9090/consumer/callMethod :調(diào)用了服務(wù)提供者 192.168.0.102:8090 的方法刷新頁面,再次訪問:調(diào)用了服務(wù)提供者 192.168.0.102:8091 的方法再次刷新頁面進行訪問:調(diào)用了服務(wù)提供者 192.168.0.102:8090 的方法我們發(fā)現(xiàn)端口為 8092 的服務(wù)已經(jīng)無法被訪問了,但是服務(wù)消費者并沒有發(fā)生異常,說明服務(wù)下線成功。這里我們還可以在節(jié)點監(jiān)聽的回掉方法中發(fā)送短信或郵件通知系統(tǒng)管理員,提醒他們服務(wù)下線了。接下來我們測試手動把服務(wù)提供者下線的情況。手動下線如果某個服務(wù)需要手動下線,我們就可以訪問我們在服務(wù)提供者中提供的下線方法,這里我們把端口為 8091 的服務(wù)下線,訪問 http://localhost:8091/provider/offline ,查看瀏覽器:>>> 服務(wù)提供者 192.168.0.102:8091 已下線我們發(fā)現(xiàn)端口為 8091 的服務(wù)已經(jīng)下線了,手動下線的情況我們不需要等待會話超時,因為這個會話還存活著,接下來我們就可以再次訪問服務(wù)消費者的接口 http://localhost:9090/consumer/callMethod :調(diào)用了服務(wù)提供者 192.168.0.102:8090 的方法我們發(fā)現(xiàn)現(xiàn)在只有端口為 8090 的服務(wù)能提供服務(wù)了,說明服務(wù)下線成功了。測試完服務(wù)下線的情況,我們來對服務(wù)進行上線測試,上線也同樣分為兩種情況,一種是停機的服務(wù)重新啟動成功時會注冊自身的地址到 Zookeeper 服務(wù),另一種是把手動下線的服務(wù)手動進行上線,手動上線的過程同樣是注冊自身的地址信息到 Zookeeper 服務(wù),接下來我們就同時測試上面兩種服務(wù)上線的情況。服務(wù)啟動 + 手動上線首先我們啟動上面停機的 8092 服務(wù),然后調(diào)用端口為 8091 的手動上線方法 http://localhost:8091/provider/online ,執(zhí)行完成后,我們就可以使用服務(wù)消費著來進行測試了,調(diào)用服務(wù)消費者的接口 http://localhost:9090/consumer/callMethod 查看瀏覽器內(nèi)容:調(diào)用了服務(wù)提供者 192.168.0.102:8090 的方法刷新頁面,再次訪問:調(diào)用了服務(wù)提供者 192.168.0.102:8091 的方法再次刷新頁面進行訪問:調(diào)用了服務(wù)提供者 192.168.0.102:8092 的方法我們可以發(fā)現(xiàn),服務(wù)消費者依次調(diào)用了 8090 ,8091 ,8092 這 3 個服務(wù)提供者的方法,并且實現(xiàn)了輪詢的負載均衡策略,說明我們的服務(wù)上線成功

4.2 布局文件編寫

我們希望能夠隨時控制播放器的起播和停止,所以需要兩個 Button 分別進行控制:<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/buttonStart" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_marginTop="74dp" android:text="啟動播放器" /> <Button android:id="@+id/buttonStop" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:text="停止播放" /></RelativeLayout>

3.3 后端服務(wù) <a href="http://app.py">app.py</a>

#!/usr/bin/python3from flask import Flask, render_templateapp = Flask(__name__)@app.route('/')def index(): return render_template('index.html')if __name__ == '__main__': app.run(debug = True, port = 4444)在第 5 行,訪問頁面 / 時,服務(wù)端返回頁面模板 index.html;在第 10 行,在端口號 4444 上進行監(jiān)聽。

<a href="http://5.IS">5.IS</a> NULL 查詢

為了演示方便,我們先給 teacher 表增加一個字段 email:ALTER TABLE `item_name`.`teacher` ADD COLUMN `email` varchar(50) NULL AFTER `id_number`;執(zhí)行結(jié)果如下圖:清空表數(shù)據(jù):TRUNCATE TABLE teacher;然后往 teacher 表插入幾條測試數(shù)據(jù):INSERT INTO teacher(name,age,id_number,email)VALUES('姓名甲',19,'42011720200604077X',NULL),('姓名乙',18,'42011720200604099X','123@qq.com'),('姓名丙',20,'42011720200604020X',NULL),('姓名丁',21,'42011720200604022X','345@qq.com'),('姓名戊',22,'42011720200604033X',NULL)然后查詢 email 為 NULL 的教師信息結(jié)果集:SELECT * FROM teacher WHERE email IS NULL;執(zhí)行結(jié)果如下圖:

3. 后端程序 <a href="http://app.py">app.py</a>

服務(wù)端程序 app.py 提供操作 Session 的功能,程序代碼分為如下部分:

1. Nginx 的進程模型

前面介紹 Nginx 時有介紹過 Nginx 的進程模型。Nginx 啟動時首先啟動一個 Master 進程,然后由 Master 進程啟動一個或者多個 Worker 子進程。Master 進程主要完成配置讀取,通過發(fā)送信號控制 Worker 進程的啟動和停止等,而 Worker 子進程是用來處理客戶端發(fā)來的 Http 請求,且Worker進程之間會通過共享內(nèi)存進行通信。

3. 場景及應(yīng)用實例

對一篇文章來說,分割線多見于標題與正文間的分隔。防止內(nèi)容過于緊湊,反而無法突出重點;不同內(nèi)容間的分隔。當我們文章包含多個關(guān)聯(lián)性較小的主題時,可以用分割線來區(qū)分,這種情況在各大問答平臺上很常見,比如:~~~~~~~~~~華麗的分割線~~~~~~~~~~實例 5:如何用分割線區(qū)分不同內(nèi)容主體,來源:人民日報 (節(jié)選)# 科普也要創(chuàng)新林群 2019年12月19日08:13 來源:人民網(wǎng)-人民日報___  什么叫科普?一次我開會乘坐出租車,司機問我:“您這么大年紀了,不在家?guī)O輩,還到處跑,是做什么工作的?”我說:“做數(shù)學的?!毕氩坏剿⒓幢某鲆痪洌骸芭?,0.618?!薄 ?..  所以,做科普也可以創(chuàng)新,和做科研一樣?! 《 人民日報 》( 2019年12月19日 19 版)____相關(guān)新聞:- [全國科學傳播發(fā)展指數(shù)報告出爐](http://scitech.people.com.cn/n1/2019/0603/c1007-31116146.html)- [科學家為啥不愛做科普](http://scitech.people.com.cn/n1/2017/0307/c1007-29129143.html)渲染結(jié)果如下:

406 Not Acceptable

指定的資源已經(jīng)找到,但它的媒體類型和客戶在Accpet頭中所指定的不兼容,客戶端瀏覽器不接受所請求頁面的媒體類型??蛻舳苏埱笠粋€ Json 格式內(nèi)容GET /foo HTTP/1.1Accept: application/jsonAccept-Language: fr-CA; q=1, fr; q=0.8 服務(wù)端不支持 JsonHTTP/1.1 406 Not AcceptableServer: curveball/0.4Content-Type: text/html

3.1 創(chuàng)建 Spring Boot web 服務(wù)端應(yīng)用

工程目錄結(jié)構(gòu)如下:? OAuth2AuthorizationServer/ ? src/ ? main/ ? java/imooc/springsecurity/oauth2/server/ ? config/ OAuth2ServerConfiguration.java # OAuth2 相關(guān)配置類 UserConfiguration.java # 基礎(chǔ)認證配置類,用于配置用戶信息 OAuth2AuthorizationServerApplication.java # 程序入口 ? resources/ application.properties # 配置文件,本例中無特殊配置 ? test/java/ pom.xml在 pom.xml 文件中增加依賴項,相比「用戶名密碼認證實例」,此處注意添加了 OAuth2 自動配置的相關(guān)依賴。spring-security-oauth2-autoconfigure。完整 pom.xml 文件如下:<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>imooc.springsecurity</groupId> <artifactId>OAuth2AuthorizationServerSample</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>2.3.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>創(chuàng)建 SpringSecurity OAuth2 配置類: OAuth2ServerConfiguration.java。src/ main/ java/ imooc/ springsecurity/ oauth2/ server/ OAuth2ServerConfiguration.java使其繼承 org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter 類,并其增加 @EnableAuthorizationServer 標簽,以聲明此類作為 OAuth2 認證服務(wù)器的配置依據(jù);在 configure(AuthorizationServerEndpointsConfigurer endpoints) 方法中配置其 TokenStore,為了便于演示,此例中 TokenStore 采用內(nèi)存形式,賬戶信息寫死在代碼中;在 configure(ClientDetailsServiceConfigurer clients) 方法中為 OAuth2 認證服務(wù)器設(shè)置可用于認證的客戶端信息。完整代碼如下:package imooc.springsecurity.oauth2.server.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.authentication.AuthenticationManager;import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;import org.springframework.security.oauth2.provider.token.TokenStore;import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;@EnableAuthorizationServer@Configurationpublic class OAuth2ServerConfiguration extends AuthorizationServerConfigurerAdapter { private AuthenticationManager authenticationManager; public OAuth2ServerConfiguration( AuthenticationConfiguration authenticationConfiguration) throws Exception { this.authenticationManager = authenticationConfiguration.getAuthenticationManager(); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { // 配置授信客戶端信息 clients.inMemory() // 內(nèi)存模式 .withClient("reader") // 第一個客戶端用戶,其名稱為「reader」 .authorizedGrantTypes("password") // 授權(quán)模式為「password」 .secret("{noop}secret") // 認證密碼為「secret」,加密方式為「NoOp」 .scopes("message:read") // 權(quán)限的使用范圍 .accessTokenValiditySeconds(600_000_000) // 票據(jù)有效期 .and() // 增加第二個授權(quán)客戶端,設(shè)置方法一致,但擁有不同的范圍權(quán)限 .withClient("writer") .authorizedGrantTypes("password") .secret("{noop}secret") .scopes("message:write") .accessTokenValiditySeconds(600_000_000); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { endpoints .authenticationManager(this.authenticationManager) .tokenStore(tokenStore()); // 使用虛機內(nèi)存存儲票據(jù)信息,也可替換成 Mysql、Redis 等。 } @Bean public TokenStore tokenStore() { return new InMemoryTokenStore(); }}除了設(shè)置授權(quán)客戶端之外,還要增加客戶端中被授權(quán)的用戶。創(chuàng)建類 UserConfiguration.javasrc/ main/ java/ imooc/ springsecurity/ oauth2/ server/ UserConfiguration.java并在其中配置用戶信息。package imooc.springsecurity.oauth2.server.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.core.userdetails.User;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.provisioning.InMemoryUserDetailsManager;@Configurationpublic class UserConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() // 任何地址都受到保護,需要首先認證 .and() .httpBasic() // 支持基本認證,因為 OAuth2 認證往往用于不同種類客戶端,所以基本認證支持是必要的。 .and() .csrf().disable(); } @Bean @Override public UserDetailsService userDetailsService() { InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager(); inMemoryUserDetailsManager.createUser(User.withUsername("admin").password("$2a$10$sR.KWdKOWYseh0KVHHnzMOveh/S7wvOkd.JrTyP2AzHhEcCSZfAmK").roles("USER").build()); // 用戶名: admin; 密碼: 123456 return inMemoryUserDetailsManager; }}

2.1 TemplateResponse 和 SimpleTemplateResponse

很早之前,我們介紹過 HttpResponse,它用于生成 HTTP 請求的相應(yīng),返回的內(nèi)容由 content 屬性確定,主要是用于提供靜態(tài)內(nèi)容顯示。TemplateResponse 對象則不同,它允許裝飾器或中間件在通過視圖構(gòu)造響應(yīng)之后修改響應(yīng)內(nèi)容。TemplateResponse 對象保留視圖提供的、用于計算響應(yīng)內(nèi)容的模板和上下文數(shù)據(jù),直到最后需要時才計算相應(yīng)內(nèi)容并返回響應(yīng)。SimpleTemplateResponse 對象是 TemplateResponse 的父類,兩者功能和使用基本類似,幾乎是一致的。# 源碼位置: django/template/response.pyclass TemplateResponse(SimpleTemplateResponse): rendering_attrs = SimpleTemplateResponse.rendering_attrs + ['_request'] def __init__(self, request, template, context=None, content_type=None, status=None, charset=None, using=None): super().__init__(template, context, content_type, status, charset, using) self._request = requestSimpleTemplateResponse 是繼承自 HttpResponse 對象,并做了諸多擴展。它的重要屬性和方法如下:重要屬性:template_name:模板文件名;context_data : 上下文字典數(shù)據(jù);rendered_content:指使用當前的模板和上下文字段數(shù)據(jù)已渲染的響應(yīng)內(nèi)容。一個作為屬性的方法,調(diào)用該屬性時啟動渲染過程;is_rendered: 布爾類型,判斷響應(yīng)內(nèi)容是否已經(jīng)被渲染。重要方法:__init__(template, context=None, content_type=None, status=None, charset=None, using=None):類初始化函數(shù),各參數(shù)的含義與 HttpResponse 相同;resolve_context(context):預(yù)處理會被用于模板渲染的上下文數(shù)據(jù) ;resolve_template(template):接收(如由 get_template() 返回的) backend-dependent 的模板對象、模板名字、或者多個模板名字組成的列表。返回 backend-dependent 的模板對象實例,后面用于渲染;add_post_render_callback():添加渲染完成后的回調(diào)函數(shù),如果該方法運行時渲染已完成,回調(diào)函數(shù)會被立即調(diào)用;render():設(shè)置 response.content 的結(jié)果為 SimpleTemplateResponse.rendered_content 的值,執(zhí)行所有渲染后的回調(diào)函數(shù),返回所有響應(yīng)對象。render() 只會在第一次調(diào)用時起作用。在隨后的調(diào)用中,它將返回從第一個調(diào)用獲得的結(jié)果。實驗部分:我們來使用 TemplateResponse 來完成一個簡單的案例。同樣是在 first_django_app 工程中,準備的代碼內(nèi)容參考如下,分別是模板文件、視圖文件以及 URLConf 配置文件。# 模板文件: template/test.html<p>{{ content }}</p><div>{{ spyinx.age }}</div># URLConf配置文件: hello_app/urls.pyurlpatterns = [ path('test-cbv/', views.TestView.as_view(), name="test-cbv")]# 視圖文件: hello_app/views.pydef my_render_callback(response): # Do content-sensitive processing print('執(zhí)行渲染完成后的回調(diào)函數(shù),渲染內(nèi)容:\n{}\n是否完成渲染:{}'.format(response.rendered_content, response.is_rendered))class TestView(View): def get(self, request, *args, **kwargs): response = TemplateResponse(request, 'test.html', context={'content': '正文1', 'spyinx':{'age': 29}}) response.add_post_render_callback(my_render_callback) return response我們在云主機上使用 curl 命令發(fā)送 HTTP 請求,觀察結(jié)果:# 使用runserver命令啟動first_django_app工程...# 打開另一個xshell窗口,使用curl命令發(fā)送請求結(jié)果[root@server ~]# curl http://127.0.0.1:8888/hello/test-cbv/<p>正文1</p><div>29</div># 回到上一個窗口,查看打印結(jié)果(django-manual) [root@server first_django_app]# python manage.py runserver 0.0.0.0:8888Watching for file changes with StatReloaderPerforming system checks...System check identified no issues (0 silenced).April 16, 2020 - 07:10:18Django version 2.2.11, using settings 'first_django_app.settings'Starting development server at http://0.0.0.0:8888/Quit the server with CONTROL-C.執(zhí)行渲染完成后的回調(diào)函數(shù),渲染內(nèi)容:<p>正文1</p><div>29</div>是否完成渲染:True[16/Apr/2020 07:10:38] "GET /hello/test-cbv/ HTTP/1.1" 200 29

2.1 服務(wù)提供者

首先我們新建服務(wù)提供者項目,我們選擇 Spring Initializr 來初始化 Spring Boot 項目,這是服務(wù)提供者的項目信息。pom.xml初始化完成,在 pom.xml 中加入項目所需的依賴。<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>cn.cdd</groupId> <artifactId>zookeeper-provider</artifactId> <version>0.0.1-SNAPSHOT</version> <name>zookeeper-provider</name> <description>zookeeper-providerDemo project for Spring Boot</description> <properties> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- curator 客戶端 --> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>5.1.0</version> </dependency> <!-- curator 客戶端 --> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>5.1.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>依賴導入完成后,我們在 application.properties 配置文件中加入端口的配置。application.propertiesserver.port=8090接下來開始編寫服務(wù)提供者的接口。ProviderService我們在 Spring Boot 主類的同級新建 service 目錄,在 service 目錄中新建 ProviderService 類。package cn.cdd.zookeeper.provider.service;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Service;import java.net.InetAddress;import java.net.UnknownHostException;@Servicepublic class ProviderService { @Value("${server.port}") private String port; public String callMethod(){ try { return "調(diào)用了服務(wù)提供者 " + InetAddress.getLocalHost().getHostAddress() + ":" + port + " 的方法"; } catch (UnknownHostException e) { e.printStackTrace(); } return null; }}接下來編寫使用 Curator 連接 Zookeeper 服務(wù)的代碼。CuratorService在 service 目錄下新建 CuratorService 類:@Componentpublic class CuratorService implements ApplicationRunner { @Value("${server.port}") private String port; // CuratorFramework 客戶端 private static CuratorFramework client; // 服務(wù)地址臨時節(jié)點的父節(jié)點 private static final String PROVIDER_NODE = "/imooc/provider"; // 服務(wù)地址臨時節(jié)點的全路徑 private static String PROVIDER_ADDRESS; // 服務(wù) ip private static String PROVIDER_IP; @Override public void run(ApplicationArguments args) throws Exception { // 獲取客戶端,連接 Zookeeper 服務(wù) buildCuratorClient(); // 獲取本機 IP PROVIDER_IP = InetAddress.getLocalHost().getHostAddress(); // 注冊本機地址到 Zookeeper registeredAddress(); } /** * 構(gòu)建 CuratorFramework 客戶端,并開啟會話 */ private void buildCuratorClient() { // 使用 CuratorFrameworkFactory 構(gòu)建 CuratorFramework client = CuratorFrameworkFactory.builder() .sessionTimeoutMs(10000) // Zookeeper 地址 .connectString("127.0.0.1:2181") // 重連策略 .retryPolicy(new RetryForever(10000)) .build(); // 開啟會話 client.start(); System.out.println(">>> 服務(wù)提供者連接 Zookeeper "); } /** * 注冊服務(wù)地址 */ public String registeredAddress() { String address = null; try { Stat stat = client.checkExists().forPath(PROVIDER_NODE); if (stat == null) { client.create().creatingParentsIfNeeded().forPath(PROVIDER_NODE); } // 獲取本機地址 address = PROVIDER_IP + ":" + port; // 創(chuàng)建臨時節(jié)點 /imooc/provider/192.168.0.106:8090 PROVIDER_ADDRESS = client.create() .withMode(CreateMode.EPHEMERAL) .forPath(PROVIDER_NODE + "/" + address); } catch (Exception e) { e.printStackTrace(); } System.out.println(">>> 本服務(wù)已上線"); return ">>> 服務(wù)提供者 " + address + " 已上線"; } /** * 注銷服務(wù)地址 */ public String deregistrationAddress() { String address = null; try { Stat stat = client.checkExists().forPath(PROVIDER_ADDRESS); if (stat != null) { client.delete().forPath(PROVIDER_ADDRESS); } // 獲取本機地址 address = PROVIDER_IP + ":" + port; } catch (Exception e) { e.printStackTrace(); } System.out.println(">>> 本服務(wù)已下線"); return ">>> 服務(wù)提供者 " + address + " 已下線"; }}在 CuratorService 類中,我們提供了創(chuàng)建 Curator 客戶端的方法,注冊服務(wù)地址的方法以及注銷服務(wù)地址的方法。在該服務(wù)啟動時,就會自動連接 Zookeeper 服務(wù),并且把自身的地址信息注冊到 Zookeeper 的臨時節(jié)點上。ProviderController這里我們使用 RESTful 的風格編寫服務(wù)提供者對外的接口,在 service 目錄同級創(chuàng)建 controller 目錄,在 controller 中創(chuàng)建 ProviderController 。@RestController@RequestMapping("/provider")public class ProviderController { @Value("${server.port}") private String port; @Autowired private CuratorService curatorService; @Autowired private ProviderService providerService; /** * 調(diào)用方法 * http://localhost:8090/provider/callMethod * * @return String */ @GetMapping("/callMethod") public String callMethod() { return providerService.callMethod(); } /** * 上線服務(wù) * http://localhost:8090/provider/online * * @return String */ @GetMapping("/online") public String registeredAddress() { return curatorService.registeredAddress(); } /** * 下線服務(wù) * http://localhost:8090/provider/offline * * @return String */ @GetMapping("/offline") public String deregistrationAddress() { return curatorService.deregistrationAddress(); }}controller 編寫完畢后,我們就可以對我們的服務(wù)提供者進行測試了。

3.3 啟動及測試

在命令行輸入啟動命令 mvn spring-boot:run。待程序啟動完畢后,打開瀏覽器訪問 http://localhost:8080,將看到以下頁面:啟動后頁面點擊「Authorize tonglei0429」按鈕,瀏覽器將跳轉(zhuǎn)到過渡頁面,如下所示:過度頁面最后顯示登錄結(jié)果頁,頁面內(nèi)容也就是我們在 src/main/resources/templates/index.html 中所編輯的模板一樣,可以看到從 Github 網(wǎng)站返回的一系列用戶信息。效果如下:登錄結(jié)果頁

瀏覽器的多線程和單線程

學習過 JavaScript 的可能會了解,JavaScript 的宿主瀏覽器只有一個線程運行 JavaScript,除了 JavaScript 的線程,瀏覽器中單個頁面還有一些其他線程,例如:UI 線程負責處理渲染 DOM 元素;GUI 線程用于處理與用戶交互的邏輯;網(wǎng)絡(luò)線程用于發(fā)送接收 HTTP 請求;file 線程用于讀取文件;定時器線程處理定時任務(wù)等等。

6. 測試

在項目的 WEB-INF 目錄下新建 jsp 子目錄,在此子目錄中新建 htllo.jsp 文件,內(nèi)容可任意填寫。編寫控制器實例:@Controllerpublic class HelloAction implements org.springframework.web.servlet.mvc.Controller {@RequestMapping("/hello")public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("Bean URL "); return “hello”;}}發(fā)布項目、啟動 tomcat、打開瀏覽器。在瀏覽器的地址欄中輸入:http://localhost:8888/sm-demo/hello 。如果在瀏覽器中看到下圖信息,則恭喜 Spring MVC 項目的基礎(chǔ)平臺搭建完成。

Web 服務(wù)器:APACHE HTTPD

剛?cè)腴T Web 的小伙伴很容易迷失在 Apache、Tomcat、Httpd、Nginx 這些陌生詞匯中,所以在開始本章節(jié)的內(nèi)容前我們先來認識下它們。Apache:全球最權(quán)威的軟件開源協(xié)會,很多公司會把自己內(nèi)部的一些系統(tǒng)開源并提交申請給 Apache,讓 Apache 統(tǒng)一來管理這些開源項目為全世界的軟件做貢獻,同時也提升了公司的知名度和一些商業(yè)的戰(zhàn)略價值。尷尬的一點是早期的 Http Server 就叫做 Apache,后來的版本改名為 Httpd 了,所以很多人習慣說 Apache 服務(wù)器,其實默認指的是 Httpd;Httpd:Apache 旗下的 Web 服務(wù)器,它只提供靜態(tài)資源的訪問;Tomcat:Apache 旗下的另一個開源項目,區(qū)別于 Httpd 的是它支持動態(tài)內(nèi)容服務(wù);Nginx:Apache 的另一個開源服務(wù)器,但是更多時候拿他來作為代理服務(wù)器。Nginx 的功能非常強大,遠超了 Http 服務(wù)器的范疇,更像是一個網(wǎng)絡(luò)管理工具。

2.1 SeekBar 常用屬性

SeekBar 的屬性都非常好理解,當然也包含了上一節(jié) ProgressBar 的所有屬性,這里挑幾個常用的做一下講解:android:max:拖拽進度條的最大值。android:progress:拖拽進度條的當前進度值。android:secondaryProgress:二級滑動條的進度值。android:thumb:拖拽滑塊的樣式資源,默認通常是一個小圓點,大多數(shù)時候我們會自定義一個更好看的樣式。android:progressDrawable:自定義 SeekBar 的進度顯示樣式,可以設(shè)置已走進度和未走進度的不同樣式。示例如下,編寫 xml 代碼,設(shè)置android:progressDrawable:<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <SeekBar android:id="@+id/seekBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:max="100" android:progress="60" android:progressDrawable="@drawable/seekbar_progress" /></FrameLayout>在 drawable 資源目錄了下創(chuàng)建“seekbar_progress.xml”文件,編寫圖像資源:<?xml version="1.0" encoding="utf-8"?><layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape> <gradient android:endColor="#055CEB" android:startColor="#f00" android:useLevel="true" /> </shape> </item></layer-list>這樣就可以為 SeekBar 增加一個漸變的樣式,效果如下:

4. HttpURLConnection使用示例

還記得前面將現(xiàn)場的時候提到過,Android 系統(tǒng)規(guī)定只能在主線程操作 UI,這里再加上一條:Android 系統(tǒng)不能在 UI 線程訪問網(wǎng)絡(luò)所以我們需要開啟一個子線程處理 Http 請求,這一節(jié)我們使用 40 節(jié)學習的 AsyncTask 來執(zhí)行網(wǎng)絡(luò)請求,拉取慕課網(wǎng) Android 教程的首頁信息。

6.7 測試

啟動項目,打開瀏覽器訪問 http://127.0.0.1:8080/goods ,即可查看輸出結(jié)果。到此,大家基本上也能發(fā)現(xiàn),這兩種方式除了模板頁面文件內(nèi)容不同,其他地方基本都是一模一樣的。也就是說,模板引擎主要負責通過一些模板標簽,將控制器返回的數(shù)據(jù)解析為網(wǎng)頁。

1. 簡介

官方解釋:支持直接下載編譯文件或通過 npm 安裝 ECharts 包。慕課解釋:除官網(wǎng)提供的兩種安裝方式外,還可以選擇使用各類免費的 CDN 服務(wù),以獲得更佳的 HTTP 性能。官網(wǎng)提供了簡潔的安裝示例,但并沒有詳細介紹各編譯版本之間的區(qū)別,本文將就此展開討論。

案例 2

我們請求在頁面上請求 80 端口,會出現(xiàn) Nginx 的默認頁面,也就是 html 目錄下的那個 index.html 頁面;另外直接訪問http://localhost/50x.html 時候,會出現(xiàn)針對狀態(tài)碼為 50x 異常頁面。接下來,我們添加一個簡單的請求訪問接口,模擬 500 異常,然后會將請求重定向到這個異常頁面。在上述默認配置的 server 塊中,我們添加一個新的匹配路徑,如下:location /internal_error { return 500;}return 指令一般用于對請求的客戶端直接返回響應(yīng)狀態(tài)碼。在該作用域內(nèi) return 指令之后的所有 Nginx 配置都是無效的。可以使用在 server、location 以及 if 配置中。 除了支持跟狀態(tài)碼,還可以跟字符串或者 url 鏈接,比如寫成這樣的形式:return 200 ‘hello, world’這樣,使用 -s reload 熱加載 Nginx 后,我們直接在瀏覽器中敲 http://ip/internal_error, 就可以看到50x的異常頁面了。

3.1 認證集成

在 Spring Security 中,使用 Open ID 作為認證標準的方式非常簡單。Spring Security 提供了集成 Open ID 認證的標簽組件,開發(fā)者只需要在表單登錄的頁面中加入 <openid-logn> 標簽即可,完整代碼如下:<http><intercept-url pattern="/**" access="ROLE_USER" /><openid-login /></http>當然,我們首先需要配置好 Open ID 的認證組件(例如:myopenid.com),并且增加用于認證的用戶信息,如:<user name="https://jimi.hendrix.myopenid.com/" authorities="ROLE_USER" />配置好后,你就可以使用 myopenid.com 網(wǎng)站作為認證服務(wù)。除此之外,我們還可以指定 UserDetailsService 對象,用于配置 OpenID 的 user-service-ref 屬性。注意,此處我們雖然也給用戶對象設(shè)置了密碼屬性,但是該用戶對象中,我們僅僅是用來獲取權(quán)限的,其密碼在此處并不生效。但我們依然要保障密碼的復雜程度,以保障認證服務(wù)的安全。

3.2 pip3 search package-name

命令 pip3 search package-name 在 pypi.org 上根據(jù) package-name 搜索第三方包。輸出所有包含有關(guān)鍵字 requests 的第三方模塊,并給出模塊的功能簡介,示例如下:C:\> pip3 search requestsrequests-auth (5.1.0) - Authentication for Requestspydantic-requests (0.1.3) - A pydantic integration with requests.Requests-OpenTracing (0.2.0) - OpenTracing support for Requestsyamlsettings-requests (1.0.0) - YamlSettings Request Extensionrequests-aws4auth (0.9) - AWS4 authentication for Requestspycopy-requests (0.0.0) - Dummy requests module for Pycopyjupyter-requests (0.0.3) - Send requests to a Jupyter server.requests-middleware (0.1.2) - Composable HTTP middleware for requests...

3. 使用代理

在 Scrapy 項目中使用代理是非常簡單的一件事情,我們只需要在發(fā)送的 Request 請求中添加 meta 參數(shù)即可實現(xiàn)代理功能:yield Request(url, callback=回調(diào)方法, errback=錯誤回調(diào), meta={"proxy": proxy, "download_timeout": 10})上面生成的 Request 請求帶上了 meta 參數(shù),該參數(shù)中又設(shè)置了代理服務(wù)器的地址以及相應(yīng)的超時時間。我們可以簡單來看看代理服務(wù)器的使用:首先我們來自己搭建一個 Nginx 服務(wù),具體的搭建過程可以參考這個教程: Nginx入門手冊;接著我們使用9999這個端口做為代理轉(zhuǎn)發(fā)端口,相關(guān)的配置如下:# nginx.confserver { resolver 114.114.114.114; resolver_timeout 5s; listen 9999; location / { proxy_pass $scheme://$host$request_uri; proxy_set_header Host $http_host; proxy_buffers 256 8k; proxy_max_temp_file_size 0; proxy_connect_timeout 30; proxy_cache_valid 200 302 10m; proxy_cache_valid 301 1h; proxy_cache_valid any 1m; }}啟動 nginx 服務(wù)后,我們這個代理服務(wù)就搞定了。我們可以使用 requests 測試下這個代理服務(wù),看看是不是生效了:import requestsproxies = { "http": "http://180.76.152.113:9999",}response = requests.get("http://www.china-pub.com/browse/", proxies=proxies)response.encoding = 'gbk'print(response.text)上述代碼位于另一臺云服務(wù)器,請求的是互動出版物的圖書分類頁面,這次我們會在 requests 請求中加上我們剛剛配置的代理,使用 nginx 代理轉(zhuǎn)發(fā)請求,請看視頻演示:99往往在 Scrapy 中,我們往往會采用這樣的方式去使用代理服務(wù):準備好一個 redis 和 web 服務(wù)。其中 web 服務(wù)往往會使用 django 或者 flask 等 web 框架開發(fā),用于爬取免費的代理 ip,同時會對爬取到的 ip:port 進行校驗。如果代理 ip 有效則將其緩存至 redis 服務(wù)中,形成有效的 ip 代理池;web 服務(wù)會定期檢查 ip 代理池的所有數(shù)據(jù),對于無效的 ip 及時清除。同時,也會定時爬取新的有效的代理 ip 并保存到 redis 中;web 服務(wù)會提供一個獲取當前 ip 池內(nèi)有效 HTTP 代理地址的接口,這樣外部應(yīng)用只需要請求這個接口就能獲取一個有效的代理地址;此外,在 Scrapy 的項目中,我們往往會按照如下的思路進行代理爬取:限于篇幅,這里不再對整個流程做案例演示,有興趣的讀者可以下去后一步步完成從 ip 代理池服務(wù)的開發(fā)到最后對接 Scrapy 框架的整個過程,推薦測試的網(wǎng)站為新浪微博,這也是 github 上許多案例的測試靶場。

2.1 ZkClient 的依賴

首先我們新建 Spring Boot 項目,在 pom.xml 文件中加入 zkclient 的依賴:<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>cn.cdd</groupId> <artifactId>zkclient-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>zkclient-demo</name> <description>zkclient-demo project for Spring Boot</description> <properties> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/com.101tec/zkclient --> <dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.11</version> <!-- 排除沖突 --> <exclusions> <exclusion> <artifactId>log4j</artifactId> <groupId>log4j</groupId> </exclusion> <exclusion> <artifactId>slf4j-log4j12</artifactId> <groupId>org.slf4j</groupId> </exclusion> <exclusion> <artifactId>slf4j-api</artifactId> <groupId>org.slf4j</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>加入了 ZkClient的依賴,我們就可以編寫程序使用 zkclient 的 API 來向 Zookeeper 服務(wù)端發(fā)送請求了。

2. ImageView 的基本用法

首先看看最簡單直接的用法:<?xml version="1.0" encoding="utf-8"?><ImageView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:background="#59A004" android:src="@drawable/image" />我們直接在根布局中添加一個 ImageView,設(shè)置android:src為圖片文件,android:background設(shè)置為綠色,效果如下:這里可以對android:src和android:background有一個定性的認識:android:src表示ImageView的前景,而android:backgound設(shè)置的是ImageView的背景,對應(yīng)的Java代碼是:setImageDrawable( ); // 設(shè)置ImageView的前景setBackgroundDrawable( ); // 設(shè)置ImageView的背景

6.4 創(chuàng)建商品頁面

我們在 resource/templates 目錄下新建商品頁面 goods.html ,先不必實現(xiàn)具體功能,代碼如下:實例:<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>商品列表</title></head><body>商品列表</body></html>此時我們啟動項目,然后訪問 http://127.0.0.1:8080/goods ,即可顯示對應(yīng)頁面內(nèi)容。

3. CSRF 攻擊的防御

我們雖然無法阻止惡意網(wǎng)站向目標網(wǎng)站發(fā)送 HTTP 請求,但是我們可以確保惡意網(wǎng)站無法生成目標網(wǎng)站所需的參數(shù),所以就出現(xiàn)了如下兩種常見的解決方案:使用同步「Token」模式在 Cookies 中指定網(wǎng)站同源的參數(shù)這兩種方式在 Spring Security 中都已支持。

直播
查看課程詳情
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學習伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號