日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

play框架使用起来(18)

發布時間:2023/12/14 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 play框架使用起来(18) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1、集成OpenID

OpenID是身份識別系統,具有開放,非集中等特點。我們只需要記錄OpenID授權用戶的使用信息,不必保持用戶的特定狀態,就可以在程序中很容易地識別新用戶。


補充:

OpenID是去中心化的網上身份認證系統。對于支持OpenID的網站,用戶不需要記住像用戶名和密碼這樣的傳統驗證標記。取而代之的是,他們只需要預先在一個作為OpenID身份提供者(identity provider, IdP)的網站上注冊。OpenID是去中心化的,任何網站都可以使用OpenID來作為用戶登錄的一種方式,任何網站也都可以作為OpenID身份提供者。OpenID既解決了問題而又不需要依賴于中心性的網站來確認數字身份。


??????下面實例將演示在Play應用中如何使用OpenID認證,以下是OpenID認證過程:

  • 針對每個用戶請求,先檢查用戶是否已經連接OpenID。
  • 如果用戶沒有連接OpenID,跳轉至用戶可以提交OpenID的頁面。
  • 將用戶提交的OpenID重定向到OpenID提供商。
  • 返回后,得到驗證通過的OpenID用戶信息,并將它保存在HTTP Session中。


??????Play中的OpenID功能由play.libs.OpenID輔助類提供,基于OpenID4Java實現。我們在控制器中定義authenticate()方法,處理用戶提交的OpenID。該方法先進行用戶OpenID的檢查,如果已經連接,則將用戶信息保存在HTTP Session中,并顯示歡迎頁面。如果用戶是第一次提交OpenID,則將提交的OpenID重定向到OpenID提供商:

@Before(unless={"login", "authenticate"})
static void checkAuthenticated() {
? ?
if(!session.contains("user")) {
? ? ? ? login
();
? ?
}
}
?
public static void index() {
? ? render
("Hello %s!", session.get("user"));
}
? ? ?
public static void login() {
? ? render
();
}
? ?
public static void authenticate(String user) {
? ?
if(OpenID.isAuthenticationResponse()) {
? ? ? ?
UserInfo verifiedUser = OpenID.getVerifiedID();
? ? ? ?
if(verifiedUser == null) {
? ? ? ? ? ? flash
.error("Oops. Authentication has failed");
? ? ? ? ? ? login
();
? ? ? ?
}
? ? ? ? session
.put("user", verifiedUser.id);
? ? ? ? index
();
? ?
} else {
? ? ? ?
if(!OpenID.id(user).verify()) { // will redirect the user
? ? ? ? ? ? flash
.error("Cannot verify your OpenID");
? ? ? ? ? ? login
();
? ? ? ?
}
? ?
}
}

??????創建Login.html模板,添加用戶提交OpenID的表單:

#{if flash.error}
<h1>${flash.error}</h1>
#{/if}
?
<form action="@{Application.authenticate()}" method="POST">
? ?
<label for="user">Whats your OpenID?</label>
? ?
<input type="text" name="user" id="user" />
? ?
<input type="submit" value="login..." />
</form>

??????最后定義路由:

GET ? / ? ? ? ? ? ? ? ? ? ? Application.index
GET ?
/login ? ? ? ? ? ? ? ?Application.login
* ? ? /authenticate ? ? ? ? Application.authenticate

2、Ajax請求

2.1 集成jQuery#

??????Play默認集成了jQuery庫,并將其存放于應用的public/javascripts目錄。框架對jQuery進行了封裝,提供#{jsAction /}標簽簡化了請求異步調用控制器中的Action方法,因此我們可以通過jQuery非常方便地處理Ajax請求。

??????本節將以簡單的Ajax應用為例,介紹在Play框架中如何使用jQuery提供的Ajax支持。


2.2 使用#{jsAction /}#

??????Play提供的#{jsAction /}標簽會返回一個JavaScript函數,該JavaScript函數由基于Action方法的URL連接和自由變量組成。它并不會自動執行Ajax請求,而需要我們先手動對返回的URL進行配置。

??????下面介紹Play應用的Ajax實例。首先在控制器Hotels中定義Action方法list,用于處理瀏覽器異步提交的請求。list方法定義完成后為其配制路由規則:

GET ? ? /hotels/list ? ? ? ?Hotels.list

??????我們在客戶端中可以通過以下方式導入路由:

<script type="text/javascript">
? ?
var listAction = #{jsAction @list(':search', ':size', ':page') /}
? ?$
('#result').load(
? ? ? ?listAction
({search: 'x', size: '10', page: '1'}),
? ? ? ?
function() {
? ? ? ? ? ?$
('#content').css('visibility', 'visible')
? ? ? ?
}
? ?
)
</script>

??????在這個例子中,我們向Hotels控制器中的list方法發送請求,請求中包含search,size和page三個參數。之后將請求保存在listAction變量中,使用load函數通過jQuery處理該請求(這里處理的是HTTP GET請求)。以下就是所發送請求的具體URL:

GET /hotels/list?search=x&size=10&page=1

??????以這種方式發送請求會返回HTML數據。當然,我們也可以在控制器中使用適當的渲染方法,返回其他格式的數據,比如renderJSON, renderXML或者直接使用XML的模版等。在客戶端接收到JSON或者XML數據后,可以通過jQuery進行格式轉換。如果讀者還想了解更多細節問題,可以查閱jQuery相關內容。

??????如果讀者需要使用POST請求,只需要將jQuery方法進行轉換即可:

$.post(listAction(), function(data) {
? $
('#result').html(data);
});


2.3 使用#{jsRoute /}#

??????Play提供的#{jsRoute /}標簽,可以幫助開發者更好地管理路由。#{jsRoute /}標簽的使用方法很簡單,并且與#{jsAction /}類似,但是不同的地方為#{jsRoute /}標簽返回的是一個對象。該對象包含基于服務端Action的URL,以及相應的HTTP方法(GET、POST等),具體范例如下所示。

<script type="text/javascript">
? ?
var updateUserRoute = #{jsRoute @Users.update(':id') /}
? ? $
.ajax({
? ? ? url
: updateUserRoute.url({id: userId}),
? ? ? type
: updateUserRoute.method,
? ? ? data
: 'user.name=Guillaume'
? ?
});
</script>

??????使用#{jsRoute /}標簽所帶來的好處是顯而易見的,開發者只需要修改routes路由文件,就可以統一地改變HTTP方法,而不再需要一個一個查看和修改模板文件了。


3、管理數據庫升級

開發人員使用關系數據庫時,通常需要跟蹤和管理數據庫結構的升級和變化。當出現以下幾種情況時,我們需要使用更成熟的方式跟蹤和管理數據庫結構的變化:

  • 在團隊開發中,每個成員都需要知道數據庫結構的任何變化。
  • 當成品部署到服務器上后,需要采用安全穩定的方式去升級數據庫結構。
  • 當開發人員在不同的機器上工作時,需要保持數據庫同步。


注意:

如果采用JPA進行操作,Hibernate會自動處理數據庫結構的升級。如果讀者經常需要手動管理數據庫結構,并進行一些精細的調整,版本控制就變得必不可少了。


3.1 升級腳本#

??????Play通過編寫升級腳本來跟蹤數據庫結構的變化。這些腳本采用標準的SQL語句作為語法規則,存放在應用程序的db/evolutions目錄下。腳本使用統一的命名規則:編寫的第一個腳本命名為1.sql,第二個腳本為2.sql,并以此類推。每個腳本都包含兩個部分:

  • Ups部分用于描述需要改變的地方。
  • Downs部分用于描述如何還原。


??????以下是數據庫升級腳本的例子,起到引導作用:

# Users schema
?
# --- !Ups
?
CREATE TABLE
User (
? ? id bigint
(20) NOT NULL AUTO_INCREMENT,
? ? email varchar
(255) NOT NULL,
? ? password varchar
(255) NOT NULL,
? ? fullname varchar
(255) NOT NULL,
? ? isAdmin
boolean NOT NULL,
? ? PRIMARY KEY
(id)
);
?
# --- !Downs
?
DROP TABLE
User;


注意:

在編寫數據庫升級腳本時,須使用注釋明確地將Ups和Downs部分區分開。


??????如果讀者已經在application.conf文件中配置了數據庫,并且編寫了數據庫升級腳本(放置在db/evolutions目錄下),應用在啟動時就會自動激活數據庫的升級模式。我們也可以強制將其關閉,只需在application.conf文件中進行如下配置:

evolutions.enabled=false ??????一旦數據庫的升級模式被激活,框架會執行升級管理。當應用處于DEV模式,Play會在請求到達時檢查數據庫的結構,如果數據庫結構不是最新的,將顯示錯誤頁面,并建議使用合適的SQL腳本同步數據庫,如圖1所示。如果應用處于PROD模式,Play則會在整個應用啟動之前進行檢查。

(圖1 數據庫結構不同步)

??????在頁面上點擊Apply evolutions按鈕,就可以直接執行SQL升級腳本。


補充:

如果應用使用內存數據庫(db=mem),Play會預先對數據庫進行檢測。如果數據庫為空就會自動執行所有的升級腳本。


3.2 同步#

??????協作開發中,保持應用同步非常重要。設想一下,如果有兩個開發者合力開發項目,開發者A因為自己負責的功能模塊需要,創建了新的數據表并編寫了升級腳本2.sql:

# Add Post
?
# --- !Ups
CREATE TABLE
Post (
? ? id bigint
(20) NOT NULL AUTO_INCREMENT,
? ? title varchar
(255) NOT NULL,
? ? content text NOT NULL
,
? ? postedAt date NOT NULL
,
? ? author_id bigint
(20) NOT NULL,
? ? FOREIGN KEY
(author_id) REFERENCES User(id),
? ? PRIMARY KEY
(id)
);
?
# --- !Downs
DROP TABLE
Post;

??????Play會將該升級腳本應用于開發者A的數據庫。與此同時,開發者B因功能需求修改了User表,也編寫了升級腳本,同樣命名為2.sql:

# Update User
?
# --- !Ups
ALTER TABLE
User ADD age INT;
?
# --- !Downs
ALTER TABLE
User DROP age;

??????開發者B先完成了負責的功能模塊,并提交了代碼(比如開發者采用Git進行管理)。開發者A需要先整合兩個人前半段的工作結果,才能開展后續工作,但是在執行git pull的時候,合并會出現如下沖突:

Auto-merging db/evolutions/2.sql
CONFLICT
(add/add): Merge conflict in db/evolutions/2.sql
Automatic merge failed; fix conflicts and then commit the result.

??????這是因為開發者A和開發者B都創建了2.sql升級腳本,必須進行整合:

<<<<<<< HEAD
# Add Post
?
# --- !Ups
CREATE TABLE
Post (
? ? id bigint
(20) NOT NULL AUTO_INCREMENT,
? ? title varchar
(255) NOT NULL,
? ? content text NOT NULL
,
? ? postedAt date NOT NULL
,
? ? author_id bigint
(20) NOT NULL,
? ? FOREIGN KEY
(author_id) REFERENCES User(id),
? ? PRIMARY KEY
(id)
);
?
# --- !Downs
DROP TABLE
Post;
=======
# Update User
?
# --- !Ups
ALTER TABLE
User ADD age INT;
?
# --- !Downs
ALTER TABLE
User DROP age;
>>>>>>> devB

??????整合工作非常簡單,只需要將沖突的部分合并即可:

# Add Post and update User
?
# --- !Ups
ALTER TABLE
User ADD age INT;
?
CREATE TABLE
Post (
? ? id bigint
(20) NOT NULL AUTO_INCREMENT,
? ? title varchar
(255) NOT NULL,
? ? content text NOT NULL
,
? ? postedAt date NOT NULL
,
? ? author_id bigint
(20) NOT NULL,
? ? FOREIGN KEY
(author_id) REFERENCES User(id),
? ? PRIMARY KEY
(id)
);
?
# --- !Downs
ALTER TABLE
User DROP age;
?
DROP TABLE
Post;

??????將整合后的腳本命名為2.sql,作為升級腳本的最新修訂版(注意:與前期開發者A應用到數據庫的2.sql不同)。Play會發現這個情況,并詢問開發者A是否同步數據庫,將最新的修訂版2.sql替換原來的版本,如圖2所示。

(圖2 同步升級腳本)


3.3 非同步狀態#

??????如果腳本(比如3.sql)中存在錯誤,數據庫升級工作將無法完成。當出現這種情況時,Play會將數據庫的結構標記為非同步狀態,并要求我們手動解決這個問題,之后才能繼續別的操作。下例的Ups部分存在錯誤:

# Add another column to User
?
# --- !Ups
ALTER TABLE
Userxxx ADD company varchar(255);
?
# --- !Downs
ALTER TABLE
User DROP company;

??????該腳本在執行時會出現錯誤,Play將數據庫的結構標記為非同步狀態,如圖3所示:

(圖3非同步狀態)

??????錯誤必須得到修正后,才能進行后續操作。使用SQL命令手動更改數據庫結構:

ALTER TABLE User ADD company varchar(255);

??????然后點擊Mark it resolved按鈕,通知框架問題已經解決。由于原先的升級腳本存在錯誤,必須將其修正。修改3.sql腳本文件:

# Add another column to User
?
# --- !Ups
ALTER TABLE
User ADD company varchar(255);
?
# --- !Downs
ALTER TABLE
User DROP company;

??????Play會發現該升級腳本是最新的,因此覆蓋原有的3.sql執行,如圖4所示:

(圖4 成功執行數據庫結構同步)

??????圖4 所顯示的是腳本正確執行的結果,之后可以繼續別的工作。


補充:

介紹一個開發小技巧:開發人員可以在每次開發前手動刪除原有的數據庫,當應用啟動時框架就會自動加載所有的升級腳本。這樣做的好處是可以使開發人員的數據庫一直保持最新版本。


3.4 升級命令#

??????當應用處于DEV模式時,數據庫升級是交互式地進行的。但是在PROD模式下,必須先使用play evolutions命令將數據庫結構升級為最新版本,才可以開啟應用。當框架發現應用程序的數據庫不是最新版本時,控制臺會出現如下錯誤信息:

~ ? ? ? ?_ ? ? ? ? ? ?_
~ ?_ __ | | __ _ _ ?_| |
~ | '_ \| |/ _' | || |_|
~ | ?__/|_|\____|\__ (_)
~ |_| ? ? ? ? ? ?|__/ ?
~
~ play! master-localbuild, http://www.playframework.org
~ framework ID is prod
~
~ Ctrl+C to stop
~
13:33:22 INFO ?~ Starting ~/test
13:33:22 INFO ?~ Precompiling ...
13:33:24 INFO ?~ Connected to jdbc:mysql://localhost
13:33:24 WARN ?~
13:33:24 WARN ?~ Your database is not up to date.
13:33:24 WARN ?~ Use `play evolutions` command to manage database evolutions.
13:33:24 ERROR ~
?
@662c6n234
Can't start in PROD mode with errors
?
Your database needs evolution!
An SQL script will be run on your database.
?
play.db.Evolutions$InvalidDatabaseRevision
? ? ? ? at play.db.Evolutions.checkEvolutionsState(Evolutions.java:323)
? ? ? ? at play.db.Evolutions.onApplicationStart(Evolutions.java:197)
? ? ? ? at play.Play.start(Play.java:452)
? ? ? ? at play.Play.init(Play.java:298)
? ? ? ? at play.server.Server.main(Server.java:141)
Exception in thread "main" play.db.Evolutions$InvalidDatabaseRevision
? ? ? ? at play.db.Evolutions.checkEvolutionsState(Evolutions.java:323)
? ? ? ? at play.db.Evolutions.onApplicationStart(Evolutions.java:197)
? ? ? ? at play.Play.start(Play.java:452)
? ? ? ? at play.Play.init(Play.java:298)
? ? ? ? at play.server.Server.main(Server.java:141)

??????該錯誤信息提示我們運行play evolutions命令同步數據庫:

$ play evolutions
~ ? ? ? ?_ ? ? ? ? ? ?_
~ ?_ __ | | __ _ _ ?_| |
~ | '_ \| |/ _' | || |_|
~ | ?__/|_|\____|\__ (_)
~ |_| ? ? ? ? ? ?|__/ ?
~
~ play! master-localbuild, http://www.playframework.org
~ framework ID is gbo
~
~ Connected to jdbc:mysql://localhost
~ Application revision is 3 [15ed3f5] and Database revision is 0 [da39a3e]
~
~ Your database needs evolutions!
?
# ----------------------------------------------------------------------------
?
# --- Rev:1,Ups - 6b21167
?
CREATE TABLE
User (
? ? id bigint
(20) NOT NULL AUTO_INCREMENT,
? ? email varchar
(255) NOT NULL,
? ? password varchar
(255) NOT NULL,
? ? fullname varchar
(255) NOT NULL,
? ? isAdmin
boolean NOT NULL,
? ? PRIMARY KEY
(id)
);
?
# --- Rev:2,Ups - 9cf7e12
?
ALTER TABLE
User ADD age INT;
CREATE TABLE
Post (
? ? id bigint
(20) NOT NULL AUTO_INCREMENT,
? ? title varchar
(255) NOT NULL,
? ? content text NOT NULL
,
? ? postedAt date NOT NULL
,
? ? author_id bigint
(20) NOT NULL,
? ? FOREIGN KEY
(author_id) REFERENCES User(id),
? ? PRIMARY KEY
(id)
);
?
# --- Rev:3,Ups - 15ed3f5
?
ALTER TABLE
User ADD company varchar(255);
?
# ----------------------------------------------------------------------------
?
~ Run `play evolutions:apply` to automatically apply this script to the db
~ or apply it yourself and mark it done using `play evolutions:markApplied`
~

??????使用play evolutions:apply命令可以通知Play自動執行數據庫升級腳本:

play evolutions:apply

??????如果在成品數據庫上手動執行腳本,可以使用play evolutions:markApplied命令通知Play該數據庫已經是最新版本了:

play evolutions:markApplied

??????當應用處于DEV模式,如果框架自動執行升級腳本失敗,就需要手動解決,并將數據庫結構標記為已修正的:

play evolutions:resolve


總結

以上是生活随笔為你收集整理的play框架使用起来(18)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。