培训
组织机构、岗位、用户、角色配置
组织机构的变更都在 控制台->组织架构
服务端
提供一些常用的接口
前端
提供单选的组件、提供选择组织架构选择器组件
菜单及权限配置
菜单配置
菜单配置在 控制台 ->应用->自定义菜单
菜单分为web、app菜单两种
菜单权限配置,菜单的权限配置现在是通过角色来配置的,角色关联人、关联菜单
权限配置
关联员工:角色关联员工
菜单权限:角色关联菜单
功能权限:角色关联套件定义的用户组
接口权限:使用注解 @PreAuthorize(“@pms.hasSuiteRoles(‘套件code:用户组:用户组权限’)”)
接口权限
配置用户组和业务权限
java代码
@ApiModelProperty("需要权限")
@GetMapping("/must/perm")
@PreAuthorize("@pms.hasSuiteRoles('cn.flyrise.test.a:work:select')")
public Reply<?> mustPerm() {
return Reply.success("有权限");
}
无权限返回信息
{
"code": "999",
"data": null,
"time": 1657073219861,
"msg": "服务异常,请联系管理员",
"annex": {
"applicationName": "pai-hello",
"ExceptionClassName": "org.springframework.security.access.AccessDeniedException",
"errorMsg": "不允许访问"
},
"success": false
}
消息通知
消息模版配置
消息模版是在开发者平台配置的
位置:套件->能力->消息服务
消息类型目前支持:站内消息(pc),app推送(极光),短信(阿里、华为、岭南大数据、漫道),邮件(smtp)
短信默认是阿里大鱼(比较麻烦需要审核)
消息支持动态参数配置 通过配置{param},发送参数传递param参数就能实现动态替换
添加消息后,编辑进入模版管理
设置自定义消息参数
发送代码测试
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class McTest {
private static final transient Logger logger = LoggerFactory.getLogger(McTest.class);
private MockMvc mvc;
@Autowired
private WebApplicationContext applicationContext; // 注入WebApplicationContext
@Before
public void setUp() {
this.mvc = MockMvcBuilders.webAppContextSetup(applicationContext).build();
}
@Resource
private McTemplateService mcTemplateService;
@Test
@WithMockOAuth2User(username = "15918411916", password = "123456")
public void sendMcTest() {
LoginUser loginUser = SecurityUtils.getLoginUser();
//开发者后台创建的消息编号
String moban = "MP_10000256";
String title = "柬媒评论:中国不应是唯一的新冠溯源目标";
String content = "近日,,新冠病毒防范疫情被政治化。……";
InnerUserBody innerUserBody = InnerUserBody.builder()
.categoryCode(moban)
.enterpriseId(loginUser.getEntId())
.sendUserId(loginUser.getUserId())
.sendUserName(loginUser.getStaffName())
.receiveUserType("user")
.receiveUserIds(new String[]{loginUser.getUserId()})
.pageH5Id("H5Id")
.param("title", title)
.param("context", content)
.build();
Reply reply = mcTemplateService.sendInnerUser(innerUserBody);
logger.info(JSONUtil.toJsonStr(reply));
}
}
短信验证码
pai.sms.enable=false,默认值是true,false的时候关闭短信的发送
pai.sms.fixed-code,默认值是1234,使用verificationGeneratorHelper工具类获取随机的验证码
当enable为false的时候,验证码是当前设置的fixedCode
配置文件:application.yml or nacos->pai-xxx-xx.yaml
配置开关,默认值
pai:
sms:
enable: true
fixed-code: 1234
获取验证码
//注入工具类
@Resource
private VerificationGeneratorHelper verificationGeneratorHelper;
//获取数字的验证码
String code = verificationGeneratorHelper.getNumberCode();
String code = verificationGeneratorHelper.getNumberCode(Integer);
//获取字符的随机验证码
String code = verificationGeneratorHelper.getCode();
String code = verificationGeneratorHelper.getCode(Integer);
Demo
public interface ISmsService {
/**
* 发送短信验证码
*
* @param smsKey 模板key
* @param phone 手机号
* @return
*/
boolean sendValidateCode(String smsKey, String phone);
/**
* 发送短信验证码
*
* @param smsKey 模板key
* @param phone 手机号
* @param map 参数
* @return
*/
boolean sendValidateCode(String smsKey, String phone, Map<String, String> map);
/**
* 发送短信验证码
*
* @param smsKey 模板key
* @param phone 手机号
* @param map 参数
* @return
*/
boolean sendSms(String smsKey, String phone, Map<String, String> map);
/**
* 校验验证码
*
* @param phone
* @param code
* @return
*/
boolean validateCode(String smsKey, String phone, String code);
}
@Service
public class SmsServiceImpl implements ISmsService {
private static final Logger log = LoggerFactory.getLogger(SmsServiceImpl.class);
@Autowired
private RedisService redisService;
@Resource
private McService mcService;
@Resource
private VerificationGeneratorHelper verificationGeneratorHelper;
@Override
public boolean sendSms(String smsKey, String phone, Map<String, String> map) {
SmsOuterUser smsOuterUser = new SmsOuterUser();
smsOuterUser.setParam(map);
smsOuterUser.setTemplateCode(smsKey);
smsOuterUser.setReceiveMobiles(new String[]{phone});
smsOuterUser.setBusinessSystemId("console");
smsOuterUser.setReceiveUserType("staff");
FeignMessage msg = mcService.sendOuterUserSms(smsOuterUser);
return true;
}
private FeignMessage sendSms(String templateCode, String phone, String code) {
Map<String, String> map = new HashMap<>();
map.put("code", code);
SmsOuterUser smsOuterUser = new SmsOuterUser();
smsOuterUser.setParam(map);
smsOuterUser.setTemplateCode(templateCode);
smsOuterUser.setReceiveMobiles(new String[]{phone});
smsOuterUser.setBusinessSystemId("console");
smsOuterUser.setReceiveUserType("staff");
FeignMessage msg = mcService.sendOuterUserSms(smsOuterUser);
return msg;
}
@Override
public boolean sendValidateCode(String templateCode, String phone) {
String cacheKey = CacheConstants.SMS + templateCode + CacheConstants.COLON + phone;
//获取数字的验证码
String code = verificationGeneratorHelper.getNumberCode();
FeignMessage smsMsg = sendSms(templateCode, phone, code);
if (!smsMsg.isOk()) {
String msg = smsMsg.getMsg();
String data = "";
if (smsMsg.getData() != null) {
data = smsMsg.getData().toString();
}
throw new ConsoleBizException(BusinessErrors.ERR_1014, msg, data);
}
log.info("发送短信 phone:{} code:{}", phone, code);
int EXPIRATION = 5;
redisService.setCacheObject(cacheKey, code, EXPIRATION, TimeUnit.MINUTES);
return true;
}
@Override
public boolean sendValidateCode(String templateCode, String phone, Map<String, String> map) {
String cacheKey = CacheConstants.SMS + templateCode + CacheConstants.COLON + phone;
//获取数字的验证码
String code = verificationGeneratorHelper.getNumberCode();
map.put("code", code);
boolean sendValidateCode = sendSms(templateCode, phone, map);
if (!sendValidateCode) {
throw new ConsoleBizException("500", "服务异常,请稍后尝试");
}
log.info("发送短信 phone:{} code:{}", phone, code);
int EXPIRATION = 5;
redisService.setCacheObject(cacheKey, code, EXPIRATION, TimeUnit.MINUTES);
return true;
}
@Override
public boolean validateCode(String templateCode, String phone, String code) {
String cacheKey = CacheConstants.SMS + templateCode + CacheConstants.COLON + phone;
String redisRegisterCode = redisService.getCacheObject(cacheKey);
if (StrUtil.isNotEmpty(redisRegisterCode)) {
if (code.equals(redisRegisterCode)) {
return true;
}
}
return false;
}
}
流程开发
开发文档
表单如何自定义数据源
无,具体需求不明确
工单开发
如果无权限访问,请联系管理员
工单 - WEB开发
工单 - APP开发
工单 - 服务端开发
中间件配置及开发
oss
后端使用
在nacos中添加配置
oss:
appId: xiwan-sIOuajfe
secretKey: rxkg3dll8eqsjvph
在pom.xml
中引入包
<dependency>
<groupId>cn.flyrise</groupId>
<artifactId>pai-common-oss</artifactId>
</dependency>
新增一个测试类
import cn.flyrise.common.oss.OssClient;
import cn.flyrise.common.oss.domain.FileObject;
import cn.flyrise.pai.xwservicetest.Application;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.CharSequenceUtil;
import feign.Request;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
import java.io.File;
import java.util.List;
import java.util.concurrent.TimeUnit;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class OssTest {
@Resource
private OssClient client;
private String attachId;
private String copyTargetAttachId;
private String fileCode;
@Test
public void run() {
saveOneFile();
listAttach(attachId);
appendFile();
getAndWriteFile();
deleteFileCode();
copyAttach();
deleteAttach();
}
/**
* 保存一张图片
*/
public void saveOneFile() {
System.out.println("---保存一张图片---");
// 上传者,仅用作记录,正常应该从token中获取用户信息
String uploadBy = "西湾";
File file = FileUtil.file("D:\\home\\翠亨\\所有权限角色.png");
FileObject fileObject = client.save(file, uploadBy);
System.out.println(fileObject);
attachId = fileObject.getAttachId();
}
/**
* 根据附件ID查询附件下的文件
*/
public void listAttach(String attachId) {
System.out.println(CharSequenceUtil.format("---查询附件{}下的文件---", attachId));
List<FileObject> list = client.list(attachId);
System.out.println(list);
}
public void copyAttach() {
System.out.println("---复制文件---");
copyTargetAttachId = client.copy(attachId, null);
System.out.println("---查询复制后的附件下的文件---");
listAttach(copyTargetAttachId);
}
/**
* 往附件中追加文件
*/
public void appendFile() {
System.out.println("---往附件中追加一个文件---");
String uploadBy = "西湾";
File file = FileUtil.file("D:\\home\\翠亨\\角色关联员工.png");
FileObject fileObject = client.save(file, attachId, uploadBy);
System.out.println(fileObject);
fileCode = fileObject.getFileCode();
listAttach(attachId);
}
/**
* 转存文件
*/
public void getAndWriteFile() {
System.out.println("---转存文件前--检查欲存储文件是否存在---");
File file = FileUtil.file("D:\\home\\翠亨\\角色关联员工2.png");
System.out.println(FileUtil.exist(file));
//如果文件比较大,则可以指定请求连接时间,避免连接超时
Request.Options options = new Request.Options(20L, TimeUnit.SECONDS, 20L, TimeUnit.SECONDS, true);
//InputStream inputStream = client.getInputStream(options, fileCode);
byte[] bytes = client.get(options, fileCode);
FileUtil.writeBytes(bytes, FileUtil.file(file));
System.out.println("---转存文件后--检查欲存储文件是否存在---");
System.out.println(FileUtil.exist(file));
}
public void deleteFileCode() {
System.out.println("---删除一个文件---");
boolean isDeleted = client.delete(attachId, fileCode);
System.out.println(isDeleted);
listAttach(attachId);
}
public void deleteAttach(){
System.out.println("---删除附件---");
client.delete(attachId);
client.delete(copyTargetAttachId);
listAttach(attachId);
listAttach(copyTargetAttachId);
}
}
控制台输出
{attachId='fca9d2780c834ee9909d15783b41ebd0', fileCode='1bcb0afd7a9c47f2b230efdc7c62cfbb', orgFileName='所有权限角色.png', suffix='.png', fileSize='9690', uploadUser='西湾', uploadTime='null', url='http://testpai.zschzhcs.com/oss-api/oss/v1/1bcb0afd7a9c47f2b230efdc7c62cfbb'}
---查询附件fca9d2780c834ee9909d15783b41ebd0下的文件---
[{attachId='fca9d2780c834ee9909d15783b41ebd0', fileCode='1bcb0afd7a9c47f2b230efdc7c62cfbb', orgFileName='所有权限角色.png', suffix='.png', fileSize='9690', uploadUser='西湾', uploadTime='Tue Jul 05 15:14:53 CST 2022', url='http://testpai.zschzhcs.com/oss-api/oss/v1/1bcb0afd7a9c47f2b230efdc7c62cfbb'}]
---往附件中追加一个文件---
{attachId='fca9d2780c834ee9909d15783b41ebd0', fileCode='a937f5be8fab4c809e4ef00a8823abc5', orgFileName='角色关联员工.png', suffix='.png', fileSize='16657', uploadUser='西湾', uploadTime='null', url='http://testpai.zschzhcs.com/oss-api/oss/v1/a937f5be8fab4c809e4ef00a8823abc5'}
---查询附件fca9d2780c834ee9909d15783b41ebd0下的文件---
[{attachId='fca9d2780c834ee9909d15783b41ebd0', fileCode='a937f5be8fab4c809e4ef00a8823abc5', orgFileName='角色关联员工.png', suffix='.png', fileSize='16657', uploadUser='西湾', uploadTime='Tue Jul 05 15:14:54 CST 2022', url='http://testpai.zschzhcs.com/oss-api/oss/v1/a937f5be8fab4c809e4ef00a8823abc5'}, {attachId='fca9d2780c834ee9909d15783b41ebd0', fileCode='1bcb0afd7a9c47f2b230efdc7c62cfbb', orgFileName='所有权限角色.png', suffix='.png', fileSize='9690', uploadUser='西湾', uploadTime='Tue Jul 05 15:14:53 CST 2022', url='http://testpai.zschzhcs.com/oss-api/oss/v1/1bcb0afd7a9c47f2b230efdc7c62cfbb'}]
---转存文件前--检查欲存储文件是否存在---
false
---转存文件后--检查欲存储文件是否存在---
true
---删除一个文件---
15:14:53.806 [PollingServerListUpdater-0] INFO c.n.c.ChainedDynamicProperty - [checkAndFlip,115] - Flipping property: pai-oss.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
true
---查询附件fca9d2780c834ee9909d15783b41ebd0下的文件---
[{attachId='fca9d2780c834ee9909d15783b41ebd0', fileCode='1bcb0afd7a9c47f2b230efdc7c62cfbb', orgFileName='所有权限角色.png', suffix='.png', fileSize='9690', uploadUser='西湾', uploadTime='Tue Jul 05 15:14:53 CST 2022', url='http://testpai.zschzhcs.com/oss-api/oss/v1/1bcb0afd7a9c47f2b230efdc7c62cfbb'}]
---复制文件---
---查询复制后的附件下的文件---
---查询附件06809202d7c247fcb1225789f5def762下的文件---
[{attachId='06809202d7c247fcb1225789f5def762', fileCode='1bcb0afd7a9c47f2b230efdc7c62cfbb', orgFileName='所有权限角色.png', suffix='.png', fileSize='9690', uploadUser='西湾', uploadTime='Tue Jul 05 15:14:53 CST 2022', url='http://testpai.zschzhcs.com/oss-api/oss/v1/1bcb0afd7a9c47f2b230efdc7c62cfbb'}]
---删除附件---
---查询附件fca9d2780c834ee9909d15783b41ebd0下的文件---
[]
---查询附件06809202d7c247fcb1225789f5def762下的文件---
[]
前端配置
找到nuxt.config.js
中
module.exports = {
isOss: true
}
就可以使用前端组件了
注意
前端上传完成之后,后端记得确认保存。否则会当成临时文件,被定期清除
client.complete(attachId);
redis
后端pom.xml
引入包
<dependency>
<groupId>cn.flyrise</groupId>
<artifactId>pai-common-cache</artifactId>
</dependency>
新增测试类
import cn.flyrise.common.redis.service.RedisService;
import cn.flyrise.pai.xwservicetest.Application;
import cn.hutool.core.thread.ThreadUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class RedisTest {
@Resource
private RedisService service;
@Test
public void test() {
//设定5秒过期
//若不指定过期时间则一直存在,注意按需选择
service.setCacheObject("xw:test", "1000", 5, TimeUnit.SECONDS);
System.out.println((String) service.getCacheObject("xw:test"));
//休眠8秒
ThreadUtil.sleep(8000);
//查看结果
System.out.println((String) service.getCacheObject("xw:test"));
}
}
控制台输出
1000
null
nacos
请求地址http://testpai.zschzhcs.com/nacos
账号:nacos
密码:@Nacos
注意:个性化的配置不要放到共享配置。
工程配置
spring:
cloud:
nacos:
discovery:
namespace: 5a1495ca-cdce-4c82-8b38-ddce5ae3c8c9
server-addr: http://10.21.6.204:32018
#Nacos 服务开启认证时需要配置
#username:
#password:
#context-path: nacos
config:
namespace: ${spring.cloud.nacos.discovery.namespace}
server-addr: ${spring.cloud.nacos.discovery.server-addr}
file-extension: yaml
消息订阅MQ
物业系统功能如何聚合
使用中台框架开发的
添加菜单
外部应用
通过单点登录