Qt广告机客户端(下位机)

news2024/9/20 1:01:50

目录

  • 功能
  • 结构
  • adClient.pro
  • main.cpp
  • adclient.h 客户端
  • adclient.cpp 客户端
    • addate.h 时间处理
    • addate.cpp 时间处理
    • adsocket.h 客户端Socket处理
    • adsocket.cpp 客户端Socket处理
    • weather.h 天气信息处理
    • weather.cpp 天气信息处理
    • rollmassege.h 滚动信息处理
    • rollmassege.cpp 滚动信息处理
  • 效果

功能

  1. 连接服务器(上位机)
  2. 广告图片播放模块
  3. 日期显示模块
  4. 天气显示模块
  5. 信息提示模块

结构

在这里插入图片描述

adClient.pro

QT       += core gui network

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

TARGET = adClient
TEMPLATE = app


SOURCES += main.cpp\
        adclient.cpp \
    addate.cpp \
    adsocket.cpp \
    weather.cpp \
    rollmassege.cpp

HEADERS  += adclient.h \
    addate.h \
    adsocket.h \
    tcp_MSG.h \
    weather.h \
    rollmassege.h

FORMS    += adclient.ui

RESOURCES += \
    res.qrc

main.cpp

#include "adclient.h"
#include <QApplication>
#include <QDebug>
#include <QDir>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    // 判断当前运行环境是否为Linux或Windows。
#ifdef Q_OS_LINUX
    qDebug() << "Current OS is Linux";
#elif defined(Q_OS_WIN)
    qDebug() << "Current OS is Windows";
#else
    qDebug() << "Unknown OS";
#endif

    QString folderName = "pic";
    //QString folderPath = QDir::currentPath() + "/" + folderName;
    QString folderPath = QApplication::applicationDirPath() + "/" + folderName;

    QDir folder(folderPath);
    if (!folder.exists())
    {

        bool success = folder.mkpath("."); // 创建文件夹
        if (success)
            qDebug() << "文件夹创建成功";
        else
            qDebug() << "文件夹创建失败";
    }
    else
         qDebug() << "文件夹已存在";

    QDir::setCurrent(folderPath);// 设置文件生成路径

    AdClient w;
    w.show();

    return a.exec();
}

adclient.h 客户端

#ifndef ADCLIENT_H
#define ADCLIENT_H

#include <QMainWindow>
#include "addate.h"
#include "adsocket.h"
#include "weather.h"
#include "rollmassege.h"
#include <QLabel>
#include <QProgressDialog>
#include "stdlib.h"
#include <QThread>
#include <QTimer>
#include <QFile>
#include <QMessageBox>
#include <QNetworkInterface>
#include <QTcpSocket>
#include <QHostAddress>
#include <QAbstractSocket>
#include <QLineEdit>
#include <QPushButton>

namespace Ui {
class AdClient;
}

class AdClient : public QMainWindow
{
    Q_OBJECT

public:
    explicit AdClient(QWidget *parent = 0);
    ~AdClient();
    void saveFile();// 保存文件
    void InitStatusBar();// 初始化底部状态栏
    QString GetLocalIP();// 获取本地IP

public slots:
    void showImage(QImage);// 图片显示
    void showProgressBar(int currentProgress,int finish);//进度条显示
    void autoPlayTimeOut();//自动播放
    void GUI_WarningMsg(QString title,QString text,QString buttons,QString defaultButton);//设置警报
    void connectToServer();// 链接到服务器
private:
    Ui::AdClient *ui;
    AdDate *date;
    AdSocket *socket;
    Weather *weater;
    RollMassege *rollmsg;
    QProgressDialog *progress;// 创建进度条
    QTimer autoPlayTimer;
    int index;
    QLabel *mLocalIP;
    QLabel *serverIP_lb;
    QLineEdit *serverIP;
    QLabel *serverPort_lb;
    QLineEdit *serverPort;
    QPushButton *connectTcp;

};

#endif // ADCLIENT_H

adclient.cpp 客户端

#include "adclient.h"
#include "ui_adclient.h"
#include <QDebug>

QMap<QString,QImage> qMapPicturePath;// 图片路径

//QTcpSocket 的默认缓存区大小是 64KB(65536字节)
AdClient::AdClient(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::AdClient)
{
    ui->setupUi(this);
    this->setWindowIcon(QIcon(":/client.jpg"));
    date = new AdDate(ui->date_lb);//时间
    socket = new AdSocket;// TCP客户端
    weater = new Weather(ui->weather_lb);// 接收天气信息绘制
    rollmsg = new RollMassege(ui->msg_lb, ui->msg_lb);// 滚动信息

    connect(socket, SIGNAL(sig_showWeather(QString,QString,QString)), weater, SLOT(showWeather(QString,QString,QString)));
    connect(socket, SIGNAL(sig_showTxt(QString)), rollmsg, SLOT(showTxt(QString)));
    connect(socket, SIGNAL(sig_showImage(QImage)), this, SLOT(showImage(QImage)));
    connect(socket, SIGNAL(sig_showProgressBar(int,int)), this, SLOT(showProgressBar(int,int)),Qt::QueuedConnection);
    connect(socket, SIGNAL(GUI_WarningSignal(QString,QString,QString,QString)), this, SLOT(GUI_WarningMsg(QString,QString,QString,QString)));

    date->start();//更新时间
    progress = nullptr;
    autoPlayTimer.stop();
    connect(&autoPlayTimer, SIGNAL(timeout()), this, SLOT(autoPlayTimeOut()));

    InitStatusBar();// 初始化底部状态栏
}

AdClient::~AdClient()
{
    delete socket;
    delete ui;
}

// 保存文件
void AdClient::saveFile()
{
    QString fileName=qMapPicturePath.lastKey();
    qDebug()<<"lastKey:"<<fileName;
    QImage image=qMapPicturePath.last();
    image.save(fileName);
}

// 初始化底部状态栏
void AdClient::InitStatusBar()
{
    mLocalIP=new QLabel(this);
    mLocalIP->setMinimumWidth(230);
    QString ip = GetLocalIP();
    //    mLocalIP->setText("本地IP:"+ip);
    mLocalIP->setText("本地IP:"+tr("<font color=\"red\">%1</font>").arg(ip));

    serverIP_lb=new QLabel(this);
    serverIP_lb->setMinimumWidth(100);
    serverIP_lb->setText("服务器IP:");
    serverIP=new QLineEdit(this);
    serverIP->setMinimumWidth(200);
    serverIP->setInputMask("000.000.000.000");

    serverPort_lb=new QLabel(this);
    serverPort_lb->setMinimumWidth(60);
    serverPort_lb->setText("Port:");
    serverPort=new QLineEdit(this);
    serverPort->setMinimumWidth(60);
    serverPort->setPlaceholderText("8888");

    connectTcp=new QPushButton("链接",this);
    connectTcp->setMinimumWidth(100);

    ui->statusBar->addWidget(mLocalIP);
    ui->statusBar->addWidget(serverIP_lb);
    ui->statusBar->addWidget(serverIP);
    ui->statusBar->addWidget(serverPort_lb);
    ui->statusBar->addWidget(serverPort);
    ui->statusBar->addWidget(connectTcp);

    connect(connectTcp, SIGNAL(clicked()), this, SLOT(connectToServer()));
}


// 获取本地IP
QString AdClient::GetLocalIP()
{
    QList<QHostAddress> list=QNetworkInterface::allAddresses();
    foreach(QHostAddress address,list)
    {
        if(address.protocol()==QAbstractSocket::IPv4Protocol)
        {
            qDebug()<<address.toString();
            return address.toString();
        }
    }
    return "";
}


// 图片显示
void AdClient::showImage(QImage image)
{
    qDebug()<<"显示图片"<<__LINE__;
    QPixmap pixmap=QPixmap::fromImage(image);
    // 内容是否自动缩放,参数true自动缩放
    ui->video_lb->setScaledContents(true);//显示图片的全部
    // 将图片缩放到指定大小,参数ui->label->size()表示缩放的大小,Qt::KeepAspectRatio表示保持图片的宽高比,Qt::SmoothTransformation表示使用平滑缩放算法
    ui->video_lb->setPixmap(pixmap.scaled(ui->video_lb->size(),Qt::KeepAspectRatio,Qt::SmoothTransformation));

    qDebug()<<"图片数量:"<<qMapPicturePath.count();
    qDebug()<<"定时器状态:"<<autoPlayTimer.isActive();

    if(qMapPicturePath.count()>=2)
    {
        if(!autoPlayTimer.isActive()){
            // 两张以上图片开启播放
            autoPlayTimer.start(5000);
            index=0;
        }
    }
    else
    {
        autoPlayTimer.stop();
    }

    if(qMapPicturePath.count()>=1)
    {
        // 功能没问题,调试注释,避免多次保存
        //saveFile();// 保存文件
    }
}

//进度条显示
void AdClient::showProgressBar(int currentProgress, int finish)
{
    qDebug()<<"进度条显示"<<__LINE__;
    if (!progress)
    {
        //创建进度条
        progress = new QProgressDialog("接收中....", "取消", 0, 100, this);
        progress->setWindowModality(Qt::WindowModal);
        progress->setFixedSize(this->width()*0.3,this->height()*0.3);
        progress->setVisible(true);

    }
    //usleep(500);//在Windows环境下已被弃用
    QThread::msleep(50);//休眠50毫秒
    //更新进度条
    progress->setValue(currentProgress * 100 / finish);

    //如果任务已经完成,隐藏进度条
    if (currentProgress == finish)
    {
        qDebug()<<"进度条显示完成"<<__LINE__;
        progress->hide();
        delete progress;
        progress = nullptr;
    }
}

//自动播放
void AdClient::autoPlayTimeOut()
{
    QList<QString> keyList = qMapPicturePath.keys();//存放的就是QMap的key值

    if(index>=qMapPicturePath.count())// 删除广告时有可能 >
        index=0;

    QImage image=qMapPicturePath.value(keyList.at(index));
    qDebug()<<"自动播放:"<<keyList.at(index);
    showImage(image);

    index++;
}
//设置警报
void AdClient::GUI_WarningMsg(QString title, QString text, QString buttons, QString defaultButton)
{
    Q_UNUSED(buttons)//忽略编译器发出的警告,表明变量event未使用
    Q_UNUSED(defaultButton)
    QMessageBox *box=new QMessageBox(QMessageBox::Warning,title,text,QMessageBox::Cancel,this);
    QTimer::singleShot(5000,this,[=](){
        if(!box->isHidden()&&box->isVisible())
        {
            box->accept();
        }
    });// 5s后必执行
    box->exec();
    return;
}

// 链接到服务器
void AdClient::connectToServer()
{
    if(serverIP->text().isEmpty()||serverPort->text().isEmpty())
    {
        QMessageBox::warning(this,"提示","请输入IP或Port");
        return;
    }
    socket->id=GetLocalIP();
    socket->address=serverIP->text();
    qDebug()<<"服务器IP:"<<socket->address;
    socket->port=serverPort->text().toInt();
    qDebug()<<"服务器Port:"<<socket->port;

    qDebug()<<"是否已经连接:"<<socket->isValid();
    if(socket->isValid())// 如果套接字有效并且可以使用,则返回true;否则返回false。
    {
        socket->disconnectFromHost();// 与服务器断开连接
        // 无需再手动连接,只要更新IP和Port就行,AdSocket::conAgain会重新发起连接.

    }
    else
    {
        socket->connectToHost(QHostAddress(socket->address), socket->port);
    }
    qDebug()<<"是否已经连接:"<<socket->isValid();
}

addate.h 时间处理

#ifndef ADDATE_H
#define ADDATE_H

#include <QTime>
#include <QDate>
#include <QLabel>
#include <QTimer>

class AdDate : public QObject
{
    Q_OBJECT
public:
    AdDate(QLabel *_mlabel, QObject *parent = 0);
    ~AdDate();
    void start();// 定时器开启
public slots:
    void updateTime();// 定时器1s超时执行一次
private:
    QLabel *mlabel;
    QTimer *mtimer;
};

#endif // ADDATE_H

addate.cpp 时间处理

#include "addate.h"

AdDate::AdDate(QLabel *_mlabel, QObject *parent):
    QObject(parent)
{
    mlabel = _mlabel;
    mtimer = new QTimer;
    connect(mtimer, SIGNAL(timeout()), this, SLOT(updateTime()));
}

AdDate::~AdDate()
{
    delete mtimer;
}

void AdDate::start()
{
     mtimer->start(1000);
}

void AdDate::updateTime()
{
    QString time = QTime::currentTime().toString("hh:mm:ss")+"\n"
            +QDate::currentDate().toString("yy/MM/dd ddd");

    mlabel->setText(time);
}

adsocket.h 客户端Socket处理

#ifndef ADSOCKET_H
#define ADSOCKET_H

#include <QTcpSocket>
#include <QHostAddress>
#include <QAbstractSocket>
#include <QAbstractSocket>
#include <QImage>
#include <QLabel>
#include <QBuffer>
#include <QTime>
#include "string.h"
#include "tcp_MSG.h"



class AdSocket : public QTcpSocket
{
    Q_OBJECT
public:
    explicit AdSocket(QObject *parent = 0);
    ~AdSocket();

    QString id;
    QString address;
    int port;
    int readMsgType;

signals:
    void sig_showWeather(QString city,QString area,QString wt);// 发送天气信息
    void sig_showTxt(QString tcp_Txt);// 发送文字信息
    void sig_showImage(QImage tcp_image);// 发送文字信息
    void sig_showProgressBar(int currentProgress, int finish);// 发送进度条信息
    void GUI_WarningSignal(QString title,QString text,QString buttons,QString defaultButton);//设置警报

public slots:
    void readMsg();// 接收信息
    void conSuc(); // 成功建立连接
    void conAgain();// 重新连接
    void conAgain(QAbstractSocket::SocketError);// 重新连接


private:
    int needFileSize;
    int currentReceiveSize;
    QByteArray currentReceiveByte;
    int milsec;
    QString fileName;
};

#endif // ADSOCKET_H

adsocket.cpp 客户端Socket处理

#include "adsocket.h"
#include <QDebug>

extern QMap<QString,QImage> qMapPicturePath;// 图片路径

// QTcpSocket会自动处理大小端问题
AdSocket::AdSocket(QObject *parent) :
    QTcpSocket(parent)
{
    //注册tcp_MSG类型
    qRegisterMetaType<tcp_MSG>("tcp_MSG");

    id = "0011";
    /* 每当有新的输入数据时,就会发出这个信号。
    请记住,新传入的数据只报告一次;如果您不读取所有数据,这个类会缓冲数据,您可以稍后读取它,但是除非新数据到达,否则不会发出信号。*/
    connect(this, SIGNAL(readyRead()),this, SLOT(readMsg()));

    //该信号在调用connectToHost()并成功建立连接之后发出。
    connect(this, SIGNAL(connected()),this, SLOT(conSuc()));

    // 该信号在套接字断开连接时发出
    connect(this, SIGNAL(disconnected()),this, SLOT(conAgain()));

    address="127.0.0.1";
    port=8888;

    //connectToHost(QHostAddress(address), port);// 默认连接127.0.0.1 8888

    //该信号在错误发生后发出。socketError参数描述发生错误的类型
    connect(this, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(conAgain(QAbstractSocket::SocketError)));

    readMsgType=MsgType::Init;

    milsec=0;
}

AdSocket::~AdSocket()
{

}

// 接收信息
void AdSocket::readMsg()
{
    //读取缓冲区数据
    QByteArray  buffer = readAll();
    qDebug()<<"进来了"<<__LINE__;
    if(readMsgType==MsgType::Init)
    {
        tcp_MSG *msg=(tcp_MSG *)buffer.data();        //强转为结构体,需要用结构体指针接收
        qDebug()<<"进来了"<<__LINE__;
        qDebug()<<"类型"<<msg->type;
        switch (msg->type)
        {
        case WEATHER://天气
        {
            QString city=msg->city;
            QString area=msg->area;
            QString weather=msg->weather;
            //weather="\t\t"+city+"\t"+area+"\n"+weather;
            emit sig_showWeather(city,area,weather);// 发送天气信息
            break;
        }
        case MASSEGE:// 留言
        {
            QString tcp_Txt=msg->txt;
            qDebug()<<"文字信息:"<<tcp_Txt;
            emit sig_showTxt(tcp_Txt);// 发送文字信息
            break;
        }
        case VIDEO:// 视频
            qDebug()<<"发送视频信息:";
            break;
        case AD_add://添加广告
        {
            qDebug()<<"添加广告"<<__LINE__;
            qDebug()<<"文件名"<< QString(msg->fileName);
            qDebug()<<"编号"<< msg->index;
            qDebug()<<"总数"<< msg->allAd_Num;

            needFileSize=msg->fileSize;
            currentReceiveSize=0;
            currentReceiveByte.clear();
            QByteArray  sendTcpData;
            //使用字节数组,将结构体转为字符数组,发送的是字符数组(数据在传输过程中都是byte类型的)
            //直接sizeof(senddata)内存会变小,设置了对齐方式解决
            sendTcpData.resize(sizeof(tcp_backMSG));
            tcp_backMSG backMsg={};
            strcpy(backMsg.id,id.toUtf8().data());
            backMsg.state=1;
            backMsg.type=MsgType::Write_back;
            //将封装好的结构体转为QByteArray数组,因为传输都是Byte类型
            memcpy(sendTcpData.data(),&backMsg,sizeof(tcp_backMSG));

            this->write(sendTcpData);// 回复

            fileName.clear();
            fileName=QString(msg->fileName);

            readMsgType=MsgType::AD_add;
            break;
        }
        case AD_delete://删除广告
        {
            qDebug()<<"删除广告"<<__LINE__;
            qDebug()<<"文件名"<< QString(msg->fileName);
            int  success= qMapPicturePath.remove(QString(msg->fileName));
            if(success)
            {
                if(qMapPicturePath.count()>=1)
                {// 有图片
                    emit sig_showImage(qMapPicturePath.first());
                }
                else
                {// 没有图片
                    QImage image(100, 100, QImage::Format_RGBA8888);
                    image.fill(QColor(0, 0, 0, 0));// 纯透明图片
                    emit sig_showImage(image);
                }
                emit GUI_WarningSignal("提示","删除广告成功",NULL,NULL);
            }
            else
            {
                emit GUI_WarningSignal("提示","删除广告失败",NULL,NULL);
            }
            break;
        }
        default:
            qDebug()<<"";
            break;
        }
    }
    else if(readMsgType==MsgType::AD_add)
    {
        qDebug()<<"添加广告"<<__LINE__;
        qDebug()<<"需要接收大小:"<<needFileSize;
        // 记录开始时间
        QTime startTime = QTime::currentTime();

        currentReceiveSize+=buffer.size();
        currentReceiveByte+=buffer;
        qDebug()<<"当前接收大小:"<<currentReceiveSize;
        emit sig_showProgressBar(currentReceiveSize,needFileSize);
        // 记录结束时间
        QTime endTime = QTime::currentTime();
        // 计算运行时间
        milsec += startTime.msecsTo(endTime);

        if(needFileSize==currentReceiveSize)
        {
            qDebug()<<"图片接收完成";
            startTime = QTime::currentTime();

            QByteArray Ret_bytearray = QByteArray::fromBase64(currentReceiveByte);
            QBuffer buffer(&Ret_bytearray);
            buffer.open(QIODevice::WriteOnly);
            QPixmap imageresult;
            imageresult.loadFromData(Ret_bytearray);

            qMapPicturePath.insert(fileName,imageresult.toImage());// 先插入键值
            emit sig_showImage(imageresult.toImage());

            readMsgType=MsgType::Init;

            endTime = QTime::currentTime();
            milsec += startTime.msecsTo(endTime);
            qDebug()<<"接收消耗时间"<<milsec<<"毫秒";
        }
    }
}
// 成功建立连接
void AdSocket::conSuc()
{
    QByteArray  sendTcpData;
    //使用字节数组,将结构体转为字符数组,发送的是字符数组(数据在传输过程中都是byte类型的)
    //直接sizeof(senddata)内存会变小,设置了对齐方式解决
    sendTcpData.resize(sizeof(tcp_backMSG));
    tcp_backMSG msg={};
    strcpy(msg.id,id.toUtf8().data());
    msg.state=0;
    msg.type=MsgType::Init;
    //将封装好的结构体转为QByteArray数组,因为传输都是Byte类型
    memcpy(sendTcpData.data(),&msg,sizeof(tcp_backMSG));

    this->write(sendTcpData);
    qDebug()<<"connect success";
}

// 重新连接
void AdSocket::conAgain()
{
    qDebug()<<"套接字断开连接时重新连接";
    abort();// 终止当前连接并重置套接字
    connectToHost(QHostAddress(address), port);
}
// 重新连接
void AdSocket::conAgain(QAbstractSocket::SocketError error)
{
    qDebug()<<"连接失败:"<<error;
    readMsgType=MsgType::Init;
    abort();// 终止当前连接并重置套接字

    if(error==QAbstractSocket::ConnectionRefusedError)
    {
        connectToHost(QHostAddress(address), port);
    }
}

weather.h 天气信息处理

#ifndef WEATHER_H
#define WEATHER_H

#include <QObject>
#include <QLabel>
#include <QDebug>
class Weather : public QObject
{
    Q_OBJECT
public:
    explicit Weather( QLabel *_label,QObject *parent = 0);

signals:

public slots:
    void showWeather(QString city,QString area,QString weather);

private:
    QLabel *label;
    QString _city;
    QString _area;
};

#endif // WEATHER_H

weather.cpp 天气信息处理

#include "weather.h"

Weather::Weather( QLabel *_label, QObject *parent) :
    QObject(parent)
{
    label = _label;
}

void Weather::showWeather(QString city,QString area,QString weather)
{
    _city=city;
    qDebug()<<"城市:"<<_city;
    _area=area;
    qDebug()<<"地区:"<<_area;
    weather="\t\t"+_city+"\t"+_area+"\n\t"+weather;
    label->setText(weather);
}

rollmassege.h 滚动信息处理

#ifndef ROLLMASSEGE_H
#define ROLLMASSEGE_H

#include <QLabel>
#include <QEvent>
#include <QTimer>
#include <QRect>
#include <QPainter>
#include <QFont>

class RollMassege : public QLabel
{
    Q_OBJECT
public:
    explicit RollMassege(QWidget *parent = 0);
    explicit RollMassege(QLabel *_label, QWidget *parent = 0);

    void paintEvent(QPaintEvent *event);
signals:

public slots:
    void updateMsg();
    void showTxt(QString tcp_Txt);
private:
    QString txt;
    QRect rect;
    int offset;//偏移量
    QTimer *timer;
};

#endif // ROLLMASSEGE_H

rollmassege.cpp 滚动信息处理

#include "rollmassege.h"
#include <QDebug>

RollMassege::RollMassege(QWidget *parent) :
    QLabel(parent)
{
}

RollMassege::RollMassege(QLabel *_label, QWidget *parent) :
    QLabel(parent)
{
    rect = _label->geometry();
    rect.setWidth(798);
    rect.setHeight(80);
    setGeometry(rect);
    show();
    qDebug()<<rect.width()<<" "<<rect.height();

    offset = rect.width();//偏移量
    txt = "暂无信息";
    timer = new QTimer;
    connect(timer, SIGNAL(timeout()), this, SLOT(updateMsg()));
    timer->start(50);
}
// 绘画事件
void RollMassege::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event); //忽略编译器发出的警告,表明变量event未使用
    QPainter painter(this);
    QFont font;
    font.setPointSize(16);
    painter.setFont(font);
    painter.drawText(rect.x()+offset, rect.y()+30, txt);// 绘制文字,x+偏移量
}


void RollMassege::updateMsg()
{
    offset--;
    if(offset<0) offset = rect.width();
    update();// 刷新,触发绘画事件paintEvent
}

void RollMassege::showTxt(QString tcp_Txt)
{
    txt =tcp_Txt;
    update();
}

效果

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/393764.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DCC数字管护生命周期模型解读

实话说&#xff0c;对于Digital Curation笔者真心不知道应该怎么翻译。本文借用了钱毅老师的观点&#xff0c;姑且翻译成“数字管护”&#xff0c;详见《从保护到管护&#xff1a;对象变迁视角下的档案保管思想演变》&#xff08;《档案学通讯》&#xff0c;2022年第2期&#x…

数据库基本功之SQL的数据类型

1.四种基本的常用数据类型 1.1 字符型 char # 固定字符,最长2000个 varchar2 # 可变长字符,最长4000个,最小值是1 nchar/nvarchar2 # 类型的列使用国家字符集 raw & long raw # 固定/可变长度的二进制数据长度 最2G,可存放多媒体图象声音等.(老类型,逐步淘汰) LONG …

浅谈CSRF跨域读取型漏洞之JSONP劫持

目录 前提知识 CSRF JSONP jsonp漏洞 原理 过程 复现 漏洞挖掘思路 漏洞防御 前提知识 CSRF 提起CSRF&#xff0c;可能很多人都会想到修改个人资料、授权登陆等攻击场景&#xff0c;可以发现这两个场景都是写入型的CSRF漏洞&#xff0c;通常会忽视更常见的读取型的CS…

MP与IP-Trunk技术讲解

目录 PPP MP技术 将PPP链路直接绑定到VT上实现MP 按照PPP链路用户名查找VT实现MP IP-Trunk技术 PPP MP技术 MP&#xff08;MultiLink PPP&#xff09;将多个PPP链路捆绑使用的技术&#xff08;Serial接口、POS接口等&#xff09; 实现方式 可以采用虚拟VT接口实现MP PPP链路…

通过canvas画出爱心图案,表达你的爱意!

通过canvas画出爱心图案&#xff0c;浏览器可以使用以下js代码&#xff0c;新建对象时&#xff0c;会自动呈现动画效果&#xff0c;代码文末可下载。 点击免费下载源码 let HeartCanvas new HeartCanvas() /*** 爱心* Heart Canvas*/class HeartCanvas {/*** param hMin 颜…

怎么恢复本地磁盘里的数据?电脑本地磁盘数据恢复7种方案

演示机型&#xff1a;技嘉 H310M HD22.0系统版本&#xff1a;Windows 10 专业版软件版本&#xff1a;云骑士数据恢复软件3.21.0.17本地磁盘是什么意思&#xff1f;所谓的本地磁盘是指安装在电脑主板上&#xff0c;不能随便拔插的硬盘&#xff0c;通俗易懂的讲就是电脑内部安装的…

Spring Cloud融合gateway构建的API网关服务 | Spring Cloud 12

一、Spring Cloud Gateway 1.1 概述 所谓的网关就是指系统的统一入口&#xff0c;它封装了运用程序的内部结构&#xff0c;为客户端提供统一的服务&#xff0c;一些与业务功能无关的公共逻辑可以在这里实现&#xff0c;诸如认证、鉴权、监控、路由转发等。 Spring Cloud Gat…

北斗导航 | PPP-RTK:CLASLIB 0.7.2 版本中文手册(CLASLIB ver. 0.7.2 Manual)

===================================================== github:https://github.com/MichaelBeechan CSDN:https://blog.csdn.net/u011344545 ===================================================== CLASLIB ver. 0.7.2 Manual

Hevc变换系数扫描

量化后变换系数的熵编码在整个熵编码中占有举足轻重的地位&#xff0c;由于量化后变换系数大多为零值或者幅度较小的值&#xff0c;如何有效利用这一特性是熵编码的关键环节&#xff0c;H265/HEVC标准中&#xff0c;亮度数据和色度数据均以变换块TB为单位&#xff0c;通过编码非…

Compose 动画 (四) : AnimatedVisibility 各种入场和出场动画效果

AnimatedVisibility中的EnterTransition 和 ExitTransition &#xff0c;用来配置入场/出场时候的动画效果。 默认的入场效果是 fadeIn() expandVertically() 默认的出场效果是 fadeOut() shrinkVertically() 1. EnterTransition和ExitTransition支持的动画 enter的参数类…

【VUE】vue3.0后台常用模板

vue3.0后台常用模板&#xff1a; 1、vue-admin-perfect 在线预览 gitee国内访问地址&#xff1a;https://yuanzbz.gitee.io/vue-admin-perfect/#/home github site : https://zouzhibin.github.io/vue-admin-perfect/ 基础功能版本预览&#xff1a;https://yuanzbz.gitee.io/…

上海亚商投顾:沪指失守3300点 两市上涨股不足500只

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。市场情绪沪指今日冲高回落&#xff0c;午后跌幅扩大至1%&#xff0c;失守3300点关口&#xff0c;深成指、创业板指跌近2%。通…

Springboot 定时任务注入FeignClient

问题引入: 在springboot 项目写了个定时任务,里面有段代码通过Feign 调用远程服务,发现通过接口调用可以程序正常执行, 通过配置定时任务发现定时任务没执行,看日志是报了NP.问题跟踪: 写了个demo 重现以上错误:Api(tags "XXX控制器") RestController RequestMapp…

认识代码之前,请先认识你自己 |《编程人生》

这是我的湛庐课程《给技术人的职场突围课》 &#xff08;链接&#xff09; 的一部分。 这篇文章也是 IT 女神征文活动 的一部分。 《编程人生》是一本优秀程序员的采访集&#xff0c;里面记录了15位世界级编程大师的故事。 我在 发刊词 里面说过&#xff0c;在这个书单课里&am…

如何有效地降低软件开发风险?

1、科学分析风险 高风险自动预警 一般对风险进行科学分析&#xff0c;主要从3个维度进行划分&#xff1a;影响的严重性、发生的可能性、产生的影响性。 根据风险对项目的影响程度&#xff0c;从3个维度将其划分5个等级&#xff1a;很低、比较低、中等、比较高、很高。这样我们能…

react router零基础使用教程

安装既然学习 react router 就免不了运行 react安装 reactnpx create-react-app my-appcd my-appnpm start安装 react routernpm install react-router-dom如果一切正常&#xff0c;就让我们打开 index.js 文件。配置路由引入 react-router-dom 的 RouterProviderimport {Route…

JavaWeb--Filter

Filter1 Filter概述2 Filter快速入门2.1 开发步骤2.2 代码演示3 Filter执行流程4 Filter拦截路径配置5 过滤器链5.1 概述5.2 代码演示5.3 问题6 案例6.1 需求6.2 分析6.3 代码实现6.3.1 创建Filter6.3.2 编写逻辑代码6.3.3 测试并抛出问题6.3.4 问题分析及解决6.3.5 过滤器完整…

智慧供热|供热末端(住户)管网远程监测方案

智慧供热通过对供热相关数据的采集、分析和对热源、热网、末端&#xff08;住户&#xff09;的各个供热环节进行智能调控&#xff0c;从而进一步实现热网资源的配置优化&#xff0c;提高热网输送的能力。供热行业存在问题&#xff1a;供热企业目前面临的主要问题还是资金周转困…

MYSQL1

MySQL基本11、MySQL 中有哪几种锁&#xff1f;2、MySQL 中有哪些不同的表格&#xff1f;2、什么是存储引擎3、MySQL 中 InnoDB 支持的四种事务隔离级别名称&#xff0c;以及逐级之间的区别4、CHAR 和 VARCHAR 的区别1、固定长度 & 可变长度2、存储方式3、存储容量4、CHAR会…

cookie session Token终极理解

左边 浏览器 右边 服务器 浏览器发送请求 服务器接收请求 并生成cookie 浏览器查看保存了哪些cookie 用户名密码放在cookie是很不安全的 因为浏览器一旦被攻击泄露 是很危险的 接着诞生了session 会话 sessionID &#xff08;一段杂乱的字母标识&#xff09; 会话结束时间 …