- 浏览: 3420852 次
- 性别:
- 来自: 珠海
文章分类
- 全部博客 (1633)
- Java (250)
- Android&HTML5 (111)
- Struts (10)
- Spring (236)
- Hibernate&MyBatis (115)
- SSH (49)
- jQuery插件收集 (55)
- Javascript (145)
- PHP (77)
- REST&WebService (18)
- BIRT (27)
- .NET (7)
- Database (105)
- 设计模式 (16)
- 自动化和测试 (19)
- Maven&Ant (43)
- 工作流 (36)
- 开源应用 (156)
- 其他 (16)
- 前台&美工 (119)
- 工作积累 (0)
- OS&Docker (83)
- Python&爬虫 (28)
- 工具软件 (157)
- 问题收集 (61)
- OFbiz (6)
- noSQL (12)
最新评论
-
HEZR曾嶸:
你好博主,这个不是很理解,能解释一下嘛//左边+1,上边+1, ...
java 两字符串相似度计算算法 -
天使建站:
写得不错,可以看这里,和这里的这篇文章一起看,有 ...
jquery 遍历对象、数组、集合 -
xue88ming:
很有用,谢谢
@PathVariable映射出现错误: Name for argument type -
jnjeC:
厉害,困扰了我很久
MyBatis排序时使用order by 动态参数时需要注意,用$而不是# -
TopLongMan:
非常好,很实用啊。。
PostgreSQL递归查询实现树状结构查询
整合Activiti Modeler到业务系统(或BPM平台)
http://www.kafeitu.me/activiti/2013/03/10/integrate-activiti-modeler.html
activit 5.12.1集成activiti-modeler 到 自己的业务系统(集成流程跟踪-完美支持IE) http://jhaij.iteye.com/blog/1871635
根据第二篇文章,整合成功;
FAQ:
1. 无法进入editor.
http://localhost:8080/YouPRJ/modeler/service/editor?id=2050,前提是这个id必需存在与act_re_model表里面,
那么,在调用这个之前,如何插入一条记录到这个表么?
待解决........
-------------
看到咖啡兔的例子,是先使用java保存到数据库,然后再打开editor, 保存的代码:
javascript: 一边保存,一边打开,同时保存后的页面又做reload, 很特别很有趣的做法,值得学习....
2. web editor保存的bpmn20文件到哪里去了?
会更新ACT_RE_MODEL和ACT_GE_BYTEARRAY表,ACT_GE_BYTEARRAY表保存了图片和xml文件信息(其实是json格式的字符串),并关联到ACT_RE_MODEL表。
ACT_RE_MODEL
说明:流程设计器设计流程后,保存数据到该表。
EDITOR_SOURCE_VALUE_ID(流程文件放在ACT_GE_BYTEARRAY中的ID);
EDITOR_SOURCE_EXTRA_VALUE_ID(流程文件图像放在ACT_GE_BYTEARRAY中的ID)。
3. 如何去部署保存在数据库里面的ACT_RE_MODEL表里面的工作流?
咖啡兔的源码: 创建,部署,删除,导出,遍历
问题:
1. java.lang.NoSuchMethodError: org.activiti.engine.impl.bpmn.diagram.ProcessDiagramCanvas.drawSequenceflowWithoutArrow(IIIIZZ)V
应为本地有两个工程的pom.xml都使用了
临时关闭或者删除一个工程,就不会提示这个错误了,至于为什么?我也搞不清楚。。。网上几乎没有人碰到这个错误,莫非是我太幸运???
http://www.kafeitu.me/activiti/2013/03/10/integrate-activiti-modeler.html
activit 5.12.1集成activiti-modeler 到 自己的业务系统(集成流程跟踪-完美支持IE) http://jhaij.iteye.com/blog/1871635
根据第二篇文章,整合成功;
FAQ:
1. 无法进入editor.
http://localhost:8080/YouPRJ/modeler/service/editor?id=2050,前提是这个id必需存在与act_re_model表里面,
那么,在调用这个之前,如何插入一条记录到这个表么?
待解决........
-------------
看到咖啡兔的例子,是先使用java保存到数据库,然后再打开editor, 保存的代码:
javascript: 一边保存,一边打开,同时保存后的页面又做reload, 很特别很有趣的做法,值得学习....
$(function() { $('#create').button({ icons: { primary: 'ui-icon-plus' } }).click(function() { $('#createModelTemplate').dialog({ modal: true, width: 500, buttons: [{ text: '创建', click: function() { if (!$('#name').val()) { alert('请填写名称!'); $('#name').focus(); return; } setTimeout(function() { location.reload(); }, 1000); $('#modelForm').submit(); } }] }); }); });
@RequestMapping(value = "create", method = RequestMethod.POST) public void create(@RequestParam("name") String name, @RequestParam("key") String key, @RequestParam("description") String description, HttpServletRequest request, HttpServletResponse response) { try { ObjectMapper objectMapper = new ObjectMapper(); ObjectNode editorNode = objectMapper.createObjectNode(); editorNode.put("id", "canvas"); editorNode.put("resourceId", "canvas"); ObjectNode stencilSetNode = objectMapper.createObjectNode(); stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#"); editorNode.put("stencilset", stencilSetNode); Model modelData = repositoryService.newModel(); ObjectNode modelObjectNode = objectMapper.createObjectNode(); modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name); modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1); description = StringUtils.defaultString(description); modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description); modelData.setMetaInfo(modelObjectNode.toString()); modelData.setName(name); modelData.setKey(StringUtils.defaultString(key)); repositoryService.saveModel(modelData); repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes("utf-8")); response.sendRedirect(request.getContextPath() + "/service/editor?id=" + modelData.getId()); } catch (Exception e) { logger.error("创建模型失败:", e); } }
2. web editor保存的bpmn20文件到哪里去了?
会更新ACT_RE_MODEL和ACT_GE_BYTEARRAY表,ACT_GE_BYTEARRAY表保存了图片和xml文件信息(其实是json格式的字符串),并关联到ACT_RE_MODEL表。
ACT_RE_MODEL
说明:流程设计器设计流程后,保存数据到该表。
EDITOR_SOURCE_VALUE_ID(流程文件放在ACT_GE_BYTEARRAY中的ID);
EDITOR_SOURCE_EXTRA_VALUE_ID(流程文件图像放在ACT_GE_BYTEARRAY中的ID)。
3. 如何去部署保存在数据库里面的ACT_RE_MODEL表里面的工作流?
咖啡兔的源码: 创建,部署,删除,导出,遍历
package me.kafeitu.demo.activiti.web.workflow; import java.io.ByteArrayInputStream; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.activiti.bpmn.converter.BpmnXMLConverter; import org.activiti.bpmn.model.BpmnModel; import org.activiti.editor.constants.ModelDataJsonConstants; import org.activiti.editor.language.json.converter.BpmnJsonConverter; import org.activiti.engine.RepositoryService; import org.activiti.engine.repository.Deployment; import org.activiti.engine.repository.Model; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.node.ObjectNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.support.RedirectAttributes; /** * 流程模型控制器 * * @author henryyan */ @Controller @RequestMapping(value = "/workflow/model") public class ModelController { protected Logger logger = LoggerFactory.getLogger(getClass()); @Autowired RepositoryService repositoryService; /** * 模型列表 */ @RequestMapping(value = "list") public ModelAndView modelList() { ModelAndView mav = new ModelAndView("workflow/model-list"); List<Model> list = repositoryService.createModelQuery().list(); mav.addObject("list", list); return mav; } /** * 创建模型 */ @RequestMapping(value = "create", method = RequestMethod.POST) public void create(@RequestParam("name") String name, @RequestParam("key") String key, @RequestParam("description") String description, HttpServletRequest request, HttpServletResponse response) { try { ObjectMapper objectMapper = new ObjectMapper(); ObjectNode editorNode = objectMapper.createObjectNode(); editorNode.put("id", "canvas"); editorNode.put("resourceId", "canvas"); ObjectNode stencilSetNode = objectMapper.createObjectNode(); stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#"); editorNode.put("stencilset", stencilSetNode); Model modelData = repositoryService.newModel(); ObjectNode modelObjectNode = objectMapper.createObjectNode(); modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name); modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1); description = StringUtils.defaultString(description); modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description); modelData.setMetaInfo(modelObjectNode.toString()); modelData.setName(name); modelData.setKey(StringUtils.defaultString(key)); repositoryService.saveModel(modelData); repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes("utf-8")); response.sendRedirect(request.getContextPath() + "/service/editor?id=" + modelData.getId()); } catch (Exception e) { logger.error("创建模型失败:", e); } } /** * 根据Model部署流程 */ @RequestMapping(value = "deploy/{modelId}") public String deploy(@PathVariable("modelId") String modelId, RedirectAttributes redirectAttributes) { try { Model modelData = repositoryService.getModel(modelId); ObjectNode modelNode = (ObjectNode) new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId())); byte[] bpmnBytes = null; BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode); bpmnBytes = new BpmnXMLConverter().convertToXML(model); String processName = modelData.getName() + ".bpmn20.xml"; Deployment deployment = repositoryService.createDeployment().name(modelData.getName()).addString(processName, new String(bpmnBytes)).deploy(); redirectAttributes.addFlashAttribute("message", "部署成功,部署ID=" + deployment.getId()); } catch (Exception e) { logger.error("根据模型部署流程失败:modelId={}", modelId, e); } return "redirect:/workflow/model/list"; } /** * 导出model的xml文件 */ @RequestMapping(value = "export/{modelId}") public void export(@PathVariable("modelId") String modelId, HttpServletResponse response) { try { Model modelData = repositoryService.getModel(modelId); BpmnJsonConverter jsonConverter = new BpmnJsonConverter(); JsonNode editorNode = new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId())); BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editorNode); BpmnXMLConverter xmlConverter = new BpmnXMLConverter(); byte[] bpmnBytes = xmlConverter.convertToXML(bpmnModel); ByteArrayInputStream in = new ByteArrayInputStream(bpmnBytes); IOUtils.copy(in, response.getOutputStream()); String filename = bpmnModel.getMainProcess().getId() + ".bpmn20.xml"; response.setHeader("Content-Disposition", "attachment; filename=" + filename); response.flushBuffer(); } catch (Exception e) { logger.error("导出model的xml文件失败:modelId={}", modelId, e); } } @RequestMapping(value = "delete/{modelId}") public String delete(@PathVariable("modelId") String modelId) { repositoryService.deleteModel(modelId); return "redirect:/workflow/model/list"; } }
问题:
1. java.lang.NoSuchMethodError: org.activiti.engine.impl.bpmn.diagram.ProcessDiagramCanvas.drawSequenceflowWithoutArrow(IIIIZZ)V
应为本地有两个工程的pom.xml都使用了
<dependency> <groupId>org.activiti</groupId> <artifactId>activiti-engine</artifactId> <version>${activiti.version}</version> </dependency>
临时关闭或者删除一个工程,就不会提示这个错误了,至于为什么?我也搞不清楚。。。网上几乎没有人碰到这个错误,莫非是我太幸运???
评论
2 楼
pyzheng
2015-08-20
哈哈 其实那时候我也只是玩一下而已 并没有做过多的研究 你问题解决了就好 共勉...........
1 楼
疯狂的君子胤
2015-08-18
我的页面一直错误,我就是找不到错误,后来看到你的这个指导也没注意,直到现在我找到我错误的原因了才看到你的指导,想哭,我这是自作孽呀!!!!!!!!!!!
发表评论
-
drools 规则文件 —— 语法
2014-06-09 21:53 3415原文:http://liureying.blog.163.co ... -
使用eclipse创建bpmn2文件的一些问题
2014-06-07 15:18 1728使用bpmn2 diagram Editor编辑器的问题 1 ... -
JBPM6入门资料: Spring4 + Hibernate4 + JBPM6整合
2014-05-21 19:39 18772参考资料: =============== ... -
我的Activiti例子
2013-09-21 15:01 6897Spring 与Activiti的入门整合 http://ww ... -
各种状态的任务查询以及和业务对象关联
2013-09-21 14:26 1942http://www.kafeitu.me/activiti/ ... -
Activiti: 三种部署方式和几种启动方式
2013-09-20 00:24 4715三种部署: 1.自动部署: <property name ... -
Activiti modeler 国际化要点
2013-09-18 15:33 25401. 界面文本:src/main/resources/sten ... -
Activiti5.12共22张表
2013-09-17 14:10 1959(1)用户管理表 ACT_ID_GROUP; ... -
Activiti: 关于表单的一些接口
2013-09-17 09:31 2480获得流程启动的时候的表单信息 ProcessInstance ... -
Activiti5: TaskQuery查询API
2013-09-16 13:34 3464http://blog.csdn.net/iflow/arti ... -
第一个Activiti5.13 + Spring3.x例子
2013-09-16 13:24 2355参考: http://www.iteye.com/topic/ ... -
kft-activiti-demo: 部署记录
2013-09-13 17:36 20082.SpringMvc + Activiti + Hibern ... -
SSH 整合 Activiti
2013-09-09 14:45 2015原文:http://blog.chinaunix.net/ui ... -
Activiti BPM Platform工作流的一些资料
2013-09-03 16:07 2925Activiti官方: http://www.activiti ... -
JBPM5.4发送email
2013-05-29 15:57 2073JBPM5.4配置参考: http://panyongzhen ... -
Spring3.1 + Hibernate4.2.1 + JBPM5.4 + Ehache整合例子
2013-05-29 11:17 9471pom.xml ----------------------- ... -
JBPM5 Designer 2.3源码问题
2013-05-24 09:50 2336最新本2.4发布,但是里面是使用Maven的module方式来 ... -
Spring 3 & jBPM 5 & LocalTaskService
2013-05-24 09:52 1819帖子地址:https://community.jboss.or ... -
JBPM Designer 部署
2013-05-24 09:53 1627版本:2.4 把war放到tomcat下面之后,进入的url是 ... -
Dynamic Process Creation Using API [JBPM 5.1]
2013-05-23 08:53 1725http://atulkotwale.blogspot.com ...
相关推荐
内容概要:文章探讨了互联网时代的背景下开发一个实用的家庭理财系统的重要性。文中分析了国内外家庭理财的现状及存在的问题,阐述了开发此系统的目的——对家庭财产进行一体化管理,提供统计、预测功能。系统涵盖了家庭成员管理、用户认证管理、账单管理等六大功能模块,能够满足用户多方面查询及统计需求,并保证数据的安全性与完整性。设计中运用了先进的技术栈如SSM框架(Spring、SpringMVC、Mybatis),并采用MVC设计模式确保软件结构合理高效。 适用人群:对于希望科学地管理和规划个人或家庭财务的普通民众;从事财务管理相关专业的学生;有兴趣于家政学、经济学等领域研究的专业人士。 使用场景及目标:适用于日常家庭财务管理的各个场景,帮助用户更好地了解自己的消费习惯和资金状况;为目标客户提供一套稳定可靠的解决方案,助力家庭财富增长。 其他说明:文章还包括系统设计的具体方法与技术选型的理由,以及项目实施过程中的难点讨论。对于开发者而言,不仅提供了详尽的技术指南,还强调了用户体验的重要性。
弹性盒子Flexbox布局.docx
网络财务系统 SSM毕业设计 附带论文 启动教程:https://www.bilibili.com/video/BV1GK1iYyE2B
联想电脑的bios设置、图文都有
1_教务处关于云南师范大学2024年大学生科研训练基金项目立项申报工作的通知 (1).zip
<项目介绍> 基于Python实现的自然语言处理大作业——方面情感分析+源代码+文档说明+实验报告 - 不懂运行,下载完可以私聊问,可远程教学 该资源内项目源码是个人的毕设,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途
内容概要:本文探讨了使用Python语言构建一个集成漏洞扫描系统的可能性,旨在解决中小型网络运维人员面临的网络安全挑战。系统采用B/S架构,使用Django框架实现快速开发,Docker容器承载扫描工具Nmap。文中介绍了项目的背景、国内外研究现状、需求分析、系统设计、实现过程和测试结果。 适合人群:初级运维人员和网络安全研究者。 使用场景及目标:系统平台用于检测Web应用程序的安全漏洞,提供轻量级、学习成本低的解决方案,提升网络安全管理水平。 其他说明:虽然系统实现了预期功能,但仍存在一些不足,如架构相对简单、功能单一等问题,未来可以进一步优化。
功能说明: 功能:个人中心、公告信息管理、学院管理、学生管理、教师管理、督导管理、教师信息管理、学生评教管理、督导评教管理等功能模块。 环境说明: 开发语言:java 框架:ssm jdk版本:jdk1.8 数据库:mysql 5.7+ 数据库工具:Navicat11+ 管理工具:maven 开发工具:idea/eclipse 部署容器:tomcat7+
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手
功能大概包括:商品管理,商品多规格属性管理,商品分类,商品类型,商品品牌,商品订单,会员信息,优惠券,订单管理,加入进货车,立即下单,我的收藏等等 第一:商城后台,功能大概包括:商品管理,商品多规格属性管理,商品分类,商品品牌,商品订单,会员信息等等。 涉及到技术: springboot+Thymeleaf+mybatis 第二:小程序API,涉及到技术: springboot+mybatis-plus+jwt+mapstruct+lombok+redis+swagger 第三:mpvue小程序,小程序主要是用 mpvue 框架开发 mpvue 小程序运行步骤: 1、安装node环境 node 是8版本,这边开发版本是8.12.0,由于mpvue属于老牌小程序框架了,目前这边验证的只是这个node版本, 当然新的小程序UNIAPP发布之后没用此限制拉 2、设置npm淘宝镜像 npm set registry https://registry.npm.taobao.org/ 3、npm install 4、npm run dev
内容概要:本文详细介绍了基于 Java 和 Spring 框架的校园物品维修管理系统的开发与设计。该系统采用 B/S 架构,主要包括管理员、使用者和维修者三类用户的权限管理。系统提供了用户管理、设备管理和维修管理等功能,通过数据库操作确保数据安全性和系统扩展性。开发中采用了面向对象的设计思想和技术手段,提高了系统的可靠性和用户体验。 适合人群:具有一定 Java 基础的软件开发人员和项目管理者。 使用场景及目标:主要用于高校或研究机构中,对校园内各类设备的使用和维修情况进行高效管理,提升设备使用率和维修效率。 其他说明:系统的设计与实现详细描述了需求分析、总体设计、详细设计以及测试过程,为后续的开发和优化提供了全面的参考。
该MATLAB代码使用两步加权最小二乘法通过TDOA技术实现了二维目标定位。它通过随机生成的锚点和目标位置进行模拟,展示了如何通过迭代优化算法来提高位置估计的准确性。代码结构清晰,适合用于理解和实现基于TDOA的定位算法。
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手
本代码是基于python pytorch环境安装的。 下载本代码后,有个环境安装的requirement.txt文本 首先是代码的整体介绍 总共是3个py文件,十分的简便 本代码是不含数据集图片的,下载本代码后需要自行搜集图片放到对应的文件夹下即可 需要我们往每个文件夹下搜集来图片放到对应文件夹下,每个对应的文件夹里面也有一张提示图,提示图片放的位置 然后我们需要将搜集来的图片,直接放到对应的文件夹下,就可以对代码进行训练了。 运行01生成txt.py,是将数据集文件夹下的图片路径和对应的标签生成txt格式,划分了训练集和验证集 运行02CNN训练数据集.py,会自动读取txt文本内的内容进行训练,这里是适配了数据集的分类文件夹个数,即使增加了分类文件夹,也不需要修改代码即可训练 训练过程中会有训练进度条,可以查看大概训练的时长,每个epoch训练完后会显示准确率和损失值 训练结束后,会保存log日志,记录每个epoch的准确率和损失值 最后训练的模型会保存在本地名称为model.ckpt 运行03pyqt界面.py,就可以实现自己训练好的模型去识别图片了
基于“分治法”的排序算法
目录 • 一、微信小程序简介 • 二、微信小程序开发准备 • 三、微信小程序开发框架 • 四、微信小程序开发实例 • 六、微信小程序开发进阶 6.1 组件化开发 6.2 API调用 6.3 云开发 • 七、微信小程序开发注意事项 7.1 遵守规范 7.2 注意性能 7.3 保护用户隐私 • 八、总结 大家好,今天将为大家介绍一下微信小程序的开发。微信小程序是一种不需要下载安装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或者搜一下即可打开应用。本文将从浅入深,以轻松易懂的方式为大家介绍微信小程序的开发。 一、微信小程序简介 微信小程序是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具备出色的使用体验。简单来说,微信小程序就是一种可以在微信内运行的应用程序,它的开发成本较低,运行速度快,用户体验良好。 二、微信小程序开发准备 1. 注册微信小程序账号:首先需要在微信公众平台(https://mp.weixin.qq.com/)注册一个小程序账号,完成相关信息的填写和实名认证。 2. 下载安装微信开发者工具:访问微信公众平台,
在Gazebo上运行基于ROS1寻路算法
数据可视化驾驶舱,包含地图,页面可以直接运行
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手