毕设项目,系统搭建笔记文档
2013-12-06 15:05
337 查看
代码结构:
![](http://images.cnitblog.com/blog/94844/201312/05130310-bca5a86af89c494b98f752c5e16507f1.jpg)
主体系统启动流程:
在dynamic web project中添加全局监听类RootListener,继承ServletContextListener接口,实现public void contextInitialized(ServletContextEvent sce),调用系统初始化入口类ArchtechRoot。在ArchtechRoot中根据spring配置文件进行系统各模块的初始化。从root bean读取SystemInitDO,用于获取配置文件中的子配置文件,即各层模块配置文件,并将其中的bean进行装配。RPCServer为RPC服务的基础server模块,对应rpcRoot bean。
子配置文件:
子配置文件中几个关键注册管理机
bean 分类注册管理机
异步任务注册机
消息注册管理机
生产过程模块管理机
bean注册管理机
如代码所示,根据类类型就行分类注册
RPC接口注册:
RPC接口定义在springContext-rpc.xml中
如以下示例接口定义
RPCServer创建
在RPCServer.java中,Rpc接口bean注册
将已注册RPC接口与已注册模块关联:
ArchtechRoot.java
对已填充beanId字段的RPC接口类进行关联
对未填充beanId字段的RPC接口类进行实例创建(目前均使用单例模式)
以上完成所有模块的创建和注册关联工作
启动异步任务注册机中的所有异步任务:
消息注册部分Shadowsong
消息注册管理机WardenManager.java
使用消息注册机时先进行消息注册
发送消息:
message类型为WardenMessage
纯虚类EquipmentObjetc类型继承了WardenOperator接口实现方法
所以继承了EquipmentObject的类直接调用sendOutMessage(WardenMessage message)即可。
举例:
读卡器模块初始化时(读卡器模块继承了EquipmentObject)
以上代码截取自Reader.java表示在接收到warden消息后将其信息实体取出并重新定义warden消息的目标和类型并转发,我们现在做一个约定:
消息接收者:目标RFID+目标类型
消息类型:消息类型+消息流向
WardenMessage.java中展示预设了几种消息类型
模块间信息交互和数据传输均可使用该消息系统
生产过程管理模块(静态模块系统leon)
过程注册模块中包含所有已注册的过程模块信息
生产过程模块(静态模块):
统一继承IProcessModule,具体见IProcessModule.java
在过程模块中建立设备列表,通过spring bean注入设备,可达到过程对设备的一个管理,实例见SortingProcess.java
对应bean的spring配置参考spring-module.xml,如下:
设备模块
统一继承纯虚类EquipmentObject,在EquipmentObject.java中已实现设备的基本功能方法
在配置设备bean时注意设置init-method="initWarden"从而调用initWarden函数进行消息注册
例:
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服务端实现通信
NettyHandler继承SimpleChannelHandler对通信接口进行一些基本封装
RPCServerNettyHandler继承NettyHandler
重写onMessageReceived
rpc client端
客户端进行RPC调用思路:
在配置文件中注册需要使用rpc的bean,通过该bean获取一个实例并使用对应的接口方法,利用spring的特性对该接口方法进行代理,将方法的实现转换成netty通信,把调用方法的参数发送给rpc server,并在rpcLockManager中进行一个注册并阻塞当前方法执行线程,等待server返回结果;当server返回结果后,在rpcLockManager中对等待结果的调用进行解锁并唤醒线程,传入server发过来的结果,再又代理返回方法调用结果。使客户端程序员的编码结构不发生任何改变的情况下实现远程调用。
RPCClient.java
基本上和RCPServer.java类似,不过这里创建的是netty服务端
用SpringMethodInterceptor对rpc调用类的实现进行代理
读卡器部分:
采用netty接收读卡器数据
接收到读卡器数据后的操作如下,详见ReaderDataManager.java
通过消息中心将接收到的读卡器数据推送给读卡器模块
由上文设备模块的创建方法可创建读卡器设备模块,详情见Reader.java
在reader模块中注册了对读卡器新接收到数据的信息的监听
![](http://images.cnitblog.com/blog/94844/201312/05130310-bca5a86af89c494b98f752c5e16507f1.jpg)
主体系统启动流程:
在dynamic web project中添加全局监听类RootListener,继承ServletContextListener接口,实现public void contextInitialized(ServletContextEvent sce),调用系统初始化入口类ArchtechRoot。在ArchtechRoot中根据spring配置文件进行系统各模块的初始化。从root bean读取SystemInitDO,用于获取配置文件中的子配置文件,即各层模块配置文件,并将其中的bean进行装配。RPCServer为RPC服务的基础server模块,对应rpcRoot bean。
ApplicationContext context = new ClassPathXmlApplicationContext("springContext-*.xml"); SystemInitDO initDO = (SystemInitDO) context.getBean("root"); RPCServer rpcRoot = (RPCServer) context.getBean("rpcRoot");
子配置文件:
<bean id="root" class=" com.multiagent.hawklithm.davinci.init.SystemInitDO"> <property name="configFileList"> <list> <value>spring-config/spring-asyntask.xml</value> <value>spring-config/spring-EventListener.xml</value> <value>spring-config/spring-dao.xml</value> <value>spring-config/spring-manager.xml</value> <value>spring-config/spring-module.xml</value> <value>spring-config/spring-ibatis.xml</value> <value>spring-config/spring-net.xml</value> <value>spring-config/spring-transaction.xml</value> <value>spring-config/spring-session.xml</value> </list> </property> </bean>
子配置文件中几个关键注册管理机
bean 分类注册管理机
<!-- bean分类注册管理机 --> <bean class="com.multiagent.hawklithm.davinci.init.AutoRegister"/>
异步任务注册机
<!-- 异步任务注册机 --> <bean id="asynTaskRegManager" class="com.multiagent.hawklithm.davinci.AsynTaskRegisterMachine" />
消息注册管理机
<!-- 消息注册管理机 --> <bean id=" wardenManager" class="com.multiagent.hawklithm.shadowsong.manager.WardenManager"/>
生产过程模块管理机
<!-- 生产过程模块管理注册机 --> <bean id="pmRegManager" class="com.multiagent.hawklithm.leon.manager.ProcessModuleRegisterManager"/>
bean注册管理机
public class AutoRegister implements BeanPostProcessor { private AsynTaskRegisterMachine asynTaskRegManager; private ProxyFactoryBean accountService; private ProcessModuleRegisterManager pmRegManager; public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof AsynTaskRegister) { System.out.println("bean name: "+beanName+" regist AsynTaskRegister"); asynTaskRegManager.regist(bean);//异步任务注册 }else if (bean instanceof IProcessModule){ System.out.println("bean name: "+beanName+" regist EquipmentObject"); pmRegManager.regist(bean);//过程模块注册 } return bean; } }
如代码所示,根据类类型就行分类注册
RPC接口注册:
RPC接口定义在springContext-rpc.xml中
如以下示例接口定义
<bean class="com.multiagent.hawklithm.davinci.rpc.DO.RPCSystemServerProxy"> <property name="interfaceName" value="com.multiagent.hawklithm.rpc.Interfacetest"/> <property name="version" value="1.0.0.hawk"/> <property name="className" value="com.multiagent.hawklithm.rpc.impl.ImplTest"/> <property name="comment" value="此处填写接口介绍"/> <property name="visible" value="true" /> </bean>
RPCServer创建
<bean id="rpcRoot" class="com.multiagent.hawklithm.davinci.rpc.Server.RPCServer"> <constructor-arg> <value>10007</value> </constructor-arg> </bean>
在RPCServer.java中,Rpc接口bean注册
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof RPCSystemServerProxy) { RPCregManager.regist((RPCSystemServerProxy) bean); } return bean; }
将已注册RPC接口与已注册模块关联:
ArchtechRoot.java
对已填充beanId字段的RPC接口类进行关联
for (RPCSystemServerProxy object : rpcRoot.getRPCregManager().getRegList()) { if (StringUtils.hasLength(object.getBeanId())) { try { Object target = tempContext.getBean(object.getBeanId()); object.setTarget(target); System.out.println(object.getInterfaceName() + "关联成功"); } catch (NoSuchBeanDefinitionException e) { // TODO 打印日志RPC配置文件中bean缺失 System.out.println("RPC配置文件中缺失bean:[" + object.getBeanId() + "]"); } } }
对未填充beanId字段的RPC接口类进行实例创建(目前均使用单例模式)
for (RPCSystemServerProxy object : rpcRoot.getRPCregManager().getRegList()) { if (!object.isLinked()) { object.setTarget(Class.forName(object.getClassName()).newInstance()); System.out.println(object.getClassName() + "生成实例成功"); } }
以上完成所有模块的创建和注册关联工作
启动异步任务注册机中的所有异步任务:
regManager.startAll();
消息注册部分Shadowsong
消息注册管理机WardenManager.java
public class WardenManager implements IRegisterManager, IMessagePusher<WardenMessage> { public boolean regist(Object object) { /**具体见源码*/ } /** * Warden接收消息的异步线程 * @author hawklithm * */ private class WardenThread implements Runnable { /**具体见源码*/ @Override public void run() { object.receiveMessage(message); } } /** * 推送消息 */ public void push(WardenMessage message) { Set<Warden> list = map.get(message.getKind()); for (Warden object : list) { exec.execute(new WardenThread(object, message)); } } }
使用消息注册机时先进行消息注册
wardenManager.registWarden(new Warden(“MessageReceiver”, “MessageType”) { //message对应消息结构体WardenMessage中的note属性 @Override public void asynchronizedProcess(String message) { /**接收到消息后的行为*/ } });
发送消息:
wardenManager.push(message);
message类型为WardenMessage
纯虚类EquipmentObjetc类型继承了WardenOperator接口实现方法
public void sendOutMessage(WardenMessage message) { wardenManager.push(message); }
所以继承了EquipmentObject的类直接调用sendOutMessage(WardenMessage message)即可。
举例:
读卡器模块初始化时(读卡器模块继承了EquipmentObject)
this.registWarden(new Warden(String.valueOf(this.getRfid()) + WardenMessage.TARGET_TYPE_READER, WardenMessage.KIND_NEW_DATA_COMING + WardenMessage.DIR_ENTER) { @Override public void asynchronizedProcess(String message) { WardenMessage wardenMessage = new WardenMessage(); wardenMessage.setNote(message); wardenMessage.setTarget(String.valueOf(targetRFID) + targetKind); wardenMessage.setKind(targetMessageKind + targetMessageDir); sendOutMessage(wardenMessage); } });
以上代码截取自Reader.java表示在接收到warden消息后将其信息实体取出并重新定义warden消息的目标和类型并转发,我们现在做一个约定:
消息接收者:目标RFID+目标类型
消息类型:消息类型+消息流向
WardenMessage.java中展示预设了几种消息类型
/** * 消息类型 */ public static String KIND_RFID_FROM_READER = "wm_rfidfromreader";//从读卡器模块发送来的RFID数据 public static String KIND_NEW_DATA_COMING = "new_data_coming";//接收到从RFID实体来的数据 /** * 目标类型 */ public static String TARGET_TYPE_READER = "target_type_reader";//数据接收目标类型为读卡器 public static String TARGET_TYPE_MACHINE = "target_type_machine";//数据接收目标类型为设备模块 /** * 数据流方向 */ public static String DIR_ENTER = "wm_enter"; public static String DIR_EXIT = "wm_exit";
模块间信息交互和数据传输均可使用该消息系统
生产过程管理模块(静态模块系统leon)
public class ProcessModuleRegisterManager implements IRegisterManager { private List<IProcessModule> regList = new ArrayList<IProcessModule>(); public boolean regist(Object thing) { /**过程模块注册*/ } public IProcessModule getProcessModuleByName(String name) throws ProcessModuleNotFoundException { /**根据模块名称(ID)获取已注册的过程模块*/ } public EquipmentObject getEquipmentByRFID(int id) throws ProcessModuleNotFoundException { /**根据设备名称(ID)获取已注册的过程模块中的设备模块*/ } }
过程注册模块中包含所有已注册的过程模块信息
生产过程模块(静态模块):
统一继承IProcessModule,具体见IProcessModule.java
public interface IProcessModule { /** * 获取模块名称 * @return 模块名称 */ String getName(); /** * 根据设备RFID从过程模块中获取设备 * @param id 设备RFID * @return * @throws EquipmentNotFoundException */ EquipmentObject getEquipmentByRFID(int id) throws EquipmentNotFoundException; }
在过程模块中建立设备列表,通过spring bean注入设备,可达到过程对设备的一个管理,实例见SortingProcess.java
对应bean的spring配置参考spring-module.xml,如下:
<bean id="sorting_process_module" class="com.multiagent.hawklithm.leon.process.SortingProcess"> <property name="equipmentList"> <list> <ref bean="reader1"/> <ref bean="sorting_equipment1" /> <ref bean="reader2" /> <ref bean="singleRead3"/> <ref bean="sorting_equipment2" /> </list> </property> </bean>
设备模块
统一继承纯虚类EquipmentObject,在EquipmentObject.java中已实现设备的基本功能方法
public abstract class EquipmentObject implements Module, WardenOperator { private int rfid ; private Set<Integer> itemRFIDs = new HashSet<Integer>(); private Set<Integer> packageRFIDs = new HashSet<Integer>(); private int staffRFID; private WardenManager wardenManager; /** * 设置设备属性 */ abstract public void doSetEquipmentParameter(); /** * 获取设备属性 * @return */ abstract public String doGetEquipmentSummaryInfo(); /** * 初始化Warden */ abstract public void initWarden(); public void sendOutMessage(WardenMessage message) { wardenManager.push(message); } public void registWarden(Warden warden) { wardenManager.regist(warden); } public void addItem(int RFID) { itemRFIDs.add(Integer.valueOf(RFID)); } public void addPackage(int RFID) { packageRFIDs.add(Integer.valueOf(RFID)); } public boolean removeItem(int RFID) { return itemRFIDs.remove(Integer.valueOf(RFID)); } public boolean removePackage(int RFID) { return packageRFIDs.remove(Integer.valueOf(RFID)); } // public EquipmentObject() { // warden = new Warden(this); // wardenManager.regist(warden); // } public String doGetModuleSummaryInfo() { return doGetEquipmentSummaryInfo(); } public int getStaffRFID() { return staffRFID; } public void setStaffRFID(int staffRFID) { this.staffRFID = staffRFID; } public WardenManager getWardenManager() { return wardenManager; } public void setWardenManager(WardenManager wardenManager) { this.wardenManager = wardenManager; } }
在配置设备bean时注意设置init-method="initWarden"从而调用initWarden函数进行消息注册
例:
<bean id="sorting_equipment1" class="com.multiagent.hawklithm.leon.module.SortingEquipmentModule" init-method="initWarden" > <property name="rfid" value="1024"/> </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服务端实现通信
private void initNetty() { ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); bootstrap.setPipelineFactory(new ChannelPipelineFactory() { @Override public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); pipeline.addLast("UP_FRAME_HANDLER", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2, 0, 2)); pipeline.addLast("DOWN_FRAME_HANDLER", new LengthFieldPrepender(2, false)); pipeline.addLast("myHandler", rpcServerNettyHandler); // return Channels.pipeline(rpcServerNettyHandler); return pipeline; } }); bootstrap.bind(new InetSocketAddress(port)); System.out.println("RPC server开启成功"); }
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
@Override public void onMessageReceived(String msg, Channel cha) throws MessageTransportException { System.out.println(msg); RPCSystemProtocol rpcMessage = gson.fromJson(msg, RPCSystemProtocol.class); if (!aclManager.verifyRPCInterfaceCall(rpcMessage)) {//权限控制 rpcMessage.setReturnObject("have no permission"); return; } if (!rpcMessage.selfCheck()) {//数据自检 throw new MessageTransportException("RPC包错误"); } try { Object instance = RPCregManager.getTarget(rpcMessage); Object ret = rpcExec.exec(rpcMessage.getClassName(), rpcMessage.getMethodName(), rpcMessage.getParamsType(), instance, rpcMessage.getParameters());//通过反射机制调用响应类的方法执行并得出结果 rpcMessage.setReturnObject(gson.toJson(ret)); if (!watcher.insert(new RPCConnectInfo(gson.toJson(rpcMessage), cha))) {//将需要返回的结果插入发送队列,由于开发RPC时还没有开始设计消息管理中心,所以使用其独立的RPCBufferCallBackWatcher类进行返回数据队列的管理,详见RPCBufferCallBackWatcher // TODO 打印日志 } } catch (RPCInterfaceNotFoundException e) { // TODO 打印日志 e.printStackTrace(); return; } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); return; } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); return; } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); return; } }
rpc client端
客户端进行RPC调用思路:
在配置文件中注册需要使用rpc的bean,通过该bean获取一个实例并使用对应的接口方法,利用spring的特性对该接口方法进行代理,将方法的实现转换成netty通信,把调用方法的参数发送给rpc server,并在rpcLockManager中进行一个注册并阻塞当前方法执行线程,等待server返回结果;当server返回结果后,在rpcLockManager中对等待结果的调用进行解锁并唤醒线程,传入server发过来的结果,再又代理返回方法调用结果。使客户端程序员的编码结构不发生任何改变的情况下实现远程调用。
RPCClient.java
基本上和RCPServer.java类似,不过这里创建的是netty服务端
public void initRPCClient() { ClientBootstrap bootstrap = new ClientBootstrap(new NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); handler = new NettyHandler() { private Gson gson = new Gson(); @Override public void onMessageReceived(String msg, Channel cha) throws MessageTransportException { RPCSystemProtocol rpcMessage = gson.fromJson(msg, RPCSystemProtocol.class); if (!rpcMessage.selfCheck()) { throw new MessageTransportException("RPC包错误"); } // announcer.insert(rpcMessage); lockManager.AnswerReceived(rpcMessage.uuid, rpcMessage);//接收到服务端回复后将结果返回并将rpc调用解锁 } @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { channel = e.getChannel(); } }; bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); pipeline.addLast("UP_FRAME_HANDLER", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2, 0, 2)); pipeline.addLast("DOWN_FRAME_HANDLER", new LengthFieldPrepender(2, false)); // return Channels.pipeline(handler); pipeline.addLast("myHandler", handler); return pipeline; } }); bootstrap.connect(new InetSocketAddress(address, port)); }
用SpringMethodInterceptor对rpc调用类的实现进行代理
public class SpringMethodInterceptor implements MethodInterceptor { public Object invoke(MethodInvocation inv) throws Throwable { System.out.println(inv.getMethod().getDeclaringClass().getName() + " " + inv.getArguments()); String version=rpcProxyRegManager.getVersion(inv.getMethod().getDeclaringClass().getName()); RPCSystemProtocol message=RPCSystemProtocolPackageUtil.getRPCProtocolPackage(inv.getMethod(),inv.getArguments(),version); rpcClient.sendRPCProtocol(message);//发送调用协议 UUID uuidOrigin=message.uuid; RPCSystemProtocol recvMessage=lockManager.waitforAnswer(uuidOrigin);//阻塞当前线程,等待rpcServer返回调用结果 Class<?> returnType=inv.getMethod().getReturnType(); return gson.fromJson(recvMessage.getReturnObject(),returnType); } }
读卡器部分:
采用netty接收读卡器数据
public void initReaderServer() { ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); bootstrap.setPipelineFactory(new ChannelPipelineFactory() { @Override public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); pipeline.addLast("UP_FRAME_HANDLER", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2, 0, 2)); pipeline.addLast("DOWN_FRAME_HANDLER", new LengthFieldPrepender(2, false)); pipeline.addLast("myHandler", readerNettyHandler); // return Channels.pipeline(rpcServerNettyHandler); return pipeline; } }); bootstrap.bind(new InetSocketAddress(port)); System.out.println("reader data server开启成功"); }
接收到读卡器数据后的操作如下,详见ReaderDataManager.java
public void OriginalDataDealing(RFIDOriginalInfos infos){ submitData(infos.getInfos());//存入数据库 sendOutDataComingMessage(infos);//发送消息给读卡器模块进行状态定义 }
通过消息中心将接收到的读卡器数据推送给读卡器模块
private void sendOutDataComingMessage(RFIDOriginalInfos infos){ WardenMessage msg=new WardenMessage(); msg.setKind(WardenMessage.KIND_NEW_DATA_COMING+WardenMessage.DIR_ENTER); String target=""; for (String s:infos.getTargets()){ target+=s+WardenMessage.TARGET_TYPE_READER+"|"; } msg.setTarget(target); msg.setNote(gson.toJson(infos.getInfos())); readerMessageComingPusher.sendOutMessage(msg); }
由上文设备模块的创建方法可创建读卡器设备模块,详情见Reader.java
public class Reader extends EquipmentObject { private int targetRFID = 0; private String targetMessageKind = ""; private String targetKind = ""; private String targetMessageDir = ""; @Override public void initWarden() { this.registWarden(new Warden(String.valueOf(this.getRfid()) + WardenMessage.TARGET_TYPE_READER, WardenMessage.KIND_NEW_DATA_COMING + WardenMessage.DIR_ENTER) { @Override public void asynchronizedProcess(String message) { WardenMessage wardenMessage = new WardenMessage(); wardenMessage.setNote(message); wardenMessage.setTarget(String.valueOf(targetRFID) + targetKind); wardenMessage.setKind(targetMessageKind + targetMessageDir); sendOutMessage(wardenMessage); } }); } }
在reader模块中注册了对读卡器新接收到数据的信息的监听
相关文章推荐
- windows 2008 R2系统下搭建php项目运行环境步骤,仅为自己学习笔记
- MVC项目结构搭建及单个类的实现学习笔记1
- 独立完成项目-----基建搭建租赁管理系统
- django学习笔记二:一个项目多个App项目搭建
- Grunt学习笔记之开发环境的搭建与创建一个基本的项目
- Java Web笔记:搭建环境和项目配置(MyEclipse 2014 + Maven + Tomcat)
- Linux系统下的web项目环境搭建
- 大数据技术学习笔记之网站流量日志分析项目:Flume日志采集系统1
- 网上图书商城项目学习笔记-003系统功能模块分析
- 【项目记录】山东大学场馆管理系统之——文档管理
- 项目总结—校园办公管理系统(SSM框架搭建)
- Linux运维笔记-文档总结-系统延迟及定时机制
- 大三下半学期“饭店餐饮系统”项目笔记
- 在github上搭建ssm项目,记录轻笔记项目的完成进度
- wiki系统很适合作为项目管理系统和文档管理系统
- [Openwrt 项目开发笔记]:Openwrt平台搭建(一)补遗
- Bootstrap3学习笔记 Bootstrap3文档和栅格系统
- Groovy语言学习和Gradle项目搭建笔记 (上)
- 系统集成项目管理之文档与配置管理
- 项目笔记2:系统菜单OptionsMenu的用法