后端

hanhanjun888@163.com

个人技术分享

php操作cookie 转换数组形式,可取某一个值
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;
hanhanjun888@163.com

个人技术分享

php操作cookie字符串,替换对应值
  • 将原始字符串中的unb和cookie2的值替换
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, '; ');
    }
}
  • 将原始字符串中的unb和cookie2的值替换
$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);
hanhanjun888@163.com

个人技术分享

php 操作cookie值
  • php 字符串cookie值数据拆分成数组,可以根据key的值进行替换,最后在组装成字符串
  • php 字符串cookie值数据拆分成数组,可以根据key的值进行替换,最后在组装成字符串
<?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;
?>
hanhanjun888@163.com

个人技术分享

fastadmin appendfieldlist 用法

添加页面

 <!--赞助商-->
    <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>

js代码

        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();
        },
hanhanjun888@163.com

个人技术分享

PHP 转到 Go

Warning: Undefined array key 1 in /www/wwwroot/hankin.cn/wp-content/themes/hankin/inc/wx-excerpt.php on line 53
从 PHP 转到 Go 的朋友,常常会因为没有便捷的工具函数而感到苦恼。PHP 写的多了就会形成路径依赖,在写 Go 的时候时不时就会想到 PHP 强大的数组函数。当然写 Go 的 PHPer 也想拥有这么强大的工具函数,在这个开源的编程世界总有一些伟大的程序员做着贡献,正是有了他们的存在,因此便有了 lancet 这样一个强大的 Go 语言工具函数库,下面我介绍一些常用的工具函数「文末附上了手册地址」。 ContainChinese 验证字符串是否包含中文字符。
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 代码。 1 最后附上这个 AI 工具的地址 https://www.codeconvert.ai/php-to-golang-converter 赶快去使用吧。
hanhanjun888@163.com

个人技术分享

PHP使用无头浏览器如何帮助数据提取和抓取
php使用webdriver做采集的好处 自动化:WebDriver 可以模拟用户与浏览器的交互操作,如点击、输入文本、提交表单等。这使得您可以自动化执行各种网页操作,而无需手动进行。 多浏览器支持:WebDriver 支持多种浏览器,包括 Chrome、Firefox、Safari 等。这意味着您可以在不同的浏览器上运行和测试您的采集脚本,以确保在不同环境下的兼容性。 动态内容处理:许多网站使用 JavaScript 和 AJAX 技术来加载和更新内容。通过 WebDriver,您可以等待页面加载完成并获取完整的渲染后的页面内容,包括动态生成的内容。 数据抽取:WebDriver 提供了丰富的方法和选择器来定位和提取页面中的元素。您可以使用这些功能来获取所需数据,并将其保存到文件或数据库中进行进一步处理。 高度可定制化:WebDriver 允许您编写灵活且高度可定制化的采集脚本。您可以根据需要设置各种选项和参数,以适应不同网站和场景。 跨平台支持:WebDriver 是一个跨平台的工具,可以在 Windows、Mac 和 Linux 等操作系统上运行。这使得它成为一个广泛适用的采集解决方案。 使用方法 使用 WebDriver,您可以等待页面加载完成并获取完整的渲染后的页面内容,包括动态生成的内容。这意味着您可以采集到前后端分离网站上通过 JavaScript 或 AJAX 加载的数据。接下来让我自己动手写一个试试看。 安装浏览器chrome 1. 下载 Chrome 浏览器的安装包: wget https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm 2. 安装 Chrome 浏览器: sudo yum localinstall google-chrome-stable_current_x86_64.rpm 3. 验证 Chrome 是否成功安装: google-chrome --version 4. 下载对应版本的 ChromeDriver,并解压到指定目录(例如 /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();
hanhanjun888@163.com

个人技术分享

Python框架 Flask和Django - 区别
  • Django功能大而全,Flask只包含基本的配置 Django的一站式解决的思路,能让开发者不用在开发之前就在选择应用的基础设施上花费大量时间。Django有模板,表单,路由,认证,基本的数据库管理等等内建功能。与之相反,Flask只是一个内核,默认依赖于两个外部库: Jinja2 模板引擎和 Werkzeug WSGI 工具集,其他很多功能都是以扩展的形式进行嵌入使用。
  • Flask 比 Django 更灵活 用Flask来构建应用之前,选择组件的时候会给开发者带来更多的灵活性 ,可能有的应用场景不适合使用一个标准的ORM(Object-Relational Mapping 对象关联映射),或者需要与不同的工作流和模板系统交互。
  • Flask 在 Django 之后发布,现阶段有大量的插件和扩展满足不同需要 Django发布于2005年,Flask创始于2010年年中。

Warning: Undefined array key 1 in /www/wwwroot/hankin.cn/wp-content/themes/hankin/inc/wx-excerpt.php on line 53

Warning: Undefined array key 1 in /www/wwwroot/hankin.cn/wp-content/themes/hankin/inc/wx-excerpt.php on line 53

Warning: Undefined array key 1 in /www/wwwroot/hankin.cn/wp-content/themes/hankin/inc/wx-excerpt.php on line 53
Python测试开发中Django和Flask框架 为了更好地阐述这个问题,我们把开发一个应用的过程进行类比,往往开发一个应用(web应用、系统应用)跟建造房子的过程一样,需要先打地基,搭好骨架,然后一块砖一块砖叠上去。 而开发一个应用呢? 同样也需要一个好的架构设计,数据库建模,然后一个模块一个模块使用代码实现。 如果开发一个软件应用不使用框架,和我们建房子时,每一块砖、每一根钢筋都需要自己生产出来本质上是一样的。 显而易见,如果在建造房子之前,每一块砖头、每一种建材,都需要我们自己去生产的话,建造房子的效率是极低的,甚至可能一辈子也无法把房子建造好。 在开发应用系统时,使用框架可以带来如下好处: **1、**大大提升开发效率; **2、**让应用开发更加规范、拓展性更强; **3、**让程序员把更多的精力放在业务逻辑的实现上,而不是重复、而复杂的基础环境上(比如web服务器、底层实现等); 二、为什么使用Django和Flask框架?   1、在Python编程语言的世界里,功能最强大、最流行的两个框架。 2、不仅在web后端开发、微服务开发,同时在ERP系统开发、API接口开发等领域,这两个框架应用非常广泛。 三、Django和Flask的区别 ◆ 形象类比 如果Django类似于精装修的房子,自带豪华家具、非常齐全功能强大的家电,什么都有了,拎包入住即可,十分方便。 而Flask类似于毛坯房,自己想把房子装修成什么样自己找材料,买家具自己装。 材料和家具种类非常丰富,并且都是现成免费的,直接拿过去用即可。 ◆ 在体量上的区别 Flask:小巧、灵活,让程序员自己决定定制哪些功能,非常适用于小型网站。 对于普通的工人来说将毛坯房装修为城市综合体还是很麻烦的,使用Flask来开发大型网站也一样,开发的难度较大,代码架构需要自己设计,开发成本取决于开发者的能力和经验。 Django:大而全,功能极其强大,是Python web框架的先驱,用户多,第三方库极其丰富。 非常适合企业级网站的开发,但是对于小型的微服务来说,总有“杀鸡焉有宰牛刀”的感觉,体量较大,非常臃肿,定制化程度没有Flask高,也没有Flask那么灵活。 ◆ 实例 使用Flask来完成: 第一步,安装Flask,pip install flask 第二步,创建my_first_app.py文件,添加如下代码 完成最简单的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上手也比较容易,开发文档详细、完善,相关资料丰富

 

 

 

 

1. 目录结构         参考:https://blog.csdn.net/yang9520/article/details/79740374   

  1. 中文文档(http://docs.jinkan.org/docs/flask/
一般情况下,Django很系统、统一。Flask项目目录风格不同一,即使用上了蓝图。

2. 数据库迁移

Flask要用第三方extensions,而Django自带,这个很方便。

3. 模块化

Flask是用蓝图。Django可以自动生成python manage.py startapp <app_name>,并在Django的项目的settings那个INSTALLED_APPS字典里注册一下就好。

4. 命令行

Django的命令行初始更多功能,例如migrate。但Flask自定义命令很简单。\ 启动方面,Flask有两种,一种是通过manage.py帮助脚本去运行,另一种是export环境变量,用flask run来运行,官方文档建议后面这种,1.02版本还新增了一个环境变量FLASK_ENV。因为Flask依赖5个包,其中一个是click,所以可以自定义CMD。
@app.cli.command()
def hello():
    click.echo('Hello, xxx!')

flask hello

5. 新建模型方面差不多。

它们都是继承ORM的Model。建模之后都是要加入到数据库中,就是做一个数据库迁移操作。\ Flask是传入想要创建的字段类型到model.Column,而Django有明显的类给你使用,例如models.charField。

6. 反向获取URL

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

7. 路由

Django的路由和view functions是分开写的:urls.py, views.py。而Flask是都写在views.py中,view function和url写在一起(以装饰器的形式app.route)。\ 因为Django是MTV模式。其实和MVC模式差不多。大致上是Controller变成了views.py和urls.py。 Flask命令行中使用flask routes可以查看URL与view function的映射关系。代码中使用app.url_map可以查看。

8. 中间件使用

Django在settings.py里设置,\ Flask要初始化中间件实例,然后传入app(Flask)实例。

9. Request对象

Django中,每个view function或者CBV中都要写一个request参数。而Flask的view function则不用,因为
from flask import request

# 这个request是对每个请求独立的,就像g变量。值得研究底层原理(Flask通过本地线程( thread local) 技术将请求对象在特定
的线程和请求中全局可访问)

10. 限制http请求方法

Flask
@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

11. 钩子函数

Flask,加钩子装饰器
@app.before_request
def do_something():
    pass # 这里的代码会在每个请求处理前执行
Django,通过中间件

框架之间的差别

  • Django功能大而全,Flask只包含基本的配置 Django的一站式解决的思路,能让开发者不用在开发之前就在选择应用的基础设施上花费大量时间。Django有模板,表单,路由,认证,基本的数据库管理等等内建功能。与之相反,Flask只是一个内核,默认依赖于两个外部库: Jinja2 模板引擎和 Werkzeug WSGI 工具集,其他很多功能都是以扩展的形式进行嵌入使用。
  • Flask 比 Django 更灵活 用Flask来构建应用之前,选择组件的时候会给开发者带来更多的灵活性 ,可能有的应用场景不适合使用一个标准的ORM(Object-Relational Mapping 对象关联映射),或者需要与不同的工作流和模板系统交互。
  • Flask 在 Django 之后发布,现阶段有大量的插件和扩展满足不同需要 Django发布于2005年,Flask创始于2010年年中。

入门引导

Flask的Hello World应用的代码是最简单的,只用在一个Python文件里码7行代码就够了。
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 创建项目和创建应用
django-admin startproject hello_django 
django-admin startapp howdy
  其目录结构:  默认情况下,Django项目和应用创建好了之后,只包含空的模型和模板文件,而Flask创建项目之后,目录里面没有任何文件,需要我们手动创建,是没有像Django一样组件分离,而对于需要把组件分离开的项目,Flask有blueprints。例如,你可以这样构建你的应用,将与用户有关的功能放在user.py里,把与销售相关的功能放在ecommerce.py里。 Django把一个项目分成各自独立的应用,而Flask认为一个项目应该是一个包含一些视图和模型的单个应用。当然我们也可以在Flask里复制出像Django那样的项目结构。

模版

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使用冒号来分隔过滤器名和参数,这样就只能传递一个参数了。
  • Flask的Jinja模版 for-else-endfor
{% 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 %}
  • Django模版 for-empty-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 。

Flask内置的6种转换器:

‘path’  ‘string’  ‘any’  ‘int’  ‘float’  ‘uuid’ Josn 和xml 的区别:首先他们都是用来数据交互的,其次josn 更加轻量些   Flask中有两种上下文,请求上下文和应用上下文。 上下文:相当于一个容器,他保存了Flask程序运行过程中的一些信息。    

请求上下文(request context)

request和session都属于请求上下文对象。 request:封装了HTTP请求的内容,针对的是http请求。举例:user = request.args.get('user'),获取的是get请求的参数。 (通俗来说:Request主要用来获取客户端发送过来的一些参数)   session:用来记录请求会话中的信息,针对的是用户信息。举例:session['name'] = user.id,可以记录用户信息。还可以通过session.get('name')获取用户信息。 (通俗来说:Session主要用来实现一些用户的会话信息)    

应用上下文(application context)

current_app和g都属于应用上下文对象。 current_app:表示当前运行程序文件的程序实例。我们可以通过current_app.name打印出当前应用程序实例的名字。 (通俗来说:Current_app代表当前程序运行实例,只要程序没有暂停终止,他会一直存在, 可以帮助我们记录项目日志) g:处理请求时,用于临时存储的对象,每次请求都会重设这个变量。比如:我们可以获取一些临时请求的用户信息。 (通俗来说:g对象和request和session比较像,请求过程中帮助我们创建,请求结束后销毁,是起到一个临时存储的作用)
  • 当调用app = Flask(_name_)的时候,创建了程序应用对象app;
  • request 在每次http请求发生时,WSGI server调用Flask.call();然后在Flask内部创建的request对象;
  • app的生命周期大于request和g,一个app存活期间,可能发生多次http请求,所以就会有多个request和g。
  • 最终传入视图函数,通过return、redirect或render_template生成response对象,返回给客户端。
区别: 请求上下文:保存了客户端和服务器交互的数据。 应用上下文:在flask程序运行过程中,保存的一些配置信息,比如程序文件名、数据库的连接、用户信息等。 (应用上下文生命周期比请求上下文的生命周期长)    

请求钩子

在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要处理,比如:在请求开始时,建立数据库连接;在请求结束时,指定数据的交互格式。为了让每个视图函数避免编写重复功能的代码,Flask提供了通用设施的功能,即请求钩子。 请求钩子是通过装饰器的形式实现,Flask支持如下四种请求钩子: before_first_request:在处理第一个请求前运行。 before_request:在每次请求前运行。 after_request:如果没有未处理的异常抛出,在每次请求后运行。 teardown_request:在每次请求后运行,即使有未处理的异常抛出。
hanhanjun888@163.com

个人技术分享

PHP To Go 转型手记

前言

作为一名PHP程序员,我感到荣幸。但在时代不断的变迁中,要具备足够的知识才可生存。 那就从Go语言学起把。 希望看到本篇文章的你可以对Go有一个基本的认识。本系列文章与我自己学习Go语言的方式去描述。以PHP代码与Go代码的对比加以区分理解。

变量

PHP
// 初始化变量
$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"
)

常量

PHP
define("FOO","something");
GO
// 单独声明
const FOO [string]= something
// 批量声明
const (
    USERNAME = "zhangsan"
    AGE      = 30
)

打印

PHP
// 基本输出
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")

函数

PHP
// 基本声明
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
}

加载

PHP
namespace Action
use Action
GO
package Action
import "action"

数组

PHP
// 初始化
$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:])

循环结构

PHP
// 基本结构
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)
}

控制结构

PHP
// 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)
}

PHP
// 声明一个类
class City{}
GO
// 声明一个结构体 这里并非混淆公众,是因为Go本身没有类的概念,只是其声明及操作方法与类概念相似
type City struct{}

声明类

PHP
class User{}
GO
type User struct{}

成员变量

PHP
class User{
    public $name;
    public $age;
}
GO
type User struct {
    username string
    age      int
}

变量修饰

PHP
class User{
    public $name;
    private $age;
}
GO
// 没有看错,Go中没有保护(protected),变量名首字母大写为public,小写为private
type User struct {
    Username string
    Age      int
}

成员方法

PHP
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
// php 没有构造方法的话,新建对象无需传参数
new User();
GO
// go 内结构体声明的变量是可选参数,既可传可不传,go既没有类概念,所以也没有构造方法。
User{"zhangsan",15}

实例化-调用

PHP
$user = new User();
$user->getName();
GO
u := User{"zhangsan",15}
fmt.Println(u.getName())

这里使用Laravel与Beego(基于Go开发的MVC框架)来演示

PHP(Laravel)
// 通过composer直接安装,简单易用
composer global require "laravel/installer"
// 创建一个项目
laravel new blog
GO(Beego)
// go自身就有包管理
go get github.com/astaxie/beego
// 创建项目也非常简单
bee api blog

目录结构

PHP(Laravel)
// 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

路由

PHP(Laravel)
Route::get('/user', 'UserController@index');
GO(Beego)
// 与laravel的使用方式差不多
// 这里为了统一,路由直接绑定控制器方法只有下列这种
// beego 还提供了注解方式 , 详情见 https://beego.me/docs/mvc/controller/router.md
beego.Router("/user",&UserController{},"get:index")

模型 (Model)

PHP(Laravel)
<?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(Laravel)
<?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()
}