if (!function_exists('ckStr2ckArr')) {
function ckStr2ckArr($cookieValue,$key='')
{
if(empty($cookieValue)) return [];
// 第一步:将 cookie 字符串拆分为键值对数组
$cookiePairs = explode(';', $cookieValue);
// 创建一个关联数组来存储键值对
$cookieArray = [];
foreach ($cookiePairs as $pair) {
$pair = trim($pair); // 去除多余的空格
if ($pair) {
list($k, $value) = explode('=', $pair, 2);
$cookieArray[$k] = $value;
}
}
//取指定的key值
if(!empty($key)) return $cookieArray[$key];
//取所有数组
return $cookieArray;
}
}
$str = 'cna=Z10vHxyLLhkCAXPgqFaTMN9A; t=0dfd9e12691b5e686d8e406981bc179f; cookie2=113f243906b3776465e8fc246291d43d; xlly_s=1; _samesite_flag_=true; _tb_token_=548dd75bd1b39; unb=2209368547703; _hvn_lgc_=77; mtop_partitioned_detect=1; _m_h5_tk=518ab9b7ade30d1634c92f423962eb36_1729138819303; _m_h5_tk_enc=548aa63b41127caaeb4e9bc65e796a49; sdkSilent=1729216940928; sgcookie=E100MANykuWklerydA%2BMl9VIKBDu93fi6%2FAkc52GgwunEqZm9s%2F4QR3w70efJdK0OjoqaSSsURjd8rmp0UbOxRuxqtfyCuinoz28cswnbcjUUfk%3D; csg=96db0be1; havana_lgc2_77=eyJoaWQiOjIyMDkzNjg1NDc3MDMsInNnIjoiM2I1OTA0MDEzYTljZTcwZTRkZDkwYTQ1YzkzYjgxYzEiLCJzaXRlIjo3NywidG9rZW4iOiIxcEprcmNFY3FXa3l3U1RnY2hhT1U0dyJ9; havana_lgc_exp=1731722711974; isg=BHd3EOiN3F5lmFlq1jMGY7UyBm3BPEuetKiDGckl5cateJK60QzK7iOTWtgmkCMW; tfstk=gtErVp23SDVj2CSshxnEQC-n2_n-D0f1tkGIKJ2nFbcoAahntJFxdHw3VWPU_7-7OJf8TklmM2aWVWNeT7NjZ3wSNSl31SZI-6n7gSa0k_C-O8MUGr4Aw_EUpHk3KWB-OTQbe8nKx11_YGw8eWEySDXjrIXnLv1_7crXm8nKx19XxNsae50nOCBExtomdYJox2cl3jDsi3DHqvAc3vhmx30nrqAmevkk-vV3ntkKiXDL382H0AglCB0NDGfWA4cgEj-HbdHrrewWRh-a0Yuzx8cVL9rqU4lilG5xelygElHUvOYETzzuNxFFbso0gy2nuo1kfXaaCk3Uq9pS9zMtqYPhjFG0u-q-5-pPI-ija-DTu1--VRz0VqEGG3FUC7rE57scEWnoKW3TA1K-ZJ2TXPiNYFogg-qt-kCvvXabKko8sst492jrHBHmRXqLzBYnrxHq1tW4O4UiIC35k2YpJqmt3f6SFeLKrWMq1TgBJe3mtxl1Fw5..';
//转换数组
$arr = ckStr2ckArr($newStr);
dump($arr);
//取数组中某一个值
$arr = ckStr2ckArr($newStr,'cookie2');
dump($arr);die;
if (!function_exists('ckStrReplace')) {
function ckStrReplace($cookieValue,$replacements)
{
if(empty($cookieValue)) return '';
if(empty($replacements) || !is_array($replacements)) return '';
// 第一步:将 cookie 字符串拆分为键值对数组
$cookiePairs = explode(';', $cookieValue);
// 创建一个关联数组来存储键值对
$cookieArray = [];
foreach ($cookiePairs as $pair) {
$pair = trim($pair); // 去除多余的空格
if ($pair) {
list($key, $value) = explode('=', $pair, 2);
$cookieArray[$key] = $value;
}
}
// 第二步:根据 replacements 数组更新或者添加相应的值
foreach ($replacements as $key => $newValue) {
// 如果数组中有这个键,进行替换
$cookieArray[$key] = $newValue;
}
// 第三步:重新组装成 cookie 字符串
$newCookieValue = '';
foreach ($cookieArray as $key => $value) {
$newCookieValue .= $key . '=' . $value . '; ';
}
// 去掉最后的多余分号和空格
return rtrim($newCookieValue, '; ');
}
}
$str = 'cna=Z10vHxyLLhkCAXPgqFaTMN9A; t=0dfd9e12691b5e686d8e406981bc179f; cookie2=113f243906b3776465e8fc246291d43d; xlly_s=1; _samesite_flag_=true; _tb_token_=548dd75bd1b39; unb=2209368547703; _hvn_lgc_=77; mtop_partitioned_detect=1; _m_h5_tk=518ab9b7ade30d1634c92f423962eb36_1729138819303; _m_h5_tk_enc=548aa63b41127caaeb4e9bc65e796a49; sdkSilent=1729216940928; sgcookie=E100MANykuWklerydA%2BMl9VIKBDu93fi6%2FAkc52GgwunEqZm9s%2F4QR3w70efJdK0OjoqaSSsURjd8rmp0UbOxRuxqtfyCuinoz28cswnbcjUUfk%3D; csg=96db0be1; havana_lgc2_77=eyJoaWQiOjIyMDkzNjg1NDc3MDMsInNnIjoiM2I1OTA0MDEzYTljZTcwZTRkZDkwYTQ1YzkzYjgxYzEiLCJzaXRlIjo3NywidG9rZW4iOiIxcEprcmNFY3FXa3l3U1RnY2hhT1U0dyJ9; havana_lgc_exp=1731722711974; isg=BHd3EOiN3F5lmFlq1jMGY7UyBm3BPEuetKiDGckl5cateJK60QzK7iOTWtgmkCMW; tfstk=gtErVp23SDVj2CSshxnEQC-n2_n-D0f1tkGIKJ2nFbcoAahntJFxdHw3VWPU_7-7OJf8TklmM2aWVWNeT7NjZ3wSNSl31SZI-6n7gSa0k_C-O8MUGr4Aw_EUpHk3KWB-OTQbe8nKx11_YGw8eWEySDXjrIXnLv1_7crXm8nKx19XxNsae50nOCBExtomdYJox2cl3jDsi3DHqvAc3vhmx30nrqAmevkk-vV3ntkKiXDL382H0AglCB0NDGfWA4cgEj-HbdHrrewWRh-a0Yuzx8cVL9rqU4lilG5xelygElHUvOYETzzuNxFFbso0gy2nuo1kfXaaCk3Uq9pS9zMtqYPhjFG0u-q-5-pPI-ija-DTu1--VRz0VqEGG3FUC7rE57scEWnoKW3TA1K-ZJ2TXPiNYFogg-qt-kCvvXabKko8sst492jrHBHmRXqLzBYnrxHq1tW4O4UiIC35k2YpJqmt3f6SFeLKrWMq1TgBJe3mtxl1Fw5..';
dump($str);
$newStr = ckStrReplace($str,[
'unb' => '测试',
'cookie2' => '测试2',
'x5sec' => 'test2'
]);
dump($newStr);
<?php
// 示例 Cookie 字符串
$cookieString = "user=hankin;age=30;city=hanzhou";
// 将字符串解析为数组
parse_str($cookieString, $cookieArray);
// 打印解析后的数组
print_r($cookieArray);
// 替换特定键的值
$cookieArray['city'] = 'shanghai';
$cookieArray['age'] = '35';
// 打印替换后的数组
print_r($cookieArray);
// 将数组重新组装为字符串
$newCookieString = http_build_query($cookieArray, '', ';');
// 打印重新组装后的字符串
echo $newCookieString;
?>
<!--赞助商-->
<div class="form-group row">
<!-- <label class="control-label col-xs-12 col-sm-2">{:__('仪器产品')}:</label>-->
<div class="col-xs-12">
<table class="table fieldlist" data-template="eventtpl" data-name="row[yiqi_images]" id="second-table">
<tr>
<td>{:__('赞助厂家')}</td>
<td>{:__('标题')}</td>
<td>{:__('图片')}<span style="color: red">670*176</span></td>
<td>{:__('链接')}</td>
<td>{:__('类型')}<span style="color: red">1内部;2外部</span></td>
<td width="100"></td>
</tr>
<tr>
<td colspan="3"><a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> {:__('Append')}</a></td>
</tr>
</table>
<!--请注意实际开发中textarea应该添加个hidden进行隐藏-->
<textarea name="row[yiqi_images]" class="form-control" style="display: none;"></textarea>
<script id="eventtpl" type="text/html">
<tr class="form-inline">
<td><input type="text" style="width: 200px;" name="<%=name%>[<%=index%>][id]" class="form-control selectpage" data-params='{"custom[status]":1}' data-source="manystore/shop" data-field="name" value="<%=row.id%>" placeholder="请选择赞助厂家"/></td>
<td><input type="text" name="<%=name%>[<%=index%>][title]" class="form-control" value="<%=row.title%>" placeholder="标题" size="10"/></td>
<td>
<input type="hidden" name="<%=name%>[<%=index%>][image]" id="c-image-<%=index%>" value="<%=row.image%>">
<!--@formatter:off-->
<button type="button" id="faupload-image" class="btn btn-danger faupload upload-image" data-input-id="c-image-<%=index%>" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp" data-multiple="false"></button>
<!--@formatter:on-->
</td>
<td><input type="text" name="<%=name%>[<%=index%>][url]" class="form-control" value="<%=row.url%>" placeholder="跳转链接" size="10"/></td>
<td><input type="text" name="<%=name%>[<%=index%>][type]" class="form-control" value="<%=row.type%>" placeholder="填1内部,2外部" size="10"/></td>
<td>
<!--下面的两个按钮务必保留-->
<span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span>
<span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span>
</td>
</tr>
</script>
</div>
</div>
<div class="form-group row">
<div class="col-xs-12">
<table class="table fieldlist" data-template="eventtpl" data-name="row[yiqi_images]" id="second-table">
<tr>
<td>{:__('赞助厂家')}</td>
<td>{:__('标题')}</td>
<td>{:__('图片')}<span style="color: red">670*176</span></td>
<td>{:__('链接')}</td>
<td>{:__('类型')}<span style="color: red">1内部;2外部</span></td>
<td width="100"></td>
</tr>
<tr>
<td colspan="3"><a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> {:__('Append')}</a></td>
</tr>
</table>
<!--请注意实际开发中textarea应该添加个hidden进行隐藏-->
<textarea name="row[yiqi_images]" class="form-control" style="display: none;">{$row.yiqi_images|htmlentities}</textarea>
<script id="eventtpl" type="text/html">
<tr class="form-inline">
<td><input type="text" style="width: 150px;" name="<%=name%>[<%=index%>][id]" class="form-control selectpage" data-params='{"custom[status]":1}' data-source="manystore/shop" data-field="name" value="<%=row.id%>" placeholder="请选择赞助厂家"/></td>
<td><input type="text" style="width: 100px;" name="<%=name%>[<%=index%>][title]" class="form-control" value="<%=row.title%>"/></td>
<td>
<input type="hidden" style="width: 100px;" name="<%=name%>[<%=index%>][image]" id="c-image-<%=index%>" value="<%=row.image%>">
<button type="button" id="faupload-image" class="btn btn-danger faupload upload-image" data-input-id="c-image-<%=index%>" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp" data-multiple="false" <%if(row.image){%>style="background-image: url('<%=Fast.api.cdnurl(row.image)%>')"<%}%>></button>
</td>
<td><input type="text" name="<%=name%>[<%=index%>][url]" class="form-control" value="<%=row.url%>"/></td>
<td><input type="text" style="width: 80px;" name="<%=name%>[<%=index%>][type]" class="form-control" value="<%=row.type%>"/></td>
<td>
<!--下面的两个按钮务必保留-->
<span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span>
<span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span>
</td>
</tr>
</script>
</div>
</div>
add: function () {
$(document).on("fa.event.appendfieldlist", "#second-table .btn-append", function (e, obj) {
//绑定动态下拉组件
Form.events.selectpage(obj);
//绑定日期组件
Form.events.datetimepicker(obj);
//绑定上传组件
Form.events.faupload(obj);
//上传成功回调事件,变更按钮的背景
$(".upload-image", obj).data("upload-success", function (data) {
$(this).css("background-image", "url('" + Fast.api.cdnurl(data.url) + "')");
})
});
Controller.api.bindevent();
},
edit: function () {
Template.helper("Fast", Fast);
$(document).on("fa.event.appendfieldlist", "#second-table .btn-append", function (e, obj) {
//绑定动态下拉组件
Form.events.selectpage(obj);
//绑定日期组件
Form.events.datetimepicker(obj);
//绑定上传组件
Form.events.faupload(obj);
//上传成功回调事件,变更按钮的背景
$(".upload-image", obj).data("upload-success", function (data) {
$(this).css("background-image", "url('" + Fast.api.cdnurl(data.url) + "')");
})
});
Controller.api.bindevent();
},
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
result1 := validator.ContainChinese("你好")
result2 := validator.ContainChinese("你好hello")
result3 := validator.ContainChinese("hello")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// true
// false
}
IsChineseMobile 验证字符串是否是中国手机号码。
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
result1 := validator.IsChineseMobile("13263527980")
result2 := validator.IsChineseMobile("434324324")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
IsChineseIdNum 验证字符串是否是中国身份证号码。
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
result1 := validator.IsChineseIdNum("210911192105130715")
result2 := validator.IsChineseIdNum("123456")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
IsChinesePhone 验证字符串是否是中国电话座机号码。
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
result1 := validator.IsChinesePhone("010-32116675")
result2 := validator.IsChinesePhone("123-87562")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
IsCreditCard 验证字符串是否是信用卡号码。
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
result1 := validator.IsCreditCard("4111111111111111")
result2 := validator.IsCreditCard("123456")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
IsEmail 验证字符串是否是有效电子邮件地址。
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
result1 := validator.IsEmail("abc@xyz.com")
result2 := validator.IsEmail("a.b@@com")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
Contain 判断 slice 是否包含 value。
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
result1 := slice.Contain([]string{"a", "b", "c"}, "a")
result2 := slice.Contain([]int{1, 2, 3}, 4)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
Chunk 按照 size 参数均分 slice。
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
arr := []string{"a", "b", "c", "d", "e"}
result1 := slice.Chunk(arr, 1)
result2 := slice.Chunk(arr, 2)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// [[a] [b] [c] [d] [e]]
// [[a b] [c d] [e]]
}
Equal 检查两个切片是否相等,相等条件:切片长度相同,元素顺序和值都相同。
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
s1 := []int{1, 2, 3}
s2 := []int{1, 2, 3}
s3 := []int{1, 3, 2}
result1 := slice.Equal(s1, s2)
result2 := slice.Equal(s1, s3)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
Comma 用逗号每隔3位分割数字/字符串,支持前缀添加符号。参数 value 必须是数字或者可以转为数字的字符串, 否则返回空字符串。
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/formatter"
)
func main() {
result1 := formatter.Comma("123", "")
result2 := formatter.Comma("12345", "$")
result3 := formatter.Comma(1234567, "¥")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 123
// $12,345
// ¥1,234,567
}
ForEach 对 map 中的每对 key和 value 执行 iteratee 函数。
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
}
var sum int
maputil.ForEach(m, func(_ string, value int) {
sum += value
})
fmt.Println(sum)
// Output:
// 10
}
Keys 返回 map 中所有 key 的切片。
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[int]string{
1: "a",
2: "a",
3: "b",
4: "c",
5: "d",
}
keys := maputil.Keys(m)
sort.Ints(keys)
fmt.Println(keys)
// Output:
// [1 2 3 4 5]
}
Merge 合并多个 maps 相同的 key 会被后来的 key 覆盖。
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m1 := map[int]string{
1: "a",
2: "b",
}
m2 := map[int]string{
1: "1",
3: "2",
}
result := maputil.Merge(m1, m2)
fmt.Println(result)
// Output:
// map[1:c 2:b 3:d]
}
RandInt 生成随机int, 范围[min, max)。
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
rInt := random.RandInt(1, 10)
fmt.Println(rInt)
}
RandString 生成给定长度的随机字符串,只包含字母(a-zA-Z)。
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
randStr := random.RandString(6)
fmt.Println(randStr) //pGWsze
}
以上这些只是部分的工具函数,如果想查看所有内容可以访问 https://www.golancet.cn/ 该网站。
再强大的函数工具库也不可能涵盖所有的场景,随着现在 AI 的盛行,AI 的编程辅助工具也应运而生。在这里我再分享一个免费的 PHP 代码直接转换 Go 代码工具,这个工具简直是 PHP 程序员的福音,直接将 PHP 代码贴上便自动生成了 Go 代码。
/usr/local/bin):
https://googlechromelabs.github.io/chrome-for-testing/ (各个版本的下载地址)
wget https://chromedriver.storage.googleapis.com/114.0.5735.90/chromedriver_linux64.zip
unzip chromedriver_linux64.zip -d /usr/local/bin/
5. 启动 ChromeDriver 服务:
LANGUAGE=ZH-CN.UTF-8 /usr/local/bin/chromedriver --port=9515
6.成功运行后,您应该会看到类似以下输出:
Starting ChromeDriver {version} on port 9515...
Only local connections are allowed.
Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
ChromeDriver was started successfully.
https://github.com/php-webdriver/php-webdriver
PHP+WebDriver使用教程
https://github.com/php-webdriver/php-webdriver
php代码执行
<?php
require_once('vendor/autoload.php');
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Chrome\ChromeOptions;
$options = new ChromeOptions();
$options->addArguments(['--no-sandbox','--headless']);
$capabilities = DesiredCapabilities::chrome();
$capabilities->setCapability(ChromeOptions::CAPABILITY, $options);
$host = 'http://localhost:9555';
$driver = RemoteWebDriver::create($host, $capabilities);
// 访问百度网站
$driver->get('https://www.baidu.com');
// 获取页面源代码
$pageSource = $driver->getPageSource();
echo $pageSource;
// 关闭 WebDriver 会话
$driver->quit();
完成最简单的Hello World功能,Flask只需要7行代码,非常简单、方便。
使用Django来完成:
第一步,安装Django,pip install django
第二步,创建工程项目目录,django-admin startprojectmyproject
第三步,创建子应用,python manage.py startappmyapp
第四步,在myapp应用所在目录中的views.py文件中,添加如下代码。
第五步,在myapp应用所在目录中创建urls.py路由文件,并添加如下代码
第六步,在主路由文件中添加路由。
从上面的操作步骤可知,实现同样的一个功能,往往Flask较为简单,代码较少,而Django所涉及到的流程较多,工程项目结构清晰,在大型项目中具有优势。
如果你想搞懂Python web开发WSGI协议原理以及实现过程、或者你想灵活定制组件,完全DIY你的应用、想实现微服务。那么建议你选择Flask。
如果你关注产品的最终交付、想快速开发一个大的应用系统(比如新闻类网站、商城、ERP等)。那么建议你选择Django,你想得到的功能它都有,想不到的功能它也有。
五、如何才能学好框架
1、需要先学习框架的基础知识、基本实现原理
2、结合项目实践,提升编码能力和业务逻辑的理解
3、翻看框架源码,深入理解源码精髓(进阶)
Flask:
1:轻量级web框架,只有一个内核,默认依赖两个外部库:Jinja2 模板引擎和 Werkzeug WSGI 工具集,自由,灵活,可扩展性强,开发者可以根据需求自己造轮子\
2:适用于做小型网站以及web服务的API,开发大型网站无压力,架构需自行设计\
3:与关系型数据库结合不弱于Django,而与非关系型数据库的结合远远优于Django\
\
Django:
1:重量级web框架,功能齐全,提供一站式解决的思路,能让开发者不用在选择应用上花费大量时间\
2:自带ORM(Object-Relational Mapping 对象关联映射)和模板引擎,支持JinJa等非官方模板引擎,灵活度不高\
3:自带ORM使Django和关系型数据库耦合度过高,如果要使用非关系型数据库,需要使用第三方库\
4:自带数据库管理app\
5:成熟、稳定、开发效率高、相对于Flask,Django的整体封闭性比较好,适合做企业级网站的开发\
6:python web框架的先驱,第三方库丰富\
7:上手容易,开发文档详细、完善、资料丰富\
---------------------
(1)Flask
Flask确实很“轻”,不愧是Micro Framework,从Django转向Flask的开发者一定会如此感慨,除非二者均为深入使用过\
Flask自由、灵活,可扩展性强,第三方库的选择面广,开发时可以结合自己最喜欢用的轮子,也能结合最流行最强大的Python库\
入门简单,即便没有多少web开发经验,也能很快做出网站\
非常适用于小型网站\
非常适用于开发web服务的API\
开发大型网站无压力,但代码架构需要自己设计,开发成本取决于开发者的能力和经验\
各方面性能均等于或优于Django\
Django自带的或第三方的好评如潮的功能,Flask上总会找到与之类似第三方库\
Flask灵活开发,Python高手基本都会喜欢Flask,但对Django却可能褒贬不一\
Flask与关系型数据库的配合使用不弱于Django,而其与NoSQL数据库的配合远远优于Django\
Flask比Django更加Pythonic,与Python的philosophy更加吻合\
(2)Django
Django太重了,除了web框架,自带ORM和模板引擎,灵活和自由度不够高\
Django能开发小应用,但总会有“杀鸡焉用牛刀”的感觉\
Django的自带ORM非常优秀,综合评价略高于SQLAlchemy\
Django自带的模板引擎简单好用,但其强大程度和综合评价略低于Jinja\
Django自带ORM也使Django与关系型数据库耦合度过高,如果想使用MongoDB等NoSQL数据,需要选取合适的第三方库,且总感觉Django+SQL才是天生一对的搭配,Django+NoSQL砍掉了Django的半壁江山\
Django目前支持Jinja等非官方模板引擎\
Django自带的数据库管理app好评如潮\
Django非常适合企业级网站的开发:快速、靠谱、稳定\
Django成熟、稳定、完善,但相比于Flask,Django的整体生态相对封闭\
Django是Python web框架的先驱,用户多,第三方库最丰富,最好的Python库,如果不能直接用到Django中,也一定能找到与之对应的移植\
Django上手也比较容易,开发文档详细、完善,相关资料丰富
python manage.py startapp <app_name>,并在Django的项目的settings那个INSTALLED_APPS字典里注册一下就好。
@app.cli.command()
def hello():
click.echo('Hello, xxx!')
flask hello
urlpatterns = [ path('', views.post_list, name='post_list') ]
这个name,相当于Flask的endpoint。意思都是通过反向这个名字,reverse(name)去获得URL。
// 在模板中
<a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a></h1> //Django
{% url_for('") %} // Flask
from flask import request
# 这个request是对每个请求独立的,就像g变量。值得研究底层原理(Flask通过本地线程( thread local) 技术将请求对象在特定
的线程和请求中全局可访问)
@app.route('/hello', methods=['GET', 'POST'])
def hello():
return '<h1>Hello, Flask!</h1>'
Django
from django.views.decorators.http import require_http_methods
@require_http_methods(['GET','POST'])
def login(request):
pass
@app.before_request
def do_something():
pass # 这里的代码会在每个请求处理前执行
Django,通过中间件
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
上面代码就已经是一个简单的 web 应用,从上面的 Hello World 应用的特点来看,一个没什么Python web开发经验的人就可以很快的上手开始撸代码。
django-admin startproject hello_django
django-admin startapp howdy
其目录结构:
默认情况下,Django项目和应用创建好了之后,只包含空的模型和模板文件,而Flask创建项目之后,目录里面没有任何文件,需要我们手动创建,是没有像Django一样组件分离,而对于需要把组件分离开的项目,Flask有blueprints。例如,你可以这样构建你的应用,将与用户有关的功能放在user.py里,把与销售相关的功能放在ecommerce.py里。
Django把一个项目分成各自独立的应用,而Flask认为一个项目应该是一个包含一些视图和模型的单个应用。当然我们也可以在Flask里复制出像Django那样的项目结构。
<!-- view.html -->
<div class="top-bar row">
<div class="col-md-10">
<!-- more top bar things go here -->
</div>
{% if user %}
<div class="col-md-2 whoami">
You are logged in as {{ user.fullname }}
</div>
{% endif %}
</div>
{% for widget in inventory %}
<li><a href="/widget/{{ widget.slug }}/">{{ widget.displayname }}</a></li>
{% endfor %}
Flask默认使用一个受Django启发而发展起来的名为Jinja2的模板,其实,所有上面的Django模板的例子在Jinja2里也是好使的。
<!-- Django -->
<div class="categories">Categories: {{ post.categories|join:", " }}</div>
<!-- Jinja -->
<div class="categories">Categories: {{ post.categories|join(", ") }}</div>
在Jinja的模板语言里,可以把任何数量的参数传给过滤器,因为Jinja像调用一个Python函数的方式来看待它,用圆括号来封装参数。Django使用冒号来分隔过滤器名和参数,这样就只能传递一个参数了。
{% for item in inventory %}
<div class="display-item">{{ item.render() }}</div>
{% else %}
<div class="display-warn">
<h3>No items found</h3>
<p>Try another search, maybe?</p>
</div>
{% endfor %}
{% for item in inventory %}
<div class="display-item">{{ item.render }}</div>
{% empty %}
<div class="display-warn">
<h3>No items found</h3>
<p>Try another search, maybe?</p>
</div>
{% endfor %}
除了上述的语法区别,Flask还提供了很多特有的上下文变量(url_for,get_flashed_messages()等)
----------------------------------------------------------------------------------
Flask框架主要的特点是轻巧,简介,扩展性强;核心就是 Werkzeug(路由模块) ,模板引擎则使用 Jinja2 。
Josn 和xml 的区别:首先他们都是用来数据交互的,其次josn 更加轻量些
Flask中有两种上下文,请求上下文和应用上下文。
上下文:相当于一个容器,他保存了Flask程序运行过程中的一些信息。
g:处理请求时,用于临时存储的对象,每次请求都会重设这个变量。比如:我们可以获取一些临时请求的用户信息。
(通俗来说:g对象和request和session比较像,请求过程中帮助我们创建,请求结束后销毁,是起到一个临时存储的作用)
// 初始化变量
$domain = "www.hankin.cn";
// 批量赋值
$domain = $domain1 = $domain2 = "www.hankin.cn";
Go
// 初始化变量
var domain string = "www.hankin.cn"
// 批量赋值
var domain,domain1,domain2 string = "www.hankin.cn"
// 批量声明赋值
var username,age,local = "zhangsan",13,"BeiJing"
var(
username="zhangsan"
age = 13
local = "BeiJing"
)
define("FOO","something");
GO
// 单独声明
const FOO [string]= something
// 批量声明
const (
USERNAME = "zhangsan"
AGE = 30
)
// 基本输出
echo "www.hankin.cn";
// 格式化输出
printf("my blog %s","www.hankin.cn");
GO
// 基本输出
fmt.Println("www.hankin.cn")
// 格式化输出
fmt.Printf("my blog %s","www.hankin.cn")
// 基本声明
function printString(string $string){
echo $string;
}
// 带返回值
function printString(string $string) : string{
return $string;
}
GO
// 基本声明
func printString(s string){
fmt.Println(s)
}
// 带返回值
func printString(s string) string{
return s
}
namespace Action
use Action
GO
package Action
import "action"
// 初始化
$arr = []
$arr = array()
// 初始化赋值
$arr = [1,2,3]
// 多维数组
$arr = [][]
// 获取值
echo $arr[1]
// 获取数组总数
echo length($arr)
// 获取数组区间
$a=array("red","green","blue","yellow","brown");
print_r(array_slice($a,1,2));
// 设置key=>value
$arr = ["username"=>"zhangsan","age"=>13]
// 删除指定下标
unset($arr[0])
GO 数组 & 切片 (切片是数组的一个View,就例如MySQL的视图一样)
// 初始化
var arr [5]int
// 初始化赋值
arr := [5]int{1, 2, 3, 4, 5}
// 无需声明数组个数
arr := [...]int{1, 2, 3, 4, 5, 6, 7}
// 多维数组
var arr [4][5]bool
// 获取值
fmt.Println(arr[1])
// 获取数组总数
fmt.Println(len(arr))
// 获取数组区间 显而易见,Go对数组的操作更便利直观
a := [...]string{"red","green","blue","yellow","brown"}
fmt.Println(a[1:2])
// 设置key=>value 这里需要使用Map
m := map[string]string{
"username": "zhangsan",
"age" : "13"
}
// 删除指定下标 Go没有删除数组下标的系统方法
arr := arr[1:]
// 删除中间位置的下标 可通过合并的方式去除指定下标
arr := append(arr[:3],arr[4:])
// 基本结构
for($i=0;$i<10;$i++){
echo $i;
}
// 死循环
for($i=0;$i<10;$i++){
echo $i;
$i--
}
// 获取key,value
foreach($arr as $key=>$value){
echo $key,$value
}
GO
// 基本结构
for i := 0; i < 10; i++ {
fmt.Println(i)
}
// 死循环 可见Go写死循环非常方便
for {
fmt.Println("")
}
// 获取key,value
for k, v := range arr {
fmt.Println(k, v)
}
// if
if(true){
}
// switch
switch(true){
case true:
echo true;
break;
}
GO
// if
if true {
}
// switch Go语言的Switch的Case不需要break
switch true {
case true:
fmt.Println(true)
}
// 声明一个类
class City{}
GO
// 声明一个结构体 这里并非混淆公众,是因为Go本身没有类的概念,只是其声明及操作方法与类概念相似
type City struct{}
class User{}
GO
type User struct{}
class User{
public $name;
public $age;
}
GO
type User struct {
username string
age int
}
class User{
public $name;
private $age;
}
GO
// 没有看错,Go中没有保护(protected),变量名首字母大写为public,小写为private
type User struct {
Username string
Age int
}
class User{
public $name;
public $age;
function setName(){
}
function getName(){
}
}
GO
type User struct {
username string
age int
}
func (u User) setName(name string) bool {
u.username = name
return true
}
func (u User) getName() string {
return u.username
}
// php 没有构造方法的话,新建对象无需传参数
new User();
GO
// go 内结构体声明的变量是可选参数,既可传可不传,go既没有类概念,所以也没有构造方法。
User{"zhangsan",15}
$user = new User();
$user->getName();
GO
u := User{"zhangsan",15}
fmt.Println(u.getName())
// 通过composer直接安装,简单易用
composer global require "laravel/installer"
// 创建一个项目
laravel new blog
GO(Beego)
// go自身就有包管理
go get github.com/astaxie/beego
// 创建项目也非常简单
bee api blog
// laravel 的结构这里就不再阐述
| - app
| - bootstrap
| - config
| - database
| - public
| - resources
| - routes
| - storage
| - tests
| - vendor
GO(Beego)
// 显而易见,beego并没有laravel那样过度设计(虽然过度设计并非指目录,
// 但以看目录就知道beego真的没有太多东西)
blog
├── conf
│ └── app.conf
├── controllers
│ └── object.go
│ └── user.go
├── docs
│ └── doc.go
├── main.go
├── models
│ └── object.go
│ └── user.go
├── routers
│ └── router.go
└── tests
└── default_test.go
Route::get('/user', 'UserController@index');
GO(Beego)
// 与laravel的使用方式差不多
// 这里为了统一,路由直接绑定控制器方法只有下列这种
// beego 还提供了注解方式 , 详情见 https://beego.me/docs/mvc/controller/router.md
beego.Router("/user",&UserController{},"get:index")
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* 与模型关联的数据表。
*
* @var string
*/
protected $table = 'user';
}
GO(Beego)
// Beego通过结构体名称作为表名,并且orm操作的所有字段都必须提前声明
package models
import (
"github.com/astaxie/beego/orm"
)
type User struct {
Id int `json:"id"`
Tel string `json:"tel"`
Password string `json:"password"`
Status string `json:"status"`
}
func init() {
orm.RegisterModel(new(User))
}
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* 显示给定用户的概要文件
*
* @param int $id
* @return Response
*/
public function index($id)
{
return view('user.profile', ['user' => User::findOrFail($id)]);
}
}
GO(Beego)
package controllers
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
)
// 这里相当于继承了父类 beegoController
type MemberController struct {
beego.Controller
}
func (c *CityController) Index() {
var results []orm.Params
orm.NewOrm().QueryTable("member").
Values(&results)
c.Data["json"] = results
c.ServeJSON()
}
暂无数据