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

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
4.2 protected

當(dāng)成員被定義為 protected 后,只能被類的內(nèi)部以及類的子類訪問(wèn)。class Base { protected baseUrl: string = 'http://api.com/' constructor() {} protected request(method: string) { const url = `${this.baseUrl}${method}` // TODO 封裝基礎(chǔ)的 http 請(qǐng)求 }}class Address extends Base { get() { return this.request('address') }}代碼解釋:第 2 行,Base 類的屬性 baseUrl 被定義為受保護(hù)的,那么第 7 行該屬性在類中被訪問(wèn)是可以的。第 14 行,因 Address 類是 Base 類的子類,在子類中允許訪問(wèn)父類中被定義為受保護(hù)類型的方法 request() 。

2.1 瀏覽器運(yùn)行原生 ES6 模塊

使用瀏覽器運(yùn)行原生 ES6 模塊的源碼在 ES6-wiki 的 mjs 文件中,瀏覽器是不能直接運(yùn)行 ES6 模塊化的,需要做一些準(zhǔn)備工作。首先,在引入 js 文件時(shí)需要定義 script 的類型:type="module" 。另外,js 文件的后綴不能使用 .js 了,需要使用 .mjs 。這樣還是不能在瀏覽器中運(yùn)行,還需要最后一步。模塊化會(huì)涉及到文件系統(tǒng),而本地打開(kāi)的 html 文件是沒(méi)有服務(wù)的,所以我們要使用 node 服務(wù)的方式打開(kāi) html 文件,這里我們使用 node 的包 http-server 可以在相應(yīng)的文件目錄中啟動(dòng) node 服務(wù)。安裝如下:npm install --global http-server安裝完啟動(dòng)服務(wù)的工具還是會(huì)有問(wèn)題,依然打不開(kāi),這是需要在瀏覽器中打開(kāi)一些配置:瀏覽器地址欄輸入:chrome://flags/ 然后搜索 JavaScript 把 Experimental JavaScript 項(xiàng)選擇 Enabled 啟用狀態(tài)。如下圖。到這里我們就把前期的工作做完了,如何打開(kāi) html 文件呢?在控制臺(tái)中進(jìn)入對(duì)應(yīng)的目錄中執(zhí)行:http-server 命令。本節(jié)的目錄在 ES6-wiki/packages/module/mjs 下。在瀏覽器打開(kāi)控制臺(tái)返回的地址即可,本實(shí)例的地址是:http://127.0.0.1:8080/index.html

3.1 表達(dá)式的應(yīng)用配置

要針對(duì) URL 應(yīng)用表達(dá)式規(guī)則,我們需要在 <http> 對(duì)象上將 use-expressions 屬性值置為 true。Spring Security 則會(huì)將 <intercept-url> 元素中 access 屬性值解釋為表達(dá)式,并根據(jù)表達(dá)式規(guī)則返回 true 或者 false 的判定結(jié)果。例如:<http> <intercept-url pattern="/admin*" access="hasRole('admin') and hasIpAddress('192.168.1.0/24')"/> ...</http>本例中,我們將 /admin 開(kāi)頭的資源定義為只有包含 admin 角色,并且來(lái)源 IP 為 192.168.1.x 網(wǎng)段的用戶才可以訪問(wèn)。這里出現(xiàn)的 hasIpAddress 方法在前面內(nèi)容中沒(méi)有提到,因?yàn)樗侵挥?Web 系統(tǒng)才包含的,被定義在 WebSecurityExpressionRoot 類中。

1.1 limit_conn 模塊

ngx_http_limit_conn_module 模塊限制單個(gè) ip 的建立連接的個(gè)數(shù),該模塊內(nèi)有 6 個(gè)指令。分別如下:limit_conn_zone: 該指令主要的作用就是分配共享內(nèi)存。 下面的指令格式中 key 定義鍵,這個(gè) key 往往取客戶端的真實(shí) ip,zone=name 定義區(qū)域名稱,后面的 limit_conn 指令會(huì)用到的。size 定義各個(gè)鍵共享內(nèi)存空間大小;Syntax: limit_conn_zone key zone=name:size;Default: —Context: httplimit_conn_status: 對(duì)于連接拒絕的請(qǐng)求,返回設(shè)置的狀態(tài)碼,默認(rèn)是 503;Syntax: limit_conn_status code;Default: limit_conn_status 503;Context: http, server, locationlimit_conn: 該指令實(shí)際限制請(qǐng)求的并發(fā)連接數(shù)。指令指定每個(gè)給定鍵值的最大同時(shí)連接數(shù),當(dāng)超過(guò)這個(gè)數(shù)字時(shí)被返回 503 (默認(rèn),可以由指令 limit_conn_status 設(shè)置)錯(cuò)誤;Syntax: limit_conn zone number;Default: —Context: http, server, locationlimit_conn_log_level: 當(dāng)達(dá)到最大限制連接數(shù)后,記錄日志的等級(jí);Syntax: limit_conn_log_level info | notice | warn | error;Default: limit_conn_log_level error;Context: http, server, locationlimit_conn_dry_run: 這個(gè)指令是 1.17.6 版本中才出現(xiàn)的,用于設(shè)置演習(xí)模式。在這個(gè)模式中,連接數(shù)不受限制。但是在共享內(nèi)存的區(qū)域中,過(guò)多的連接數(shù)也會(huì)照常處理。Syntax: limit_conn_dry_run on | off;Default: limit_conn_dry_run off;Context: http, server, locationlimit_zone: 該指令已棄用,由 limit_conn_zone 代替,不再進(jìn)行說(shuō)明。實(shí)例http { ... limit_conn_zone $binary_remote_addr zone=addr:10m server { ... location / { limit_conn_status 500; limit_conn_log_level warn; # 限制向用戶返回的速度,每秒50個(gè)字節(jié) limit_rate 50; limit_conn addr 10; } }}

2.1 基本原理

Prometheus 專注于現(xiàn)在正在發(fā)生的事情,而不是追蹤數(shù)周或數(shù)月前的數(shù)據(jù)。Prometheus 通常不用于長(zhǎng)期數(shù)據(jù)保留,默認(rèn)保存 15 天的時(shí)間序列數(shù)據(jù)。它有這樣一個(gè)前提,即大多數(shù)監(jiān)控查詢和警報(bào)都是從最近的數(shù)據(jù)中生成的。Prometheus的基本原理是通過(guò)HTTP協(xié)議周期性抓取被監(jiān)控組件的狀態(tài),任意組件只要提供對(duì)應(yīng)的HTTP接口就可以接入監(jiān)控。不需要任何SDK或者其他的集成過(guò)程。輸出被監(jiān)控組件信息的HTTP接口被叫做exporter 。常用的組件大部分都有exporter可以直接使用,比如Nginx、MySQL、Linux系統(tǒng)信息等等。大致工作流程如下:Prometheus定時(shí)去目標(biāo)上抓取指標(biāo)監(jiān)控?cái)?shù)據(jù),抓取目標(biāo)需要暴露一個(gè)http服務(wù)的接口給它定時(shí)抓取。對(duì)于不能直接抓取的目標(biāo),Prometheus支持這些應(yīng)用服務(wù)主動(dòng)推送監(jiān)控指標(biāo)到PushGateway,而后Prometheus定時(shí)去這些網(wǎng)關(guān)上抓取數(shù)據(jù)。Prometheus在本地存儲(chǔ)保存抓取的數(shù)據(jù),并按規(guī)則進(jìn)行過(guò)濾和整理數(shù)據(jù)。Prometheus支持很多方式的圖表可視化,例如Grafana、自帶的Promdash以及自身提供的模版引擎等等。Prometheus還提供HTTP API的查詢方式,自定義所需要的輸出。

Upgrade

該字段用來(lái)支持以一種協(xié)議建立連接后,想要升級(jí)成更高層的協(xié)議,比如 Http/1.1 想要升級(jí)成 Http/2.0 的協(xié)議,或者說(shuō)要升級(jí)成 Websocket 協(xié)議。Upgrade:websocketConnection: Upgrade如果 Connection 的值是 Upgrade ,通常也需要一個(gè) Upgrade 字段來(lái)標(biāo)明要升級(jí)的協(xié)議,該值可以是多個(gè)的逗號(hào)分隔開(kāi),服務(wù)端會(huì)按照順序查看支持的升級(jí)服務(wù)。上面客戶端想要升級(jí)成 Websocket 協(xié)議,如果服務(wù)端支持就會(huì)返回一個(gè) 101 Switching Protocols 響應(yīng)狀態(tài)碼,和一個(gè)要切換到的協(xié)議的頭部字段 Upgrade。 如果服務(wù)器沒(méi)有(或者不能)升級(jí)這次連接,它會(huì)忽略客戶端發(fā)送的 Upgrade 頭部字段,返回一個(gè)常規(guī)的響應(yīng)。CloseHttp/1.1 規(guī)定了默認(rèn)保持長(zhǎng)連接(HTTP persistent connection ,也有翻譯為持久連接),數(shù)據(jù)傳輸完成了保持 TCP 連接不斷開(kāi)(不發(fā) RST 包、不四次握手),等待在同域名下繼續(xù)用這個(gè)通道傳輸數(shù)據(jù)。當(dāng)服務(wù)器端想明確斷開(kāi)連接時(shí),則指定 Connection 首部字段的值為 Close。Connection: closeKeep-AliveHttp/1.1 之前的 HTTP 版本的默認(rèn)連接都是非持久連接。為此, 如果想在舊版本的 HTTP 協(xié)議上維持持續(xù)連接,則需要指定 Connection 首部字段的值為 Keep-Alive。Connection: Keep-Alive

2.6 案例:體驗(yàn) Nginx 的 include 指令和內(nèi)置變量

我們準(zhǔn)備三個(gè)配置文件,分別為主配置文件 Nginx.conf 和次配置文件 8080.conf、8088.conf,在 Nginx 根目錄下的 conf 目錄中,新建 conf.d 目錄,然后將 8080.conf、8088.conf 兩個(gè)文件放到此處。通過(guò)cat命令查看三個(gè)配置文件內(nèi)容,如下:$ cat 8080.confserver { listen 8080; server_name localhost; location / { default_type text/html; return 200 'hello, 8080\n'; }}$ cat 8088.confserver { listen 8088; server_name localhost; location / { default_type text/html; return 200 'hello, 8088\n'; }}$ cat nginx.conf ...http: { ... server: { ... # 前面的不變化,但是我們需要變化兩個(gè)地方 location / { default_type text/html; # 自定義變量 set $limit_rate 10k; return 200 ' arg_a: $arg_a, arg_b: $arg_b, args: $args connection: $connection, connection_requests: $connection_requests cookie_a: $cookie_a uri: $uri, document_uri: $document_uri, request_uri: $request_uri request: $request , request_id: $request_id server: $server_addr, $server_name, http_host: $http_host, limit_rate: $limit_rate, hostname: $hostname, content_length: $content_length status: $status, body_bytes_sent: $body_bytes_sent, bytes_sent: $bytes_sent time: $request_time, $msec, $time_iso8601, $time_local\n'; } } ... # 包含其他配置文件,包括了8080.conf和8088.conf include conf.d/*.conf;}準(zhǔn)備好這三個(gè)三個(gè)配置文件后,直接啟動(dòng) Nginx,可以發(fā)現(xiàn) Nginx 服務(wù)分別監(jiān)聽(tīng)了 80、8080 和 8088 端口。這說(shuō)明 include 指令生效了,8080.conf、8088.conf 配置被包含進(jìn)來(lái)了。當(dāng)然我們也可以去掉這個(gè) include 指令再看看 Nginx 會(huì)不會(huì)監(jiān)聽(tīng) 8080 和 8088 端口,來(lái)個(gè)終極確認(rèn)。最后我們?cè)诜?wù)器上使用 curl 命令來(lái)模擬 Http 請(qǐng)求訪問(wèn)服務(wù)器的 8080 和 8088 端口,看是否會(huì)有對(duì)應(yīng)的相應(yīng)文本輸出。最后請(qǐng)求 80 端口,帶上相應(yīng)的參數(shù),具體操作以及打印結(jié)果如下:[root@server ~]# cd /root/nginx/sbin# 如果Nginx服務(wù)已經(jīng)啟動(dòng),使用 -s reload 重新加載配置,否則直接使用 ./nginx 啟動(dòng)Nginx服務(wù) [root@server sbin]# ./nginx -s reload[root@server sbin]# curl http://localhost:8080hello, 8080[root@server sbin]# curl http://localhost:8088hello, 8088# 一定要使用雙引號(hào)包含整個(gè)URL,不然后面的b參數(shù)會(huì)被漏掉[root@server sbin]# curl "http://localhost:80?a=xxxx&b=yyyy" arg_a: xxxx, arg_b: yyyy, args: a=xxxx&b=yyyy connection: 27, connection_requests: 1 cookie_a: uri: /, document_uri: /, request_uri: /?a=xxxx&b=yyyy request: GET /?a=xxxx&b=yyyy HTTP/1.1 , request_id: 3784dd519727856c17b38e2ec9f2c8a1 server: 127.0.0.1, , http_host: localhost, limit_rate: 10240, hostname: server, content_length: status: 200, body_bytes_sent: 0, bytes_sent: 0 time: 0.000, 1581417768.174, 2020-02-11T18:42:48+08:00, 11/Feb/2020:18:42:48 +0800

4.7 運(yùn)行程序

在瀏覽器中,訪問(wèn) http://localhost:5000/news/society/, 顯示如下:因?yàn)?news.css 定義 h1 標(biāo)簽為紅色,因此顯示是紅色的。

3. Servlet 權(quán)限控制的配置實(shí)現(xiàn)

默認(rèn)情況下,Spring Security 的權(quán)限要求所有的請(qǐng)求都需要首先通過(guò)認(rèn)證。相當(dāng)于以下配置描述:protected void configure(HttpSecurity http) throws Exception { http // ... .authorizeRequests(authorize -> authorize .anyRequest().authenticated() );}如果我們需要配置 Spring Security 對(duì)不同請(qǐng)求有不同的處理規(guī)則時(shí),可通過(guò)以下方式修改配置:protected void configure(HttpSecurity http) throws Exception { http // ... .authorizeRequests(authorize -> authorize .mvcMatchers("/resources/**", "/signup", "/about").permitAll() .mvcMatchers("/admin/**").hasRole("ADMIN") .mvcMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')") .anyRequest().denyAll() );}以上這段代碼實(shí)現(xiàn)了如下功能:指定了多種規(guī)則,每種規(guī)則按照其配置的順序決定優(yōu)先級(jí);匹配了多個(gè) URL 規(guī)則,對(duì)于 /resources、/signup、/about 允許任何用戶訪問(wèn);任何以 /admin/ 開(kāi)頭的地址都要求用戶具有管理員權(quán)限 ROLE_ADMIN,其中 ROLE_ 前綴是 Spring Security 默認(rèn)添加的,用戶無(wú)需做特殊處理;任何以 /db/ 為開(kāi)頭的地址需要同時(shí)擁有 ROLE_ADMIN 和 ROLE_DBA 角色;沒(méi)有被上述 URL 地址匹配的地址都將被禁止訪問(wèn),加上這一條非常有助于提升系統(tǒng)的安全性。

4.2 命令選項(xiàng)

命令選項(xiàng)說(shuō)明–sdk_root使用指定的 SDK 路徑而不是包含此工具的 SDK。–channel包含從 channel_0 到 channel_id 所有渠道中的軟件包??捎玫那腊ǎ?(穩(wěn)定版)、1(測(cè)試版)、2(開(kāi)發(fā)版)和 3(Canary 版)。–include_obsolete在列出或更新軟件包時(shí)納入那些已過(guò)時(shí)的軟件包。–no_https強(qiáng)制所有連接使用 HTTP 而不是 HTTPS。–verbose詳細(xì)輸出模式。該模式會(huì)輸出錯(cuò)誤、警告和參考性消息。–proxy通過(guò)給定類型的代理建立連接:用 http 指定一個(gè)高層級(jí)協(xié)議(如 HTTP 或 FTP)的代理,或用 socks 指定一個(gè) SOCKS(V4 或 V5)代理。–proxy_host要使用的代理的 IP 或 DNS 地址。–proxy_port要連接到的代理端口號(hào)。

1.跨域請(qǐng)求

簡(jiǎn)單來(lái)說(shuō),跨域請(qǐng)求就是一個(gè)域下的資源請(qǐng)求另外一個(gè)域下的資源。同一個(gè)域,指的是,協(xié)議名、域名、端口號(hào)都一致。 舉個(gè)例子來(lái)說(shuō),假如 “http://www.a.com” 下的 JavaScript 腳本發(fā)起 Ajax 請(qǐng)求 “http://www.a.com/ajax” ,由于 協(xié)議名 http 、域名 www.a.com 和 端口號(hào)(默認(rèn)都是 80)三者都是一致的,因此都屬于同一個(gè)域,不造成跨域請(qǐng)求。而假如其中任一元素不相同,則造成跨域請(qǐng)求。與此同時(shí),瀏覽器出于安全考慮,基于同源策略則會(huì)做一定的限制:比方說(shuō):無(wú)法獲取不同域的 Cookie、LocalStorage 等等。無(wú)法獲取不同域的 DOM 對(duì)象。無(wú)法向不同域發(fā)送 Ajax 請(qǐng)求。

2.1 創(chuàng)建 Spring Security 項(xiàng)目

修改 Hello World 模板工程的目錄名稱為 UsernamePasswordSample;修改 pom.xml 文件,將基礎(chǔ)信息部分改為如下形式:<?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">略... <groupId>imooc.springsecurity</groupId> <artifactId>UsernamePasswordSample</artifactId> <version>0.0.1-SNAPSHOT</version>略...</project>修改啟動(dòng)類,修改其包名為 imooc.springsecurity.usernamepassword,修改類名為 UsernamePasswordSample;創(chuàng)建測(cè)試頁(yè)面,返回登錄用戶信息新建 src/main/java/imooc/springsecurity/usernamepassword/controller/UserController.java。package imooc.springsecurity.usernamepassword.controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import java.security.Principal;@RestController@RequestMapping("user")public class UserController { @RequestMapping("me") private String showMe(Principal principal) { return String.format("當(dāng)前登錄用戶為:「%s」", principal.getName()); }}在項(xiàng)目根目錄控制臺(tái)輸入命令 mvn spring-boot:run,如看到以下輸出代表配置正確。

2.2 工程搭建

1. 創(chuàng)建工程2. 引入依賴<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!-- Spring jdbc 使用的依賴--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency> </dependencies>3. 準(zhǔn)備代碼實(shí)體類代碼/** * 賬戶的實(shí)體類 */public class Account implements Serializable { //數(shù)據(jù)id private Integer id; //賬號(hào)編碼 private String accountNum; //賬號(hào)金額 private Float money;}持久層接口代碼/** * 賬戶的持久層接口 */public interface IAccountDao { /** * 根據(jù)Id查詢賬戶 * @param accountId * @return */ Account findAccountById(Integer accountId); /** * 保存賬戶 * @param account */ void saveAccount(Account account); /** * 更新賬戶 * @param account */ void updateAccount(Account account);}持久層實(shí)現(xiàn)類代碼/** * 賬戶的持久層實(shí)現(xiàn)類 */@Repositorypublic class AccountDaoImpl implements IAccountDao { //jdbc模板類屬性 @Autowired private JdbcTemplate jdbcTemplate; //根據(jù)id查找 public Account findAccountById(Integer accountId) { List<Account> accounts = jdbcTemplate.query("select * from account where id = ?",new BeanPropertyRowMapper<Account>(Account.class),accountId); return accounts.isEmpty()?null:accounts.get(0); } public void saveAccount(Account account) { jdbcTemplate.update("insert into account values(?,?,?)", account.getId(),account.getAccountNum(),account.getMoney()); } public void updateAccount(Account account) { jdbcTemplate.update("update account set accountnum=?,money=? where id=?",account.getAccountNum(),account.getMoney(),account.getId()); }}業(yè)務(wù)層接口代碼/** * @Auther: wyan */public interface UserService { /** * 賬戶轉(zhuǎn)賬 * @param fromId toId */ public void transMoney(Integer fromId, Integer toId, Integer money);}業(yè)務(wù)層實(shí)現(xiàn)類代碼/** * @Auther: wyan * @Description: */@Servicepublic class UserServiceImpl implements UserService { @Autowired private IAccountDao accountDao; public void transMoney(Integer fromId, Integer toId, Integer money) { Account fromAccount = accountDao.findAccountById(fromId); Account toAccount = accountDao.findAccountById(toId); //原始賬號(hào)減錢 fromAccount.setMoney(fromAccount.getMoney()-money); accountDao.updateAccount(fromAccount); //拋出異常 int i=1/0; //轉(zhuǎn)賬賬號(hào)加錢 toAccount.setMoney(toAccount.getMoney()+money); accountDao.updateAccount(toAccount); }}Tips: 我們?cè)俳o原始賬號(hào)減掉錢后,執(zhí)行保存。然后在這里會(huì)出現(xiàn)個(gè)異常,就是為了測(cè)試事務(wù)的特性,所以手動(dòng)加了個(gè)除 0 的代碼。4. 配置文件<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--配置JdbcTemplate--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置數(shù)據(jù)源--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql:///transmoney"></property> <property name="username" value="root"></property> <property name="password" value="root"></property> </bean> <!--包路徑掃描--> <context:component-scan base-package="com.offcn"></context:component-scan> <!--事務(wù)管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!--事務(wù)的通知--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED"/> <tx:method name="del*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="find*" read-only="true"/> </tx:attributes> </tx:advice> <!--切面的配置--> <aop:config> <aop:pointcut id="pt" expression="execution(* com.offcn.service.*.*(..))"/> <aop:advisor pointcut-ref="pt" advice-ref="txAdvice" /> </aop:config></beans>此處需要注意:? context:component-scan:掃描的節(jié)點(diǎn)路徑為包含 service 和 dao 兩個(gè)子目錄的父級(jí)目錄;? transactionManager: 此節(jié)點(diǎn)作用就是初始化 Spring 框架提供的事務(wù)管理器的實(shí)現(xiàn)類;? tx:advice: 此節(jié)點(diǎn)的作用是配置切面的通知,因?yàn)橹拔覀兊那忻骖愂亲远x的,這里使用的是 Spring 提供的事務(wù)管理器類作為切面,那么針對(duì)什么方法需要做增強(qiáng)呢,在此節(jié)點(diǎn)配置,可以看得出來(lái):以 save、del、update 開(kāi)頭的方法都會(huì)支持事務(wù),而 find 開(kāi)頭的方法,指定的是只讀。? aop:config: 此節(jié)點(diǎn)就是 AOP 的相關(guān)配置節(jié)點(diǎn)了,將切入點(diǎn)和通知整合到一起,同以前的項(xiàng)目差別不大。這里可以看到:切入點(diǎn)規(guī)則是針對(duì) service 下面的所有類所有方法任意參數(shù)做增強(qiáng)。通知使用的就是我們上面配置過(guò)的 tx:advice 節(jié)點(diǎn)。5. 測(cè)試代碼public class AccountServiceTest { public static void main(String[] args) { //1.獲取容器 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); //2.獲取業(yè)務(wù)對(duì)象 UserService userService = ac.getBean(UserService.class); //3.從id為1的賬號(hào)轉(zhuǎn)成1000到2賬號(hào) userService.transMoney(1,2,1000); System.out.println("轉(zhuǎn)賬完成.."); }}6. 測(cè)試結(jié)果:ok, 大家,控制臺(tái)如愿以償打印了異常的堆棧信息,但是這個(gè)不是目的,哈哈哈。目的是在程序執(zhí)行發(fā)生異常的情況下,數(shù)據(jù)的數(shù)據(jù)不會(huì)錯(cuò)亂。我們可以看見(jiàn)數(shù)據(jù)庫(kù)數(shù)據(jù)并沒(méi)有發(fā)生改變。

1. 創(chuàng)建多渠道資源文件目錄

首先,我們新創(chuàng)建一個(gè)工程,然后在 main 模塊下面,根據(jù)不同渠道創(chuàng)建不同的資源文件目錄。我們先定義一個(gè)簡(jiǎn)單的頁(yè)面,里面顯示渠道跟一張圖片。layout 布局文件如下所示:<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:orientation="vertical" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="26sp" android:textColor="@color/colorPrimary" android:text="@string/chanl_name" /> <ImageView android:layout_width="match_parent" android:layout_height="wrap_content" android:src="@mipmap/girl" > </ImageView></LinearLayout>然后我們根據(jù)我們用到的資源,對(duì)不同渠道配置不同的資源。我們這里 model 比較簡(jiǎn)單,主要是圖片和字符串,圖片這里我們不同渠道顯示的不同。具體目錄如下所示:Tips: 注意這里我們創(chuàng)建資源文件目錄的時(shí)候不能包含 test ,否則會(huì)編譯報(bào)錯(cuò)的。我親自嘗試過(guò) res-test。

1.下載軟件源碼包

使用如下命令下載 nginx 源碼包:wget http://nginx.org/download/nginx-1.18.0.tar.gz執(zhí)行結(jié)果如下圖所示:

3.2 代碼

package com.imooc.mytomcat.tomcat;import java.io.IOException;import java.io.OutputStream;import java.net.ServerSocket;import java.net.Socket;/** * Mytomcat * * @author zhourj * description */public class Mytomcat { public static void main(String[] args) { Mytomcat server = new Mytomcat(); server.start(); } private void start(){ try { //開(kāi)啟一個(gè) Socket 服務(wù)端,并監(jiān)聽(tīng) 8090 端口 ServerSocket serverSocket = new ServerSocket(8090); do { //阻塞,直到有客戶端連接上,才會(huì)執(zhí)行后面的邏輯 Socket socket = serverSocket.accept(); //處理數(shù)據(jù) hander(socket); } while (true); } catch (IOException e) { e.printStackTrace(); } } /** * http response * 第一行 協(xié)議 返回狀態(tài) * 第二行 媒體類型 josn/html * 第三行 空 * 內(nèi)容 * @param socket */ private void hander(Socket socket) throws IOException { //拼接返回的 request 報(bào)文 StringBuilder responseBuilder = new StringBuilder(); responseBuilder //返回 200 狀態(tài)碼,表示請(qǐng)求成功 .append("HTTP/1.1 200 \r\n") //告訴請(qǐng)求的客戶端,返回的內(nèi)容是 text/html 格式的 .append("Content-Type: text/html\r\n") //首部字段和消息實(shí)體中間的空行 .append("\r\n") //內(nèi)容部分 .append("hello tomcat"); //獲取客戶端通道的輸出流 OutputStream outputStream = socket.getOutputStream(); //往輸出流通道寫(xiě)消息 outputStream.write(responseBuilder.toString().getBytes()); //流是有緩存機(jī)制的,寫(xiě)消息的時(shí)候不一定立馬發(fā)出去,刷一下才能保證數(shù)據(jù)發(fā)送出去 outputStream.flush(); //關(guān)閉輸出流通道 outputStream.close(); }}上面的代碼初學(xué)者可以自己模仿著寫(xiě)一個(gè),相信對(duì) Http 會(huì)有很深刻的體驗(yàn)。代碼中主要是監(jiān)聽(tīng)連接,客戶端連接后,根據(jù) Http 協(xié)議進(jìn)行字符串的拼接返回給客戶端,客戶端瀏覽器接收到是標(biāo)準(zhǔn)的 Http 格式就會(huì)進(jìn)行渲染。

2. 版本(Versioning)

師生管理系統(tǒng)不是一成不變的,日后還要更新維護(hù)。為了區(qū)分不同版本,API 的 URL 中應(yīng)當(dāng)包含 API 版本信息:http://www.demo.com/api/1.0/foohttp://www.demo.com/api/1.1/foohttp://www.demo.com/api/2.0/foo除了上述方法外,API 版本信息還可放在 HTTP 請(qǐng)求頭中。Github 采用的就是這種做法。因?yàn)椴煌陌姹?,可以理解成同一種資源的不同表現(xiàn)形式,所以應(yīng)該采用同一個(gè) URL。版本號(hào)可以在 HTTP 請(qǐng)求頭信息的 Accept 字段中進(jìn)行區(qū)分(參見(jiàn)Versioning REST Services):Accept: vnd.example-com.foo+json; version=1.0Accept: vnd.example-com.foo+json; version=1.1Accept: vnd.example-com.foo+json; version=2.0實(shí)際工作中,通常采用第一種方法,因?yàn)檫@樣的方式更加直觀,方便使用。

3.2 強(qiáng)制安全傳輸

Spring Security 提供了對(duì)強(qiáng)制安全傳輸?shù)闹С?,并且其在默認(rèn)情況下是開(kāi)啟的。此部分在 HTTP 安全響應(yīng)頭中也有過(guò)介紹。例如,當(dāng)我們?cè)L問(wèn)某個(gè)銀行網(wǎng)站「mybank.example.com」,當(dāng)我們使用 https 方式訪問(wèn)時(shí),便避免了出現(xiàn)中間人攻擊。在開(kāi)啟強(qiáng)制安全傳輸?shù)那闆r下,瀏覽器將所有將要發(fā)送到服務(wù)端的請(qǐng)求都強(qiáng)制為 https 協(xié)議。此功能默認(rèn)被開(kāi)啟,如果需要修改它的默認(rèn)配置,可通過(guò)如下方式進(jìn)行配置:@EnableWebSecuritypublic class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http // ... .headers(headers -> headers .httpStrictTransportSecurity(hsts -> hsts .includeSubDomains(true) // 包含子域名 .preload(true) // 增加到瀏覽器內(nèi)置的 HTTPS 列表 .maxAgeInSeconds(31536000) // 強(qiáng)制期限 ) ); }}

1. 前言

在上一章節(jié)中我們介紹了 HTTP 協(xié)議相關(guān)的面試題目,作為 HTTP 協(xié)議的擴(kuò)展,HTTPS 協(xié)議也經(jīng)常被面試官提起。因?yàn)閷?duì)于大部分的前端、后端開(kāi)發(fā)者,都接觸不到 HTTPS 協(xié)議的開(kāi)發(fā)場(chǎng)景,因?yàn)槲覀兺魂P(guān)注請(qǐng)求路徑后綴,例如關(guān)注 URL: /get/username,而非路徑全稱 https://coding.imooc.com/get/username ,所以考察 HTTPS 協(xié)議也是對(duì)候選人的知識(shí)深度的考驗(yàn)。

5. 使用IntelliJ IDEA快速構(gòu)建Ktor Server應(yīng)用

IntelliJ IDEA提供一個(gè)Ktor應(yīng)用插件可以快速構(gòu)建Ktor Server應(yīng)用,其中可以借助Ktor插件可視化地安裝各種Feature功能構(gòu)件。下面會(huì)一步一步引導(dǎo)快速構(gòu)建一個(gè)Ktor Server應(yīng)用。5.1 安裝Ktor插件在IDEA中的plugins模塊中,搜索ktor安裝Ktor插件。安裝完Ktor插件后,restart IDEA。5.2 創(chuàng)建Ktor應(yīng)用工程并安裝Features打開(kāi)IDEA,點(diǎn)擊new Project, 選擇左邊欄中的"Ktor"應(yīng)用,然后輸入Project name,選擇項(xiàng)目路徑、選擇構(gòu)建系統(tǒng)(Groovy Gradle、Kotlin Gradle或Maven)以及選擇對(duì)應(yīng)的服務(wù)器容器的引擎(Netty、Tomcat、Jetty、CIO).點(diǎn)擊next后,就到需要選擇對(duì)應(yīng)安裝的Feature(功能構(gòu)件),Ktor插件提供了不同類型的Features, 主要有Security、Routing、HTTP、Monitoring、Templating、Serialization、Sockets、Administration幾大類的Feature, 可以按照自己應(yīng)用的需求,按需安裝即可。Security類型相關(guān)的Features:Routing類型相關(guān)的Features: 添加Routing構(gòu)件用于路由請(qǐng)求的處理HTTP類型相關(guān)的Features: 添加CORS解決跨域訪問(wèn)問(wèn)題監(jiān)控類型相關(guān)的Features: 添加監(jiān)控日志構(gòu)件CallLogging構(gòu)件樣式模板類型相關(guān)的Features: 添加HTML DSL和CSS DSL構(gòu)件序列化類型相關(guān)的Features: 添加Gson構(gòu)件Sockets類型相關(guān)的FeaturesAdministration類型相關(guān)的Features最終,下面是我們安裝的所有Features,點(diǎn)擊Finish即可創(chuàng)建Ktor Server工程5.3 Ktor應(yīng)用工程項(xiàng)目結(jié)構(gòu)可以看到所有安裝的Features都在plugins包中生成,并在Application類main啟動(dòng)執(zhí)行的入口函數(shù)進(jìn)行初始化和配置,并且應(yīng)用程序默認(rèn)端口為:8080。Routing Feature默認(rèn)生成的代碼:Template Feature默認(rèn)生成代碼:序列化Gson Feature默認(rèn)生成代碼:5.4 運(yùn)行Ktor應(yīng)用Ktor應(yīng)用運(yùn)行起來(lái)后,可以通過(guò)localhost訪問(wèn)上述默認(rèn)生成的頁(yè)面:Routing Feature默認(rèn)生成的頁(yè)面結(jié)果: http://localhost:8080/Template Feature默認(rèn)生成的html-dsl頁(yè)面結(jié)果: http://localhost:8080/html-dslTemplate Feature默認(rèn)生成的html-dsl頁(yè)面結(jié)果: http://localhost:8080/html-css-dslGson Feature默認(rèn)生成的頁(yè)面結(jié)果: http://localhost:8080/json/gson5.5 Debug Ktor應(yīng)用

3.2 論壇系統(tǒng)概述

一個(gè)論壇系統(tǒng)由如下數(shù)據(jù)構(gòu)成:主題,每個(gè)主題包含有標(biāo)題和內(nèi)容,使用 topicID 標(biāo)識(shí)該主題;用戶,每個(gè)用戶包含姓名和密碼,使用 userID 標(biāo)識(shí)該用戶。假設(shè)論壇的域名是 www.bbs.com,它向外界提供了若干可訪問(wèn)的 URL:URL 功能 http://www.bbs.com/topics/12373 訪問(wèn) topicID 為 12373 的主題 http://www.bbs.com/users/1353 訪問(wèn) userID 為 1353 的用戶頁(yè)面

3.1 布局文件

布局文件非常簡(jiǎn)單,主要功能就是做一個(gè)解析事件的觸發(fā)和解析結(jié)果的展示即可,如下:<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/json" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentStart="true" android:layout_alignParentTop="true" android:layout_marginStart="30dp" android:layout_marginTop="46dp" android:text="Json文本" /> <Button android:id="@+id/parse" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/json" android:layout_centerHorizontal="true" android:layout_marginTop="30dp" android:text="開(kāi)始解析" /></RelativeLayout>

4.3 布局文件編寫(xiě)

布局文件主要有兩個(gè)關(guān)鍵點(diǎn):添加一個(gè)輸入框 EditText,用于接收用戶的輸入;添加一個(gè) Button,用于觸發(fā)廣播的發(fā)送,同時(shí)獲取 EditText 中輸入的內(nèi)容放入 intent 中。如下:<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginStart="100dp" android:layout_marginTop="150dp" android:text="廣播接收器" android:textColor="#a4c639" android:textSize="50sp" /> <EditText android:id="@+id/textMsg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="100dp" android:layout_marginTop="270dp" android:ems="10" /> <Button android:id="@+id/send" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="130dp" android:layout_marginTop="310dp" android:text="發(fā)送廣播" /></RelativeLayout>

1.1 Nginx中的模塊化設(shè)計(jì)

Nginx 的內(nèi)部結(jié)構(gòu)是由核心部分和一系列的功能模塊所組成。這樣劃分是為了使得每個(gè)模塊的功能相對(duì)簡(jiǎn)單,便于開(kāi)發(fā),同時(shí)也便于對(duì)系統(tǒng)進(jìn)行功能擴(kuò)展。Nginx 將各功能模塊組織成一條鏈,當(dāng)有請(qǐng)求到達(dá)的時(shí)候,請(qǐng)求依次經(jīng)過(guò)這條鏈上的部分或者全部模塊,進(jìn)行處理。例如前面講到的 http 請(qǐng)求,會(huì)有11個(gè)處理階段,而每個(gè)階段有對(duì)應(yīng)著許多在此階段生效的模塊對(duì)該 http 請(qǐng)求進(jìn)行處理。同時(shí),Nginx 開(kāi)放了第三方模塊編寫(xiě)功能,用戶可以自定義模塊,控制 http 請(qǐng)求的處理與響應(yīng),這種高度可定制化催生了 Nginx 的大量第三方模塊,也使得 Nginx 定制化開(kāi)發(fā)在各大互聯(lián)網(wǎng)公司十分流行。

5.1 <a href="http://idcbgp.cn/wiki/flasklesson/flaskintro.html">Flask</a>

和 Django 直接競(jìng)爭(zhēng)的 Web 框架莫過(guò)于 Flask 和 Tornado 了。Flask 是除了 Django 之外另一個(gè)流行的 Python Web 框架。Flask 的設(shè)計(jì)哲學(xué)和 Django 恰恰相反,它不會(huì)替開(kāi)發(fā)者做選擇,有且只有一個(gè)核心的模塊,因此沒(méi)有過(guò)多的額外功能。Flask 可以被稱為一個(gè)微框架,服務(wù)的更多功能會(huì)由開(kāi)發(fā)者自行選擇的插件提供。因此,F(xiàn)lask 的強(qiáng)大第三方市場(chǎng)也使得其與 Django 能在正面上產(chǎn)生競(jìng)爭(zhēng)。其在 GitHub 上的關(guān)注度和社區(qū)活躍度與 Django 類似,這也表明越來(lái)越多的開(kāi)發(fā)者正在關(guān)注著 Flask。Flask 起步比較晚,社區(qū)和生態(tài)不如 Django 那樣完善,此外它不如 Django 那樣對(duì)初學(xué)者友好,學(xué)習(xí)成本相比 Django 要高。

7.7 測(cè)試

啟動(dòng)項(xiàng)目,打開(kāi)瀏覽器訪問(wèn) http://127.0.0.1:8080/goods ,即可查看輸出結(jié)果。

4.1 POST 發(fā)送請(qǐng)求

話不多說(shuō),上代碼:xhr.open("POST", "http://localhost:8080/simple/post");xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");xhr.send("mk=慕課網(wǎng)&class=ajax");查看效果圖:基本和上面 GET 請(qǐng)求類似,這里我們構(gòu)造了一個(gè) POST 請(qǐng)求,請(qǐng)求的 url 為 http://localhost:8080/simple/post,發(fā)送請(qǐng)求的參數(shù)有兩個(gè),分別為 mk=慕課網(wǎng) 和 class=ajax。從瀏覽器的控制臺(tái)面板上可以看到,在 Headers 上,F(xiàn)orm Data 部分正是我們要發(fā)送的數(shù)據(jù),數(shù)據(jù)發(fā)送正常。這里兩個(gè)地方需要注意:send 方法接受可選參數(shù)作為請(qǐng)求主體,即發(fā)送到服務(wù)器的內(nèi)容。Content-type 需要設(shè)置為請(qǐng)求主體類型, 這是因?yàn)槿绻辉O(shè)置的話會(huì)采取默認(rèn)值,在很多時(shí)候服務(wù)端可能無(wú)法解析參數(shù)。XMLHttpRequest.setRequestHeader() 是請(qǐng)求HTTP 請(qǐng)求頭部的方法,因此設(shè)置 Content-type 自然也是通過(guò)調(diào)用這個(gè)方法來(lái)實(shí)現(xiàn)。該方法需要在 open() 和 send() 之間使用。

3.1 應(yīng)用層

為終端應(yīng)用提供的服務(wù),如我們的瀏覽器交互時(shí)候需要用到的 HTTP 協(xié)議,郵件發(fā)送的 SMTP,文件傳輸?shù)?FTP 等。

4.5 其它常用的模塊

模塊名功能urllib3Python HTTP庫(kù),安全連接池、支持文件postRoboBrowser無(wú)需獨(dú)立的瀏覽器即可瀏覽網(wǎng)頁(yè)MechanicalSoup一個(gè)與網(wǎng)站自動(dòng)交互 Python 庫(kù)mechanize有狀態(tài)、可編程的 Web 瀏覽庫(kù)hyperPython的HTTP/2客戶端grab網(wǎng)絡(luò)爬蟲(chóng)框架(基于pycurl/multicur)scrapy網(wǎng)絡(luò)爬蟲(chóng)框架(基于twisted)架selenium用于Web應(yīng)用程序測(cè)試的工具jieba中文分詞工具OpenCV開(kāi)源計(jì)算機(jī)視覺(jué)庫(kù)SimpleCV用于照相機(jī)、圖像處理、特征提取、格式轉(zhuǎn)換

2.1 @RequestMapping 的位置

@RequestMapping 注解既可以放置在類前面也可以放在方法前面。@Controller//類名前面 @RequestMapping("/user") public class UserController { @RequestMapping(value = "/register") public String register() { return “user/register”; }}如上代碼,請(qǐng)求控制器中的 register() 方法的 URL 應(yīng)該是 http://localhost:8888/user/register 。 如果類前面沒(méi) @RequestMapping 則訪問(wèn)的 URL 應(yīng)該是 http://localhost:8888/register 。如此可知,通過(guò)類前面添加 @RequestMapping 注解可以歸類控制器的主體功能,窄化請(qǐng)求范圍。Tips: 可以把類前面 @RequestMapping 中提供的名字看成命名空間。

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

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

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

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