Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
者:HelloGitHub-追夢人物
博客文章的模型有一個 excerpt 字段,這個字段用于存儲文章的摘要。目前為止,還只能在 django admin 后臺手動為文章輸入摘要。每次手動輸入摘要比較麻煩,對有些文章來說,只要摘取正文的前 N 個字符作為摘要,以便提供文章預覽就可以了。因此我們來實現(xiàn)如果文章沒有輸入摘要,則自動摘取正文的前 N 個字符作為摘要,這有兩種實現(xiàn)方法。
覆寫 save 方法
第一種方法是通過覆寫模型的 save 方法,從正文字段摘取前 N 個字符保存到摘要字段。在 創(chuàng)作后臺開啟,請開始你的表演[1] 中我們提到過 save 方法中執(zhí)行的是保存模型實例數(shù)據(jù)到數(shù)據(jù)庫的邏輯,因此通過覆寫 save 方法,在保存數(shù)據(jù)庫前做一些事情,比如填充某個缺失字段的值。
回顧一下博客文章模型代碼:
blog/models.py ? class Post(models.Model): # 其它字段... body=models.TextField() excerpt=models.CharField(max_length=200, blank=True) def save(self, *args, **kwargs): self.modified_time=timezone.now() super().save(*args, **kwargs)
其中 body 字段存儲的是正文,excerpt 字段用于存儲摘要。通過覆寫模型的 save 方法,在數(shù)據(jù)被保存到數(shù)據(jù)庫前,先從 body 字段摘取 N 個字符保存到 excerpt 字段中,從而實現(xiàn)自動摘要的目的。具體代碼如下:
blog/models.py ? import markdown from django.utils.html import strip_tags ? class Post(models.Model): # 其它字段... body=models.TextField() excerpt=models.CharField(max_length=200, blank=True) # 其它方法... def save(self, *args, **kwargs): self.modified_time=timezone.now() ? # 首先實例化一個 Markdown 類,用于渲染 body 的文本。 # 由于摘要并不需要生成文章目錄,所以去掉了目錄拓展。 md=markdown.Markdown(extensions=[ 'markdown.extensions.extra', 'markdown.extensions.codehilite', ]) ? # 先將 Markdown 文本渲染成 HTML 文本 # strip_tags 去掉 HTML 文本的全部 HTML 標簽 # 從文本摘取前 54 個字符賦給 excerpt self.excerpt=strip_tags(md.convert(self.body))[:54] ? super().save(*args, **kwargs)
這里生成摘要的方案是,先將 body 中的 Markdown 文本轉為 HTML 文本,去掉 HTML 文本里的 HTML 標簽,然后摘取文本的前 54 個字符作為摘要。去掉 HTML 標簽的目的是防止前 54 個字符中存在塊級 HTML 標簽而使得摘要格式比較難看。可以看到很多網(wǎng)站都采用這樣一種生成摘要的方式。
然后在模板中適當?shù)牡胤绞褂媚0鍢撕炓?{{ post.excerpt }} 顯示摘要的值即可:
templates/blog/index.html ? <article class="post post-{{ post.pk }}"> ... <div class="entry-content clearfix"> <p>{{ post.excerpt }}...</p> <div class="read-more cl-effect-14"> <a href="{{ post.get_absolute_url }}" class="more-link">繼續(xù)閱讀 <span class="meta-nav">→</span></a> </div> </div> </article>
新添加一篇文章(這樣才能觸發(fā) save 方法,此前添加的文章不會自動生成摘要,要手動保存一下觸發(fā) save 方法),可以看到摘要效果了。
使用 truncatechars 模板過濾器
第二種方法是使用 truncatechars 模板過濾器(Filter)。在 django 的模板系統(tǒng)中,模板過濾器的使用語法為 {{ var | filter: arg }}。可以將模板過濾看做一個函數(shù),它會作用于被它過濾的模板變量,從而改變模板變量的值。例如這里的 truncatechars 過濾器可以截取模板變量值的前 N 個字符顯示。關于模板過濾器,我們之前使用過 safe 過濾器,可以參考 讓博客支持 Markdown 語法和代碼高亮[2] 這篇文章中對模板過濾器的說明。
例如摘要效果,需要顯示 post.body 的前 54 的字符,那么可以在模板中使用 {{ post.body | truncatechars:54 }}。
templates/blog/index.html ? <article class="post post-{{ post.pk }}"> ... <div class="entry-content clearfix"> <p>{{ post.body|truncatechars:54 }}</p> <div class="read-more cl-effect-14"> <a href="{{ post.get_absolute_url }}" class="more-link">繼續(xù)閱讀 <span class="meta-nav">→</span></a> </div> </div> </article>
不過這種方法的一個缺點就是如果前 54 個字符含有塊級 HTML 元素標簽的話(比如一段代碼塊),會使摘要比較難看。所以推薦使用第一種方法。
References
[1] 創(chuàng)作后臺開啟,請開始你的表演: https://www.zmrenwu.com/courses/hellodjango-blog-tutorial/materials/65/
[2]讓博客支持 Markdown 語法和代碼高亮:
https://www.zmrenwu.com/courses/hellodjango-blog-tutorial/materials/67/
『講解開源項目系列』——讓對開源項目感興趣的人不再畏懼、讓開源項目的發(fā)起者不再孤單。跟著我們的文章,你會發(fā)現(xiàn)編程的樂趣、使用和發(fā)現(xiàn)參與開源項目如此簡單。歡迎加入我們,讓更多人愛上開源、貢獻開源~
文章中的某段文字轉化為鏈接:
混沌現(xiàn)象——扇形內(nèi)部的光線反射現(xiàn)象_百度經(jīng)驗
https://jingyan.baidu.com/article/0eb457e5ca429103f1a90507.html
先熟悉一下這個網(wǎng)頁!
然后在Runoob網(wǎng)頁里面運行如下代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<p>
<a >扇形內(nèi)部的光線反射現(xiàn)象</a>
是一個指向百度經(jīng)驗網(wǎng)站中的一個頁面的鏈接。</p>
</body>
</html>
點擊超鏈接,就會直接跳轉:
在移動商城的設計中,除商品和分類查詢是完全開放權限的頁面外,其他涉及個人隱私的個人信息、訂單查詢和購物車等都必須進行權限管理。
有關用戶權限管理的功能,在這里根據(jù)移動設備的特點,使用了本地存儲的方式,提供了用戶登錄設計和賬號切換設計。
注意,為了節(jié)省篇幅,這里的用戶信息只是一個演示數(shù)據(jù),并沒有跟實際用戶服務進行綁定。
用戶登錄設計
在用戶登錄設計中,為了保證用戶身份的真實性,可以由用戶提供手機號,并通過短信接收到的驗證碼進行驗證。
用戶登錄設計主要在視圖 verify.html 中實現(xiàn),這是一個H5單頁設計,主要使用本地存儲來保存用戶的登錄狀態(tài),代碼如下所示:
<! DOCTYPE html>
<html xmlns:th- "http://www.thymeleaf.org">
<head>
<meta charset="utf-8"/>
<meta content="yes" name="apple-mobile-web-app-capable"/>
<meta content="black" name="apple-mobile-web-app-status-bar-style"/><meta name="format-detection" content="telephone=no"/>
<script th:src="@{/scripts/viewscale.js}"></script>
<script th:src="@{/scripts/jquery-1.10.2.min.js)"></script><title>用戶登錄</title>
<link th:href="@(/styles/microApply.css}" rel="stylesheet"
type="text/css"/>
<style type="text/css">
article, aside,dialog, footer, header,section, footer, nav,figure, menu {display:block}
</style></head>
<body>
<div class="content">
<div class="iphone">
<pclass="tips">手機號碼</p>
<input type="text" placeholder="" value="13500001111"/></div>
<div class=" verifyBox">
<p class="tips">驗證碼</p>
<input type="text" placeholder="" value="123456"/></div>
<div class="verifyErro" style="display:none; ">
<span></span>
<pclass="tips">驗證碼錯誤</p><p class="countdown"></p>
</div>
<div class="sure"><input class="verifyBtn" type="submit" value="確定
"/></div>
</div>
<div class="copy">關于我們</div></body>
<script>
/*<![CDATA[*/
$(function(){
$('.verifyBtn') ﹒click(function(){//驗證失敗
//$(".verifyErro") .show();
var storage=window.localStorage;
var customer=new Object(o;
new Object ();
customer-phone="13500001111";customer.userid-"11111235";
var str=JSON .stringify(customer);storage.setItem ("user", str);
window. location.href="./index";});
$( '.verifyBoX').find ( 'input').click(function(){
$( " .verifyErro").hide();
});
H);/*]]>*/</script>
</html>
這里為了簡化設計,我們把手機號和驗證碼都寫進了程序中。
當用戶通過驗證后,將在本地存儲中登記用戶的手機號和用戶ID,讓用戶處于登錄狀態(tài)中直到用戶切換賬號時,才退出當前登錄狀態(tài)。所以在測試時,直接單擊“確定”按鈕后,即可保存用戶的登錄狀態(tài)。
用戶登錄設計完成之后,顯示效果如圖9-4所示。
用戶登錄之后,當需要進行身份確認時,就可以通過本地存儲取得用戶信息,執(zhí)行相關的操作流程。
賬號切換設計
如果用戶沒有清除移動設備的緩存,則本地存儲將長期存在。為了讓用戶能夠退出登錄狀態(tài),或者切換到另一個賬號進行操作,這里提供了一個切換賬號設計。
切換賬號視圖設計“switch.html”是一個H5單頁,實現(xiàn)代碼如下所示:
<!DOCTYPE html>
<html xmlns: th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8"/>
<meta content="yes" name="apple-mobile-web-app-capable"/>
<meta content="black" name="apple-mobile-web-app-status-bar-style<meta name="format-detection" content="telephone=no"/>
<script th:src="@{/scripts/viewscale.js}"></script>
<script th:src="@(/scripts/jquery-1.10.2.min.js}"></script><title>切換賬號</title>
<link th:href="@{/styles/microApply.css}" rel="stylesheet"
type="text/css"/>
<style type="text/css">
article, aside,dialog,footer,header,section,footer,nav,figure, menu{display:block}
</style></head>
<body>
<div class="content">
<div class="iphone">
<pclass="swit">切換登錄賬號</p></div>
<div class="sure"><input class="switchBtn" type="submit" value="確
定
"/></div>
</div>
<div class="copy">關于我們</div></body>
<script>
/*<![CDATA[*/
$(function(){
$(' .switchBtn') .click (function(){
var storage=window. 1ocalStorage;
storage. removeItem ("user");
window. location.href="./index";});
});/*]]>*/</script>
</html>
從上面的代碼可以看出,只要在本地存儲中清除用戶登錄時保存的用戶對象,就可以退出登錄狀態(tài),然后將用戶引導到訂單查詢的主頁上,在這里會自動要求用戶進行登錄。
切換賬號設計完成之后,顯示效果如圖9-5所示。
在訂單查詢設計中,主要是使用訂單列表的方式顯示每一個特定用戶的訂單。
首先在OrderController 控制器中,設計一個訂單的主頁鏈接,通過主頁顯示訂單列表及其詳細信息,代碼如下所示:
@RestController
@RequestMapping ("/order")CSlf4j
public class OrderController {
@Autowired
private OrderRestService orderRestService;
@RequestMapping (value="/index")
public ModelAndView index(ModelMap model) throws Exception{
return new ModelAndview ( "order/index");
}
@RequestMapping(value="/list")
public Page<Map<String,Object>> findAll (0rderQo orderQo){
String json=orderRestService.findPage(orderQo);
Pageable pageable=PageRequest.of (orderQo.getPage(),orderQo.getSize(),
null);
List<0rderQo> list=new Gson() .fromJson(json,new
TypeToken<List<orderQo>>(){}.getType());
for(0rderQo order :list){
order.setStatusStr (StatusEnum.valueOf (order.getStatus ()).getName ());
}
String count=orderRestService.getCount ();
return new Page Impl(list, pageable,new Long ( count));
}
}
在上面的代碼中,通過“/index”鏈接,返回訂單查詢的主頁視圖設計“index.html”
訂單查詢的主頁視圖設計與商品查詢設計相似,都是通過屏幕的滑動下拉實現(xiàn)自動分頁功能的,不同之處在于權限管理和信息顯示處理設計。
為了保證每個用戶只能查詢自己的訂單,在訂單列表查詢視圖設計中會檢查用戶的登錄狀態(tài)。如果用戶未登錄,則提示用戶登錄,實現(xiàn)代碼如下所示:
<script>
var storage=window. localStorage;
var user=storage.getItem("user");
var userid;var orderno;
if(user){
var a=JSON .parse(user);userid=a.userid;
Jelse{
window.location. href="./verify";
</script>
另外,在訂單的信息處理中,使用了如下所示的設計:
<script>
/*<! [CDATA[*/
//刷新頁面數(shù)據(jù)
function listData(pageNum, pageSize, callback){
var $dataUl=$(" .dataUl");$.ajax({
url: "./list",data:{
orderNo:orderno,userid:userid,page: pageNum,size:pageSize},
type: "GET",
dataType: "json",
success: function (data){
$('#totalPage ').val(data.totalPages);var html='';
$.each(data.content, function (i,v){
html +='<li>';
html +='<div class="orderInfList">';
html +='<div class="orderInfTxtclearPb">';
html+='<p>訂?單?號:'+v.orderNo +'('+
v.statusStr +')</p>';
html +='<p>訂單金額:¥'+v.amount.toFixed(2)+'</p>';html +='<p>下單時間:'+new Date(v.created).format
("yyyy-MM-dd HH:mm:ss")+ '</p>';
html +='</div>';
html +='<div class="orderPicList">';$.each(v.orderDetails, function (j,w){
html +='<img src="' +w.photo +'"/>';});
html +='</div>';html +='</div>';html +='</li>';
});
$dataUl .append (html);callback &&callback();
});
/*]]>*/
</script>
在上面的代碼中使用了四個參數(shù)進行查詢,即訂單號 ( orderNo)、用戶編號(userid)頁碼(page)和每頁行數(shù)(size)。其中,訂單號可以由用戶輸入,如果用戶未提供訂單號,則顯示所有的訂單。同時,針對訂單金額的小數(shù)位數(shù)也進行了設定,以避免因為浮點數(shù)的原因出現(xiàn)很長的小數(shù)位,影響用戶體驗。訂單明細數(shù)據(jù)則以商品圖片的形式進行顯示。
訂單查詢設計完成之后,顯示效果如圖9-6所示。
當移動商城設計完成之后,可以進行一個集成測試。在這個集成測試中,可以按下列順序啟動相關應用:
啟動完成之后,可以通過注冊中心查看所有應用的啟動情況,如圖9-7所示。
下面在瀏覽器中輸入如下鏈接,打開移動商城進行測試:
http://localhost: 7090
如果打開成功,則可以將瀏覽器調(diào)整成手機或iPad的顯示界面,模擬移動設備操作,如圖9-8所示。
當在手機或者iPad 上進行測試時,請確認手機或iPad與電腦處于同一個局域網(wǎng)中,然后將上面的“l(fā)ocalhost”改成電腦上的P地址進行訪問。在 iPad上打開的移動商城首頁如圖9-9所示。這里用到的P地址是“192.168.0.104”。
在手機上測試時,可以參考前面在開發(fā)講解中提供的各種場景的效果圖。
當我們在測試中進行了一些操作之后,會生成一些數(shù)據(jù),這時可以通過如下鏈接打開PC端的訂單管理后臺,查看訂單列表,進行訂單管理操作。
http://localhost:8095
打開鏈接之后,可以看到如圖9-10所示頁面。這是第8章的工作成果,即訂單管理后臺主頁的操作界面。在這個界面中,可以進行一些訂單管理操作。
本章使用前面章節(jié)設計的各種接口服務,設計并開發(fā)了一個移動端的商城。在這個設計中,演示了微服務接口的調(diào)用方法,同時,針對移動設備進行了一些H5的單頁設計實踐。在整個開發(fā)過程中,讀者可以更加深刻地體會到微服務之間的接口調(diào)用是非常方便的。而使用SpringCloud工具套件進行移動端應用的開發(fā),同樣是輕量級且令人感到愉快的。
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。