分类

课内:
不限
类型:
不限 游戏 项目 竞赛 个人研究 其他
评分:
不限 10 9 8 7 6 5 4 3 2 1
年份:
不限 2018 2019 2020 2021

资源列表

  • 基于Java实现的多用户同步MarkDown编辑器

    一、功能简介
    1.1 离线功能支持本地文件导入、保存,导出HTML、Word文档,添加CSS样式、导入外部CSS文件,大文件处理。如果用户一直输入,没有停下超过1秒,右边的HTML视图就不会更新,这样可以减少无用的计算。左侧的导航栏用树形结构表示,点击标题可以跳转到对应行。

    1.2 在线编辑模拟多人在线编辑的效果,可以用IDE运行多个当前程序,除了第一个正常,之后的会提示无法创建本地服务器等等好几个错误,这是正常的,因为服务器已经由第一个进程创建,之后的就不能再次创建。忽略即可。

    如图,运行3个进程。

    每一个都注册。然后让一个人创建一个房间,另外两个加入进去。

    他们三个现在在0号房间内,并且用户“大王”是房间主。目前设计的模式是只有房间主人可以进行文本的修改,其他成员无权修改。

    二、技术实现2.1 Markdown解析2.1.1 Markdown导出主要用了开源的markdown4j包。
    2.1.2 实时显示为了减少不必要的计算,这里用线程阻塞的方式,结合SwingUtilities.InvokeLater()实现高效地更新。每次,想要更新的线程先sleep 1000毫秒,如果之后又有想要更新的线程,就将上一个阻塞,这样的话上一个就直接返回,放弃更新的操作。这样的效果就是,只要持续输入或删除内容,对文本内容做出改变的间隔不超过1秒钟,就一直不会更新,当用户停止1秒后,才会执行更新操作。大大减少了无用的计算。
    private void updateUIEfficiently() { new Thread(() -> { Thread last = lastThread; lastThread = Thread.currentThread(); try { //阻塞上一个更新的线程 if(last != null) { last.interrupt(); } Thread.sleep(1000); } catch(InterruptedException exc) { return; } if(Thread.currentThread().isInterrupted()) return; SwingUtilities.invokeLater(() -> {update();}); if(mIsHost) { String updation = mTextArea.getText(); try { mClient.disposeRequest(RequestType.UPLOAD_UPDATION, updation); } catch (Exception e) { e.printStackTrace(); Utility.error("与服务器端连接出现错误!"); } } }).start();}
    2.1.3 导航栏用了JTree,生成关于目录的树状结构,并对每个节点添加点击事件。
    2.2 Socket编程创建一个本地服务器,开放2个端口,8080和8081。总共创建了2个类Server和Client。Server处理客户端发来的所有请求,并返回回复;Client用于在客户端帮助用户发送所有请求。工程建立在C/S架构上。
    所有客户端一旦试图进行登录或注册,就会创建一个Client,并建立相应的端口进行通信。服务器也会新开一个线程对这个客户端进行服务。客户端进行的一切操作都是在向服务器发送请求,然后得到服务器的回复。当客户端退出登录或是退出程序,就断开连接的端口,释放资源,防止内存浪费。
    一旦一个用户创建或是加入了一个房间,那么服务器就必须通过另一个端口——8081,来进行房间内内容的更新等操作。所以加入房间后,客户端会试图连接服务器的8081端口。对应的服务器上8081端口专门有一个线程来进行处理,依然是每有一个客户端连接过来就新开一个线程进行服务。这个端口做的事就是专门把房间主人发过来的文本内容发送给房间其他所有成员让他们进行同步。所以,每个客户端也必须开一个线程,不断尝试从对应8081端口的socket读取内容,然后更新。
    关于请求的类型定义在RequestType.java中:
    /** * 向服务器提交请求,请求格式为:[请求类型]#[参数列表(中间用#隔开)] * @param request*/public void disposeRequest(RequestType type, String ... args) throws Exception { //传输请求 switch (type) { case LOGIN: disposeLogin(type, args[0], args[1]); break; //注册和登录在客户端的处理不区分 case REGISTER: disposeLogin(type, args[0], args[1]); break; case CUT_CONNECT: disposeCut(type); break; case CREATE_ROOM: disposeCreateRoom(type); break; case JOIN_ROOM: disposeJoinRoom(type, args[0]); break; case UPLOAD_UPDATION: disposeUpdation(type, args[0]); break; default: break; }}
    一共定义了这么几种类型。同样,服务器端也根据某些特征判断发来的请求是什么类型的,然后执行相应的处理方法。
    目前设计的模式是只有房间主人可以对文本内容进行更改。由于时间有限,没有添加申请成为房间主人的功能,不过这个只不过是在RequestType中加入了一个新的请求。
    1 评论 6 下载 2019-10-17 07:31:01 下载需要12点积分
  • 《WINDOWS黑客编程技术详解》配套资源下载

    《WINDOWS黑客编程技术详解》是一本面向黑客编程初学者的书,较为全面的地总结黑客编程技术。其内容重在实践,着重剖析技术实现原理,向读者讲解黑客编程技术的实现方法。
    本书介绍的是些黑客编程的基础技术,涉及用户层下的Windows编程和内核层下的Rootkit编程。全书分为用户篇和内核篇两部分,用户篇包括11章,配套49个示例程序源码;内核篇包括7章,配套28个示例程序源码。本书每个技术都有详细的实现原理分析,以及对应的示例代码(配套代码均支持32位和64位Windows 7、Windows 8.1及Windows 10系统),帮助初学者建立起黑客编程技术的基础技能。
    本书面向对计算机系统安全开发感兴趣,或者希望提升安全开发水平的读者,以及恶意代码分析研究方面的安全人员。
    购书方式
    淘宝、天猫、京东等各大电商网站均有纸质书和电子书销售,请搜索 “WINDOWS黑客编程技术详解”。
    当当:http://product.dangdang.com/25859838.html
    京东:https://item.jd.com/12464379.html
    天猫:https://detail.tmall.com/item.htm?spm=a230r.1.14.76.cb1940a5YFnLgL&id=582626540408&ns=1&abbucket=18
    书籍封面

    目录

    第1篇 用户篇

    第1章 开发环境

    1.1 环境安装1.2 工程项目设置1.3 关于Debug模式和Release模式的小提示
    第2章 基础技术

    2.1 运行单一实例2.2 DLL延时加载2.3 资源释放
    第3章 注入技术

    3.1 全局钩子注入3.2 远线程注入3.3 突破SESSION 0隔离的远线程注入3.4 APC注入
    第4章 启动技术

    4.1 创建进程API4.2 突破SESSION 0隔离创建用户进程4.3内存直接加载运行
    第5章 自启动技术

    5.1 注册表5.2 快速启动目录5.3 计划任务5.4 系统服务
    第6章 提权技术

    6.1 进程访问令牌权限提升6.2 Bypass UAC
    第7章 隐藏技术

    7.1 进程伪装7.2傀儡进程7.3 进程隐藏7.4 DLL劫持
    第8章 压缩技术

    8.1 数据压缩API8.2 ZLIB压缩库
    第9章 加密技术

    9.1 Windows自带的加密库9.2 Crypto++密码库
    第10章 传输技术

    10.1 Socket通信10.2 FTP通信10.3 HTTP通信10.4 HTTPS通信
    第11章 功能技术

    11.1 进程遍历11.2 文件遍历11.3 桌面截屏11.4 按键记录11.5 远程CMD11.6 U盘监控11.7 文件监控11.8 自删除

    第2篇 内核篇

    第12章 开发环境

    12.1 环境安装12.2 驱动程序开发与调试12.3 驱动无源码调试12.4 32位和64位驱动开发
    第13章 文件管理技术

    13.1 文件管理之内核API13.2 文件管理之IRP13.3 文件管理之NTFS解析
    第14章 注册表管理技术

    14.1 注册表管理之内核API14.2 注册表管理之HIVE文件解析
    第15章 HOOK技术

    15.1 SSDT Hook15.2过滤驱动
    第16章 监控技术

    16.1 进程创建监控16.2 模块加载监控16.3 注册表监控16.4 对象监控16.5 Minifilter文件监控16.6 WFP网络监控
    第17章 反监控技术

    17.1 反进程创建监控17.2 反线程创建监控17.3 反模块加载监控17.4 反注册表监控17.5 反对象监控17.6 反Minifilter文件监控
    第18章 功能技术

    18.1 过PatchGuard的驱动隐藏18.2 过PatchGuard的进程隐藏18.3 TDI网络通信18.4 强制结束进程18.5 文件保护18.6 文件强删

    附录 函数一览表

    PS:源码下载可以直接点击下述附件下载,也可以到 github 和人民邮电出版社-异步社区上面下载:
    https://github.com/BigGan/Windows-Hack-Programming
    https://www.epubit.com/bookDetails?id=N39391
    PS:若对书中内容有疑惑或者发现错误,可以直接戳下面的勘误收集链接哦
    https://www.write-bug.com/article/1966.html
    19 评论 567 下载 2018-11-26 11:48:29
  • 基于VC++的画图板程序

    1. 概述1.1 简介使用VC开发平台,MFC框架实现一个画图程序,尽可能多的实现Windows自带的画图功能,并扩展其功能。
    1.2 功能需求1.2.1 基本绘图功能
    能够用鼠标操控方式,绘制直线、矩形、椭圆。
    在绘图时,选择绘制某种图像后(如直线),在画布中按住鼠标左键后移动鼠标,在画布中实时的根据鼠标的移动显示相应的图形。在松开鼠标左键后,一次绘图操作完成。
    能够在绘制一图形(如一条直线)前设置线的粗细、颜色。(以菜单方式)
    可以以矢量图方式保存绘制的图形。
    可以读取保存的矢量图形文件,并显示绘图的结果。

    界面友好的要求:

    有画直线、矩形、椭圆的工具箱。
    有颜色选择工具箱。
    对于当前选中的绘图工具,以“下沉”的形式显示。
    在状态栏中显示鼠标的位置。
    在鼠标移向一工具不动时,有工具的功能提示。
    在菜单上有当前选中的菜单项标识(即前面有小钩)
    可以用鼠标操作方式,通过“拖拽”方式,改变画布的大小。
    在画布大而外框小时,应有水平或垂直方向的滚动条。

    1.2.2 高级编辑功能
    具有Undo功能。
    可以用鼠标选中绘制的某一图形。被选中的图形符号有标识(参见Word,如一直线段,其两端点上加了两个小框;矩形上有8个小框点)。
    当鼠标靠近某一目标时,鼠标的形状发生改变
    修改被选中的图形。通过鼠标的“拖拽”,可以改变图形的位置、或大小。
    修改被选中图形的颜色、笔划的粗细。
    删除被选中的图形。
    可以使用鼠标“拖拽”一个虚矩形框,一次选择多个图形。
    可以使用 Ctrl 或Shift加鼠标左键选择多个图形对象。

    1.2.3 附加功能
    可选择打开或关闭工具栏。
    应用程序的标题栏上有程序的图标。
    将图形转换成位图文件的形式保存。
    在选择一个图形元素后(如直线),会有进一步选择线型或线宽的界面。
    仿Word,选择“线型”、“粗细”图标后,会出现进一步选择的选项卡。
    2.主要功能描述

    右键修改选中图形的颜色,粗细,线型,删除选中图形

    右键和鼠标调整图形

    对话框矢量修改所有图形

    3. 技术细节3.1 代码结构3.1.1 代码文件MFC自动生成的文件1个CHDrawPView1个HStroke2个Dialog(HStrokeEditDlg+HStrokeTextDlg)1个ToolBar(HColorBar)
    3.1.2 代码类HDrawPView文件只有一个类:CHDrawPView,该类集成自MFC的CScrollView,主要实现维护画布类CHDrawView和滚动功能。
    HStroke文件里包含目前所有的图形类信息,包括集成与MFC的CObject类的基类HStroke,以及集成自HStroke的具体图形类HStrokeLine(直线),HStrokeRect(矩形),HStrokeEllipse(椭圆),HStrokeText(文本),HStrokePoly(曲线)。
    HStrokeEditDlg文件只有一个类:HStrokeEditDlg,该类集成自MFC的CDialog类,主要用来编辑已有图形类,如下图所示:

    HStrokeTextDlg文件只有一个类:HStrokeTextDlg,该类集成自MFC的CDialog类,主要用来画文本时输入文本信息,如图所示:

    HColorBar类只有一个类:HColorBar类,该类集成自MFC的CToolBar类,呈现一个颜色框,方便用户在绘图时选择不同的颜色。
    3.2 SetROP2实现重绘在画图状态下,鼠标移动时既要擦除旧图形,又要绘制新图形。这里主要有两种实现方法:一是全部重绘,二是先擦除旧图形。
    如果使用矢量图全部重绘,频繁的绘图动作消耗很大,很容易造成屏幕闪动。但是如果将已有图形保存为位图,然后重绘的时候只要绘制位图即可,这样能避免闪动。第二种方法要考虑的就是擦除旧图形的问题,本程序使用SetROP2函数设置MASK的方式,每次绘图时采用非异或运算的方式擦除旧图形:
    pDC->SetROP2(R2_NOTXORPEN); //设置ROP2 DrawStroke(pDC); //画图擦除旧线(自定义函数) SetCurrentPoint(point); //设置新点的坐标(自定义函数) DrawStroke(pDC); //画新线(自定义函数)
    3.3 嵌套View实现画布 m_drawView = new CHDrawView();//创建画布View if (!m_drawView->CreateEx(WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR, AfxRegisterWndClass(CS_VREDRAW | CS_HREDRAW,LoadCursor(NULL,IDC_CROSS), (HBRUSH)GetStockObject(WHITE_BRUSH),NULL),///白色画布 "",WS_CHILDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, m_tracker.m_rect.left,m_tracker.m_rect.top, m_tracker.m_rect.right-1,m_tracker.m_rect.bottom-1, this->m_hWnd,NULL)){ TRACE0("Failed to create toolbar\n"); return -1; // fail to create } m_drawView->SetDocument((CHDrawDoc*)m_pDocument);//传递CDocument给新View m_drawView->ShowWindow(SW_NORMAL); m_drawView->UpdateWindow(); //设置背景View颜色为灰色 SetClassLong(m_hWnd,GCL_HBRBACKGROUND,(long)GetStockObject(GRAY_BRUSH));
    3.4 鼠标靠近目标时突出显示在鼠标移动的时候,OnMouseMove函数会遍历已有图形,判断鼠标所在点是否属于已有图形范围,如果是,则高亮显示该图形。
    高亮显示的方法比较简单,只要增加CRectTracker即可,而判断当前点是否属于某图形比较有意思:
    3.4.1 判断一点是否属于矩形HStrokeRect使用用MFC的CRect类的IsPointIn方法,当鼠标在矩形边框附近时,认为该点属于HStrokeRect。如图,实线矩形表示HStrokeRect。外矩形为外面的虚线矩形,内矩形为里面的虚线矩形:

    BOOL HStrokeRect::IsPointIn(const CPoint &point){ //矩形左上角x坐标 int x1 = m_points.GetAt(0).x < m_points.GetAt(1).x ? m_points.GetAt(0).x : m_points.GetAt(1).x; //矩形左上角y坐标 int y1 = m_points.GetAt(0).y < m_points.GetAt(1).y ? m_points.GetAt(0).y : m_points.GetAt(1).y; //矩形右下角x坐标 int x2 = m_points.GetAt(0).x > m_points.GetAt(1).x ? m_points.GetAt(0).x : m_points.GetAt(1).x; //矩形右下角y坐标 int y2 = m_points.GetAt(0).y > m_points.GetAt(1).y ? m_points.GetAt(0).y : m_points.GetAt(1).y; //构建外矩行和内矩形 CRect rect(x1,y1,x2,y2), rect2(x1+5,y1+5,x2-5,y2-5); //如果在外矩形内并在内矩形外 if(rect.PtInRect(point) && !rect2.PtInRect(point)) return TRUE; else return FALSE;}
    3.4.2 判断一点是否属于线段首先判断一点是否属于这条线段所属的直线,根据直线的判定公式y1/x1 = y2/x2得到x1y2-x2y1=0,但是在画图中应该在直线附近就能选中,所以在本程序中:|x1y2-x2y1| < 偏差,然后判断该点是否属于这条线段。
    //计算该点到线段HStrokeLine的两个顶点的线段(x1,y1), (x2,y2) int x1 = point.x - m_points.GetAt(0).x; int x2 = point.x - m_points.GetAt(1).x; int y1 = point.y - m_points.GetAt(0).y; int y2 = point.y - m_points.GetAt(1).y; //计算判断量x1*y2 - x2*y1 int measure = x1*y2 - x2*y1; //误差允许范围,也就是直线的“附近” int rule = abs(m_points.GetAt(1).x - m_points.GetAt(0).x) +abs(m_points.GetAt(0).y - m_points.GetAt(1).y); rule *= m_penWidth;//将线宽考虑进去 //属于直线 if(measure < rule && measure > -rule){ //判断该点是否属于这条线段 if(x1 * x2 < 0) return TRUE;; } return FALSE;
    3.4.3 判断一点是否属于椭圆根据椭圆的定义椭圆上的点到椭圆的两个焦点的距离之和为2a,首先计算出椭圆的a, b, c,然后计算出椭圆的两个焦点。
    针对某个点,首先根据点坐标和两个焦点的坐标计算出该点到椭圆焦点的距离,然后减去2a,如果在“附近”,则认为其属于HStrokeEllipse,否则不属于。
    //计算椭圆的a, b, c int _2a = abs(m_points.GetAt(0).x - m_points.GetAt(1).x); int _2b = abs(m_points.GetAt(0).y - m_points.GetAt(1).y); double c = sqrt(abs(_2a*_2a - _2b*_2b))/2; //计算椭圆的焦点 double x1,y1,x2,y2; if(_2a > _2b){//横椭圆 x1 = (double)(m_points.GetAt(0).x + m_points.GetAt(1).x)/2 - c; x2 = x1 + 2*c; y1 = y2 = (m_points.GetAt(0).y + m_points.GetAt(1).y)/2; } else{//纵椭圆 _2a = _2b; x1 = x2 = (m_points.GetAt(0).x + m_points.GetAt(1).x)/2; y1 = (m_points.GetAt(0).y + m_points.GetAt(1).y)/2 - c; y2 = y1 + 2*c; } //点到两个焦点的距离之和,再减去2a //distance(point - p1) + distance(point - p2) = 2*a; double measure = sqrt((x1 - point.x)*(x1-point.x) + (y1 - point.y)*(y1-point.y) ) + sqrt( (point.x - x2)*(point.x - x2) + (point.y - y2)*(point.y - y2)) - _2a; //计算椭圆的“附近” double rule = 4*m_penWidth; if(measure < rule && measure > -rule) return TRUE; else return FALSE;
    3.5 文档序列化MFC提供了良好的序列化机制,只要在类定义时加入DECLARE_SERIAL宏,在类构造函数的实现前加入IMPLEMENT_SERIAL宏,然后实现Serialize方法即可。本程序即使用该方法序列化:首先在CHDrawDoc类实现Serialize方法,保存画布大小和所有图形信息:
    void CHDrawDoc::Serialize(CArchive& ar){ if (ar.IsStoring()) { //保存时,首先保存画布高和宽,然后序列化所有图形 ar<<m_cavasH<<m_cavasW; m_strokeList.Serialize(ar); } else { //打开时,首先打开画布高和宽,然后打开所有图形 ar>>m_cavasH>>m_cavasW; m_strokeList.Serialize(ar); }}
    m_strokeList.Serialize(ar);这一句很神奇,Debug追踪的时候会发现,容器类会自动序列化容器内的元素数量,并调用每个元素的序列化方法序列化,所以还需要对每个图形元素实现序列化,以HStrokeLine为例:在HStrokeLine的类声明中:
    class HStrokeLine : public HStroke {public: HStrokeLine(); DECLARE_SERIAL(HStrokeLine)
    然后在HStrokeLine的构造函数实现前:
    IMPLEMENT_SERIAL(HStrokeLine, CObject, 1)HStrokeLine::HStrokeLine(){ m_picType = PIC_line;}
    最后实现HStrokeLine的序列化函数,因为这里HStrokeLine集成自HStroke类而且没有特殊的属性,而HStroke类实现了Serialize函数,所以HStrokeLine类不需要实现Serilize方法,看一下HStroke的Serialize方法即可:
    void HStroke::Serialize(CArchive& ar){ if(ar.IsStoring()){ int enumIndex = m_picType; ar<<enumIndex<<m_penWidth<<m_penColor; m_points.Serialize(ar); } else{ int enumIndex; ar>>enumIndex>>m_penWidth>>m_penColor; m_picType = (enum HPicType)enumIndex; m_points.Serialize(ar); }}
    3.6 打开保存导出文档序列化实现以后,程序的打开和保存功能就已经完成了。但是从序列化方法可以看出,打开和保存的都是矢量图形,所以这里实现了一个导出为BMP图像的方法,导出:
    //保存文件对话框,选择导出路径 CFileDialog dlg(FALSE, "bmp","hjz.bmp"); if(dlg.DoModal() != IDOK){ return ; } CString filePath = dlg.GetPathName(); // CClientDC client(this);//用于本控件的,楼主可以不用此句 CDC cdc; CBitmap bitmap; RECT rect;CRect r; GetClientRect(&rect); int cx = rect.right - rect.left; int cy = rect.bottom - rect.top; bitmap.CreateCompatibleBitmap(&client, cx, cy); cdc.CreateCompatibleDC(NULL); //获取BMP对象 CBitmap * oldbitmap = (CBitmap* ) cdc.SelectObject(&bitmap); //白色画布 cdc.FillRect(&rect, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH))); //画图 for(int i = 0; i < GetDocument()->m_strokeList.GetSize(); i ++){ GetDocument()->m_strokeList.GetAt(i)->DrawStroke(&cdc); } cdc.SelectObject(oldbitmap); ::OpenClipboard(this->m_hWnd); ::EmptyClipboard(); ::SetClipboardData(CF_BITMAP, bitmap); ::CloseClipboard(); HBITMAP hBitmap = (HBITMAP)bitmap; HDC hDC; int iBits; WORD wBitCount; DWORD dwPaletteSize=0, dwBmBitsSize=0, dwDIBSize=0, dwWritten=0; BITMAP Bitmap; BITMAPFILEHEADER bmfHdr; BITMAPINFOHEADER bi; LPBITMAPINFOHEADER lpbi; HANDLE fh, hDib, hPal,hOldPal=NULL; hDC = CreateDC("DISPLAY", NULL, NULL, NULL); iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES); DeleteDC(hDC); if (iBits <= 1) wBitCount = 1; else if (iBits <= 4) wBitCount = 4; else if (iBits <= 8) wBitCount = 8; else wBitCount = 24; GetObject(hBitmap, sizeof(Bitmap), (LPSTR)&Bitmap); bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = Bitmap.bmWidth; bi.biHeight = Bitmap.bmHeight; bi.biPlanes = 1; bi.biBitCount = wBitCount; bi.biCompression = BI_RGB; bi.biSizeImage = 0; bi.biXPelsPerMeter = 0; bi.biYPelsPerMeter = 0; bi.biClrImportant = 0; bi.biClrUsed = 0; dwBmBitsSize = ((Bitmap.bmWidth * wBitCount + 31) / 32) * 4 * Bitmap.bmHeight; hDib = GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER)); lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib); *lpbi = bi; hPal = GetStockObject(DEFAULT_PALETTE); if (hPal) { hDC = ::GetDC(NULL); hOldPal = ::SelectPalette(hDC, (HPALETTE)hPal, FALSE); RealizePalette(hDC); } GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER) +dwPaletteSize, (BITMAPINFO *)lpbi, DIB_RGB_COLORS); if (hOldPal) { ::SelectPalette(hDC, (HPALETTE)hOldPal, TRUE); RealizePalette(hDC); ::ReleaseDC(NULL, hDC); } fh = CreateFile(filePath, GENERIC_WRITE,0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (fh == INVALID_HANDLE_VALUE) return ; bmfHdr.bfType = 0x4D42; // "BM" dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize; bmfHdr.bfSize = dwDIBSize; bmfHdr.bfReserved1 = 0; bmfHdr.bfReserved2 = 0; bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize; WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL); WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL); GlobalUnlock(hDib); GlobalFree(hDib); CloseHandle(fh);
    3.7 友好用户界面菜单项选中和工具栏图标下沉。该功能的实现非常简单,而且用户体验很好,以当前所画的图形为例:第一步:增加3个菜单项名称 ID直线 ID_DRAW_LINE椭圆 ID_DRAW_ELLIPSE矩形 ID_DRAW_RECT第二步:在工具栏上增加3个工具栏项,注意ID要和上面的三个ID相同。第三步:在CHDrawDoc类的ClassWizard中增加消息响应函数,分别为以上三个ID增加COMMAND和UPDATE_COMMAND_UI的Handler,COMMAND的Handler就是针对按下工具栏按钮或菜单项的响应函数,而UPDATE_COMMAND_UI则是显示菜单栏时执行的操作,有点类似OnDraw。以直线为例,ID_DRAW_LINE的COMMAND的Handler为OnDrawLine
    void CHDrawDoc::OnDrawLine() { //设置当前画图的图形类型为直线 m_picType = PIC_line;}ID_DRAW_LINE的UPDATE_COMMAND_UI的Handler为OnUpdateDrawLine:void CHDrawDoc::OnUpdateDrawLine(CCmdUI* pCmdUI) { //如果当前画图类型为直线,设置菜单项前加对号,工具栏项下沉 pCmdUI->SetCheck(PIC_line == m_picType);}
    3.8 右键菜单修改选中图形的属性实现方法如下:第一步:在资源视图中增加一个菜单第二步:在CHDrawView中增加右键菜单响应函数OnRButtonDown:
    void CHDrawView::OnRButtonDown(UINT nFlags, CPoint point) { //检查所有处于选中状态的图形,可以有多个 CHDrawDoc *pDoc = GetDocument(); m_strokeSelected.RemoveAll();//首先清空旧数据 for(int i = 0; i < pDoc->m_strokeList.GetSize(); i ++){ if(pDoc->m_strokeList.GetAt(i)->IsHightLight()) m_strokeSelected.Add(pDoc->m_strokeList.GetAt(i)); } //显示右键菜单 CMenu rmenu; rmenu.LoadMenu(IDR_MENU_SET);//加载资源中的菜单IDR_MENU_SET ClientToScreen(&point);//需要坐标转换 rmenu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN, point.x, point.y, this); //因为这里的rmenu是局部变量,所以必须Detach掉 rmenu.Detach(); CView::OnRButtonDown(nFlags, point);}
    第三步:增加菜单响应函数,这里以删除当前所选图形为例:
    void CHDrawView::OnPicDelete() { //获取存储数据的文档类 CHDrawDoc *pDoc = GetDocument(); //移除所有处于选中状态的图形 int i = 0, j = 0; for(; i < m_strokeSelected.GetSize(); i ++){ //这里的j没有归0,是有原因的,可以很有效的提高效率 //遍历复杂度为两个数组的和 for(; j < pDoc->m_strokeList.GetSize(); j ++){ if(m_strokeSelected.GetAt(i) == pDoc->m_strokeList.GetAt(j)){ delete pDoc->m_strokeList.GetAt(j); pDoc->m_strokeList.RemoveAt(j); break; } } } //如果没有处于选中状态的图形,则不需要刷新。 if(i > 0) Invalidate();}
    3.9 撤销和恢复操作MFC提供了默认的撤销和恢复的ID,但是并没有提供默认实现,本程序的思路是,定义一个数组和一个数组索引,每执行一个操作,就把当前状态存储到数组中,并把数组索引加1。撤销时,把索引减一的数组元素恢复到当前文档,恢复时,把索引加一的数组元素恢复到当前文档。在程序中的步骤为:第一步:定义数组,数组索引和备份,恢复函数:
    CObArray m_backup; int m_backup_index; void ReStore(BOOL backward); void BackUp();void CHDrawDoc::BackUp(){ //备份操作,有利有弊。简单,节省内存,序列化有变时不需修改;产生文件占据磁盘 CString fileName; fileName.Format("hjz%d", m_backup.GetSize()); OnSaveDocument(fileName); //这里使用Insert而不是Add是因为恢复是并没有删除 m_backup.InsertAt(m_backup_index++, NULL, 1);}void CHDrawDoc::ReStore(BOOL backward){ m_backup_index -= backward ? 1 : -1;//撤销还是恢复 //…把数组元素恢复到当前文档 OnOpenDocument(m_backup.GetAt(m_backup_index-1));}
    第二步:添加撤销和恢复菜单项,并添加消息句柄:
    void CHDrawDoc::OnEditUndo() { ReStore(TRUE); UpdateAllViews(NULL);}void CHDrawDoc::OnEditRedo() { ReStore(FALSE); UpdateAllViews(NULL);}
    第三步:在每次对文档的修改操作之前,调用GetDocument()->Backup()
    3.10 使用鼠标拖拽选中多个图形
    首先自HStrokeRect类继承一个HStrokeSelect类,实现DrawStroke方法:
    void HStrokeSelect::DrawStroke(CDC *pDC){ m_penColor = RGB(255,0,0); m_penWidth = 1; m_penStyle = PS_DASH; HStrokeRect::DrawStroke(pDC);}
    然后在LButtonUp时选中区域内的图形,并将HStrokeSelect对象删除:
    //Step0.2 选择框 else if(PIC_select == m_stroke->m_picType){ bool refresh = false;//是否需要刷新 CRect rect(m_stroke->m_points.GetAt(0),m_stroke->m_points.GetAt(1)); for(int i = 0; i < pDoc->m_strokeList.GetSize(); i ++){ //是否在所框区域内 if(rect.PtInRect(pDoc->m_strokeList.GetAt(i)->m_points.GetAt(0)) && rect.PtInRect(pDoc->m_strokeList.GetAt(i)->m_points.GetAt(1))){ //设置选中状态 pDoc->m_strokeList.GetAt(i)->m_bSelected = true; refresh = true;//标志需要刷新 } } if(refresh) Invalidate();//刷新 delete m_stroke;//释放内存 }
    3.11 直线HStrokeLine的Tracker只显示两个Point
    CRectTracker在选中状态下会显示8个点,这对于矩形是合理的,而对于线段来讲,只要显示两个点就可以了,这里重载了CRectTracker类的Draw方法:
    void HStrokeTracker::Draw(CDC* pDC) const{ CRect rect; //一般图形用CRectTracker的方法即可 CRectTracker::Draw(pDC); //对于直线 if((m_picType == PIC_line) && ((m_nStyle&(resizeInside|resizeOutside))!=0)){ UINT mask = GetHandleMask(); for (int i = 0; i < 8; ++i) { if (mask & (1<<i)) { int p1, p2; //直线斜率小于0,即左上+右下 if(m_picExtra == 0) { p1 = 1, p2 = 4; } //直线斜率大于0,即左下+右上 else{ p1 = 2, p2 = 8; } if( ((1<<i) == p1) || ((1<<i) == p2)){ GetHandleRect((TrackerHit)i, &rect); pDC->FillSolidRect(rect, RGB(0, 0, 0)); } else{ GetHandleRect((TrackerHit)i, &rect); pDC->FillSolidRect(rect, RGB(255, 255, 255)); } } } }}
    3.12 键盘控制重载PreTranslate函数,响应Ctrl+A,Delete,Shift+(UP|DOWN|LEFT|RIGHT)键盘事件,实现全选,删除所选,控制所选多个图形移动功能。
    CHDrawDoc *pDoc = GetDocument(); BOOL deleted = FALSE; int i, x, y; if (pMsg->message == WM_KEYDOWN) { switch (pMsg->wParam){ //删除 case VK_DELETE: for(i = 0; i <pDoc->m_strokeList.GetSize(); i ++){ if(pDoc->m_strokeList.GetAt(i)->m_bSelected){ pDoc->m_strokeList.RemoveAt(i--); deleted = TRUE; } } if(deleted) Invalidate(); break; //全选 case 'A': case 'a': if(::GetKeyState(VK_CONTROL) < 0){ for(int i = 0; i <pDoc->m_strokeList.GetSize(); i ++){ pDoc->m_strokeList.GetAt(i)->m_bSelected = TRUE; } Invalidate(); } break; //移动 case VK_UP: case VK_DOWN: case VK_LEFT: case VK_RIGHT: x = (pMsg->wParam==VK_RIGHT) - (pMsg->wParam==VK_LEFT); y = (pMsg->wParam==VK_DOWN) - (pMsg->wParam==VK_UP); //Shift键加速移动 if(::GetKeyState(VK_SHIFT) < 0){ x *= 8; y *= 8; } for(int i = 0; i <pDoc->m_strokeList.GetSize(); i ++){ if(pDoc->m_strokeList.GetAt(i)->m_bSelected){ pDoc->m_strokeList.GetAt(i)->Move(x,y); } } Invalidate(); break; } }
    3.13 对话框控制
    HStrokeEditDlg对话框,实现对所有图形的矢量化编辑,可以直接修改图形的坐标,颜色,宽度,删除图形等操作。
    3.14 动画程序图标第一步:在资源中增加5个图标资源ICON:IDI_ICON1~IDI_ICON5第二步:在CMainFrame中增加变量HICON m_icons[5],并在构造函数中加载资源:
    m_icons[0] = LoadIcon(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDI_ICON1)); m_icons[1] = LoadIcon(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDI_ICON2)); m_icons[2] = LoadIcon(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDI_ICON3)); m_icons[3] = LoadIcon(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDI_ICON4)); m_icons[4] = LoadIcon(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDI_ICON5));
    第三步:在CMainFrame的OnCreate函数中加载资源,并启动计数器:
    SetClassLong(m_hWnd, GCL_HICON, (LONG)m_icons[0]); SetTimer(WM_ICONALT, 1000, NULL); //设置计数器每秒
    第四步:在计数器函数OnTimer中增加修改图标的代码:
    static int iconIndex = 1; //静态变量计算第几个图标 if(nIDEvent == WM_ICONALT){ SetClassLong(m_hWnd, GCL_HICON, (LONG)m_icons[iconIndex]); iconIndex = (++iconIndex) % 5; } CFrameWnd::OnTimer(nIDEvent);
    3.15 LButtonDown流程如果Ctrl键没有被按下,遍历图形数组,如果有Track的图形,执行Track操作
    Step1:If Ctrl键没有被按下For 每个图形 If 该图形被选中If Track 移动图形 标记b_Track为真,表示当前是Track而不是绘图EndIf EndIf EndForEndIfStep2:For每个图形,If当前鼠标点在其范围内 If Ctrl键被按下 该图形的选中状态取反 Else 没有按下Ctrl键 选中当前图形 EndIfElse 当前鼠标点不再其范围内 If Ctrl键被按下 无操作,认为是用户多选时的误操作Else Ctrl键没有被按下取消该图形的选中状态 EndIf EndIfEnd ForStep3:If b_Track为假,表示当前是绘图而不是TrackStep3.1. 设置捕获鼠标SetCapture();Step3.2. 加入新图形m_stroke = pDoc->NewStroke(); Step3.3. 设置起点m_stroke->SetCurrentPoint(point); Step4. 设置文件已经修改状态EndIf3.16 LButtonUp流程If 用户点下鼠标后就松开,等于没有画 删除指针,释放内存ElseIf 画图类型为选择框 For 每个图形 If 该图形在选择框内 设置状态为选中 EndIf EndFor 删除指针,释放内存Else 画图 设置当前鼠标坐标 加入图形 备份EndIf3.17 MouseMove流程If 当前处于捕获状态(参考LButtonDown) 重画图形Else For 每个图形 If 当前鼠标坐标在该图形内 设置该图形高亮状态为真 Else 设置该图形高亮状态为假 EndIf EndForEndIf4. 总结4.1 Tricks4.1.1 子View和父View公用一个Doc本程序使用了两个View,CHDrawPView中创建了CHDrawView,而为了在CHDrawView中使用CHDrawDoc对象,需要将CHDrawPView的Doc传给CHDrawView。这个需求只要为CHDrawView增加一个方法,将m_pDocument指针传过去即可。
    但是这样就引来另外一个问题,在CView析构的时候,它会去析构m_pDocument,这样CHDrawDoc就会被CHDrawView和CHDrawPView一共析构两次,出现错误,为了解决这个问题,在传递m_pDocument的时候,用另外一个CDocument指针储存CHDrawView的m_pDocument,然后在CHDrawView析构函数中,再将m_pDocument修改回去。
    4.1.2 在类中获取其它类的句柄在CMainframe中:
    SDI中获取View ((CMainFrame*)AfxGetApp()->m_hMainWnd)->GetActiveView();SDI中获取View CMainFrame::GetActiveView()SDI中获取Doc((CMainFrame*)AfxGetApp()->m_hMainWnd)->GetActiveDocument();MDI中获取ViewAfxGetApp()->m_pMainWnd)->GetActiveFrame()->GetActiveView();MDI中获取DocAfxGetApp()->m_pMainWnd)->GetActiveFrame()->GetActiveDocument();MDI中获取View GetActiveFrame()->GetActiveView()MDI中获取View MDIGetActive()->GetActiveView()在CxxxDoc类中:MDI中获取View GetFirstViewPosition();MDI中获取View GetNextView()在CxxxView类中:SDI中获取Frame getMainFrame AfxGetApp()->m_hMainWnd;SDI中获取Frame getMainFrame CWnd::GetParentFrame()SDI中获取Frame getMainFrame AfxGetMainWnd()SDI中获取Doc GetDocument()MDI中获取Doc GetDocument();4.1.3 CRectTracker用法CRectTracker是MFC提供的一个很好用的类,简单易用。使用步骤:第一步:声明CRectTracker变量
    CRectTracker m_tracker;
    第二步:初始化CRectTracker的区域m_rect和样式m_style
    m_tracker.m_rect.SetRect(0,0,GetDocument()->m_cavasW, GetDocument()->m_cavasH); m_tracker.m_nStyle=CRectTracker::resizeOutside;
    第三步:override OnSetCursor方法:
    CPoint point; //Step1. get cursor position GetCursorPos(&point); //Step2. convert point from screen to client ScreenToClient(&point); if(m_tracker.HitTest(point) >= 0){ //Step3. set cursor, **notice, use nHitTest instead of return of tracker m_tracker.SetCursor(pWnd, nHitTest); …
    第四步:在OnLButtonDown函数中调用HitTest检测并用Track函数跟踪
    int hit = m_tracker.HitTest(point); switch(hit){ case 2: case 5: case 6: if(m_tracker.Track(this,point)){ //step1. cavas reset GetDocument()->m_cavasH = m_tracker.m_rect.bottom; GetDocument()->m_cavasW = m_tracker.m_rect.right; //step2. scroll or not CRect clientRect; GetClientRect(&clientRect); SetScrollSizes(MM_TEXT, CSize(m_tracker.m_rect.Width()+10, m_tracker.m_rect.Height()+10)); m_drawView->MoveWindow(m_tracker.m_rect.left, m_tracker.m_rect.top, m_tracker.m_rect.right,m_tracker.m_rect.bottom); GetDocument()->BackUp();//备份 Invalidate(); } }
    使用时容易出现的问题:如果在调用CRectTracker的Track方法之前调用了SetCapture函数,会发现Track方法失效。因为SetCapture方法会捕获鼠标事件,而Track则需要独立处理鼠标事件,两个函数争夺鼠标活动的处理权,并以Track的失败告终。
    3.1.4 内存泄露内存泄露问题发生的概率非常高,MFC的Debug功能对内存泄露的检测虽然算不上完美,但是基本够用了,使用F5启动调试,然后尽可能多的执行操作,关闭后在Debug窗口显示调试结构,如果有内存泄露,则会出现以下类型的信息:
    Detected memory leaks!Dumping objects ->afxtempl.h(370) : {1208} normal block at 0x00376880, 40 bytes long. Data: < . > BE 00 00 00 2E 00 00 00 AC 00 00 00 A1 00 00 00 E:\code\less01\HDraw\HDrawDoc.cpp(131) : {1202} client block at 0x00376770, subtype 0, 48 bytes long.a HStrokeLine object at $00376770, 48 bytes longafxtempl.h(370) : {960} normal block at 0x00376708, 40 bytes long. Data: < ~ > 92 00 00 00 1E 00 00 00 7E 00 00 00 A8 00 00 00 E:\code\less01\HDraw\HDrawDoc.cpp(131) : {954} client block at 0x003765B0, subtype 0, 48 bytes long.a HStrokeLine object at $003765B0, 48 bytes longafxtempl.h(370) : {723} normal block at 0x00376548, 40 bytes long. Data: <Q [ w > 51 00 00 00 5B 00 00 00 07 01 00 00 77 00 00 00 E:\code\less01\HDraw\HDrawDoc.cpp(131) : {717} client block at 0x00377768, subtype 0, 48 bytes long.a HStrokeLine object at $00377768, 48 bytes longafxtempl.h(370) : {422} normal block at 0x00377910, 40 bytes long. Data: << # Y > 3C 00 00 00 23 00 00 00 E4 00 00 00 59 00 00 00 E:\code\less01\HDraw\HDrawDoc.cpp(131) : {419} client block at 0x00377800, subtype 0, 48 bytes long.a HStrokeLine object at $00377800, 48 bytes longObject dump complete.
    双击相应的信息就能定位到未释放内存的申请地址,然后考虑应该在什么地方释放。
    0 评论 7 下载 2019-07-15 23:22:53 下载需要11点积分
  • 基于Python和opencv实现抖音上墨镜和烟卷效果

    一、项目简介现今较火的抖音上有一个十分有趣的特效,其可以自动检测出人脸并且放置墨镜和烟卷,鉴于此,想自己实现动手实现以下该特效的制作。
    二、工作环境Python 3.6,opencv+Dlib,Windows操作系统,pycharm
    三、流程
    从摄像头获取视频流,并转换为一帧一帧的图像,然后将图像信息传递给opencv这个工具库处理,返回灰度图像。
    程序启动后,根据监听器信息,使用一个while循环,不断的加载视频图像,然后返回给opencv工具呈现图像信息。
    创建一个键盘事件监听,按下”d”键,则开始执行面部匹配,并进行面具加载(这个过程是动态的,你可以随时移动)。
    面部匹配使用Dlib中的人脸检测算法来查看是否有人脸存在。如果有,它将为每个人脸创建一个结束位置,眼镜和烟卷会移动到那里结束。
    然后我们需要缩放和旋转我们的眼镜以适合每个人的脸。我们将使用从Dlib的68点模型返回的点集来找到眼睛和嘴巴的中心,并为它们之间的空间旋转。
    在我们实时获取眼镜和烟卷的最终位置后,眼镜和烟卷从屏幕顶部进入,开始匹配你的眼镜和嘴巴
    假如没有人脸,程序会直接返回你的视频信息,不会有面具移动的效果。默认一个周期是4秒钟。然后你可以通过”d”键再次检测。
    退出程序按下q键。

    四、关键代码
    创建面具加载服务类DynamicStreamMaskService及其对应的初始化属性:
    读取摄像头视频流并转化为图象:
    实现人脸定位函数,及眼镜和烟卷的定位:
    接下来实现画图函数:
    创建启动函数start:

    五、运行结果运行后,首先会打开摄像头,然后按下键盘d键,就会看到墨镜和烟卷从屏幕上方出来,自动定位到眼睛和嘴巴。参考结果如下:图片经过马赛克处理了。
    注意代码中需要调用shape_predictor_68_face_landmarks.dat人脸库,需要下载,然后在代码调用处中指定路径即可。
    0 评论 5 下载 2019-07-11 15:04:59 下载需要15点积分
  • 基于移动网络通讯行为的用户风险识别

    一、实验内容参加“基于移动网络通讯行为的用户风险识别”大赛,本次大赛以模拟的语音通话、短信收发、网站及App访问记录等移动网络使用行为为基础,参赛队伍需要通过数据挖掘技术和机器学习算法,构建识别风险用户的预测模型,判别用户属于风险用户的可能性。从而为各行业提供风控保障,助力新时代大数字生态的健康有序发展。
    二、实验主要思想与方法本实验主要根据用户的通话记录、短信记录、网站和APP访问记录的信息,对用户进行分类和预测。在实验方法介绍分为三部分,第一部分为数据集训练与可视化,第二部分介绍特征提取的主要策略,在第三部分将介绍此次实验使用的LightGBM模型。
    2.1 数据集训练与可视化2.1.1 用户通话记录用户通话记录数据

    通话号码长度分布

    不同通话类型所占比例

    打入和打出电话所占比例

    打入和打出电话不同长度出现次数

    打入和打出电话号码不同头部出现次数

    每日活跃次数

    打入和打出情况下每天的活跃次数

    5种不同类型下每天的活跃次数

    通话号码不同长度出现次数

    已给风险用户的通话号码长度出现次数

    通话号码头部出现次数(仅截取主要部分)

    已给风险用户通话号码头部出现次数(仅截取主要部分)

    2.1.2 用户短信记录用户短信记录数据

    短信号码长度分布

    短信号码不同头部出现次数

    已给风险用户的短信号码头部出现次数

    短信号码不同长度出现次数

    已给风险用户的短信号码长度出现次数

    接收/发送短信情况下不同短信头部出现次数

    接收/发送短信情况下不同短信长度出现次数

    2.1.3 用户网站/App访问记录用户网站/App访问记录数据

    用户访问网站/APP分别占的比例

    两种类型每日活跃次数

    2.2 特征提取经过对可视化结果的分析,对特征进行如下处理:

    通话记录:

    voice_time:将end_time、start_time转为时间格式并计算通话时长(end_time-start_time);voice_date:取start_time的前两位
    短信记录:sms_date:取start_time的前两位。
    对已给特征使用常规的提取方法,如取:sum、mean、min、max、median等。
    将提取的特征与in_out、call_type、wa_type等进行结合。
    多变量进行结合,如:
    voice_feature[‘voice_cnt_peruniquecall’]= voice_feature[‘voice_opp_num_unique’]/voice_feature[‘voice_date_cnt’],求每天有通话的号码数量等。

    经过以上特征处理,最终得到如下特征:

    feature,importancesms_opp_head_max_in,92voice_len_mean_in,70sms_opp_len_mean_in,57voice_cnt_peruniquecall,56wa_type1_date_mean,54wa_dura_sum_percnt,50wa_type0_namecnt_perday,50sms_opp_head_min_in,49voice_head_mean_in,47sms_opp_head_mean_in,41sms_opp_len_mean,39voice_opp_head_min,39voice_headinunique_perday,37voice_head_mean_type1,36wa_type0_dura_perday,36wa_down_flow_median,35voice_time_median,35voice_date_mean_type1,34voice_timesum_peruniquecall,34voice_head_mean_out,33sms_start_time_mean,33voice_time_min,33voice_start_mean_in,33wa_type1_dura_perday,33voice_head_max_type1,32wa_namecnt_perday,32sms_callunique_perday,31voice_len_max_in,31voice_start_mean_out,30sms_calluniquein_mean_perday,30sms_calluniquein_perday,30sms_len_perday,30voice_headoutunique_perday,29voice_time_mean_out,29voice_len_mean_type1,29wa_type1_date_cnt,29wa_up_flow_median,28wa_type1_namecnt_perday,28voice_head_unique_in,28wa_type0_namedura_perday,28wa_type0_date_mean,27voice_headout_perday,27voice_timeoutmean_percall,26voice_headin_perday,26voice_opp_head_mean,26sms_callcnt_perday,26wa_visit_date_cnt,26wa_type1_namevicnt_perday,26wa_type0_dura_mean,25voice_opp_head_max,25voice_date_cnt_in,25wa_type1_namedura_perday,25wa_name_count_uinque,24wa_type0_visitcnt_mean,24voice_time_max,24sms_opp_num_count_in,23wa_type0_date_cnt,23voice_headmean_peruniquecall,23wa_type0_namevicnt_perday,23wa_type1_namevicntall_perday,23voice_time1mean_percall,23wa_visit_cnt_mean,23wa_type1_dura_mean,23sms_opp_head_max,22voice_opp_len_max,22wa_visit_dura_median,22sms_head_unique_perday,22voice_cntoutsum_perday,22voice_opp_unique_in,22wa_down_flow_mean,22wa_type1_downflow_mean,22sms_start_time_mean_in,21voice_time_mean_type1,21wa_visitdura_perday,21wa_up_flow_std,21voice_time_mean_in,21sms_opp_len_sum,21wa_namedura_perday,20sms_start_time_mean_out,20wa_type0_up_persec,20wa_type1_visitcnt_all,20wa_type0_visitcnt_perday,20voice_timeoutunique_percall,20voice_len_mean_out,20wa_up_flow_max,20wa_type0_flow_mean,19voice_cntoutmean_perday,19voice_timeoutsum_perday,19voice_head_peruniquecall,19wa_type1_upflow_mean,19sms_calluniquemeanout_perday,19sms_calluniquemeanin_perday,19wa_type1_visitcnt_perday,19voice_time_std,19wa_visitcnt_perday,19wa_type1_down_percnt,19wa_flow_sum_perday,19sms_opp_head_min,19wa_type0_downflow_all,18voice_cntinsum_perday,18wa_type1_flow_mean,18sms_calluniqueout_mean_perday,18voice_numcnt3mean_perday,18wa_type1_name_unique,18sms_opp_head_mean_out,17wa_down_flow_std,17voice_timemean_peruniquecall,17voice_lenmean_peruniquecall,17voice_cnt_perday,17wa_type0_name_unique,17sms_opp_head_mean,17voice_timeout_percall,16voice_opp_unique_out,16wa_type0_down_perday,16wa_type0_namevicntall_perday,16wa_flow,16sms_date_cnt_in,16wa_upflowcnt_perday,16voice_timeinunique_percall,16sms_opp_len_max,15wa_up_flow_mean,15wa_visit_dura_std,15sms_date_cnt,15wa_visit_dura_mean,15voice_numcnt1mean_perday,15voice_opp_len_mean,15voice_date_mean_type2,15voice_len_max_out,15wa_namevicnt_perday,15sms_date_mean_in,14voice_lensum_peruniquecall,14voice_timeoutsum_percall,14voice_time_sum_out,14wa_upflow_perday,14voice_timeoutmean_perday,14voice_time_mean_type3,14wa_type1_visitcnt_mean,14wa_type0_upflow_mean,14voice_time_sum_type3,13wa_downflowcnt_perday,13wa_type1_up_perday,13wa_flow_sum_percnt,13sms_date_cnt_out,13wa_down_flow_max,13voice_timemean_percall,13sms_calluniquecntin_perday,13voice_timein_percall,13voice_date_mean_out,12voice_time_sum_in,12voice_date_count_type1,12voice_time_sum_type1,12voice_date_count_type3,12wa_type1_up_persec,12voice_head_mean_type2,12voice_time1_percall,12voice_time2_percall,12voice_time3_percall,12voice_len_peruniquecall,12wa_type0_upflow_all,12wa_flow_sum_persecond,12wa_type0_down_percnt,12voice_opp_len_unique,11wa_type0_visitcnt_all,11wa_type0_up_perday,11sms_calluniqueout_perday,11voice_time3mean_percall,11wa_down_flow_sum,11voice_timeinmean_percall,11wa_visit_cnt_std,11voice_date_mean_type3,11voice_date_cnt_out,10wa_up_flow_sum,10wa_upflowdura_persec,10voice_time2mean_percall,10voice_cntinmean_perday,10voice_head_mean_type3,10sms_opp_head_min_out,10wa_visit_cnt_median,10wa_visit_cnt_sum,10voice_timeinsum_perday,10wa_type0_downflow_mean,9wa_type1_down_perday,9sms_opp_num_unique_in,9wa_visit_dura_sum,9sms_opp_num_count_unique,8voice_opp_count_all,8sms_calluniquecntout_perday,8voice_date_count_type2,8sms_date_mean_out,8voice_date_cnt,8voice_time_mean_type2,8voice_time_mean,8voice_opp_num_unique,8voice_numcnt1_perday,8voice_numcnt2mean_perday,8sms_opp_num_count_out,8wa_visit_cnt_max,8wa_type1_upflow_all,7voice_opp_count_out,7voice_numcnt2_perday,7wa_downflowdura_persec,7voice_headsum_peruniquecall,7wa_visit_dura_max,7voice_timeinsum_percall,7voice_date_mean_in,6wa_downflow_perday,6sms_opp_len_mean_out,6voice_time_sum,6sms_opp_num_count_all,6voice_time_percall,6voice_head_unique_out,6voice_num_cnt_type1,6voice_num_cnt_type3,6voice_opp_head_unique,5sms_opp_num_unique_out,5wa_type1_downflow_all,4voice_len_sum_out,4sms_opp_head_max_out,4voice_numcnt3_perday,4sms_opp_head_unique,3voice_timeinmean_perday,3voice_head_max_type3,3voice_time_sum_type2,2voice_head_max_type2,2voice_len_sum_in,2voice_opp_count_in,2voice_num_cnt_type2,0

    在特征工程中,删除了一些低分的特征,最终确定维数为228。
    2.3 LightGBMLightGBM与其他流行算法采用depth-wise的叶子生长策略不同,其使用的是带深度限制的leaf-wise的叶子生长策略。与depth-wise相比,leaf-wise算法收敛得更快。但leaf-wise的一个缺点就是:参数选择不当可能会产生比较深的决策树从而产生过拟合。因此LightGBM在Leaf-wise上增加了一个最大深度限制,在保证高效率的同时防止过拟合。
    在调参方面,由于LightGBM使用的是leaf-wise算法,因此调节使用的是num_leaves控制模型复杂度,大致设置为num_leaves=2^max_depth。另外,min_data_in_leaf参数用于处理过拟合的问题,设置大可以防止过拟合,但需要注意可能会导致欠拟合。
    由于特征过多,必须要考虑多过拟合的处理,所以设置较小的num_leavea和max_depth以避免过深的树,同时要设置合适的min_data_in_leaf避免过拟合或欠拟合。
    以下为参数设置:
    lgb_params = { 'boosting_type': 'gbdt', 'objective': 'binary', 'is_training_metric': False, 'learning_rate': 0.08, 'num_leaves':16, 'max_depth':6, 'min_data_in_leaf':40, 'verbosity':-1, 'is_training_metric':False, 'feature_fraction': 0.8, 'bagging_fraction': 0.8, 'bagging_freq':1, 'is_unbalance':True}三、实验结果通过特征提取和调整模型参数,提交结果前最终线下测试结果为0.809,线上测试结果为0.760,最终排名142/211。
    比赛结果截图:

    四、心得体会本次实训对我来说实际上是一次很大的考验。因为先前既没有python的基础,也没有上过数据挖掘理论课,所以一开始对相关的理论概念一无所知。
    在这样的情况下,我从网上的教程一步步开始学习,包括学习python的网站以及在同学推荐下看数据挖掘和机器学习的网课,慢慢摸索。尽管这样,在初赛阶段,写出来的代码和测试结果仍然惨不忍睹(线上测试分数只有0.39)。
    后来,在同学的帮助下(包括模型讲解和编码的指导)和参考了助教提供的baseline,逐渐把分数提高,最终有这样的成绩。
    可以说现在我依然对数据挖掘相关的理论知识一知半解,仅仅停留在照着葫芦画瓢的阶段。但至少在这个过程中我逐渐熟悉了python的使用,以及一些很实用的python库如numpy、pandas等,还算是有些收获。
    0 评论 3 下载 2019-06-25 18:08:51 下载需要12点积分
  • Palette-based Photo Recoloring论文算法重现

    一、使用方法直接打开index.html从相册中选择合适图片上传,程序将自动计算调色板。待计算完成,可点击调色板编辑变换的目标颜色。编辑完后,点击CONFIRM按钮开始重着色。
    二、算法实现2.1 调色板计算
    将RGB颜色空间均匀分成$16\times 16\times 16$个bins,统计图像中属于各个bin的颜色个数。每个bin的RGB空间均值为其代表色 (注: 原文为Lab空间均值,但求该均值较复杂,故使用了差别不大的RGB均值)。
    对bin进行聚类,使用的方法是改进的K-means算法。
    在聚类前,规定黑色为调色板颜色之一,这样可避免生成的调色板中有很多暗色。
    将聚类得到的调色板颜色按照Lab亮度升序排序。

    2.2 重着色
    单个的颜色变换可以看成颜色在L通道与a、b通道单独变换的组合。
    L通道的变换由对调色板亮度线性插值得到。
    ab通道的变换(左下图)由颜色在Lab空间内平移得到。其中对于超出Lab边界的情况做了特殊处理
    一组颜色变换可以看做是若干个单独颜色变换的组合(右下图),文章给出了使用径向基函数分配权重的方法:

    $$f(x)=\sum_i^k \omega _i(x) f_i(x)$$ $$\omega _i(x)=\sum_j^k\lambda_{ij}\phi(\parallel x-C_j\parallel)$$ $$\phi(r)=e^{-\frac{r^2}{2\sigma_r^2}}$$ <div style="text-align:center"> <img src="img/report/p1.png" height=200>   <img src="img/report/p1.png" height=200> </div>
    三、主要函数及说明


    函数
    位置
    说明




    Color.lab2rgb(InputColor)
    color.js
    将RGB颜色转换为Lab颜色($RGB\to XYZ\to Lab$)


    Color.rgb2lab(InputColor)
    color.js
    将Lab颜色转换为RGB颜色


    Color.labBoundary(pin, pout)
    color.js
    在Lab空间内,求颜色pin与pout连线与Lab边界的交点(二分查找)


    Palette.palette()
    palette.js
    统计图像颜色属于各个bin的颜色个数


    Palette.kmeansFirst()
    palette.js
    聚类,由统计好的bins数据得到调色板


    Palette.kmeans()
    palette.js
    调整上一步聚类得到的颜色,直到调色板不再变化


    Palette.colorTransformSingleL(l)
    palette.js
    根据调色板颜色亮度,确定新图像亮度的变化


    Palette.colorTransformSingleAB(ab1,ab2,L,x)
    palette.js
    在Lab空间某一亮度的层内,根据论文方法,由$ab1\to ab2$这一对颜色变换,对x做a、b通道的颜色变换


    Palette.colorTransform(colors1,colors2)
    palette.js
    综合几组颜色变换的结果,得到新的图片



    Gallery<div style="text-align:center"><img src="img/gallery/p1.png" height=400><img src="img/gallery/p2.png" height=400></div><div style="text-align:center"><img src="img/gallery/p3.png" height=400><img src="img/gallery/p4.png" height=400></div>---<div style="text-align:center"><img src="img/gallery/p5.png" height=400><img src="img/gallery/p6.png" height=400></div><div style="text-align:center"><img src="img/gallery/p7.png" height=400><img src="img/gallery/p8.png" height=400></div>---<div style="text-align:center"><img src="img/gallery/p9.png" height=400><img src="img/gallery/p10.png" height=400></div>
    0 评论 4 下载 2019-06-18 13:31:52 下载需要12点积分
  • 基于Java的开心农场

    1 概述构思如下
    前端用户交互系统,包括用户注册和登录,农场概况、土地操作。作物操作等。用户注册时要有相应的用户名、密码、提示问题、答案,登陆后可以修改用户部分相关信息。农场主要信息包括金币数、经验值、好友排行,涉及到相关数据库的存储。对土地的操作主要是耕地、开垦,增加经验同时减少金币。作物的种植、除草、浇水、施肥,对应着相关数据库数据更新。金币的主要来源应该是以卖果实增加的金币。 后端包括后台数据库管理、进程调度。对于金币、经验、土地数、成熟时间等都应有详细记录,主体以时间的记录推进,以金币数和经验值数作为判断标准,进行相应的进程调度。
    1.1 需求规定1.1.1 对功能的规定


    功能
    输入
    处理
    输出




    登录;找回忘记密码
    在登录页面输入的用户名、密码;提示问题答案
    信息验证,并判断是否弹出农场界面;
    在登录页面提示登录结果;用户基本信息修改页面


    浏览农场
    单击农场按钮;对农场的拖动操作
    弹出农场界面
    弹出农场界面


    购买商品
    点击商店小图片进入商店界面;在商店页面选择的商品种类、输入的数量
    用户金币值减少,用户包裹商品种类、数量增加
    显示商品种类名称+商品数量,提示购买结果,显示用户金币减少


    播种
    在农场界面对土地进行的操作;种子种类名称+播种的土地编号
    在界面中替换图片
    在农场界面的土地上发生变化


    作物生长
    作物阶段生长时间+作物生长状态
    在界面中替换图片;计算作物生长时间、生长状态
    在农场界面的土地上发生变化


    拖动、翻地、收获、(不能放虫、放杂草)
    在农场界面对土地进行的操作;操作编号
    在界面中替换图片
    在农场界面的土地上发生变化


    收获果实,放仓库
    在农场界面对土地进行的操作
    在界面中替换图片;将商品种类及其数量加在数据库中;用户经验的变化
    在农场界面的土地上发生变化,仓库中果实的种类及其数量增加


    卖果实
    在仓库页面选择的商品种类、输入的数量
    将商品种类及其数量在数据库中减去;用户金钱的增加
    仓库中的商品种类及其数量减少


    开垦土地
    在农场界面对土地进行的操作
    在界面中替换图片
    在农场界面的土地上发生变化


    查看包裹;包裹内物品的使用
    单击包裹按钮;点击使用按钮
    弹出包裹显示种类,数量列表
    弹出包裹;对包裹内的物品进行操作


    分页显示好友信息
    点击好友面板可弹出好友列表界面
    经验排行,金钱排行,查询好友功能
    相应显示操作结果



    1.1.2 系统功能层次模块图
    1.1.2.1 子模块用户土地操作:包括翻地、播种、收获等;增加经验值
    2 系统功能设计2.1 登录注册功能本功能为登录注册功能,包括登录、注册。当个人忘记密码时,由其通过回答提示问题找回密码。
    2.1.1 登录子功能系统要求登录者提供帐号、密码,并进行身份确认及登录结果页面导向。如果登录者输入的账号和密码与数据库数据不一致,则提示该用户“您输入的账号或密码错误,请从新输入!”;登录成功后弹出用户农场界面。又或者该用户已经不记得密码,登录还设置一个找回密码的功能,用户可以修改自己的密码及部分基本信息,单击找回密码按钮则弹出用户早先在注册信息中设置的问题,如果用户输入的答案与注册信息中设置的答案不一致,则提示用户“您输入的答案错误,请从新输入!”;如果输入的答案正确,则弹出密码从新输入对话框,要求用户重新输入密码,并再次确认以及是否修改其他基本信息,用户提交后,经过验证将数据保存到数据库。
    2.2 用户功能农场界面会显示用户的游戏信息,如昵称、等级、金币等信息。同时农场会显示不同的图片按钮供用户进行操作,如点击商店图片进入商店购买物品、点击留言可以输入留言信息、点击仓库图片进入仓库查看作物等。
    2.2.1 土地操作子功能用户对自己土地的操作,主要包括拖动、翻地、播种收获、等。不能放虫、种杂草等等。如果进行翻地操作的土地上已经存在作物,这时对土地进行操作为有效操作,。当土地上没有作物时可以进行播种操作,当土地上存在作物时不可以进行播种操作。物已经成熟,可以进行收获、,当土地上的作物没有成熟,则不能进行收获。
    2.2.2 买卖商品子功能游戏中包含商店系统,用户可以从商店中用金币购买物品,也可以把自己仓库(仓库是用来存取用户作物收成的地方)中收获或偷取的果实、蔬菜等物品卖到商店获得金币。用户通过单击商店按钮进入商店界面,在商店中用户可以看到系统所提供的所有商品,其商品信息主要包括:商品名称、购买单价、限制购买等级等等;如果用户单击仓库按钮,则进入仓库界面,在仓库界面中,用户可以看到已经收获的或偷取好友的果实各自的种类、名称、数量、卖出单价及其所有果实的卖出收入。
    记录日志也是系统的功能,用户对好友的土地操作会由系统记录下来,并显示到用户的日志信息中。日志记录的主要内容应该包括:用户对土地的操作、用户的买卖行为以及好友对土地的操作等等。主要日志字段包含操作人、操作时间以及操作内容等。
    3 数据字典设计数据字典的主要目的是提供查阅对不了解的条目的解释。在数据字典中记录数据元素的下列信息:一般信息(名字,别名,描述等),定义(数据类型,长度,结构等),使用特点(值的范围,使用频率,使用方式—输入/输出/本地,条件值等),控制信息(来源,用户,使用它的程序,改变权等),分组信息(父结构,从属结构,物理位置—记录、文件和数据库等)。
    下面的例子是通过卡片来描述数据字典:

    4 数据库设计4.1 表设计4.1.1 TableName(表名的解释)userBasic 用户基本信息表



    字段名
    数据类型
    是否为空
    默认值
    备注




    userID
    Int
    Not null

    用户编号,主键,标识列,初始值为1,增量为1


    userName
    Nvarchar(30)
    Not null

    用户昵称


    Sex
    Bit
    Not null
    0
    用户性别


    Email
    Nvarchar(50)
    Null

    用户Email地址


    enrollTime
    Datetime
    Not null

    注册日期


    userIcoSrc
    Nvarchar(50)
    Not null

    用户头像地址


    userCode
    Nvarchar(12)
    Not null

    用户游戏帐号


    Pwd
    Nvarchar(50)
    Not null

    用户密码



    userInfo 用户游戏信息表



    字段名
    数据类型
    是否为空
    默认值
    备注




    infoID
    Int
    Not null

    信息编号,主键,标识列,初始值为1,增量为1


    userID
    Int
    Not null

    用户编号,外键,与userBasic表中userID字段关联


    Experience
    Int
    Not null
    0
    用户游戏经验值


    Coin
    Int
    Not null
    1000
    用户游戏金币值


    Grade
    Int
    Not null
    0
    用户游戏级别


    lastTime
    Datetime
    Not null

    用户最近一次登录游戏的时间



    cropBasic 作物基本信息表



    字段名
    数据类型
    是否为空
    默认值
    备注




    cropID
    Int
    Not null

    作物编号,主键,标识列,初始值为1,增量为1


    cropName
    Nvarchar(50)
    Not null

    作物名称


    Grade
    Int
    Not null
    0
    用户种植该作物所需达到的游戏级别


    seedPrice
    Int
    Not null
    0
    用户购买该作物种子的单价


    cropPrice
    Int
    Not null
    0
    作物果实卖出时的单价


    getExp
    Int
    Not null
    0
    用户收获果实所得的单位经验值


    hvtMax
    Int
    Not null

    作物可收获果实的最大值


    hvtMin
    Int
    Not null

    作物可收获果实的最小值


    hvtTime
    Int
    Not null

    作物从种子阶段成长到结果阶段所需的时间值


    cropIcoSrc
    Nvarchar(50)
    Not null

    作物图标地址


    Instroduce
    Nvarchar(50)
    Not null

    作物简单介绍



    cropGrowthInfo 作物生长信息表



    字段名
    数据类型
    是否为空
    默认值
    备注




    infoID
    Int
    Not null

    信息编号,主键,标识列,初始值为1,增量为1


    cropID
    Int
    Not null

    作物编号,外键,与cropBasic表中cropID字段关联


    germinateTime
    Int
    Not null

    作物发芽阶段所需的时间值


    litterTime
    Int
    Not null

    作物小叶阶段所需的时间值


    bigTime
    Int
    Not null

    作物大叶阶段所需的时间值


    flowerTime
    Int
    Not null

    作物开花阶段所需的时间值


    frutTime
    Int
    Not null

    作物结果阶段所需的时间值


    germinateIcoSrc
    Nvarchar(50)
    Not null

    作物发芽阶段的图片地址


    litterIcoSrc
    Nvarchar(50)
    Not null

    作物小叶阶段的图片地址


    bigIcoSrc
    Nvarchar(50)
    Not null

    作物大叶阶段的图片地址


    flowerIcoSrc
    Nvarchar(50)
    Not null

    作物开花阶段的图片地址


    frutIcoSrc
    Nvarchar(50)
    Not null

    作物结果阶段的图片地址



    harvestList 成果列表



    字段名
    数据类型
    是否为空
    默认值
    备注




    listID
    Int
    Not null

    列表编号,主键,标识列,初始值为1,增量为1


    userID
    Int
    Not null

    用户编号,外键,与userBasic表中userID字段关联


    cropID
    Int
    Not null

    作物编号,外键,与cropBasic表中cropID字段关联


    hvtTotal
    Int
    Not null
    0
    用户在游戏中摘取果实的累计值



    cropStoreInfo 果实存储列表



    字段名
    数据类型
    是否为空
    默认值
    备注




    storied
    Int
    Not null

    存储编号,主键,标识列,初始值为1,增量为1


    userID
    Int
    Not null

    用户编号,外键,与userBasic表中userID字段关联


    cropID
    Int
    Not null

    作物编号,外键,与cropBasic表中cropID字段关联


    storeNumber
    Int
    Not null
    0
    用户仓库中存储的果实数量



    seedStoreInfo 种子存储列表



    字段名
    数据类型
    是否为空
    默认值
    备注




    storied
    Int
    Not null

    存储编号,主键,标识列,初始值为1,增量为1


    userID
    Int
    Not null

    用户编号,外键,与userBasic表中userID字段关联


    cropID
    Int
    Not null

    作物编号,外键,与cropBasic表中cropID字段关联


    storeNumber
    Int
    Not null
    0
    用户包裹中存储的果实种子数量



    plantInfo 种植列表



    字段名
    数据类型
    是否为空
    默认值
    备注




    plantID
    Int
    Not null

    种植编号,主键,标识列,初始值为1,增量为1


    userID
    Int
    Not null

    用户编号,外键,与userBasic表中userID字段关联


    soilID
    Int
    Not null

    游戏中被开垦的土地编号


    isReclaim
    Bit
    Not null
    0
    记录游戏中该块土地是否已被开垦;0代表未开垦,1代表已开垦


    cropID
    Int
    Not null

    作物编号,外键,与cropBasic表中cropID字段关联


    startTime
    Datatime
    Not null

    作物种植开始时间


    State
    Int
    Not null
    0
    作物生长期间的状态值,包括无、正常、杂草、有虫、干旱、积水六种状态分别用0、1、2、3、4、5代表


    Degree
    Int
    Not null
    0
    作物处于上述状态中的程度值;程度分为五级(x=2、4、6、8、10)



    friendsList 好友列表



    字段名
    数据类型
    是否为空
    默认值
    备注




    listID
    Int
    Not null

    列表编号,主键,标识列,初始值为1,增量为1


    userID
    Int
    Not null

    用户编号,外键,与userBasic表中userID字段关联


    friendID
    Int
    Not null

    好友编号



    4.2 表之间的关联设计
    0 评论 13 下载 2019-06-03 19:47:47 下载需要13点积分
  • 基于Cocos Creator开发的打砖块游戏

    一、简介
    Cocos简而言之就是一个开发工具,详见官方网站TypeScript简而言之就是开发语言,是JavaScript的一个超集详解官网
    今天我们就来学习如何写一个打砖块的游戏,很简单的一个入门级小游戏。
    二、实现过程2.1 布局部分首先来一个整体的工程界面:

    一看就很简单吧,就几个元素+脚本(之所以分开写是为了便于查错)。
    再来一个游戏界面:很简洁有木有?当然啦,美观的工作需要各位小伙伴自行发挥啦。好了,下面进入正题…









    游戏中画面
    游戏结束画面



    首先,创建一个新的“世界”名字叫game。将场景设置为640X960

    然后,你在这个世界花了1亿买了一块地皮,当然得有地契“BG”(在Canvas下新增一个空节点将大小改为640X960,或者你自己选择一张背景,拖在Canvas下设置大小就ok了,至于其他的就默认)

    好了,有地皮了,你就可以“为所欲为”了。先添加砖块吧:

    将砖块拖到Canvas下,然后拖回Texture就成了预制体(很简单有木有)。
    至于大小什么的可以用代码控制。
    因为是砖块,要和小球碰撞,所以要加上物理碰撞。

    知识点

    cc.RigidBodyType.Static:静态刚体,零质量,零速度,即不会受到重力或速度影响,但是可以设置他的位置来进行移动
    cc.RigidBodyType.Dynamic:动态刚体,有质量,可以设置速度,会受到重力影响
    cc.RigidBodyType.Kinematic:运动刚体,零质量,可以设置速度,不会受到重力的影响,但是可以设置速度来进行移动
    cc.RigidBodyType.Animated:动画刚体,在上面已经提到过,从 Kinematic 衍生的类型,主要用于刚体与动画编辑结合使用

    这里我们选择:

    Type:Static(静止),在那等着小球来碰撞。然后给他添加一个包围盒PhysicsBoxCollider
    PhysicsBoxCollider 类型,摩擦力、弹性系数请自由发挥


    再来是我们的主角:

    同样的给他一个碰撞组件,Type: Dynamic;然后添加包围盒

    下面就是托盘,也是Static

    然后添加一个空节点,大小比BG小一些,他的作用其实就是“围墙”,避免小球或托盘飞出场景。同时添加碰撞组件和包围盒。

    然后还有个foot_line,这个就是监测小球掉下去游戏结束。

    还有个count ,后面再说这个计数。好了,罗里吧嗦的布局就完成了。
    2.2 代码部分我们首先建一个game的游戏脚本,用来初始化一些节点(其实所有的代码都可以放在一个脚本里,但是遇到复制的程序的时候不便于查错,所以该分开写的还是要分开写。

    首先呢,我们要加载一些节点变量。写代码的时候带上注释是好习惯哦!
    我们来一个创建砖块的方法吧:

    我采用的是中规中矩的生成方法,通过i和j控制行和列,然后在设置横向间距即可最后生成的结果为:(其他的样式,只要找到规律生成即可。)

    再来我们看onload方法:

    第二句先忽略。因为小球和砖块碰撞会产生效果,所以要开启物理碰撞(默认是关闭的)。托盘是根据手指移动的,所以要监听手指的移动:
    知识点

    我们这里用touch_move,接着需要
    //获取点击的坐标并转换成节点坐标系坐标let eposition = self.node.convertToNodeSpaceAR(event.getLocation());
    然后设置托盘的位置即可。托盘是左右移动的,所以还需要控制他不能移出屏幕
    //控制不能移除屏幕let minx = -self.node.width / 2 + this.wall.width / 2;//最小坐标let maxx = -minx;if (this.wall.x > maxx) { this.wall.x = maxx;}if (this.wall.x < minx) { this.wall.x = minx;}
    场景开始加载的时候我们需要快速的生成好砖块,所以这用了定时器使用计时器
    //自动生成砖块self.schedule(function () { self.createbrick(); }, 0.2, 1);
    第一个参数就是回调方法,第二个是时间间隔,每隔多少秒调用一次,第三个是执行次数,默认为0执行一次。
    好了,初始代码完了,简单吧(其实还有些新增的东西,如障碍物和多个小球的生成,这个我们就后面再讲)。
    然后我把脚本挂在Canvas上,并把相应的节点和组件拖进去。运行可以看到已经生成了砖块了吧。

    再来我们看主角:ball,同样的给他创建一个脚本ball并挂在小球上。

    这个脚本的作用主要是检测,碰撞检测。关于碰撞标签tag,按顺序给碰撞体添加即可。

    onBeginContact(contact:cc.PhysicsContact,selfCollider:cc.PhysicsCollider,otherCollider:cc.PhysicsCollider):void{}
    用碰撞的tag来区分与小球(self)碰撞的是哪个碰撞体。如果是托盘,那就给小球一个速度。如果是托盘没接住小球掉下去了,游戏结束我们就要跳转到结束界面(后面讲)。
    接着就是砖块了:

    这个呢主要就是加分用的。基本是完工了,很简单的有木有。
    再来看结束的场景:

    创建一个结束的场景Sence,同样的需要一个脚本overcount,脚本里需要处理的是:

    接收主场景传过来的分数并做展示,此处我直接把节点给传过来了
    重新开始按钮功能


    第一个,分数节点,我们创建一个label节点但是因为要是常驻节点所以它和Canvas平级。

    然后新建一个脚本挂在此节点上
    onLoad () { cc.game.addPersistRootNode(this.node);}
    声明它为常驻节点。
    Brick.ts:当小球和砖块碰撞的时候呢,分数+1,并且要销毁砖块。
    if (otherCollider.tag == 0) {//球和砖块碰撞 let gamecc = cc.director.getScene().getChildByName('count').getComponent(cc.Label); gamecc.string = String(Number(gamecc.string) + 1); this.node.destroy();
    拿到分数后,ball.ts:
    if(otherCollider.tag==5){//球和foot_line碰撞 cc.director.getPhysicsManager().enabled = false; cc.find('Canvas').destroyAllChildren(); cc.director.loadScene('over'); }
    如果小球掉下去了(托盘没接到),然后我们将小球的物理状态关掉,清除game场景下的所有节点并跳转到结束场景over。
    Over场景中有一个重新开始的按钮overcount.ts:
    需要做的就是获取分数并将分数复制给结束界面的Label,然后隐藏此常驻节点。
    let gamecount = cc.director.getScene().getChildByName('count').getComponent(cc.Label);gamecount.node.active = false;this.overcount.string = gamecount.string;self.again.on(cc.Node.EventType.TOUCH_START, function () { gamecount.string = String(0); cc.director.loadScene('game'); }, self)
    点击重新开始按钮,那么需要把分数置为0,当然还没完,前面我们是关闭了分数计数节点,现在需要打开Game.ts
    onLoad() { let self = this; //开启分数节点 cc.director.getScene().getChildByName('count').getComponent(cc.Label).node.active = true;
    好了,到这你就可以让你的程序跑起来了。
    2.3 新增功能障碍物
    障碍物很简单的,也是通过预制体,然后给它上面挂个label用来当小球碰到障碍物的时候,这个数值自减最后在总分数上加上这个分值。

    创建一个bar脚本并挂在此节点上,Bar.ts

    脚本的作用呢就是给障碍物一个常量,小球和障碍物每碰撞一次就减1,当小于1 的时候就给总发加上3分。
    好了,大概就是这些了,项目其实很简单。多练、多写ヾ(◍°∇°◍)ノ゙
    还有添加隐藏的小球,碰撞后生成多个小球!这个请小伙伴自行发挥了…
    1 评论 12 下载 2019-05-29 11:04:12 下载需要12点积分
  • 基于c语言的一个很好玩的整人小游戏,让你不仅仅拘泥于小黑方框(适合新手)。

    这是一个很有意思的小游戏,是本人自己写的一个c语言程序,内容相对很简单,可以让你的电脑关机,同时还可以调一些本电脑中的图片音乐,体会到不一样的乐趣。再也不是死板的小黑框了。上传的压缩包含有所有内容,请自取。
    下面我来详解一下我的小程序:
    close()函数,因为是整人小程序,那么必不可少的是关机!
    int close() { printf("你终于是走到了这一步,还有五十秒重启,抽支烟冷静一下,等待重启吧!\n"); system("shutdown -r -t 50"); return 0;}
    system(“shutdown -r -t 50”);这一句是调用系统命令,相当于你从DOS命令框中输入命令,本程序的核心也正是围绕此处展开的。
    wanjiu()函数,是让人有复活的机会,具体指令参考源码。
    剩下的主要核心是switch语句,让用户不断的选择,以完成闯关。
    运行中的细节图:





    0 评论 4 下载 2019-05-27 11:29:25 下载需要8点积分
  • 基于c语言的表白神器,闪烁心。

    这个实例相对是比较简单的,核心的内容有以下几点:
    借助一个数组,将用户的输入信息赋值给数组,其中元素是“yes”则开始动画。
    画心代码如下:
    for (y = 1.5f; y > -1.5f; y-=0.1f)//画心形图案 { for (x = -1.5f; x < 1.5f; x += 0.05f) { z = x*x + y*y -1; f = z*z*z - x*x*y*y*y; putchar(f <= 0.0f ? "*********"[(int)(f*-8.0f)]:' '); } putchar('\n');}
    以9个*为一组,这样可以快速填充。
    system("color a");
    system函数,用于更改控制台的参数的函数,color a意为更改颜色;
    for(time=0;time<99999999;time++);
    每隔一段时间换一种颜色,实现颜色跳跃。
    0 评论 14 下载 2019-05-27 11:29:12 下载需要8点积分
  • 基于SSH框架的电影订票系统网站的设计与实现

    1 总体描述1.1 产品前景目前国内市场上的电影购票网站很多,各个网站都有一定的用户量。用户还处于一种培养习惯的阶段。鉴于目前各个购票网站的质量参差不齐,许多网站都把大部分内容堆积在其首页,我们如果能够做一款用户体验极佳的购票网站,用户有好的体验过程,再加上我们网站特有的功能,用户就会慢慢习惯使用我们的网站,长远看来这有很大的商业机遇。
    在我们购票网站中,我们可以通过与影片制片方合作,在我们网页中推荐其即将上映的影片,只要我们的网站流量足够,这无疑会是一个很大的商机。
    1.2 产品功能
    记录销售交易与实时票务统计 支付交易(使用第三方交易网站进行交易)用户账号的安全性管理电影的介绍以及基本了解提供喜欢电影的推荐以及提醒功能针对不同使用场景下的自适应界面基于行业标准,与第三方库进行实时交易,包括电影票务、支付、院线、选座系统等
    1.3 用户类及其特征
    普通用户:以消遣为主,内容消费较少,对网站的使用体验比较在意,对网 站能够提供的附加功能比较敏感电影爱好者:对于电影有内容和题材偏好,有喜欢的导演和演员。在意网站 推荐的的电影,在意网站提供关于影片的评价专业影评人:很在意网站上的评论功能,提供好的评论交互方式会吸引这样 的用户
    1.4 运行环境支持PC端网页访问,移动端暂不支持
    1.5 开发环境和工具
    终端支持:PC
    开发语言框架:HTML5,CSS3,JavaScript
    服务器端支持
    语言:Java,Python
    Web框架:Struts MVC + Spring Boot,Hibernate
    关系数据库:MySQL
    负载均衡机制:Nginx
    开发平台与工具
    IDE:eclipse
    集成与测试:Travis
    源代码管理:Github
    项目管理与自动构建:maven

    1.6 开发规范
    WEB前端
    语言:Javascript,html,CSS
    代码风格:JS ES5代码风格;ES6代码风格;CSS代码风格;HTML/CSS代码风格
    自动化检测工具:ESLint
    WEB后端
    语言:Java
    代码风格 Google Java Style(科学上网),中文翻译
    自动化检测工具:Checkstyle(Ecplise 插件安装教程)
    爬虫脚本
    语言:Python 3.6+
    代码风格:Python风格规范

    1.7 设计和实现上的约束
    设计约束:改变现有购票网站较为杂乱的整体局面,剔除购票流程的冗 余过程,符合现代年轻人审美,尽量做到简洁、美观、大方
    可用性:系统需要提供较为完整的第三方接口,以供院线使用。功能完 备,贴合用户要求,能够提供较好的电影购票体验
    可靠性:使用行业标准,以便于部不同的第三方接口进行信息交换。有 一定的防差错功能,能保证高峰时期的购票正常
    可支持性:标准的接口,在进行信息交换的时候流畅无差错。

    1.8 假设和依赖本平台依赖于PC端运行环境,后台是使用了JAVA进行编写,使用了MySQL数据库管理系统对用户信息、电影及影院信息进行管理,前端页面显示使用了MVC框架。
    2 系统功能


    ID
    Name
    Imp
    Est
    How to demo
    Notes




    0
    搜索框
    7
    8
    可搜索影片、影院



    1
    电影 (按钮)
    8
    12
    点击主页面上方“电影”按钮,根据当前电影热度,票房,评分等列出现在上映的所有电影,每个电影的小项里包括名字,影片时长,类型,主演,评分以及选座购票按钮
    需要用户授权定位,也可点击定位,手动选择定位


    2
    影片详情
    9
    12
    页面包括名字,影片时长,上映日期,影片简介,影片评分,影片海报,可选影院部分(推荐)列表,导演编剧等各项信息及选座购票按钮
    影片评分我们提供豆瓣,烂番茄,时光网等不同影评网站的评分,使用户参考更多样


    3
    选座购票
    10
    9
    从影片列表或者影片详情页都可点击选座购票
    会有影院列表,点击进去就会看到场次票价,用户可根据需求选择场次,座次


    4
    即将上映
    5
    6
    在主页面中,给出近期即将上映的所有电影
    点击每个分项会进入影片详情页


    5
    登录
    3
    11
    点击主页面“登录”,进入登录界面,输入用户名密码即登陆成功
    在登录界面包含注册按钮,账户可与社交账号绑定或绑定邮箱,要与手机绑定(用于短信提醒)


    6
    我的主页
    6
    8
    登陆成功后,点击主页面“我的”,进入我的主页
    含有电影票订单、优惠方式、收藏三大类,其中优惠方式包含折扣卡、红包、现金券等;收藏分为电影收藏、影院收藏、活动收藏



    3 数据库实体关系图

    实体定义

    user 表:用户表,记录用户的信息,用户名,密码的 MD5,电话,邮箱movie 表:记录电影的信息,包括中文名,英文名,电影类型,电影时长,上映日期,电影简介,电影海报的 URL,参演人员名单 person 表:记录电影人的信息,通过 type 列区别是导演还是演员,包括名字,照片 URL,type 电影人的类型(导演/演员) cinema 表:订单编号,电影 id、影院 id、场次 id、座位 id screen 表:荧屏 id,语言,价格,房间 id,时间,影院 id,电影名字,座位 id admin 表:id,名字,密码,email,电话号码movie 表和 person 表是一对多的关联映射关系
    四、总体设计4.1 概念术语描述(后端)4.1.1 Java
    java是纯面向对象编程的语言平台无关性 (一次编译,到处运行;Write Once,Run Anywhere)java提供了许多内置的类库,通过这些类库,简化了开发人员的设计工作,同时缩短了项目开发时间提供了对Web应用开发的支持,例如,Applet,Servlet,和JSP可以用来开发Web应用程序,,Socket,RMI可以用来开发分布式应用程序的类库去除了c++中难以理解,容易混淆的特性(如c++中的多继承,头文件,指针,结构,单元,运算符重载,虚拟基础类,使得程序更加严谨,整洁具有较好的安全性和健壮性。java语言经常会被用在网络环境中,为了增强程序的安全性
    4.1.2 SpringSpring Framework(简称Spring)是根据Rod Johnson著名的《Expert One-on-One J2EE Design and Development》而开发的J2EE应用程序框架。目前主要根据Rod Johnson和Juergen Hoeller而进行开发的,目前发布的最新版为1.1.4。 Spring是J2EE应用程序框架,不过,更严格地讲它是针对Bean的生命周期进行管理的轻量级容器(Lightweight container),可以单独利用Spring构筑应用程序,也可以和Struts,Webwork,Tapestry等众多Web应用程序框架组合使用,并且可以与Swing等桌面应用程序API组合。所以Spring并不仅仅只能应用在J2EE中,也可以应用在桌面应用及小应用程序中。针对Spring开发的组件不需要任何外部库。
    优点:

    Spring能有效地组织你的中间层对象Spring能消除在许多工程中常见的对Singleton的过多使用Spring能消除各种各样自定义格式的属性文件的需要,使配置信息一元化Spring能够帮助我们真正意义上实现针对接口编程在Spring应用中的大多数业务对象没有依赖于Spring使用Spring构建的应用程序易于单元测试Spring支持JDBC和O/R Mapping产品(Hibernate)MVC Web框架,提供一种清晰,无侵略性的MVC实现方式JNDI抽象层,便于改变实现细节,可以方便地在远程服务和本地服务间切换简化访问数据库时的例外处理Spring能使用AOP提供声明性事务管理,可以不直接操作JTA也能够对事务进行管理提供了JavaMail或其他邮件系统的支持
    4.2 概念术语描述(前端)5.2.1 Vue.jsVue.js(读音 /vjuː/, 类似于 view)是一个构建数据驱动的 web 界面的库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。
    优点:

    响应式编程:mvvm框架,实现数据的双向绑定组件化:一切都是组件,组件可以套其他组件,增强了可复用性模块化:我们用一个模块打包工具来配合 Vue.js,比如Webpack或者Browserify,然后再加上 ES2015。每一个 Vue 组件都可以看做一个独立的模块动画:Vue 自带简洁易用的过渡动画系统。有很多获奖的互动类网站是用 Vue 开发的。Vue 的反应式系统也使得它可以用来开发高效的数据驱动的逐帧动画路由:Vue 本身是不带路由功能的。但是,有vue-router这个可选的库来配合。vue-router 可以将嵌套的路径映射到嵌套的组件,并且提供了细致的路径跳转控制文档和配套设施:文档和配套设施完善,社区活跃,生态系统完备,易于上手
    4.2.2 ES6(ECMAScript 6)新一代的javascript也被称为ECMAScript 6(也称为 ES6 or Harmony)。
    优点:

    糖语法:首先,语法糖是一种语法,使得语言更容易理解和更具有可读性,它使语言相对我们来说变得更”甜”。这也意味着ES6的一些”新”的特点并不是真的新,只是试图简化语法而已,让我们编程更容易。这样就无需使用老式的取巧的方法编写你的代码,而是可以一种更简单的方式来编写代码,那就是使用糖语法模块Module:如果你想将所有js放在一个文件中,或者你要在应用的不同地方使用相同的功能,你就要使用模块,关键词是exportlet和const:在一段代码块中用let或者const声明的变量会限制它们只在这个块中可见。这叫做块级作用域
    4.3 基本设计描述4.3.1 系统总体逻辑结构图
    4.3.2 系统部署结构图
    4.4 主要界面流程描述
    4.5 模块列表4.5.1 模块划分


    后端
    前端









    4.5.2 前端结构
    4.6 Web服务器4.6.1 返回的状态码


    类型
    stateCode
    info




    成功
    200
    NULL


    错误
    500
    错误信息



    4.6.2 用户登录/注册


    路由
    方法
    说明
    提交格式
    测试




    /api/login
    POST
    提交用户登录表单 username, password, 允许邮箱/手机/用户名登录

    OK


    /api/signup
    POST
    提交用户注册表单 username, password, email, phone

    OK


    /api/logout
    PUT
    登出

    OK


    /api/user
    GET
    获取当前用户信息

    OK


    /api/user
    PUT
    修改当前用户信息,填写需要修改的项,username,email,phone,oldPassword,newPassword

    OK


    /api/user/order
    GET
    查看该用户的所有订单
    OrderModel
    OK


    /api/user/screen/{id}
    PUT
    锁定/购买座位,需要上传 需要用户登录后
    eat={88长字符串, 锁定的位置用1表示,购买位置用2表示,其他用0填充}



    // 购票例子:// 表单格式:seat=1100000000000000000000000000000000000000000000000000000000000000000000000000000000000000// 表示锁定第1,2个位置seat=0022000000000000000000000000000000000000000000000000000000000000000000000000000000000000// 表示购买第1,2个位置// 购买前需要先锁定public class OrderModel { private List<FilmOrder> filmOrderModelList;}public class FilmOrder { private Integer id; private User user; private Integer screenId; private String seat;}
    4.6.3 管理员账号


    路由
    方法
    说明
    提交格式




    /api/admin/login
    POST
    adminname, password 登录



    /api/admin/logout
    PUT
    登出



    /api/admin/newMovie
    POST
    需要填写的域chineseName,englishName,pictureUrl,type,length,releaseDate,introduction



    /api/admin/{id}
    DELETE
    当初对应id的电影



    /api/admin/{id}
    PUT
    更新电影信息,只需要填写需要更新的域,和创建电影的域名字相同



    /api/admin/cinema/{id}
    DELETE
    参数对应id的影院



    /api/admin/cinema/create
    POST
    创建一个影院
    CinemaModel


    /api/admin/cinema/{id}
    PUT
    修改一个影院信息
    CinemaModel



    CinemaModel { private String name; private String address; private String phone; private List<Screen> screens;}
    4.6.4 获取电影信息


    路由
    方法
    说明
    返回值
    测试




    /api/movie/name/{查询电影名}
    GET
    返回电影名对应信息,允许查询中英文电影名,返回一条记录或空
    SimpMovie
    OK


    /api/movie/type/{type}?id=ID
    GET
    返回电影类型列表, 数目为从id开始往后20条,默认id = 0
    List
    OK


    /api/movie/date/day/20170501
    GET
    返回2017-05-01上映的电影列表,如果输入非法日期,返回当天上映列表
    List
    OK


    /api/movie/date/month/201705
    GET
    返回2017-05上映的电影列表,如果输入非法日期,返回当月上映列表
    List
    OK


    /api/movie/date/year/2017
    GET
    返回2017上映的电影列表,如果输入非法日期,返回当年上映列表
    List
    OK


    /api/movie/{id}
    GET
    返回ID=id的电影详细信息
    Movie
    OK


    /api/movie/showing/{number}
    GET
    返回最近一个月上映的电影列表,number条
    List
    OK


    /api/movie/query/count?type={}&area={}&year={}
    GET
    year=2007, 允许type,area,year字段为”all”
    Integer
    OK


    /api/movie/query?type={}&area={}&year={}&page={}&step={}
    GET
    返回 [pagestap, pagestep+step]的数据,允许type,area,year字段为”all”
    List
    OK



    SimpMovie { private String name; private Integer id; private String url;}
    4.6.5 获取演员/导演信息


    路由
    方法
    说明
    返回值
    测试




    /api/person/{id}
    GET
    通过演员/导演的ID获取
    Person
    OK


    /api/person/movie/{id}
    GET
    获取电影ID的演员/导演名单
    List
    OK



    Person { private Integer id; // 名字 private String name; // 照片的URL private String url; // 表示是导演还是演员 private String type; // "actor", "director"}
    4.6.6 获取影院信息


    路由
    方法
    说明
    接受内容
    返回值
    测试




    /api/cinema?number={}&address={}
    GET
    number选填默认10,address必填

    List



    /api/cinema/{id}
    GET
    返回影院详细信息

    Cinema
    OK


    /api/cinema/showing?id={id}
    GET
    返回正在该影院上映的电影简要信息列表

    List
    OK



    SimpCinema { private Integer id; private String name;}Cinema { private Integer id; private String name; private String address; private String phone; private List<Screen> screens;}
    4.6.7 获取排片信息


    路由
    方法
    说明
    接受内容
    返回值
    测试




    /api/screen?cinemaid={}&movieid={}&date={}&time={}
    GET
    获取对应影院对应电影的排片情况列表

    List
    OK


    /api/screen/{id}
    GET
    获取对应id的排片情况

    Screen
    OK



    Seat { private List<Integer> vacancy; private List<Integer> soldOut; private List<Integer> locking;}Screen { private Integer id; private Date time; private String language; private String room; private Double price; private Cinema cinema; private String movieName; private String seats; // '0'->空位,'1'->被锁定,'2'->已售出 8x11 列优先, 比如2行1列下标为8}
    4.6.8 搜索功能


    路由
    方法
    说明
    返回值
    测试




    /api/search?query={}






    五、软件设计技术5.1 前后端分离5.1.1 理解MVCMVC是一种经典的设计模式,全名为Model-View-Controller,即模型-视图-控制器。
    其中,模型是用于封装数据的载体,例如,在Java中一般通过一个简单的POJO(Plain Ordinary Java Object)来表示,其本质是一个普通的java Bean,包含一系列的成员变量及其getter/setter方法。对于视图而言,它更加偏重于展现,也就是说,视图决定了界面到底长什么样子,在Java中可通过JSP来充当视图,或者通过纯HTML的方式进行展现,而后者才是目前的主流。模型和视图需要通过控制器来进行粘合,例如,用户发送一个HTTP请求,此时该请求首先会进入控制器,然后控制器去获取数据并将其封装为模型,最后将模型传递到视图中进行展现。
    综上所述,MVC的交互过程如图1所示。

    5.1.2 MVC模式的优点与不足MVC模式早在上个世纪70年代就诞生了,直到今天它依然存在,可见生命力相当之强。MVC模式最早用于Smalltalk语言中,最后在其它许多开发语言中都得到了很好的应用,例如,Java中的Struts、spring MVC等框架。正是因为这些MVC框架的出现,才让MVC模式真正落地,让开发更加高效,让代码耦合度尽量减小,让应用程序各部分的职责更加清晰。
    既然MVC模式这么好,难道它就没有不足的地方吗?我认为MVC至少有以下三点不足:

    每次请求必须经过“控制器->模型->视图”这个流程,用户才能看到最终的展现的界面,这个过程似乎有些复杂。
    实际上视图是依赖于模型的,换句话说,如果没有模型,视图也无法呈现出最终的效果。
    渲染视图的过程是在服务端来完成的,最终呈现给浏览器的是带有模型的视图页面,性能无法得到很好的优化。

    为了使数据展现过程更加直接,并且提供更好的用户体验,我们有必要对MVC模式进行改进。不妨这样来尝试,首先从浏览器发送AJAX请求,然后服务端接受该请求并返回JSON数据返回给浏览器,最后在浏览器中进行界面渲染。
    改进后的MVC模式如图2所示。

    也就是说,我们输入的是AJAX请求,输出的是JSON数据,市面上有这样的技术来实现这个功能吗?答案是REST。
    REST全称是Representational State Transfer(表述性状态转移),它是RoyFielding博士在2000年写的一篇关于软件架构风格的论文,此文一出,威震四方!国内外许多知名互联网公司纷纷开始采用这种轻量级的Web服务,大家习惯将其称为RESTful Web Services,或简称REST服务。]
    如果将浏览器这一端视为前端,而服务器那一端视为后端的话,可以将以上改进后的MVC模式简化为以下前后端分离模式,如图3所示。

    可见,有了REST服务,前端关注界面展现,后端关注业务逻辑,分工明确,职责清晰。那么,如何使用REST服务将应用程序进行前后端分离呢?我们接下来继续探讨,首先我们需要认识REST。
    5.1.3 认识RESTREST本质上是使用URL来访问资源种方式。众所周知,URL就是我们平常使用的请求地址了,其中包括两部分:请求方式与请求路径,比较常见的请求方式是GET与POST,但在REST中又提出了几种其它类型的请求方式,汇总起来有六种:GET、POST、PUT、DELETE、HEAD、OPTIONS。尤其是前四种,正好与CRUD(Create-Retrieve-Update-Delete,增删改查)四种操作相对应,例如,GET(查)、POST(增)、PUT(改)、DELETE(删),这正是REST与CRUD的异曲同工之妙!需要强调的是,REST是“面向资源”的,这里提到的资源,实际上就是我们常说的领域对象,在系统设计过程中,我们经常通过领域对象来进行数据建模。
    REST是一个“无状态”的架构模式,因为在任何时候都可以由客户端发出请求到服务端,最终返回自己想要的数据,当前请求不会受到上次请求的影响。也就是说,服务端将内部资源发布REST服务,客户端通过URL来访问这些资源,这不就是SOA所提倡的“面向服务”的思想吗?所以,REST也被人们看做是一种“轻量级”的SOA实现技术,因此在企业级应用与互联网应用中都得到了广泛应用。
    下面我们举几个例子对REST请求进行简单描述:可以查看API来更好地理解。
    可见,请求路径相同,但请求方式不同,所代表的业务操作也不同,例如,/advertiser/1这个请求,带有GET、PUT、DELETE三种不同的请求方式,对应三种不同的业务操作。
    虽然REST看起来还是很简单的,实际上我们往往需要提供一个REST框架,让其实现前后端分离架构,让开发人员将精力集中在业务上,而并非那些具体的技术细节。下面我们将使用Java技术来实现这个REST框架,整体框架会基于Spring进行开发。
    5.2 Vue渐进式框架5.2.1 为什么要有框架框架的存在是为了帮助我们应对复杂度
    前端框架特别多,那么为什么要有框架呢?框架的存在是为了帮助我们应对复杂度。当我们需要解决一些前端上工程问题的时候,这些问题会有不同的复杂度。如果你用太简陋的工具应对非常复杂的需求,就会极大地影响你的生产力。所以,框架本身是帮我们把一些重复的并且已经受过验证的模式,抽象到一个已经帮你设计好的API封装当中,帮助我们去应对这些复杂的问题。
    框架自身也有复杂度
    框架本身也会带来复杂度。相信大家在调研各种框架或学习各种框架时,会遇到学习曲线问题——有些框架会让人一时不知如何上手。
    工具复杂度是为了处理内在复杂度所做的投资
    工具的复杂度是可以理解为是我们为了处理问题内在复杂度所做的投资。为什么叫投资?那是因为如果投的太少,就起不到规模的效应,不会有合理的回报。这就像创业公司拿风投,投多少是很重要的问题。如果要解决的问题本身是非常复杂的,那么你用一个过于简陋的工具应付它,就会遇到工具太弱而使得生产力受影响的问题。
    反之,是如果所要解决的问题并不复杂,但你却用了很复杂的框架,那么就相当于杀鸡用牛刀,会遇到工具复杂度所带来的副作用,不仅会失去工具本身所带来优势,还会增加各种问题,例如培训成本、上手成本,以及实际开发效率等。
    Pick the right tool for the job
    “Pick theright tool for the job”——在国外,跟开发者讨论一些框架选型问题时,大家都会说这句话——一切都要看场景。因为,前端开发原生开发或者桌面开发模式相比,有自己的独特之处,它跟其实并不那么固定。在Web上面,应用可以有非常多的形态,不同形态的Web应用可能有完全不同程度的复杂度。这也是为什么要谈工具复杂度和所要做的应用复杂度的问题。
    怎么看前端框架的复杂度
    目前的前端开发已经越来越工程化,而我们需要解决的实际问题也是不同的。我们就下图进行分析。

    我们可能在任何情况下都需要声明式的渲染功能 ,并希望尽可能避免手动操作,或者说是可变的命令式操 ,希望尽可能地让DOM的更新操作是自动的,状态变化的时候它就应该自动更新到正确的状态;我们需要组件系统,将一个大型的界面切分成一个一个更小的可控单元; 客户端路由 ——这是针对单页应用而言,不做就不需要,如果需要做单页应用,那么就需要有一个URL对应到一个应用的状态,就需要有路由解决方案; 大规模的状态管理 ——当应用简单的时候,可能一个很基础的状态和界面映射可以解决问题,但是当应用变得很大,涉及多人协作的时候,就会涉及多个组件之间的共享、多个组件需要去改动同一份状态,以及如何使得这样大规模应用依然能够高效运行,这就涉及大规模状态管理的问题,当然也涉及到可维护性,还有构建工具。现在,如果放眼前端的未来,当HTTP2普及后,可能会带来构建工具的一次革命。但就目前而言,尤其是在中国的网络环境下,打包和工程构建依然是非常重要且不可避免的一个环节。
    5.2.2 渐进式框架Vue.jsVue.js现状
    以下数据可以体现出Vue.js的现状。

    前一段时间突破了三万星(如下图所示),总下载量过百万。

    官网上每个月的用户量为26万,这个应该是不包含中国区数据。官方开发者插件的周活跃用户数在5万5左右。这个数据是我觉得最有说服力的数据。安装并且使用开发者插件的Vue用户,应该会在实际生产中真正频繁使用Vue。
    Google搜索趋势的相关数据如下图所示。图中,绿色的是Backbone的数据,黄色是Ember,红色是React,蓝色是Vue。可以看出React和Vue近两年发展势头都比较迅猛。可以看出,Vue的曲线开始的是很早,2013年已经开始,但是有很长一段时间的增长是比较低的。因为在那一段时间我还在谷歌工作,Vue基本上是作为个人项目在运营。在过去一两年中,Vue获得了非常大的突破性发展。这个图里没有Angular,因为Angular的量还是非常大的,如果放进去就破表了。

    这些数据并不能绝对地代表框架当前的热度,但有一定的参考价值。可以看到React的势头很足。而由Vue的曲线还可以看出它的增长速度还在不停上扬。
    Vue的定位
    它与其他框架的区别就是渐进式的想法,也就是“Progressive”——这个词在英文中定义是渐进,一步一步,不是说你必须一竿子把所有的东西都用上。
    Vue的设计
    接下来我们回到之前看的图:

    Vue从设计角度来讲,虽然能够涵盖这张图上所有的东西,但是并不需要一上手就把所有东西全用上 ,因为没有必要。无论从学习角度,还是实际情况,这都是可选的。声明式渲染和组建系统是Vue的核心库所包含内容,而客户端路由、状态管理、构建工具都有专门解决方案。这些解决方案相互独立,你可以在核心的基础上任意选用其他的部件,不一定要全部整合在一起。
    6 系统演示电影订票网站首页

    会员注册

    会员登录

    查找电影
    6 评论 185 下载 2018-10-05 23:12:23 下载需要14点积分
  • 基于JAVA实现的游戏大厅

    一、概述服务器端分为五大部分:服务器的管理,用户信息管理和储存,游戏服务器的实现,大厅信息的更新与转发以及针对用户的线程管理。
    服务器的整体架构图

    游戏大厅可完成三人斗地主,双人五子棋对战,大厅内聊天等功能。
    二、服务器的管理首先进入服务器登陆界面,初始的账号和密码分别为admin和123456。文件存储在文件目录下的“log/administrator”,以“admin&123456”进行AES加密后进行base64加密储存。此文件必须保证存在且正确,若文件不存在或被修改,系统将不能登陆。
    2.1 菜单栏四个选项:

    开启服务器
    关闭服务器
    退出,以正常方式退出,在退出时会将内存中的用户数据放入磁盘中
    强制退出,有风险,可能会未正常保存用户数据,并且使客户端报错,用于紧急情况

    2.2 在线人员查看开启服务器后,客户端可进行连接,连接成功后,会更新表中数据。断开连接功能可单选或多选恶意人员进行强制中断连接。
    2.3 按钮功能共有五个按钮:

    刷新数据库:可让服务器强制进行一次数据刷新,将磁盘中的用户信息刷新
    显示/关闭游戏大厅:可打开大厅的监控界面
    与客户端不同的是,服务器会广播人员的上线信息,并显示各大厅的在线人数
    刷新公告: 公告的信息在“log/notice.html”进行修改,每次修改保存后可刷新服务器中的公告,随后改变后来新登陆的人的公告栏信息
    查询账号信息:可查询某个账号的个人信息
    显示/关闭监视器:系统运行的每个步骤都将记录到文档中,可查看系统正在运行中的日志系统,日志系统将保存到“log/activity”中

    其中监视器,用来显示系统进行中的操作,以及可以显示用户选择大厅信息,以及状态信息的更新,均会记录到文档中。磁盘中文件日志的储存,以单位日为时间轴进行。因为是实时更新的,可以防止系统因崩溃找不到日志文件,方便管理员进行对服务器的维护以及管理。
    以上为服务器主框架的大致介绍,服务器的功能还包括有定时刷新数据库,定时刷新重置次数,黑白名单(当客户端进行对客户端的非法操作时加入黑名单,白名单方便管理人员测试管理)等。
    三、用户信息管理和储存用户的信息储存在一颗B+树上,树的阶数视用户的估计数量而定,在测试中测试用户有十万个,所以采用的是万阶B+树,查找速度均在毫秒之内。B+树的插入与删除速度也均在毫秒之内。B+树的序列化采用将树和树上每一个叶节点通过ObjectOutputStream写入文本文档中。B+树上的每个叶节点有一个键值对存储着每一个Account信息。在找到用户对应的哈希值范围时,再对叶节点的键值对取出用户对象。在未来版本中,可以实现在服务器端修改用户的个人信息,volatile保证树是最新的树,将修改的数据马上刷新到主存。
    在存储用户信息的过程中,对用户的密码、密保问题、密保答案均进行AES加密,加密密钥为“log/aes.key”,只有密钥正确才能在初始化时读取到用户的正确信息。用户的管理和存储包括:

    注册:会修改树的信息,所以采用线程同步锁;每个人注册都会由系统分配一个对应的Id给用户,类似于QQ
    登陆:在登陆过程中因涉及敏感操作,所以在传输过程中,采用服务器发送公钥给客户端,加密后由服务器解密,防止用户信息的暴露在网络中
    注销:即设置在线状态为false,关闭连接与线程
    重置密码(将重置失败次数超过三次的用户禁掉,并每24小时自动刷新重置的次数)
    修改昵称头像等

    在用户使用此客户端时,能捕捉用户的异常输入与操作,并对用户发出信息,如收到的信息格式不符合要求,或者收到非法信息等。登陆成功后,即可进入大厅进行操作。
    四、大厅信息的更新大厅信息包括斗地主游戏大厅和五子棋游戏大厅的桌子状态以及更新、大厅聊天信息的更新、大厅公告栏的更新。
    桌子状态的更新采用TCP协议与每个用户建立连接,收取用户的动作状态,如坐下、准备、站起来,存储在对应的容器Vector中,并通过函数对在相同大厅的人进行转发,其他大厅或未选择大厅的用户将无法收取动作信息。每次用户选择大厅点击确认后将会收到全部桌子状态进行刷新。
    实现此功能的是Gobang_Tables.java和Landlord_Tables.java两个文件。当发送桌子的状态信息失败的时候(即网络阻塞或客户端异常断开时),程序会捕捉异常并及时把异常用户移出列表并关闭用户,防止二次异常。
    大厅聊天信息采用UDP协议接收用户发来的聊天信息,并可以显示在服务器的游戏大厅上并对所有在线的用户在进行转发。
    大厅公告栏通过发送html文本给客户端进行更新,html文件可在“log/notice.html”修改,不再重复叙述。
    五、针对用户的线程管理因为对每一个建立了TCP连接的客户,都会分配一个线程进行处理,所以将进行对用户的线程管理。
    首先设置对用户操作时间超时,测试设置了20分钟,当用户超过这个时间没有任何动作时,服务器便会自动断开用户的连接,防止内存过度消耗。
    同时,考虑到大用户量,便必然会引发并发问题,所以在服务器中,设置了阻塞队列,当服务器并发处理数量达到一定值,服务器便拒绝接收客户端的登陆,将优先处理前面的客户端。
    最后,对用户操作有异常超过两次的,会加入服务器黑名单列表。
    六、测试截图6.1 服务器测试截图





    6.2 客户端测试截图





    1 评论 11 下载 2019-05-12 17:53:51 下载需要13点积分
  • 基于Qt和Mysql的学生信息管理与收发系统

    哈哈哈,小白在学校期间的练手作品,很粗糙,很简陋,bug也有,但是对于新手来说还是很具有参考价值的,不喜勿喷,指出问题,共同进步。
    项目简介
    项目名称:学生信息管理与收发系统(客户端+服务器)-(学生端-服务器-教师端)
    使用工具:QT Creator 5.6 + Mysql5.6;
    使用技术:C/S(客户端-服务器)、TCP/IP(协议)、socket、多线程、数据库;
    项目描述:

    服务器:服务器监听一个IP地址,用来连接教师端和学生端,用于数据转发(eg:教师端发消息到服务器,在由服务器发消息到学生端)教师端:教师端的主要功能是选择需要发送的学生(可以发送给不在线学生),输入将要发送给一部分学生的表格名(标题),和1-8个字段名(不能重复,因为数据库中的字段名不能重复),在点击发送后由服务器转发给学生端。在学生端收到消息并且提交消息后可以查询学生的信息和提交的信息,还可以将数据表导出成xls文件。文件发送还没有完成0.0…..学生端:学生端可以编辑个人信息。学生端可以查询收到的并未提交的数据表并且提交信息。(可以收到离线信息)(在线学生收到消息提示后从数据库中查找教师端所发出的数据)(不在线学生在上线后从数据库中查找数据)。文件发送还没有完成0.0……
    注意事项:本系统只能用于局域网中的数据传输,并且由于本项目是在学校完成后并没有改动,所以服务器所监听的地址为我本身的地址,在下载后本系统是不可用的。还有就是数据库的问题,数据库是我在花钱买的一个远程服务器上搭建的,所以数据库也是不可用的。因此

    在拿到本系统的代码时应该修改IP地址(服务器-教师端-学生端)改为你所需要的在拿到本系统的代码时应该把我所发的数据库加入到你的数据库中,并且修改代码中跟数据库有关的代码

    服务器

    教师端

    学生端

    程序代码我就不贴了,自己下载看吧~
    0 评论 15 下载 2019-05-08 15:13:43 下载需要11点积分
  • 基于C#的对WORD文件修改的小系统

    一、背景亲戚在家乡的一家电影放映场工作,由于不太先进的设备,导致每一次打印机打出都号码都与座位号对应不上,所以就跟我聊,问能不能写一个方便一点的小系统。
    二、抽象设计2.1 选择编程语言这个小代码的难点是如何操作(WORD文本)以及如何方便安装使用,至于性能,可能不需要考虑的太多。由于之前写了两个JAVA与PHP的WEB网站,就想用WEB网站的形式。但是由于需要稳定服务器就被迫放弃了,因为没有必要。简单调研了一下,决定用C#编写一个单机版的客户端小程序。一是因为简单,二是因为c#对word的操作应该更好支持。
    2.2 是否选择数据库如上面所言,使用数据库还要安装,使用线上资源没必要,而且就算使用本地数据,由于操作可能需要一定的技术功底,所以也暂时放弃。
    2.3 程序设想一个单机版的可以通过word模板去生成对应的电影票信息的word文本的软件。

    并且要在每一步对应打上log,方便纠错与统计。
    三、难点解析c#直接使用net框架很方面的完成图形界面的编写以及按钮的颜色改变,按钮信息获取等,这些就不再阐述了,接下来我主要写一下关于如何使用c#操作word以及如何编写一个简单的日志类。

    已售出自动修改为红色且不再可选,点击座位号,确认可以生成对应word。
    3.1 操作word模板c#操作word的两种方式:
    3.1.1 使用 office.Core.dll 引用
    直接添加引用,搜索office就可以,它使用的是你电脑office上的dll引用,不过感觉上使用起来比较复杂。推荐第二种。
    3.1.2 使用 Aspose.WORD for net 进行操作Aspose 官网下载 此处需要google CSDN下载(破解版)。
    操作WORD:使用上面两种方式操作一个word文件都是很麻烦的,因为word和txt不同,它有很多编码,字号缩进等设置,要找到编辑的地方很麻烦。在查了一些资料以后,发现微软word有一个很好的功能书签,它可以理解为一个key,对应的value即为所需要编辑的word的地址位置。查看详细

    office 操作代码
    //赋值书签名oBookMark[0] = "movieName";oBookMark[1] = "pai";oBookMark[2] = "pai1";oBookMark[3] = "hao";oBookMark[4] = "hao1";doc = wordApp.Documents.Open("D://test//test.doc");//插入对应书签 对应值doc.Bookmarks.get_Item(ref oBookMark[0]).Range.Text = movieName;doc.Bookmarks.get_Item(ref oBookMark[1]).Range.Text = pai;doc.Bookmarks.get_Item(ref oBookMark[2]).Range.Text = pai;doc.Bookmarks.get_Item(ref oBookMark[3]).Range.Text = hao;doc.Bookmarks.get_Item(ref oBookMark[4]).Range.Text = hao;//另存为 savePath 路径doc.SaveAs2(savePath);TraceHelper.GetInstance().Info("已保存至" + savePath, "WordRW Function");doc.Close(ref unknow, ref unknow, ref unknow);wordApp.Documents.Save(ref unknow, ref unknow);wordApp.Quit(ref unknow, ref unknow, ref unknow);
    Aspose 操作代码
    //初始化信息doc = new Aspose.Words.Document("test.doc");DocumentBuilder bulider = new DocumentBuilder(doc);//移动并写对应信息bulider.MoveToBookmark(oBookMark[0]);bulider.Write(movieName);bulider.MoveToBookmark(oBookMark[1]);bulider.Write(pai);bulider.MoveToBookmark(oBookMark[2]);bulider.Write(pai);bulider.MoveToBookmark(oBookMark[3]);bulider.Write(hao);bulider.MoveToBookmark(oBookMark[4]);bulider.Write(hao);//doc 另存doc.Save(savePath);TraceHelper.GetInstance().Info("已保存至" + savePath, "WordRW Function");
    上述两种方式都可以做到我们想要的功能。

    3.2 日志类为了更好的调试代码,也为了保存一些有用的信息,所有日志是必不可少的。 已调研日志引用(EventLog Log4Net)但他们用起来都比较麻烦,因为他们都是为大型系统设计的,所以就用网上例子自己写了一个简单日志类(利用DEBUG)。
    TraceHelper.GetInstance().Info("程序开始...", "Main Function");
    1 评论 4 下载 2019-05-07 16:35:55 下载需要12点积分
  • X509证书读取与解析实验

    一、X509证书结构描述1.1 X509证书类型X.509证书有多种常用的文件扩展名,代表着不同形式的数据编码以及内容
    其中常见的有(来自 Wikipedia ):

    .pem
    隐私增强型电子邮件 ,DER编码的证书再进行Base64编码的数据存放在”——-BEGIN CERTIFICATE——-“和”——-END CERTIFICATE——-“之中。

    .cer, .crt, .der – 通常是DER二进制格式的,但Base64编码后也很常见。
    .p7b, .p7c – PKCS#7 SignedData structure without data, just certificate(s) or CRL(s)
    .p12 – PKCS#12格式,包含证书的同时可能还有带密码保护的私钥
    .pfx – PFX,PKCS#12之前的格式(通常用PKCS#12格式,比如那些由IIS产生的PFX文件)

    1.2 X509证书的结构整体数据结构如下图所示:

    1.2.1 X509证书基本部分
    版本号:
    标识证书的版本(版本1、版本2或是版本3)
    序列号:
    标识证书的唯一整数,由证书颁发者分配的本证书的唯一标识符
    签名算法:
    用于签证书的算法标识,由对象标识符加上相关的参数组成,用于说明本证书所用的数字签名算法
    颁发者:
    证书颁发者的可识别名(DN)
    证书有效期 :
    证书有效期的时间段。本字段由”Not Before”和”Not After”两项组成,意义为:此日期前无效 - 此日期后无效。它们分别由UTC时间或一般的时间表示(在RFC2459中有详细的时间表示规则)。
    主体:
    证书拥有者的可识别名,这个字段必须是非空的,除非你在证书扩展中有别名。
    主体公钥信息

    公钥算法主体公钥
    颁发者唯一标识符(可选项)
    标识符—证书颁发者的唯一标识符,仅在版本2和版本3中有要求,属于可选项。
    主体唯一身份信息(可选项)
    证书拥有者的唯一标识符,仅在版本2和版本3中有要求,属于可选项。

    1.2.2 X509证书拓展部分
    发行者密钥标识符
    密钥使用
    CRL分布点
    私钥的使用期
    证书策略
    策略映射
    主体别名
    颁发者别名
    主体目录属性

    二、数据结构这次我们主要进行解析的是X509证书的基本部分。包括版本号、序列号、颁发者详情、证书有效期、证书主体、签名算法、签名信息和公钥。
    利用FileInputStream 读取文件流,
    然后使用 java.security 的库对文件流进行解析,生成证书。
    import java.security.*;import java.io.*;import java.security.cert.*;import java.security.cert.Certificate;CertificateFactory cf;// 获取工厂实例CertificateFactory cf = CertificateFactory.getInstance("X.509");// 用文件流读入证书FileInputStream fis = new FileInputStream(fileLocation);// 生成证书Certificate c = cf.generateCertificate(fis);X509Certificate t = (X509Certificate)c;fis.close();
    解析证书后,获取库中 X509Certificate 类的关键成员信息,其中包括版本号、序列号、颁发者详情、证书有效期、证书主体、签名算法、签名信息和公钥等,然后在终端上输出结果。
    System.out.println("版本号: " + t.getVersion());System.out.println("序列号: " + t.getSerialNumber().toString(16));System.out.println("颁发者部分: ");String issuerDN = t.getIssuerDN().toString();String[] issuerInfo = issuerDN.split(",");judge = false;for(int i = 0; i < issuerInfo.length; i++) { if(issuerInfo[i].contains("\"")) { if(judge) System.out.println("," + issuerInfo[i]); else { int index = issuerInfo[i].indexOf("="); String key = issuerInfo[i].substring(0, index).replaceAll(" ", ""); String value = issuerInfo[i].substring(index+1); System.out.print(" [" + key + "]: " + value); } judge = !judge; continue; } int index = issuerInfo[i].indexOf("="); String key = issuerInfo[i].substring(0, index).replaceAll(" ", ""); String value = issuerInfo[i].substring(index+1); System.out.println(" [" + key + "]: " + value);}System.out.println("有效起始日期: " + t.getNotBefore());System.out.println("有效终止日期: " + t.getNotAfter());System.out.println("主体部分: ");String[] subjectInfo = t.getSubjectDN().toString().split(",");judge =false;for(int i = 0; i < subjectInfo.length; i++) { if(subjectInfo[i].contains("\"")) { if(judge) System.out.println("," + subjectInfo[i]); else { int index = subjectInfo[i].indexOf("="); String key = subjectInfo[i].substring(0, index).replaceAll(" ", ""); String value = subjectInfo[i].substring(index+1); System.out.print(" [" + key + "]: " + value); } judge = !judge; continue; } int index = subjectInfo[i].indexOf("="); String key = subjectInfo[i].substring(0, index).replaceAll(" ", ""); String value = subjectInfo[i].substring(index+1); System.out.println(" [" + key + "]: " + value);}System.out.println("签名算法: " + t.getSigAlgName());System.out.println("签名: " + t.getSignature().toString());System.out.println("公钥: ");PublicKey pk = t.getPublicKey();String pkStr = pk.toString();String[] pkInfo = pkStr.split("\n");for(int i = 0; i < pkInfo.length; i++) System.out.println(" " + pkInfo[i].trim());
    三、java语言源代码源码已经在上传作业包下的 src 文件夹内
    四、编译运行结果运行环境:Win 10
    示例:github.com.cer
    $ javac X509.java$ java X509 ../resource/github.com.cer../resource/github.com.cer版本号: 3序列号: a0630427f5bbced6957396593b6451f颁发者部分: [CN]: DigiCert SHA2 Extended Validation Server CA [OU]: www.digicert.com [O]: DigiCert Inc [C]: US有效起始日期: Tue May 08 08:00:00 CST 2018有效终止日期: Wed Jun 03 20:00:00 CST 2020主体部分: [CN]: github.com [O]: "GitHub, Inc." [L]: San Francisco [ST]: California [C]: US [SERIALNUMBER]: 5157550 [OID.1.3.6.1.4.1.311.60.2.1.2]: Delaware [OID.1.3.6.1.4.1.311.60.2.1.3]: US [OID.2.5.4.15]: Private Organization签名算法: SHA256withRSA签名: [B@42d80b78公钥: Sun RSA public key, 2048 bits modulus: 25025100770112519133826373044337089322469791879220152213643221754976969243477927257227415181039366015609149001175458675631697702239034823716334509809784926406937227125890521894087124165874208928008511527244368706849310092475511259401776633076671238008575313180508596720476568749022900129891932143823778833404532554658303977351639532131107111874168053266560861447299063764771943313867349795002140249378509492410727023509926138655327290063258841194245159501288231930813126290727910076185376418441777313922434226388044466254908262848472806237246586907086347793775219421137443851512766147228992395134669954845000049168203 public exponent: 65537
    截图结果:

    其余证书实验截图:

    google.com.cer


    microsoft.com.cer


    csdn.net.cer


    baidu.com.cer
    0 评论 1 下载 2019-05-06 15:49:10 下载需要7点积分
显示 30 到 45 ,共 15 条
eject