个人博客地址:www.wzbjsz.cn

在线浏览地址:activiti.wzbjsz.cn

什么是工作流?

工作流(Workflow),就是通过计算机对业务流程自动化执行管理。它主要解决的是“使在多个参与者之间按照某种预定义的规则自动进行传递文档、信息或任务的过程,从而实现某个预期的业务目标,或者促使此目标的实现”。

什么是Activiti?

Alfresco软件在2010年5月17日宣布Activiti业务流程管理(BPM)开源项目的正式启动,其首席架构师由业务流程管理BPM的专家 Tom Baeyens担任,Tom Baeyens就是原来jbpm的架构师,而jbpm是一个非常有名的工作流引擎,当然activiti也是一个工作流引擎。

Activiti是一个工作流引擎, activiti可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言(BPMN2.0)进行定义,业务系统按照预先定义的流程进行执行,实现了业务系统的业务流程由activiti进行管理,减少业务系统由于流程变更进行系统升级改造的工作量,从而提高系统的健壮性,同时也减少了系统开发维护成本。

什么是BPMN?

BPMN(Business Process Model And Notation)- 业务流程模型和符号 是由BPMI(Business Process Management Initiative)开发的一套标准的业务流程建模符号,使用BPMN提供的符号可以创建业务流程。 2004年5月发布了BPMN1.0规范.BPMI于2005年9月并入OMG(The Object Management Group对象管理组织)组织。OMG于2011年1月发布BPMN2.0的最终版本。

具体发展历史如下:


BPMN 是目前被各 BPM 厂商广泛接受的 BPM 标准。Activiti 就是使用 BPMN 2.0 进行流程建模、流程执行管理,它包括很多的建模符号,比如:

Event 用一个圆圈表示,它是流程中运行过程中发生的事情。


活动用圆角矩形表示,一个流程由一个活动或多个活动组成

一个bpmn图形的例子:

Bpmn图形其实是通过xml表示业务流程,上边的.bpmn文件使用文本编辑器打开:

一:在项目pom.xml文件中添加activity依赖。

        <dependency><groupId>org.activiti</groupId><artifactId>activiti-spring-boot-starter-basic</artifactId><version>6.0.0</version></dependency>

二:修改启动类。

@SpringBootApplication(exclude={org.activiti.spring.boot.SecurityAutoConfiguration.class})

三:流程文件。
在src/main/java/resources目录下新建processes目录,并在该目录下新增一个业务流程文件(默认以.bpmn20.xml或.bpmn为后缀名)(activity默认校验resources下的processes文件夹里的流程文件,如果没有processes目录并且目录下没有流程文件会报错class path resource [processes/] cannot be resolved to URL because it does not exist),
可以在配置文件中配置spring.activiti.check-process-definitions=false,设置为不校验,这样就不会报错。
四:修改activity默认的id生成策略。
1.activiti默认的ID生成策略在高并发场景下会出现ID重复的情况,因此在高并发场景下建议采用UUID的策略。
2.传统的spring在配置文件中添加idGenerator属性:

    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"><!-- UUID作为主键生成策略 --><property name="idGenerator" ref="idGenerator" /></bean>

3.springboot中在配置类中修改idGenerator。
需要写一个类实现IdGenerator,并重写getNextId()方法;
activity也内置了一个实现类org.activiti.engine.impl.persistence.StrongUuidGenerator,生成的uuid是带'-'的

package com.mycompany.myapp.config;import org.activiti.spring.SpringProcessEngineConfiguration;
import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
import org.springframework.context.annotation.Configuration;import com.mycompany.myapp.utils.idGenerator;/**
* @author www.wzbjsz.cn
* @date 2019-01-09 10:26:47
*/
@Configuration
public class ActivitiConfig implements ProcessEngineConfigurationConfigurer {@Overridepublic void configure(SpringProcessEngineConfiguration springProcessEngineConfiguration) {springProcessEngineConfiguration.setIdGenerator(new idGenerator());}}
package com.mycompany.myapp.utils;import java.util.UUID;import org.activiti.engine.impl.cfg.IdGenerator;/**
* @author www.wzbjsz.cn
* @date 2019-01-09 10:47:59
*/
public class idGenerator implements IdGenerator{/*** 封装JDK自带的UUID, 通过Random数字生成, 中间无-分割.*/public static String uuid() {return UUID.randomUUID().toString().replaceAll("-", "");}/*** Activiti ID 生成*/@Overridepublic String getNextId() {return IdGen.uuid();}}

五:配置文件属性:
1.spring.activiti.database-schema-update

spring.activiti.database-schema-update=true

databaseSchemaUpdate配置项可以设置流程引擎启动和关闭时数据库执行的策略。 databaseSchemaUpdate有以下四个值:

false:false为默认值,设置为该值后,Activiti在启动时,会对比数据库表中保存的版本,如果版本不匹配时,将在启动时抛出异常。
true:设置为该值后,Activiti会对数据库中所有的表进行更新,如果表不存在,则Activiti会自动创建。
create-drop:Activiti启动时,会执行数据库表的创建操作,在Activiti关闭时,执行数据库表的删除操作。
drop-create:Activiti启动时,执行数据库表的删除操作在Activiti关闭时,会执行数据库表的创建操作。

设置为true后启动应用,会在数据库里创建28张表,表创建好之后停止应用,设置为false,每次应用启动不检查Activiti数据表是否存在及版本号是否匹配,以提升应用启动速度。
2.spring.activiti.history-level

#保存历史数据级别设置为full最高级别,便于历史数据的追溯
spring.activiti.history-level=full

对于历史数据,保存到何种粒度,Activiti提供了history-level属性对其进行配置。history-level属性有点像log4j的日志输出级别,该属性有以下四个值:

none:不保存任何的历史数据,因此,在流程执行过程中,这是最高效的。
activity:级别高于none,保存流程实例与流程行为,其他数据不保存。
audit:除activity级别会保存的数据外,还会保存全部的流程任务及其属性。audit为history的默认值。
full:保存历史数据的最高级别,除了会保存audit级别的数据外,还会保存其他全部流程相关的细节数据,包括一些流程参数等。

3.spring.activiti.check-process-definitions

#关闭activiti自动部署(使用流程设计器部署,不使用具体文件访问方式)
spring.activiti.check-process-definitions=false

六:集成在线流程设计器Activiti Modeler。
1.pom文件添加activiti-modeler依赖。

        <!-- https://mvnrepository.com/artifact/org.activiti/activiti-modeler --><dependency><groupId>org.activiti</groupId><artifactId>activiti-modeler</artifactId><version>5.22.0</version><exclusions><exclusion><groupId>org.activiti</groupId><artifactId>activiti-bpmn-model</artifactId></exclusion></exclusions></dependency>

2.下载activiti5.22.0源码https://github.com/Activiti/Activiti/tree/activiti-5.22.0。
3.复制Activiti 5.22.0中Activiti\modules\activiti-webapp-explorer2\src\main\webapp中的diagram-viewer、editor-app两个文件夹和modeler.html文件到Spring Boot项目resources目录下的static文件夹下。

image.png

image.png

4.修改resource/static/editor-app/app-cfg.js。

image.png

改为:

var ACTIVITI = ACTIVITI || {};ACTIVITI.CONFIG = {'contextRoot' : '/service',
};

5.复制Activiti\modules\activiti-webapp-explorer2\src\main\resources中的stencilset.json文件到Spring Boot项目中的resources目录下,activiti自带是英文的。
6.将Activiti 5.22.0源码中activiti-modeler中的下列3个java文件复制到自己的项目中,并在三个java类上添加注解@RequestMapping("/service")。(/service与上面app-cfg.js中保持一致)

image.png

image.png

7.修改ModelSaveRestResource.java文件:

/* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/
package com.mycompany.myapp.modeler.editor.model;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;/*** @author Tijs Rademakers*/
@RestController
@RequestMapping("/service")
public class ModelSaveRestResource implements ModelDataJsonConstants {protected static final Logger LOGGER = LoggerFactory.getLogger(ModelSaveRestResource.class);@Autowiredprivate RepositoryService repositoryService;@Autowiredprivate ObjectMapper objectMapper;@RequestMapping(value="/model/{modelId}/save", method = RequestMethod.PUT)@ResponseStatus(value = HttpStatus.OK)public void saveModel(@PathVariable String modelId, String name, String description, String json_xml, String svg_xml) {try {Model model = repositoryService.getModel(modelId);ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());modelJson.put(MODEL_NAME, name);modelJson.put(MODEL_DESCRIPTION, description);model.setMetaInfo(modelJson.toString());model.setName(name);repositoryService.saveModel(model);repositoryService.addModelEditorSource(model.getId(), json_xml.getBytes("utf-8"));InputStream svgStream = new ByteArrayInputStream(svg_xml.getBytes("utf-8"));TranscoderInput input = new TranscoderInput(svgStream);PNGTranscoder transcoder = new PNGTranscoder();// Setup outputByteArrayOutputStream outStream = new ByteArrayOutputStream();TranscoderOutput output = new TranscoderOutput(outStream);// Do the transformationtranscoder.transcode(input, output);final byte[] result = outStream.toByteArray();repositoryService.addModelEditorSourceExtra(model.getId(), result);outStream.close();} catch (Exception e) {LOGGER.error("Error saving model", e);throw new ActivitiException("Error saving model", e);}}
}

8.测试创建模型。

    /*** 新建一个空模型* @return* @throws UnsupportedEncodingException*/@GetMapping("/create")public void newModel(HttpServletRequest request,HttpServletResponse response) throws Exception {//初始化一个空模型Model model = repositoryService.newModel();//设置一些默认信息String name = "new-process";String description = "";int revision = 1;String key = "process";ObjectNode modelNode = objectMapper.createObjectNode();modelNode.put(ModelDataJsonConstants.MODEL_NAME, name);modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);modelNode.put(ModelDataJsonConstants.MODEL_REVISION, revision);model.setName(name);model.setKey(key);model.setMetaInfo(modelNode.toString());repositoryService.saveModel(model);String id = model.getId();//完善ModelEditorSourceObjectNode editorNode = objectMapper.createObjectNode();editorNode.put("id", "canvas");editorNode.put("resourceId", "canvas");ObjectNode stencilSetNode = objectMapper.createObjectNode();stencilSetNode.put("namespace","http://b3mn.org/stencilset/bpmn2.0#");editorNode.set("stencilset", stencilSetNode);repositoryService.addModelEditorSource(id,editorNode.toString().getBytes("utf-8"));response.sendRedirect("/modeler.html?modelId="+id);}

9.请求创建模型接口后,显示如下页面表示成功:

image.png

10.去掉Activiti Afresco的logo标题栏,并且把样式上的空白栏去掉。
1)修改modeler.html中的以下内容,注意不要把该文本删除,建议加style=”display:none”,删除后其会造成底层下的一些内容有40个像数的东西显示不出来,也可以直接删除掉。

    <div style="display:none" class="navbar navbar-fixed-top navbar-inverse" role="navigation" id="main-header"><div class="navbar-header"><a href="" ng-click="backToLanding()" class="navbar-brand"title="{{'GENERAL.MAIN-TITLE' | translate}}"><spanclass="sr-only">{{'GENERAL.MAIN-TITLE' | translate}}</span></a></div></div>

2)在editor-app/css/style-common.css中,把以下样式的padding-top部分改为0px;

.wrapper.full {padding: 0px 0px 0px 0px;overflow: hidden;max-width: 100%;min-width: 100%;
}

11.保存模型如果报错获取不到参数。(http://www.wzbjsz.cn),添加过滤器:

package com.mycompany.myapp.config;import javax.servlet.annotation.WebFilter;import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.HttpPutFormContentFilter;/**
* @author www.wzbjsz.cn
* @date 2019-01-20 15:47:39
*/
@Component
@WebFilter(urlPatterns = "/*", filterName = "putFilter")
@Order(Integer.MIN_VALUE)
public class PutFilter extends HttpPutFormContentFilter {}

七.modeler相关方法的封装。

package com.lhtc.jv.vo;import java.io.Serializable;import javax.validation.constraints.NotNull;import lombok.Data;/**
* @author www.wzbjsz.cn
* @date 2019-01-21 14:38:54
*/
@Data
public class ActModelVO implements Serializable{/****/private static final long serialVersionUID = 1L;private String id;//模型id@NotNullprivate String name;//模型名称@NotNullprivate String key;//模型标识private String description;//模型描述private String category;//模型分类}
package com.lhtc.jv.service;import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;import javax.servlet.http.HttpServletResponse;import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ModelQuery;
import org.activiti.engine.repository.ProcessDefinition;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.lhtc.jv.vo.ActModelVO;/*** 流程模型service* @author www.wzbjsz.cn* @date 2019-01-21 11:28:38*/
@Service
@Transactional(readOnly = true)
public class ActModelService {@Autowiredprivate RepositoryService repositoryService;@Autowiredprivate ObjectMapper objectMapper;/*** 创建模型* @param actModelVO* @return* @throws UnsupportedEncodingException*/@Transactional(readOnly = false)public Model createModel(ActModelVO actModelVO) throws UnsupportedEncodingException{//初始化一个空模型Model model = repositoryService.newModel();model.setKey(actModelVO.getKey());model.setName(actModelVO.getName());model.setCategory(actModelVO.getCategory());model.setVersion(Integer.parseInt(String.valueOf(repositoryService.createModelQuery().modelKey(model.getKey()).count()+1)));ObjectNode modelNode = objectMapper.createObjectNode();modelNode.put(ModelDataJsonConstants.MODEL_NAME, model.getName());modelNode.put(ModelDataJsonConstants.MODEL_REVISION, model.getVersion());modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, actModelVO.getDescription());model.setMetaInfo(modelNode.toString());repositoryService.saveModel(model);//完善ModelEditorSourceObjectNode editorNode = objectMapper.createObjectNode();editorNode.put("id", "canvas");editorNode.put("resourceId", "canvas");ObjectNode stencilSetNode = objectMapper.createObjectNode();stencilSetNode.put("namespace","http://b3mn.org/stencilset/bpmn2.0#");editorNode.set("stencilset", stencilSetNode);repositoryService.addModelEditorSource(model.getId(),editorNode.toString().getBytes("utf-8"));return model;}/*** 根据模型id查询* @param modelId 模型id* @return*/public Model getModelById(String modelId){return repositoryService.getModel(modelId);}/*** 查询模型列表* @param pageable* @return*/public Page<Model> getAllModels(Pageable pageable){ModelQuery modelQuery = repositoryService.createModelQuery().latestVersion().orderByLastUpdateTime().desc();return new PageImpl<>(modelQuery.listPage(pageable.getPageNumber()*pageable.getPageSize(), pageable.getPageSize()), pageable, modelQuery.count());}/*** 部署模型* @param modelId 模型id* @return* @throws IOException*/@Transactional(readOnly = false)public List<ProcessDefinition> deployModel(String modelId) throws IOException{Model modelData = repositoryService.getModel(modelId);BpmnJsonConverter jsonConverter = new BpmnJsonConverter();ObjectNode editorNode = (ObjectNode) new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editorNode);BpmnXMLConverter xmlConverter = new BpmnXMLConverter();byte[] bpmnBytes = xmlConverter.convertToXML(bpmnModel);ByteArrayInputStream in = new ByteArrayInputStream(bpmnBytes);Deployment deployment = repositoryService.createDeployment().name(modelData.getName()).addInputStream(modelData.getKey()+".bpmn20.xml", in).enableDuplicateFiltering().deploy();return repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).list();}/*** 删除模型* @param modelId 模型id*/@Transactional(readOnly = false)public void deleteModel(String modelId){repositoryService.deleteModel(modelId);}/*** 导出模型xml文件* @param modelId 模型id* @param response HttpServletResponse* @throws IOException*/public void exportModel(String modelId, HttpServletResponse response) throws IOException{Model modelData = repositoryService.getModel(modelId);BpmnJsonConverter jsonConverter = new BpmnJsonConverter();ObjectNode editorNode = (ObjectNode) new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editorNode);BpmnXMLConverter xmlConverter = new BpmnXMLConverter();byte[] bpmnBytes = xmlConverter.convertToXML(bpmnModel);ByteArrayInputStream in = new ByteArrayInputStream(bpmnBytes);IOUtils.copy(in, response.getOutputStream());String filename = bpmnModel.getMainProcess().getId() + ".bpmn20.xml";response.setHeader("Content-Disposition", "attachment; filename=" + java.net.URLEncoder.encode(filename, "UTF-8"));response.flushBuffer();}}
package com.lhtc.jv.web.rest.activiti;import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Optional;import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import com.lhtc.jv.service.ActModelService;
import com.lhtc.jv.vo.ActModelVO;
import com.lhtc.jv.web.rest.util.HeaderUtil;
import com.lhtc.jv.web.rest.util.PaginationUtil;import io.github.jhipster.web.util.ResponseUtil;/*** 流程模型controller* @author www.wzbjsz.cn* @date 2019-01-21 13:39:47*/
@RestController
@RequestMapping("/api")
public class ActModelResource {private final Logger log = LoggerFactory.getLogger(ActModelResource.class);private static final String ENTITY_NAME = "model";@Autowiredprivate ActModelService actModelService;/*** 创建模型* @param actModelVO* @return the ResponseEntity with status 201 (Created) and with body the new model* @throws UnsupportedEncodingException* @throws URISyntaxException if the Location URI syntax is incorrect*/@PostMapping("/models")public ResponseEntity<Model> createModel(@Valid @RequestBody ActModelVO actModelVO) throws UnsupportedEncodingException, URISyntaxException{log.debug("REST request to save Model : {}", actModelVO);Model result = actModelService.createModel(actModelVO);return ResponseEntity.created(new URI("/act/models/" + result.getId())).headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString())).body(result);}/*** 根据模型id查询* @param modelId 模型id* @return*/@GetMapping("/models/{modelId}")public ResponseEntity<Model> getModel(@PathVariable String modelId){log.debug("REST request to get Model : {}", modelId);return ResponseUtil.wrapOrNotFound(Optional.ofNullable(actModelService.getModelById(modelId)));}/*** 查询模型列表* @param pageable the pagination information* @return the ResponseEntity with status 200 (OK) and with body all models*/@GetMapping("/models")public ResponseEntity<List<Model>> getAllModels(Pageable pageable) {final Page<Model> page = actModelService.getAllModels(pageable);HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/act/models");return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);}/*** 部署模型* @param modelId 模型id* @return*/@PutMapping("/models/deploy")public ResponseEntity<Void> deployModel(@RequestBody ActModelVO actModelVO){String modelId = actModelVO.getId();log.debug("REST request to deploy Model : {}", modelId);try {List<ProcessDefinition> processDefinitions = actModelService.deployModel(modelId);if(!CollectionUtils.isEmpty(processDefinitions)){return ResponseEntity.ok().headers(HeaderUtil.createAlert("A " + ENTITY_NAME + " is deployed with identifier " + modelId, modelId)).build();}} catch (Exception e) {e.printStackTrace();}return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).headers(HeaderUtil.createFailureAlert(ENTITY_NAME, modelId,"A " + ENTITY_NAME + " failed to deploy with identifier " + modelId)).build();}/*** 删除模型* @param modelId 模型id* @return*/@DeleteMapping("/models/{modelId}")public ResponseEntity<Void> deleteModel(@PathVariable String modelId) {log.debug("REST request to delete Model: {}", modelId);actModelService.deleteModel(modelId);return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, modelId)).build();}/*** 导出模型xml文件* @param modelId 模型id* @param response HttpServletResponse* @throws IOException*/@GetMapping("/models/export")public void exportModel(@RequestParam("modelId")String modelId, HttpServletResponse response) throws IOException{actModelService.exportModel(modelId, response);}}

springboot集成activity6.0.0相关推荐

  1. 【Java从0到架构师】交错的日志系统、SpringBoot 集成日志框架

    交错的日志系统.SpringBoot 集成日志框架 交错复杂的日志系统① - 多个项目实现 SLF4J 门面 交错复杂的日志系统② - 统一底层实现为 Logback 交错复杂的日志系统③ - 统一底 ...

  2. springboot集成支付宝支付2.0

    springboot集成微信APP支付V3最新版 流程详解 创建应用 添加支付能力 接口加签 获取证书 集成支付到springboot项目 流程详解 相对于集成微信支付来说,支付宝相对简单些,支付宝对 ...

  3. SpringBoot集成Mybatis(0配置注解版)

    Mybatis初期使用比较麻烦,需要各种配置文件.实体类.dao层映射关联.还有一大推其它配置.当然Mybatis也发现了这种弊端,初期开发了generator可以根据表结构自动生成实体类.配置文件和 ...

  4. springboot集成ShardingSphere-JDBC(5.0.0-beta)

    一.背景:因为项目需要,要求对两个大表进行分表,每个月分一个表,保证单表数据不会特别大,后续查询限定时间段,保证整体查询和统计性能.作为搞java的农民工,自然选择了java契合度比较高的分库中间件: ...

  5. Jeecg-Boot 2.0.0 版本发布,基于Springboot+Vue 前后端分离快速开发平台

    Jeecg-Boot 2.0.0 版本发布,前后端分离快速开发平台 Jeecg-Boot项目简介 源码下载 升级日志 Issues解决 v1.1升级到v2.0不兼容地方 系统截图 Jeecg-Boot ...

  6. springboot新版本(2.1.0)、springcloud新版本(Greenwich.M1)实现链路追踪的一些坑

    主要问题 由于springboot新版本(2.1.0).springcloud新版本(Greenwich.M1)实现链路追踪sleuth+zipkin的一些"新特性",使得我在实现 ...

  7. springboot 2.0.0.M7之 注解 与 配置

    spring boot 注解和配置 更多干货 spring-boot系列一 之restfull api与多环境配置 springboot系列二之 日志 SpringBoot系列三之 MVC 模版引擎 ...

  8. element vue 动态单选_软件更新丨vue-element-admin 4.0.0 beta 发布,后台集成方案

    vue-element-admin 4.0.0 beta 发布了. vue-element-admin 是一个后台集成解决方案,它基于 vue 和 element.它使用了最新的前端技术栈,内置了 i ...

  9. cdh的集成phoenix安装_环境篇:Kylin3.0.1集成CDH6.2.0

    环境篇:Kylin3.0.1集成CDH6.2.0 Kylin是什么? Apache Kylin™是一个开源的.分布式的分析型数据仓库,提供Hadoop/Spark 之上的 SQL 查询接口及多维分析( ...

最新文章

  1. 用matlab求解不等方程组,Matlab:求高人指点用matlab求解非线性方程组,解出来的值不收敛,提前结束...
  2. 4.1 基础-放苹果(整数划分)
  3. c语言创建学生成绩表,C语言创建信息链表,求助
  4. Coursera自动驾驶课程第3讲:Self-Driving Hardware and Software Architectures
  5. 信息学奥赛一本通(1125:矩阵乘法)
  6. python-字符串的切片操作
  7. 园龄一年了,可还未动笔.
  8. 推动隐私计算技术,360数科提出分割式神经网络框架
  9. 联想开机壁纸存放位置
  10. l2tp 账户管理系统
  11. 电脑如何共享无线网络wifi给手机、其他电脑
  12. 庞博 上海交大计算机系,那个脱口秀的段子手——交大帅哥庞博
  13. 嘉应大学黄林鑫计算机学院,嘉应学院学子参加第十届全国大学生数学竞赛获佳绩...
  14. 槛外人观察 :语义和语用
  15. 多商家商城系统有哪些功能
  16. 怎样在群晖中安装GitLab用于项目代码管理
  17. idea pom中的依赖加载成功import报红解决方法
  18. 读书笔记15:VAIN:Attentional Multi-agent Predictive Modeling
  19. 【LuKS】Vba开发从入门到精通 =.=
  20. 多元线性回归的基础理解

热门文章

  1. 解决Chrome无法播放Songtaste的问题
  2. 修改了xiaoxia的sogou代理脚本使之能在windows下bind 127.0.0.1
  3. access对比数据_七大数据库产品测评Sqlserver完美胜出,五大理由告诉你最好选择...
  4. 学会数据分析,帮你工作效率翻倍,告别加班!
  5. .net NPOI Excel导入:时间格式2022/5/26导入变成26-5月-2022
  6. 八. 项目的立项管理
  7. easypoi 导入错误返回流_C++ I/O 流
  8. 企业开发必备的6个Spring Cloud微服务开源项目
  9. aws ec2开启bbr加速
  10. php 创建 map,golang如何创建map