Java语言的Hook实现
引言:最近在玩完美时空的诛仙Online(不知道这里有没人有共同爱好的),这个游戏每晚七点会出现一个任务“新科试炼”。这个任务简单地说就是做选择题,范围小到柴米油盐,大到世界大千,所以多玩的YY上出现一个频道叫“诛仙答题频道”,这个频道会即时为玩家提供正确答案,所以当大家都上YY的时候,最终出来的成绩的高低并不取决于你的知识面,而是取决你家的网速及你的反应速度(答题越早,所获得的成绩越高)。我家的网速很好,可惜我的反应速度一般,所以从来没上过一次前十,因为每次听说YY上的答案后还要移动鼠标去点击相应的答案,这个过程平均需要0.5秒,这无疑是我成绩不高的根本所在。所以我想到了通过按下键盘上的某些按键实现将鼠标移动到指定位置并模拟鼠标键按下事件(以下简称模拟)。也许你会问:这还不简单,直接加个KeyListener不就完了?但是你想过没有,在模拟的时候,窗口的焦点是在游戏窗口,而不是Java程序的窗口(甚至连窗口都没有),所以我们需要一个监听所有进程的接口,这就是我接下要说的“Hook(钩子)”(了解外挂制作的人应该知道是什么东西,没看过?百度之)。不废话,进入正题:
首先,编写之前,我们要使用到一个第三方类库,它实现的功能就是让你直接调用API,而将对Window的调用交给它处理,下载地址是:http://feeling.sourceforge.net/
将包下载完后解压,并创建项目,结构如左图,lib下的三个dll文件要拷到window/system32下,下面就是编码了:首先我们定义一个抽象类来拦截键盘事件,如下:
- import org.sf.feeling.swt.win32.extension.hook.data.HookData;
- import org.sf.feeling.swt.win32.extension.hook.data.KeyboardHookData;
- import org.sf.feeling.swt.win32.extension.hook.listener.HookEventListener;
- public abstract class KeyboardHookEventListener implements HookEventListener{
- public void acceptHookData(HookData arg0) {
- KeyboardHookData khd = ((KeyboardHookData) arg0);
- {
- if(khd.getTransitionState()) //处理按下事件
- {
- doPress(khd.getWParam());
- }
- else
- {
- doReleased(khd.getWParam()); //处理释放事件
- }
- }
- }
- public abstract void doPress(int keyNum);
- public abstract void doReleased(int keyNum);
- }
import org.sf.feeling.swt.win32.extension.hook.data.HookData;
import org.sf.feeling.swt.win32.extension.hook.data.KeyboardHookData;
import org.sf.feeling.swt.win32.extension.hook.listener.HookEventListener; public abstract class KeyboardHookEventListener implements HookEventListener{public void acceptHookData(HookData arg0) {
KeyboardHookData khd = ((KeyboardHookData) arg0);
{
if(khd.getTransitionState()) //处理按下事件
{
doPress(khd.getWParam());
}
else
{
doReleased(khd.getWParam()); //处理释放事件
}
}
}
public abstract void doPress(int keyNum);
public abstract void doReleased(int keyNum);
}
接着再定义一个抽象类到拦截鼠标事件,如下:
- import org.sf.feeling.swt.win32.extension.hook.data.HookData;
- import org.sf.feeling.swt.win32.extension.hook.data.MouseHookData;
- import org.sf.feeling.swt.win32.extension.hook.listener.HookEventListener;
- public abstract class MouseHookEventListener implements HookEventListener{
- public void acceptHookData(HookData hookData) {
- int x=((MouseHookData) hookData).getPointX();
- int y=((MouseHookData) hookData).getPointY();
- switch(hookData.getWParam())
- {
- case 513:
- doLeftPressed(x,y);
- break;
- case 514:
- doLeftReleased(x,y);
- break;
- case 516:
- doRightPressed(x,y);
- break;
- case 517:
- doRightReleased(x,y);
- break;
- case 519:
- doMiddlePressed(x,y);
- break;
- case 520:
- doMiddleReleased(x,y);
- break;
- default:
- }
- }
- protected abstract void doLeftPressed(int x,int y);
- protected abstract void doLeftReleased(int x,int y);
- protected abstract void doRightPressed(int x,int y);
- protected abstract void doRightReleased(int x,int y);
- protected abstract void doMiddlePressed(int x,int y);
- protected abstract void doMiddleReleased(int x,int y);
- }
import org.sf.feeling.swt.win32.extension.hook.data.HookData;
import org.sf.feeling.swt.win32.extension.hook.data.MouseHookData;
import org.sf.feeling.swt.win32.extension.hook.listener.HookEventListener; public abstract class MouseHookEventListener implements HookEventListener{public void acceptHookData(HookData hookData) {
int x=((MouseHookData) hookData).getPointX();
int y=((MouseHookData) hookData).getPointY();
switch(hookData.getWParam())
{
case 513:
doLeftPressed(x,y);
break;
case 514:
doLeftReleased(x,y);
break;
case 516:
doRightPressed(x,y);
break;
case 517:
doRightReleased(x,y);
break;
case 519:
doMiddlePressed(x,y);
break;
case 520:
doMiddleReleased(x,y);
break;
default:
}
} protected abstract void doLeftPressed(int x,int y);
protected abstract void doLeftReleased(int x,int y);
protected abstract void doRightPressed(int x,int y);
protected abstract void doRightReleased(int x,int y);
protected abstract void doMiddlePressed(int x,int y);
protected abstract void doMiddleReleased(int x,int y);
}
至此,我们的项目底层架构已经完成,下面就是业务流程的控制问题了,在贴上我的代码之前,我觉得有必要先做一下诛仙答题跟项目的介绍(又要废话了,顺便帮老池免费作下广告,遇上我是他的福分,^-^)。
答题是这样的:首先,诛仙这个游戏是支持窗口化(且提供几个固定窗口大小供选择),而其中的答题窗口就是窗口中的窗口了(可拖动的)。7点,答题系统开启,每个玩家可选择进入答题窗口,等下一分钟才真正开始,这一分钟中,页面会显示出3个幸运星,但是没有题目........经过一番分析,可以确定用户要输入的有:当前使用的窗口大小及幸运星的位置(幸运星跟选项的位置不固定的,幸运星一确定,选项的位置也就知道了)。以下是关于这个业务的代码:
定义一个特定的鼠标事件响应,如下:
- import java.awt.Dimension;
- import java.util.LinkedList;
- import java.util.List;
- public class MyMouseHookEventListener extends MouseHookEventListener {
- private Dimension zeroDimension;
- private List<Dimension> dimensions=new LinkedList<Dimension>();
- private boolean needFetchZeroDimension=false;
- private String currentOffsetSeries="";
- public void resetZeroDimension()
- {
- this.needFetchZeroDimension=true;
- }
- public void resetDimensions(String dimensionSeries)
- {
- this.dimensions.clear();
- String[] dimStrs=dimensionSeries.split(",");
- for(int i=0;dimStrs!=null&&i<dimStrs.length/2;i++)
- {
- int width=Integer.parseInt(dimStrs[i*2])+(int)zeroDimension.getWidth();
- int height=Integer.parseInt(dimStrs[i*2+1])+(int)zeroDimension.getHeight();
- dimensions.add(new Dimension(width,height));
- }
- }
- public String getDimensionSeries()
- {
- String dimSeries="";
- for(Dimension dim:this.dimensions)
- {
- dimSeries=dimSeries+","+(int)(dim.getWidth()-zeroDimension.getWidth())+","+(int)(dim.getHeight()-zeroDimension.getHeight());
- }
- if(dimSeries.length()>0)
- {
- dimSeries=dimSeries.substring(1);
- }
- return dimSeries;
- }
- @Override
- protected void doLeftPressed(int x, int y) {}
- @Override
- protected void doLeftReleased(int x, int y) {}
- @Override
- protected void doMiddlePressed(int x, int y) {}
- @Override
- protected void doMiddleReleased(int x, int y) {}
- @Override
- protected void doRightPressed(int x, int y) {
- if(this.needFetchZeroDimension)
- {
- this.zeroDimension=new Dimension(x,y);
- resetDimensions(currentOffsetSeries);
- this.needFetchZeroDimension=false;
- System.out.println("幸运星位置已获取,关闭重置模式,\r\n现在你可以使用小键盘上的12345来实现鼠标事件模拟,如果你需要重新选择请按F11");
- }
- }
- @Override
- protected void doRightReleased(int x, int y) {}
- public void setCurrentOffsetSeries(String currentOffsetSeries) {
- this.currentOffsetSeries = currentOffsetSeries;
- }
- public List<Dimension> getDimensions() {
- return dimensions;
- }
- }
import java.awt.Dimension;
import java.util.LinkedList;
import java.util.List; public class MyMouseHookEventListener extends MouseHookEventListener {
private Dimension zeroDimension;
private List<Dimension> dimensions=new LinkedList<Dimension>();
private boolean needFetchZeroDimension=false;
private String currentOffsetSeries="";public void resetZeroDimension()
{
this.needFetchZeroDimension=true;
} public void resetDimensions(String dimensionSeries)
{
this.dimensions.clear();
String[] dimStrs=dimensionSeries.split(",");
for(int i=0;dimStrs!=null&&i<dimStrs.length/2;i++)
{
int width=Integer.parseInt(dimStrs[i*2])+(int)zeroDimension.getWidth();
int height=Integer.parseInt(dimStrs[i*2+1])+(int)zeroDimension.getHeight();
dimensions.add(new Dimension(width,height));
}
} public String getDimensionSeries()
{
String dimSeries="";
for(Dimension dim:this.dimensions)
{
dimSeries=dimSeries+","+(int)(dim.getWidth()-zeroDimension.getWidth())+","+(int)(dim.getHeight()-zeroDimension.getHeight());
}
if(dimSeries.length()>0)
{
dimSeries=dimSeries.substring(1);
}
return dimSeries;
} @Override
protected void doLeftPressed(int x, int y) {} @Override
protected void doLeftReleased(int x, int y) {} @Override
protected void doMiddlePressed(int x, int y) {} @Override
protected void doMiddleReleased(int x, int y) {} @Override
protected void doRightPressed(int x, int y) {
if(this.needFetchZeroDimension)
{
this.zeroDimension=new Dimension(x,y);
resetDimensions(currentOffsetSeries);
this.needFetchZeroDimension=false;
System.out.println("幸运星位置已获取,关闭重置模式,\r\n现在你可以使用小键盘上的12345来实现鼠标事件模拟,如果你需要重新选择请按F11");
}
} @Override
protected void doRightReleased(int x, int y) {} public void setCurrentOffsetSeries(String currentOffsetSeries) {
this.currentOffsetSeries = currentOffsetSeries;
} public List<Dimension> getDimensions() {
return dimensions;
}
}
再定义一个运行类:
- import java.awt.AWTException;
- import java.awt.Robot;
- import java.awt.Toolkit;
- import java.awt.datatransfer.Clipboard;
- import java.awt.datatransfer.StringSelection;
- import java.awt.datatransfer.Transferable;
- import java.awt.event.InputEvent;
- import org.sf.feeling.swt.win32.extension.hook.Hook;
- public class ZhuXianSwifter {
- public static final int NUM_1=97;
- public static final int NUM_2=98;
- public static final int NUM_3=99;
- public static final int NUM_4=100;
- public static final int NUM_5=101;
- public static final int F_11=122;
- public static final int F_12=123;
- private static final String OFFSET_SERIES_640_480="-125,84,-125,107,-125,130,-125,152,44,0,20,0,0,0";
- private static final String OFFSET_SERIES_800_600="-156,105,-156,134,-156,163,-156,190,55,0,25,0,0,0";
- private static final String OFFSET_SERIES_1024_768="-200,138,-200,172,-200,211,-200,248,70,0,32,0,0,0";
- /**
- * 使用说明:
- * 1、启动后先选择所使用的分辨率,目前只支持640*480,800*600,1024*768;
- * 2、然后使用鼠标右键点击一下试炼答题窗口的第一个幸运星的中心点即可;
- * 3、使用小键盘的1234选择答案,使用5点星星(第一个使用完会自动用第二个),
- * 4、只支持命令行模式
- * 5、F11为取坐标模式,按F11开始,再次按F11结束,并将零坐标跟之前的偏移坐标复制到系统剪贴板
- * 6、按F12退出程序
- * @throws AWTException
- */
- public static void main(String[] args) throws AWTException {
- /*注册鼠标Hook*/
- final MyMouseHookEventListener mouseListener=new MyMouseHookEventListener();
- Hook.MOUSE.addListener(mouseListener);
- Hook.MOUSE.install();
- /*系统剪贴板*/
- final Clipboard systemClipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
- final Robot robot=new Robot();
- /*键盘监听器*/
- final KeyboardHookEventListener keyboardListener=new KeyboardHookEventListener(){
- private boolean haveChooseMode=false;
- private int count=0;
- @Override
- public void doPress(int keyNum) {
- String mode="";
- if(keyNum==F_12)
- {
- if(!mouseListener.getDimensionSeries().equals(""))
- {
- System.out.println("内容已经复制到系统剪贴板");
- Transferable text = new StringSelection(mouseListener.getDimensionSeries());
- systemClipboard.setContents(text,null);
- }
- System.out.println("------程序退出------");
- System.exit(0);
- }
- else if(keyNum==F_11)
- {
- haveChooseMode=false;
- count=0;
- System.out.println("启动重置模式");
- printChooseMode();
- }
- else
- {
- if(haveChooseMode==false)
- {
- switch(keyNum)
- {
- case NUM_1:
- mode="640*480";
- mouseListener.setCurrentOffsetSeries(OFFSET_SERIES_640_480);
- break;
- case NUM_2:
- mode="800*600";
- mouseListener.setCurrentOffsetSeries(OFFSET_SERIES_800_600);
- break;
- case NUM_3:
- mode="1024*768";
- mouseListener.setCurrentOffsetSeries(OFFSET_SERIES_1024_768);
- break;
- default:
- System.out.println("请重新选择:");
- printChooseMode();
- return;
- }
- System.out.println("您选择了"+mode+"分辨率模式");
- haveChooseMode=true;
- mouseListener.resetZeroDimension();
- printFetchZeroCoordinate();
- }
- else
- {
- switch (keyNum) {
- case NUM_1:
- robot.mouseMove((int)mouseListener.getDimensions().get(0).getWidth(),(int)mouseListener.getDimensions().get(0).getHeight());
- robot.mousePress(InputEvent.BUTTON1_MASK);
- robot.mouseRelease(InputEvent.BUTTON1_MASK);
- break;
- case NUM_2:
- robot.mouseMove((int)mouseListener.getDimensions().get(1).getWidth(),(int)mouseListener.getDimensions().get(1).getHeight());
- robot.mousePress(InputEvent.BUTTON1_MASK);
- robot.mouseRelease(InputEvent.BUTTON1_MASK);
- break;
- case NUM_3:
- robot.mouseMove((int)mouseListener.getDimensions().get(2).getWidth(),(int)mouseListener.getDimensions().get(2).getHeight());
- robot.mousePress(InputEvent.BUTTON1_MASK);
- robot.mouseRelease(InputEvent.BUTTON1_MASK);
- break;
- case NUM_4:
- robot.mouseMove((int)mouseListener.getDimensions().get(3).getWidth(),(int)mouseListener.getDimensions().get(3).getHeight());
- robot.mousePress(InputEvent.BUTTON1_MASK);
- robot.mouseRelease(InputEvent.BUTTON1_MASK);
- break;
- case NUM_5:
- robot.mouseMove((int)mouseListener.getDimensions().get(4+count).getWidth(),(int)mouseListener.getDimensions().get(4+count).getHeight());
- robot.mousePress(InputEvent.BUTTON1_MASK);
- robot.mouseRelease(InputEvent.BUTTON1_MASK);
- count++;
- if(count==3)
- {
- count=0;
- }
- break;
- default:
- break;
- }
- }
- }
- }
- @Override
- public void doReleased(int keyNum) {}
- };
- Hook.KEYBOARD.addListener(keyboardListener);
- Hook.KEYBOARD.install(); // 註冊事件
- printChooseMode();
- }
- private static void printChooseMode()
- {
- System.out.println("请选择窗口大小:");
- System.out.println("NUM1:640*480");
- System.out.println("NUM2:800*600");
- System.out.println("NUM3:1024*768");
- }
- private static void printFetchZeroCoordinate()
- {
- System.out.println("请在第一个幸运星的中心上点击鼠标右键");
- }
- }
import java.awt.AWTException;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.event.InputEvent; import org.sf.feeling.swt.win32.extension.hook.Hook; public class ZhuXianSwifter {public static final int NUM_1=97;
public static final int NUM_2=98;
public static final int NUM_3=99;
public static final int NUM_4=100;
public static final int NUM_5=101;
public static final int F_11=122;
public static final int F_12=123; private static final String OFFSET_SERIES_640_480="-125,84,-125,107,-125,130,-125,152,44,0,20,0,0,0";
private static final String OFFSET_SERIES_800_600="-156,105,-156,134,-156,163,-156,190,55,0,25,0,0,0";
private static final String OFFSET_SERIES_1024_768="-200,138,-200,172,-200,211,-200,248,70,0,32,0,0,0"; /**
* 使用说明:
* 1、启动后先选择所使用的分辨率,目前只支持640*480,800*600,1024*768;
* 2、然后使用鼠标右键点击一下试炼答题窗口的第一个幸运星的中心点即可;
* 3、使用小键盘的1234选择答案,使用5点星星(第一个使用完会自动用第二个),
* 4、只支持命令行模式
* 5、F11为取坐标模式,按F11开始,再次按F11结束,并将零坐标跟之前的偏移坐标复制到系统剪贴板
* 6、按F12退出程序
* @throws AWTException
*/
public static void main(String[] args) throws AWTException { /*注册鼠标Hook*/
final MyMouseHookEventListener mouseListener=new MyMouseHookEventListener();
Hook.MOUSE.addListener(mouseListener);
Hook.MOUSE.install(); /*系统剪贴板*/
final Clipboard systemClipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); final Robot robot=new Robot(); /*键盘监听器*/
final KeyboardHookEventListener keyboardListener=new KeyboardHookEventListener(){ private boolean haveChooseMode=false;
private int count=0; @Override
public void doPress(int keyNum) {
String mode="";
if(keyNum==F_12)
{
if(!mouseListener.getDimensionSeries().equals(""))
{
System.out.println("内容已经复制到系统剪贴板");
Transferable text = new StringSelection(mouseListener.getDimensionSeries());
systemClipboard.setContents(text,null);
}
System.out.println("------程序退出------");
System.exit(0);
}
else if(keyNum==F_11)
{
haveChooseMode=false;
count=0;
System.out.println("启动重置模式");
printChooseMode();
}
else
{
if(haveChooseMode==false)
{
switch(keyNum)
{
case NUM_1:
mode="640*480";
mouseListener.setCurrentOffsetSeries(OFFSET_SERIES_640_480);
break;
case NUM_2:
mode="800*600";
mouseListener.setCurrentOffsetSeries(OFFSET_SERIES_800_600);
break;
case NUM_3:
mode="1024*768";
mouseListener.setCurrentOffsetSeries(OFFSET_SERIES_1024_768);
break;
default:
System.out.println("请重新选择:");
printChooseMode();
return;
}
System.out.println("您选择了"+mode+"分辨率模式");
haveChooseMode=true;
mouseListener.resetZeroDimension();
printFetchZeroCoordinate();
}
else
{
switch (keyNum) {
case NUM_1:
robot.mouseMove((int)mouseListener.getDimensions().get(0).getWidth(),(int)mouseListener.getDimensions().get(0).getHeight());
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
break;
case NUM_2:
robot.mouseMove((int)mouseListener.getDimensions().get(1).getWidth(),(int)mouseListener.getDimensions().get(1).getHeight());
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
break;
case NUM_3:
robot.mouseMove((int)mouseListener.getDimensions().get(2).getWidth(),(int)mouseListener.getDimensions().get(2).getHeight());
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
break;
case NUM_4:
robot.mouseMove((int)mouseListener.getDimensions().get(3).getWidth(),(int)mouseListener.getDimensions().get(3).getHeight());
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
break;
case NUM_5:
robot.mouseMove((int)mouseListener.getDimensions().get(4+count).getWidth(),(int)mouseListener.getDimensions().get(4+count).getHeight());
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
count++;
if(count==3)
{
count=0;
}
break;
default:
break;
}
}
}
} @Override
public void doReleased(int keyNum) {} }; Hook.KEYBOARD.addListener(keyboardListener);
Hook.KEYBOARD.install(); // 註冊事件 printChooseMode(); } private static void printChooseMode()
{
System.out.println("请选择窗口大小:");
System.out.println("NUM1:640*480");
System.out.println("NUM2:800*600");
System.out.println("NUM3:1024*768");
} private static void printFetchZeroCoordinate()
{
System.out.println("请在第一个幸运星的中心上点击鼠标右键");
}
}
以上就是本项目的所以代码,运行时要先按小键盘的1/2/3选择使用的窗口大小,然后在第一个幸运星的中心点击下右键鼠标就可以了,之后你就可以用小键盘的1/2/3/4/5(5是幸运星)来选择你的答案了。
Java语言的Hook实现的更多相关文章
- JAVA语言中的修饰符
JAVA语言中的修饰符 -----------------------------------------------01--------------------------------------- ...
- Atitit onvif协议获取rtsp地址播放java语言 attilx总结
Atitit onvif协议获取rtsp地址播放java语言 attilx总结 1.1. 获取rtsp地址的算法与流程1 1.2. Onvif摄像头的发现,ws的发现机制,使用xcf类库1 2. 调用 ...
- AVL树原理及实现(C语言实现以及Java语言实现)
欢迎探讨,如有错误敬请指正 如需转载,请注明出处http://www.cnblogs.com/nullzx/ 1. AVL定义 AVL树是一种改进版的搜索二叉树.对于一般的搜索二叉树而言,如果数据恰好 ...
- Java语言中的面向对象特性总结
Java语言中的面向对象特性 (总结得不错) [课前思考] 1. 什么是对象?什么是类?什么是包?什么是接口?什么是内部类? 2. 面向对象编程的特性有哪三个?它们各自又有哪些特性? 3. 你知 ...
- JAVA语言搭建白盒静态代码、黑盒网站插件式自动化安全审计平台
近期打算做一个插件化的白盒静态代码安全审计自动化平台和黑盒网站安全审计自动化平台.现在开源或半开源做黑盒网站安全扫描的平台,大多是基于python脚本,安全人员贡献python脚本插件增强平台功能.对 ...
- 关于Java语言和面向对象记录
本科时常用的c语言是面向过程的语言,而Java是面向对象的语言 Java语言的11个关键术语 简单性.可移植性.面向对象.分布式.高性能.解释型.健壮性.多线程.安全性.动态性.体系结构中立 面向对象 ...
- 用Java语言编写一个简易画板
讲了三篇概博客的概念,今天,我们来一点实际的东西.我们来探讨一下如何用Java语言,编写一块简易的画图板. 一.需求分析 无论我们使用什么语言,去编写一个什么样的项目,我们的第一步,总是去分析这个项目 ...
- 【百度文库课程】Java语言基础与OOP入门学习笔记一
一. Java的历史与由来 原名Oak,针对嵌入式系统开发设计,语法与C/C++基本一致 二. Java语言特点 Java由四方面组成:Java编程语言.Java类文件格式.Java虚拟机和Java应 ...
- 0031 Java学习笔记-梁勇著《Java语言程序设计-基础篇 第十版》英语单词
第01章 计算机.程序和Java概述 CPU(Central Processing Unit) * 中央处理器 Control Unit * 控制单元 arithmetic/logic unit /ə ...
随机推荐
- NodeJS学习笔记 进阶 (3)Nodejs 进阶:Express 常用中间件 body-parser 实现解析(ok)
个人总结:Node.js处理post表单需要body-parser,这篇文章进行了详细的讲解. 摘选自网络 写在前面 body-parser是非常常用的一个express中间件,作用是对http请求体 ...
- MySql系列表之间的关系
foreign key 快速理解foreign key 员工信息表有三个字段:工号 姓名 部门 公司有3个部门,但是有1个亿的员工,那意味着部门这个字段需要重复存储,部门名字越长,越浪费 数据 ...
- subline Text3 插件安装
--没有解决,换了vscode 安装Package Control 这是必须的步骤,安装任何插件之前需要安装这个 自动安装的方法最方便,只需要在控制台(不是win的控制台,而是subline 的)里粘 ...
- springboot框架笔记——springboot提供的自动配置
Springboot基本配置 spring MVC的定制配置需要我们的配置实现一个WebMvcConfigurer接口,如果实在spring环境下需要使用@EnableWebMVC注解,来开启对spr ...
- .ashx 实现自动路由和参数填充
在Mvc中访问控制器,参数填充和路由控制都非常方便,但之前项目用的是webFrom,和js交互的ashx页面,路由非常麻烦要根据传进来关键字来做switch,参数填充更坑,要一个一个去form中取出来 ...
- Objective-C中的同步线程的锁
概述 在多线程编程中往往会遇到多个线程同时访问共享的资源,这种情况我们需要通过同步线程来避免.也就是给线程加锁. 因为Objective-C是C语言的超集.,严格的来说是真超集.所以C语言当中的pth ...
- 独立python环境之virtualenv和virtualenvwrapper
介绍 如果有一台測试机,多个人使用,有多个项目,不同项目可能python版本号不一样.须要的库不一样. 我们须要一个独立干净的python环境,互相隔离,互不影响. virtualenv能够帮我们解决 ...
- leetcode第一刷_Text Justification
这个题的接受率好低,搞得我一直不敢做.后来认真的看了一下题目,不是非常难嘛.字符串的题目ac率就是低,除了难,还由于它的測试用例太多. 思路不难,主要是由于特殊情况太多.纯模拟,我把全部的情况罗列一下 ...
- BootstrapDialog模态框
5最近是比较烦直接使用Bootstrap里面的模态框,满屏都是模态框代码,看得心烦.然后想起以前使用的BootstrapDialog.show()的方式,挺简单好用的.然后就拿出来分享一下. 1.下载 ...
- Cisco交换机解决网络蠕虫病毒入侵问题
Cisco交换机解决网络蠕虫病毒入侵问题 今年来网络蠕虫泛滥给ISP和企业都造成了巨大损失,截至目前已发现近百万种病毒及木马.受感染的网络基础设施遭到破坏,以Sql Slammer为 ...