主頁 > 軟體設計 > 基于C++(QT框架)設計的網路攝像頭專案(支持跨平臺運行)

基于C++(QT框架)設計的網路攝像頭專案(支持跨平臺運行)

2021-08-22 07:59:33 軟體設計

一、運行效果展示

1.1 windows系統運行效果展示

<iframe id="BoclmWnD-1629390446435" src="https://live.csdn.net/v/embed/175540" allowfullscreen="true" data-mediaembed="csdn"></iframe>

網路攝像頭專案(Windows系統運行效果)

1.2 Android系統運行效果展示

<iframe id="FKhAXSxG-1629390456745" src="https://live.csdn.net/v/embed/175537" allowfullscreen="true" data-mediaembed="csdn"></iframe>

網路攝像頭專案(Android系統運行效果)

1.3 Linux系統運行效果展示

<iframe id="5F4Gkd5G-1629390467286" src="https://live.csdn.net/v/embed/175539" allowfullscreen="true" data-mediaembed="csdn"></iframe>

網路攝像頭專案(Linux系統運行效果)

二、功能簡介

2.1 功能介紹

這是基于C++(QT框架)設計的網路攝像頭專案,本篇文章介紹的網路攝像頭專案并不是采用RTMP或者RTSP推流編碼的網路攝像頭產品,而是采用HTTP協議推送圖片流的方式,采用瀏覽器訪問查看攝像頭畫面,

專案原始碼下載地址: https://download.csdn.net/download/xiaolong1126626497/21232910

這是軟體運行截圖:

這是瀏覽器訪問截圖:

專案運行的效果:

軟體打開之后,先點擊重繪資訊,程式會掃描當前設備的攝像頭和IP地址資訊;并將訪問的地址列印了出來,然后點擊開啟攝像頭,界面就實時顯示選擇的攝像頭畫面, 在局域網內,其他設備打開瀏覽器,輸入下面提示的地址訪問,輸入用戶名和密碼,即可查看到攝像頭畫面,程式里處理瀏覽器的請求是采用多執行緒方式,可以支持多個瀏覽器同時訪問,

代碼思路

代碼采用的是C++(QT框架)撰寫,代碼本身主要是分為兩個部分:

1. 系結指定埠號,創建TCP服務器,用來回應客戶端的請求(瀏覽器)

2. 攝像頭畫面采集部分,攝像頭資料采集采用單獨的執行緒,采集之后將影像傳遞給界面重繪顯示,并將影像填充到全域緩沖區,方便客戶端處理執行緒將影像再傳遞給瀏覽器,

每當有新的瀏覽器訪問進來,就會單獨開辟一個執行緒,去處理這個瀏覽器接下來的通信互動,瀏覽器斷開連接之后,執行緒自動銷毀;影像緩沖區是一個公共的緩沖區,攝像頭影像采集執行緒向該緩沖區填充資料,與瀏覽器通信的執行緒就從這個緩沖區讀取資料,采用的是條件變數+互斥鎖同步訪問,

專案里用到的知識點主要是攝像頭采集,執行緒處理、網路編程,HTTP協議等知識點,

如果是搞QT開發,都可以當做入門學習參考;如果想要用其他語言實作,思路搞清楚也很容易, 標準C語言,

在Linux下如果不需要界面,可以直接使用C語言完成專案效果,攝像頭采集采用Linux下標準V4L2框架,執行緒就采用pthread_create創建,互斥鎖、條件變數這些Linux都有,只要把程式思路搞清楚,實作起來還是很容易,

2.2 跨平臺運行

代碼是采用QT框架撰寫,所以支持跨平臺編譯運行;目前代碼在Android、Linux、windows系統上都編譯運行通過,達到相同效果;由于身邊沒有蘋果設備,暫時未做測驗,

不同系統間代碼上還是有少許區別,代碼里通過宏的方式區分了,不同的系統運行不同的部分代碼,

如果要編譯QT的代碼在Android設備上運行,得先搭建對應的開發環境;如果不會環境搭建,可以參考下面鏈接,

(1). Linux(ubuntu)下搭建QT Android開發環境

https://blog.csdn.net/xiaolong1126626497/article/details/117256660

(2). windows(win10 64bit)下搭建QT Android開發環境

https://blog.csdn.net/xiaolong1126626497/article/details/117254453

(3). windows下Qt + VS2017 環境安裝

https://blog.csdn.net/xiaolong1126626497/article/details/112402861

2.3 專案原始碼運行環境

QT版本: 5.12.6

編譯器: MinGW 32

系統: Win10 Ubuntu18.04

2.4 代碼運行介紹

程式運行時,需要用到一些資源檔案,這些資源檔案在程式的原始碼目錄下,名稱是: www

如果是windows、Linux系統環境,需要把資源目錄拷貝到程式運行的同級目錄下,

如果是Android系統,這些資源檔案需要在編譯的時候打包進APK里,在工程目錄下的Android目錄里創建一個assets目錄,將資源檔案全部拷貝到assets目錄下;程式編譯的時候會自動將assets目錄打包進apk,到時候Android程式運行時就可以直接去assets目錄下獲取資源檔案,

當apk生成之后,可以解壓出來看看,assets目錄打包成功沒有,

檢查了下,打包成功的,這樣Android程式運行時,訪問的路徑就沒有問題,

2.5 Linux系統運行攝像頭無法讀取資料問題說明

由于我測驗的環境是在虛擬機里運行ubuntu系統,要在ubuntu里訪問攝像頭,需要先把攝像頭掛載到虛擬機,才能訪問,如果打開虛擬機發現右下角托盤里攝像頭圖示都沒有,說明托盤程式可能被360、電腦管家之類的安全軟體禁止了,需要開啟自動啟動,重啟VM虛擬機軟體再測驗,

直接掛載進來可能遇到攝像頭打開了,但是影像無法獲取的情況,這個問題可能是USB協議版本引起的,

可以在這里切換USB協議測驗,我的筆記本電腦是USB3.0才可以正常使用,

三、代碼分析

3.1 初始化代碼(建構式)

代碼開發時,主要是針對在windows平臺運行的,所有程式里很多都是偏向于windows環境的設計,

建構式里去除了系統原視窗標題欄,自定義了自己的標題;QT隱藏標題欄之后,是不能拖動拉伸的,需要自己實作,我這里采用的是GitHUB上開源的一個示例代碼實作的這部分功能,效果不錯,達到了想要的效果,剩下代碼里初始化了托盤系統,方便程式最小化時,隱藏在windows系統的托盤圖示欄里,其他的代碼就是做寫基本的初始化,信號槽的連接,IP地址、攝像頭資訊重繪等,

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //自定義標題欄
    FramelessHelper *pHelper = new FramelessHelper(this);
    setWindowFlags(Qt::FramelessWindowHint);
    pHelper->activateOn(this);  //激活當前表單
    //pHelper->setTitleHeight(m_pTitleBar->height());  //設定表單的標題欄高度
    pHelper->setWidgetMovable(true);  //設定表單可移動
    pHelper->setWidgetResizable(true);  //設定表單可縮放
   // pHelper->setRubberBandOnMove(true);  //設定橡皮筋效果-可移動
   // pHelper->setRubberBandOnResize(true);  //設定橡皮筋效果-可縮放

    /*基本設定*/
    this->setWindowIcon(QIcon(":/log.ico")); //設定圖示
    this->setWindowTitle("網路攝像頭");

    //打開的視窗在螢屏中間
    QDesktopWidget *widget= QApplication::desktop();
    move((widget->width()-this->width())/2,(widget->height()-this->height())/2);

    //重繪攝像頭與IP地址資訊
    on_pushButton_config_clicked();

    //重繪在線人數
    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(timer_update()));
    timer->start(1000);

    tray= new QSystemTrayIcon(this);//初始化托盤物件tray
    connect(tray,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(show_Widget(QSystemTrayIcon::ActivationReason)));

    tray->setIcon(QIcon(QPixmap(":/log.png")));//設定托盤圖示,引號內是自定義的png圖片路徑
    tray->setToolTip("網路攝像頭"); //提示文字
    restoreAction = new QAction("打開", this);
    connect(restoreAction, SIGNAL(triggered()), this, SLOT(show()));
    quitAction = new QAction("退出", this);
    connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));

    trayMenu = new QMenu(this);
    trayMenu->addAction(restoreAction);
    trayMenu->addSeparator();
    trayMenu->addAction(quitAction);
    tray->setContextMenu(trayMenu);

    work_class=new VideoReadThread_0;
    work_thread=new QThread;

    //啟動攝像頭的信號
    connect(this,SIGNAL(StartWorkThread()),work_class,SLOT(run()));
    //釋放資源-釋放攝像頭
    connect(this,SIGNAL(Stop_VideoAudioEncode_0()),work_class,SLOT(stop()));

    //連接攝像頭采集信號,在主執行緒實時顯示視頻畫面
    connect(work_class,SIGNAL(VideoDataOutput(QImage)),this,SLOT(VideoDataDisplay_0(QImage)));

    //將類移動到子執行緒作業
    work_class->moveToThread(work_thread);
}

3.2 攝像頭采集部分

攝像頭采集采用的是QCamera + QVideoProbe實作,

初始化代碼示例: 初始化代碼里完成攝像頭的一些引數,捕獲模式,槽函式關聯等設定,

初始化代碼默認設定輸出的影像格式是YUYV,在windows和Linux系統上是支持的,這個可能與攝像頭有關,實際需要測驗調整;Android系統上只支持NV21格式,如果是Android系統上運行,要記得修改格式,

void VideoReadThread_0::Camear_Init()
{
    /*創建攝像頭物件,根據選擇的攝像頭打開*/
    camera = new QCamera(videoaudioencode_0.camera);
    m_pProbe = new QVideoProbe;
    if(m_pProbe != nullptr)
    {
        m_pProbe->setSource(camera); // Returns true, hopefully.
        connect(m_pProbe, SIGNAL(videoFrameProbed(QVideoFrame)),this, SLOT(slotOnProbeFrame(QVideoFrame)), Qt::QueuedConnection);
    }
    else
    {
           qDebug()<<"m_pProbe == nullptr";
    }

    /*配置攝像頭捕    QCamera *camera;
    QVideoProbe *m_pProbe;獲模式為幀捕獲模式*/
     camera->setCaptureMode(QCamera::CaptureVideo);  //如果在Linux系統下運行就這樣設定
     //camera->setCaptureMode(QCamera::CaptureVideo);//如果在android系統下運行就這樣設定


    /*設定攝像頭的采集幀率和解析度*/
    QCameraViewfinderSettings settings;
    settings.setPixelFormat(QVideoFrame::Format_YUYV); //設定像素格式  Android上只支持NV21格式
    settings.setResolution(QSize(VIDEO_WIDTH,VIDEO_HEIGHT)); //設定攝像頭的解析度
    camera->setViewfinderSettings(settings);


    /*啟動攝像頭*/
    camera->start();

}

捕獲到攝像頭的影像資料之后,QVideoProbe會發出videoFrameProbed信號,在關聯的槽函式里完成資料處理,

處理代碼如下:

void VideoReadThread_0::slotOnProbeFrame(const QVideoFrame &frame)
{
//    qDebug()<<"開始采集.";
   QVideoFrame cloneFrame(frame);
   cloneFrame.map(QAbstractVideoBuffer::ReadOnly);

//    qDebug()<<"height:"<<cloneFrame.height();
//    qDebug()<<"width:"<<cloneFrame.width();
//    qDebug()<<"bytesPerLine:"<<cloneFrame.bytesPerLine();
//    qDebug()<<"mappedBytes:"<<cloneFrame.mappedBytes();
//    qDebug()<<"pixelFormat:"<<cloneFrame.pixelFormat();

   unsigned char rgb_buffer[VIDEO_WIDTH*VIDEO_HEIGHT*3];
   if(cloneFrame.pixelFormat()==QVideoFrame::Format_YUYV)
   {
       yuyv_to_rgb(cloneFrame.bits(),rgb_buffer,cloneFrame.width(),cloneFrame.height());
   }
   else if(cloneFrame.pixelFormat()==QVideoFrame::Format_NV21)
   {
        NV21_TO_RGB24(cloneFrame.bits(),rgb_buffer,cloneFrame.width(),cloneFrame.height());
   }
   else
   {
       qDebug()<<"當前格式編碼為%1,暫時不支持轉換.\n";
       return;
   }
    cloneFrame.unmap();

    //加載圖片資料
    QImage image(rgb_buffer,
                       cloneFrame.width(),
                       cloneFrame.height(),
                       QImage::Format_RGB888);

    //繪制圖片水印
    QDateTime dateTime(QDateTime::currentDateTime());
    //時間效果: 2020-03-05 16:25::04 周一
    QString qStr="";
    qStr+=dateTime.toString("yyyy-MM-dd hh:mm:ss ddd");
    QPainter pp(&image);
    QPen pen = QPen(Qt::white);
    pp.setPen(pen);
    pp.setFont(QFont("宋體",20));
    pp.drawText(QPointF(0,40),qStr);

    mutex.lock();
    QBuffer buff;
    image.save(&buff,"jpg",80); // 30表示壓宿率,值從0 – 100, 值越小表示編碼出來的影像檔案就越小,當然也就越不清晰
    lcd_image_data=buff.data();
    cond_wait.wakeAll();
    mutex.unlock();

    emit VideoDataOutput(image); //發送信號
}

代碼里區分了資料格式,如果是YUYV就呼叫對應的轉換函式將資料轉為RGB格式,如果是NV21也是一樣,呼叫對應的轉換函式將資料轉為RGB格式后續再做其他處理,

影像格式轉換的代碼如下:

/*
函式功能: 將YUV資料轉為RGB格式
函式引數:
unsigned char *yuv_buffer: YUV源資料
unsigned char *rgb_buffer: 轉換之后的RGB資料
int iWidth,int iHeight   : 影像的寬度和高度
*/
void yuyv_to_rgb(unsigned char *yuv_buffer,unsigned char *rgb_buffer,int iWidth,int iHeight)
{
    int x;
    int z=0;
    unsigned char *ptr = rgb_buffer;
    unsigned char *yuyv= yuv_buffer;
    for (x = 0; x < iWidth*iHeight; x++)
    {
        int r, g, b;
        int y, u, v;

        if (!z)
        y = yuyv[0] << 8;
        else
        y = yuyv[2] << 8;
        u = yuyv[1] - 128;
        v = yuyv[3] - 128;

        r = (y + (359 * v)) >> 8;
        g = (y - (88 * u) - (183 * v)) >> 8;
        b = (y + (454 * u)) >> 8;

        *(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r);
        *(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g);
        *(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b);

        if(z++)
        {
            z = 0;
            yuyv += 4;
        }
    }
}

void NV21_TO_RGB24(unsigned char *yuyv, unsigned char *rgb, int width, int height)
{
    const int nv_start = width * height ;
    int  index = 0, rgb_index = 0;
    uint8_t y, u, v;
    int r, g, b, nv_index = 0,i, j;

    for(i = 0; i < height; i++){
        for(j = 0; j < width; j ++){
            //nv_index = (rgb_index / 2 - width / 2 * ((i + 1) / 2)) * 2;
            nv_index = i / 2  * width + j - j % 2;

            y = yuyv[rgb_index];
            u = yuyv[nv_start + nv_index ];
            v = yuyv[nv_start + nv_index + 1];

            r = y + (140 * (v-128))/100;  //r
            g = y - (34 * (u-128))/100 - (71 * (v-128))/100; //g
            b = y + (177 * (u-128))/100; //b

            if(r > 255)   r = 255;
            if(g > 255)   g = 255;
            if(b > 255)   b = 255;
            if(r < 0)     r = 0;
            if(g < 0)     g = 0;
            if(b < 0)     b = 0;

            index = rgb_index % width + (height - i - 1) * width;
            //rgb[index * 3+0] = b;
            //rgb[index * 3+1] = g;
            //rgb[index * 3+2] = r;

            //顛倒影像
            //rgb[height * width * 3 - i * width * 3 - 3 * j - 1] = b;
            //rgb[height * width * 3 - i * width * 3 - 3 * j - 2] = g;
            //rgb[height * width * 3 - i * width * 3 - 3 * j - 3] = r;

            //正面影像
            rgb[i * width * 3 + 3 * j + 0] = b;
            rgb[i * width * 3 + 3 * j + 1] = g;
            rgb[i * width * 3 + 3 * j + 2] = r;

            rgb_index++;
        }
    }
}

影像格式轉換完成之后,下面就加載到QImage里,繪制上時間水印,將資料填充到緩沖區,然后再喚醒等待的執行緒,最后在傳遞一份資料給UI界面完成渲染顯示,

如果使用程序中,攝像頭支持的是其他格式,那么這里需要自己增加對應的轉換函式,

3.3 瀏覽器互動執行緒

這里是TCP客戶端處理資料的執行緒,每當連接一個新的客戶端,就會開辟一個新的執行緒獨立運行,

執行緒里完成瀏覽器請求的處理,回應,互動,

完整的回應代碼如下:

void TcpServerThread::run()
{
    qDebug()<<"TcpServerThread_子執行緒run槽函式的ID:"<<QThread::currentThreadId();
   QTcpSocket *tcpSocket;
    tcpSocket=new QTcpSocket;
    /*使用socketDescriptor套接字初始化QAbstractSocket*/
    if(!tcpSocket->setSocketDescriptor(socketDescriptor))
    {
        return;
    }

    //讀取接收的資料
    QString text;
    if(tcpSocket->waitForReadyRead())
    {
        text=tcpSocket->readAll();
    }

    //處理瀏覽器的請求
    if(text.contains("GET / HTTP/1.1", Qt::CaseInsensitive))
    {
        //如果是Android系統
#ifdef Q_OS_ANDROID
        text="assets:/login.html";
#else
         text=QCoreApplication::applicationDirPath();
         text+="/www/login.html";
#endif
        SendFileData(buff,text,"text/html",tcpSocket);
    }
    else if(text.contains("GET /image.jpg HTTP/1.1", Qt::CaseInsensitive))
    {
        SendImageData(buff,tcpSocket);
    }
    else if(text.contains("GET /favicon.ico HTTP/1.1", Qt::CaseInsensitive))
    {

#ifdef Q_OS_ANDROID
        text="assets:/logo.ico";
#else
        text=QCoreApplication::applicationDirPath();
        text+="/www/logo.ico";
#endif
        SendFileData(buff,text,"image/x-icon",tcpSocket);
    }
    else if(text.contains("GET /three.min.js", Qt::CaseInsensitive))
    {

#ifdef Q_OS_ANDROID
        text="assets:/three.min.js";
#else
        text=QCoreApplication::applicationDirPath();
        text+="/www/three.min.js";
#endif
        SendFileData(buff,text,"application/x-javascript",tcpSocket);
    }
    else if(text.contains("GET /style.css", Qt::CaseInsensitive))
    {

#ifdef Q_OS_ANDROID
        text="assets:/style.css";
#else
        text=QCoreApplication::applicationDirPath();
        text+="/www/style.css";
#endif
        SendFileData(buff,text,"text/css",tcpSocket);
    }
    else if(text.contains("GET /Stats.min.js", Qt::CaseInsensitive))
    {

#ifdef Q_OS_ANDROID
        text="assets:/Stats.min.js";
#else
        text=QCoreApplication::applicationDirPath();
        text+="/www/Stats.min.js";
#endif
        SendFileData(buff,text,"application/x-javascript",tcpSocket);
    }
    else if(text.contains("GET /logo.png HTTP/1.1", Qt::CaseInsensitive))
    {

#ifdef Q_OS_ANDROID
        text="assets:/logo.png";
#else
        text=QCoreApplication::applicationDirPath();
        text+="/www/logo.png";
#endif
        SendFileData(buff,text,"image/png",tcpSocket);
    }
    else if(text.contains("userName=admin&passWord=12345678", Qt::CaseInsensitive))
    {   

#ifdef Q_OS_ANDROID
        text="assets:/index.html";
#else
        text=QCoreApplication::applicationDirPath();
        text+="/www/index.html";
#endif
        SendFileData(buff,text,"text/html",tcpSocket);
    }

    //卸載連接的套接字
    fd_list.Del_fd(socketDescriptor);
    //關閉連接
    tcpSocket->close();
    delete  tcpSocket;
}

/**
 * 向瀏覽器回應請求資料
 */
int TcpServerThread::SendFileData(char *buff, QString file_path, const char *type, QTcpSocket *tcpSocket)
{
    qint64 size=0;
    /*1. 讀取檔案*/
    QFile file(file_path);
    if(file.open(QIODevice::ReadOnly)!=true)
    {
        qDebug()<<"檔案不存在:"<<file_path<<endl;
        return -1;
    }

    size=file.size(); //得到檔案大小
    QByteArray byte=file.readAll(); //讀取所有資料
    file.close();//關閉檔案
    /*2. 構建回應格式字串*/
    sprintf(buff,"HTTP/1.1 200 OK\r\n"
                 "Content-type:%s\r\n"
                 "Content-Length:%lld\r\n"
                 "\r\n",type,size);
    /*3. 向客戶端發送回應請求*/
    if(tcpSocket->write(buff,strlen(buff))<=0)return -2;
    tcpSocket->waitForBytesWritten();  //等待寫
    /*4. 向客戶端發送回應物體資料*/
    if(tcpSocket->write(byte)<=0)return -3;
    tcpSocket->waitForBytesWritten();  //等待寫
    return 0;
}

/*
向客戶端回圈發送圖片資料流
*/
int TcpServerThread::SendImageData(char *buff, QTcpSocket *tcpSocket)
{
    /*1. 構建回應格式字串*/
    sprintf(buff,"HTTP/1.0 200 OK\r\n"
                "Server: wbyq\r\n"
                "Content-Type:multipart/x-mixed-replace;boundary=boundarydonotcross\r\n"
                "\r\n"
                "--boundarydonotcross\r\n");
    /*2. 向客戶端發送回應請求*/
    if(tcpSocket->write(buff,strlen(buff))<=0)return -2;
    tcpSocket->waitForBytesWritten();  //等待寫
    /*3. 回圈發送資料*/
    while(thread_run_flag)
    {
        //從全域緩沖區取資料
        mutex.lock();
        cond_wait.wait(&mutex);
        QByteArray image_data; //保存一幀影像資料
        image_data=lcd_image_data;
        mutex.unlock();

//        QBuffer data_buff;
//        QPixmap pixmap;
//        QScreen *screen = QGuiApplication::primaryScreen();
//        pixmap=screen->grabWindow(0); //獲取當前螢屏的影像
//        //縮放影像
//        pixmap = pixmap.scaled(lcd_image_w,lcd_image_h, Qt::KeepAspectRatio);
//        pixmap.save(&data_buff,"jpg",image_val);

//        QByteArray image_data1=data_buff.data();


        /*4. 向瀏覽器發送回應頭*/
        sprintf(buff,"Content-type:image/jpeg\r\n"
                     "Content-Length:%d\r\n"
                     "\r\n",image_data.size());
        if(tcpSocket->write(buff,strlen(buff))<=0)break;
        tcpSocket->waitForBytesWritten();  //等待寫

        /*5. 發送物體資料*/
         if(tcpSocket->write(image_data)<=0)break;
         tcpSocket->waitForBytesWritten();  //等待寫

        /*6. 發送邊界符*/
        sprintf(buff,"\r\n--boundarydonotcross\r\n");
        if(tcpSocket->write(buff,strlen(buff))<=0)break;
        tcpSocket->waitForBytesWritten();  //等待寫

        //等待一段時間
        msleep(5);
    }
    return 0;
}

當密碼、賬號驗證通過之后,服務器就與瀏覽器建立長連接,回圈發送圖片流資料,瀏覽器完成連續重繪顯示, 里面實作的思路,就是基本的TCP網路編程代碼,

四、 HTTP協議簡單介紹

這個網路攝像頭專案主要是與瀏覽器互動的,要完成瀏覽器的互動,首先得知道HTTP協議的報文格式,如何回應,下面只是介紹當前專案里用到的部分知識,方便理解第三章的瀏覽器互動代碼,

4.1 HTTP協議介紹

HTTP協議是Hyper Text Transfer Protocol(超文本傳輸協議)的縮寫,服務器傳輸超文本到本地瀏覽器的傳送協議,
HTTP是一個基于TCP/IP通信協議來傳遞資料(HTML 檔案, 圖片檔案, 查詢結果等),

HTTP是無狀態:HTTP協議是無狀態協議,無狀態是指協議對于事務處理沒有記憶能力,缺少狀態意味著如果后續處理需要前面的資訊,則它必須重傳,這樣可能導致每次連接傳送的資料量增大,另一方面,在服務器不需要先前資訊時它的應答就較快,

HTTP協議作業于客戶端-服務端架構上,瀏覽器作為HTTP客戶端通過URL向HTTP服務端即WEB服務器發送所有請求,Web服務器根據接收到的請求后,向客戶端發送回應資訊,

4.2 請求方法與報文格式

客戶端請求訊息
客戶端發送一個HTTP請求到服務器的請求訊息包括以下格式:請求行(request line)、請求頭部(header)、空行和請求資料四個部分組成,下圖給出了請求報文的一般格式,

服務器回應訊息
HTTP回應也由四個部分組成,分別是:狀態行、訊息報頭、空行和回應正文,

HTTP協議常用的2種請求方法: GET, POST 方法,

1

GET

請求指定的頁面資訊,并回傳物體主體,

2

POST

向指定資源提交資料進行處理請求(例如提交表單或者上傳檔案),資料被包含在請求體中,POST請求可能會導致新的資源的建立和/或已有資源的修改,

4.3 HTTP回應頭資訊

HTTP請求頭提供了關于請求,回應或者其他的發送物體的資訊,

應答頭

說明

Allow

服務器支持哪些請求方法(如GETPOST等),

Content-Encoding

檔案的編碼(Encode)方法,只有在解碼之后才可以得到Content-Type頭指定的內容型別,利用gzip壓縮檔案能夠顯著地減少HTML檔案的下載時間,JavaGZIPOutputStream可以很方便地進行gzip壓縮,但只有Unix上的NetscapeWindows上的IE 4IE 5才支持它,因此,Servlet應該通過查看Accept-Encoding頭(即request.getHeader("Accept-Encoding"))檢查瀏覽器是否支持gzip,為支持gzip的瀏覽器回傳經gzip壓縮的HTML頁面,為其他瀏覽器回傳普通頁面,

Content-Length

表示內容長度,只有當瀏覽器使用持久HTTP連接時才需要這個資料,如果你想要利用持久連接的優勢,可以把輸出檔案寫入 ByteArrayOutputStream,完成后查看其大小,然后把該值放入Content-Length頭,最后通過byteArrayStream.writeTo(response.getOutputStream()發送內容,

Content-Type

表示后面的檔案屬于什么MIME型別,Servlet默認為text/plain,但通常需要顯式地指定為text/html,由于經常要設定Content-Type,因此HttpServletResponse提供了一個專用的方法setContentType,

Date

當前的GMT時間,你可以用setDateHeader來設定這個頭以避免轉換時間格式的麻煩,

Expires

應該在什么時候認為檔案已經過期,從而不再快取它?

Last-Modified

檔案的最后改動時間,客戶可以通過If-Modified-Since請求頭提供一個日期,該請求將被視為一個條件GET,只有改動時間遲于指定時間的檔案才會回傳,否則回傳一個304Not Modified)狀態,Last-Modified也可用setDateHeader方法來設定,

Location

表示客戶應當到哪里去提取檔案,Location通常不是直接設定的,而是通過HttpServletResponsesendRedirect方法,該方法同時設定狀態代碼為302

Refresh

表示瀏覽器應該在多少時間之后重繪檔案,以秒計,除了重繪當前檔案之外,你還可以通過setHeader("Refresh", "5; URL=http://host/path")讓瀏覽器讀取指定的頁面,
注意這種功能通常是通過設定HTML頁面HEAD區的<META HTTP-EQUIV="Refresh" CONTENT="5;URL=http://host/path">實作,這是因為,自動重繪或重定向對于那些不能使用CGIServletHTML撰寫者十分重要,但是,對于Servlet來說,直接設定Refresh頭更加方便,

注意Refresh的意義是"N秒之后重繪本頁面或訪問指定頁面",而不是"每隔N秒重繪本頁面或訪問指定頁面",因此,連續重繪要求每次都發送一個Refresh頭,而發送204狀態代碼則可以阻止瀏覽器繼續重繪,不管是使用Refresh頭還是<META HTTP-EQUIV="Refresh" ...>,
注意Refresh頭不屬于HTTP 1.1正式規范的一部分,而是一個擴展,但NetscapeIE都支持它,

Server

服務器名字,Servlet一般不設定這個值,而是由Web服務器自己設定,

Set-Cookie

設定和頁面關聯的CookieServlet不應使用response.setHeader("Set-Cookie", ...),而是應使用HttpServletResponse提供的專用方法addCookie,參見下文有關Cookie設定的討論,

WWW-Authenticate

客戶應該在Authorization頭中提供什么型別的授權資訊?在包含401Unauthorized)狀態行的應答中這個頭是必需的,例如,response.setHeader("WWW-Authenticate", "BASIC realm="executives"")
注意Servlet一般不進行這方面的處理,而是讓Web服務器的專門機制來控制受密碼保護頁面的訪問(例如.htaccess),

4.4 HTTP狀態碼

當瀏覽者訪問一個網頁時,瀏覽者的瀏覽器會向網頁所在服務器發出請求,

當瀏覽器接收并顯示網頁前,此網頁所在的服務器會回傳一個包含HTTP狀態碼的資訊頭(server header)用以回應瀏覽器的請求,

HTTP狀態碼的英文為HTTP Status Code,

下面是常見的HTTP狀態碼:
200 - 請求成功
301 - 資源(網頁等)被永久轉移到其它URL
404 - 請求的資源(網頁等)不存在
500 - 內部服務器錯誤

4.5 HTTP content-type

Content-Type,內容型別,一般是指網頁中存在的Content-Type,用于定義網路檔案的型別和網頁的編碼,決定瀏覽器將以什么形式、什么編碼讀取這個檔案,這就是經常看到一些Asp網頁點擊的結果卻是下載到的一個檔案或一張圖片的原因,

HTTP content-type 對照表:

檔案擴展名

Content-Type(Mime-Type)

檔案擴展名

Content-Type(Mime-Type)

.* 二進制流,不知道下載檔案型別)

application/octet-stream

.tif

image/tiff

.001

application/x-001

.301

application/x-301

.323

text/h323

.906

application/x-906

.907

drawing/907

.a11

application/x-a11

.acp

audio/x-mei-aac

.ai

application/postscript

.aif

audio/aiff

.aifc

audio/aiff

.aiff

audio/aiff

.anv

application/x-anv

.asa

text/asa

.asf

video/x-ms-asf

.asp

text/asp

.asx

video/x-ms-asf

.au

audio/basic

.avi

video/avi

.awf

application/vnd.adobe.workflow

.biz

text/xml

.bmp

application/x-bmp

.bot

application/x-bot

.c4t

application/x-c4t

.c90

application/x-c90

.cal

application/x-cals

.cat

application/vnd.ms-pki.seccat

.cdf

application/x-netcdf

.cdr

application/x-cdr

.cel

application/x-cel

.cer

application/x-x509-ca-cert

.cg4

application/x-g4

.cgm

application/x-cgm

.cit

application/x-cit

.class

java/*

.cml

text/xml

.cmp

application/x-cmp

.cmx

application/x-cmx

.cot

application/x-cot

.crl

application/pkix-crl

.crt

application/x-x509-ca-cert

.csi

application/x-csi

.css

text/css

.cut

application/x-cut

.dbf

application/x-dbf

.dbm

application/x-dbm

.dbx

application/x-dbx

.dcd

text/xml

.dcx

application/x-dcx

.der

application/x-x509-ca-cert

.dgn

application/x-dgn

.dib

application/x-dib

.dll

application/x-msdownload

.doc

application/msword

.dot

application/msword

.drw

application/x-drw

.dtd

text/xml

.dwf

Model/vnd.dwf

.dwf

application/x-dwf

.dwg

application/x-dwg

.dxb

application/x-dxb

.dxf

application/x-dxf

.edn

application/vnd.adobe.edn

.emf

application/x-emf

.eml

message/rfc822

.ent

text/xml

.epi

application/x-epi

.eps

application/x-ps

.eps

application/postscript

.etd

application/x-ebx

.exe

application/x-msdownload

.fax

image/fax

.fdf

application/vnd.fdf

.fif

application/fractals

.fo

text/xml

.frm

application/x-frm

.g4

application/x-g4

.gbr

application/x-gbr

.

application/x-

.gif

image/gif

.gl2

application/x-gl2

.gp4

application/x-gp4

.hgl

application/x-hgl

.hmr

application/x-hmr

.hpg

application/x-hpgl

.hpl

application/x-hpl

.hqx

application/mac-binhex40

.hrf

application/x-hrf

.hta

application/hta

.htc

text/x-component

.htm

text/html

.html

text/html

.htt

text/webviewhtml

.htx

text/html

.icb

application/x-icb

.ico

image/x-icon

.ico

application/x-ico

.iff

application/x-iff

.ig4

application/x-g4

.igs

application/x-igs

.iii

application/x-iphone

.img

application/x-img

.ins

application/x-internet-signup

.isp

application/x-internet-signup

.IVF

video/x-ivf

.java

java/*

.jfif

image/jpeg

.jpe

image/jpeg

.jpe

application/x-jpe

.jpeg

image/jpeg

.jpg

image/jpeg

.jpg

application/x-jpg

.js

application/x-javascript

.jsp

text/html

.la1

audio/x-liquid-file

.lar

application/x-laplayer-reg

.latex

application/x-latex

.lavs

audio/x-liquid-secure

.lbm

application/x-lbm

.lmsff

audio/x-la-lms

.ls

application/x-javascript

.ltr

application/x-ltr

.m1v

video/x-mpeg

.m2v

video/x-mpeg

.m3u

audio/mpegurl

.m4e

video/mpeg4

.mac

application/x-mac

.man

application/x-troff-man

.math

text/xml

.mdb

application/msaccess

.mdb

application/x-mdb

.mfp

application/x-shockwave-flash

.mht

message/rfc822

.mhtml

message/rfc822

.mi

application/x-mi

.mid

audio/mid

.midi

audio/mid

.mil

application/x-mil

.mml

text/xml

.mnd

audio/x-musicnet-download

.mns

audio/x-musicnet-stream

.mocha

application/x-javascript

.movie

video/x-sgi-movie

.mp1

audio/mp1

.mp2

audio/mp2

.mp2v

video/mpeg

.mp3

audio/mp3

.mp4

video/mpeg4

.mpa

video/x-mpg

.mpd

application/vnd.ms-project

.mpe

video/x-mpeg

.mpeg

video/mpg

.mpg

video/mpg

.mpga

audio/rn-mpeg

.mpp

application/vnd.ms-project

.mps

video/x-mpeg

.mpt

application/vnd.ms-project

.mpv

video/mpg

.mpv2

video/mpeg

.mpw

application/vnd.ms-project

.mpx

application/vnd.ms-project

.mtx

text/xml

.mxp

application/x-mmxp

.net

image/pnetvue

.nrf

application/x-nrf

.nws

message/rfc822

.odc

text/x-ms-odc

.out

application/x-out

.p10

application/pkcs10

.p12

application/x-pkcs12

.p7b

application/x-pkcs7-certificates

.p7c

application/pkcs7-mime

.p7m

application/pkcs7-mime

.p7r

application/x-pkcs7-certreqresp

.p7s

application/pkcs7-signature

.pc5

application/x-pc5

.pci

application/x-pci

.pcl

application/x-pcl

.pcx

application/x-pcx

.pdf

application/pdf

.pdf

application/pdf

.pdx

application/vnd.adobe.pdx

.pfx

application/x-pkcs12

.pgl

application/x-pgl

.pic

application/x-pic

.pko

application/vnd.ms-pki.pko

.pl

application/x-perl

.plg

text/html

.pls

audio/scpls

.plt

application/x-plt

.png

image/png

.png

application/x-png

.pot

application/vnd.ms-powerpoint

.ppa

application/vnd.ms-powerpoint

.ppm

application/x-ppm

.pps

application/vnd.ms-powerpoint

.ppt

application/vnd.ms-powerpoint

.ppt

application/x-ppt

.pr

application/x-pr

.prf

application/pics-rules

.prn

application/x-prn

.prt

application/x-prt

.ps

application/x-ps

.ps

application/postscript

.ptn

application/x-ptn

.pwz

application/vnd.ms-powerpoint

.r3t

text/vnd.rn-realtext3d

.ra

audio/vnd.rn-realaudio

.ram

audio/x-pn-realaudio

.ras

application/x-ras

.rat

application/rat-file

.rdf

text/xml

.rec

application/vnd.rn-recording

.red

application/x-red

.rgb

application/x-rgb

.rjs

application/vnd.rn-realsystem-rjs

.rjt

application/vnd.rn-realsystem-rjt

.rlc

application/x-rlc

.rle

application/x-rle

.rm

application/vnd.rn-realmedia

.rmf

application/vnd.adobe.rmf

.rmi

audio/mid

.rmj

application/vnd.rn-realsystem-rmj

.rmm

audio/x-pn-realaudio

.rmp

application/vnd.rn-rn_music_package

.rms

application/vnd.rn-realmedia-secure

.rmvb

application/vnd.rn-realmedia-vbr

.rmx

application/vnd.rn-realsystem-rmx

.rnx

application/vnd.rn-realplayer

.rp

image/vnd.rn-realpix

.rpm

audio/x-pn-realaudio-plugin

.rsml

application/vnd.rn-rsml

.rt

text/vnd.rn-realtext

.rtf

application/msword

.rtf

application/x-rtf

.rv

video/vnd.rn-realvideo

.sam

application/x-sam

.sat

application/x-sat

.sdp

application/sdp

.sdw

application/x-sdw

.sit

application/x-stuffit

.slb

application/x-slb

.sld

application/x-sld

.slk

drawing/x-slk

.smi

application/smil

.smil

application/smil

.smk

application/x-smk

.snd

audio/basic

.sol

text/plain

.sor

text/plain

.spc

application/x-pkcs7-certificates

.spl

application/futuresplash

.spp

text/xml

.ssm

application/streamingmedia

.sst

application/vnd.ms-pki.certstore

.stl

application/vnd.ms-pki.stl

.stm

text/html

.sty

application/x-sty

.svg

text/xml

.swf

application/x-shockwave-flash

.tdf

application/x-tdf

.tg4

application/x-tg4

.tga

application/x-tga

.tif

image/tiff

.tif

application/x-tif

.tiff

image/tiff

.tld

text/xml

.top

drawing/x-top

.torrent

application/x-bittorrent

.tsd

text/xml

.txt

text/plain

.uin

application/x-icq

.uls

text/iuls

.vcf

text/x-vcard

.vda

application/x-vda

.vdx

application/vnd.visio

.vml

text/xml

.vpg

application/x-vpeg005

.vsd

application/vnd.visio

.vsd

application/x-vsd

.vss

application/vnd.visio

.vst

application/vnd.visio

.vst

application/x-vst

.vsw

application/vnd.visio

.vsx

application/vnd.visio

.vtx

application/vnd.visio

.vxml

text/xml

.wav

audio/wav

.wax

audio/x-ms-wax

.wb1

application/x-wb1

.wb2

application/x-wb2

.wb3

application/x-wb3

.wbmp

image/vnd.wap.wbmp

.wiz

application/msword

.wk3

application/x-wk3

.wk4

application/x-wk4

.wkq

application/x-wkq

.wks

application/x-wks

.wm

video/x-ms-wm

.wma

audio/x-ms-wma

.wmd

application/x-ms-wmd

.wmf

application/x-wmf

.wml

text/vnd.wap.wml

.wmv

video/x-ms-wmv

.wmx

video/x-ms-wmx

.wmz

application/x-ms-wmz

.wp6

application/x-wp6

.wpd

application/x-wpd

.wpg

application/x-wpg

.wpl

application/vnd.ms-wpl

.wq1

application/x-wq1

.wr1

application/x-wr1

.wri

application/x-wri

.wrk

application/x-wrk

.ws

application/x-ws

.ws2

application/x-ws

.wsc

text/scriptlet

.wsdl

text/xml

.wvx

video/x-ms-wvx

.xdp

application/vnd.adobe.xdp

.xdr

text/xml

.xfd

application/vnd.adobe.xfd

.xfdf

application/vnd.adobe.xfdf

.xhtml

text/html

.xls

application/vnd.ms-excel

.xls

application/x-xls

.xlw

application/x-xlw

.xml

text/xml

.xpl

audio/scpls

.xq

text/xml

.xql

text/xml

.xquery

text/xml

.xsd

text/xml

.xsl

text/xml

.xslt

text/xml

.xwd

application/x-xwd

.x_b

application/x-x_b

.sis

application/vnd.symbian.install

.sisx

application/vnd.symbian.install

.x_t

application/x-x_t

.ipa

application/vnd.iphone

.apk

application/vnd.android.package-archive

.xap

application/x-silverlight-app

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/295460.html

標籤:其他

上一篇:豆瓣評分預測(如何用自己的資料集進行文本分類)——基于pytorch的 BERT中文文本分類,超詳細教程必會!!!

下一篇:Fuchsia OS 將推送給所有第一代 Nest Hub 設備

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more