zoukankan      html  css  js  c++  java
  • 毕设项目,系统搭建笔记文档

    代码结构:

     

    主体系统启动流程:

    在dynamic web project中添加全局监听类RootListener,继承ServletContextListener接口,实现public void contextInitialized(ServletContextEvent sce),调用系统初始化入口类ArchtechRoot。在ArchtechRoot中根据spring配置文件进行系统各模块的初始化。从root bean读取SystemInitDO,用于获取配置文件中的子配置文件,即各层模块配置文件,并将其中的bean进行装配。RPCServerRPC服务的基础server模块,对应rpcRoot bean。

     

    1 ApplicationContext context = new ClassPathXmlApplicationContext("springContext-*.xml");
    2 SystemInitDO initDO = (SystemInitDO) context.getBean("root");
    3 RPCServer rpcRoot = (RPCServer) context.getBean("rpcRoot");

     

    子配置文件:

     1 <bean id="root" class=" com.multiagent.hawklithm.davinci.init.SystemInitDO"> 
     2         <property name="configFileList">
     3             <list>
     4                 <value>spring-config/spring-asyntask.xml</value>
     5                 <value>spring-config/spring-EventListener.xml</value>
     6                 <value>spring-config/spring-dao.xml</value>
     7                 <value>spring-config/spring-manager.xml</value>
     8                 <value>spring-config/spring-module.xml</value>
     9                 <value>spring-config/spring-ibatis.xml</value>
    10                 <value>spring-config/spring-net.xml</value>
    11                 <value>spring-config/spring-transaction.xml</value>
    12                 <value>spring-config/spring-session.xml</value>
    13             </list>
    14         </property>      
    15     </bean>

    子配置文件中几个关键注册管理机

    bean 分类注册管理机

    1 <!-- bean分类注册管理机 -->
    2     <bean class="com.multiagent.hawklithm.davinci.init.AutoRegister"/>

    异步任务注册机

    1 <!-- 异步任务注册机 -->
    2     <bean id="asynTaskRegManager" class="com.multiagent.hawklithm.davinci.AsynTaskRegisterMachine" />

    消息注册管理机

    1 <!-- 消息注册管理机 -->    
    2     <bean id=" wardenManager" class="com.multiagent.hawklithm.shadowsong.manager.WardenManager"/>

    生产过程模块管理机

    1 <!-- 生产过程模块管理注册机 -->
    2     <bean id="pmRegManager" class="com.multiagent.hawklithm.leon.manager.ProcessModuleRegisterManager"/>

    bean注册管理机

     1 public class AutoRegister implements BeanPostProcessor {
     2     private AsynTaskRegisterMachine asynTaskRegManager;
     3     private ProxyFactoryBean accountService;
     4     private ProcessModuleRegisterManager pmRegManager;
    27 public Object postProcessAfterInitialization(Object bean, String beanName) 28 throws BeansException { 29 if (bean instanceof AsynTaskRegister) { 30 System.out.println("bean name: "+beanName+" regist AsynTaskRegister"); 31 asynTaskRegManager.regist(bean);//异步任务注册 32 }else if (bean instanceof IProcessModule){ 33 System.out.println("bean name: "+beanName+" regist EquipmentObject"); 34 pmRegManager.regist(bean);//过程模块注册 35 } 36 return bean; 37 } 38 64 }

    如代码所示,根据类类型就行分类注册

    RPC接口注册:

    RPC接口定义在springContext-rpc.xml中

    如以下示例接口定义

    1     <bean class="com.multiagent.hawklithm.davinci.rpc.DO.RPCSystemServerProxy">
    2         <property name="interfaceName" value="com.multiagent.hawklithm.rpc.Interfacetest"/>
    3         <property name="version" value="1.0.0.hawk"/>
    4         <property name="className" value="com.multiagent.hawklithm.rpc.impl.ImplTest"/>
    5         <property name="comment" value="此处填写接口介绍"/>
    6         <property name="visible" value="true" />
    7     </bean>

    RPCServer创建

    1 <bean id="rpcRoot" class="com.multiagent.hawklithm.davinci.rpc.Server.RPCServer">
    2         <constructor-arg>
    3             <value>10007</value>
    4         </constructor-arg>
    5 
    6     </bean>

    在RPCServer.java中,Rpc接口bean注册

    1 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    2         if (bean instanceof RPCSystemServerProxy) {
    3             RPCregManager.regist((RPCSystemServerProxy) bean);
    4         }
    5         return bean;
    6     }

    将已注册RPC接口与已注册模块关联:

    ArchtechRoot.java

    对已填充beanId字段的RPC接口类进行关联

     1 for (RPCSystemServerProxy object : rpcRoot.getRPCregManager().getRegList()) {
     2                 if (StringUtils.hasLength(object.getBeanId())) {
     3                     try {
     4                         Object target = tempContext.getBean(object.getBeanId());
     5                         object.setTarget(target);
     6                         System.out.println(object.getInterfaceName() + "关联成功");
     7                     } catch (NoSuchBeanDefinitionException e) {
     8                         // TODO 打印日志RPC配置文件中bean缺失
     9                         System.out.println("RPC配置文件中缺失bean:[" + object.getBeanId() + "]");
    10                     }
    11                 }
    12             }

    对未填充beanId字段的RPC接口类进行实例创建(目前均使用单例模式)

    1 for (RPCSystemServerProxy object : rpcRoot.getRPCregManager().getRegList()) {
    2                 if (!object.isLinked()) {
    3                     object.setTarget(Class.forName(object.getClassName()).newInstance());
    4                     System.out.println(object.getClassName() + "生成实例成功");
    5                 }
    6             }

    以上完成所有模块的创建和注册关联工作

    启动异步任务注册机中的所有异步任务:

    1 regManager.startAll();

    消息注册部分Shadowsong

    消息注册管理机WardenManager.java

     1 public class WardenManager implements IRegisterManager, IMessagePusher<WardenMessage> {
     2     
     3     public boolean regist(Object object) {
     4     /**具体见源码*/
     5     }
     6 
     7     /**
     8      * Warden接收消息的异步线程
     9      * @author hawklithm
    10      *
    11      */
    12     private class WardenThread implements Runnable {
    13         /**具体见源码*/
    14         @Override
    15         public void run() {
    16             object.receiveMessage(message);
    17         }
    18 
    19     }
    20 
    21     /**
    22      * 推送消息
    23      */
    24     public void push(WardenMessage message) {
    25         Set<Warden> list = map.get(message.getKind());
    26         for (Warden object : list) {
    27             exec.execute(new WardenThread(object, message));
    28         }
    29     }
    30 
    31 }

    使用消息注册机时先进行消息注册

    1 wardenManager.registWarden(new Warden(“MessageReceiver”, “MessageType”) {
    2 
    3                         //message对应消息结构体WardenMessage中的note属性
    4             @Override
    5             public void asynchronizedProcess(String message) {
    6                 /**接收到消息后的行为*/
    7             }
    8 
    9         });

    发送消息:

    1 wardenManager.push(message);

    message类型为WardenMessage

    纯虚类EquipmentObjetc类型继承了WardenOperator接口实现方法

    1 public void sendOutMessage(WardenMessage message) {
    2         wardenManager.push(message);
    3     }

    所以继承了EquipmentObject的类直接调用sendOutMessage(WardenMessage message)即可。

    举例:

    读卡器模块初始化时(读卡器模块继承了EquipmentObject)

     1 this.registWarden(new Warden(String.valueOf(this.getRfid()) + WardenMessage.TARGET_TYPE_READER, WardenMessage.KIND_NEW_DATA_COMING + WardenMessage.DIR_ENTER) {
     2 
     3             @Override
     4             public void asynchronizedProcess(String message) {
     5                 WardenMessage wardenMessage = new WardenMessage();
     6                 wardenMessage.setNote(message);
     7                 wardenMessage.setTarget(String.valueOf(targetRFID) + targetKind);
     8                 wardenMessage.setKind(targetMessageKind + targetMessageDir);
     9                 sendOutMessage(wardenMessage);
    10             }
    11 
    12         });

    以上代码截取自Reader.java表示在接收到warden消息后将其信息实体取出并重新定义warden消息的目标和类型并转发,我们现在做一个约定:

    消息接收者:目标RFID+目标类型

    消息类型:消息类型+消息流向

    WardenMessage.java中展示预设了几种消息类型

     1     /**
     2      * 消息类型
     3      */
     4     public static String KIND_RFID_FROM_READER = "wm_rfidfromreader";//从读卡器模块发送来的RFID数据
     5     public static String KIND_NEW_DATA_COMING = "new_data_coming";//接收到从RFID实体来的数据
     6     /**
     7      * 目标类型
     8      */
     9     public static String TARGET_TYPE_READER = "target_type_reader";//数据接收目标类型为读卡器
    10     public static String TARGET_TYPE_MACHINE = "target_type_machine";//数据接收目标类型为设备模块
    11     /**
    12      * 数据流方向
    13      */
    14     public static String DIR_ENTER = "wm_enter";
    15     public static String DIR_EXIT = "wm_exit";

    模块间信息交互和数据传输均可使用该消息系统

    生产过程管理模块(静态模块系统leon)

     1 public class ProcessModuleRegisterManager implements IRegisterManager {
     2     private List<IProcessModule> regList = new ArrayList<IProcessModule>();
     3     public boolean regist(Object thing) {
     4     /**过程模块注册*/
     5     }
     6 
     7     public IProcessModule getProcessModuleByName(String name) throws ProcessModuleNotFoundException {
     8 /**根据模块名称(ID)获取已注册的过程模块*/
     9     }
    10 
    11     public EquipmentObject getEquipmentByRFID(int id) throws ProcessModuleNotFoundException {
    12         /**根据设备名称(ID)获取已注册的过程模块中的设备模块*/
    13     }
    14 }

    过程注册模块中包含所有已注册的过程模块信息

    生产过程模块(静态模块):

    统一继承IProcessModule,具体见IProcessModule.java

     1 public interface IProcessModule {
     2     /**
     3      * 获取模块名称
     4      * @return 模块名称
     5      */
     6     String getName();
     7     /**
     8      * 根据设备RFID从过程模块中获取设备
     9      * @param id 设备RFID
    10      * @return
    11      * @throws EquipmentNotFoundException
    12      */
    13     EquipmentObject getEquipmentByRFID(int id) throws EquipmentNotFoundException;
    14 }

    在过程模块中建立设备列表,通过spring bean注入设备,可达到过程对设备的一个管理,实例见SortingProcess.java

    对应bean的spring配置参考spring-module.xml,如下:

     1 <bean id="sorting_process_module" class="com.multiagent.hawklithm.leon.process.SortingProcess">
     2         <property name="equipmentList">
     3             <list>
     4                 <ref bean="reader1"/>
     5                 <ref bean="sorting_equipment1" />
     6                 <ref bean="reader2" />
     7                 <ref bean="singleRead3"/>
     8                 <ref bean="sorting_equipment2" />
     9                 
    10             </list>
    11         </property>
    12     </bean>

    设备模块

    统一继承纯虚类EquipmentObject,在EquipmentObject.java中已实现设备的基本功能方法

     1 public abstract class EquipmentObject implements Module, WardenOperator {
     2     private int rfid ;
     3     private Set<Integer> itemRFIDs = new HashSet<Integer>();
     4     private Set<Integer> packageRFIDs = new HashSet<Integer>();
     5     private int staffRFID;
     6     private WardenManager wardenManager;
     7 
     8     
     9     /**
    10      * 设置设备属性
    11      */
    12     abstract public void doSetEquipmentParameter();
    13 
    14     /**
    15      * 获取设备属性
    16      * @return
    17      */
    18     abstract public String doGetEquipmentSummaryInfo();
    19 
    20     /**
    21      * 初始化Warden
    22      */
    23     abstract public void initWarden();
    24 
    25     public void sendOutMessage(WardenMessage message) {
    26         wardenManager.push(message);
    27     }
    28 
    29     public void registWarden(Warden warden) {
    30         wardenManager.regist(warden);
    31     }
    32 
    33     public void addItem(int RFID) {
    34         itemRFIDs.add(Integer.valueOf(RFID));
    35     }
    36 
    37     public void addPackage(int RFID) {
    38         packageRFIDs.add(Integer.valueOf(RFID));
    39     }
    40 
    41     public boolean removeItem(int RFID) {
    42         return itemRFIDs.remove(Integer.valueOf(RFID));
    43     }
    44 
    45     public boolean removePackage(int RFID) {
    46         return packageRFIDs.remove(Integer.valueOf(RFID));
    47     }
    48 
    49     // public EquipmentObject() {
    50     // warden = new Warden(this);
    51     // wardenManager.regist(warden);
    52     // }
    53 
    54     public String doGetModuleSummaryInfo() {
    55         return doGetEquipmentSummaryInfo();
    56     }
    57 
    58     public int getStaffRFID() {
    59         return staffRFID;
    60     }
    61 
    62     public void setStaffRFID(int staffRFID) {
    63         this.staffRFID = staffRFID;
    64     }
    65 
    66     public WardenManager getWardenManager() {
    67         return wardenManager;
    68     }
    69 
    70     public void setWardenManager(WardenManager wardenManager) {
    71         this.wardenManager = wardenManager;
    72     }
    98 }

    在配置设备bean时注意设置init-method="initWarden"从而调用initWarden函数进行消息注册

    例:

    1 <bean id="sorting_equipment1"    class="com.multiagent.hawklithm.leon.module.SortingEquipmentModule"  init-method="initWarden" >
    2         <property name="rfid" value="1024"/>
    3     </bean>

    initWarden中的注册warden见上文消息注册管理Shadowsong部分,具体实现见com.multiagent.hawklithm.leon.module包下的模块类

    RPC系统

    rpc client端在rpc工程中,server端在davinci中,rpc所有spring bean配置文件均在springContext-rpc.xml中,rpc接口信息通过interfaceInfoDAO保存到数据库中。

    RPCServer.java

    在initNetty()函数中创建Netty服务端实现通信

     1 private void initNetty() {
     2         ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
     3         bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
     4 
     5             @Override
     6             public ChannelPipeline getPipeline() throws Exception {
     7                 ChannelPipeline pipeline = Channels.pipeline();
     8                 pipeline.addLast("UP_FRAME_HANDLER", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2, 0, 2));
     9                 pipeline.addLast("DOWN_FRAME_HANDLER", new LengthFieldPrepender(2, false));
    10                 pipeline.addLast("myHandler", rpcServerNettyHandler);
    11                 // return Channels.pipeline(rpcServerNettyHandler);
    12                 return pipeline;
    13             }
    14 
    15         });
    16         bootstrap.bind(new InetSocketAddress(port));
    17         System.out.println("RPC server开启成功");
    18     }

    NettyHandler继承SimpleChannelHandler对通信接口进行一些基本封装

    public class NettyHandler extends SimpleChannelHandler {
    
        @Override
        public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
                throws Exception {
    /**接收到数据将通信相关数据取出并传入onMessageReceived方法*/
            ChannelBuffer buffer = (ChannelBuffer) e.getMessage();
            String recvMsg=buffer.toString(Charset.defaultCharset());
            System.out.println("receive: " +recvMsg);
            onMessageReceived(recvMsg,e.getChannel());
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
                throws Exception {
    /**异常处理*/
        }
    
        public void sendMessage(String message,Channel channel) throws MessageTransportException {
            if (channel == null) {
                throw new MessageTransportException(new NullPointerException());
            }
            ChannelBuffer buffer = ChannelBuffers.buffer(message.length());
            buffer.writeBytes(message.getBytes());
            channel.write(buffer);
        }
        /**
         * 重写该函数可获取传输数据
         */
        public void onMessageReceived(String message,Channel channel) throws MessageTransportException {
            
        }
    }

    RPCServerNettyHandler继承NettyHandler

    重写onMessageReceived

     1 @Override
     2     public void onMessageReceived(String msg, Channel cha) throws MessageTransportException {
     3         System.out.println(msg);
     4         RPCSystemProtocol rpcMessage = gson.fromJson(msg, RPCSystemProtocol.class);
     5         if (!aclManager.verifyRPCInterfaceCall(rpcMessage)) {//权限控制
     6             rpcMessage.setReturnObject("have no permission");
     7             return;
     8         }
     9         if (!rpcMessage.selfCheck()) {//数据自检
    10             throw new MessageTransportException("RPC包错误");
    11         }
    12         try {
    13             Object instance = RPCregManager.getTarget(rpcMessage);
    14             Object ret = rpcExec.exec(rpcMessage.getClassName(), rpcMessage.getMethodName(), rpcMessage.getParamsType(), instance, rpcMessage.getParameters());//通过反射机制调用响应类的方法执行并得出结果
    15             rpcMessage.setReturnObject(gson.toJson(ret));
    16             if (!watcher.insert(new RPCConnectInfo(gson.toJson(rpcMessage), cha))) {//将需要返回的结果插入发送队列,由于开发RPC时还没有开始设计消息管理中心,所以使用其独立的RPCBufferCallBackWatcher类进行返回数据队列的管理,详见RPCBufferCallBackWatcher
    17                 // TODO 打印日志
    18             }
    19         } catch (RPCInterfaceNotFoundException e) {
    20             // TODO 打印日志
    21             e.printStackTrace();
    22             return;
    23         } catch (IllegalAccessException e) {
    24             // TODO Auto-generated catch block
    25             e.printStackTrace();
    26             return;
    27         } catch (IllegalArgumentException e) {
    28             // TODO Auto-generated catch block
    29             e.printStackTrace();
    30             return;
    31         } catch (InvocationTargetException e) {
    32             // TODO Auto-generated catch block
    33             e.printStackTrace();
    34             return;
    35         }
    36     }

    rpc client端

    客户端进行RPC调用思路:

    在配置文件中注册需要使用rpc的bean,通过该bean获取一个实例并使用对应的接口方法,利用spring的特性对该接口方法进行代理,将方法的实现转换成netty通信,把调用方法的参数发送给rpc server,并在rpcLockManager中进行一个注册并阻塞当前方法执行线程,等待server返回结果;当server返回结果后,在rpcLockManager中对等待结果的调用进行解锁并唤醒线程,传入server发过来的结果,再又代理返回方法调用结果。使客户端程序员的编码结构不发生任何改变的情况下实现远程调用。

    RPCClient.java

    基本上和RCPServer.java类似,不过这里创建的是netty服务端

     1 public void initRPCClient() {
     2         ClientBootstrap bootstrap = new ClientBootstrap(new NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
     3         handler = new NettyHandler() {
     4 
     5             private Gson gson = new Gson();
     6 
     7             @Override
     8             public void onMessageReceived(String msg, Channel cha) throws MessageTransportException {
     9                 RPCSystemProtocol rpcMessage = gson.fromJson(msg, RPCSystemProtocol.class);
    10                 if (!rpcMessage.selfCheck()) {
    11                     throw new MessageTransportException("RPC包错误");
    12                 }
    13                 // announcer.insert(rpcMessage);
    14                 lockManager.AnswerReceived(rpcMessage.uuid, rpcMessage);//接收到服务端回复后将结果返回并将rpc调用解锁
    15 
    16             }
    17 
    18             @Override
    19             public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
    20                 channel = e.getChannel();
    21             }
    22         };
    23         bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
    24             public ChannelPipeline getPipeline() throws Exception {
    25                 ChannelPipeline pipeline = Channels.pipeline();
    26                 pipeline.addLast("UP_FRAME_HANDLER", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2, 0, 2));
    27                 pipeline.addLast("DOWN_FRAME_HANDLER", new LengthFieldPrepender(2, false));
    28                 // return Channels.pipeline(handler);
    29                 pipeline.addLast("myHandler", handler);
    30                 return pipeline;
    31             }
    32         });
    33         bootstrap.connect(new InetSocketAddress(address, port));
    34     }

    用SpringMethodInterceptor对rpc调用类的实现进行代理

     1 public class SpringMethodInterceptor implements MethodInterceptor {
     2 
     3 
     4     public Object invoke(MethodInvocation inv) throws Throwable {
     5     System.out.println(inv.getMethod().getDeclaringClass().getName() + " " + inv.getArguments());
     6         String version=rpcProxyRegManager.getVersion(inv.getMethod().getDeclaringClass().getName());
     7         RPCSystemProtocol message=RPCSystemProtocolPackageUtil.getRPCProtocolPackage(inv.getMethod(),inv.getArguments(),version);
     8         rpcClient.sendRPCProtocol(message);//发送调用协议
     9         UUID uuidOrigin=message.uuid;
    10         RPCSystemProtocol recvMessage=lockManager.waitforAnswer(uuidOrigin);//阻塞当前线程,等待rpcServer返回调用结果
    11         Class<?> returnType=inv.getMethod().getReturnType();
    12         return gson.fromJson(recvMessage.getReturnObject(),returnType);
    13 
    14     }
    15 
    16 }

    读卡器部分:

    采用netty接收读卡器数据

     1 public void initReaderServer() {
     2         ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
     3         bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
     4 
     5             @Override
     6             public ChannelPipeline getPipeline() throws Exception {
     7                 ChannelPipeline pipeline = Channels.pipeline();
     8                 pipeline.addLast("UP_FRAME_HANDLER", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2, 0, 2));
     9                 pipeline.addLast("DOWN_FRAME_HANDLER", new LengthFieldPrepender(2, false));
    10                 pipeline.addLast("myHandler", readerNettyHandler);
    11                 // return Channels.pipeline(rpcServerNettyHandler);
    12                 return pipeline;
    13             }
    14 
    15         });
    16         bootstrap.bind(new InetSocketAddress(port));
    17         System.out.println("reader data server开启成功");
    18     }

    接收到读卡器数据后的操作如下,详见ReaderDataManager.java

    1     public void OriginalDataDealing(RFIDOriginalInfos infos){
    2         submitData(infos.getInfos());//存入数据库
    3         sendOutDataComingMessage(infos);//发送消息给读卡器模块进行状态定义
    4     }

    通过消息中心将接收到的读卡器数据推送给读卡器模块

     1     private void sendOutDataComingMessage(RFIDOriginalInfos infos){
     2         WardenMessage msg=new WardenMessage();
     3         msg.setKind(WardenMessage.KIND_NEW_DATA_COMING+WardenMessage.DIR_ENTER);
     4         String target="";
     5         for (String s:infos.getTargets()){
     6             target+=s+WardenMessage.TARGET_TYPE_READER+"|";
     7         }
     8         msg.setTarget(target);
     9         
    10         msg.setNote(gson.toJson(infos.getInfos()));
    11         readerMessageComingPusher.sendOutMessage(msg);
    12     }

    由上文设备模块的创建方法可创建读卡器设备模块,详情见Reader.java

     1 public class Reader extends EquipmentObject {
     2 
     3     private int targetRFID = 0;
     4     private String targetMessageKind = "";
     5     private String targetKind = "";
     6     private String targetMessageDir = "";
     7 
     8     @Override
     9     public void initWarden() {
    10     
    11         this.registWarden(new Warden(String.valueOf(this.getRfid()) + WardenMessage.TARGET_TYPE_READER, WardenMessage.KIND_NEW_DATA_COMING + WardenMessage.DIR_ENTER) {
    12 
    13             @Override
    14             public void asynchronizedProcess(String message) {
    15                 WardenMessage wardenMessage = new WardenMessage();
    16                 wardenMessage.setNote(message);
    17                 wardenMessage.setTarget(String.valueOf(targetRFID) + targetKind);
    18                 wardenMessage.setKind(targetMessageKind + targetMessageDir);
    19                 sendOutMessage(wardenMessage);
    20             }
    21 
    22         });
    23     }
    24 
    25 }

    在reader模块中注册了对读卡器新接收到数据的信息的监听

     

  • 相关阅读:
    Vim学习指南
    frambuffer lcd.c
    工控显示界面
    ubuntu nfs 开发板
    java初学1
    使用多态来实现数据库之间的切换
    Space Shooter 太空射击
    CandyCrush 糖果传奇
    进制转换以及原码、反码、补码
    winform小知识
  • 原文地址:https://www.cnblogs.com/waterfalleagle/p/3461431.html
Copyright © 2011-2022 走看看