开发背景
此次开发的项目主要是提供给婚恋的销售人员使用的经纪人项目,包含APP,小程序以及web管理端三端,我作为后端开发,主要开发模块有客源,服务进度,跟进小记,微聊模块。三方接口有环信,法大大,Pulsar,XXL-JOB。
后端开发框架及技术
框架
- SpringBoot
技术
- 服务治理和 RPC 通信: Dubbo
- 消息队列: Pulsar
- 数据缓存: Redis
- 分布式任务调度: XXL-JOB
- 数据转换: MapStruct
- 持久层框架: MyBatis-Plus
- 数据库版本控制: Flyway
- 版本控制系统: Git
- 容器编排和管理: Kubernetes (K8s)
- 即时通讯: 环信
- 支付退款: 灵活用工
- 用户身份验证登录: 企微登录
- 云存储服务: 腾讯COS
- 电子合同签署及实名认证:法大大
开发知识及总结
mybatis中Wrapper的方法积累
1.and表达式中包含or语句
java
LambdaQueryWrapper<ServiceConfirmation> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(ServiceConfirmation::getCustomerId, customerId)
.and(i -> i
.and(j -> j.eq(ServiceConfirmation::getIsServiceCompleted, CompletedStatus.UNCOMPLETED.getCode())
.eq(ServiceConfirmation::getIsSendConfirmation, 1))
.or()
.eq(ServiceConfirmation::getIsServiceCompleted, CompletedStatus.NO_COMMENT.getCode())
);
2.排序
java
new LambdaQueryWrapper<CustomerCollaboration>()
.eq(CustomerCollaboration::getAgentId, agentId)
.eq(CustomerCollaboration::getCustomerId, collaborationPageReq.getCustomerId())
.ne(CustomerCollaboration::getCollaborationStatus, CollaborationStatus.REFUSE.getCode())
.orderByDesc(CustomerCollaboration::getCreateTime)
Stream流方法积累
1.按照集合中的某个字段分组
java
Map<Long, List<CommissionInfo>> agentCommissionMap = commissionInfos.stream()
.collect(Collectors.groupingBy(CommissionInfo::getAgentId));
2.合并
java
//相同经纪人分佣金额合并
CommissionInfo mergeCommissionInfo = entry.getValue().stream()
.reduce((a, b) -> {
a.setAgentMoney(a.getAgentMoney().add(b.getAgentMoney()));
return a;
})
.orElse(null);
SQL知识积累
1.按照服务类型或服务状态排序
sql
ORDER BY
CASE sp.service_type
WHEN '1' THEN 1
WHEN '3' THEN 2
WHEN '2' THEN 3
WHEN '4' THEN 4
ELSE 5
END,
CASE spi.service_status
WHEN '2' THEN 1
WHEN '3' THEN 2
WHEN '1' THEN 3
END,
文件流
应用场景:当订单完成后客户可以点击查看评价后分享给其他微信用户,其他微信用户扫描小程序二维码后登录到小程序页面并且将该客户添加到经纪人的客户列表中。
参考文档:获取不限制的小程序码 | 微信开放文档
代码示例:
java
private String getQrCode(Long agentId) {
//获取微信token
String accessToken = String.valueOf(JSON.parseObject(HttpUtil.get(String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", wechatProperties.getMiniPayAppId(), wechatProperties.getMiniPaySecret()))).get("access_token"));
//生成二维码
String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken;
JSONObject params = new JSONObject();
params.put("scene", "agentId="+agentId);
params.put("env_version", "trial");
HttpResponse response = HttpRequest.post(url)
.body(params.toString())
.execute();
byte[] imageBytes = response.bodyBytes();
MultipartFile multipartFile = new MockMultipartFile(
"file",
"qr.png",
"image/png",
imageBytes
);
List<FileUploadRes> qR = fileService.upload(Arrays.asList(multipartFile), "qr");
if(ObjectUtil.isEmpty(qR)){
throw fileException.uploadException();
}
return qR.get(0).getFilePath();
}
知识点:
1.response.bodyBytes()和response.body()的区别
-
response.bodyBytes():
返回类型:byte[]
用途:此方法返回响应体的原始字节数据。这在处理二进制数据时非常有用,例如下载文件、图像或其他媒体类型。这种方法保证数据的精确性,因为它不会尝试将原始内容转换成字符串。
-
response.body():
返回类型:String
用途:此方法返回响应体作为一个字符串。这在响应是文本格式时非常有用,例如JSON、XML或普通文本。这种方法通常在API响应是文本格式并需要解析这些文本(如JSON解析)时使用。
总结:
如果你需要原始二进制数据,使用response.bodyBytes()。
如果你处理的是文本格式的响应,使用response.body()。
在上传图像或处理其他二进制文件时,始终使用byte[]以防止数据损坏。
在处理图像或其他二进制数据的上传时,通常需要使用byte[]而不是String,因为使用String可能会导致数据损坏。当你从一个服务接收图像数据并打算将其上传到另一个服务时,应该保持数据在byte[]格式以保持数据的完整性。
ResponseEntity
直接返回图像内容:
java
@GetMapping("/image")
public ResponseEntity<byte[]> getImage() throws IOException {
// 假设这是图像文件的路径
Path path = Paths.get("/path/to/your/image.png");
byte[] image = Files.readAllBytes(path);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
return new ResponseEntity<>(image, headers, HttpStatus.OK);
}