澳洲山火持續多月 NASA:煙塵快將環繞地球一周

摘錄自2020年1月14日星島日報報導

美國太空總署(NASA)指出,澳洲山火造成的煙霧快將環繞地球一周。

NASA指出,元旦前後煙霧已越過南美,令南美國家天空變得朦朧,也嚴重影響紐西蘭。澳洲最近山火非常大,產生「異常多」的火積雲,火積雲使煙霧飛入平流層,其中有煙霧最長錄得17.7公里,煙霧就可飄到四方八面,影響全球大氣環境,部份已抵達智利。NASA稱,大量煙塵有機會形成火積雲,再產生閃電及引發新一輪大火。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

中國電動車充電樁規模將超1300億

據中國汽車工業協會的數據顯示,純電動汽車銷量最大,前三季度產銷分別完成20365輛和19228輛,同比分別增長2.7倍和2.9倍。   《節能與新能源汽車產業發展規劃(2012—2020年)》的主要目標要求,產業化方面,到2015年,純電動汽車和插電式混合動力汽車累計產銷量力爭達到50萬輛;到2020年,純電動汽車和插電式混合動力汽車生產能力達200萬輛、累計產銷量超過500萬輛,燃料電池汽車、車用氫能源產業與國際同步發展。   據國家能源局電力司副司長童光毅介紹,500萬輛電動汽車充電意味著需要建480萬個分散式充電樁、1.2萬座集中式充換電站。據此估算,未來每年將需建設至少96萬個充電樁,按照目前建設費用計,直接市場規模將超過1300億元。   工信部公佈的數據顯示,國內已經建成723座充電站,充電樁配備量為2.8萬個。目前,充電設施與新能源汽車保有量比例維持在1∶4左右的水準,而標配為1∶1。無疑,充電樁的建設滯後是新能源汽車發展的軟肋。根據“十三五”規劃,預計到2020年,集中式充換電站將增長到1.2萬座,分散式充電樁數量將增長100倍達到450萬個。   文章來源:科技日報

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

Unity中用Mesh畫一個圓環(二)

中目標-生成完整面

在之前的內容中我們已經成功生成了一個面,接下來我們要生成剩下的面就很容易了。

我們把之前生成的面當作頂面,接着我們來生成底面。

還記得前面說過\(\color{#1E90FF}{Depth}\)這個參數用來控制深度,也就是頂面和地面之間的距離,放到坐標系中就是控制Z的位置。

底面和頂面的頂點生成方法是一樣的,唯一不同的地方就是Z軸的不同。 我們只要用生成頂面的方法改下Z坐標,就可以得到底面了。

//下
        for (int i = 0; i <= NumberOfSides; i++)
        {
            float angle = 180 - i * incrementAngle;
            float innerX = (Radius - Thickness) * Mathf.Cos(angle * Mathf.Deg2Rad);
            float innerY = (Radius - Thickness) * Mathf.Sin(angle * Mathf.Deg2Rad);
            vertexList.Add(new Vector3(innerX, innerY, -1 * Depth / 2));
            float outsideX = Radius * Mathf.Cos(angle * Mathf.Deg2Rad);
            float outsideY = Radius * Mathf.Sin(angle * Mathf.Deg2Rad);
            vertexList.Add(new Vector3(outsideX, outsideY, - 1 * Depth / 2));
        }

三角形索引的生成和之前也是一樣的,不同的是一開始的方向,因為頂面的法線是向上的,而底面的法線是向下的:

  direction = 1;
        startIndex += (NumberOfSides + 1) * 2;
        for (int i = 0; i < NumberOfSides * 2; i++)
        {
            int[] triangleIndexs = getTriangleIndexs(i, direction, startIndex);
            direction *= -1;
            for (int j = 0; j < triangleIndexs.Length; j++)
            {
                triangleList.Add(triangleIndexs[j]);
            }
        }

至於UV索引則設置和頂面的一樣即可。

其實生成頂面和底面之後,大部分的工作已經完成了,這時候我們已經生成了我們需要的所有頂點。前後左右也只是用現有的這些頂點進行生成。

我們前面生成的圓柱體是基於圓生成的,如果我們改成基於貝塞爾生成的那也是可以的。

修改方法很簡單,就是改下生成頂點時的過程就好了,其他的不需要動。

具體過程直接看代碼吧,包看包懂。

當然下面的代碼是為了方面理解所以寫得冗餘,如果用到項目中建議優化下,不然會被主程打的。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//[RequireComponent(typeof(MeshFilter))]
//[RequireComponent(typeof(MeshRenderer))]
[ExecuteInEditMode]
public class DrawArch : MonoBehaviour
{
    public float Radius = 20.0f;                //外圈的半徑
    public float Thickness = 10.0f;             //厚度,外圈半徑減去內圈半徑
    public float Depth = 1.0f;                  //厚度
    public int NumberOfSides = 30;         //由多少個面組成
    public float DrawArchDegrees = 90.0f;       //要繪畫多長
    public Vector2[] bezierPoints = new Vector2[4];
    public Material archMaterial = null;

    private int VertexCountOneSide = 0;         //生成一面所需的頂點數
    private Mesh mesh = null;

    private float incrementAngle = 0;
    private List<Vector3> vertexList = new List<Vector3>();
    private List<int> triangleList = new List<int>();
    private List<Vector2> uvList = new List<Vector2>();

    // Start is called before the first frame update
    void Start()
    {
        mesh = new Mesh();
    }

    void GenerateMesh()
    {
        VertexCountOneSide = (NumberOfSides + 1) * 2;
        incrementAngle = DrawArchDegrees / NumberOfSides;

        GenerateVertex();
        GenerateTriangleIndex();
        GenerateUV();

        mesh.vertices = vertexList.ToArray();
        mesh.uv = uvList.ToArray();
        mesh.triangles = triangleList.ToArray();

        mesh.RecalculateNormals();
        gameObject.GetComponent<MeshFilter>().mesh = mesh;
        gameObject.GetComponent<MeshRenderer>().material = archMaterial;
    }

    //生成頂點坐標
    void GenerateVertex()
    {
        //上
        vertexList.Clear();
        for (int i = 0; i <= NumberOfSides; i++)
        {
            //float[] points = GetCirclePoint(Radius - Thickness,  i);
            //vertexList.Add(new Vector3(points[0], points[1], Depth / 2));
            //points = GetCirclePoint(Radius, i);
            //vertexList.Add(new Vector3(points[0], points[1], Depth / 2));
            float[] points = GetBezierPoint(i);
            vertexList.Add(new Vector3(points[0], points[1], Depth / 2));
            points = GetBezierPoint(i);
            vertexList.Add(new Vector3(points[0] - 1, points[1], Depth / 2));
        }

        //下
        for (int i = 0; i <= NumberOfSides; i++)
        {
            //float[] points = GetCirclePoint(Radius - Thickness,  i);
            //vertexList.Add(new Vector3(points[0], points[1], -1 * Depth / 2));
            //points = GetCirclePoint(Radius, i);
            //vertexList.Add(new Vector3(points[0], points[1], -1 * Depth / 2));
            float[] points = GetBezierPoint(i);
            vertexList.Add(new Vector3(points[0], points[1], -1 * Depth / 2));
            points = GetBezierPoint(i);
            vertexList.Add(new Vector3(points[0] - 1, points[1], -1 * Depth / 2));
        }

        //前
        for (int i = 0; i <= NumberOfSides * 2 ; i += 2)
        {
            vertexList.Add(vertexList[i]);
            vertexList.Add(vertexList[i + VertexCountOneSide]);
        }
        //后
        for (int i = 0; i <= NumberOfSides * 2; i += 2)
        {
            vertexList.Add(vertexList[i + 1]);
            vertexList.Add(vertexList[i + VertexCountOneSide + 1]);
        }
        //左
        vertexList.Add(vertexList[0]);
        vertexList.Add(vertexList[1]);
        vertexList.Add(vertexList[VertexCountOneSide + 0]);
        vertexList.Add(vertexList[VertexCountOneSide + 1]);
        //右
        vertexList.Add(vertexList[VertexCountOneSide -2]);
        vertexList.Add(vertexList[VertexCountOneSide - 1]);
        vertexList.Add(vertexList[VertexCountOneSide * 2 - 2]);
        vertexList.Add(vertexList[VertexCountOneSide * 2 - 1]);
    }

    void GenerateTriangleIndex()
    {
        //三角形索引
        triangleList.Clear();
        //上
        int direction = -1;
        int startIndex = 0;
        for (int i = 0; i < NumberOfSides * 2; i++)
        {
            int[] triangleIndexs = getTriangleIndexs(i, direction);
            direction *= -1;
            for (int j = 0; j < triangleIndexs.Length; j++)
            {
                triangleList.Add(triangleIndexs[j]);
            }
        }

        //下
        direction = 1;
        startIndex += (NumberOfSides + 1) * 2;
        for (int i = 0; i < NumberOfSides * 2; i++)
        {
            int[] triangleIndexs = getTriangleIndexs(i, direction, startIndex);
            direction *= -1;
            for (int j = 0; j < triangleIndexs.Length; j++)
            {
                triangleList.Add(triangleIndexs[j]);
            }
        }

        //前
        direction = 1;
        startIndex += VertexCountOneSide;
        for (int i = 0; i < NumberOfSides * 2; i++)
        {
            int[] triangleIndexs = getTriangleIndexs(i, direction, startIndex);
            direction *= -1;
            for (int j = 0; j < triangleIndexs.Length; j++)
            {
                triangleList.Add(triangleIndexs[j]);
            }
        }

        //后
        direction = -1;
        startIndex += VertexCountOneSide;
        for (int i = 0; i < NumberOfSides * 2; i++)
        {
            int[] triangleIndexs = getTriangleIndexs(i, direction, startIndex);
            direction *= -1;
            for (int j = 0; j < triangleIndexs.Length; j++)
            {
                triangleList.Add(triangleIndexs[j]);
            }
        }
        startIndex += VertexCountOneSide;
        //左
        triangleList.Add(startIndex + 0);
        triangleList.Add(startIndex + 1);
        triangleList.Add(startIndex + 2);
        triangleList.Add(startIndex + 3);
        triangleList.Add(startIndex + 2);
        triangleList.Add(startIndex + 1);
        //右
        triangleList.Add(startIndex + 4 + 2);
        triangleList.Add(startIndex + 4 + 1);
        triangleList.Add(startIndex + 4 + 0);
        triangleList.Add(startIndex + 4 + 1);
        triangleList.Add(startIndex + 4 + 2);
        triangleList.Add(startIndex + 4 + 3);
    }

    //UV索引
    void GenerateUV()
    {
        uvList.Clear();
        //上
        for (int i = 0; i <= NumberOfSides; i++)
        {
            float angle = 180 - i * incrementAngle;
            float littleX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(littleX, 0));
            float bigX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(bigX, 1));
        }

        //下
        for (int i = 0; i <= NumberOfSides; i++)
        {
            float angle = 180 - i * incrementAngle;
            float littleX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(littleX, 0));
            float bigX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(bigX, 1));
        }

        //前
        for (int i = 0; i <= NumberOfSides; i++)
        {
            float angle = 180 - i * incrementAngle;
            float littleX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(littleX, 0));
            float bigX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(bigX, 1));
        }

        //后
        for (int i = 0; i <= NumberOfSides; i++)
        {
            float angle = 180 - i * incrementAngle;
            float littleX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(littleX, 0));
            float bigX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(bigX, 1));
        }
        //左
        uvList.Add(new Vector2(1.0f, 1.0f));
        uvList.Add(new Vector2(0.0f, 1.0f));
        uvList.Add(new Vector2(0.0f, 0.0f));
        uvList.Add(new Vector2(1.0f, 0.0f));
        //右
        uvList.Add(new Vector2(1.0f, 1.0f));
        uvList.Add(new Vector2(0.0f, 1.0f));
        uvList.Add(new Vector2(0.0f, 0.0f));
        uvList.Add(new Vector2(1.0f, 0.0f));
    }

    int[] getTriangleIndexs(int index, int direction, int startIndex = 0)
    {
        int[] triangleIndexs = new int[3] { 0+ startIndex, 1 + startIndex, 2 + startIndex };
        for (int i = 0; i < triangleIndexs.Length; i++)
        {
            triangleIndexs[i] += index;
        }
        if (direction == -1)
        {
            int temp = triangleIndexs[0];
            triangleIndexs[0] = triangleIndexs[2];
            triangleIndexs[2] = temp;
        }
        return triangleIndexs;
    }

    private void Update()
    {
        GenerateMesh();
    }

    float[] GetCirclePoint(float radius, int index)
    {
        float angle = 180 - index * incrementAngle;
        float[] points = new float[2];
        float x = radius * Mathf.Cos(angle * Mathf.Deg2Rad);
        float y = radius * Mathf.Sin(angle * Mathf.Deg2Rad);
        points[0] = x;
        points[1] = y;
        return points;
    }

    float[] GetBezierPoint(int index)
    {
        float t = 1.0f / (NumberOfSides + 1) * index;
        float[] points = new float[2];
        var vec = Bezier(bezierPoints[0], bezierPoints[1], bezierPoints[2], bezierPoints[3], t);
        points[0] = vec.x;
        points[1] = vec.y;
        return points;
    }

    Vector2 Bezier(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t)
    {
        Vector2 result;
        Vector2 p0p1 = (1 - t) * p0 + t * p1;
        Vector2 p1p2 = (1 - t) * p1 + t * p2;
        Vector2 p2p3 = (1 - t) * p2 + t * p3;
        Vector2 p0p1p2 = (1 - t) * p0p1 + t * p1p2;
        Vector2 p1p2p3 = (1 - t) * p1p2 + t * p2p3;
        result = (1 - t) * p0p1p2 + t * p1p2p3;
        return result;
    }
}

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

泰國曼谷空品差 民眾抱怨政府無作為

摘錄自2020年1月21日公視報導

泰國曼谷近年來每到冬天,空氣品質就拉警報。曼谷的天空再度為霧霾籠罩,機車騎士紛紛戴上口罩,家庭主婦出門也不例外。

根據曼谷官方監測的數據,曼谷部分地區中午時段PM2.5濃度,飆升到每立方公尺 95微克,幾乎是安全標準的兩倍。官員表示這主要是受到逆溫現象的影響,也就是暖空氣將冷空氣困在地面附近,導致汽機車廢氣滯留且散不出去。泰國政府雖然已經開始管控汽車廢氣,必要時還派出無人機灑水,但霧鎖曼谷的情況依然每年上演。最新民調顯示,曼谷有八成一的民眾,認為政府改善空污沒有效率。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

日本風災損害輻射檢查設備 營養午餐難保食安

文:宋瑞文(媽媽監督核電廠聯盟特約撰述)

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

vue學習筆記(五)條件渲染和列表渲染

前言

在眾多的編程語言中,我們的基礎語法總是少不了一些專業語法,比如像定義變量,條件語句,for循環,數組,函數等等,vue.js這個優秀的前端框架中也有同樣的語法,我們換一個名詞,將條件語句改成專業詞彙叫做條件渲染,循環語句改成專業詞彙叫做列表渲染,這樣比較舒服一點。

本章目標

  • 學會條件渲染的使用

  • 學會可復用的key的使用

  • 學會列表渲染的使用

條件渲染

1.v-if的使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<div id="app01">
    <span v-if="type==='A'">成績為A</span>
</div>
<script src="../js/vue.js"></script>
<script>
    let vm=new Vue({
        el:'#app01',
        data:{
            type:'A'
        },
        methods:{
            
        },
        watch:{
            
        },
        computed:{
            
        }
    })
</script>
</body>
</html>

結果:成績為A

v-if判斷條件是否相等,就像if一樣,如果相等,那麼值就會true,與之對應的還有v-else,v-else-if

2.v-else的使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<div id="app01">
    <span v-if="type==='A'">成績為A</span>
    <span v-else>成績為B</span>
</div>
<script src="../js/vue.js"></script>
<script>
    let vm=new Vue({
        el:'#app01',    
        data:{
            type:'B'
        },
        methods:{
            
        },
        watch:{
            
        },
        computed:{
            
        }
    })
</script>
</body>
</html>

結果:成績為B

小練習

我們做一個小練習,鞏固一下v-if和v-else的使用,需求如下:點擊一個按鈕時,按鈕上的文字變為显示,再次點擊時按鈕上的文字變為隱藏,當按鈕上的文字显示隱藏時,显示紅色,按鈕上的文字變為显示時显示藍色

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            .box{
                width: 100px;
                height: 100px;
            }
            .red{
                background: red;
            }
            .blue{
                background: blue;
            }
        </style>
    </head>
    <body>
        <div id="app">
            <button @click="handleClick">{{text}}</button>
            <div v-if="show" class="box red"></div>
            <div v-else class="blue box"></div>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            let vm=new Vue({
                el:'#app',
                data:{
                    show:true,
                    text:'隱藏'
                },
                methods:{
                    handleClick(){
                        this.show=!this.show;
                        this.text=this.show?'隱藏':'显示'
                    }
                }
            })
            
        </script>
    </body>
</html>

結果

 

3.v-else-if的使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<div id="app01">
    <input type="text" v-model="type"/>
    <div v-if="type==='A'">成績為A</div>
    <div v-else-if="type==='B'">成績為B</div>
    <div v-else-if="type==='C'">成績為C</div>
    <div v-else>不及格</div>
</div>
<script src="../js/vue.js"></script>
<script>
    let vm=new Vue({
        el:'#app01',    
        data:{
            type:''
        },
        methods:{
            
        },
        watch:{
            
        },
        computed:{
            
        }
    })
</script>
</body>
</html>

結果:

4.v-show

說起這個v-show,其實和v-if有與曲同工的妙處,但是又有不同的地方,我們來看下示例你就秒懂了

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            .box{
                width: 100px;
                height: 100px;
            }
            .red{
                background: red;
            }
            .blue{
                background: blue;
            }
        </style>
    </head>
    <body>
        <div id="app">
            <div v-show="show" class="box red"></div>
            <button @click="handleClick()">{{text}}</button>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            let vm=new Vue({
                el:'#app',
                data:{
                    show:true,
                    text:'隱藏',
                },
                methods:{
                    handleClick(){
                        this.show=!this.show;
                        this.text=this.show?'隱藏':'显示'
                    }
                },
                computed:{
                    
                }
            })
        </script>
    </body>
</html>

當按鈕變為显示的時候,背景顏色消失,這裏就不截圖了,有興趣的小夥伴可以自己去嘗試,既然v-if可以幫我們實現元素的显示和隱藏,那我們還需要v-show干什麼呢?不妨看下接下來的實例。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            .box{
                width: 100px;
                height: 100px;
            }
            .red{
                background: red;
            }
            .blue{
                background: blue;
            }
        </style>
    </head>
    <body>
        <div id="app">
            <div v-show="show" class="box red"></div>
            <div class="box blue" v-if="show"></div>
            <button @click="handleClick()">{{text}}</button>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            let vm=new Vue({
                el:'#app',
                data:{
                    show:true,
                    text:'隱藏',
                },
                methods:{
                    handleClick(){
                        this.show=!this.show;
                        this.text=this.show?'隱藏':'显示'
                    }
                },
                computed:{
                    
                }
            })
        </script>
    </body>
</html>

 當我們點擊按鈕的時候

 

現在結果已經出來了,使用v-show的dom元素,dom元素只是簡單的切換display屬性,而v-if會將dom元素移除,當我們再次點擊時,v-if又會重新渲染元素,可想而知如果頻繁的切換的話,那麼有多麼的耗費性能,因此我總結了如下幾點

  • 頻繁的切換显示/隱藏要使用v-show

  • 只判斷一次時,使用v-if

5.減少dom的生成

我們都知道js操作dom元素是非常消耗性能的,但是我們需要盡量的避免這個問題,vue中為我們提供了一個template標籤,這個標籤叫做模板(至於什麼叫做模板,後期的博客會講到),我們先看一個示例

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            .box{
                width: 100px;
                height: 100px;
            }
            .red{
                background: red;
            }
            .blue{
                background: blue;
            }
        </style>
    </head>
    <body>
        <div id="app">
            <div v-if="show">
                <div class="box red"></div>
                <div class="box blue"></div>
            </div>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            let vm=new Vue({
                el:'#app',
                data:{
                    show:true,
                },
                methods:{
                    
                },
                computed:{
                    
                }
            })
        </script>
    </body>
</html>

 我們想讓圖上的那個div消失,不想為了管理同一組元素而多生成一個節點,這樣是非常消耗性能的,我們將div標籤變成template標籤

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            .box{
                width: 100px;
                height: 100px;
            }
            .red{
                background: red;
            }
            .blue{
                background: blue;
            }
        </style>
    </head>
    <body>
        <div id="app">
            <div v-if="show">
                <div class="box red"></div>
                <div class="box blue"></div>
            </div>
            <template v-if="show">
                <div class="box red"></div>
                <div class="box blue"></div>
            </template>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            let vm=new Vue({
                el:'#app',
                data:{
                    show:true,
                },
                methods:{
                    
                },
                computed:{
                    
                }
            })
        </script>
    </body>
</html>

View Code

 現在我有心中萌生了一個想法,v-if可以使用template,那麼v-show是否可以使用呢?

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            .box{
                width: 100px;
                height: 100px;
            }
            .red{
                background: red;
            }
            .blue{
                background: blue;
            }
        </style>
    </head>
    <body>
        <div id="app">
            <template v-if="show">
                <div class="box red"></div>
                <div class="box blue"></div>
            </template>
            <template v-show="show">
                <div class="box red"></div>
                <div class="box blue"></div>
            </template>
            <button @click="handleClick()">{{text}}</button>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            let vm=new Vue({
                el:'#app',
                data:{
                    show:true,
                    text:'隱藏',
                },
                methods:{
                    handleClick(){
                        this.show=!this.show;
                        this.text=this.show?'隱藏':'显示'
                    }
                },
                computed:{
                    
                }
            })
        </script>
    </body>
</html>

View Code

 

 答案是v-if可以使用template,而v-show不能使用template

vue中用key管理可復用的元素

Vue 會盡可能高效地渲染元素,通常會復用已有元素而不是從頭開始渲染。這麼做除了使 Vue 變得非常快之外,還有其它一些好處。例如,如果你允許用戶在不同的登錄方式之間切換。

示例一:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<div id="app01">
    <template v-if="type==='username'">
        <label>用戶名</label>
        <input type="text" placeholder="請輸入您的賬號" />
    </template>
    <template v-else>
        <label>郵箱</label>
        <input type="text" placeholder="請輸入您的郵箱" />
    </template>
    <p>
        <a href=""@click.prevent="type='username'">用戶名登錄</a>|
        <a href=""@click.prevent="type='email'">郵箱登錄</a>
    </p>
</div>
<script src="../js/vue.js"></script>
<script>
    let vm=new Vue({
        el:'#app01',    
        data:{
            isShow:true,
            type:'username'
        },
        methods:{
            
        },
        watch:{
            
        },
        computed:{
            
        }
    })
</script>
</body>
</html>

結果:

 

 

當我們在用戶名登錄和郵箱切換的時候,我們發現我們輸入的內容始終保持,為什麼呢?總的來說,因為兩個模板使用了相同的元素,input不會被替換掉——僅僅是替換了它的 placeholder屬性,這樣也不總是符合實際需求,所以 Vue 為你提供了一種方式來表達這兩個元素是完全獨立的,不要復用它們,只需添加一個具有唯一值的key屬性即可。

示例二:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<div id="app01">
    <template v-if="type==='username'">
        <label>用戶名:</label>
        <input type="text" placeholder="請輸入您的用戶名"  key='usename'/>
    </template>
    <template v-else>
        <label>郵箱:</label>
        <input type="text" placeholder="請輸入您的郵箱"  key='email'/>
    </template>
    <p>
        <a href=""@click.prevent="type='username'">用戶名登錄</a>|
        <a href=""@click.prevent="type='email'">郵箱登錄</a>
    </p>
</div>
<script src="../js/vue.js"></script>
<script>
    let vm=new Vue({
        el:'#app01',    
        data:{
            isShow:true,
            type:'username'
        },
        methods:{
            
        },
        watch:{
            
        },
        computed:{
            
        }
    })
</script>
</body>
</html>

結果:

 

現在我們點擊切換的時候,輸入框都會重新渲染,當然我們的<label>標籤依舊的高效的復用,因為它沒有添加key。

列表渲染

我們用v-for指令根據一組數組的選項列表進行渲染,v-for指令需要以item in items的形式的特殊語法,items是原數據數組並且item是元素迭代的別名

1.v-for的基本使用

語法:(item,index) in|of items

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>v-for的基本使用</title>
    </head>
    <body>
        <div id="app">
            <ul>
                <li v-for="(item) in arr">{{item}}</li>
            </ul>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            let vm=new Vue({
                el:'#app',
                data:{
                    arr:['apple','banana','pear']
                },
                methods:{
                    
                },
                computed:{
                    
                }
            })
        </script>
    </body>
</html>

結果:

當然v-for中也可以帶第二個參數index

2.v-for中帶索引

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>v-for的基本使用</title>
    </head>
    <body>
        <div id="app">
            <ul>
                <li v-for="(item,index) in arr">{{item}}--{{index}}</li>
            </ul>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            let vm=new Vue({
                el:'#app',
                data:{
                    arr:['apple','banana','pear']
                },
                methods:{
                    
                },
                computed:{
                    
                }
            })
        </script>
    </body>
</html>

View Code

3.v-for迭代字符串

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>v-for的基本使用</title>
    </head>
    <body>
        <div id="app">
            <ul>
                <li v-for="(item,index) in arr">{{item}}--{{index}}</li>
            </ul>
            <ul>
                <li v-for="item in 'helloworld'">{{item}}</li>
            </ul>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            let vm=new Vue({
                el:'#app',
                data:{
                    arr:['apple','banana','pear']
                },
                methods:{
                    
                },
                computed:{
                    
                }
            })
        </script>
    </body>
</html>

View Code

4.v-for迭代對象

語法:(value,key,index) of | in items

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>v-for迭代對象</title>
    </head>
    <body>
        <div id="app">
            <ul>
                <li v-for="(value,key,index) of obj">{{value}}-{{key}}-{{index}}</li>
            </ul>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            let vm=new Vue({
                el:'#app',
                data:{
                    obj:{
                        name:'kk',
                        age:18,
                        sex:'male'
                    }
                },
                methods:{
                    
                },
                computed:{
                    
                }
            })
        </script>
    </body>
</html>

結果:

5.v-for迭代整數

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>v-for迭代對象</title>
    </head>
    <body>
        <div id="app">
            <ul>
                <li v-for="(value,key,index) of obj">{{value}}-{{key}}-{{index}}</li>
            </ul>
            <ul>
                <li v-for="item in 10">{{item}}</li>
            </ul>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            let vm=new Vue({
                el:'#app',
                data:{
                    obj:{
                        name:'kk',
                        age:18,
                        sex:'male'
                    }
                },
                methods:{
                    
                },
                computed:{
                    
                }
            })
        </script>
    </body>
</html>

結果:

注意:但我們迭代整數的時候,item從1開始而不是從0開始

總結

在本章內容中,我們一共學習了三個知識點,分別是條件渲染的使用(v-if,v-else,v-else-if),管理可復用的key,列表渲染(v-for的基本使用等等),本章的內容也多但是在實際應用上非常廣泛,畢竟這些是非常基礎的語法,基礎不牢,地動山搖,學習任何東西都需要自己一步一個腳印走出來。

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

老虎「從後追上」一把壓地上!他「裝死不動」倖存

摘錄自2020年1月30日ETtoday報導

位於印度中部的馬哈拉施特拉邦(Maharashtra)25日發生老虎攻擊人的事件,一名當地村民被老虎追趕後壓制在地上,為了脫困,他先是假裝自己已經死亡,一動也不動動的躺在地上,旁邊的村民則是不斷地朝著老虎丟擲石頭以示恐嚇;最後老虎似乎受到驚嚇轉身逃跑,而該名村民也平安無事的躲過了一劫。

報導中指出,這起混亂一共造成至少三人受傷,老虎最後則是似乎受到驚嚇,頭也不回地轉身跑走,被壓在地上的男子幸運地存活下來,沒有受到太大的傷害。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

【自然語言處理】利用LDA對希拉里郵件進行主題分析

首先是讀取數據集,並將csv中ExtractedBodyText為空的給去除掉

import pandas as pd
import re
import os

dir_path=os.path.dirname(os.path.abspath(__file__))
data_path=dir_path+"/Database/HillaryEmails.csv"
df=pd.read_csv(data_path)
df=df[['Id','ExtractedBodyText']].dropna()

對於這些郵件信息,並不是所有的詞都是有意義的,也就是先要去除掉一些噪聲數據:

def clean_email_text(text):
    text = text.replace('\n'," ") #新行,我們是不需要的
    text = re.sub(r"-", " ", text) #把 "-" 的兩個單詞,分開。(比如:july-edu ==> july edu)
    text = re.sub(r"\d+/\d+/\d+", "", text) #日期,對主體模型沒什麼意義
    text = re.sub(r"[0-2]?[0-9]:[0-6][0-9]", "", text) #時間,沒意義
    text = re.sub(r"[\w]+@[\.\w]+", "", text) #郵件地址,沒意義
    text = re.sub(r"/[a-zA-Z]*[:\//\]*[A-Za-z0-9\-_]+\.+[A-Za-z0-9\.\/%&=\?\-_]+/i", "", text) #網址,沒意義
    pure_text = ''
    # 以防還有其他特殊字符(数字)等等,我們直接把他們loop一遍,過濾掉
    for letter in text:
        # 只留下字母和空格
        if letter.isalpha() or letter==' ':
            pure_text += letter
    # 再把那些去除特殊字符后落單的單詞,直接排除。
    # 我們就只剩下有意義的單詞了。
    text = ' '.join(word for word in pure_text.split() if len(word)>1)
    return text

然後取出ExtractedBodyText的那一列,對每一行email進行噪聲過濾,並返回一個對象:

docs = df['ExtractedBodyText']
docs = docs.apply(lambda s: clean_email_text(s))  

然後我們呢把裏面的email提取出來:

doclist=docs.values

接下來,我們使用gensim庫來進行LDA模型的構建,gensim可用指令pip install -U gensim安裝。但是,要注意輸入到模型中的數據的格式。例如:[[一條郵件字符串],[另一條郵件字符串], ...]轉換成[[一,條,郵件,在,這裏],[第,二,條,郵件,在,這裏],[今天,天氣,腫么,樣],...]。對於英文的分詞,只需要對空白處分割即可。同時,有些詞語(不同於噪聲)是沒有意義的,我們要過濾掉那些沒有意義的詞語,這裏簡單的寫一個停止詞列表:

stoplist = ['very', 'ourselves', 'am', 'doesn', 'through', 'me', 'against', 'up', 'just', 'her', 'ours',
            'couldn', 'because', 'is', 'isn', 'it', 'only', 'in', 'such', 'too', 'mustn', 'under', 'their',
            'if', 'to', 'my', 'himself', 'after', 'why', 'while', 'can', 'each', 'itself', 'his', 'all', 'once',
            'herself', 'more', 'our', 'they', 'hasn', 'on', 'ma', 'them', 'its', 'where', 'did', 'll', 'you',
            'didn', 'nor', 'as', 'now', 'before', 'those', 'yours', 'from', 'who', 'was', 'm', 'been', 'will',
            'into', 'same', 'how', 'some', 'of', 'out', 'with', 's', 'being', 't', 'mightn', 'she', 'again', 'be',
            'by', 'shan', 'have', 'yourselves', 'needn', 'and', 'are', 'o', 'these', 'further', 'most', 'yourself',
            'having', 'aren', 'here', 'he', 'were', 'but', 'this', 'myself', 'own', 'we', 'so', 'i', 'does', 'both',
            'when', 'between', 'd', 'had', 'the', 'y', 'has', 'down', 'off', 'than', 'haven', 'whom', 'wouldn',
            'should', 've', 'over', 'themselves', 'few', 'then', 'hadn', 'what', 'until', 'won', 'no', 'about',
            'any', 'that', 'for', 'shouldn', 'don', 'do', 'there', 'doing', 'an', 'or', 'ain', 'hers', 'wasn',
            'weren', 'above', 'a', 'at', 'your', 'theirs', 'below', 'other', 'not', 're', 'him', 'during', 'which']

然後我們將輸入轉換成gensim所需的格式,並過濾掉停用詞:

texts = [[word for word in doc.lower().split() if word not in stoplist] for doc in doclist]

再將這所有的單詞放入到一個詞袋中,把每個單詞用一個数字index指代:

from gensim import corpora, models, similarities
import gensim
dictionary = corpora.Dictionary(texts)

再分別統計每一篇email中每個詞語在這個詞袋中出現的次數,並返回一個列表:

corpus = [dictionary.doc2bow(text) for text in texts]

 這個列表告訴我們,第14(從0開始是第一)個郵件中,一共6個有意義的單詞(經過我們的文本預處理,並去除了停止詞后)其中,51號單詞出現1次,505號單詞出現1次,以此類推。。。

最後,就可以開始構建我們的模型了:

lda = gensim.models.ldamodel.LdaModel(corpus=corpus, id2word=dictionary, num_topics=20)
print(lda.print_topic(10, topn=5))

 可以看到,第11個主題最常用的單詞,接下來,我們看下所有的主題:

for i in lda.print_topics(num_topics=20, num_words=5):
    print(i)

 我們再看下第一篇email屬於哪一個主題:

print(lda.get_document_topics(corpus[0]))

 屬於第四個主題的概率是0.95

相關代碼和數據:鏈接: https://pan.baidu.com/s/1sl1I5IeQFDHjVwf2a0C89g 提取碼: xqqf 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

02-MyBatis執行Sql的流程分析

目錄

本博客着重介紹MyBatis執行Sql的流程,關於在執行過程中緩存、動態SQl生成等細節不在本博客中體現,相應內容後面再單獨寫博客分析吧。

還是以之前的查詢作為列子:

public class UserDaoTest {

    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void setUp() throws Exception{
        ClassPathResource resource = new ClassPathResource("mybatis-config.xml");
        InputStream inputStream = resource.getInputStream();
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void selectUserTest(){
        String id = "{0003CCCA-AEA9-4A1E-A3CC-06D884BA3906}";
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CbondissuerMapper cbondissuerMapper = sqlSession.getMapper(CbondissuerMapper.class);
        Cbondissuer cbondissuer = cbondissuerMapper.selectByPrimaryKey(id);
        System.out.println(cbondissuer);
        sqlSession.close();
    }

}

之前提到拿到sqlSession之後就能進行各種CRUD操作了,所以我們就從sqlSession.getMapper這個方法開始分析,看下整個Sql的執行流程是怎麼樣的。

獲取Mapper

進入sqlSession.getMapper方法,會發現調的是Configration對象的getMapper方法:

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    //mapperRegistry實質上是一個Map,裏面註冊了啟動過程中解析的各種Mapper.xml
    //mapperRegistry的key是接口的全限定名,比如com.csx.demo.spring.boot.dao.SysUserMapper
    //mapperRegistry的Value是MapperProxyFactory,用於生成對應的MapperProxy(動態代理類)
    return mapperRegistry.getMapper(type, sqlSession);
}

進入getMapper方法:

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    //如果配置文件中沒有配置相關Mapper,直接拋異常
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      //關鍵方法
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

進入MapperProxyFactory的newInstance方法:

public class MapperProxyFactory<T> {

  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();

  public MapperProxyFactory(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }

  public Class<T> getMapperInterface() {
    return mapperInterface;
  }

  public Map<Method, MapperMethod> getMethodCache() {
    return methodCache;
  }

  //生成Mapper接口的動態代理類MapperProxy
  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }
  
  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

}

下面是動態代理類MapperProxy,調用Mapper接口的所有方法都會先調用到這個代理類的invoke方法(注意由於Mybatis中的Mapper接口沒有實現類,所以MapperProxy這個代理對象中沒有委託類,也就是說MapperProxy幹了代理類和委託類的事情)。好了下面重點看下invoke方法。

//MapperProxy代理類
public class MapperProxy<T> implements InvocationHandler, Serializable {

  private static final long serialVersionUID = -6424540398559729838L;
  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;

  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    //獲取MapperMethod,並調用MapperMethod
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }

  private MapperMethod cachedMapperMethod(Method method) {
    MapperMethod mapperMethod = methodCache.get(method);
    if (mapperMethod == null) {
      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
      methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
  }

  @UsesJava7
  private Object invokeDefaultMethod(Object proxy, Method method, Object[] args)
      throws Throwable {
    final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class
        .getDeclaredConstructor(Class.class, int.class);
    if (!constructor.isAccessible()) {
      constructor.setAccessible(true);
    }
    final Class<?> declaringClass = method.getDeclaringClass();
    return constructor
        .newInstance(declaringClass,
            MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
                | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC)
        .unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
  }

  /**
   * Backport of java.lang.reflect.Method#isDefault()
   */
  private boolean isDefaultMethod(Method method) {
    return ((method.getModifiers()
        & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC)
        && method.getDeclaringClass().isInterface();
  }
}

所以這邊需要進入MapperMethod的execute方法:

public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    //判斷是CRUD那種方法
    switch (command.getType()) {
      case INSERT: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName() 
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }

然後,通過一層一層的調用,最終會來到doQuery方法, 這兒咱們就隨便找個Excutor看看doQuery方法的實現吧,我這兒選擇了SimpleExecutor:

public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      //內部封裝了ParameterHandler和ResultSetHandler
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      //StatementHandler封裝了Statement, 讓 StatementHandler 去處理
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

接下來,咱們看看StatementHandler 的一個實現類 PreparedStatementHandler(這也是我們最常用的,封裝的是PreparedStatement), 看看它使怎麼去處理的:

public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
     //到此,原形畢露, PreparedStatement, 這個大家都已經滾瓜爛熟了吧
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    //結果交給了ResultSetHandler 去處理,處理完之後返回給客戶端
    return resultSetHandler.<E> handleResultSets(ps);
  }

到此,整個調用流程結束。

簡單總結

這邊結合獲取SqlSession的流程,做下簡單的總結:

  • SqlSessionFactoryBuilder解析配置文件,包括屬性配置、別名配置、攔截器配置、環境(數據源和事務管理器)、Mapper配置等;解析完這些配置後會生成一個Configration對象,這個對象中包含了MyBatis需要的所有配置,然後會用這個Configration對象創建一個SqlSessionFactory對象,這個對象中包含了Configration對象;
  • 拿到SqlSessionFactory對象后,會調用SqlSessionFactory的openSesison方法,這個方法會創建一個Sql執行器(Executor組件中包含了Transaction對象),這個Sql執行器會代理你配置的攔截器方法
  • 獲得上面的Sql執行器后,會創建一個SqlSession(默認使用DefaultSqlSession),這個SqlSession中也包含了Configration對象和上面創建的Executor對象,所以通過SqlSession也能拿到全局配置;
  • 獲得SqlSession對象后就能執行各種CRUD方法了。

以上是獲得SqlSession的流程,下面總結下本博客中介紹的Sql的執行流程:

  • 調用SqlSession的getMapper方法,獲得Mapper接口的動態代理對象MapperProxy,調用Mapper接口的所有方法都會調用到MapperProxy的invoke方法(動態代理機制);
  • MapperProxy的invoke方法中唯一做的就是創建一個MapperMethod對象,然後調用這個對象的execute方法,sqlSession會作為execute方法的入參;
  • 往下,層層調下來會進入Executor組件(如果配置插件會對Executor進行動態代理)的query方法,這個方法中會創建一個StatementHandler對象,這個對象中同時會封裝ParameterHandler和ResultSetHandler對象。調用StatementHandler預編譯參數以及設置參數值,使用ParameterHandler來給sql設置參數。

Executor組件有兩個直接實現類,分別是BaseExecutor和CachingExecutor。CachingExecutor靜態代理了BaseExecutor。Executor組件封裝了Transction組件,Transction組件中又分裝了Datasource組件。

  • 調用StatementHandler的增刪改查方法獲得結果,ResultSetHandler對結果進行封裝轉換,請求結束。

Executor、StatementHandler 、ParameterHandler、ResultSetHandler,Mybatis的插件會對上面的四個組件進行動態代理。

重要類

  • MapperProxyFactory

  • MapperProxy

  • MapperMethod

  • SqlSession:作為MyBatis工作的主要頂層API,表示和數據庫交互的會話,完成必要數據庫增刪改查功能;

  • Executor:MyBatis執行器,是MyBatis 調度的核心,負責SQL語句的生成和查詢緩存的維護;

    StatementHandler 封裝了JDBC Statement操作,負責對JDBC statement 的操作,如設置參數、將Statement結果集轉換成List集合。
    ParameterHandler 負責對用戶傳遞的參數轉換成JDBC Statement 所需要的參數,
    ResultSetHandler 負責將JDBC返回的ResultSet結果集對象轉換成List類型的集合;
    TypeHandler 負責java數據類型和jdbc數據類型之間的映射和轉換
    MappedStatement MappedStatement維護了一條<select|update|delete|insert>節點的封裝,
    SqlSource 負責根據用戶傳遞的parameterObject,動態地生成SQL語句,將信息封裝到BoundSql對象中,並返回
    BoundSql 表示動態生成的SQL語句以及相應的參數信息

    Configuration MyBatis所有的配置信息都維持在Configuration對象之中。

參考

  • https://www.cnblogs.com/dongying/p/4031382.html
  • https://blog.csdn.net/qq_38409944/article/details/82494187

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

紐西蘭南島大淹水 宣布進入緊急狀態

摘錄自2020年02月05日公視報導

紐西蘭南島最南端的南地大區,過去60個小時,當地已經降下超過1000毫米的大雨,造成多處河川暴漲或潰堤、交通要道爆發土石流,一度造成200名旅客受困,兩人受傷。迫使南地大區宣布進入緊急狀態,紐西蘭氣象局也首次發布天氣紅色警戒。

為了大家生命安全著想,當局5日上午通知6000名住在地勢低窪地區的民眾緊急撤離家園。同時採取預防性停電等措施,避免災情擴大。目前預估未來幾天仍會持續降雨,所幸雨勢將會減小。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!