-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
2248 lines (1950 loc) · 128 KB
/
atom.xml
File metadata and controls
2248 lines (1950 loc) · 128 KB
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>菜鸟Java成长之路</title>
<subtitle>半途而废便是最大的失败</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://yoursite.com/"/>
<updated>2017-06-23T01:38:45.507Z</updated>
<id>http://yoursite.com/</id>
<author>
<name>Felix</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>Activiti流程框架上手</title>
<link href="http://yoursite.com/2017/06/22/Activiti%E6%B5%81%E7%A8%8B%E6%A1%86%E6%9E%B6%E4%B8%8A%E6%89%8B/"/>
<id>http://yoursite.com/2017/06/22/Activiti流程框架上手/</id>
<published>2017-06-22T09:12:42.000Z</published>
<updated>2017-06-23T01:38:45.507Z</updated>
<content type="html"><![CDATA[<p>Activiti其核心是BPMN2.0 的流程引擎,是覆盖了业务流程管理、工作流、服务协作等领域的一个开源的、灵活的、易扩展的可执行流程语言框架<br><a id="more"></a><br><a href="https://www.activiti.org/quick-start" target="_blank" rel="external">官网quick-start</a><br><a href="http://itmyhome.com/activiti/#download" target="_blank" rel="external">Activiti 5.16 中文用户手册</a></p>
<p>简单使用介绍,深入需自行查文档 </p>
<h1 id="Activiti介绍"><a href="#Activiti介绍" class="headerlink" title="Activiti介绍"></a>Activiti介绍</h1><p><img src="http://oje7mvhbz.bkt.clouddn.com/%E7%BB%93%E6%9E%84%E5%9B%BE.png" alt="Activiti结构图"></p>
<h2 id="工作流引擎ProcessEngine"><a href="#工作流引擎ProcessEngine" class="headerlink" title="工作流引擎ProcessEngine"></a>工作流引擎ProcessEngine</h2><p>这是Activiti工作的核心。负责生成流程运行时的各种实例及数据、监控和管理流程的运行。<br><strong>产生方式:</strong> </p>
<pre><code>//方式一
ProcessEngine processEngine = ProcessEngineConfiguration
.createProcessEngineConfigurationFromResource("activiti.cfg.xml")
.buildProcessEngine();
//方式二
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//自动加载classpath下的activiti.cfg.xml
</code></pre><p><strong>主要Service的作用:</strong> </p>
<ul>
<li><p><strong>Repository Service</strong> 提供了管理和控制发布包和流程的定义操作。如:部署流程定义;查询引擎中的已有发布包和流程定义;暂停或激活发布包;获取发布包中的资源,如xml文件或是流程图片等。 </p>
</li>
<li><p><strong>Runtime Service</strong> 负责启动一个流程顶的新实例。对于每个流程定义来说,同一个时间内,可以有多个实例在执行。runtime service还可以用于获取和保存流程实例中的变量。或是用于查询流程实例,执行实例,触发实例等。 </p>
</li>
<li><p><strong>Task Service</strong> 任务相关的服务。包含功能:查询分配给用户或用户组的任务的信息;创建独立运行于流程实例外的任务;手段设置任务与用户的关联关系;认领(claim)任务, 完成(complete)任务等。 </p>
</li>
<li><p>Identity Service 负责管理(创建,更新,删除,查询…)群组和用户。注意,activiti执行时不会对用户执行检查。任务可以分配给任何人,无论这个用户是否存在。</p>
</li>
<li><p>Form Service 表单服务。可选的。提供启动表单和任务表单两个概念。即在流程实例启动前展示给用户的,和完成任务时展示给用户的两种表单。注意,这是个可选服务,表单不一定需要嵌入到流程定义中。</p>
</li>
<li><p><strong>History Service</strong> 历史数据服务。执行流程时,引擎会保存如实例启动时间,任务参与者,完成时间,执行路径等数据。Histroy Service通过查询功能获取这些数据。</p>
</li>
<li><p>Management Service 管理服务。提供查询和管理异步操作的功能。异步操作的用途包含定时器,延迟,暂停,激活等。</p>
</li>
</ul>
<h2 id="BPMN2-0"><a href="#BPMN2-0" class="headerlink" title="BPMN2.0"></a>BPMN2.0</h2><p>业务流程建模与标注(Business Process Model and Notation,BPMN) ,描述流程的基本符号,包括这些图元如何组合成一个业务流程图(Business Process Diagram),可以安装eclipse插件,直接建立bpmn图</p>
<h2 id="eclipse插件安装"><a href="#eclipse插件安装" class="headerlink" title="eclipse插件安装"></a>eclipse插件安装</h2><ol>
<li>打开 Help -> Install New Software. </li>
<li>在Install界面板中,点击Add按钮</li>
<li><p>然后填入下列字段 </p>
<pre><code>Name: Activiti BPMN 2.0 designer
Location: http://activiti.org/designer/update/
</code></pre></li>
<li>回到Install界面,在面板正中列表中把所有展示出来的项目都勾上</li>
<li>安装完以后,点击新建工程new->Other…打开面板,如果看到下图内容则安装成功:<br><img src="http://oje7mvhbz.bkt.clouddn.com/%E6%8F%92%E4%BB%B6.png" alt="插件安装"></li>
<li>打开菜单Windows->Preferences->Activiti->Save下流程流程图片的生成方式:<br><img src="http://oje7mvhbz.bkt.clouddn.com/%E6%8F%92%E4%BB%B6%E4%BD%BF%E7%94%A8.png" alt=""><h2 id="相关数据库"><a href="#相关数据库" class="headerlink" title="相关数据库"></a>相关数据库</h2>Activiti的后台是有数据库的支持,所有的表都以ACT_开头。 第二部分是表示表的用途的两个字母标识。 用途也和服务的API对应。使用Activiti自动建表策略,创建引擎时会自动建立25张表,如下图:<br><img src="http://oje7mvhbz.bkt.clouddn.com/%E8%A1%A8.png" alt="25张相关表"></li>
</ol>
<ul>
<li>ACT<em> RE</em>*: ‘RE’表示repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。</li>
<li>ACT<em> RU</em>*: ‘RU’表示runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。Activiti只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。</li>
<li>ACT<em> ID</em>*: ‘ID’表示identity。 这些表包含身份信息,比如用户,组等等。</li>
<li>ACT<em> HI</em>*: ‘HI’表示history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。</li>
<li>ACT<em> GE</em>*: 通用数据, 用于不同场景下。</li>
</ul>
<h2 id="配置文件"><a href="#配置文件" class="headerlink" title="配置文件"></a>配置文件</h2><p>建立activiti.cfg.xml文件,Activiti核心配置文件,配置流程引擎创建工具的基本参数和数据库连接池参数。可以和spring整合。</p>
<pre><code><beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- 定义流程引擎配置对象 -->
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<!-- 配置数据库驱动 -->
<property name="jdbcDriver" value="com.mysql.jdbc.Driver"></property>
<!-- 配置数据库url -->
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/actdemo?characterEncoding=UTF-8"></property>
<!-- 配置数据库用户名 -->
<property name="jdbcUsername" value="root"></property>
<!-- 配置数据库密码 -->
<property name="jdbcPassword" value=""></property>
<!-- 配置数据库建表策略,自动建立25张相关表 -->
<property name="databaseSchemaUpdate" value="true"></property>
<!--
Actiivit提供了4中历史记录级别
none:不保存任何记录,可以提高系统性能
activity:保存所有的流程实例,任务,活动信息
auit:默认级别,保存所有实例,任务,活动,表单属性
full:最完整的,除了auit中的,还能保存更加详细的信息,如流程变量
-->
<property name="history" value="activity"></property>
</bean>
</beans>
</code></pre><h1 id="流程定义语言"><a href="#流程定义语言" class="headerlink" title="流程定义语言"></a>流程定义语言</h1><p><img src="http://oje7mvhbz.bkt.clouddn.com/%E8%AF%B7%E5%81%87%E6%B5%81%E7%A8%8B.png" alt="请假流程"></p>
<h2 id="流程-process"><a href="#流程-process" class="headerlink" title="流程(process)"></a>流程(process)</h2><p>bpmn文件一个流程的根元素。一个流程就代表一个工作流。</p>
<h2 id="顺序流-sequenceFlow"><a href="#顺序流-sequenceFlow" class="headerlink" title="顺序流(sequenceFlow )"></a>顺序流(sequenceFlow )</h2><p>顺序流是连接两个流程节点的连线,代表一个节点的出口。流程执行完一个节点后,会沿着节点的所有外出顺序流继续执行。 就是说,BPMN 2.0默认的行为就是并发的: 两个外出顺序流会创造两个单独的,并发流程分支。<br>顺序流主要由4个属性组成:<br><strong>Id:</strong> 唯一标示,用来区分不同的顺序流<br><strong>sourceRef:</strong>连线的源头节点ID<br><strong>targetRef:</strong> 连线的目标节点ID<br><strong>name(可选):</strong> 连线的名称,不涉及业务,主要用于显示 </p>
<ul>
<li>结束节点没有出口</li>
<li>其他节点有一个或多个出口。如果有一个出口,则代表是一个单线流程;如果有多个出口,则代表是开启并发流程。</li>
</ul>
<h1 id="请假流程快速实现(测试)"><a href="#请假流程快速实现(测试)" class="headerlink" title="请假流程快速实现(测试)"></a>请假流程快速实现(测试)</h1><h2 id="建立maven工程引入依赖"><a href="#建立maven工程引入依赖" class="headerlink" title="建立maven工程引入依赖"></a>建立maven工程引入依赖</h2><pre><code><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.rtzc</groupId>
<artifactId>activitiDemoProject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
<version>5.22.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.22</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
</dependencies>
</project>
</code></pre><h2 id="建立bpmn图片或者bpmn的xml文件"><a href="#建立bpmn图片或者bpmn的xml文件" class="headerlink" title="建立bpmn图片或者bpmn的xml文件"></a>建立bpmn图片或者bpmn的xml文件</h2><ol>
<li>使用bpmn,建立bpmn如下图,部署后,系统会自动解析,可以在properties选项卡下设置相关属性,我使用的是这种方式<br><img src="http://oje7mvhbz.bkt.clouddn.com/%E8%AF%B7%E5%81%87%E6%B5%81%E7%A8%8B.png" alt="请假流程"></li>
</ol>
<ol>
<li>使用bpmn的xml文件,流程定义文件,在部署后,每次系统启动时都会被解析,把内容封装成流程定义放入项目缓存中。Activiti框架结合这个xml文件自动管理流,</li>
</ol>
<pre><code><definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" targetNamespace="Examples">
<!-- 流程定义部分 -->
<processid="myProcess"name="My First Process">
<startEvent id="startevent1" name="Start"></startEvent>
<endEvent id="endevent1" name="End"></endEvent>
<userTask id="usertask1" name="员工申请请假" activiti:assignee="员工"></userTask>
<userTask id="usertask2" name="项目经理审批" activiti:assignee="经理"></userTask>
<userTask id="usertask3" name="总经理审批" activiti:assignee="老板"></userTask>
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
<sequenceFlow id="flow2" name="提交申请" sourceRef="usertask1" argetRef="usertask2"></sequenceFlow>
<sequenceFlow id="flow3" name="项目经理审批" sourceRef="usertask2" argetRef="usertask3"></sequenceFlow>
<sequenceFlow id="flow4" name="总经理审批" sourceRef="usertask3" argetRef="endevent1"></sequenceFlow>
</process>
<!-- BPMN绘图规范定义部分(用来描述节点图标的大小和坐标) -->
<bpmndi:BPMNDiagram id="BPMNDiagram_myProcess">
....
</bpmndi:BPMNDiagram>
</definitions>
</code></pre><h2 id="部署流程定义"><a href="#部署流程定义" class="headerlink" title="部署流程定义"></a>部署流程定义</h2><pre><code>/**
* 部署流程定义
*/
@Test
public void deploy() {
// 创建流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 创建部署环境变量
DeploymentBuilder deploymentBuilder = processEngine
.getRepositoryService().createDeployment();
// 部署流程
Deployment deployment = deploymentBuilder.name("请假部署测试")//部署流程显示名称
.addClasspathResource("请假流程.bpmn")//设置流程文件
.addClasspathResource("请假流程.png")
.deploy();//部署
//打印部署id
System.out.println("部署id为"+deployment.getId()+"部署名称为"+deployment.getName() );
}
</code></pre><p>说明: </p>
<ol>
<li>通过流程引擎获取了一个RepositoryService对象->仓库服务对象 </li>
<li>由仓库的服务对象产生一个部署对象配置对象,用来封装部署环境的相关配置。 </li>
<li>在部署配置对象中设置显示名,上传规则文件相对classpath的地址。</li>
<li>部署,往数据库中存储流程定义的过程。操作了三张表这一步</li>
</ol>
<p><strong>act_ re_deployment</strong> 存放流程定义的显示名和部署时间,每部署一次增加一条记录 </p>
<p><strong>act_ re_procdef</strong> 存放流程定义的属性信息,部署每个新的流程定义都会在这张表中增加一条记录。<br><strong>act_ge_bytearray</strong> 存储流程定义相关的部署信息。即流程定义文档的存放地。每部署一次就会增加两条记录,一条是关于bpmn规则文件的,一条是图片的(如果部署时只指定了bpmn一个文件,activiti会在部署时解析bpmn文件内容自动生成流程图)。以二进制形式存储在数据库中。</p>
<h2 id="查询流程定义的相关信息"><a href="#查询流程定义的相关信息" class="headerlink" title="查询流程定义的相关信息"></a>查询流程定义的相关信息</h2><pre><code>/**
* 查看流程规则信息
*/
@Test
public void view(){
// 创建流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取流程定义信息
List<ProcessDefinition> definitions = processEngine.getRepositoryService()
.createProcessDefinitionQuery()//创建流程定义查询对象
.list();//执行查询,也可以添加过滤和排序分页条件
//迭代查询出来的流程定义
for (ProcessDefinition processDefinition : definitions) {
System.out.println("id="+processDefinition.getId());
System.out.println("name="+processDefinition.getName());
System.out.println("key="+processDefinition.getKey());
System.out.println("version="+processDefinition.getVersion());
System.out.println("depolymentId="+processDefinition.getDeploymentId());
System.out.println("-----------查询完毕----------");
}
}
</code></pre><p>查询结果: </p>
<pre><code>id=leaveFlow:1:25004
name=leaveFlow
key=leaveFlow
version=1
depolymentId=25001
-----------查询完毕----------
id=leaveFlow:2:32504
name=leaveFlow
key=leaveFlow
version=2
depolymentId=32501
-----------查询完毕----------
</code></pre><p>说明: </p>
<ul>
<li>key属性被用来区别不同的流程定义。 </li>
<li>带有特定key的流程定义第一次部署时,version为1。之后每次部署都会在当前最高版本号上加1 </li>
<li>Id的值的生成规则为:{processDefinitionKey}:{processDefinitionVersion}:{generated-id}, 这里的generated-id是一个自动生成的唯一的数字</li>
<li>重复部署一次,deploymentId的值以一定的形式变化 </li>
<li>流程定义(ProcessDefinition)在数据库中没有相应的表对应,只是从act_ge_bytearray表中取出相应的bpmn和png图片,并进行解析。</li>
</ul>
<h2 id="删除流程定义"><a href="#删除流程定义" class="headerlink" title="删除流程定义"></a>删除流程定义</h2><pre><code>/**
* 删除流程定义
*/
@Test
public void delete(){
//创建流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//流程定义id
String deploymentId = "20001";
//删除指定的部署信息,如果有关联,则报错,一般用这个,级联涉及数据较多,一般是超级管理员权限
//processEngine.getRepositoryService().deleteDeployment(deploymentId);
//删除指定的部署信息,如果有关联,则级联删除,cascade参数代表是否级联删除
processEngine.getRepositoryService().deleteDeployment(deploymentId, true);
}
</code></pre><p>说明: </p>
<ul>
<li>因为删除的是流程定义,而流程定义的部署是属于仓库服务的,所以应该先得到RepositoryService </li>
<li>如果该流程定义下没有正在运行的流程,则可以用普通方法进行删除。如果是有关联的信息,则需要用方法进行级联删除。一般情况下用普通删除就可以。级联删除涉及的数据比较多,一般只开放给超级管理员使用。</li>
</ul>
<h2 id="查询出流程图片(用来显示流程图片)"><a href="#查询出流程图片(用来显示流程图片)" class="headerlink" title="查询出流程图片(用来显示流程图片)"></a>查询出流程图片(用来显示流程图片)</h2><pre><code>/**
* 查询流程定义文档(主要是流程图片)
*/
@Test
public void queryResource() throws Exception{
// 创建流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 流程定义id
String deploymentId = "10001";
List<String> names = processEngine.getRepositoryService().getDeploymentResourceNames(deploymentId);
String resourceName = null;
//遍历资源文件名列表
for (String string : names) {
//获取以.png后缀的文件名
if (string.lastIndexOf(".png")>=0) {
resourceName = string;
}
}
//如果流程图片存在
if (resourceName != null) {
File file = new File("D:/"+resourceName);
//通过流程图片对应的id和名称获得对应的输入流
InputStream in = processEngine.getRepositoryService().getResourceAsStream(deploymentId, resourceName);
//使用fileUtils把图片拷贝至指定目录下
FileUtils.copyInputStreamToFile(in, file);
}
}
</code></pre><p>说明: </p>
<ul>
<li>deploymentId为流程部署ID</li>
<li>resourceName为act_ge<em>bytearray表中NAME</em>列的值</li>
<li>使用repositoryService的getDeploymentResourceNames方法可以获取指定部署下得所有文件的名称</li>
<li>使用repositoryService的getResourceAsStream方法传入部署ID和文件名称可以获取部署下指定名称文件的输入流</li>
<li>最后的有关IO流的操作,使用FileUtils工具的copyInputStreamToFile方法完成流程流程到文件的拷贝</li>
</ul>
<h2 id="开始流程"><a href="#开始流程" class="headerlink" title="开始流程"></a>开始流程</h2><pre><code>/**
* 启动流程实例
* 启动流程实例,返回流程实例对象,停在start后的第一个节点上
*/
@Test
public void startProcess(){
//创建流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取流程运行时服务对象
RuntimeService runtimeService = processEngine.getRuntimeService();
//启动流程实例,返回实例对象
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leaveFlow");
//显示相关信息
System.out.println("流程实例ID="+processInstance.getId());
System.out.println("当前活动节点ID="+processInstance.getActivityId());
}
</code></pre><p>结果显示: </p>
<pre><code>流程实例ID=40001
当前活动节点ID=usertask1
</code></pre><p>说明: </p>
<ul>
<li>操作数据库的act_ru_execution表,如果是用户任务节点,同时也会在act_ru_task添加一条记录</li>
</ul>
<h2 id="查询待办任务"><a href="#查询待办任务" class="headerlink" title="查询待办任务"></a>查询待办任务</h2><pre><code>/**
* 查询指定用户的待办任务
*
*/
@Test
public void findUnfinshTask() {
// 创建流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
String assignee = "员工";
//查询个人的代办任务
List<Task> tasks = processEngine.getTaskService()
.createTaskQuery()//创建流程任务查询对象
.taskAssignee(assignee)//添加过滤条件
//.listPage(firstResult, maxResults)添加分页
.orderByTaskCreateTime().desc()//排序
.list();//执行查询
System.out.println("------"+assignee+"的个人任务列表------");
for (Task task : tasks) {
System.out.println("任务ID:"+task.getId());
System.out.println("任务名称:"+task.getName());
System.out.println("任务办理者:"+task.getAssignee());
System.out.println("任务创建时间:"+task.getCreateTime());
System.out.println("任务执行对象的ID:"+task.getExecutionId());
}
}
</code></pre><p>显示结果: </p>
<pre><code>------员工的个人任务列表------
任务ID:40004
任务名称:员工请假申请
任务办理者:员工
任务创建时间:Fri Jun 23 08:33:08 CST 2017
任务执行对象的ID:40001
任务ID:32508
任务名称:员工请假申请
任务办理者:员工
任务创建时间:Thu Jun 22 16:50:10 CST 2017
任务执行对象的ID:32505
</code></pre><p>说明: </p>
<ul>
<li>因为是任务查询,所以从processEngine中应该得到TaskService</li>
<li>使用TaskService获取到任务查询对象TaskQuery</li>
<li>为查询对象添加查询过滤条件,使用taskAssignee指定任务的候选者(即查询指定用户的代办任务),添加分页排序等过滤条件</li>
<li>调用list方法执行查询,返回办理者为指定用户的任务列表</li>
<li>任务ID、名称、办理人、创建时间可以从act_ru_task表中查到。</li>
<li>在这种情况下,ProcessInstance相当于Execution</li>
<li>一个Task节点和Execution节点是1对1的情况,在task对象中使用Execution_来标示他们之间的关系</li>
<li>任务ID在数据库表act<em> ru</em> task中对应“ID_”列</li>
</ul>
<h2 id="可领取任务查询和领取"><a href="#可领取任务查询和领取" class="headerlink" title="可领取任务查询和领取"></a>可领取任务查询和领取</h2><pre><code>/**
* 查询指定用户的可以领取的任务
*
*/
@Test
public void findCanTakeTask() {
// 创建流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
String candidateUser = "员工";
//查询个人的代办任务
List<Task> tasks = processEngine.getTaskService()
.createTaskQuery()//创建流程任务查询对象
.taskCandidateUser(candidateUser)//代表过滤任务候选者为自己的任务
//.listPage(firstResult, maxResults)添加分页
.orderByTaskCreateTime().desc()//排序
.list();//执行查询
System.out.println("------"+candidateUser+"的个人任务列表------");
for (Task task : tasks) {
System.out.println("任务ID:"+task.getId());
System.out.println("任务名称:"+task.getName());
System.out.println("任务办理者:"+task.getAssignee());
System.out.println("任务创建时间:"+task.getCreateTime());
System.out.println("任务执行对象的ID:"+task.getExecutionId());
}
}
/**
* 查询指定用户的可以领取的任务
*
*/
@Test
public void findCanTakeTask() {
// 创建流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
String candidateUser = "员工1";
//查询个人的代办任务
List<Task> tasks = processEngine.getTaskService()
.createTaskQuery()//创建流程任务查询对象
.taskCandidateUser(candidateUser)//代表过滤任务候选者为自己的任务
//.listPage(firstResult, maxResults)添加分页
.orderByTaskCreateTime().desc()//排序
.list();//执行查询
System.out.println("------"+candidateUser+"的个人任务列表------");
for (Task task : tasks) {
System.out.println("任务ID:"+task.getId());
System.out.println("任务名称:"+task.getName());
System.out.println("任务办理者:"+task.getAssignee());
System.out.println("任务创建时间:"+task.getCreateTime());
System.out.println("任务执行对象的ID:"+task.getExecutionId());
}
}
/**
* 公共任务的认领
*/
@Test
public void takeTask(){
// 创建流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 接手得任务ID
String taskId = "";
// 员工ID
String userId = "";
//认领任务
processEngine.getTaskService().claim(taskId, userId);
}
</code></pre><p>说明: </p>
<ul>
<li>在查询对象上,添加taskCandidateUser过滤条件,代表过滤任务候 选者为自己的任务</li>
<li>所有公共任务的assignee属性为空</li>
<li>调用taskService的claim(认领)方法,把公共任务变成指定用户的私有任务</li>
</ul>
<h2 id="办理任务"><a href="#办理任务" class="headerlink" title="办理任务"></a>办理任务</h2><pre><code>/**
* 任务的办理,完成任务后,使流程往后进行
*/
@Test
public void completeTask() {
// 创建流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 指定任务id
String taskId = "35002";
// 完成任务
processEngine.getTaskService().complete(taskId);
}
</code></pre><p>说明: </p>
<ul>
<li>是办理任务,所以从ProcessEngine得到的是TaskService。</li>
<li>当执行完这段代码,再以员工的身份去执行查询的时候,会发现这个时候已经没有数据了。</li>
<li>对于执行完的任务,activiti将从act_ru_task表中删除该任务,下一个任务会被插入进来。</li>
<li>以”项目经理”的身份进行查询,可以查到结果。因为流程执行到项目经理审批这个节点了。</li>
<li>再执行办理任务代码,执行完以后以”项目经理”身份进行查询,没有结果。</li>
<li>重复上面的直到流程执行完。</li>
</ul>
<h2 id="验证流程是否结束,查看历史流程"><a href="#验证流程是否结束,查看历史流程" class="headerlink" title=" 验证流程是否结束,查看历史流程"></a> 验证流程是否结束,查看历史流程</h2><pre><code>/**
* 验证流程已结束
*/
@Test
public void checkTaskEnded() {
// 创建流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 流程定义ID
String processId = "leaveFlow:1:25004";
//通过流程定义Id获取到流程定义对象
ProcessInstance processInstance = processEngine.getRuntimeService()
.createProcessInstanceQuery()
.processInstanceId(processId)
.singleResult();
//查看实例是否完成
if (processInstance!= null) {
System.out.println("当前活动节点为"+processInstance.getActivityId());
}else {
System.out.println("ID为【"+processId+"】的实例流程已经结束");
}
}
/**
* 查看历史流程,某个用户一共执行了多少次请假流程
*
*/
@Test
public void queryHistoryInstance() {
// 创建流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 指定流程定义Id
String processDefinitionId = "leaveFlow:1:25004";
// 查询历史流程实例
List<HistoricProcessInstance> list = processEngine.getHistoryService()
.createHistoricProcessInstanceQuery()
.processDefinitionId(processDefinitionId)//安装该流程定义id
.finished()//已完成
.orderByProcessInstanceStartTime().desc()//排序
.list();
for (HistoricProcessInstance historicProcessInstance : list) {
System.out.println("ID:"+historicProcessInstance.getProcessDefinitionId());
System.out.println("开始活动ID:"+historicProcessInstance.getStartActivityId());
System.out.println("开始时间:"+historicProcessInstance.getStartTime());
System.out.println("结束时间:"+historicProcessInstance.getEndTime());
}
}
/**
* 查看历史流程活动 查看某一次流程所经历的步骤
*/
@Test
public void queryHistoryActivit() {
// 创建流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 指定流程定义Id
String processDefinitionId = "leaveFlow:1:25004";
//查询历史流程
List<HistoricActivityInstance> list = processEngine.getHistoryService()
.createHistoricActivityInstanceQuery()
.processInstanceId(processDefinitionId)
.list();
for (HistoricActivityInstance historicActivityInstance : list) {
System.out.println("ID:"+historicActivityInstance.getProcessDefinitionId());
System.out.println("开始活动ID:"+historicActivityInstance.getActivityId());
System.out.println("开始活动名称:" + historicActivityInstance.getActivityName());
System.out.println("开始时间:"+historicActivityInstance.getStartTime());
System.out.println("结束时间:"+historicActivityInstance.getEndTime());
}
}
}
</code></pre><p>说明: </p>
<ul>
<li><p>在流程执行的过程中,创建的流程实例ID在整个过程中都不会变,当流程结束后,流程实例将会被删除</p>
</li>
<li><p>HistoricProcessInstance 包含当前和已经结束的流程实例信息。</p>
</li>
<li>HistoricActivityInstance 包含一个活动(流程上的节点)的执行信息 </li>
<li>processInstanceId查看具体某一次流程执行过程中所经历的步骤</li>
</ul>
<h2 id="流程变量添加(可添加javabean)"><a href="#流程变量添加(可添加javabean)" class="headerlink" title="流程变量添加(可添加javabean)"></a>流程变量添加(可添加javabean)</h2>]]></content>
<summary type="html">
<p>Activiti其核心是BPMN2.0 的流程引擎,是覆盖了业务流程管理、工作流、服务协作等领域的一个开源的、灵活的、易扩展的可执行流程语言框架<br>
</summary>
<category term="JavaEE" scheme="http://yoursite.com/categories/JavaEE/"/>
<category term="Activiti" scheme="http://yoursite.com/tags/Activiti/"/>
<category term="BPMN2.0" scheme="http://yoursite.com/tags/BPMN2-0/"/>
</entry>
<entry>
<title>UEditor样式被过滤解决</title>
<link href="http://yoursite.com/2017/06/21/UEditor%E6%A0%B7%E5%BC%8F%E8%A2%AB%E8%BF%87%E6%BB%A4%E8%A7%A3%E5%86%B3/"/>
<id>http://yoursite.com/2017/06/21/UEditor样式被过滤解决/</id>
<published>2017-06-21T06:34:34.000Z</published>
<updated>2017-06-21T06:51:26.830Z</updated>
<content type="html"><![CDATA[<p>前几天项目使用UEditor,结果发现class样式被过滤掉了,div标签也被自动替换成了p标签</p>
<a id="more"></a>
<h1 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h1><p>前几天项目使用UEditor,结果发现class样式被过滤掉了,div标签也被自动替换成了p标签,也就是html内容无法正确显示,会被自动替换。</p>
<h1 id="解决办法"><a href="#解决办法" class="headerlink" title="解决办法"></a>解决办法</h1><p>1.在ueditor.all.js文件内找到如下代码 </p>
<pre><code>UE.plugins['defaultfilter'] = function () {
var me = this;
me.setOpt({
'allowDivTransToP':true,
'disabledTableInTable':true
});
//默认的过滤处理
//进入编辑器的内容处理
me.addInputRule(function (root) {
var allowDivTransToP = this.options.allowDivTransToP;
var val;
function tdParent(node){
while(node && node.type == 'element'){
if(node.tagName == 'td'){
return true;
}
node = node.parentNode;
}
return false;
}
//进行默认的处理
root.traversal(function (node) {
if (node.type == 'element') {
if (!dtd.$cdata[node.tagName] && me.options.autoClearEmptyNode && dtd.$inline[node.tagName] && !dtd.$empty[node.tagName] && (!node.attrs || utils.isEmptyObject(node.attrs))) {
if (!node.firstChild()) node.parentNode.removeChild(node);
else if (node.tagName == 'span' && (!node.attrs || utils.isEmptyObject(node.attrs))) {
node.parentNode.removeChild(node, true)
}
return;
}
switch (node.tagName) {
case 'style':
case 'script':
node.setAttr({
cdata_tag: node.tagName,
cdata_data: (node.innerHTML() || ''),
'_ue_custom_node_':'true'
});
node.tagName = 'div';
node.innerHTML('');
break;
case 'a':
if (val = node.getAttr('href')) {
node.setAttr('_href', val)
}
break;
//以下代码省略
</code></pre><p>2.把上面代码中的’allowDivTransToP’:true, 改成如下 </p>
<pre><code>me.setOpt({
'allowDivTransToP':false,
'disabledTableInTable':true
});
</code></pre><p>3.把 switch (node.tagName)中的case ‘style’:case ‘script’:注释掉,如下 </p>
<pre><code>switch (node.tagName) {
//case 'style':
/*case 'script':
node.setAttr({
cdata_tag: node.tagName,
cdata_data: (node.innerHTML() || ''),
'_ue_custom_node_':'true'
});
node.tagName = 'div';
node.innerHTML('');
break;
*/
case 'a':
if (val = node.getAttr('href')) {
node.setAttr('_href', val)
}
break;
//以下代码省略
</code></pre><h1 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h1><ul>
<li>allowDivTransToP设置为false是因为默认的设置是将div自动转换为p,这样写好的样式就找不到相应的div<br>了,所以才渲染不上的。</li>
<li>addInputRule函数中的switch 代码段中的case style ,script选择给删除或者注释,是为了避免出现编辑器style或script自动的转换成别的标签。</li>
</ul>
]]></content>
<summary type="html">
<p>前几天项目使用UEditor,结果发现class样式被过滤掉了,div标签也被自动替换成了p标签</p>
</summary>
<category term="JavaEE" scheme="http://yoursite.com/categories/JavaEE/"/>
<category term="UEditor样式过滤" scheme="http://yoursite.com/tags/UEditor%E6%A0%B7%E5%BC%8F%E8%BF%87%E6%BB%A4/"/>
</entry>
<entry>
<title>webmagic爬虫使用</title>
<link href="http://yoursite.com/2017/06/20/webmagic%E7%88%AC%E8%99%AB%E4%BD%BF%E7%94%A8/"/>
<id>http://yoursite.com/2017/06/20/webmagic爬虫使用/</id>
<published>2017-06-20T06:45:42.000Z</published>
<updated>2017-06-21T07:31:12.362Z</updated>
<content type="html"><![CDATA[<p>WebMagic是国内大牛开发的一款灵活开源的Java爬虫框架</p>
<a id="more"></a>
<p><img src="http://oje7mvhbz.bkt.clouddn.com/webmagic.png" alt="WebMagic"><br><a href="https://github.com/code4craft/webmagic" target="_blank" rel="external">github项目地址</a><br><a href="http://webmagic.io/docs/zh/" target="_blank" rel="external">官方中文文档</a></p>
<h1 id="简单入门"><a href="#简单入门" class="headerlink" title="简单入门"></a>简单入门</h1><p>WebMagic使用简单,而且中文文档介绍的也很详细,这篇博客主要介绍简单的使用,想要深入的话需要再研究</p>
<h2 id="编写基本爬虫"><a href="#编写基本爬虫" class="headerlink" title="编写基本爬虫"></a>编写基本爬虫</h2><h2 id="使用注解编写爬虫"><a href="#使用注解编写爬虫" class="headerlink" title="使用注解编写爬虫"></a>使用注解编写爬虫</h2><h1 id="使用WebMagic爬取新浪nba页面新闻"><a href="#使用WebMagic爬取新浪nba页面新闻" class="headerlink" title="使用WebMagic爬取新浪nba页面新闻"></a>使用WebMagic爬取新浪nba页面新闻</h1><pre><code>import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.model.OOSpider;
import us.codecraft.webmagic.model.annotation.ExtractBy;
import us.codecraft.webmagic.model.annotation.HelpUrl;
import us.codecraft.webmagic.model.annotation.TargetUrl;
import us.codecraft.webmagic.pipeline.FilePageModelPipeline;
@TargetUrl("http://sports.sina.com.cn/basketball/nba/2017-06-19/doc-\\w+.shtml")
@HelpUrl("http://sports.sina.com.cn/")
public class NbaNews{
@ExtractBy(value="//h1[@id='j_title']/text()",notNull=true)
private String title;
@ExtractBy("//section[@class='article-a_keywords']/a/text()")
private String keywords;
@ExtractBy("//div[@id=artibody]/tidyText()")
private String content;
public static void main(String[] args) {
OOSpider.create(Site.me().setSleepTime(1000)
, new FilePageModelPipeline("D:\\webmagic\\"), NbaNews.class)
.addUrl("http://sports.sina.com.cn/nba/").thread(5).run();
}
}
</code></pre>]]></content>
<summary type="html">
<p>WebMagic是国内大牛开发的一款灵活开源的Java爬虫框架</p>
</summary>
<category term="JavaEE" scheme="http://yoursite.com/categories/JavaEE/"/>
<category term="WebMagic" scheme="http://yoursite.com/tags/WebMagic/"/>
<category term="爬虫" scheme="http://yoursite.com/tags/%E7%88%AC%E8%99%AB/"/>
</entry>
<entry>
<title>Ueditor使用</title>
<link href="http://yoursite.com/2017/06/14/Ueditor%E4%BD%BF%E7%94%A8/"/>
<id>http://yoursite.com/2017/06/14/Ueditor使用/</id>
<published>2017-06-14T10:12:41.000Z</published>
<updated>2017-06-14T10:54:38.593Z</updated>
<content type="html"><![CDATA[<p>UEditor和springMVC整合上传图片</p>
<a id="more"></a>
<p><a href="http://ueditor.baidu.com/website/" target="_blank" rel="external">UEditro官网</a><br><a href="http://fex.baidu.com/ueditor/#start-start" target="_blank" rel="external">官方文档</a></p>
<h3 id="下载"><a href="#下载" class="headerlink" title="下载"></a>下载</h3><p>提供了各种版本的下载,我下载的是jsp版本的,当然你也可以下载完整源码,一样的使用,<strong>注意版本,不同的版本使用方法可能有些不同</strong><br><img src="http://oje7mvhbz.bkt.clouddn.com/GD%5DADT7L~%29Q%7B6_1%5BTGJ%29%5B%5DF.png" alt="下载UEditor"></p>
<h3 id="导入项目"><a href="#导入项目" class="headerlink" title="导入项目"></a>导入项目</h3><p>把所有下载的包解压后,导入项目中。<strong>并把/jsp/lib文件夹下的jar包添加到pom.xml中</strong><br><img src="http://oje7mvhbz.bkt.clouddn.com/06%5D36C5@P4P3G0@0Q5X%7DB56.png" alt="导入项目中"></p>
<h3 id="在需要使用的页面引入js和css"><a href="#在需要使用的页面引入js和css" class="headerlink" title="在需要使用的页面引入js和css"></a>在需要使用的页面引入js和css</h3><pre><code><script type="text/javascript" src="/js/ueditor/ueditor.config.js"></script>
<script type="text/javascript" src="/js/ueditor/ueditor.all.js"></script>
<script type="text/javascript" charset="utf-8" src="/js/ueditor/lang/zh-cn/zh-cn.js"></script>
<link href="/js/ueditor/themes/default/css/ueditor.css" rel="stylesheet" type="text/css" />
</code></pre><h3 id="在页面js中实例化UE"><a href="#在页面js中实例化UE" class="headerlink" title="在页面js中实例化UE"></a>在页面js中实例化UE</h3><pre><code>/*富文本编辑器*/
var editor = UE.getEditor('content');
UE.Editor.prototype._bkGetActionUrl = UE.Editor.prototype.getActionUrl;
UE.Editor.prototype.getActionUrl = function(action) {
if (action == 'uploadimage' || action == 'uploadscrawl' || action == 'catchimage'
|| action == 'uploadimage') {
return basePath+'/uploadimage.html';
}else {
return this._bkGetActionUrl.call(this, action);
}
}
</code></pre><h3 id="如果你的jsp文件夹没有移动过位置就不需要配置uditor-config-js和controller中的路径"><a href="#如果你的jsp文件夹没有移动过位置就不需要配置uditor-config-js和controller中的路径" class="headerlink" title="如果你的jsp文件夹没有移动过位置就不需要配置uditor.config.js和controller中的路径"></a>如果你的jsp文件夹没有移动过位置就不需要配置uditor.config.js和controller中的路径</h3><h3 id="配置uditor-config-js自定义工具栏"><a href="#配置uditor-config-js自定义工具栏" class="headerlink" title="配置uditor.config.js自定义工具栏"></a>配置uditor.config.js自定义工具栏</h3><pre><code>toolbars: [
[
'anchor', //锚点
'undo', //撤销
'redo', //重做
'bold', //加粗
'indent', //首行缩进
'snapscreen', //截图
'italic', //斜体
'underline', //下划线
'strikethrough', //删除线
'subscript', //下标
'fontborder', //字符边框
'superscript', //上标
'formatmatch', //格式刷
'source', //源代码
'blockquote', //引用
'pasteplain', //纯文本粘贴模式
'selectall', //全选
'print', //打印
'preview', //预览
'horizontal', //分隔线
'removeformat', //清除格式
'time', //时间
'date', //日期
'unlink', //取消链接
'insertrow', //前插入行
'insertcol', //前插入列
'mergeright', //右合并单元格
'mergedown', //下合并单元格
'deleterow', //删除行
'deletecol', //删除列
'splittorows', //拆分成行
'splittocols', //拆分成列
'splittocells', //完全拆分单元格
'deletecaption', //删除表格标题
'inserttitle', //插入标题
'mergecells', //合并多个单元格
'deletetable', //删除表格
'cleardoc', //清空文档
'insertparagraphbeforetable', //"表格前插入行"
'insertcode', //代码语言
'fontfamily', //字体
'fontsize', //字号
'paragraph', //段落格式
'simpleupload', //单图上传
'insertimage', //多图上传
'edittable', //表格属性
'edittd', //单元格属性
'link', //超链接
'emotion', //表情
'spechars', //特殊字符
'searchreplace', //查询替换
'map', //Baidu地图
'gmap', //Google地图
'insertvideo', //视频
'help', //帮助
'justifyleft', //居左对齐
'justifyright', //居右对齐
'justifycenter', //居中对齐
'justifyjustify', //两端对齐
'forecolor', //字体颜色
'backcolor', //背景色
'insertorderedlist', //有序列表
'insertunorderedlist', //无序列表
'fullscreen', //全屏
'directionalityltr', //从左向右输入
'directionalityrtl', //从右向左输入
'rowspacingtop', //段前距
'rowspacingbottom', //段后距
'pagebreak', //分页
'insertframe', //插入Iframe
'imagenone', //默认
'imageleft', //左浮动
'imageright', //右浮动
'attachment', //附件
'imagecenter', //居中
'wordimage', //图片转存
'lineheight', //行间距
'edittip ', //编辑提示
'customstyle', //自定义标题
'autotypeset', //自动排版
'webapp', //百度应用
'touppercase', //字母大写
'tolowercase', //字母小写
'background', //背景
'template', //模板
'scrawl', //涂鸦
'music', //音乐
'inserttable', //插入表格
'drafts', // 从草稿箱加载
'charts', // 图表
]
]
</code></pre><h3 id="配置config-json,这里列举一个配置,其他一样配置imagePathFormat和imageUrlPrefix一定不能错"><a href="#配置config-json,这里列举一个配置,其他一样配置imagePathFormat和imageUrlPrefix一定不能错" class="headerlink" title="配置config.json,这里列举一个配置,其他一样配置imagePathFormat和imageUrlPrefix一定不能错"></a>配置config.json,这里列举一个配置,其他一样配置imagePathFormat和imageUrlPrefix一定不能错</h3><pre><code>/* 前后端通信相关的配置,注释只允许使用多行方式 */
{
/* 上传图片配置项 */
"imageActionName": "uploadimage", /* 执行上传图片的action名称 */
"imageFieldName": "upfile", /* 提交的图片表单名称 */
"imageMaxSize": 2048000, /* 上传大小限制,单位B */
"imageAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 上传图片格式显示 */
"imageCompressEnable": true, /* 是否压缩图片,默认是true */
"imageCompressBorder": 1600, /* 图片压缩最长边限制 */
"imageInsertAlign": "none", /* 插入的图片浮动方式 */
"imageUrlPrefix": "", /* 图片访问路径前缀 */
"imagePathFormat": "/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
/* {filename} 会替换成原文件名,配置这项需要注意中文乱码问题 */
/* {rand:6} 会替换成随机数,后面的数字是随机数的位数 */
/* {time} 会替换成时间戳 */
/* {yyyy} 会替换成四位年份 */
/* {yy} 会替换成两位年份 */
/* {mm} 会替换成两位月份 */
/* {dd} 会替换成两位日期 */
/* {hh} 会替换成两位小时 */
/* {ii} 会替换成两位分钟 */
/* {ss} 会替换成两位秒 */
/* 非法字符 \ : * ? " < > | */
/* 具请体看线上文档: fex.baidu.com/ueditor/#use-format_upload_filename */
}
</code></pre><p><strong>imageUrlPrefix:</strong> 这个一般是项目url,比如www.baidu.com<br><strong>imagePathFormat:</strong> 和上传路劲中的一致就可以了</p>
<h3 id="我使用的是springMVC实现上传,只有当返回的json中state的值为SUCCESS才上传成功,上传失败则回显state的值"><a href="#我使用的是springMVC实现上传,只有当返回的json中state的值为SUCCESS才上传成功,上传失败则回显state的值" class="headerlink" title="我使用的是springMVC实现上传,只有当返回的json中state的值为SUCCESS才上传成功,上传失败则回显state的值"></a>我使用的是springMVC实现上传,只有当返回的json中state的值为SUCCESS才上传成功,上传失败则回显state的值</h3><pre><code>@ResponseBody
@RequestMapping(value = "/uploadimage.html")
public Map<String,Object> uploadImage(@RequestParam("upfile") MultipartFile[] multipartFiles, HttpServletRequest request, HttpServletResponse response) {
//存放地址
String filepath = "";
Map<String,Object> map=new HashMap<String,Object>();
//对上传文件进行安全性验证
if(multipartFiles!=null && multipartFiles.length>0){
//循环遍历
for (MultipartFile multipartFile : multipartFiles) {
String state="SUCCESS";
if (CheckoutFileTypeUtil.getUpFilelegitimacyFlag(multipartFile)) {
try {
filepath = UploadUtil.uploadUeFile(multipartFile);
if (logger.isDebugEnabled()) {
logger.debug("上传成功---------------------"+filepath+"上传成功---------------------");
}
//注意url会和conf.json中的路径配合找到图片
map.put("url", filepath);
map.put("state", "SUCCESS");
} catch (IOException e) {
logger.debug("图片上传失败");
e.printStackTrace();
}
}else {
map.put("state", "上传失败!");
map.put("url", null);
if (logger.isDebugEnabled()) {
logger.debug("图片格式不对,上传失败!");
}
}
}
}
return map;
}
</code></pre><h3 id="对上传的文件进行后端安全性验证,验证文件的魔数和格式,防止黑客绕过前端上传木马"><a href="#对上传的文件进行后端安全性验证,验证文件的魔数和格式,防止黑客绕过前端上传木马" class="headerlink" title="对上传的文件进行后端安全性验证,验证文件的魔数和格式,防止黑客绕过前端上传木马"></a>对上传的文件进行后端安全性验证,验证文件的魔数和格式,防止黑客绕过前端上传木马</h3><pre><code> /**
*
* @Description: 处理上传附件,校验是否合法
* 在服务器端判断文件类型的问题,故用获取文件头的方式,
* 直接读取文件的前几个字节,来判断上传文件是否符合格式
*/
public class CheckoutFileTypeUtil {
//记录各个文件头信息及对应的文件类型
public static Map<String, String> mFileTypes = new HashMap<String, String>();
//所有合法的文件后缀
public static String res_fileType=".jpg.png.gif.bmp";
static {
// images
mFileTypes.put("FFD8FFE0", ".jpg");
mFileTypes.put("FFD8FFE1", ".jpg");
mFileTypes.put("89504E47", ".png");
mFileTypes.put("47494638", ".gif");
mFileTypes.put("49492A00", ".tif");
mFileTypes.put("424D", ".bmp");
//PS和CAD
mFileTypes.put("38425053", ".psd");
mFileTypes.put("41433130", ".dwg"); // CAD
mFileTypes.put("252150532D41646F6265",".ps");
//办公文档类
mFileTypes.put("D0CF11E0", ".doc"); //ppt、doc、xls
mFileTypes.put("504B0304", ".docx");//pptx、docx、xlsx
/**注意由于文本文档录入内容过多,则读取文件头时较为多变-START**/
mFileTypes.put("0D0A0D0A", ".txt");//txt
mFileTypes.put("0D0A2D2D", ".txt");//txt
mFileTypes.put("0D0AB4B4", ".txt");//txt
mFileTypes.put("B4B4BDA8", ".txt");//文件头部为汉字
mFileTypes.put("73646673", ".txt");//txt,文件头部为英文字母
mFileTypes.put("32323232", ".txt");//txt,文件头部内容为数字
mFileTypes.put("0D0A09B4", ".txt");//txt,文件头部内容为数字
mFileTypes.put("3132330D", ".txt");//txt,文件头部内容为数字
/**注意由于文本文档录入内容过多,则读取文件头时较为多变-END**/
mFileTypes.put("7B5C727466", ".rtf"); // 日记本
mFileTypes.put("255044462D312E", ".pdf");
//视频或音频类
mFileTypes.put("3026B275",".wma");
mFileTypes.put("57415645", ".wav");
mFileTypes.put("41564920", ".avi");
mFileTypes.put("4D546864", ".mid");
mFileTypes.put("2E524D46", ".rm");
mFileTypes.put("000001BA", ".mpg");
mFileTypes.put("000001B3", ".mpg");
mFileTypes.put("6D6F6F76", ".mov");
mFileTypes.put("3026B2758E66CF11", ".asf");
//压缩包
mFileTypes.put("52617221", ".rar");
mFileTypes.put("1F8B08", ".gz");
//程序文件
mFileTypes.put("3C3F786D6C", ".xml");
mFileTypes.put("68746D6C3E", ".html");
mFileTypes.put("7061636B", ".java");
mFileTypes.put("3C254020", ".jsp");
mFileTypes.put("4D5A9000", ".exe");
mFileTypes.put("44656C69766572792D646174653A", ".eml"); // 邮件
mFileTypes.put("5374616E64617264204A", ".mdb");//Access数据库文件
mFileTypes.put("46726F6D", ".mht");
mFileTypes.put("4D494D45", ".mhtml");
}
/**
* 根据文件的输入流获取文件头信息
*
* @param filePath 文件路径
* @return 文件头信息
*/
public static String getFileType(InputStream is) {
byte[] b = new byte[4];