当前位置: 首页 > news >正文

若依微服务整合activiti7.1.0.M6

若依微服务3.6.3版本整合activiti7(7.1.0.M6)

目前有两种办法集成activiti7

  1. 放弃activiti7新版本封装的API,使用老版本的API,这种方式只需要直接集成即可,在7.1.0.M6版本中甚至不需要去除security的依赖。不多介绍,需要的可以私聊找我。
  2. 需要使用新版本的API,那就需要集成security,需要写一点代码实现security的集成。以下详细介绍这一种方式。

步骤1

在主项目的pom中添加如下代码,其中lombok和activiti-image-generator可以不加,一定要加spring-boot-starter-security,因为不知道为什么activiti的7.1.0.M6版本中去除了security的部分依赖,导致不能直接集成security,需要添加spring-boot-starter-security才行。

			<dependency><groupId>org.activiti</groupId><artifactId>activiti-spring-boot-starter</artifactId><version>7.1.0.M6</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId><version>3.1.1</version></dependency><dependency><groupId>org.activiti</groupId><artifactId>activiti-image-generator</artifactId><version>5.22.0</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version></dependency>

步骤2

在你的activiti模块的pom文件中添加如下代码

<dependency><groupId>org.activiti</groupId><artifactId>activiti-spring-boot-starter</artifactId><exclusions><exclusion><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId></exclusion>
<!--                <exclusion>-->
<!--                    <groupId>org.activiti.core.common</groupId>-->
<!--                    <artifactId>activiti-spring-security</artifactId>-->
<!--                </exclusion>-->
<!--                <exclusion>-->
<!--                    <groupId>org.springframework.security</groupId>-->
<!--                    <artifactId>spring-security-core</artifactId>-->
<!--                </exclusion>--></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.activiti</groupId><artifactId>activiti-image-generator</artifactId><exclusions><exclusion><artifactId>activiti-bpmn-model</artifactId><groupId>org.activiti</groupId></exclusion></exclusions></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>

步骤3

添加对应的代码,目录及源码如下(security目录下的源码即可)
在这里插入图片描述
ActivitiSecurityConfig

package com.ruoyi.activiti.security.config;import com.ruoyi.activiti.security.LoginFailureHandler;
import com.ruoyi.activiti.security.LoginSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;@Configuration
@EnableWebSecurity
public class ActivitiSecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate LoginSuccessHandler loginSuccessHandler;@Autowiredprivate LoginFailureHandler loginFailureHandler;@Overrideprotected void configure(HttpSecurity http) throws Exception {
//--------------------------最精简的配置 对所有的页面都允许-----------------------------http.formLogin().loginPage("/login").loginProcessingUrl("/login")//对应ActivitiSecurityController.requireAuthentication 未登录用户进行提示 提示内容编写.successHandler(loginSuccessHandler).failureHandler(loginFailureHandler).and().authorizeRequests().anyRequest().permitAll().and().logout().permitAll().and().csrf().disable().headers().frameOptions().disable();//全部页面不验证}}

LoginUser

package com.ruoyi.activiti.security.domain;import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import java.util.Collection;
import java.util.List;
import java.util.Set;/*** 用户信息** @author ruoyi*/
public class LoginUser implements UserDetails {private static final long serialVersionUID = 1L;/*** 用户唯一标识*/private String token;/*** 用户名id*/private Long userid;/*** 用户名*/private String username;/*** 登录时间*/private Long loginTime;/*** 过期时间*/private Long expireTime;/*** 登录IP地址*/private String ipaddr;/*** 权限列表*/private Set<String> permissions;/*** 角色列表*/private Set<String> roles;/*** 用户信息*/private SysUser sysUser;private List<SimpleGrantedAuthority> authorities;public LoginUser(SysUser user, Set<String> permissions, List<SimpleGrantedAuthority> authorities) {this.sysUser = user;this.permissions = permissions;this.authorities = authorities;}public String getToken() {return token;}public void setToken(String token) {this.token = token;}public Long getUserid() {return userid;}public void setUserid(Long userid) {this.userid = userid;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return authorities;}@Overridepublic String getPassword() {
//        return sysUser.getPassword();return new BCryptPasswordEncoder().encode("111");}public String getUsername() {return sysUser.getUserName();}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}public void setUsername(String username) {this.username = username;}public Long getLoginTime() {return loginTime;}public void setLoginTime(Long loginTime) {this.loginTime = loginTime;}public Long getExpireTime() {return expireTime;}public void setExpireTime(Long expireTime) {this.expireTime = expireTime;}public String getIpaddr() {return ipaddr;}public void setIpaddr(String ipaddr) {this.ipaddr = ipaddr;}public Set<String> getPermissions() {return permissions;}public void setPermissions(Set<String> permissions) {this.permissions = permissions;}public Set<String> getRoles() {return roles;}public void setRoles(Set<String> roles) {this.roles = roles;}public SysUser getSysUser() {return sysUser;}public void setSysUser(SysUser sysUser) {this.sysUser = sysUser;}}

SysDept

package com.ruoyi.activiti.security.domain;import com.ruoyi.common.core.web.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.util.ArrayList;
import java.util.List;/*** 部门表 sys_dept** @author ruoyi*/
public class SysDept extends BaseEntity {private static final long serialVersionUID = 1L;/*** 部门ID*/private Long deptId;/*** 父部门ID*/private Long parentId;/*** 祖级列表*/private String ancestors;/*** 部门名称*/private String deptName;/*** 显示顺序*/private String orderNum;/*** 负责人*/private String leader;/*** 联系电话*/private String phone;/*** 邮箱*/private String email;/*** 部门状态:0正常,1停用*/private String status;/*** 删除标志(0代表存在 2代表删除)*/private String delFlag;/*** 父部门名称*/private String parentName;/*** 子部门*/private List<SysDept> children = new ArrayList<SysDept>();public Long getDeptId() {return deptId;}public void setDeptId(Long deptId) {this.deptId = deptId;}public Long getParentId() {return parentId;}public void setParentId(Long parentId) {this.parentId = parentId;}public String getAncestors() {return ancestors;}public void setAncestors(String ancestors) {this.ancestors = ancestors;}@NotBlank(message = "部门名称不能为空")@Size(min = 0, max = 30, message = "部门名称长度不能超过30个字符")public String getDeptName() {return deptName;}public void setDeptName(String deptName) {this.deptName = deptName;}@NotBlank(message = "显示顺序不能为空")public String getOrderNum() {return orderNum;}public void setOrderNum(String orderNum) {this.orderNum = orderNum;}public String getLeader() {return leader;}public void setLeader(String leader) {this.leader = leader;}@Size(min = 0, max = 11, message = "联系电话长度不能超过11个字符")public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}@Email(message = "邮箱格式不正确")@Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public String getStatus() {return status;}public void setStatus(String status) {this.status = status;}public String getDelFlag() {return delFlag;}public void setDelFlag(String delFlag) {this.delFlag = delFlag;}public String getParentName() {return parentName;}public void setParentName(String parentName) {this.parentName = parentName;}public List<SysDept> getChildren() {return children;}public void setChildren(List<SysDept> children) {this.children = children;}@Overridepublic String toString() {return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).append("deptId", getDeptId()).append("parentId", getParentId()).append("ancestors", getAncestors()).append("deptName", getDeptName()).append("orderNum", getOrderNum()).append("leader", getLeader()).append("phone", getPhone()).append("email", getEmail()).append("status", getStatus()).append("delFlag", getDelFlag()).append("createBy", getCreateBy()).append("createTime", getCreateTime()).append("updateBy", getUpdateBy()).append("updateTime", getUpdateTime()).toString();}
}

SysMenu

package com.ruoyi.activiti.security.domain;import com.ruoyi.common.core.web.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.ArrayList;
import java.util.List;/*** 菜单权限表 sys_menu** @author ruoyi*/
public class SysMenu extends BaseEntity {private static final long serialVersionUID = 1L;/*** 菜单ID*/private Long menuId;/*** 菜单名称*/private String menuName;/*** 父菜单名称*/private String parentName;/*** 父菜单ID*/private Long parentId;/*** 显示顺序*/private Integer orderNum;/*** 路由地址*/private String path;/*** 组件路径*/private String component;/*** 路由参数*/private String query;/*** 是否为外链(0是 1否)*/private String isFrame;/*** 是否缓存(0缓存 1不缓存)*/private String isCache;/*** 类型(M目录 C菜单 F按钮)*/private String menuType;/*** 显示状态(0显示 1隐藏)*/private String visible;/*** 菜单状态(0显示 1隐藏)*/private String status;/*** 权限字符串*/private String perms;/*** 菜单图标*/private String icon;/*** 子菜单*/private List<SysMenu> children = new ArrayList<SysMenu>();public Long getMenuId() {return menuId;}public void setMenuId(Long menuId) {this.menuId = menuId;}@NotBlank(message = "菜单名称不能为空")@Size(min = 0, max = 50, message = "菜单名称长度不能超过50个字符")public String getMenuName() {return menuName;}public void setMenuName(String menuName) {this.menuName = menuName;}public String getParentName() {return parentName;}public void setParentName(String parentName) {this.parentName = parentName;}public Long getParentId() {return parentId;}public void setParentId(Long parentId) {this.parentId = parentId;}@NotNull(message = "显示顺序不能为空")public Integer getOrderNum() {return orderNum;}public void setOrderNum(Integer orderNum) {this.orderNum = orderNum;}@Size(min = 0, max = 200, message = "路由地址不能超过200个字符")public String getPath() {return path;}public void setPath(String path) {this.path = path;}@Size(min = 0, max = 200, message = "组件路径不能超过255个字符")public String getComponent() {return component;}public void setComponent(String component) {this.component = component;}public String getQuery() {return query;}public void setQuery(String query) {this.query = query;}public String getIsFrame() {return isFrame;}public void setIsFrame(String isFrame) {this.isFrame = isFrame;}public String getIsCache() {return isCache;}public void setIsCache(String isCache) {this.isCache = isCache;}@NotBlank(message = "菜单类型不能为空")public String getMenuType() {return menuType;}public void setMenuType(String menuType) {this.menuType = menuType;}public String getVisible() {return visible;}public void setVisible(String visible) {this.visible = visible;}public String getStatus() {return status;}public void setStatus(String status) {this.status = status;}@Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符")public String getPerms() {return perms;}public void setPerms(String perms) {this.perms = perms;}public String getIcon() {return icon;}public void setIcon(String icon) {this.icon = icon;}public List<SysMenu> getChildren() {return children;}public void setChildren(List<SysMenu> children) {this.children = children;}@Overridepublic String toString() {return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).append("menuId", getMenuId()).append("menuName", getMenuName()).append("parentId", getParentId()).append("orderNum", getOrderNum()).append("path", getPath()).append("component", getComponent()).append("isFrame", getIsFrame()).append("IsCache", getIsCache()).append("menuType", getMenuType()).append("visible", getVisible()).append("status ", getStatus()).append("perms", getPerms()).append("icon", getIcon()).append("createBy", getCreateBy()).append("createTime", getCreateTime()).append("updateBy", getUpdateBy()).append("updateTime", getUpdateTime()).append("remark", getRemark()).toString();}
}

SysPost

package com.ruoyi.activiti.security.domain;import com.ruoyi.common.core.annotation.Excel;
import com.ruoyi.common.core.annotation.Excel.ColumnType;
import com.ruoyi.common.core.web.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;/*** 岗位表 sys_post** @author ruoyi*/
public class SysPost extends BaseEntity {private static final long serialVersionUID = 1L;/*** 岗位序号*/@Excel(name = "岗位序号", cellType = ColumnType.NUMERIC)private Long postId;/*** 岗位编码*/@Excel(name = "岗位编码")private String postCode;/*** 岗位名称*/@Excel(name = "岗位名称")private String postName;/*** 岗位排序*/@Excel(name = "岗位排序")private String postSort;/*** 状态(0正常 1停用)*/@Excel(name = "状态", readConverterExp = "0=正常,1=停用")private String status;/*** 用户是否存在此岗位标识 默认不存在*/private boolean flag = false;public Long getPostId() {return postId;}public void setPostId(Long postId) {this.postId = postId;}@NotBlank(message = "岗位编码不能为空")@Size(min = 0, max = 64, message = "岗位编码长度不能超过64个字符")public String getPostCode() {return postCode;}public void setPostCode(String postCode) {this.postCode = postCode;}@NotBlank(message = "岗位名称不能为空")@Size(min = 0, max = 50, message = "岗位名称长度不能超过50个字符")public String getPostName() {return postName;}public void setPostName(String postName) {this.postName = postName;}@NotBlank(message = "显示顺序不能为空")public String getPostSort() {return postSort;}public void setPostSort(String postSort) {this.postSort = postSort;}public String getStatus() {return status;}public void setStatus(String status) {this.status = status;}public boolean isFlag() {return flag;}public void setFlag(boolean flag) {this.flag = flag;}@Overridepublic String toString() {return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).append("postId", getPostId()).append("postCode", getPostCode()).append("postName", getPostName()).append("postSort", getPostSort()).append("status", getStatus()).append("createBy", getCreateBy()).append("createTime", getCreateTime()).append("updateBy", getUpdateBy()).append("updateTime", getUpdateTime()).append("remark", getRemark()).toString();}
}

SysUser

package com.ruoyi.activiti.security.domain;import com.fasterxml.jackson.annotation.JsonProperty;
import com.ruoyi.common.core.annotation.Excel;
import com.ruoyi.common.core.annotation.Excel.ColumnType;
import com.ruoyi.common.core.annotation.Excel.Type;
import com.ruoyi.common.core.annotation.Excels;
import com.ruoyi.common.core.web.domain.BaseEntity;
import com.ruoyi.common.core.xss.Xss;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.util.Date;
import java.util.List;/*** 用户对象 sys_user** @author ruoyi*/
public class SysUser extends BaseEntity {private static final long serialVersionUID = 1L;/*** 用户ID*/@Excel(name = "用户序号", cellType = ColumnType.NUMERIC, prompt = "用户编号")private Long userId;/*** 部门ID*/@Excel(name = "部门编号", type = Type.IMPORT)private Long deptId;/*** 用户账号*/@Excel(name = "登录名称")private String userName;/*** 用户昵称*/@Excel(name = "用户名称")private String nickName;/*** 用户邮箱*/@Excel(name = "用户邮箱")private String email;/*** 手机号码*/@Excel(name = "手机号码")private String phonenumber;/*** 用户性别*/@Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知")private String sex;/*** 用户头像*/private String avatar;/*** 密码*/private String password;/*** 帐号状态(0正常 1停用)*/@Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用")private String status;/*** 删除标志(0代表存在 2代表删除)*/private String delFlag;/*** 最后登录IP*/@Excel(name = "最后登录IP", type = Type.EXPORT)private String loginIp;/*** 最后登录时间*/@Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT)private Date loginDate;/*** 部门对象*/@Excels({@Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT),@Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT)})private SysDept dept;/*** 角色对象*/private List<SysRole> roles;/*** 角色组*/private Long[] roleIds;/*** 岗位组*/private Long[] postIds;/*** 角色ID*/private Long roleId;public SysUser() {}public SysUser(Long userId) {this.userId = userId;}public Long getUserId() {return userId;}public void setUserId(Long userId) {this.userId = userId;}public boolean isAdmin() {return isAdmin(this.userId);}public static boolean isAdmin(Long userId) {return userId != null && 1L == userId;}public Long getDeptId() {return deptId;}public void setDeptId(Long deptId) {this.deptId = deptId;}@Xss(message = "用户昵称不能包含脚本字符")@Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")public String getNickName() {return nickName;}public void setNickName(String nickName) {this.nickName = nickName;}@Xss(message = "用户账号不能包含脚本字符")@NotBlank(message = "用户账号不能为空")@Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}@Email(message = "邮箱格式不正确")@Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}@Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符")public String getPhonenumber() {return phonenumber;}public void setPhonenumber(String phonenumber) {this.phonenumber = phonenumber;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public String getAvatar() {return avatar;}public void setAvatar(String avatar) {this.avatar = avatar;}@JsonPropertypublic String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getStatus() {return status;}public void setStatus(String status) {this.status = status;}public String getDelFlag() {return delFlag;}public void setDelFlag(String delFlag) {this.delFlag = delFlag;}public String getLoginIp() {return loginIp;}public void setLoginIp(String loginIp) {this.loginIp = loginIp;}public Date getLoginDate() {return loginDate;}public void setLoginDate(Date loginDate) {this.loginDate = loginDate;}public SysDept getDept() {return dept;}public void setDept(SysDept dept) {this.dept = dept;}public List<SysRole> getRoles() {return roles;}public void setRoles(List<SysRole> roles) {this.roles = roles;}public Long[] getRoleIds() {return roleIds;}public void setRoleIds(Long[] roleIds) {this.roleIds = roleIds;}public Long[] getPostIds() {return postIds;}public void setPostIds(Long[] postIds) {this.postIds = postIds;}public Long getRoleId() {return roleId;}public void setRoleId(Long roleId) {this.roleId = roleId;}@Overridepublic String toString() {return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).append("userId", getUserId()).append("deptId", getDeptId()).append("userName", getUserName()).append("nickName", getNickName()).append("email", getEmail()).append("phonenumber", getPhonenumber()).append("sex", getSex()).append("avatar", getAvatar()).append("password", getPassword()).append("status", getStatus()).append("delFlag", getDelFlag()).append("loginIp", getLoginIp()).append("loginDate", getLoginDate()).append("createBy", getCreateBy()).append("createTime", getCreateTime()).append("updateBy", getUpdateBy()).append("updateTime", getUpdateTime()).append("remark", getRemark()).append("dept", getDept()).toString();}
}

SysMenuMapper

package com.ruoyi.activiti.security.mapper;import org.apache.ibatis.annotations.Mapper;import java.util.List;/*** 菜单表 数据层** @author ruoyi*/
@Mapper
public interface SysMenuMapper {/*** 根据用户ID查询权限** @param userId 用户ID* @return 权限列表*/public List<String> selectMenuPermsByUserId(Long userId);}

SysPostMapper

package com.ruoyi.activiti.security.mapper;import org.apache.ibatis.annotations.Mapper;import java.util.Set;/*** 岗位信息 数据层** @author ruoyi*/
@Mapper
public interface SysPostMapper {/*** 根据用户ID获取岗位选择框列表** @param userId 用户ID* @return 选中岗位ID列表*/public Set<String> selectPostCodeByUserId(Long userId);}

SysUserMapper

package com.ruoyi.activiti.security.mapper;import com.ruoyi.activiti.security.domain.SysUser;
import org.apache.ibatis.annotations.Mapper;import java.util.List;/*** 用户表 数据层** @author ruoyi*/
@Mapper
public interface SysUserMapper {//    public List<String> selectUserNameByPostCodeAndDeptId(@Param("postCode")String postCode,@Param("deptId") String deptId);public List<String> selectUserNameByPostCodeAndDeptId(String postCode, Long deptId);/*** 通过用户名查询用户** @param userName 用户名* @return 用户对象信息*/public SysUser selectUserByUserName(String userName);
}

MyUserDetailsService

package com.ruoyi.activiti.security.service.impl;import com.ruoyi.activiti.security.domain.LoginUser;
import com.ruoyi.common.core.enums.UserStatus;
import com.ruoyi.common.core.exception.base.BaseException;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.activiti.security.domain.SysUser;
import com.ruoyi.activiti.security.service.ISysPermissionService;
import com.ruoyi.activiti.security.service.ISysPostService;
import com.ruoyi.activiti.security.service.ISysUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;@Component
public class MyUserDetailsService implements UserDetailsService {private Logger logger = LoggerFactory.getLogger(getClass());private static final Logger log = LoggerFactory.getLogger(MyUserDetailsService.class);@Autowiredprivate ISysUserService userService;@Autowiredprivate ISysPostService sysPostService;@Autowiredprivate ISysPermissionService permissionService;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {SysUser user = userService.selectUserByUserName(username);if (StringUtils.isNull(user)) {log.info("登录用户:{} 不存在.", username);throw new UsernameNotFoundException("登录用户:" + username + " 不存在");} else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {log.info("登录用户:{} 已被删除.", username);throw new BaseException("对不起,您的账号:" + username + " 已被删除");} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {log.info("登录用户:{} 已被停用.", username);throw new BaseException("对不起,您的账号:" + username + " 已停用");}return createLoginUser(user);}public UserDetails createLoginUser(SysUser user) {Set<String> postCode = sysPostService.selectPostCodeByUserId(user.getUserId());postCode = postCode.parallelStream().map(s -> "GROUP_" + s).collect(Collectors.toSet());postCode.add("ROLE_ACTIVITI_USER");List<SimpleGrantedAuthority> collect = postCode.stream().map(s -> new SimpleGrantedAuthority(s)).collect(Collectors.toList());return new LoginUser(user, permissionService.getMenuPermission(user.getUserId()), collect);}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}}

SysMenuServiceImpl

package com.ruoyi.activiti.security.service.impl;import com.ruoyi.activiti.security.service.ISysMenuService;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.activiti.security.mapper.SysMenuMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;/*** 菜单 业务层处理** @author ruoyi*/
@Service
public class SysMenuServiceImpl implements ISysMenuService {public static final String PREMISSION_STRING = "perms[\"{0}\"]";@Autowiredprivate SysMenuMapper menuMapper;/*** 根据用户ID查询权限** @param userId 用户ID* @return 权限列表*/@Overridepublic Set<String> selectMenuPermsByUserId(Long userId) {List<String> perms = menuMapper.selectMenuPermsByUserId(userId);Set<String> permsSet = new HashSet<>();for (String perm : perms) {if (StringUtils.isNotEmpty(perm)) {permsSet.addAll(Arrays.asList(perm.trim().split(",")));}}return permsSet;}}

SysPermissionServiceImpl

package com.ruoyi.activiti.security.service.impl;import com.ruoyi.activiti.security.service.ISysMenuService;
import com.ruoyi.activiti.security.service.ISysPermissionService;
import com.ruoyi.activiti.security.domain.SysUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.HashSet;
import java.util.Set;@Service
public class SysPermissionServiceImpl implements ISysPermissionService {@Autowiredprivate ISysMenuService menuService;/*** 获取菜单数据权限** @param userId 用户Id* @return 菜单权限信息*/@Overridepublic Set<String> getMenuPermission(Long userId) {Set<String> perms = new HashSet<String>();// 管理员拥有所有权限if (SysUser.isAdmin(userId)) {perms.add("*:*:*");} else {perms.addAll(menuService.selectMenuPermsByUserId(userId));}return perms;}
}

SysPostServiceImpl

package com.ruoyi.activiti.security.service.impl;import com.ruoyi.activiti.security.service.ISysPostService;
import com.ruoyi.activiti.security.mapper.SysPostMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.Set;/*** 岗位信息 服务层处理** @author ruoyi*/
@Service
public class SysPostServiceImpl implements ISysPostService {@Autowiredprivate SysPostMapper postMapper;/*** 根据用户ID获取岗位选择框列表** @param userId 用户ID* @return 选中岗位ID列表*/@Overridepublic Set<String> selectPostCodeByUserId(Long userId) {return postMapper.selectPostCodeByUserId(userId);}}

SysUserServiceImpl

package com.ruoyi.activiti.security.service.impl;import com.ruoyi.activiti.security.service.ISysUserService;
import com.ruoyi.activiti.security.domain.SysUser;
import com.ruoyi.activiti.security.mapper.SysUserMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;/*** 用户 业务层处理** @author ruoyi*/
@Service
public class SysUserServiceImpl implements ISysUserService {private static final Logger log = LoggerFactory.getLogger(SysUserServiceImpl.class);@Autowiredprivate SysUserMapper userMapper;public List<String> selectUserNameByPostCodeAndDeptId(String postCode, Long deptId) {return userMapper.selectUserNameByPostCodeAndDeptId(postCode, deptId);}/*** 通过用户名查询用户** @param userName 用户名* @return 用户对象信息*/@Overridepublic SysUser selectUserByUserName(String userName) {return userMapper.selectUserByUserName(userName);}
}

ISysMenuService

package com.ruoyi.activiti.security.service;import java.util.Set;/*** 菜单 业务层** @author ruoyi*/
public interface ISysMenuService {/*** 根据用户ID查询权限** @param userId 用户ID* @return 权限列表*/public Set<String> selectMenuPermsByUserId(Long userId);}

ISysPermissionService

package com.ruoyi.activiti.security.service;import java.util.Set;public interface ISysPermissionService {/*** 获取菜单数据权限** @param userId 用户Id* @return 菜单权限信息*/public Set<String> getMenuPermission(Long userId);
}

ISysPostService

package com.ruoyi.activiti.security.service;import java.util.Set;/*** 岗位信息 服务层** @author ruoyi*/
public interface ISysPostService {/*** 根据用户ID获取岗位选择框列表** @param userId 用户ID* @return 选中岗位ID列表*/public Set<String> selectPostCodeByUserId(Long userId);}

ISysUserService

package com.ruoyi.activiti.security.service;import com.ruoyi.activiti.security.domain.SysUser;import java.util.List;/*** 用户 业务层** @author ruoyi*/
public interface ISysUserService {public List<String> selectUserNameByPostCodeAndDeptId(String postCode, Long deptId);/*** 通过用户名查询用户** @param userName 用户名* @return 用户对象信息*/public SysUser selectUserByUserName(String userName);
}

ActivitiSecurityUtil

package com.ruoyi.activiti.security.util;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;import java.util.Collection;@Component
public class ActivitiSecurityUtil {private Logger logger = LoggerFactory.getLogger(ActivitiSecurityUtil.class);@Autowiredprivate UserDetailsService userDetailsService;public void logInAs(String username) {UserDetails user = userDetailsService.loadUserByUsername(username);if (user == null) {throw new IllegalStateException("User " + username + " doesn't exist, please provide a valid user");}logger.info("> Logged in as: " + username);SecurityContextHolder.setContext(new SecurityContextImpl(new Authentication() {@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return user.getAuthorities();}@Overridepublic Object getCredentials() {return user.getPassword();}@Overridepublic Object getDetails() {return user;}@Overridepublic Object getPrincipal() {return user;}@Overridepublic boolean isAuthenticated() {return true;}@Overridepublic void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {}@Overridepublic String getName() {return user.getUsername();}}));org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username);}
}

GlobalConfig

package com.ruoyi.activiti.security.util;public class GlobalConfig {/*** 测试场景*/public static final Boolean Test = false;//windows路径
//    public static final String BPMN_PathMapping = "file:D:\\WangJianIDEA_Test\\activiti-imooc\\src\\main\\resources\\resources\\bpmn\\";//Liunx路径public static final String BPMN_PathMapping = "file:/opt/app/activitiweb/upload/";public enum ResponseCode {SUCCESS(0, "成功"),ERROR(1, "错误");private final int code;private final String desc;ResponseCode(int code, String desc) {this.code = code;this.desc = desc;}public int getCode() {return code;}public String getDesc() {return desc;}}}

LoginFailureHandler

package com.ruoyi.activiti.security;import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.activiti.security.util.GlobalConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@Component("loginFailureHandler")
public class LoginFailureHandler implements AuthenticationFailureHandler {private Logger logger = LoggerFactory.getLogger(getClass());@Autowiredprivate ObjectMapper objectMapper;@Overridepublic void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {logger.info("登录失败");httpServletResponse.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());httpServletResponse.setContentType("application/json;charset=UTF-8");httpServletResponse.getWriter().write(objectMapper.writeValueAsString(AjaxResult.success(GlobalConfig.ResponseCode.ERROR.getDesc(),"登录失败:" + e.getMessage())));}
}

LoginSuccessHandler

package com.ruoyi.activiti.security;import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.activiti.security.util.GlobalConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@Component("loginSuccessHandler")
public class LoginSuccessHandler implements AuthenticationSuccessHandler {private Logger logger = LoggerFactory.getLogger(getClass());@Autowiredprivate ObjectMapper objectMapper;@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException {logger.info("登录成功1");}@Overridepublic void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {logger.info("登录成功2");httpServletResponse.setContentType("application/json;charset=UTF-8");httpServletResponse.getWriter().write(objectMapper.writeValueAsString(AjaxResult.success(GlobalConfig.ResponseCode.SUCCESS.getDesc(),authentication.getName())));}
}

SysMenuMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.activiti.security.mapper.SysMenuMapper"><resultMap type="SysMenu" id="SysMenuResult"><id     property="menuId"         column="menu_id"        /><result property="menuName"       column="menu_name"      /><result property="parentName"     column="parent_name"    /><result property="parentId"       column="parent_id"      /><result property="orderNum"       column="order_num"      /><result property="path"           column="path"           /><result property="component"      column="component"      /><result property="query"          column="query"          /><result property="isFrame"        column="is_frame"       /><result property="isCache"        column="is_cache"       /><result property="menuType"       column="menu_type"      /><result property="visible"        column="visible"        /><result property="status"         column="status"         /><result property="perms"          column="perms"          /><result property="icon"           column="icon"           /><result property="createBy"       column="create_by"      /><result property="createTime"     column="create_time"    /><result property="updateTime"     column="update_time"    /><result property="updateBy"       column="update_by"      /><result property="remark"         column="remark"         /></resultMap><sql id="selectMenuVo">select menu_id, menu_name, parent_id, order_num, path, component, `query`, is_frame, is_cache, menu_type, visible, status, ifnull(perms,'') as perms, icon, create_time from sys_menu</sql><select id="selectMenuPermsByUserId" parameterType="Long" resultType="String">select distinct m.permsfrom sys_menu mleft join sys_role_menu rm on m.menu_id = rm.menu_idleft join sys_user_role ur on rm.role_id = ur.role_idleft join sys_role r on r.role_id = ur.role_idwhere m.status = '0' and r.status = '0' and ur.user_id = #{userId}</select></mapper> 

SysPostMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.activiti.security.mapper.SysPostMapper"><resultMap type="SysPost" id="SysPostResult"><id     property="postId"        column="post_id"       /><result property="postCode"      column="post_code"     /><result property="postName"      column="post_name"     /><result property="postSort"      column="post_sort"     /><result property="status"        column="status"        /><result property="createBy"      column="create_by"     /><result property="createTime"    column="create_time"   /><result property="updateBy"      column="update_by"     /><result property="updateTime"    column="update_time"   /><result property="remark"        column="remark"        /></resultMap><sql id="selectPostVo">select post_id, post_code, post_name, post_sort, status, create_by, create_time, remark from sys_post</sql><select id="selectPostCodeByUserId" parameterType="Long" resultType="String">select p.post_codefrom sys_post pleft join sys_user_post up on up.post_id = p.post_idleft join sys_user u on u.user_id = up.user_idwhere u.user_id = #{userId}</select></mapper> 

SysUserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.activiti.security.mapper.SysUserMapper"><!--	<select id="selectUserNameByPostCodeAndDeptId"  parameterType="String" resultType="String">-->
<!--        		SELECT user_name FROM  sys_post p-->
<!--        left join sys_user_post up on p.post_id = up.post_id-->
<!--        left join sys_user u on up.user_id= u.user_id-->
<!--        where post_code=#{postCode} and dept_id=#{deptId}-->
<!--	</select>--><resultMap type="SysUser" id="SysUserResult"><id     property="userId"       column="user_id"      /><result property="deptId"       column="dept_id"      /><result property="userName"     column="user_name"    /><result property="nickName"     column="nick_name"    /><result property="email"        column="email"        /><result property="phonenumber"  column="phonenumber"  /><result property="sex"          column="sex"          /><result property="avatar"       column="avatar"       /><result property="password"     column="password"     /><result property="status"       column="status"       /><result property="delFlag"      column="del_flag"     /><result property="loginIp"      column="login_ip"     /><result property="loginDate"    column="login_date"   /><result property="createBy"     column="create_by"    /><result property="createTime"   column="create_time"  /><result property="updateBy"     column="update_by"    /><result property="updateTime"   column="update_time"  /><result property="remark"       column="remark"       /><association property="dept"    column="dept_id" javaType="SysDept" resultMap="deptResult" /><collection  property="roles"   javaType="java.util.List"           resultMap="RoleResult" /></resultMap><resultMap id="deptResult" type="SysDept"><id     property="deptId"    column="dept_id"     /><result property="parentId"  column="parent_id"   /><result property="deptName"  column="dept_name"   /><result property="ancestors" column="ancestors"   /><result property="orderNum"  column="order_num"   /><result property="leader"    column="leader"      /><result property="status"    column="dept_status" /></resultMap><resultMap id="RoleResult" type="SysRole"><id     property="roleId"       column="role_id"        /><result property="roleName"     column="role_name"      /><result property="roleKey"      column="role_key"       /><result property="roleSort"     column="role_sort"      /><result property="dataScope"     column="data_scope"    /><result property="status"       column="role_status"    /></resultMap><sql id="selectUserVo">select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark,d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status,r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_statusfrom sys_user uleft join sys_dept d on u.dept_id = d.dept_idleft join sys_user_role ur on u.user_id = ur.user_idleft join sys_role r on r.role_id = ur.role_id</sql><select id="selectUserNameByPostCodeAndDeptId" resultType="String">SELECT user_name FROM  sys_post pleft join sys_user_post up on p.post_id = up.post_idleft join sys_user u on up.user_id= u.user_idwhere post_code=#{param1} and dept_id=#{param2}</select><select id="selectUserByUserName" parameterType="String" resultMap="SysUserResult"><include refid="selectUserVo"/>where u.user_name = #{userName}</select></mapper> 

以上就是全部代码了

需要注意的是

  1. 在整合的时候写的nacos配置网关文件中,不要写StripPrefix=1,否则会删除一节访问路径,导致404找不到接口的情况,这个问题搞了我好几天
  2. 写了这么多代码,其实大体思路就是整合了security后,在需要使用activiti新版本api的时候,使用activitiSecurityUtil.logInAs(SecurityUtils.getUsername());这一句来进行登录,并给与ROLE_ACTIVITI_USER权限即可。

相关文章:

若依微服务整合activiti7.1.0.M6

若依微服务3.6.3版本整合activiti7&#xff08;7.1.0.M6&#xff09; 目前有两种办法集成activiti7 放弃activiti7新版本封装的API&#xff0c;使用老版本的API&#xff0c;这种方式只需要直接集成即可&#xff0c;在7.1.0.M6版本中甚至不需要去除security的依赖。不多介绍&a…...

Ubuntu 下安装软件,卸载,查看已经安装的软件

参考网址&#xff1a;http://wiki.ubuntu.org.cn/UbuntuSkills 一般的安装程序用三种&#xff1a; .deb 和.rpm 这两种安装文件 .bundle 这是二进制的安装文件  而 tar.gz 这类的只是压缩包&#xff08;相当于 .rar,.zip 压缩包一样&#xff09;,如果此类文件是程序的话&a…...

微信小程序导入微信地址

获取用户收货地址。调起用户编辑收货地址原生界面&#xff0c;并在编辑完成后返回用户选择的地址。 1&#xff1a;原生微信小程序接口使用API&#xff1a;wx.chooseAddress(OBJECT) wx.chooseAddress({success (res) {console.log(res.userName)console.log(res.postalCode)c…...

如何在Debian中配置代理服务器?

开始搭建代理服务器 首先我参考如下文章进行搭建代理服务器&#xff0c;步骤每一个命令都执行过报了各种错&#xff0c;找了博客 目前尚未开始&#xff0c;我已经知道我的路很长&#xff0c;很难走呀&#xff0c;加油&#xff0c;go&#xff01;go&#xff01;go&#xff01; …...

在外远程NAS群晖Drive - 群晖Drive挂载电脑磁盘同步备份【无需公网IP】

文章目录 前言1.群晖Synology Drive套件的安装1.1 安装Synology Drive套件1.2 设置Synology Drive套件1.3 局域网内电脑测试和使用 2.使用cpolar远程访问内网Synology Drive2.1 Cpolar云端设置2.2 Cpolar本地设置2.3 测试和使用 3. 结语 前言 群晖作为专业的数据存储中心&…...

[SQL挖掘机] - 标量子查询

介绍: 标量子查询&#xff08;Scalar Subquery&#xff09;是一种特殊类型的子查询&#xff0c;它返回单个值作为结果&#xff0c;而不是结果集。标量子查询通常嵌套在另一个查询的选择列表、条件或表达式中&#xff0c;并提供单个值来完成计算、比较或作为查询结果的一部分。…...

MTK 进META的两种方式

1. Preloader进meta&#xff1a; 开机情况下&#xff1a;先发adb reboot meta进入Preloader&#xff0c;然后再进META 2. 开机后直接进meta...

AutoSAR系列讲解(实践篇)9.2-信息发送的Filter机制

再强调一遍哈,这几节的内容大家看不懂没关系。都属于不常用的知识,仅作了解,假如用到了可以再挖出来看看。还有一点,很多的英文不太好翻译,比如这里的Filter,翻译成滤波,筛选我感觉都不太贴切,干脆就直接叫Filter了,之后应该会出现类似的英文,博主尽量想办法让大家理…...

JVM详解(超详细)

目录 JVM 的简介 JVM 执行流程 JVM 运行时数据区 由五部分组成 JVM 的类加载机制 类加载的过程(五个) 双亲委派模型 类加载器 双亲委派模型的优点 JVM 中的垃圾回收策略 GC GC 中主要分成两个阶段 死亡对象的判断算法 引用计数算法 可达性分析算法 垃圾回收算…...

Vue学习Day3——生命周期\组件化

一、Vue生命周期 Vue生命周期&#xff1a;就是一个Vue实例从创建 到 销毁 的整个过程。 生命周期四个阶段&#xff1a;① 创建 ② 挂载 ③ 更新 ④ 销毁 1.创建阶段&#xff1a;创建响应式数据 2.挂载阶段&#xff1a;渲染模板 3.更新阶段&#xff1a;修改数据&#xff0c;更…...

Rust vs Go:常用语法对比(八)

题目来自 Golang vs. Rust: Which Programming Language To Choose in 2023?[1] 141. Iterate in sequence over two lists Iterate in sequence over the elements of the list items1 then items2. For each iteration print the element. 依次迭代两个列表 依次迭代列表项1…...

pytorch学习-线性神经网络——softmax回归+损失函数+图片分类数据集

1.softmax回归 Softmax回归&#xff08;Softmax Regression&#xff09;是一种常见的多分类模型&#xff0c;可以用于将输入变量映射到多个类别的概率分布中。softmax回归是机器学习中非常重要并且经典的模型&#xff0c;虽然叫回归&#xff0c;实际上是一个分类问题 1.1分类与…...

Docker compose(容器编排)

Docker compose&#xff08;容器编排&#xff09; 一、安装Docker compose 1.安装Docker compose Docker Compose 环境安装 Docker Compose 是 Docker 的独立产品&#xff0c;因此需要安装 Docker 之后在单独安装 Docker Compose#下载 curl -L https://github.com/docker/co…...

xmind latex【记录备忘】

xmind latex 换行 换行必须要有\begin{align}和\end{align}&#xff0c;此时再在里面用\才能换行&#xff0c;如果只写112\224是不能换行的...

RocketMQ(1.NameServer源码)

NameServer功能简述 主要功能如下 服务注册与发现&#xff1a;Nameserver扮演了RocketMQ集群中服务注册中心的角色。当RocketMQ中的Broker、Producer和Consumer启动时&#xff0c;它们会向Nameserver注册自己的网络地址和角色信息。Nameserver维护着集群中所有活跃实例的信息…...

责任链vs金融登录

金融app相对普通app而言&#xff0c;出于安全考虑&#xff0c;其安全校验方式比较多&#xff0c;以某些银行app为例&#xff0c;手机号登录成功后&#xff0c;会增加指纹、手势、OCR人脸等验证&#xff01;这些安全项的校验&#xff0c;会根据用户的风险等级有不同的校验优先级…...

通过VIOOVI,了解联合作业分析的意义和目标!

现如今企业的主流生产模式就是流水线生产&#xff0c;一道工序结束后&#xff0c;紧接着开展下一项工序&#xff0c;这种作业模式可以以一种比较高效的方式缩减生产时间。尽管流水作业的效率已经够高的了&#xff0c;但是各个工序之间如果衔接不到位的话&#xff0c;会造成生产…...

清洁机器人规划控制方案

清洁机器人规划控制方案 作者联系方式Forrest709335543qq.com 文章目录 清洁机器人规划控制方案方案简介方案设计模块链路坐标变换算法框架 功能设计定点自主导航固定路线清洁区域覆盖清洁贴边沿墙清洁自主返航回充 仿真测试仿真测试准备定点自主导航测试固定路线清洁测试区域…...

设计模式 - 工厂模式

一、 简单工厂&#xff08;Simple Factory Pattern&#xff09; 1、概念 一个工厂对象决定创建出哪一种产品类的实力&#xff0c;但不属于GOF23种设计模式。 简单工厂适用于工厂类负责创建的对象较少的场景&#xff0c;且客户端只需要传入工厂类的参数&#xff0c;对于如何创…...

elementUI this.$confirm 文字大小样式

dangerouslyUseHTMLString:true // message部分 以html片段处理 customClass //MessageBox 的自定义类名 整个comfirm框自定义类名 cancelButtonClass // 取消按钮的自定义类名 confirmButtonClass // 确定按钮的自定义类名<style> .addcomfirm{width: 500px; } .a…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

【Python】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

MFC 抛体运动模拟:常见问题解决与界面美化

在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...

Docker拉取MySQL后数据库连接失败的解决方案

在使用Docker部署MySQL时&#xff0c;拉取并启动容器后&#xff0c;有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致&#xff0c;包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因&#xff0c;并提供解决方案。 一、确认MySQL容器的运行状态 …...

游戏开发中常见的战斗数值英文缩写对照表

游戏开发中常见的战斗数值英文缩写对照表 基础属性&#xff08;Basic Attributes&#xff09; 缩写英文全称中文释义常见使用场景HPHit Points / Health Points生命值角色生存状态MPMana Points / Magic Points魔法值技能释放资源SPStamina Points体力值动作消耗资源APAction…...