lightquant.com


  • 首页

  • 标签

  • 分类

  • 归档

  • 关于

  • 搜索

微信精选文章

发表于 2099-12-12 | 分类于 weixin

微信精选文章

中国何时能成为“超级大国”?

为什么建议年轻人不要买房?

房产和投资理财,哪个更好?

养鹅——才能实现财务自由

更多文章请微信搜索“灯塔量化”公众号,跟我一起学习投资理财知识!

weixin

Activiti工作流进阶

发表于 2018-06-24 | 分类于 Activiti

一、Activiti表单

1
2
3
4
5
6
7
8
<startEvent id="startevent1" name="Start">
<extensionElements>
<activiti:formProperty id="userName" name="userName"
variable="userName" type="string" />
<activiti:formProperty id="age" name="age"
variable="age" type="string" />
</extensionElements>
</startEvent>
1
2
3
4
5
6
7
8
9
10
11
12
13
FormService formService = engine.getFormService();
StartFormData sfd = formService.getStartFormData(pd.getId());
List<FormProperty> formProps = sfd.getFormProperties();
Map<String, Object> variables = Maps.newHashMap();
for(FormProperty fp : formProps) {
System.out.println(fp.getName() + "--" + fp.getType());
if (StringFormType.class.isInstance(formProperty.getType())) {
variables.put(formProperty.getId(), "1");
} else if (DateFormType.class.isInstance(formProperty.getType())) {
variables.put(formProperty.getId(), "1");
}
taskService.complete(task.getId(), variables);
}

执行任务

1
2
//这样也会执行任务到下一个任务节点
proccessEngine.getFormService().submitTaskFormData(task.getId(),map);

二、事件监听

配置监听

activiti.cfg.xml配置文件添加配置:
添加一个bean实现ActivitiEventListener接口
根据ActivitiEventType枚举判断监听的类型

程序添加
runtimeService.addEventListener(new MyEventListenner());

主动触发监听自定义类型

runtimeService.dispatchEvent(new ActivitiEventImpl(ActivitiEventType.CUSTOM));

会签

利用多实例,实现多个审核通过

其他

taskAssignee 优先 taskCandidateGroup
delegate > setAssignee > claim 后两者都是设置Assignee(代理人),设置claim时,存在就会抛出异常不会设置成功

Activiti工作流基础

发表于 2018-06-04 | 分类于 Activiti

一、activiti配置文件


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- spring模式加载的class不同 -->
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">

<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/db_activiti" />
<!-- 数据库配置也可以直接用数据源dataSource注入 -->
<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
<property name="jdbcUsername" value="root" />
<property name="jdbcPassword" value="root" />
<!-- false:关闭;true:当表不存在时自动创建;create-drop/drop-create -->
<property name="databaseSchemaUpdate" value="true" />
<!-- 监控流程作业,默认false -->
<property name="jobExecutorActivate" value="false" />
<!--
none: 跳过所有的历史数据。性能最优,但是没有历史数据。
activity: 保存所有的流程实例和活动信息。只保留最后信息,没有明细信息。
audit: 默认级别。保存所有的流程实例,任务、活动、表单属性等信息。
full: 最高级别,最完整的的历史信息。除了audit中的信息外,还包含详细信息。
-->
<property name="history" value="audit" />
<!-- 打开异步处理Service任务 -->
<property name="asyncExecutorActivate" value="true"></property>
<!-- 发布流程不生成流程图 -->
<property name="createDiagramOnDeploy" value="false" />
<!-- 字体 -->
<property name="activityFontName" value="宋体" />
<property name="labelFontName" value="宋体" />
<!-- 不保存流程图片 -->
<property name="createDiagramOnDeploy" value="false" />

<property name="DbIdentityUsed" value="true" />
<property name="DbHistoryUsed" value="true" />
<property name="databaseTablePrefix" value="T_" />
<property name="databaseType" value="mysql" />
</bean>

</beans>

二、数据库表

参考:Activiti数据库表结构(表详细版)

activiti6.0新增:

  • ACT_RU_TIMER_JOB 存放定时任务
  • ACT_RU_SUSPENDED_JOB 存放暂停任务
  • ACT_RU_DEADLETTER_JOB 无法执行的任务
  • ACT_EVT_LOG 异步日志表
  • ACT_PROCDEF_INFO 流程定义扩展表

三、service接口

  • RepositoryService

    流程仓库Service,用于管理流程仓库,如部署、删除、读取流程资源。

  • IdentifyService

    身份Service,管理和查询用户、组之间的关系。

  • RuntimeService

    运行时Service,管理所有正在运行状态的流程实例、任务等。

  • TaskService

    任务Service,用于管理、查询任务,如签收、办理、指派等。

  • FormService

    表单Service,用于读取和流程、任务相关的表单数据。

  • HistoryService

    历史Service,可以查询所有历史数据。

  • ManagementService

    引擎管理Service,和具体业务无关,主要是可以查询引擎配置、数据库、作业等。

7个service都是通过ProcessEngine对象来获取的

ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();

四、activiti流程设计器使用(BPMN2.0规范)

事件

1、事件的分类与定义

  • 定时器事件定义

    可以用在开始事件、中间事件、边界事件。可选指定时间触发、循环触发。支持cron表达式

  • 错误事件定义

    可以用在开始事件、结束事件、边界事件。捕获/抛出错误。

  • 信号事件定义

    通过一个信号控制多个流程实例,可以用在边界事件、中间事件。

  • 消息事件定义

    一个消息控制一个流程实例

  • 取消事件定义

    用在事务子流程模型中,有取消边界事件和取消结束事件

  • 补偿事件定义

    补偿事件

  • 其他事件

2、开始事件

  • 无指定开始事件
  • 定时器开始事件

    必须在配置文件打开异步处理Service任务,可以设置定时器触发方式

  • 消息开始事件

    通过消息名称启动流程:
    ProcessInstance pi = runService.startProcessInstanceByMessage(“msgName”);
    流程配置文件添加<message id="msgA" name="msgName"></message>

  • 错误开始事件

    流程中抛出异常,在事件子流程开始错误事件中捕获异常
    流程配置文件添加<error id="countError" errorCode="abc"></error>
    处理类抛出throw new org.activiti.engine.delegate.BpmnError("abc");

3、结束事件

  • 无指定结束事件

  • 错误结束事件

    流程以错误事件结束,然后事务子流程中就会捕获,从而执行子流程。或者触发边界错误捕获流程。

  • 取消结束事件

    在事务子流程中,触发取消结束事件后,就会触发所有补偿边界事件,然后先执行补偿边界事件,再判断整个事务子流程中是否有边界事件,有就执行事务子流程中的。

    1
    2
    3
    4
    <endEvent id="cancelendevent1" name="CancelEnd">
    <cancelEventDefinition></cancelEventDefinition>
    </endEvent>
    >
  • 终止结束事件

    当一个流程实例中,有多个任务都可以执行(并行网关),有一条执行到了终止结束事件,那么整个流程实例都终止了。

4、边界事件

  • 定时器边界事件

    当触发定时器时,执行定时器指定的任务

  • 错误边界事件

    捕获异常:throw new org.activiti.engine.delegate.BpmnError("abc");

  • 信号边界事件

    ,当执行到某个节点的时候触发信号或者消息时,执行另一个任务。申请–>审批–>审批不通过触发事件–>回到申请

  • 取消边界事件

    当事务子流程中,取消结束事件被触发后,补偿边界事件触发,然后子流程取消边界事件也会触发

  • 补偿边界事件

    1
    2
    3
    4
    <boundaryEvent id="boundarycompensation1" name="Compensate" attachedToRef="usertask1" cancelActivity="true">
    <compensateEventDefinition></compensateEventDefinition>
    </boundaryEvent>
    >

5、中间事件

  • 定时器中间事件(捕获)

    必须等待定时器触发后才能执行后面的节点任务(下个节点延迟拿到执行)

    1
    2
    3
    4
    5
    6
    <intermediateCatchEvent id="timerintermediatecatchevent1"
    name="TimerCatchEvent">
    <timerEventDefinition>
    <timeDuration>PT5S</timeDuration>
    </timerEventDefinition>
    </intermediateCatchEvent>

>

  • 信号中间事件(捕获和抛出)

    比如并行网关里,多条执行任务都是捕获信号中间事件,然后其中一条任务执行完成后,抛出信号中间事件,其他有捕获信号中间时间的执行任务才能往下走。(中间信号事件是自动触发的)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <signal id="finishPay" name="finishPay"></signal>
    <!-- 捕获 -->
    <intermediateThrowEvent id="signalintermediatethrowevent1" name="SignalThrowEvent">
    <signalEventDefinition signalRef="finishPay"></signalEventDefinition>
    </intermediateThrowEvent>
    <!-- 抛出 -->
    <intermediateCatchEvent id="signalintermediatecatchevent2"
    name="SignalCatchEvent">
    <signalEventDefinition signalRef="finishPay"></signalEventDefinition>
    </intermediateCatchEvent>
    >
  • 消息中间事件(捕获)

1
2
3
4
Execution run = runService.createExecutionQuery().messageEventSubscriptionName("message").singleResult();
System.out.println(run.getId());
runService.messageEventReceived("message", run.getId());
>
  • 信号中间事件
1
2
3
4
5
6
7
8
9
// 启动流程
ProcessInstance pi = runService.startProcessInstanceById(pd.getId());
// 查当前的子执行流(只有一个)
Execution exe = runService.createExecutionQuery()
.processInstanceId(pi.getId()).onlyChildExecutions()
.singleResult();
System.out.println(pi.getId() + ", 当前节点:" + exe.getActivityId());
runService.signalEventReceived("testSignal");
>
  • 补偿中间事件

6、补偿事件

补偿边界事件
  • 事务子流程有取消结束事件就会执行子流程中补偿边界事件
  • 触发补偿中间事件==>触发边界补偿事件
补偿中间事件

触发补偿中间事件就会触发所有之前任务的边界补偿事件

任务

1、用户任务

  • 分配任务的候选人

    • 方式1:使用taskService的addCandidateGroup和addCandidateUser方法
    • 方式2:使用XML配置
      id
      1
      2
      3
      4
      5
      6
      7
          <potentialOwner>
      <resourceAssignmentExpression>
      <formalExpression>user(angus), group(management), boss
      </formalExpression>
      </resourceAssignmentExpression>
      </potentialOwner>
      </userTask>
  • 分配任务代理人
    一个任务可以分配多个候选人,但是只能有一个代理人

    • 方式1:使用task对象的setAssignee方法设置代理人
    • 方式2:使用XML配置
      id
      1
      2
      3
      4
      5
      6
              <humanPerformer>
      <resourceAssignmentExpression>
      <formalExpression>user</formalExpression>
      </resourceAssignmentExpression>
      </humanPerformer>
      > </userTask>
  • 权限分配扩展

    1
    2
    3
    4
    <userTask id="usertask1" name="Task A" activiti:assignee="user1"
    activiti:candidateUsers="angus,angus1" activiti:candidateGroups="boss,management">
    </userTask>
    >

当设置代理人的时候,该任务只属于该代理人

  • 使用任务监听器进行权限分配

    见监听器

  • 使用JUEL分配权限

    1
    2
    3
    4
    <userTask id="usertask1" name="My Task" activiti:candidateUsers="${authService.getCandidateUsers()}"
    activiti:candidateGroups="${authService.getCandidateGroups()}" activiti:assignee="${authService.getAssignee()}"
    ></userTask>
    >

启动流程:

1
2
3
4
Map<String, Object> vars = new HashMap<String, Object>();
vars.put("authService", new AuthService());
ProcessInstance pi = runService.startProcessInstanceById(pd.getId(), vars);
>

AuthService类中方法返回List<String>获取String类型即可

2、服务任务

  • Java Service Task

    • activiti:class:必须是该两个接口的实现类JavaDelegate、ActivityBehavior

      必须写死类路径

    • activiti:delegateExpression

      activiti:delegateExpression="${myDelegate}"

      1
      2
      3
      4
      5
      6
      7
          //MyDelegate实现JavaDelegate和Serializable
      MyDelegate de = new MyDelegate();
      Map<String ,Object> vars = new HashMap<String, Object>();
      vars.put("myDelegate", de);
      // 启动流程
      ProcessInstance pi = runService.startProcessInstanceById(pd.getId(), vars);
      >
    • activiti:expression

      activiti:expression="${myBean.print(execution)}"
      activiti:expression="${execution.setVariable('myName', myBean.name)}"

      1
      2
      3
      4
      5
      6
      Map<String ,Object> vars = new HashMap<String, Object>();
      //print方法传入Execution exe,可以获取当前的任务
      vars.put("myBean", new MyBean());//实现Serializable接口,并且有name成员变量,getName方法
      // 启动流程
      ProcessInstance pi = runService.startProcessInstanceById(pd.getId(), vars);
      >

JavaDelegate 会自动执行,ActivityBehavior 会等待

  • Shell Task
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <serviceTask id="servicetask1" name="Service Task" activiti:type="shell">
    <extensionElements>
    <activiti:field name="command" stringValue="cmd"/>
    <activiti:field name="arg1" stringValue="/c"/>
    <activiti:field name="arg2" stringValue="echo"/>
    <activiti:field name="arg3" stringValue="%JAVA_HOME%"/>
    <activiti:field name="outputVariable" stringValue="javaHome"/>
    </extensionElements>
    </serviceTask>
    >

获取参数值runService.getVariable(pi.getId(), "javaHome")

  • Receive Task
1
2
3
4
5
6
7
8
9
10
// 启动流程
ProcessInstance pi = runService.startProcessInstanceById(pd.getId());
// 查当前的子执行流(只有一个)
Execution exe = runService.createExecutionQuery()
.processInstanceId(pi.getId()).onlyChildExecutions()
.singleResult();
System.out.println(pi.getId() + ", 当前节点:" + exe.getActivityId());
// 让它往前走
runService.trigger(exe.getId());
>
  • Web Service Task

    用不上

    3、其他任务与流程监听器

    其他任务

  • 手工任务

    自己会执行,会记录历史数据

  • 接收任务: RuntimeService.trigger(exe.getId())
  • 邮件任务

    自动发送邮件

  • Mule任务
  • 业务规则任务

任务监听器

同Service Task有三种配置方式:

  • class
  • delegateExpression
  • expression

监听器触发:

  • create

    流程创建时

  • assignment

    流程任务分配

  • complete

    任务完成

1
2
3
4
5
6
7
8
9
10
<userTask id="usertask1" name="User Task" activiti:assignee="crazyit">
<extensionElements>
<activiti:taskListener event="create"
class="org.crazyit.act.c10.MyTaskListener">
<activiti:field name="userName" stringValue="crazyit" /></activiti:taskListener>
<activiti:taskListener event="assignment"
class="org.crazyit.act.c10.TaskListenerAssignment"></activiti:taskListener>
<activiti:taskListener event="complete" class="org.crazyit.act.c10.TaskListenerComplete"></activiti:taskListener>
</extensionElements>
</userTask>

监听器也可以获取流程中设置的参数
监听器实现TaskListener接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyTaskListener implements TaskListener {

private FixedValue userName;

public void setUserName(FixedValue userName) {
this.userName = userName;
}

@Override
public void notify(DelegateTask arg0) {
System.out.println("这是自定义任务监听器, " + userName.getExpressionText());
}

}

流程监听器
监听器触发:

  • start

    流程开始

  • take

    流程经过

  • end

    流程完成

1
2
3
4
5
6
7
8
9
10
11
<extensionElements>
<activiti:executionListener event="start"
class="org.crazyit.act.c10.ExecutionListener">
<activiti:field name="userName" stringValue="crazyit" />
</activiti:executionListener>
<activiti:executionListener event="take"
class="org.crazyit.act.c10.ExecutionListenerAssignment"></activiti:executionListener>
<activiti:executionListener event="end"
class="org.crazyit.act.c10.ExecutionListenerComplete">
</activiti:executionListener>
</extensionElements>

监听器实现类是ExecutionListener

流程网关其他

1、子流程

  • 嵌入式子流程

    子流程与外部任务交互必须经过边界事件

  • 调用式子流程
    调用外部流程

    添加callActivity节点,指定外部流程ID:SubProcess<callActivity id="callactivity1" name="调用其他的流程" calledElement="SubProcess"></callActivity>
    获取外部流程的实例:ProcessInstance piSub = runService.createProcessInstanceQuery(). superProcessInstanceId(pi.getId()).singleResult();
    传递参数:

    1
    2
    3
    4
    5
    <extensionElements>
    <activiti:in source="days" target="newDays"/>
    <activiti:out source="myDays" target="resultDays"/>
    </extensionElements>
    >
  • 事件子流程

    可以由错误、信号、消息、定时器事件触发

  • 事务子流程

    在事务子流程中出现异常,子流程边界错误事件会捕捉到。事务子流程中出现取消结束流程,会触发之前的流程任务的边界补偿事务,同时触发子流程取消边界事务

  • 特别子流程

    6.0 新增,在该子流程中,不存在执行顺序,由执行时决定

2、顺序流与网关

条件顺序流

1
2
3
4
<sequenceFlow id="flow3" sourceRef="exclusivegateway1" targetRef="usertask2">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${days <= 3 || day == 5}]]></conditionExpression>
</sequenceFlow>

如果是条件网关的话,不满足条件会报错。多条满足,会默认走第一个
普通顺序流

一个任务不能出现多条普通顺序流吧

网关

  • 单向网关
    与条件顺序流一起使用,只能有一个条件通过
  • 并行网关

  • 兼容网关
    单向网关和并行网关结合体

  • 事件网关
    和中间事务结合使用,多个任务的时候,哪个任务先触发就执行哪条任务
  • 组合网关
    不支持

3、流程活动的特性

  • 多实例流程活动

    创建多个任务实例

    1
    2
    3
    4
    5
    6
    7
    <serviceTask id="servicetask1" name="Service Task" activiti:class="org.crazyit.act.c10.ForeachDelegate">
    <multiInstanceLoopCharacteristics
    isSequential="false">
    <loopCardinality>3</loopCardinality>
    </multiInstanceLoopCharacteristics>
    </serviceTask>
    >
  • 设置循环数据(6.0版本)

    1
    2
    3
    4
     Map<String, Object> vars = new HashMap<String, Object>();
    vars.put("datas1", datas1); //List<String>格式
    ProcessInstance pi = runService.startProcessInstanceById(pd.getId(), vars);
    >
1
2
3
4
5
6
 <serviceTask id="servicetask1" name="Service Task" activiti:class="org.crazyit.act.c10.ForeachDelegate">
<multiInstanceLoopCharacteristics isSequential="false" activiti:elementVariable="data">
<loopDataInputRef>datas1</loopDataInputRef>
</multiInstanceLoopCharacteristics>
</serviceTask>
>
1
2
3
4
5
6
7
8
//处理类,List集合有多少个元素就执行几次
public class ForeachDelegate implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) {
System.out.println("执行服务任务: " + execution.getVariable("data"));
}
}
>

设置了循环了数据,会有内置参数,例如nrOfCompletedInstances是当前执行的实例数
添加<completionCondition>${nrOfCompletedInstances >= 2}</completionCondition>设置条件执行流程

Activiti与BPMN2.0规范

五、流程启动与服务调用API

1、查询

查询所有
通过service获取,各个service查询类似。
service.createGroupQuery().groupName("Group_1").groupType("TYPE_1").list();
分页查询
service.createGroupQuery().listPage(1, 5)
查询单个
service.createGroupQuery().groupName("Group_0").singleResult();
排序
service.createGroupQuery().orderByGroupId().desc().orderByGroupName().asc().list()
自定义查询
service.createNativeGroupQuery(). sql("SELECT * FROM ACT_ID_GROUP where NAME_ = #{name}"). parameter("name", "Group_2").list();
保存
service.newGroup(id); //新增一个执行ID值

###2、流程部署
ZIP

1
2
3
4
FileInputStream fis = new FileInputStream(new File("resource/datas.zip"));
ZipInputStream zis = new ZipInputStream(fis);
builder.addZipInputStream(zis);
builder.deploy();

代码生成流程模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public static void main(String[] args) {
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
// 存储服务
RepositoryService rs = engine.getRepositoryService();
RuntimeService run = engine.getRuntimeService();

DeploymentBuilder builder = rs.createDeployment();
builder.addBpmnModel("My Process", createProcessModel());

Deployment dep = builder.deploy();

}

private static BpmnModel createProcessModel() {
// 创建BPMN模型对象
BpmnModel model = new BpmnModel();
// 创建一个流程定义
org.activiti.bpmn.model.Process process = new org.activiti.bpmn.model.Process();
model.addProcess(process);
process.setId("myProcess");
process.setName("My Process");
// 开始事件
StartEvent startEvent = new StartEvent();
startEvent.setId("startEvent");
process.addFlowElement(startEvent);
// 用户任务
UserTask userTask = new UserTask();
userTask.setName("User Task");
userTask.setId("userTask");
process.addFlowElement(userTask);
// 结束事件
EndEvent endEvent = new EndEvent();
endEvent.setId("endEvent");
process.addFlowElement(endEvent);
// 添加流程顺序
process.addFlowElement(new SequenceFlow("startEvent", "userTask"));
process.addFlowElement(new SequenceFlow("userTask", "endEvent"));
return model;
}

关闭流程部署验证

1
2
3
4
DeploymentBuilder builder = rs.createDeployment();
builder.addClasspathResource("error/schema_error.bpmn");
builder.disableSchemaValidation(); //关闭
builder.deploy();

查询文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
// 存储服务
RepositoryService rs = engine.getRepositoryService();

DeploymentBuilder builder = rs.createDeployment();
builder.addClasspathResource("my_text.txt");
Deployment dep = builder.deploy();
// 数据查询
InputStream is = rs.getResourceAsStream(dep.getId(), "my_text.txt");
int count = is.available();
byte[] contents = new byte[count];
is.read(contents);
String result = new String(contents);
//输入结果
System.out.println(result);

查询流程文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 创建流程引擎
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
// 得到流程存储服务对象
RepositoryService repositoryService = engine.getRepositoryService();
// 部署一份流程文件
Deployment dep = repositoryService.createDeployment()
.addClasspathResource("gen.bpmn").deploy();
// 查询流程定义
//查询流程定义实体
ProcessDefinition def = repositoryService.createProcessDefinitionQuery()
.deploymentId(dep.getId()).singleResult();
// 查询资源文件
InputStream is = repositoryService.getProcessModel(def.getId());
// 读取输入流
int count = is.available();
byte[] contents = new byte[count];
is.read(contents);
String result = new String(contents);
//输入输出结果
System.out.println(result);

查询流程图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 创建流程引擎
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
// 得到流程存储服务对象
RepositoryService repositoryService = engine.getRepositoryService();
// 部署一份流程文件与相应的流程图文件
Deployment dep = repositoryService.createDeployment()
.addClasspathResource("gen.bpmn").deploy();
// 查询流程定义
ProcessDefinition def = repositoryService.createProcessDefinitionQuery()
.deploymentId(dep.getId()).singleResult();
// 查询资源文件
InputStream is = repositoryService.getProcessDiagram(def.getId());
// 将输入流转换为图片对象
BufferedImage image = ImageIO.read(is);
// 保存为图片文件
File file = new File("resource/result.png");
if (!file.exists()) file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);
ImageIO.write(image, "png", fos);
fos.close();
is.close();

删除流程部署

1
2
repositoryService.deleteDeployment(dep.getId());
repositoryService.deleteDeployment(dep.getId(), true); //级联删除(会删除运行实例和历史数据)

3、流程定义

自己指定流程图片

1
2
3
4
5
6
7
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
// 存储服务
RepositoryService rs = engine.getRepositoryService();

DeploymentBuilder builder = rs.createDeployment();
builder.addClasspathResource("test2.bpmn").addClasspathResource("test2.png");
builder.deploy();

流程中止
流程被中止后是不能被重新启动的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
// 存储服务
RepositoryService rs = engine.getRepositoryService();

DeploymentBuilder builder = rs.createDeployment();
builder.addClasspathResource("test3.bpmn");
Deployment dep = builder.deploy();

ProcessDefinition def = rs.createProcessDefinitionQuery()
.deploymentId(dep.getId()).singleResult();

System.out.println("id: " + def.getId());
rs.suspendProcessDefinitionByKey(def.getKey());
// 将会抛出异常,因为流程定义被中止了
RuntimeService runService = engine.getRuntimeService();
runService.startProcessInstanceByKey(def.getKey());

启动流程任务权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
// 存储服务
RepositoryService rs = engine.getRepositoryService();
IdentityService is = engine.getIdentityService();
TaskService ts = engine.getTaskService();
User user = is.newUser(UUID.randomUUID().toString());
user.setFirstName("Angus");
is.saveUser(user);
DeploymentBuilder builder = rs.createDeployment();
builder.addClasspathResource("test3.bpmn");
Deployment dep = builder.deploy();
ProcessDefinition def = rs.createProcessDefinitionQuery()
.deploymentId(dep.getId()).singleResult();
rs.addCandidateStarterUser(def.getId(), user.getId());
//查询该用户有多少个流程可以启动
List<ProcessDefinition> defs = rs.createProcessDefinitionQuery().startableByUser(user.getId()).list();
for(ProcessDefinition de : defs) {
System.out.println(de.getId());
}

###4、流程任务
任务候选人(组)
多少个用户或组能看见这个任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
TaskService ts = engine.getTaskService();
IdentityService is = engine.getIdentityService();
// 创建任务
String taskId = UUID.randomUUID().toString();
Task task = ts.newTask(taskId);
task.setName("test");
ts.saveTask(task);
// 创建用户
String userId = UUID.randomUUID().toString();
User user = is.newUser(userId);
user.setFirstName("angus");
is.saveUser(user);
// 设置任务的候选用户组
ts.addCandidateUser(taskId, userId);

/*添加用户到组*/
//is.createMembership(userId, groupId);

List<Task> tasks = ts.createTaskQuery().taskCandidateUser(userId).list();
System.out.println(userId + " 这个用户有权限处理的任务有:");
for(Task t : tasks) {
System.out.println(t.getName());
}

任务持有人
当前处理该任务用户,一个任务只有一个持有人

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
TaskService ts = engine.getTaskService();
IdentityService is = engine.getIdentityService();
// 创建任务
String taskId = UUID.randomUUID().toString();
Task task = ts.newTask(taskId);
task.setName("test1");
ts.saveTask(task);
// 创建用户
String userId = UUID.randomUUID().toString();
User user = is.newUser(userId);
user.setFirstName("angus1");
is.saveUser(user);
// 设置任务持有人
ts.setOwner(taskId, userId);
// ts.setOwner(taskId, "e110a0a5-1314-4c0c-9ba9-142447b11dea");
// 根据用户来查询他所持有的任务
List<Task> tasks = ts.createTaskQuery().taskOwner(userId).list();
for(Task t : tasks) {
System.out.println(t.getName());
}
engine.close();

任务代理人

1
2
3
4
5
//任务被认领之后,其他人认领就会报错
ts.claim(taskId, user.getId());

//任务指定代理人
ts.setAssignee(taskId, user.getId());

任务完成
taskService.complete(task.getId());

4、参数与附件

设置参数

  • a、流程配置文件设置

    1
    2
    3
    4
    5
    6
    7
    <!-- process标签里面 -->
    <dataObject id="personName" name="personName"
    itemSubjectRef="xsd:string">
    <extensionElements>
    <activiti:value>Crazyit</activiti:value>
    </extensionElements>
    </dataObject>
  • b、启动流程设置

    1
    2
    3
    4
    5
    6
    7
    Map<String,Object> map = new HashMap<>();
    Person p = new Person();
    p.setId(1);
    p.setName("angus");
    map.put("p", p);
    map.put("key", "val1");
    ProcessInstance pi = runService.startProcessInstanceById(pd.getId(),map);
  • c、服务设置

    1
    2
    runService.setVariable(execution.getId(), "key",value);
    taskService.setVariable(task.getId(), "key", value);
  • d、设置本地参数
    setVariable变成setVariableLocal

获取参数值

1
2
runService.getVariable(execution.getId(), "key");
taskService.getVariable(task.getId(), "key");

附件

5、启动流程

1
2
3
4
5
6
7
//通过ID启动并设置business_key参数
runService.startProcessInstanceById(pd.getId(), "test");
//通过key值启动
runService.startProcessInstanceByKey(pd.getKey());
//通过消息启动,消息开始事件
runService.startProcessInstanceByMessage(message);
//

6、流程操作与数据查询

task流程
taskService.complete(task.getId());
Receive Task流程
该task不会产生task数据,只有execution

1
2
3
4
5
6
7
8
9
// 启动流程
ProcessInstance pi = runService.startProcessInstanceById(pd.getId());
// 查当前的子执行流(只有一个)
Execution exe = runService.createExecutionQuery()
.processInstanceId(pi.getId()).onlyChildExecutions()
.singleResult();
System.out.println(pi.getId() + ", 当前节点:" + exe.getActivityId());
// 让它往前走
runService.trigger(exe.getId());

7、JOB

手动执行任务(act_run_job)

1
2
3
4
Job job = managementService.createJobQuery().singleResult();
//设置重试次数
managementService.setJobRetries(job.getId(), 1);
managementService.executeJob(job.getId());

六、其他

6.0版本支持activiti:candidateGroups=”${prd_add}”
5.X版本只能activiti:candidateGroups=”#{prd_add}”

AngularJS

发表于 2018-04-30 | 分类于 前端

例子

  • ng-app 指令告诉 AngularJS,
    元素是 AngularJS 应用程序 的”所有者”。
  • ng-model 指令把输入域的值绑定到应用程序变量 name。
  • ng-bind 指令把应用程序变量 name 绑定到某个段落的 innerHTML。
1
2
3
4
5
6
7
8
9
<div ng-app="">
<p>名字 : <input type="text" ng-model="name"></p>
<h1>Hello {{name}}</h1>
</div>


<div ng-app="" ng-init="firstName='John'">
<p>姓名为 <span ng-bind="firstName"></span></p>
</div>

ng-app作用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div ng-app="myApp" ng-controller="myCtrl">

名: <input type="text" ng-model="firstName"><br>
姓: <input type="text" ng-model="lastName"><br>
<br>
姓名: {{firstName + " " + lastName}}

</div>

<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.firstName= "John";
$scope.lastName= "Doe";
});
</script>

AngularJS 对象

1
2
3
4
5
<div ng-app="" ng-init="person={firstName:'John',lastName:'Doe'}">

<p>姓为 {{ person.lastName }}</p>

</div>

AngularJS 数组

1
2
3
4
5
<div ng-app="" ng-init="points=[1,15,19,2,40]">

<p>第三个值为 <span ng-bind="points[2]"></span></p>

</div>

重复 HTML 元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div ng-app="" ng-init="names=['Jani','Hege','Kai']">
<p>使用 ng-repeat 来循环数组</p>
<ul>
<li ng-repeat="x in names">
{{ x }}
</li>
</ul>
</div>

<div ng-app="" ng-init="names=[
{name:'Jani',country:'Norway'},
{name:'Hege',country:'Sweden'},
{name:'Kai',country:'Denmark'}]">

<p>循环对象:</p>
<ul>
<li ng-repeat="x in names">
{{ x.name + ', ' + x.country }}
</li>
</ul>

</div>

创建自定义的指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<body ng-app="myApp">

<runoob-directive></runoob-directive>

<script>
var app = angular.module("myApp", []);
app.directive("runoobDirective", function() {
return {
restrict : "A",
template : "<h1>自定义指令!</h1>"
};
});
</script>

</body>

你可以通过以下方式来调用指令:

  • 元素名
    <runoob-directive></runoob-directive>
  • 属性
    <div runoob-directive></div>
  • 类名
  • 注释

restrict 值可以是以下几种:

  • E 作为元素名使用
  • A 作为属性使用
  • C 作为类名使用
  • M 作为注释使用
    restrict 默认值为 EA, 即可以通过元素名和属性名来调用指令。

ng-model 指令

1
2
3
4
5
6
7
8
9
10
11
<div ng-app="myApp" ng-controller="myCtrl">
名字: <input ng-model="name">
<h1>你输入了: {{name}}</h1>
</div>

<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.name = "John Doe";
});
</script>

验证用户输入

1
2
3
4
5
<form ng-app="" name="myForm">
Email:
<input type="email" name="myAddress" ng-model="text">
<span ng-show="myForm.myAddress.$error.email">不是一个合法的邮箱地址</span>
</form>

应用状态

1
2
3
4
5
6
7
8
9
<form ng-app="" name="myForm" ng-init="myText = 'test@runoob.co">

Email:
<input type="email" name="myAddress" ng-model="myText" required>
<p>编辑邮箱地址,查看状态的改变。</p>
<h1>状态</h1>
<p>Valid: {{myForm.myAddress.$valid}} (如果输入的值是合法的则为 true)。</p>
<p>Dirty: {{myForm.myAddress.$dirty}} (如果值改变则为 true)。</p>
<p>Touched: {{myForm.myAddress.$touched}} (如果通过触屏点击则为 true)。</p>

CSS 类

1
2
3
4
5
6
7
8
9
10
11
<style>
input.ng-invalid {
background-color: lightblue;
}
</style>
<body>

<form ng-app="" name="myForm">
输入你的名字:
<input name="myAddress" ng-model="text" required>
</form>

ng-model 指令根据表单域的状态添加/移除以下类:

  • ng-valid: 验证通过
  • ng-invalid: 验证失败
  • ng-valid-[key]: 由$setValidity添加的所有验证通过的值
  • ng-invalid-[key]: 由$setValidity添加的所有验证失败的值
  • ng-pristine: 控件为初始状态
  • ng-dirty: 控件输入值已变更
  • ng-touched: 控件已失去焦点
  • ng-untouched: 控件未失去焦点
  • ng-pending: 任何为满足$asyncValidators的情况

AngularJS Scope(作用域)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div ng-app="myApp" ng-controller="myCtrl">
<input ng-model="name">
<h1>{{greeting}}</h1>
<button ng-click='sayHello()'>点我</button>
</div>

<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.name = "Runoob";
$scope.sayHello = function() {
$scope.greeting = 'Hello ' + $scope.name + '!';
};
});
</script>

根作用域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div ng-app="myApp" ng-controller="myCtrl">

<h1>{{lastname}} 家族成员:</h1>

<ul>
<li ng-repeat="x in names">{{x}} {{lastname}}</li>
</ul>

</div>

<script>
var app = angular.module('myApp', []);

app.controller('myCtrl', function($scope, $rootScope) {
$scope.names = ["Emil", "Tobias", "Linus"];
$rootScope.lastname = "Refsnes";
});
</script>

外部文件中的控制器

1
2
3
4
5
6
7
8
9
10
<div ng-app="myApp" ng-controller="personCtrl">

First Name: <input type="text" ng-model="firstName"><br>
Last Name: <input type="text" ng-model="lastName"><br>
<br>
Full Name: {{firstName + " " + lastName}}

</div>

<script src="personController.js"></script>

AngularJS 过滤器

currency 格式化数字为货币格式。
filter 从数组项中选择一个子集。
lowercase 格式化字符串为小写。
orderBy 根据某个表达式排列数组。
uppercase 格式化字符串为大写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div ng-app="myApp" ng-controller="personCtrl">
<input type="number" ng-model="quantity">
<input type="number" ng-model="price">
<p>姓名为 {{ lastName | uppercase }}</p>
<p>姓名为 {{ lastName | lowercase }}</p>
<p>总价 = {{ (quantity * price) | currency }}</p>
</div>

<!--排序-->
<li ng-repeat="x in names | orderBy:'country'">
{{ x.name + ', ' + x.country }}
</li>

<!--过滤输入-->
<p><input type="text" ng-model="test"></p>

<ul>
<li ng-repeat="x in names | filter:test | orderBy:'country'">
{{ (x.name | uppercase) + ', ' + x.country }}
</li>
</ul>

自定义过滤器

1
2
3
4
5
6
7
8
9
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.msg = "Runoob";
});
app.filter('reverse', function() { //可以注入依赖
return function(text) {
return text.split("").reverse().join("");
}
});

AngularJS 服务

$location服务

返回当前页面的 URL 地址。

1
2
3
4
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $location) {
$scope.myUrl = $location.absUrl();
});

$http 服务

向服务器发送Http请求

1
2
3
4
5
6
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $http) {
$http.get("welcome.htm").then(function (response) {
$scope.myWelcome = response.data;
});
});

$timeout 服务

$timeout 服务对应了 JS window.setTimeout 函数。

1
2
3
4
5
6
7
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $timeout) {
$scope.myHeader = "Hello World!";
$timeout(function () {
$scope.myHeader = "How are you today?";
}, 2000);
});

$interval 服务

$interval 服务对应了 JS window.setInterval 函数。

1
2
3
4
5
6
app.controller('myCtrl', function($scope, $interval) {
$scope.theTime = new Date().toLocaleTimeString();
$interval(function () {
$scope.theTime = new Date().toLocaleTimeString();
}, 1000);
});

创建自定义服务

1
2
3
4
5
6
7
8
9
10
var app = angular.module('myApp', []);

app.service('hexafy', function() {
this.myFunc = function (x) {
return x.toString(16);
}
});
app.controller('myCtrl', function($scope, hexafy) {
$scope.hex = hexafy.myFunc(255);
});

过滤器中,使用自定义服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div ng-app="myApp">
在过滤器中使用服务:
<h1>{{255 | myFormat}}</h1>
</div>
<script>
var app = angular.module('myApp', []);
app.service('hexafy', function() {
this.myFunc = function (x) {
return x.toString(16);
}
});
app.filter('myFormat',['hexafy', function(hexafy) {
return function(x) {
return hexafy.myFunc(x);
};
}]);
</script>

$http

1
2
3
4
5
6
7
8
9
10
11
12
13
// 简单的 GET 请求,可以改为 POST
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// 请求成功执行代码
}, function errorCallback(response) {
// 请求失败执行代码
});

//简写
$http.get('/someUrl', config).then(successCallback, errorCallback);
$http.post('/someUrl', data, config).then(successCallback, errorCallback);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div ng-app="myApp" ng-controller="siteCtrl"> 

<ul>
<li ng-repeat="x in names">
{{ x.Name + ', ' + x.Country }}
</li>
</ul>

</div>

<script>
var app = angular.module('myApp', []);
app.controller('siteCtrl', function($scope, $http) {
$http.get("http://www.runoob.com/try/angularjs/data/sites.php")
.then(function (response) {$scope.names = response.data.sites;});
});
</script>

AngularJS Select(选择框)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div ng-app="myApp" ng-controller="myCtrl">

<select ng-init="selectedName = names[0]" ng-model="selectedName" ng-options="x for x in names">
</select>
<!--也可以使用下面的-->
<select>
<option ng-repeat="x in names">{{x}}</option>
</select>

</div>

<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.names = ["Google", "Runoob", "Taobao"];
});
</script>

ng-options 与 ng-repeat区别

http://www.runoob.com/angularjs/angularjs-select.html

AngularJS 表格

http://www.runoob.com/angularjs/angularjs-tables.html

AngularJS HTML DOM和事件

ng-disabled 指令

1
2
3
4
5
6
7
8
9
10
11
<div ng-app="" ng-init="mySwitch=false">
<p>
<button ng-disabled="mySwitch">点我!</button>
</p>
<p>
<input type="checkbox" ng-model="mySwitch"/>按钮
</p>
<p>
{{ mySwitch }}
</p>
</div>

ng-show 指令

1
2
3
4
<div ng-app="" ng-init="hour=13">
<p ng-show="true">我是可见的。</p>
<p ng-show="false">我是不可见的。</p>
<p ng-show="hour > 12">我是可见的。</p>

ng-hide 指令

1
2
<p ng-hide="true">我是不可见的。</p>
<p ng-hide="false">我是可见的。</p>

ng-click 指令

1
2
<button ng-click="count = count + 1">点我!</button>
<p>{{ count }}</p>

隐藏 HTML 元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<div ng-app="myApp" ng-controller="personCtrl">

<button ng-click="toggle()">隐藏/显示</button>

<p ng-hide="myVar">
<!--<p ng-show="myVar">-->
名: <input type="text" ng-model="firstName"><br>
姓名: <input type="text" ng-model="lastName"><br>
<br>
Full Name: {{firstName + " " + lastName}}
</p>

</div>

<script>
var app = angular.module('myApp', []);
app.controller('personCtrl', function($scope) {
$scope.firstName = "John",
$scope.lastName = "Doe"
$scope.myVar = false;
$scope.toggle = function() {
$scope.myVar = !$scope.myVar;
};
});
</script>

AngularJS 表单

http://www.runoob.com/angularjs/angularjs-forms.html

数据绑定

<input type="text" ng-model="firstname">

Checkbox(复选框)

单选框

单选框使用同一个 ng-model

下拉菜单

HTML 表单

AngularJS 全局 API

全局 API 函数使用 angular 对象进行访问。

  • angular.lowercase() 转换字符串为小写
  • angular.uppercase() 转换字符串为大写
  • angular.isString() 判断给定的对象是否为字符串,如果是返回 true。
  • angular.isNumber() 判断给定的对象是否为数字,如果是返回 true。

switch case语句

1
2
3
4
5
6
<p ng-switch = "x3">
是不是字符串:
<label ng-switch-when = "true">是</label>
<label ng-switch-when = "false">不是</label>
<label ng-switch-when = ""></label>
</p>

AngularJS 包含

包含html页面

ng-include="'runoob.htm'"

跨域包含

AngularJS 动画

AngularJS 依赖注入

AngularJS 路由

###

ng-bind 和花括号的区别就是 启动加载的时候显示不同

netty

发表于 2018-04-30 | 分类于 java框架

同步阻塞IO—-BIO
同步非阻塞IO—-JAVA-NIO
异步非阻塞IO—-JAVA-AIO

Channel:通道
Buffer:缓冲区
Selector:选择器

多个通道注册到一个选择器中,所有的数据都是与缓冲区交互,然后缓冲区与通道交互

ES6快速入门

发表于 2018-04-27 | 分类于 前端

1. 变量声明const和let

  • let表示变量(局部变量)
  • const表示常量(JAVA的final)

2. 模板字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const name = 'lux';
console.log(`hello ${name}`) //hello lux

//多行文本--使用反引号
// ES5
var msg = "Hi \
man!
"
// ES6
const template = `<div>
<span>hello world</span>
</div>`

// 1.includes:判断是否包含然后直接返回布尔值
const str = 'hahay'
console.log(str.includes('y')) // true

// 2.repeat: 获取字符串重复n次
const str = 'he'
console.log(str.repeat(3)) // 'hehehe'
//如果你带入小数, Math.floor(num) 来处理
// s.repeat(3.1) 或者 s.repeat(3.9) 都当做成 s.repeat(3) 来处理

// 3. startsWith 和 endsWith 判断是否以 给定文本 开始或者结束
const str = 'hello world!'
console.log(str.startsWith('hello')) // true
console.log(str.endsWith('!')) // true

3. 函数

默认参数,类似于python

1
2
3
function action(num = 200) {
console.log(num)
}

箭头函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
x => x * x
//等于下面
function (x) {
return x * x;
}

x => {
if (x > 0) {
return x * x;
}
else {p
return - x * x;
}
}

// 两个参数:
(x, y) => x * x + y * y

// 无参数:
() => 3.14

// 可变参数:
(x, y, ...rest) => {
var i, sum = x + y;
for (i=0; i<rest.length; i++) {
sum += rest[i];
}
return sum;
}

//返回对象
x => ({ foo: x })

4. 拓展的对象功能

对象初始化简写

1
2
3
4
5
6
function people(name, age) {
return {
name, // name : name
age // age : age
};
}

浅克隆

5. 更方便的数据访问–解构

1
2
3
4
5
6
7
8
9
10
11
12
//对象
const people = {
name: 'lux',
age: 20
}
const { name, age } = people
console.log(`${name} --- ${age}`)
//数组
const color = ['red', 'blue']
const [first, second] = color
console.log(first) //'red'
console.log(second) //'blue'

Object.assign() 可以把任意多个源对象自身可枚举的属性拷贝给目标对象,然后返回目标对象。第一参数即为目标对象。在实际项目中,我们为了不改变源对象。一般会把目标对象传为{}

6. Spread Operator 展开运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//数组
const color = ['red', 'yellow']
const colorful = [...color, 'green', 'pink']
console.log(colorful) //[red, yellow, green, pink]

//对象
const alp = { fist: 'a', second: 'b'}
const alphabets = { ...alp, third: 'c' }
console.log(alphabets) //{ "fist": "a", "second": "b", "third": "c"

//数组
const number = [1,2,3,4,5]
const [first, ...rest] = number
console.log(rest) //2,3,4,5
}

7. import导入模块、export导出模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//全部导入
import people from './example'

//有一种特殊情况,即允许你将整个模块当作单一对象进行导入
//该模块的所有导出都会作为对象的属性存在
import * as example from "./example.js"
console.log(example.name)
console.log(example.age)
console.log(example.getName())

//导入部分
import {name, age} from './example'

// 导出默认, 有且只有一个默认
export default App

// 部分导出
export class App extend Component {};

作者:陈嘻嘻啊
链接:https://www.jianshu.com/p/287e0bb867ae
來源:简书

python进阶

发表于 2018-04-23 | 分类于 python

python把函数作为参数

1
2
3
4
def add(x, y, f):
return f(x) + f(y)
add(-5, 9, abs)
# 其实是调用 abs(-5) + abs(9)

常用函数

  1. map()函数

    1
    2
    3
    4
    def f(x):
    return x*x
    print map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
    # 输出 [1, 4, 9, 10, 25, 36, 49, 64, 81]
  2. reduce()函数

    1
    2
    3
    def f(x, y):
    return x + y
    print reduce(f, [1, 3, 5, 7, 9])
  3. filter()函数

    1
    2
    3
    4
    def is_odd(x):
    return x % 2 == 1
    filter(is_odd, [1, 4, 6, 7, 9, 12, 17])
    # 输出 [1, 7, 9, 17]
  4. sorted()函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    sorted([36, 5, 12, 9, 21])  # 排序

    def reversed_cmp(x, y):
    if x > y:
    return -1
    if x < y:
    return 1
    return 0
    sorted([36, 5, 12, 9, 21], reversed_cmp)
    # 输出 [36, 21, 12, 9, 5]
  5. 装饰者模式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    from functools import reduce
    def log(f):
    def fn(x):
    print('call ' + f.__name__ + '()...')
    return f(x)
    return fn

    @log # 指定被装饰的方法
    def factorial(n):
    return reduce(lambda x,y: x*y, range(1, n+1))
    print(factorial(10))
  6. 偏函数

    1
    2
    3
    import functools
    int2 = functools.partial(int, base=2)
    # int2就是一个偏函数

SpringCloud

发表于 2018-04-10 | 分类于 SpringCloud

微服务基本架构图

服务注册 spring Cloud eureka

他是一个服务注册中心,服务消费者会注册到服务中心,服务实例会通过心跳方式定时通知服务中心(定时向注册中心更新实例。默认30S),Eureka Server收到心跳后,会通知集群里的其它Eureka Server更新此实例的状态。

  • 在Service Provider服务shutdown的时候,主动通知Eureka Server把自己剔除,从而避免客户端调用已经下线的服务。

  • Eureka Server会定时,进行检查,如果发现实例在在一定时间,内没有收到心跳,则会注销此实例。(间隔值是eureka.server.eviction-interval-timer-in-ms,默认值为60)

  • 保护模式:则会触发自我保护模式,此时Eureka Server此时会认为这是网络问题,它不会注销任何过期的实例。

其他服务注册中心也有Consul和Zookeeper

依赖

1
2
3
4
5
6
7
8
9
10
<!-- eureka server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<!-- eureka client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

配置文件

server

1
2
3
4
5
6
7
8
9
10
11
12
13
server.port=9990
#服务名称
spring.application.name=eureka-server
#服务地址
eureka.instance.hostname=127.0.0.1
#是否注册eureka(当高可用模式下才会启用) 是否向服务注册中心注册自己
eureka.client.register-with-eureka=false
#是否启用获取服务注册信息
eureka.client.fetch-registry=false
#注册和查询都需依赖该地址,多个以逗号分隔
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
#留存的服务实例低于多少比列进入保护模式 默认是85%
eureka.server.renewal-percent-threshold=0.5

client

1
2
3
4
5
6
7
8
server.port=8083
spring.application.name=comment
#eureka server地址
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:9990/eureka/
# 心跳间隔 5s 默认30s
eureka.instance.lease-renewal-interval-in-seconds=5
# 服务失效时间: 如果多久没有收到请求,则可以删除服务 默认90s
eureka.instance.lease-expiration-duration-in-seconds=10

代码

eureka server在启动类添加注解@EnableEurekaServer
eureka client在启动类添加注解@EnableEurekaClient

@EnableEurekaClient和@EnableEurekaClient功能类似,但是@EnableEurekaClient只用于eureka。

网关服务 apigateway

我这里的例子是web服务,所有采用的是springBoot作为网关。如果是应用服务可以用spring Cloud zuul

所有的接口都是通过网关提供出去的,所以身份认证、路由服务、流量控制、日志统计代码编写都是在网关服务。

springBoot

配置

1
2
3
4
5
6
server.port=8090
spring.application.name=api-gateway
###########eureka配置#################
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:9990/eureka/
#是否向服务注册中心注册自己
#eureka.client.register-with-eureka=false

spring Cloud zuul

zuul主要就是路由转发和过滤器

依赖

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>

配置

1
2
3
4
5
6
7
8
server.port=8769
spring.application.name=service-zuul
eureka.client.service-url.defaultZone=http://127.0.0.1:8761/eureka
zuul.routes.api-a.path=/api-a/**
zuul.routes.api-a.path.serviceId=service-a
zuul.routes.api-b.path=/api-b/**
zuul.routes.api-b.path.serviceId=service-b
#api-a 和api-b 都是对应子服务的名称

启动

启动类添加@EnableZuulProxy注解

网关与子服务通信

两种通信方式:restTemplate+httpclient和feign

restTemplate+httpclient

1、注入restTemplate

1
2
3
4
5
@Bean
//@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}

2、调用原子服务

post

1
int result = restTemplate.postForObject("http://comment/insert", comment, Integer.class);

get

1
2
3
Map<String, Integer> map = new HashMap<>();
map.put("nid", nid);
List<CommentUser> response = restTemplate.getForObject("http://comment/list?nid={nid}", List.class,map);

其中comment就是服务配置文件中的spring.application.name=comment

feign

依赖

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>

请求方式

类似于controller编写

1
2
3
4
5
6
7
8
9
@FeignClient(value = "comment")
public interface NewsFeign {

@RequestMapping(value="insert",method=RequestMethod.POST)
public int insert(@RequestBody Comment comment);

@RequestMapping(value="list",method=RequestMethod.GET)
public List<CommentUser> queryAll(int nid);
}

负载均衡ribbon

restTemplate+httpclient方式

1、需要添加依赖
1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
2、添加注解@LoadBalanced
1
2
3
4
5
@Bean
@LoadBalanced // 启动负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}

feign

feign默认集成了ribbon

断路器hystrix

服务隔离(每个服务有单独线程池)、熔断(也可以称为断路)、降级等手段控制依赖服务的延迟与失败。
防止单个服务的故障,从而影响整个系统的性能,避免分布式环境里大量级联失败。使用快速失败策略,当调用一个服务超时,或者,线程池满了的情况,会立即拒绝服务而不会排队等待,还有服务降级,当调用失败的时候,就调用备用的服务。

依赖

1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
###########hystrix配置################
#执行超时时间,超过这个时间执行没反应就返回
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=2000
#并发执行的最大线程数,默认10
hystrix.threadpool.default.coreSize=5
#线程最大队列数 默认1
hystrix.threadpool.default.maxQueueSize=1
#最大的线程池
#hystrix.threadpool.default.maximumSize=10
#错误比率阀值,如果错误率>=该值,断路器会被打开,并短路所有请求触发fallback。默认50
hystrix.command.default.circuitBreaker.errorThresholdPercentage=1
#触发短路的时间值,当该值设为5000时,则当触发circuit break后的5000毫秒内都会拒绝request,也就是5000毫秒后才会关闭circuit。默认5000
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=100000

代码

可以使用注解自定义配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@Repository
@DefaultProperties(groupKey="newsDao",
commandProperties={@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000")},
threadPoolProperties={@HystrixProperty(name="coreSize",value="10")
,@HystrixProperty(name="maxQueueSize",value="1000")},
threadPoolKey="newsDao"
)
public class NewsDao {

@Autowired
private RestTemplate restTemplate;

public int insert(News news){
return restTemplate.postForObject("http://news/news/insert", news, Integer.class);
}

@HystrixCommand
public UserNews queryOne(int id){
Map<String,Integer> map = new HashMap<>();
map.put("id", id);
UserNews response = restTemplate.getForObject("http://news/news/query?id={id}", UserNews.class, map);
return response;
}

@HystrixCommand(fallbackMethod = "errFallback")
public List<News> queryAll(){
List<News> response = restTemplate.getForObject("http://news/news/list", List.class);
return response;
}
/**
* 有降级方法,但是用户线程池用完了的话,还是会启动短路器。并且一定的时间段调用还是会拒绝所有请求,当这个请求时间过了的时候,等下一次请求正常访问,断路器才会关闭
* @return
*/
public List<News> errFallback(){
return null;
}
}

启动方式

在启动类添加注解@EnableCircuitBreaker

服务跟踪系统Sleuth

分布式服务跟踪系统,微服务中,分布式服务架构,业务的调用链越来越复杂。分布式服务跟踪是整个分布式系统中跟踪一个用户请求的过程(包括数据采集、数据传输、数据存储、数据分析、数据可视化)提供链路追踪,故障快速定位,可视化各个阶段耗时,进行性能分析。理清服务依赖关系

依赖

1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

配置文件

1
2
3
4
5
#############zipkin配置###############
#1就是 100%采样
spring.sleuth.sampler.percentage=1
#zipkin服务地址
spring.zipkin.baseUrl=http://127.0.0.1:9993

通过引入spring-cloud-starter-zipkin依赖和设置spring.zipkin.base-url就可以了。

监控系统

1、admin

健康检测,监控服务的堆栈,线程、GC、请求等信息

a. 创建一个admin服务,添加依赖。设置端口9992

1
2
3
4
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>

b. 添加启动类注解@EnableAdminServer
c. 子服务添加依赖和admin服务地址配置

1
2
3
4
5
6
7
8
9
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>1.5.1</version>
</dependency>

1
2
3
4
5
6
###########spring-admin配置###########
spring.boot.admin.url=http://localhost:9992
#管理地址
management.port=8099
#关闭安全访问
management.security.enabled=false

2、hystrix dashboard

监控信息包括请求成功,失败(客户端抛出的异常),超时和线程拒绝。如果访问依赖服务的错误百分比超过阈值,断路器会跳闸,此时服务会在一段时间内停止对特定服务的所有请求

a. 创建hystrix-dashboard服务,添加依赖,端口为9991

1
2
3
4
5
6
7
8
9
10
11
12
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>

b. 启动类添加注解@EnableHystrixDashboard

3、zipkin

服务调用在整个链路中的状态可视化界面。sleuth收集数据,然后发送到zipkin存储展示。(默认存储到内存中,也可以存储到redis/mysql)

a. 创建zipkin服务,添加依赖,端口为9993

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
</dependency>

b. 添加启动依赖注解@EnableZipkinServer

本文springCloud源码链接

ELK日志分析平台

服务产生的日志文件后,logstash去收集,然后解析,输出到ElasticSearch中,最后由kibana展示出来。

ElasticSearch

ElasticSearch是一个基于 Lucene 的搜索服务器。
安装:Elasticsearch 基础入门
常见坑:elasticsearch启动常见错误

kibana

数据可视化平台,安装最简单,安装完后指向ES地址即可。

logstash

Logstash 基础入门
Logstash 是一个开源的数据收集引擎,它具有备实时数据传输能力。
难点就是编写配置文件中的过滤器部分:grok 插件

grok 插件用于过滤杂乱的内容,将其结构化,增加可读性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
input{
file{
path => "C:\gaojindeng\mooc\api-gateway\logs\house-info*"
sincedb_path => "C:\gaojindeng\logstash-6.2.3\sincedb_house"
codec => multiline {
pattern => "^%{TIMESTAMP_ISO8601}"
negate => true
what => "previous"
}
}
}

filter {

}

output {
elasticsearch {
hosts => ["192.168.1.103:9200"]
index => "house-info-%{+YYYY.MM.dd }"
}
stdout {codec => rubydebug}
}

ELK整体搭建:搭建ELK日志分析平台

其他

SpringCloud Config:全局配置,比如git,svn,githup
SpringCloud Bus: +RabbitMQ 可以实现配置更新通知所有服务

log4j2 和logback日志对比

  • 异步模式性能优秀
  • 插件化架构易扩展

log4j2:多个线程会把日志放入到一个无锁化环形队列,然后由一个异步队列去拉取队列的数据打印到日志里面去

手把手教你读财报

发表于 2018-04-01 | 分类于 财经

简单公式

资产=负债+股东权益

资产负债表

一、流动资产(经营性资产)

  1. 货币资金

    简介:银行存款、现金、准备金、库存现金(保险柜里的钱),存银行的采购,专款专用的钱,同业(冻结和被质押的存款)

    影响:

    1. 过大的表资金运用能力较弱,过小,在偿债能力不足。
    2. 货币资金远小于负债,说明随时有偿债危机爆发,货币充裕,但基本都是高利贷。
    3. 其他货币资金巨大,但没有合理解释。
  2. 应收票据

    简介:银行承兑汇票和商业承兑汇票,急用钱,就会把银行承兑汇票打折出售给银行,这个折扣就叫做银行贴现。银行转给其他银行叫转贴现,还有直接给了央行,拿到现金,这就叫做再贴现。商业承兑汇票是企业开出来的。

  3. 应收账款

    简介:大部分都是赊账拿货,然后卖完了再把钱给你。

    影响:应收账款占收入比例较大,且长期没有还,就说明有问题。
    应收账款的时间,如果拖的越久,变成烂账的可能性就越大。而坏账准备就会计提越多。(计提就是预先计入某些已经发生但未实际支付的费用;)
    也就是多年未还,就计资产减值损失。熊市好多企业大量的隐藏收入就是这个,然后牛市又把利润释放出来,从而达到套现或者增发的目的。

    举例:一些公司,会以客户的名义打入一笔钱,用来冲销数额巨大的期限过长的应收账款,然后再把这笔钱,通过其他应收款和预付款,购货款的名义转出去,于是就不用减值太多,所以资产就增加了。还有利用关联方,先将应收账款收回,然后通过在建工程和无形资产长期投资这些项目把资金流出,这样就能光明正大的折旧了。

  4. 预付账款

    简介:先交钱再拿货,如果预付款过多的话,那么也就意味着这个公司没什么地位,总是处于资金被压榨的地位。

    影响:还有长期挂账的预付款,这很可能就是一种资金挪用,通过预付款把钱拿走不知道干什么去了。给投资者出个招,就是要把历年的预付款占应收的比例都算出来,如果这个比例大幅度波动,就要找原因,如果没有原因,就有可能是个雷了。

  5. 其他应收款

    简介:这就是个垃圾筐,无关营业的应收款,都会放到这里面。比如借钱给别人。优秀的工作一般都是0

  6. 长期应收款

    简介:主要是融资租赁和递延分期付款,比如公司卖的房,别人分期还款。

  7. 存货

    简介:就是企业在生产过程中的原材料。基本上劳务福利,折旧费和修理费,办公水电耗材全都放在这里了。

    影响:基本上劳务福利,折旧费和修理费,办公水电耗材全都放在这里了。利用存货造假的手法很多,比如为了虚增利润,故意不对已经贬值的存货计提跌价准备,减少费用就会让利润增多。还有,很多公司还通过让存货大量增长,从而掩护大量现金流出,然后再以关联公司虚构订单方式回来。还有用增加存货的方式来增加毛利率,美化报表。

    例子:所以你看到毛利率大幅提升的时候,应该赶紧去看看存货是不是也大幅增加了,如果是的话,那么这个报表就是做出来的。

  8. 其他

    • 应收利息:应收利息则是指企业因债权投资而应收取的一年内到期收回的利息

二、非流动资产(生产相关资产)

  1. 固定资产

    简介:包括房屋建筑物,机器,运输车辆等,按折旧计算。随时间要做减值准备

    影响:短期内折旧很快,说明公司在着眼于未来发展,他们希望把更多的业绩留到以后。

  2. 在建工程和工程物资

    简介:在建工程是不需要折旧的,因为还没建好

    影响:如果你发现有一个在建工程很长时间都不转入固定资产,那么有两个可能,一是公司避免折旧,不愿意减少利润。二一个其实我们之前讲过,是上市公司通过在建工程向关联供应商输送资金,然后再采购商品,增加订单,流入公司。最后这种在建工程,往往会通过大比例折旧,或者意外损毁的名义毁尸灭迹。

  3. 无形资产

    简介:知识产权一类或者是品牌。这其中注意,包括了土地使用权。所以如果买地产股,一定注意这个科目。

    影响:无形资产也是有折旧的,但他叫做摊销。这其中有个叫做研发费用的项目,也是用来调整报表的。低收入企业通常把研发费用计算到无形资产里面,而不进入公司费用,也是为了粉饰报表,显得资产多一点,利润高一点。

  4. 商誉

    简介:说白了就是你花10块钱,愿意买7块钱的东西,3块钱的附加值就是商誉。但只有公司收购之后才会体现,一般公司的报表里都是0。

  5. 长期待摊费用

    简介:是企业已经支出的,但持续期1年以上的费用。比如装修房子,修理机器等等,这些需要进入当期费用,然后从利润里扣除。比如预交了一年的房租。

  6. 递延所得税资产和负债

    简介:会计算的所得税和税务算的不一样,但一定要按照税务算的交,于是如果算的少了,多交了钱,回去就把多交的钱,写在递延所得税资产里面。相反就是负债

三、投资相关的资产

  1. 交易性金融资产

    简介:交易性金融资产主要是指企业为了近期内出售而持有的金融资产,如企业以赚取差价为目的从二级市场购入的股票、债券、基金等。

  2. 可供出售金融资产

    简介:随时可以卖了,牛市里这块就是低估的金矿。而熊市里这就是地雷。

  3. 长期股权投资

    简介:指的是上市公司持有其他公司股份,一般是那种战略投资。有这么几个关系,持股大于50%叫做控制,持股在20%-50%之间,叫做联营,持股100%,叫做全资子公司。还有一种合营,持股随便约定。这种长期投资不计入利润,只要不卖,股权价值变动对于公司没影响,如果持有公司分红,还会被计入到利润。

  4. 投资性房地产

    简介:这里面有一个巨大的陷阱,那就是很多人看房产股的时候发现市盈率和市净率都很低啊,其实主要都是公允价值计量所造成的,每年房价上涨,净利润和净资产都会很多,表现出来就是获利能力强,资产庞大,但事实上公允价值都是财富幻觉,这个很多普通人买房是一样的,总觉得自己很有钱,因为房子值上千万,但其实这都没什么卵用,好比你打高一分钱,买入中石油100股,大概只需要700块钱,但你却能瞬间提高中石油的市值将近20亿,所以懂了吧,这东西都是乘数乘出来的,其实根本就没这么多钱。大量的房地产公司,其实就是用这些公允价值玩出了把戏,而实际上一旦房价不涨了,其实根本就无法变现。

  5. 其他
    • 持有至到期投资
    • 固定资产清理:固定资产清理是指企业因出售、报废和毁损等原因转入清理的固定资产价值及其在清理过程中所发生的清理费用和清理收入等。

四、负债和股东权益

1. 负债

主要也是为了方便债权人看他到底有没有偿债能力。如果一个公司分红,就会大幅增加分配性负债,从资产的未分配利润科目划入到负债的应付股利科目,如果你发现公司净资产大幅下降,先不要慌,看看是不是因为分红了。很多公司分红并不是真心的,而是出于再融资的考虑,大比例分红后,净资产下降,但净利润却不变,所以净资产收益率就大幅提升了,他就可以符合要求,进行再融资了。所以你要翻翻这个公司的历史,看有没有这个传统,分红之后再融资。如果有千万别踩雷。

注意房地产:

【在会计准则里,房企预收账款按负债计,但预收款本质上是尚待确认的营业收入,不需要支付利息,和通常语境下的负债不是一回事。预收款多,说明房企房子卖得多,经营状况好。】

  1. 应付薪酬工资

    简介:假如老总年薪百万,会计如果把你的工资计入管理费用,就要从利润里面减掉,公司营业利润就少了上百万,如果想释放这百万的利润出来,就把你同时任命为车间主任,待遇不变。然后你的工资就进入了生产成本,变成了存货。
    薪资是不会减少的,除了裁员

所有者权益(净资产)、股东权益

  1. 股本

    简介:总股数

  2. 盈余公积金

    简介:是利润留下来的,是继续扩大再生产的钱,法定盈余公积是政府强制股东留下来的,一般10%。

  3. 未分配利润

    简介:企业赚的钱提取了盈余公积金之后,剩下的就是未分配利润了,企业可以利用盈余公积金和未分配利润送红股,前提是有利润,送股后盈余公积金不得低于注册资本的25%。

    注意:但未分配利润可不一定都是现金,公司手里的钱就是货币资金里面的现金和现金等价物,未分配利润可能已经被公司挪用出去投资了,比如变成了固定资产或者是土地厂房什么的。

  4. 资本公积金

    简介:叫做股本溢价或者资本溢价,计入资本公积。换句话说,资本公积金,就是放置股东投入的地方。

  5. 库存股

    简介:公司将已经发行出去的股票,从市场中买回,存放于公司,而尚未再出售或是注销

  6. 归属于母公司股东权益合计

  7. 少数股东权益

  8. 股东权益合计

    简介:净资产
    所有者权益合计=母公司股东权益合计母+少数股东权益合计

  9. 负债和股东权益总计

    简介:公司将已经发行出去的股票,从市场中买回,存放于公司,而尚未再出售或是注销

注意

也就是所有带应收两字的总和,减去应收票据里的银行承兑汇票金额,然后除以总资产。如果这个比例过大, 比如超过了3成,说明资产质量不佳。欠的钱很可能拿不回来,第二看是否有大的变动,总资产基本上变动不大,应收如果变动很大的话,那么一定是销售出了问题,可能就是公司变坏的苗头。

货币资金除以有息负债,看你抵御危机的能力,特别是在经济逆周期,比如现在,看看有多少现金和现金等价物,是你投资一个公司的根本保证,未来现金会越来越值钱,而如果负债过多,会在加息周期,步伐越来越沉重。

非主业资产比上总资产,无疑就是看公司业务是否聚焦,如果这个比例过大,那么也就意味着他觉得自己的主业已经不赚钱了

利润表

公式:

利润=收入-支出

  1. 营业收入(营业总收入)

    描述:企业卖出的产品所获得的收益就是营业收入。一个是销售商品,一个提供劳务,另外一个就是让渡资产使用权

  2. 营业成本

    描述:卖出去的产品就是营业成本.主要包括两部分,一个是产品成本,以及劳务成本。

  3. 营业总成本

    描述:营业成本,营业税金及附加,营业费用,营业费用又包括销售费用,管理费用和财务费用。俗称三费。

    • 销售费用是销售产品所产生的费用,比如广告费,促销费保险运输费,装卸费,销售人员的返点等等。销售费用和销售收入应该是同涨共跌的,毕竟多列销售费用的目的就是促进销。
    • 管理费用包含管理者的工资福利,工会经费,职工教育培训,行政开支。比如员工乱开发票。管理费用太大说明管理不行
    • 财务费用主要就是利息和手续费
  4. 毛利润

    描述:主营收入(营业收入)减去主营成本就是毛利润,而毛利润占主营收入的比例就是毛利率,毛利低的行业,竞争很激烈,毛利高的行业才有护城

  5. 营业利润

    描述:收入和成本相减

  6. 营业利润率

    描述:营业利润除以营业总收入。然后跟同行比较一下,如果这个指标高,说明这个公司在行业里的竞争地位很强。

  7. 净利润

    描述:营业利润加上其他的营业外的收支净额,交完所得税,剩下的钱。

  8. 扣非净利润

    描述:由于能为公司带来利润的方法很多,比如:股权投资,打新股,财补贴,债务重组…等,这些东西跟公司的主营业务无关,都是一次性的,不可持续的

  9. 资产减值损失

    描述:一般投资亏了,或者坏账了,才会提这个减值损失。

  10. 公允价值变动

    描述:主要是交易性金融资产,比如买了很多的房子,房价涨了,这块也就跟着涨而来。

  11. 投资收益

    描述:是股票分红,债券利息,主要指那些付息的东西,在还本付息之前,拿到的利息收入。

  12. 汇兑收益

    描述:就是企业持有外汇资产或者负债期间,所造成的汇率变化。

  13. 营业外收入

    描述:比如卖一栋房,专业投资者上来就会把这些营业外收入给剔除掉,因为这东西根本不可持续。

  14. 营业外支出

    描述:包括的项目有固定资产盘亏、处置固定资产净损失、处置无形资产净损失、债务重组损失、计提的无形资产减值准备、计提的固定资产减值准备、计提的在建工程减值准备、罚款支出、捐赠支出、非常损失等。

  15. 营业税金及附加

    描述:营业税、消费税以及城建税、教育费附加、地方教育附加。

  16. 所得税

    描述:

  17. 其他综合收益

    描述:可供出售金融资产的公允价值变动、减值及处置导致的其他综合收益的增加或减少。

  18. 综合收益总额

    描述:综合收益总额是企业净利润搜索与其他综合收益的合计金额。其中净利润好理解,而其他综合收益是指直接计入所有者权益的利得或损失扣除所得税之后的余额,它们都属于利润表大类项目。

公式

  • (1)营业利润=营业利润=营业收入-营业成本-营业税金及附加-销售费用-管理费用-财务费用-资产减值损失+公允价值变动净收益+投资净收益
  • (2)利润总额=营业利润+营业外收入-营业外支出
  • (3)净利润=利润总额-所得税费用

注意

净利润必须结合现金一起看,脱离了现金你会被骗的怀疑人生的。很简单打白条,把货拉走,权益发生了,净利润增加了,但钱却压根没见着。看似净利润大增,过几天人家告诉你应收账款全都坏账了,企业分分钟变成巨亏。这都是套路。套的就是那些只看利润不看现金的股市上懒惰的投资者。

重点

1. 营业收入

  • 潜在需求增长

    市场整个份额扩大了。

  • 市场份额扩大

    抢了别人的份额,,很可能会带来价格战和报复。

  • 价格提升

    牺牲客户利益为大家。那就看会不会让客户减少了。还要看替代产品强不强。

营业增长速度 还要跟同行比较

2.毛利率

高毛利率就说明很强的竞争优势,我建议大家毛利率40%以下的就可以不看了。因为替代性太强的企业,

3.费用率

三费占营业总收入的比例,这个指标反映的是公司的管理水平。要跟同行比较。销售费用管理费用,财务费用加在一起除以毛利润,比例小于30%,这个企业就算不错

4.营业利润率

营业利润除以营业收入;跟同行比较

经营现金流净额,除以净利润。这个比值越大越好大于1就是好企业了

现金流量表

三大类

经营活动,投资活动和筹资活动

投资活动 就是收购

筹资活动,公司回购股票,向股东分红,借债,发行股票再融资等等。

经营活动

  1. 经营活动现金流入

    描述: 主要是销售商品或者提供劳务产生现金,收到税费返还的钱,还有收到其他与企业经营有关的钱,比如出租什么的。

  2. 经营活动现金流出

    描述:购买商品,接受劳务,付出的钱,支付应付款,减去本期退货收到的现金。支付给职工的工资,奖金以及各种津贴。支付各种税费,还比如支付各种租金。

重点

重点就是要得到流量净额这个数据,要从净利润反推经营活动现金收入净额,拢共分三步,第一步就是把净利润里扣除的费用,比如什么资产减值准备和折旧摊销全部都给他加回去,第二步是把净利润跟经营活动无关的收入,全部减去,比如什么投资收益,募集资金收入,非经常性的损益。第三步,把经营活动中没有包含在成本里的现金支出减去,比如多交了得税,这个在递延所得税资产里,增加了的存货,以及增加了的营收和支付了的应付

销售商品和提供劳务收到的现金,这个数字可以和营收对比,因为前者包含了增值税,所以两个数字按照理论来说应该前者是后者的1.17倍,前面的数字比后面大就对了,如果销售商品提供劳务还没有营收多,那就有问题了。证明大量款项被作为应收账款,打了白条。这笔钱能不能收回,就很难说了。

如果一个企业总是花钱投资,属于扩张阶段,如果一个企业投资活动现金流是往回流的,是正数,那么说明这个企业已经扩张放缓,属于收缩阶段。

8种企业的组合

  1. 妖怪型:经营现金流,投资现金流筹资现金流都是正向流入的企业,企业本身赚钱,但是有不投资,而且还向别人借钱。

    这类企业现实中还真存在,属于妖怪型,他们可能随时要开展一场大规模的投资活动,要不就是在借着上市公司的壳搞钱,搞到钱之后在给关联方使用。反正这样的企业相当可疑。估计是没憋好屁。

  2. 老母鸡型,经营流入,投资流入,筹资流出,很赚钱,而且还能拿钱去赚钱,这都很好。

    筹资活动现金流出有两种可能,要么在还债,要么是回报分红,如果是分红,这个企业还不错。应该是价值型的公司。

  3. 企业疯牛型,属于经营流入,投资流出,融资流入。企业能够赚到钱,然后赚到的钱,都愿意拿出去扩张,说明很看好未来的发展。

    另外还能借到钱,说明外面的人也看好这个企业的项目。这时候两种可能,一个是高增长持续,但也很容易出现资金断流。太多的企业都是死在了冲锋的路上,所以投资这块要谨慎看待,特别是那种打出多元化国际化口号的。务必小心。

  4. 最佳类型:经营流入,投资流出,融资也流出,企业能赚钱,然后也能投资,还能够偿债或者回报股东,如果可以持续的话,这应该是最佳的类型了。

    他经营的钱能够覆盖对外投资和分红,这就属于那种现金奶牛,比如茅台和格力。增长不见得很快,但每年都会有钱拿。巴菲特最喜欢的企业类型。这时候你要在算算,经营现金减去投资再减去融资,是不是仍然为正,如果仍然为正,这个奶牛的成色非常足。如果减完了得到了负数,那么很可能很快就变成了上面那种企业。

  5. 骗吃骗喝型,经营现金流为负值,投资现金流净额为正的,筹资为正的是骗吃骗喝型

    筹资活动现金流出有两种可能,要么在还债,要么是回报分红,如果是分红,这个企业还不错。应该是价值型的公司。

  6. 混吃等死型,经营现金流为负值,筹资为负的就是是混吃等死型

  7. 赌徒型,经营现金流为负值,投资活动为负的就更糟糕,能融到钱的属于赌徒型

  8. 大出血型,经营现金流为负值,融不到钱还要还债的属于大出血型

优秀的企业

关注以下5组数据就够了。第一就是经营活动现金流量净额大于净利润,并且大于零。第二销售商品提供劳动收入现金大于营业收入,第三投资活动的现金流净流量小于零,且主要是投入的新项目。第四现金及现金等价物净增加额大于零,或者排除分红因素该科目仍然大于零,第五期末现金及现金等价物余额大于有息负债。

三大报表总结

要结合历史报表和同行业报表来看

杜邦分析体系

安全性分析指标

有一个指标你总是要记住的,那就是现金及现金等价物,一定要大于有息负债。

  1. 流动比率和速动比率

    教科书一般认为,流动比率2,速动比率在1是一个比较理想的状态

  2. 资产负债率
  3. 净资产负债率

盈利能力的分析

营业利润率等于营业收入减去营业成本再减去三费,然后用这个结果再除以营业收入,用以反应收入到底多少能转化成利润。

  1. 净资产收益率(ROE): 最好15%以上。
  2. 总资产收益率:净利润除以平均总资产,注意这是总资产,跟净资产就差一个字。

    这里面还能体现杠杆的因素,比如只有1成的钱,借来了9成的钱,然后赚了1成,他就收益100%了,但其实他的生意利润也就10%,所以如果两家公司净资产收益率一样,而总资产收益率更强的那家,显然盈利能力更强,承担的风险更小。

成长性分析

  1. 营业收入增长率:本期收入减去上期营收,除以上期营收,反应业务能力扩大的速度
  2. 营业利润增长率:本期利润减去上期利润除以上期利润
  3. 总资产增长率:本期总资产减去上期总资产除以上期总资产
  4. 净资产增长率:本期净资产减去上期净资产除以上期净资产

营业增长率和利润增长率是必须要看的指标,我们常用的PEG估值方法,那个G就是增长率的情况,通常保守的价值型企业用利润增长率来算,成长型企业则用营业增长率来计算,增长率20%,顶多给20倍市盈率的估值。成长率为10%,最好买入的市盈率别超过10倍。至于增长率100%,理论上可以给100倍市盈率的估值,但问题是这100%的增长能维持多久?

PEG,是用公司的市盈率(PE)除以公司未来3或5年的每股收益复合增长率。

衡量公司管理水平

应收账款周转率,存货周转率和固定资产周转率,说白了就是营运能力,周转率就是周转的次数,如果固定周期中周转的次数越多,说明公司越高效,毕竟存货周期短的话,计提减值就少。

杜邦分析体系

净资产收益率=净利润/销售收入 X 销售收入/平均总资产 X 平均总资产/净资产。

分别是净利润除以销售收入,这其实就是产品净利润率,销售收入除以平均总资产,这是总资产周转率,而平均总资产除以净资产,就是杠杆系数。这确实是高人研究出来的,因为这三个部分,刚好表明了企业的有且只有的三种发展模式,也就是茅台模式,沃尔玛模式和银行模式,所谓茅台模式,就是第一个净利润比上销售收入,是产品净利率极高的发展模式。属于现金奶牛,属于超级大白马,属于超高产品附加值。

而沃尔玛模式,就是总资产周转率高的企业,也就是第二个公式销售收入比上平均总资产,说明这个企业的利润并不高,周转效率很高,靠的是效率赚大钱。

第三种是银行模式,利润不高,也没什么周转率,但人家靠的是高杠杆,把本来很低的利润给放大了。所以通过杜邦公式你一眼就能看出这是一个怎样的企业,他的净资产收益率到底高在哪了。所以这个公式是你必须牢记的,4个指标也是你要率先从报表上找出来的。重复一遍,四个指标分别是净利润,销售收入,平均总资产和净资产,杜邦公司的净资产收益率公式是,净资产收益率=净利润/销售收入X销售收入/平均总资产X平均总资产/净资产。

常见的操纵财报的手法

1、操纵利润

利润等于收入减去费用,所以只有2个手法,要么虚构收入,要么减少费用。其中虚构收入是比较常见的,比如某上市公司,成立了35家秘密控制的空壳公司,拿出其中一家当低价买农村山地,然后以100倍的价格卖给上市公司,这样上市公司就虚增资产1亿多,而那家卖地的公司,就从上市公司掏出来上亿的现金,接着以类似的手法分转给其他的公司,然后再由那些公司,从这个上市公司采购产品,虚增营业收入。
还有的公司,把产品单价提高,然后以高价格卖给关联公司,最后再通过在建工程款,原料采购等名义,把钱返还出去,这样他就有很高的收入。甚至还有的不要脸的公司,会把政策的补助,给化妆成合同采购,假装成销售收入流入公司。

另外,我们之前也讲过,还有很多公司借助一次性的卖资产而来的钱,扩大收入。还有通过收购一个公司,多付出一些钱,然后被收购对象再把钱返回来购买产品,虚增收入。
还有些公司会将亏损打包进一个公司和业务部门,高价出售,然后掩盖亏损。然后上市公司会通过,借款,担保,项目合作,并购或者咨询费用再把这些钱补偿给接盘公司。

最无耻的还有互换贸易,就是跟一个公司约定好,我高价采购你的产品,你也高价采购我的产品。这样双方的营业收入就都提升了。

2、互换贸易

就是跟一个公司约定好,我高价采购你的产品,你也高价采购我的产品。这样双方的营业收入就都提升了。

3、操纵费用

经常会把本期费用推迟到未来,来掩盖本期的业绩问题。还有虚增费用,然后给业绩洗澡,把几年的费用一年爆出来,大比例的注销资产或者存货,大额计提减值准备,集中亏一次,总比持续的小亏要强的多。有个上市公司,少记原材料成本1个亿,结果虚增利润7000万。这是比较常见的手法,然后还有的公司不计入对外拆借资金的利息,减少财务费用的。这样的事很多。

4、苦肉计

有一个苦肉计大家要注意,就是公司有时候会恍然大悟,然后承认错误,说我之前漏算了很多费用,现在把这些费用放回去。这就好比,我先打你一嘴巴,然后说对不起一样。您的业绩都披露完好久了,股价也涨了,现在要把之前的业绩改回来,道歉有用吗?

5、操纵现金流

这是为了专业投资者准备的坑,知道你们老盯着现金流,所以他们就必须要在现金流上面下手脚。例如把投资或者筹资的 现金流入,变成经营活动流入,这个手法有,投资收购一家公司,然后跟对方商量好,你们让客户慢点付款,多保留些应付款,等于我投资下去,收购了很多的应收款,这就把钱变成了经营现金流入。而且有的时候收购未必要出很多钱。所以投资活动现金也不用怎么流出,就能换回经营现金流入。
还有公司会出售子公司,把出售款分成首付和未来收入分账两部分,这样收入分账部分,就变成了这家公司的未来经营现金流入。这就把投资现金流入变成了经营现金流入。有的公司还以存货抵押借款,然后签合同的时候说,咱们改一种说法,叫做我先卖给你,然后约定未来再回购从而创造本期经营活动现金流入。还有的上市公司替客户担保,然后让客户大比例购买他的产品,其实也是投资现金流出,而经营现金流入。
当然有流入就有流出,上市公司会尽量避免经营现金流出,能放到投资流出的绝不放到经营现金流流出。

6、造假

  • 第一重点关注高毛利率的业务,这块非常多的用来造假,因为空间大,不容易被发现。如果某个产品毛利率显著高于同行,或者大幅波动,那么就要小心了,除非是特别知名的产品,否则很可能就是个坑。

  • 第二是其他业务收入,一般也是玩文字游戏的地方。而报表是可以不披露其他业务收入明细的,所以你很难进一步知道这个东西到底是什么玩意。这就为造假提供可能。

  • 第三是销售费用和管理费用,这是藏污纳垢的重灾区,一定要跟同行对比。

  • 第四是营业外支出和一次性费用,二话不说先把一次费用排除掉。带着其他字眼的东西,最好都给他加回去。对于有经验的投资者来说,其他两个字,就跟标红差不多。那意思就是这里该有故事了。

  • 第五是资产减值损失,这里是业绩洗澡的地方,很多东西会一次性减值注销。

  • 第六是应收账款,这个指标大幅增加,或者显著高于同行,说明打了很多的白条。
  • 第七是其他应收款,这就更可疑了,好公司这块绝对很小的。

  • 第八预付账款,这个大幅增加很可能是在作假,通过预付款流出资金,然后通过营收再流回来,虚增收入。

注意

1、小心公司的计划、预计、规划,都有可能是骗人的

2、而利润表和现金流量表的作用,只是为了印证资产负债表上的内容。

送红股和转增股的区别

用未分配利润或者盈余公积金送股叫做派送红股

如果用资本公积金送股叫做转增多少股。转增股票是不用交税的。

python高级

发表于 2018-03-16 | 分类于 python

一、条件和循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
## if条件判断
if condition_1:
statement_block_1
elif condition_2:
statement_block_2
else:
statement_block_3

## while循环和while else语句
count = 0
while count < 5:
print (count, " 小于 5")
count = count + 1
else:
print (count, " 大于或等于 5")

## for循环
for <variable> in <sequence>:
<statements>
else:
<statements>

## range()函数 它会生成数列;range(4) 表述从0到4的税数列
for i in range(5,9) :
print(i)

## break和continue语句 与JAVA相同

## pass 语句
# Python pass是空语句,是为了保持程序结构的完整性。
while True:
pass # 等待键盘中断 (Ctrl+C)

二、迭代器与生成器

迭代器有两个基本的方法:iter() 和 next()。

1
2
3
4
5
6
7
8
9
10
list=[1,2,3,4]
it = iter(list) # 创建迭代器对象
for x in it:
print (x, end=" ")

while True:
try:
print (next(it))
except StopIteration:
sys.exit()

使用了 yield 的函数被称为生成器(generator),作用是函数执行时遇到这个关键字的时候就会停止执行,知道调用了next之后才能继续执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import sys

def fibonacci(n): # 生成器函数 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成

while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()

三、函数

1
2
3
def 函数名(参数列表):
函数体
rturn ;

1. 参数

  • 必需参数
  • 关键字参数

    调用时:printinfo( age=50, name="light" );

  • 默认参数

    定义时:def printinfo( name, age = 35 ):

  • 不定长参数

    定义时:def printinfo( name, *str ):类似与java的...

  • 字典

    定义时:def printinfo( name, **args):

    2. 匿名函数

    python 使用 lambda 来创建匿名函数。

    1
    2
    sum = lambda arg1, arg2: arg1 + arg2;
    print ("相加后的值为 : ", sum( 10, 20 ))

3. global 和 nonlocal关键字

global局部变量修改全局变量的值

1
2
3
4
5
6
7
num = 1
def fun1():
global num # 需要使用 global 关键字声明
num = 123
print(num)
fun1()
print(num)

nonlocal关键字

1
2
3
4
5
6
7
8
def fun():
j = 0
def fun1():
nonlocal j
j = 5
print(j)
fun1()
print(j)

四、数据结构

1. python实现堆栈

1
2
3
4
5
6
7
8
9
10
# 堆栈:先进后出,后进先出
stack = [3, 4, 5]
stack.append(6) //压栈
stack.pop() //出栈

# 队列:先进先出
from collections import deque
queue = deque([1,2,3,4,56])
queue.append(6) # 添加到末尾
e = queue.popleft() # 取出队列中第一个参数

2. 列表推导式和遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
vec = [2, 4, 6]
result = [3*x for x in vec]
## return [6, 12, 18]
[[x, x**2] for x in vec]
## return [[2, 4], [4, 16], [6, 36]]

freshfruit = [' banana', ' loganberry ', 'passion fruit ']
[weapon.strip() for weapon in freshfruit]
## return ['banana', 'loganberry', 'passion fruit']

[3*x for x in vec if x > 3]
## return [12, 18]

vec1 = [2, 4, 6]
vec2 = [4, 3, -9]
[x*y for x in vec1 for y in vec2]
## return [8, 6, -18, 16, 12, -36, 24, 18, -54]
[vec1[i]*vec2[i] for i in range(len(vec1))]
## return [8, 12, -54]
[str(round(355/113, i)) for i in range(1, 6)]
## return ['3.1', '3.14', '3.142', '3.1416', '3.14159']
matrix = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
[[row[i] for row in matrix] for i in range(4)]
## return [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

## 列表转化为字典
dict(sape=4139, guido=4127, jack=4098)

## 遍历字典
for k, v in knights.items():
print(k,v)

## 遍历列表,带下标
for i, v in enumerate(['tic', 'tac', 'toe']):
print(i, v)

reversed(list) # 倒叙

五、模块

1
2
3
4
5
6
7
8
9
10
11
from modname import * # 把一个模块的所有内容全都导入到当前的命名空间,但是由单一下划线(_)开头的名字不在此例。
from fibo import fib, fib2
```

### `__name__`属性

```python
if __name__ == '__main__':
print('程序自身在运行')
else:
print('我来自另一模块')

每个模块都有一个__name__属性,当其值是'__main__'时,表明该模块自身在运行,否则是被引入。

1
2
import fibo
v = dir(fibo) # return ['__name__', 'fib', 'fib2']

六、文件

1
2
3
4
5
6
7
8
9
10
f = open(filename, mode)    # 打开文件
f.read() # 读文件
f.readline() # 读一行
f.readlines() # 读所有的行
f.write('......') # 写文件
f.close() # 释放资源
f.writelines(sequence) # 写入多行

############os 模块############
os 模块提供了非常丰富的方法用来处理文件和目录

六、错误和异常

1
2
3
4
5
6
7
8
9
10

try:
f = 1/0
except:
print("我是错误")
raise ## 往外抛异常
else:
print("我没有报错")
finally:
print("我最终会执行")

预定义的清理行为

关键词 with 语句就可以保证诸如文件之类的对象在使用完之后一定会正确的执行他的清理方法

1
2
3
with open("myfile.txt") as f:
for line in f:
print(line, end="")

自定义异常

1
2
3
4
5
6
7
class MyError(Exception):
a = 'sf'
try:
i = 1/2
raise MyError('a', '')
except MyError :
print(MyError.a)

七、面向对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class A:
name = '父类的普通参数'
__name = '父类的私有参数'
# 定义私有属性,私有属性在类外部无法直接进行访问

# 定义构造方法
def __init__(self, name):
self.name = name
self.name2 = '这样也可以定义参数'
### 类方法必须包含参数 self, 且为第一个参数,self 代表的是类的实例。
def fun(self,name):
self.__name = name
print('我是父类普通方法')

class B:
B_name = '我是B类的名称'
def __foo(self): # 私有方法
print('这是B类的私有方法')

class C(B,A): ## 多继承
def __init__(self,name):
A.__init__(self,name)
print(A.name)

## 也可以覆写父类的方法
def fun(self,name):
self.name = name
print('我要重写父类的方法')

def fun(self):
print('python不支持重载,但是这个方法生效,调用上面的方法将报错')

a = A('init_name')
print(a.name)
print(a.name2)
c = C(name='asd')
print(A.name)
super(C,c).fun('') # 调用父类的方法

八、Python3 标准库概览

操作系统接口

os模块提供了不少与操作系统相关联的函数。

1
2
3
4
5
6
7
8
import os
os.getcwd() # 返回当前的工作目录
os.chdir('/server/accesslogs') # 修改当前的工作目录
os.system('mkdir today') # 执行系统命令 mkdir

import shutil
shutil.copyfile('data.db', 'archive.db')
shutil.move('/build/executables', 'installdir')

建议使用 “import os” 风格而非 “from os import *”。这样可以保证随操作系统不同而有所变化的 os.open() 不会覆盖内置函数 open()。

文件通配符

1
2
3
import glob
glob.glob('*.py')
# return ['primes.py', 'random.py', 'quote.py']

命令行参数

1
2
import sys
print(sys.argv) # 打印运行脚本传进来的参数

字符串正则匹配

1
2
3
4
import re
re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')

'tea for too'.replace('too', 'two') # 字符串替换

数字:import math

随机数:import random

访问 互联网

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
## URL访问
from urllib.request import urlopen
for line in urlopen('http://www.baidu.com'):
line = line.decode('utf-8')
print(line)

## 发送邮件
import smtplib
server = smtplib.SMTP('localhost')
server.sendmail('soothsayer@example.org', 'jcaesar@example.org',
"""
To: jcaesar@example.org
From: soothsayer@example.org

Beware the Ides of March.
""")
server.quit()

日期和时间

1
2
3
4
5
6
from datetime import date
now = date.today()
print(now) # 输出 yyyy-MM-dd

nowdate = now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B.")
print(nowdate) # 格式化输出

数据压缩

1
2
3
4
5
6
7
8
import zlib
s = b'witch which has which witches wrist watch'
# 字符串前面添加u代表是unicode字符串;r表示非转义的原始字符串 ;b是bytes的意思
print(len(s))
t = zlib.compress(s) # 压缩
print(len(t))
tt = zlib.decompress(t) # 解压
print(tt)

性能度量

1
2
3
4
5
from timeit import Timer
Timer('t=a; a=b; b=t', 'a=1; b=2').timeit()
## return 0.57535828626024577
Timer('a,b = b,a', 'a=1; b=2').timeit()
## return 0.54962537085770791

测试模块

1
# 待补充......
12…4
lightquant

lightquant

你得拼命奔跑,才能留在原地!

36 日志
16 分类
27 标签
GitHub E-Mail
© 2018 lightquant
由 Hexo 强力驱动
|
主题 — NexT.Gemini v6.0.0