Merge remote-tracking branch 'origin/wzj-main' into wzj-main
This commit is contained in:
commit
e3ae60b5f8
@ -136,6 +136,7 @@ tenant:
|
||||
- sys_role_menu
|
||||
- sys_user_post
|
||||
- sys_user_role
|
||||
- sys_message
|
||||
- sys_client
|
||||
- sys_oss_config
|
||||
- ums_member
|
||||
@ -145,6 +146,7 @@ tenant:
|
||||
- ums_cart
|
||||
- ums_account
|
||||
- ums_account_change_record
|
||||
- sys_message_template
|
||||
- ums_fans
|
||||
- ums_block
|
||||
- oms_aftersale
|
||||
|
@ -1,4 +0,0 @@
|
||||
package org.dromara.common.web.core;
|
||||
|
||||
public interface MemberFill {
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
package com.wzj.soopin.member.annotation;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.wzj.soopin.member.domain.vo.MemberVO;
|
||||
import com.wzj.soopin.member.service.IMemberService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collection;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class MemberFillAspect {
|
||||
|
||||
private final IMemberService memberService;
|
||||
|
||||
@Around("@annotation(com.wzj.soopin.member.annotation.MemberFillMethod)")
|
||||
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
Object result = joinPoint.proceed();
|
||||
if (result instanceof R<?>) {
|
||||
Object data = ((R<?>) result).getData();
|
||||
if (data != null) {
|
||||
processObject(data);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void processObject(Object obj) {
|
||||
|
||||
//基础类型跳过
|
||||
if (obj == null || isPrimitiveType(obj.getClass())) return;
|
||||
|
||||
// 处理集合类型
|
||||
if (obj instanceof Collection) {
|
||||
for (Object item : (Collection<?>) obj) {
|
||||
processObject(item);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 处理分页类型
|
||||
if (obj instanceof IPage<?>) {
|
||||
|
||||
for (Object item : (Collection<?>)((IPage<?>) obj).getRecords()) {
|
||||
processObject(item);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 处理数组类型
|
||||
if (obj.getClass().isArray()) {
|
||||
int length = java.lang.reflect.Array.getLength(obj);
|
||||
for (int i = 0; i < length; i++) {
|
||||
processObject(java.lang.reflect.Array.get(obj, i));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 同原 MemberFillInterceptor 中的逻辑,简化处理
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != null && clazz != Object.class) {
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if (field.isAnnotationPresent(MemberFillField.class)) {
|
||||
handleMemberFill(obj, field);
|
||||
}
|
||||
}
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否为基本类型或包装类型
|
||||
private boolean isPrimitiveType(Class<?> clazz) {
|
||||
return clazz.isPrimitive() ||
|
||||
clazz.equals(String.class) ||
|
||||
clazz.equals(Integer.class) ||
|
||||
clazz.equals(Long.class) ||
|
||||
clazz.equals(Double.class) ||
|
||||
clazz.equals(Float.class) ||
|
||||
clazz.equals(Boolean.class) ||
|
||||
clazz.equals(Character.class) ||
|
||||
clazz.equals(Short.class) ||
|
||||
clazz.equals(Byte.class);
|
||||
}
|
||||
|
||||
private void handleMemberFill(Object obj, Field field) {
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
MemberFillField annotation = field.getAnnotation(MemberFillField.class);
|
||||
String memberIdFieldName = annotation.id();
|
||||
|
||||
Field idField = findField(obj.getClass(), memberIdFieldName);
|
||||
idField.setAccessible(true);
|
||||
Object memberId = idField.get(obj);
|
||||
|
||||
if (memberId instanceof Long) {
|
||||
MemberVO member = memberService.getMemberInfo((Long) memberId);
|
||||
if (member != null) {
|
||||
field.set(obj, member);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("会员信息填充失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
private Field findField(Class<?> clazz, String fieldName) throws NoSuchFieldException {
|
||||
try {
|
||||
return clazz.getDeclaredField(fieldName);
|
||||
} catch (NoSuchFieldException e) {
|
||||
Class<?> superClass = clazz.getSuperclass();
|
||||
if (superClass == null) throw e;
|
||||
return findField(superClass, fieldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
package com.wzj.soopin.member.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 自定义vo处理器,用于标注需要填充member的对象
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MemberFillField {
|
||||
|
||||
/**
|
||||
* 指向memberId字段名
|
||||
*/
|
||||
String id() default "";
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.wzj.soopin.member.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 自定义vo处理器,用于修饰接口,如果需要自动填充vo中的用户信息则需要增加这个注解
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MemberFillMethod {
|
||||
|
||||
}
|
@ -1,19 +1,17 @@
|
||||
package com.wzj.soopin.member.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.wzj.soopin.member.annotation.MemberFillMethod;
|
||||
import com.wzj.soopin.member.convert.FansConvert;
|
||||
import com.wzj.soopin.member.convert.FeedbackConvert;
|
||||
import com.wzj.soopin.member.convert.MemberBlockConvert;
|
||||
import com.wzj.soopin.member.domain.bo.FansBO;
|
||||
import com.wzj.soopin.member.domain.bo.FeedbackBO;
|
||||
import com.wzj.soopin.member.domain.po.Fans;
|
||||
import com.wzj.soopin.member.domain.po.Feedback;
|
||||
import com.wzj.soopin.member.domain.po.Member;
|
||||
import com.wzj.soopin.member.domain.po.MemberBlock;
|
||||
import com.wzj.soopin.member.domain.vo.FansVO;
|
||||
import com.wzj.soopin.member.domain.vo.FeedbackVO;
|
||||
import com.wzj.soopin.member.domain.vo.MemberBlockVO;
|
||||
import com.wzj.soopin.member.service.IFansService;
|
||||
import com.wzj.soopin.member.service.IMemberBlockService;
|
||||
import com.wzj.soopin.member.service.IMemberService;
|
||||
@ -22,7 +20,6 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.constant.CacheConstants;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.redis.utils.RedisUtils;
|
||||
@ -45,28 +42,29 @@ public class FansController {
|
||||
|
||||
private final IMemberBlockService memberBlockService;
|
||||
|
||||
private final MemberBlockConvert memberblockconvert;
|
||||
|
||||
@Tag(name ="粉丝列表")
|
||||
@PostMapping("/fan/list")
|
||||
public R<IPage<FansVO>> fansList( Long memberId, @RequestBody Page page) {
|
||||
public R<IPage<FansVO>> fansList(@RequestBody FansBO bo, @RequestBody Page page) {
|
||||
LambdaQueryWrapper< Fans> fansQuery = new LambdaQueryWrapper<>();
|
||||
fansQuery.eq(Fans::getVloggerId, memberId);
|
||||
fansQuery.eq(Fans::getVloggerId, bo.getMemberId());
|
||||
Page<Fans> fans= service.page(page,fansQuery);
|
||||
return R.ok(convert.toVO( fans));
|
||||
}
|
||||
@Tag(name ="关注列表")
|
||||
@PostMapping("/follow/list")
|
||||
public R<IPage<FansVO>> followList( Long memberId, @RequestBody Page page) {
|
||||
public R<IPage<FansVO>> followList(@RequestBody FansBO bo, @RequestBody Page page) {
|
||||
LambdaQueryWrapper< Fans> fansQuery = new LambdaQueryWrapper<>();
|
||||
fansQuery.eq(Fans::getFanId, memberId);
|
||||
fansQuery.eq(Fans::getFanId, bo.getMemberId());
|
||||
Page<Fans> fans= service.page(page,fansQuery);
|
||||
return R.ok(convert.toVO( fans));
|
||||
}
|
||||
@Tag(name ="朋友列表")
|
||||
@PostMapping("/friend/list")
|
||||
public R<IPage<FansVO>> friendList( Long memberId, @RequestBody Page page) {
|
||||
public R<IPage<FansVO>> friendList( @RequestBody FansBO bo, @RequestBody Page page) {
|
||||
LambdaQueryWrapper< Fans> fansQuery = new LambdaQueryWrapper<>();
|
||||
fansQuery.eq(Fans::getVloggerId, memberId);
|
||||
fansQuery.eq(Fans::getVloggerId, bo.getMemberId());
|
||||
fansQuery.eq(Fans::getFriendFlag, 1);
|
||||
Page<Fans> fans= service.page(page,fansQuery);
|
||||
return R.ok(convert.toVO( fans));
|
||||
@ -152,9 +150,12 @@ public class FansController {
|
||||
}
|
||||
|
||||
@GetMapping("block/list")
|
||||
public R<List<MemberBlock>> queryBlockVloger(@RequestParam Long myId) {
|
||||
@MemberFillMethod
|
||||
public R<List<MemberBlockVO>> queryBlockVloger(@RequestParam Long myId) {
|
||||
|
||||
return R.ok(memberBlockService.list(new LambdaQueryWrapper<MemberBlock>().eq(MemberBlock::getMemberId, myId)));
|
||||
List<MemberBlock> blockList= memberBlockService.list(new LambdaQueryWrapper<MemberBlock>().eq(MemberBlock::getMemberId, myId));
|
||||
|
||||
return R.ok(memberblockconvert.toVO(blockList));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,7 +112,7 @@ public class FeedbackController {
|
||||
|
||||
@Tag(name = ("处理"))
|
||||
@Log(title = "意见反馈", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/handle/handle")
|
||||
@PostMapping("/handle")
|
||||
public R changeStatus(@RequestBody FeedbackBO bo) {
|
||||
service.handle(convert.toPo(bo));
|
||||
return R.ok();
|
||||
|
@ -3,6 +3,7 @@ package com.wzj.soopin.member.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.wzj.soopin.member.annotation.MemberFillMethod;
|
||||
import com.wzj.soopin.member.convert.MemberAddressConvert;
|
||||
import com.wzj.soopin.member.domain.bo.MemberAddressBO;
|
||||
import com.wzj.soopin.member.domain.po.MemberAddress;
|
||||
@ -27,7 +28,7 @@ import java.util.List;
|
||||
*/
|
||||
@Tag(name ="会员收货地址接口列表")
|
||||
@RestController
|
||||
@RequestMapping("/ums/memberAddress")
|
||||
@RequestMapping("/ums/member/address")
|
||||
@RequiredArgsConstructor
|
||||
public class MemberAddressController {
|
||||
|
||||
@ -37,6 +38,7 @@ public class MemberAddressController {
|
||||
|
||||
@Tag(name ="查询会员收货地址列表")
|
||||
@PostMapping("/list")
|
||||
@MemberFillMethod
|
||||
public R list(@RequestBody MemberAddressBO query,@RequestBody Page<MemberAddress> page) {
|
||||
Page<MemberAddress> list = service.page(page,query.toWrapper());
|
||||
return R.ok(convert.toVO(list));
|
||||
@ -53,22 +55,22 @@ public class MemberAddressController {
|
||||
|
||||
@Tag(name ="获取会员收货地址详细信息")
|
||||
@GetMapping(value = "/{id}")
|
||||
public R<MemberAddress> getInfo(@PathVariable("id") Long id) {
|
||||
return R.ok(service.getById(id));
|
||||
public R<MemberAddressVO> getInfo(@PathVariable("id") Long id) {
|
||||
return R.ok(convert.toVO(service.getById(id)));
|
||||
}
|
||||
|
||||
@Tag(name ="新增会员收货地址")
|
||||
@Log(title = "会员收货地址", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/add")
|
||||
public R<Object> add(@RequestBody MemberAddress memberAddress) {
|
||||
return R.ok(service.save(memberAddress));
|
||||
public R<Object> add(@RequestBody MemberAddressBO memberAddress) {
|
||||
return R.ok(service.save(convert.toPo(memberAddress)));
|
||||
}
|
||||
|
||||
@Tag(name ="修改会员收货地址")
|
||||
@Log(title = "会员收货地址", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/update")
|
||||
public R edit(@RequestBody MemberAddress memberAddress) {
|
||||
service.updateById(memberAddress);
|
||||
public R edit(@RequestBody MemberAddressBO memberAddress) {
|
||||
service.updateById(convert.toPo(memberAddress));
|
||||
return R.ok(null);
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ package com.wzj.soopin.member.controller;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.wzj.soopin.member.annotation.MemberFillMethod;
|
||||
import com.wzj.soopin.member.convert.MemberCartConvert;
|
||||
import com.wzj.soopin.member.domain.bo.MemberCartBO;
|
||||
import com.wzj.soopin.member.domain.po.MemberCart;
|
||||
@ -34,6 +35,7 @@ public class MemberCartController extends BaseController {
|
||||
|
||||
@Tag(name = "查询购物车列表")
|
||||
@PostMapping("/list")
|
||||
@MemberFillMethod
|
||||
public R<IPage<MemberCartVO>> list(@RequestBody MemberCartBO bo, @RequestBody Page page) {
|
||||
Page<MemberCart> userPage = service.page(page, bo.toWrapper());
|
||||
return R.ok(convert.toVO(userPage));
|
||||
@ -51,6 +53,7 @@ public class MemberCartController extends BaseController {
|
||||
|
||||
@Tag(name = "获取购物车详细信息")
|
||||
@GetMapping(value = "/{id}")
|
||||
@MemberFillMethod
|
||||
public R<MemberCartVO> getInfo(@PathVariable("id") Long id) {
|
||||
return R.ok(convert.toVO(service.getById(id)));
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package com.wzj.soopin.member.convert;
|
||||
|
||||
import com.wzj.soopin.member.domain.bo.FeedbackBO;
|
||||
import com.wzj.soopin.member.domain.po.Feedback;
|
||||
import com.wzj.soopin.member.domain.po.MemberBlock;
|
||||
import com.wzj.soopin.member.domain.vo.FeedbackVO;
|
||||
import com.wzj.soopin.member.domain.vo.MemberBlockVO;
|
||||
import org.dromara.common.web.core.BaseConverter;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
|
||||
/**
|
||||
* 意见反馈 DO <=> VO / BO
|
||||
*
|
||||
* @author zcc
|
||||
*/
|
||||
@Mapper(componentModel = "spring",uses = BaseConverter.class)
|
||||
public interface MemberBlockConvert extends BaseConverter<MemberBlockVO, MemberBlock, MemberBlock> {
|
||||
|
||||
}
|
@ -19,6 +19,14 @@ import org.springframework.boot.actuate.integration.IntegrationGraphEndpoint;
|
||||
public class FansBO extends BaseBO<Fans> {
|
||||
|
||||
|
||||
/**
|
||||
* 用户
|
||||
*/
|
||||
@Schema(description ="用户id")
|
||||
private String memberId;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 博主id
|
||||
*/
|
||||
|
@ -1,7 +1,6 @@
|
||||
package com.wzj.soopin.member.domain.bo;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.wzj.soopin.member.domain.po.MemberAddress;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
@ -14,12 +13,16 @@ import org.dromara.common.core.domain.BaseBO;
|
||||
*/
|
||||
@Schema(description="会员收货地址 查询 对象")
|
||||
@Data
|
||||
public class MemberAddressBO extends BaseBO {
|
||||
public class MemberAddressBO extends BaseBO<MemberAddress> {
|
||||
|
||||
|
||||
|
||||
private Long id;
|
||||
@Schema(description ="MEMBER_ID 精确匹配")
|
||||
private Long memberId;
|
||||
|
||||
@Schema(description ="收货人名称 精确匹配")
|
||||
private String nameLike;
|
||||
private String name;
|
||||
|
||||
@Schema(description ="PHONE 精确匹配")
|
||||
private String phone;
|
||||
@ -43,10 +46,19 @@ public class MemberAddressBO extends BaseBO {
|
||||
private String detailAddress;
|
||||
|
||||
@Schema(description ="是否默认 精确匹配")
|
||||
private Integer isDefault;
|
||||
private Integer defaultFlag;
|
||||
|
||||
@Override
|
||||
public LambdaQueryWrapper<MemberAddress> toWrapper() {
|
||||
return new QueryWrapper<MemberAddress>().lambda().eq(MemberAddress::getMemberId,this.getMemberId());
|
||||
return super.toWrapper().eq(city!=null,MemberAddress::getCity,city)
|
||||
.eq(district!=null,MemberAddress::getDistrict,district)
|
||||
.like(detailAddress!=null,MemberAddress::getDetailAddress,detailAddress)
|
||||
.eq(phone!=null,MemberAddress::getPhoneEncrypted,phone)
|
||||
.eq(province!=null,MemberAddress::getProvince,province)
|
||||
.eq(city!=null,MemberAddress::getCity,city)
|
||||
.eq(defaultFlag!=null,MemberAddress::getDefaultFlag,defaultFlag)
|
||||
.eq(memberId!=null,MemberAddress::getMemberId,memberId)
|
||||
.like(name!=null,MemberAddress::getName,name);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package com.wzj.soopin.member.domain.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.core.domain.model.BaseAudit;
|
||||
import org.dromara.common.excel.annotation.Excel;
|
||||
@ -15,7 +16,6 @@ import org.dromara.common.excel.annotation.Excel;
|
||||
@Data
|
||||
@TableName("ums_member_address")
|
||||
public class MemberAddress extends BaseAudit {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description ="ID")
|
||||
private Long id;
|
||||
@ -24,6 +24,7 @@ public class MemberAddress extends BaseAudit {
|
||||
@Excel(name = "MEMBER_ID")
|
||||
private Long memberId;
|
||||
|
||||
|
||||
@Schema(description ="收货人名称")
|
||||
@Excel(name = "收货人名称")
|
||||
private String name;
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.wzj.soopin.member.domain.vo;
|
||||
|
||||
import com.wzj.soopin.member.annotation.MemberFillField;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
@ -17,6 +18,7 @@ public class FansVO {
|
||||
|
||||
@Schema(description ="博主id")
|
||||
@Excel(name = "博主id")
|
||||
@MemberFillField(id = "vloggerId")
|
||||
private MemberVO vlogger;
|
||||
|
||||
@Schema(description ="博主id")
|
||||
@ -24,6 +26,7 @@ public class FansVO {
|
||||
|
||||
@Schema(description ="粉丝id")
|
||||
@Excel(name = "粉丝id")
|
||||
@MemberFillField(id = "fanId")
|
||||
private MemberVO fan;
|
||||
|
||||
@Schema(description ="粉丝id")
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.wzj.soopin.member.domain.vo;
|
||||
|
||||
import com.wzj.soopin.member.annotation.MemberFillField;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.excel.annotation.Excel;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
@ -16,6 +18,14 @@ public class MemberAddressVO extends BaseEntity {
|
||||
/** MEMBER_ID */
|
||||
@Excel(name = "MEMBER_ID")
|
||||
private Long memberId;
|
||||
|
||||
/** MEMBER_ID */
|
||||
@Excel(name = "MEMBER_ID")
|
||||
@Schema(description = "MEMBER_ID")
|
||||
@MemberFillField(id = "memberId")
|
||||
private MemberVO member;
|
||||
|
||||
|
||||
/** 收货人名称 */
|
||||
@Excel(name = "收货人名称")
|
||||
private String name;
|
||||
@ -26,7 +36,7 @@ public class MemberAddressVO extends BaseEntity {
|
||||
private String phoneHidden;
|
||||
/** 是否为默认 */
|
||||
@Excel(name = "是否为默认")
|
||||
private Integer defaultStatus;
|
||||
private Integer defaultFlag;
|
||||
/** 邮政编码 */
|
||||
@Excel(name = "邮政编码")
|
||||
private String postCode;
|
||||
@ -42,7 +52,5 @@ public class MemberAddressVO extends BaseEntity {
|
||||
/** 详细地址(街道) */
|
||||
@Excel(name = "详细地址(街道)")
|
||||
private String detailAddress;
|
||||
/** 是否默认 */
|
||||
@Excel(name = "是否默认")
|
||||
private Integer isDefault;
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.wzj.soopin.member.domain.vo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.wzj.soopin.member.annotation.MemberFillField;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.core.domain.model.BaseAudit;
|
||||
@ -20,8 +20,15 @@ public class MemberBlockVO extends BaseAudit {
|
||||
|
||||
@Schema(description ="用户id")
|
||||
private Long memberId;
|
||||
@Schema(description ="用户")
|
||||
@MemberFillField(id = "memberId")
|
||||
private MemberVO member;
|
||||
|
||||
@Schema(description ="被拉黑人id")
|
||||
private Long blockMemberId;
|
||||
|
||||
@Schema(description ="被拉黑人")
|
||||
@MemberFillField(id = "blockMemberId")
|
||||
private MemberVO blockMember;
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.wzj.soopin.member.domain.vo;
|
||||
|
||||
import com.wzj.soopin.member.annotation.MemberFillField;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.excel.annotation.Excel;
|
||||
@ -35,6 +36,7 @@ public class MemberCartVO {
|
||||
|
||||
@Schema(description ="会员")
|
||||
@Excel(name = "会员")
|
||||
@MemberFillField(id = "memberId")
|
||||
private MemberVO member;
|
||||
|
||||
|
||||
|
@ -7,6 +7,7 @@ import com.wzj.soopin.member.domain.po.Member;
|
||||
import com.wzj.soopin.member.domain.vo.MemberVO;
|
||||
import org.dromara.common.core.constant.ResultCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
public interface IMemberService extends IService<Member> {
|
||||
@ -60,4 +61,7 @@ public interface IMemberService extends IService<Member> {
|
||||
|
||||
|
||||
String getPhoneDecrypted(String phoneEncrypted) ;
|
||||
|
||||
|
||||
MemberVO getMemberInfo(Serializable id);
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ public class MemberAddressServiceImpl extends ServiceImpl<MemberAddressMapper,
|
||||
public IPage<MemberAddress> selectList(MemberAddressBO query, IPage page) {
|
||||
|
||||
QueryWrapper<MemberAddress> qw = new QueryWrapper<>();
|
||||
String nameLike = query.getNameLike();
|
||||
String nameLike = query.getName();
|
||||
if (!StringUtils.isEmpty(nameLike)) {
|
||||
qw.like("name", nameLike);
|
||||
}
|
||||
|
@ -6,10 +6,12 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.wzj.soopin.member.convert.MemberConvert;
|
||||
import com.wzj.soopin.member.domain.bo.MemberBO;
|
||||
import com.wzj.soopin.member.domain.form.ChangeMemberStatusForm;
|
||||
import com.wzj.soopin.member.domain.po.Member;
|
||||
import com.wzj.soopin.member.domain.po.MemberAccount;
|
||||
import com.wzj.soopin.member.domain.vo.MemberVO;
|
||||
import com.wzj.soopin.member.mapper.MemberAccountMapper;
|
||||
import com.wzj.soopin.member.mapper.MemberCartMapper;
|
||||
import com.wzj.soopin.member.mapper.MemberMapper;
|
||||
@ -54,6 +56,9 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper,Member> implemen
|
||||
|
||||
private final MemberAccountMapper memberAccountMapper;
|
||||
|
||||
|
||||
private final MemberConvert memberConvert;
|
||||
|
||||
@Override
|
||||
public boolean usernameExists(String username) {
|
||||
return baseMapper.countByUsername(username) > 0; // 确保实现
|
||||
@ -102,8 +107,6 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper,Member> implemen
|
||||
|
||||
|
||||
|
||||
@CachePut(value = CacheConstants.MEMBER, key = "#id")
|
||||
|
||||
public Integer changeStatus(MemberBO bo) {
|
||||
UpdateWrapper<Member> wrapper = new UpdateWrapper<>();
|
||||
wrapper.eq("id", bo.getId());
|
||||
@ -252,4 +255,10 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper,Member> implemen
|
||||
public Member getById(Serializable id) {
|
||||
return super.getById(id);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MemberVO getMemberInfo(Serializable id) {
|
||||
return memberConvert.toVO(getById(id));
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-core</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@ -112,6 +113,23 @@
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot WebSocket -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Jakarta WebSocket API -->
|
||||
<dependency>
|
||||
<groupId>jakarta.websocket</groupId>
|
||||
<artifactId>jakarta.websocket-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Jakarta WebSocket Implementation -->
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
@ -0,0 +1,183 @@
|
||||
package org.dromara.system.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.service.UserService;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.core.validate.QueryGroup;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.system.domain.SysMessage;
|
||||
import org.dromara.system.domain.SysUser;
|
||||
import org.dromara.system.domain.bo.SysMessageBo;
|
||||
import org.dromara.system.domain.bo.SysUserBo;
|
||||
import org.dromara.system.domain.vo.SysMessageVo;
|
||||
import org.dromara.system.domain.vo.SysUserVo;
|
||||
import org.dromara.system.service.ISysMessageService;
|
||||
import org.dromara.system.service.ISysUserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息管理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Validated
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/system/message")
|
||||
public class SysMessageController extends BaseController {
|
||||
|
||||
private final ISysMessageService messageService;
|
||||
private final ISysUserService userService;
|
||||
|
||||
/**
|
||||
* 获取当前用户ID
|
||||
*/
|
||||
private Long getUserId() {
|
||||
return LoginHelper.getUserId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询消息列表
|
||||
*/
|
||||
@SaCheckPermission("system:message:list")
|
||||
@Tag(name = "查询消息列表")
|
||||
@PostMapping("/list")
|
||||
public R<Page<SysMessageVo>> list(@RequestBody SysMessageBo bo, @RequestBody Page<SysMessage> page) {
|
||||
Page<SysMessage> messagePage = messageService.page(page, bo.toWrapper());
|
||||
Page<SysMessageVo> voPage = new Page<>(messagePage.getCurrent(), messagePage.getSize(), messagePage.getTotal());
|
||||
voPage.setRecords(MapstructUtils.convert(messagePage.getRecords(), SysMessageVo.class));
|
||||
return R.ok(voPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取消息详细信息
|
||||
*
|
||||
* @param id 消息ID
|
||||
*/
|
||||
@SaCheckPermission("system:message:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<SysMessageVo> getInfo(@NotNull(message = "消息ID不能为空") @PathVariable Long id) {
|
||||
return R.ok(messageService.selectMessageById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*/
|
||||
@SaCheckPermission("system:message:send")
|
||||
@Log(title = "消息管理", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/send")
|
||||
public R<Void> send(@Validated(AddGroup.class) @RequestBody SysMessageBo bo) {
|
||||
List<SysUserVo> users = userService.selectUserListByDept(null);
|
||||
List<Long> userIds;
|
||||
|
||||
switch (bo.getSendScope()) {
|
||||
case "all":
|
||||
// 全部用户
|
||||
userIds = users.stream().map(SysUserVo::getUserId).toList();
|
||||
break;
|
||||
case "expert":
|
||||
// 达人
|
||||
userIds = users.stream()
|
||||
.filter(user -> "expert".equals(user.getUserType()))
|
||||
.map(SysUserVo::getUserId)
|
||||
.toList();
|
||||
break;
|
||||
case "merchant":
|
||||
// 商户
|
||||
userIds = users.stream()
|
||||
.filter(user -> "merchant".equals(user.getUserType()))
|
||||
.map(SysUserVo::getUserId)
|
||||
.toList();
|
||||
break;
|
||||
case "user":
|
||||
// 普通用户
|
||||
userIds = users.stream()
|
||||
.filter(user -> "user".equals(user.getUserType()))
|
||||
.map(SysUserVo::getUserId)
|
||||
.toList();
|
||||
break;
|
||||
default:
|
||||
// 其他情况(如指定userIds)
|
||||
userIds = bo.getUserIds();
|
||||
}
|
||||
|
||||
return toAjax(messageService.sendMessageToUsers(bo, userIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记消息为已读
|
||||
*/
|
||||
@SaCheckPermission("system:message:mark")
|
||||
@Log(title = "消息管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/mark/{id}")
|
||||
public R<Void> markAsRead(@NotNull(message = "消息ID不能为空") @PathVariable Long id) {
|
||||
return toAjax(messageService.markAsRead(id, getUserId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除消息
|
||||
*
|
||||
* @param ids 消息ID串
|
||||
*/
|
||||
@SaCheckPermission("system:message:remove")
|
||||
@Log(title = "消息管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "消息ID不能为空") @PathVariable Long[] ids) {
|
||||
return toAjax(messageService.deleteMessageByIds(ids));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取未读消息列表
|
||||
*/
|
||||
@SaCheckPermission("system:message:list")
|
||||
@Tag(name = "查询未读消息列表")
|
||||
@PostMapping("/unread")
|
||||
public R<Page<SysMessageVo>> unreadList(@RequestBody Page<SysMessage> page) {
|
||||
Page<SysMessageVo> unreadPage = messageService.selectUnreadMessagesPage(getUserId(), page);
|
||||
return R.ok(unreadPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已读消息列表
|
||||
*/
|
||||
@SaCheckPermission("system:message:list")
|
||||
@Tag(name = "查询已读消息列表")
|
||||
@PostMapping("/read")
|
||||
public R<Page<SysMessageVo>> readList(@RequestBody Page<SysMessage> page) {
|
||||
Page<SysMessageVo> readPage = messageService.selectReadMessagesPage(getUserId(), page);
|
||||
return R.ok(readPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户列表
|
||||
*/
|
||||
// @SaCheckPermission("system:message:list")
|
||||
// @GetMapping("/user/list")
|
||||
// public R<TableDataInfo<SysUserVo>> getUserList() {
|
||||
// PageQuery pageQuery = new PageQuery();
|
||||
// pageQuery.setPageNum(1);
|
||||
// pageQuery.setPageSize(Integer.MAX_VALUE);
|
||||
// TableDataInfo<SysUserVo> users = userService.selectPageUserList(new SysUserBo(), pageQuery);
|
||||
// return R.ok(users);
|
||||
// }
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package org.dromara.system.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.system.domain.SysMessageTemplate;
|
||||
import org.dromara.system.domain.bo.SysMessageTemplateBo;
|
||||
import org.dromara.system.domain.vo.SysMessageTemplateVo;
|
||||
import org.dromara.system.service.ISysMessageTemplateService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息模板管理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/system/message/template")
|
||||
public class SysMessageTemplateController extends BaseController {
|
||||
|
||||
private final ISysMessageTemplateService templateService;
|
||||
|
||||
/**
|
||||
* 查询消息模板列表
|
||||
*/
|
||||
@SaCheckPermission("system:message:template:list")
|
||||
@Tag(name = "查询消息模板列表")
|
||||
@PostMapping("/list")
|
||||
public R<Page<SysMessageTemplateVo>> list(@RequestBody SysMessageTemplateBo bo, @RequestBody Page<SysMessageTemplate> page) {
|
||||
Page<SysMessageTemplate> templatePage = templateService.page(page, bo.toWrapper());
|
||||
Page<SysMessageTemplateVo> voPage = new Page<>(templatePage.getCurrent(), templatePage.getSize(), templatePage.getTotal());
|
||||
voPage.setRecords(MapstructUtils.convert(templatePage.getRecords(), SysMessageTemplateVo.class));
|
||||
return R.ok(voPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取消息模板详细信息
|
||||
*
|
||||
* @param id 消息模板ID
|
||||
*/
|
||||
@SaCheckPermission("system:message:template:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<SysMessageTemplateVo> getInfo(@NotNull(message = "消息模板ID不能为空") @PathVariable Long id) {
|
||||
SysMessageTemplate template = templateService.getById(id);
|
||||
return R.ok(MapstructUtils.convert(template, SysMessageTemplateVo.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增消息模板
|
||||
*/
|
||||
@SaCheckPermission("system:message:template:add")
|
||||
@Log(title = "消息模板管理", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody SysMessageTemplateBo bo) {
|
||||
return toAjax(templateService.save(bo.toEntity()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改消息模板
|
||||
*/
|
||||
@SaCheckPermission("system:message:template:edit")
|
||||
@Log(title = "消息模板管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysMessageTemplateBo bo) {
|
||||
return toAjax(templateService.updateById(bo.toEntity()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除消息模板
|
||||
*
|
||||
* @param ids 消息模板ID串
|
||||
*/
|
||||
@SaCheckPermission("system:message:template:remove")
|
||||
@Log(title = "消息模板管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "消息模板ID不能为空") @PathVariable Long[] ids) {
|
||||
return toAjax(templateService.removeByIds(List.of(ids)));
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package org.dromara.system.converter;
|
||||
|
||||
import org.dromara.system.domain.SysMessage;
|
||||
import org.dromara.system.domain.vo.SysMessageVo;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息对象转换器
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Mapper(componentModel = "spring")
|
||||
public interface SysMessageConvert {
|
||||
|
||||
SysMessageConvert INSTANCE = Mappers.getMapper(SysMessageConvert.class);
|
||||
|
||||
/**
|
||||
* SysMessage转SysMessageVo
|
||||
*/
|
||||
SysMessageVo convert(SysMessage sysMessage);
|
||||
|
||||
/**
|
||||
* SysMessage列表转SysMessageVo列表
|
||||
*/
|
||||
List<SysMessageVo> convertList(List<SysMessage> sysMessageList);
|
||||
|
||||
/**
|
||||
* SysMessageVo转SysMessage
|
||||
*/
|
||||
SysMessage convert(SysMessageVo sysMessageVo);
|
||||
|
||||
/**
|
||||
* SysMessageVo列表转SysMessage列表
|
||||
*/
|
||||
List<SysMessage> convertListVoToEntity(List<SysMessageVo> sysMessageVoList);
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package org.dromara.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.core.domain.model.BaseAudit;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 消息对象 sys_message
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("sys_message")
|
||||
public class SysMessage extends BaseAudit {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键ID */
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/** 消息标题 */
|
||||
private String title;
|
||||
|
||||
/** 消息内容 */
|
||||
private String content;
|
||||
|
||||
/** 消息类型(AUTO自动/MANUAL手动) */
|
||||
private String msgType;
|
||||
|
||||
/** 触发条件 */
|
||||
private String subType;
|
||||
|
||||
/** 发送者ID */
|
||||
private Long senderId;
|
||||
|
||||
/** 定时发送时间 */
|
||||
private Date scheduledTime;
|
||||
|
||||
// /** 状态(0正常 1停用) */
|
||||
// private String status;
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package org.dromara.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.core.domain.model.BaseAudit;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
|
||||
/**
|
||||
* 消息模板对象 sys_message_template
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("sys_message_template")
|
||||
public class SysMessageTemplate extends BaseAudit {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 模板ID
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 模板类型(0通知 1公告)
|
||||
*/
|
||||
private String templateType;
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 模板编码
|
||||
*/
|
||||
private String templateCode;
|
||||
|
||||
/**
|
||||
* 模板名称
|
||||
*/
|
||||
private String templateName;
|
||||
|
||||
|
||||
/**
|
||||
* 模板内容
|
||||
*/
|
||||
private String templateContent;
|
||||
|
||||
// /**
|
||||
// * 模板参数
|
||||
// */
|
||||
// private String templateParams;
|
||||
|
||||
/**
|
||||
* 状态(0正常 1停用)
|
||||
*/
|
||||
private String status;
|
||||
//
|
||||
// /**
|
||||
// * 备注
|
||||
// */
|
||||
// private String remark;
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package org.dromara.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.core.domain.model.BaseAudit;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 消息用户关联对象 sys_message_user
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("sys_message_user")
|
||||
public class SysMessageUser extends BaseAudit {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 消息ID
|
||||
*/
|
||||
private Long messageId;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 是否已读(0未读 1已读)
|
||||
*/
|
||||
private Boolean isRead;
|
||||
|
||||
/**
|
||||
* 阅读时间
|
||||
*/
|
||||
private Date readTime;
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
package org.dromara.system.domain.bo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.core.domain.model.BaseAudit;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.system.domain.SysMessage;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息业务对象
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = SysMessage.class, reverseConvertGenerate = false)
|
||||
public class SysMessageBo extends BaseAudit {
|
||||
|
||||
/** 主键ID */
|
||||
@ExcelProperty(value = "消息ID")
|
||||
private Long id;
|
||||
|
||||
/** 消息标题 */
|
||||
@NotBlank(message = "消息标题不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@Size(min = 0, max = 100, message = "消息标题长度不能超过100个字符")
|
||||
@ExcelProperty(value = "消息标题")
|
||||
private String title;
|
||||
|
||||
/** 消息内容 */
|
||||
@NotBlank(message = "消息内容不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@ExcelProperty(value = "消息内容")
|
||||
private String content;
|
||||
|
||||
/** 消息类型(AUTO自动/MANUAL手动) */
|
||||
@NotBlank(message = "消息类型不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@ExcelProperty(value = "消息类型")
|
||||
private String msgType;
|
||||
|
||||
/** 触发条件 */
|
||||
@ExcelProperty(value = "触发条件")
|
||||
private String subType;
|
||||
|
||||
/** 发送者ID */
|
||||
@ExcelProperty(value = "发送者ID")
|
||||
private Long senderId;
|
||||
|
||||
/** 定时发送时间 */
|
||||
@ExcelProperty(value = "定时发送时间")
|
||||
private Date scheduledTime;
|
||||
|
||||
/** 发送范围(all:全部用户, userType:按用户类型, userIds:指定用户) */
|
||||
@NotBlank(message = "发送范围不能为空", groups = { AddGroup.class })
|
||||
private String sendScope;
|
||||
|
||||
/** 接收用户ID列表 */
|
||||
private List<Long> userIds;
|
||||
|
||||
/** 是否发送给所有用户 */
|
||||
private Boolean sendToAll;
|
||||
|
||||
/** 扩展数据(JSON格式) */
|
||||
private String extraData;
|
||||
|
||||
/** 状态(0正常 1停用) */
|
||||
private String status;
|
||||
|
||||
/** 备注 */
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 转换为查询条件
|
||||
*/
|
||||
public LambdaQueryWrapper<SysMessage> toWrapper() {
|
||||
LambdaQueryWrapper<SysMessage> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.like(StringUtils.isNotBlank(this.getTitle()), SysMessage::getTitle, this.getTitle())
|
||||
.eq(StringUtils.isNotBlank(this.getMsgType()), SysMessage::getMsgType, this.getMsgType())
|
||||
.eq(StringUtils.isNotBlank(this.getSubType()), SysMessage::getSubType, this.getSubType())
|
||||
.eq(this.getSenderId() != null, SysMessage::getSenderId, this.getSenderId())
|
||||
// .eq(StringUtils.isNotBlank(this.getStatus()), SysMessage::getStatus, this.getStatus())
|
||||
.orderByDesc(SysMessage::getCreateTime);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为实体对象
|
||||
*/
|
||||
public SysMessage toEntity() {
|
||||
SysMessage entity = new SysMessage();
|
||||
entity.setId(this.getId());
|
||||
entity.setTitle(this.getTitle());
|
||||
entity.setContent(this.getContent());
|
||||
entity.setMsgType(this.getMsgType());
|
||||
entity.setSubType(this.getSubType());
|
||||
entity.setSenderId(this.getSenderId());
|
||||
entity.setScheduledTime(this.getScheduledTime());
|
||||
// entity.setExtraData(this.getExtraData());
|
||||
// entity.setStatus(this.getStatus());
|
||||
// entity.setRemark(this.getRemark());
|
||||
entity.setCreateBy(this.getCreateBy());
|
||||
entity.setCreateTime(this.getCreateTime());
|
||||
entity.setUpdateBy(this.getUpdateBy());
|
||||
entity.setUpdateTime(this.getUpdateTime());
|
||||
return entity;
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
package org.dromara.system.domain.bo;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.dromara.common.core.domain.model.BaseAudit;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.system.domain.SysMessageTemplate;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* 消息模板业务对象
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = SysMessageTemplate.class, reverseConvertGenerate = false)
|
||||
public class SysMessageTemplateBo extends BaseAudit {
|
||||
|
||||
/**
|
||||
* 模板ID
|
||||
*/
|
||||
@NotNull(message = "模板ID不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 模板名称
|
||||
*/
|
||||
@NotBlank(message = "模板名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@Size(max = 100, message = "模板名称长度不能超过{max}个字符")
|
||||
private String templateName;
|
||||
|
||||
/**
|
||||
* 模板编码
|
||||
*/
|
||||
@NotBlank(message = "模板编码不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@Size(max = 50, message = "模板编码长度不能超过{max}个字符")
|
||||
private String templateCode;
|
||||
|
||||
/**
|
||||
* 模板类型(SMS=短信 MAIL=邮件 WECHAT=微信 SYSTEM=系统消息)
|
||||
*/
|
||||
@NotBlank(message = "模板类型不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@Size(max = 20, message = "模板类型长度不能超过{max}个字符")
|
||||
private String templateType;
|
||||
|
||||
/**
|
||||
* 模板内容
|
||||
*/
|
||||
@NotBlank(message = "模板内容不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String templateContent;
|
||||
|
||||
/**
|
||||
* 状态(0正常 1停用)
|
||||
*/
|
||||
private String status;
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
private String title;
|
||||
// /**
|
||||
// * 备注
|
||||
// */
|
||||
// private String remark;
|
||||
|
||||
/**
|
||||
* 将当前对象转换为查询条件
|
||||
*/
|
||||
public LambdaQueryWrapper<SysMessageTemplate> toWrapper() {
|
||||
LambdaQueryWrapper<SysMessageTemplate> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.like(StringUtils.isNotBlank(templateName), SysMessageTemplate::getTemplateName, templateName)
|
||||
.like(StringUtils.isNotBlank(templateCode), SysMessageTemplate::getTemplateCode, templateCode)
|
||||
.eq(StringUtils.isNotBlank(templateType), SysMessageTemplate::getTemplateType, templateType)
|
||||
.eq(StringUtils.isNotBlank(status), SysMessageTemplate::getStatus, status)
|
||||
.orderByDesc(SysMessageTemplate::getCreateTime);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为实体对象
|
||||
*/
|
||||
public SysMessageTemplate toEntity() {
|
||||
SysMessageTemplate entity = new SysMessageTemplate();
|
||||
entity.setId(id);
|
||||
entity.setTemplateName(templateName);
|
||||
entity.setTemplateCode(templateCode);
|
||||
entity.setTemplateType(templateType);
|
||||
entity.setTemplateContent(templateContent);
|
||||
entity.setStatus(status);
|
||||
entity.setTitle(title);
|
||||
// entity.setRemark(remark);
|
||||
return entity;
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package org.dromara.system.domain.event;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.dromara.system.domain.vo.SysMessageVo;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* 消息事件
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Getter
|
||||
public class MessageEvent extends ApplicationEvent {
|
||||
|
||||
private final SysMessageVo message;
|
||||
private final Long userId;
|
||||
|
||||
public MessageEvent(Object source, SysMessageVo message, Long userId) {
|
||||
super(source);
|
||||
this.message = message;
|
||||
this.userId = userId;
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package org.dromara.system.domain.vo;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
import org.dromara.system.domain.SysMessage;
|
||||
import org.dromara.system.domain.SysMessageTemplate;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 消息模板视图对象 sys_message_template
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Data
|
||||
@AutoMapper(target = SysMessageTemplate.class)
|
||||
public class SysMessageTemplateVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 模板ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 模板类型(1通知 2公告 3消息)
|
||||
*/
|
||||
private String templateType;
|
||||
|
||||
/**
|
||||
* 模板编码
|
||||
*/
|
||||
private String templateCode;
|
||||
|
||||
/**
|
||||
* 模板名称
|
||||
*/
|
||||
private String templateName;
|
||||
|
||||
/**
|
||||
* 模板内容
|
||||
*/
|
||||
private String templateContent;
|
||||
|
||||
// /**
|
||||
// * 模板参数
|
||||
// */
|
||||
// private String templateParams;
|
||||
|
||||
/**
|
||||
* 状态(0正常 1停用)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
// /**
|
||||
// * 备注
|
||||
// */
|
||||
// private String remark;
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package org.dromara.system.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 消息用户关联视图对象 sys_message_user
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Data
|
||||
//@EqualsAndHashCode(callSuper = true)
|
||||
public class SysMessageUserVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 消息ID
|
||||
*/
|
||||
private Long messageId;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 是否已读(0未读 1已读)
|
||||
*/
|
||||
private Boolean isRead;
|
||||
|
||||
/**
|
||||
* 阅读时间
|
||||
*/
|
||||
private Date readTime;
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package org.dromara.system.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.system.domain.SysMessage;
|
||||
import org.dromara.system.domain.SysNotice;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 消息视图对象
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Data
|
||||
@AutoMapper(target = SysMessage.class)
|
||||
public class SysMessageVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键ID */
|
||||
@ExcelProperty(value = "消息ID")
|
||||
private Long id;
|
||||
|
||||
/** 消息标题 */
|
||||
@ExcelProperty(value = "消息标题")
|
||||
private String title;
|
||||
|
||||
/** 消息内容 */
|
||||
@ExcelProperty(value = "消息内容")
|
||||
private String content;
|
||||
|
||||
/** 消息类型(AUTO自动/MANUAL手动) */
|
||||
@ExcelProperty(value = "消息类型")
|
||||
private String msgType;
|
||||
|
||||
/** 触发条件 */
|
||||
@ExcelProperty(value = "触发条件")
|
||||
private String subType;
|
||||
|
||||
/** 发送者ID */
|
||||
@ExcelProperty(value = "发送者ID")
|
||||
private Long senderId;
|
||||
|
||||
/** 发送者名称 */
|
||||
@ExcelProperty(value = "发送者")
|
||||
private String senderName;
|
||||
|
||||
/** 定时发送时间 */
|
||||
@ExcelProperty(value = "定时发送时间")
|
||||
private Date scheduledTime;
|
||||
|
||||
// /** 状态(0正常 1停用) */
|
||||
// @ExcelProperty(value = "状态")
|
||||
// private String status;
|
||||
|
||||
/** 创建时间 */
|
||||
@ExcelProperty(value = "创建时间")
|
||||
private Date createTime;
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package org.dromara.system.event;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.system.domain.event.MessageEvent;
|
||||
import org.dromara.system.websocket.MessageWebSocketServer;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 消息事件监听器
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class MessageEventListener {
|
||||
|
||||
private final MessageWebSocketServer messageWebSocketServer;
|
||||
|
||||
/**
|
||||
* 处理消息事件
|
||||
*/
|
||||
@Async
|
||||
@EventListener
|
||||
public void handleMessageEvent(MessageEvent event) {
|
||||
try {
|
||||
messageWebSocketServer.sendMessage(event.getUserId(), String.valueOf(event.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("处理消息事件失败", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package org.dromara.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.dromara.system.domain.SysMessage;
|
||||
import org.dromara.system.domain.vo.SysMessageVo;
|
||||
|
||||
/**
|
||||
* 消息Mapper接口
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public interface SysMessageMapper extends BaseMapper<SysMessage> {
|
||||
|
||||
/**
|
||||
* 查询用户未读消息分页列表
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param userId 用户ID
|
||||
* @return 消息分页列表
|
||||
*/
|
||||
Page<SysMessageVo> selectPageUnreadMessages(Page<SysMessageVo> page, Long userId);
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package org.dromara.system.mapper;
|
||||
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.system.domain.SysMessageTemplate;
|
||||
import org.dromara.system.domain.vo.SysMessageTemplateVo;
|
||||
|
||||
/**
|
||||
* 消息模板Mapper接口
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public interface SysMessageTemplateMapper extends BaseMapperPlus<SysMessageTemplate, SysMessageTemplateVo> {
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package org.dromara.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.system.domain.SysMessageUser;
|
||||
import org.dromara.system.domain.vo.SysMessageUserVo;
|
||||
|
||||
/**
|
||||
* 消息用户关联Mapper接口
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public interface SysMessageUserMapper extends BaseMapperPlus<SysMessageUser, SysMessageUserVo> {
|
||||
|
||||
/**
|
||||
* 更新消息读取状态
|
||||
*
|
||||
* @param messageId 消息ID
|
||||
* @param userId 用户ID
|
||||
* @param isRead 是否已读
|
||||
* @return 结果
|
||||
*/
|
||||
default int updateReadStatus(Long messageId, Long userId, boolean isRead) {
|
||||
LambdaQueryWrapper<SysMessageUser> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(SysMessageUser::getMessageId, messageId)
|
||||
.eq(SysMessageUser::getUserId, userId);
|
||||
SysMessageUser messageUser = new SysMessageUser();
|
||||
messageUser.setIsRead(isRead);
|
||||
return update(messageUser, lqw);
|
||||
}
|
||||
}
|
@ -120,4 +120,19 @@ public interface SysUserMapper extends BaseMapperPlus<SysUser, SysUserVo> {
|
||||
})
|
||||
int updateById(@Param(Constants.ENTITY) SysUser user);
|
||||
|
||||
/**
|
||||
* 根据用户类型查询用户ID列表
|
||||
*
|
||||
* @param userType 用户类型
|
||||
* @return 用户ID列表
|
||||
*/
|
||||
List<Long> selectUserIdsByType(@Param("userType") String userType);
|
||||
|
||||
/**
|
||||
* 查询所有用户ID
|
||||
*
|
||||
* @return 用户ID列表
|
||||
*/
|
||||
List<Long> selectAllUserIds();
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
package org.dromara.system.service;
|
||||
|
||||
import org.dromara.system.domain.vo.SysMessageVo;
|
||||
|
||||
/**
|
||||
* WebSocket消息服务接口
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public interface IMessageWebSocketService {
|
||||
|
||||
/**
|
||||
* 发送消息给指定用户
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param message 消息内容
|
||||
*/
|
||||
void sendMessage(Long userId, SysMessageVo message);
|
||||
|
||||
/**
|
||||
* 广播消息给所有在线用户
|
||||
*
|
||||
* @param message 消息内容
|
||||
*/
|
||||
void broadcastMessage(SysMessageVo message);
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
package org.dromara.system.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.system.domain.SysMessage;
|
||||
import org.dromara.system.domain.bo.SysMessageBo;
|
||||
import org.dromara.system.domain.vo.SysMessageVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息Service接口
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public interface ISysMessageService extends IService<SysMessage> {
|
||||
|
||||
/**
|
||||
* 分页查询消息列表
|
||||
*/
|
||||
TableDataInfo<SysMessageVo> selectPageMessageList(SysMessageBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询未读消息分页(Page方式)
|
||||
*/
|
||||
Page<SysMessageVo> selectUnreadMessagesPage(Long userId, Page<SysMessage> page);
|
||||
|
||||
/**
|
||||
* 查询已读消息分页(Page方式)
|
||||
*/
|
||||
Page<SysMessageVo> selectReadMessagesPage(Long userId, Page<SysMessage> page);
|
||||
|
||||
/**
|
||||
* 发送消息给指定用户
|
||||
*
|
||||
* @param message 消息内容
|
||||
* @param userId 用户ID
|
||||
* @return 结果
|
||||
*/
|
||||
int sendMessageToUser(SysMessageBo message, Long userId);
|
||||
|
||||
/**
|
||||
* 发送消息给多个用户
|
||||
*
|
||||
* @param message 消息内容
|
||||
* @param userIds 用户ID列表
|
||||
* @return 结果
|
||||
*/
|
||||
int sendMessageToUsers(SysMessageBo message, List<Long> userIds);
|
||||
|
||||
/**
|
||||
* 发送自动消息
|
||||
*
|
||||
* @param message 消息信息
|
||||
* @param userIds 用户ID列表
|
||||
* @return 结果
|
||||
*/
|
||||
int sendAutoMessage(SysMessageBo message, List<Long> userIds);
|
||||
|
||||
/**
|
||||
* 标记消息为已读
|
||||
*
|
||||
* @param messageId 消息ID
|
||||
* @param userId 用户ID
|
||||
* @return 结果
|
||||
*/
|
||||
int markAsRead(Long messageId, Long userId);
|
||||
|
||||
/**
|
||||
* 查询用户未读消息分页列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param pageQuery 分页参数
|
||||
* @return 消息分页列表
|
||||
*/
|
||||
TableDataInfo<SysMessageVo> selectPageUnreadMessages(Long userId, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询用户已读消息分页列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param pageQuery 分页参数
|
||||
* @return 消息分页列表
|
||||
*/
|
||||
TableDataInfo<SysMessageVo> selectPageReadMessages(Long userId, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询消息列表
|
||||
*
|
||||
* @param message 消息信息
|
||||
* @return 消息列表
|
||||
*/
|
||||
List<SysMessageVo> selectMessageList(SysMessageBo message);
|
||||
|
||||
/**
|
||||
* 查询消息详细信息
|
||||
*
|
||||
* @param id 消息ID
|
||||
* @return 消息信息
|
||||
*/
|
||||
SysMessageVo selectMessageById(Long id);
|
||||
|
||||
/**
|
||||
* 新增消息
|
||||
*
|
||||
* @param message 消息信息
|
||||
* @return 结果
|
||||
*/
|
||||
int insertMessage(SysMessageBo message);
|
||||
|
||||
/**
|
||||
* 修改消息
|
||||
*
|
||||
* @param message 消息信息
|
||||
* @return 结果
|
||||
*/
|
||||
int updateMessage(SysMessageBo message);
|
||||
|
||||
/**
|
||||
* 批量删除消息
|
||||
*
|
||||
* @param ids 需要删除的消息ID数组
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteMessageByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 删除消息信息
|
||||
*
|
||||
* @param id 消息ID
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteMessageById(Long id);
|
||||
|
||||
/**
|
||||
* 将BO对象转换为查询条件
|
||||
*
|
||||
* @param bo 业务对象
|
||||
* @return 查询条件
|
||||
*/
|
||||
LambdaQueryWrapper<SysMessage> toWrapper(SysMessageBo bo);
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package org.dromara.system.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.system.domain.SysMessageTemplate;
|
||||
import org.dromara.system.domain.bo.SysMessageTemplateBo;
|
||||
import org.dromara.system.domain.vo.SysMessageTemplateVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息模板Service接口
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public interface ISysMessageTemplateService extends IService<SysMessageTemplate> {
|
||||
|
||||
/**
|
||||
* 查询消息模板列表
|
||||
*
|
||||
* @param template 消息模板信息
|
||||
* @return 消息模板列表
|
||||
*/
|
||||
List<SysMessageTemplateVo> selectTemplateList(SysMessageTemplateBo template);
|
||||
|
||||
/**
|
||||
* 查询消息模板分页列表
|
||||
*
|
||||
* @param template 消息模板信息
|
||||
* @param pageQuery 分页参数
|
||||
* @return 消息模板分页列表
|
||||
*/
|
||||
TableDataInfo<SysMessageTemplateVo> selectTemplatePage(SysMessageTemplateBo template, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询消息模板详细信息
|
||||
*
|
||||
* @param id 消息模板ID
|
||||
* @return 消息模板信息
|
||||
*/
|
||||
SysMessageTemplateVo selectTemplateById(Long id);
|
||||
|
||||
/**
|
||||
* 新增消息模板
|
||||
*
|
||||
* @param template 消息模板信息
|
||||
* @return 结果
|
||||
*/
|
||||
int insertTemplate(SysMessageTemplateBo template);
|
||||
|
||||
/**
|
||||
* 修改消息模板
|
||||
*
|
||||
* @param template 消息模板信息
|
||||
* @return 结果
|
||||
*/
|
||||
int updateTemplate(SysMessageTemplateBo template);
|
||||
|
||||
/**
|
||||
* 批量删除消息模板
|
||||
*
|
||||
* @param ids 需要删除的消息模板ID数组
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteTemplateByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 删除消息模板信息
|
||||
*
|
||||
* @param id 消息模板ID
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteTemplateById(Long id);
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package org.dromara.system.service.impl;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.system.domain.vo.SysMessageVo;
|
||||
import org.dromara.system.service.IMessageWebSocketService;
|
||||
import org.dromara.system.websocket.MessageWebSocketServer;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* WebSocket消息服务实现类
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class MessageWebSocketServiceImpl implements IMessageWebSocketService {
|
||||
|
||||
private final MessageWebSocketServer messageWebSocketServer;
|
||||
|
||||
@Override
|
||||
public void sendMessage(Long userId, SysMessageVo message) {
|
||||
messageWebSocketServer.sendMessage(userId, String.valueOf(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastMessage(SysMessageVo message) {
|
||||
messageWebSocketServer.broadcastMessage(String.valueOf(message));
|
||||
}
|
||||
}
|
@ -0,0 +1,208 @@
|
||||
package org.dromara.system.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.system.domain.SysMessage;
|
||||
import org.dromara.system.domain.SysMessageUser;
|
||||
import org.dromara.system.domain.bo.SysMessageBo;
|
||||
import org.dromara.system.domain.event.MessageEvent;
|
||||
import org.dromara.system.domain.vo.SysMessageVo;
|
||||
import org.dromara.system.mapper.SysMessageMapper;
|
||||
import org.dromara.system.mapper.SysMessageUserMapper;
|
||||
import org.dromara.system.service.ISysMessageService;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息Service业务层处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SysMessageServiceImpl extends ServiceImpl<SysMessageMapper, SysMessage> implements ISysMessageService {
|
||||
|
||||
private final SysMessageMapper messageMapper;
|
||||
private final SysMessageUserMapper messageUserMapper;
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@Override
|
||||
public TableDataInfo<SysMessageVo> selectPageMessageList(SysMessageBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<SysMessage> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.like(StringUtils.isNotBlank(bo.getTitle()), SysMessage::getTitle, bo.getTitle())
|
||||
.eq(StringUtils.isNotBlank(bo.getMsgType()), SysMessage::getMsgType, bo.getMsgType())
|
||||
// .eq(StringUtils.isNotBlank(bo.getStatus()), SysMessage::getStatus, bo.getStatus())
|
||||
.orderByDesc(SysMessage::getCreateTime);
|
||||
Page<SysMessage> page = messageMapper.selectPage(pageQuery.build(), lqw);
|
||||
List<SysMessageVo> records = MapstructUtils.convert(page.getRecords(), SysMessageVo.class);
|
||||
Page<SysMessageVo> voPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
|
||||
voPage.setRecords(records);
|
||||
return TableDataInfo.build(voPage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<SysMessageVo> selectUnreadMessagesPage(Long userId, Page<SysMessage> page) {
|
||||
LambdaQueryWrapper<SysMessage> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.inSql(SysMessage::getId,
|
||||
"SELECT message_id FROM sys_message_user WHERE user_id = " + userId + " AND is_read = 0")
|
||||
.orderByDesc(SysMessage::getCreateTime);
|
||||
|
||||
Page<SysMessage> messagePage = messageMapper.selectPage(page, lqw);
|
||||
Page<SysMessageVo> voPage = new Page<>(messagePage.getCurrent(), messagePage.getSize(), messagePage.getTotal());
|
||||
voPage.setRecords(MapstructUtils.convert(messagePage.getRecords(), SysMessageVo.class));
|
||||
return voPage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<SysMessageVo> selectReadMessagesPage(Long userId, Page<SysMessage> page) {
|
||||
LambdaQueryWrapper<SysMessage> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.inSql(SysMessage::getId,
|
||||
"SELECT message_id FROM sys_message_user WHERE user_id = " + userId + " AND is_read = 1")
|
||||
.orderByDesc(SysMessage::getCreateTime);
|
||||
|
||||
Page<SysMessage> messagePage = messageMapper.selectPage(page, lqw);
|
||||
Page<SysMessageVo> voPage = new Page<>(messagePage.getCurrent(), messagePage.getSize(), messagePage.getTotal());
|
||||
voPage.setRecords(MapstructUtils.convert(messagePage.getRecords(), SysMessageVo.class));
|
||||
return voPage;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int sendMessageToUser(SysMessageBo message, Long userId) {
|
||||
// 保存消息
|
||||
SysMessage entity = message.toEntity();
|
||||
messageMapper.insert(entity);
|
||||
// 创建消息用户关联
|
||||
SysMessageUser messageUser = new SysMessageUser();
|
||||
messageUser.setMessageId(entity.getId());
|
||||
messageUser.setUserId(userId);
|
||||
messageUser.setIsRead(false);
|
||||
int rows = messageUserMapper.insert(messageUser);
|
||||
// 发送WebSocket消息
|
||||
if (rows > 0) {
|
||||
SysMessageVo messageVo = MapstructUtils.convert(entity, SysMessageVo.class);
|
||||
eventPublisher.publishEvent(new MessageEvent(this, messageVo, userId));
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int sendMessageToUsers(SysMessageBo message, List<Long> userIds) {
|
||||
// 保存消息
|
||||
SysMessage entity = message.toEntity();
|
||||
messageMapper.insert(entity);
|
||||
// 批量创建消息用户关联
|
||||
int count = 0;
|
||||
for (Long userId : userIds) {
|
||||
SysMessageUser messageUser = new SysMessageUser();
|
||||
messageUser.setMessageId(entity.getId());
|
||||
messageUser.setUserId(userId);
|
||||
messageUser.setIsRead(false);
|
||||
int rows = messageUserMapper.insert(messageUser);
|
||||
if (rows > 0) {
|
||||
count++;
|
||||
// 发送WebSocket消息
|
||||
SysMessageVo messageVo = MapstructUtils.convert(entity, SysMessageVo.class);
|
||||
eventPublisher.publishEvent(new MessageEvent(this, messageVo, userId));
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int sendAutoMessage(SysMessageBo message, List<Long> userIds) {
|
||||
message.setMsgType("AUTO");
|
||||
return sendMessageToUsers(message, userIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int markAsRead(Long messageId, Long userId) {
|
||||
LambdaQueryWrapper<SysMessageUser> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.eq(SysMessageUser::getMessageId, messageId)
|
||||
.eq(SysMessageUser::getUserId, userId);
|
||||
SysMessageUser messageUser = new SysMessageUser();
|
||||
messageUser.setIsRead(true);
|
||||
return messageUserMapper.update(messageUser, lqw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<SysMessageVo> selectPageUnreadMessages(Long userId, PageQuery pageQuery) {
|
||||
Page<SysMessageVo> page = messageMapper.selectPageUnreadMessages(pageQuery.build(), userId);
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<SysMessageVo> selectPageReadMessages(Long userId, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<SysMessage> lqw = new LambdaQueryWrapper<>();
|
||||
// lqw.eq(SysMessage::getStatus, "0")
|
||||
// .inSql(SysMessage::getId,
|
||||
// "SELECT message_id FROM sys_message_user WHERE user_id = " + userId + " AND is_read = 1")
|
||||
// .orderByDesc(SysMessage::getCreateTime);
|
||||
//
|
||||
Page<SysMessage> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
|
||||
Page<SysMessage> resultPage = messageMapper.selectPage(page, lqw);
|
||||
List<SysMessageVo> records = MapstructUtils.convert(resultPage.getRecords(), SysMessageVo.class);
|
||||
Page<SysMessageVo> voPage = new Page<>(resultPage.getCurrent(), resultPage.getSize(), resultPage.getTotal());
|
||||
voPage.setRecords(records);
|
||||
return TableDataInfo.build(voPage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SysMessageVo> selectMessageList(SysMessageBo message) {
|
||||
LambdaQueryWrapper<SysMessage> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.eq(StringUtils.isNotBlank(message.getMsgType()), SysMessage::getMsgType, message.getMsgType())
|
||||
.eq(StringUtils.isNotBlank(message.getSubType()), SysMessage::getSubType, message.getSubType())
|
||||
.eq(message.getSenderId() != null, SysMessage::getSenderId, message.getSenderId())
|
||||
// .eq(StringUtils.isNotBlank(message.getStatus()), SysMessage::getStatus, message.getStatus())
|
||||
.orderByDesc(SysMessage::getCreateTime);
|
||||
return MapstructUtils.convert(messageMapper.selectList(lqw), SysMessageVo.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SysMessageVo selectMessageById(Long id) {
|
||||
return MapstructUtils.convert(messageMapper.selectById(id), SysMessageVo.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int insertMessage(SysMessageBo message) {
|
||||
return messageMapper.insert(message.toEntity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateMessage(SysMessageBo message) {
|
||||
return messageMapper.updateById(message.toEntity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteMessageByIds(Long[] ids) {
|
||||
return messageMapper.deleteBatchIds(List.of(ids));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteMessageById(Long id) {
|
||||
return messageMapper.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LambdaQueryWrapper<SysMessage> toWrapper(SysMessageBo bo) {
|
||||
LambdaQueryWrapper<SysMessage> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.like(StringUtils.isNotBlank(bo.getTitle()), SysMessage::getTitle, bo.getTitle())
|
||||
.eq(StringUtils.isNotBlank(bo.getMsgType()), SysMessage::getMsgType, bo.getMsgType())
|
||||
.orderByDesc(SysMessage::getCreateTime);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package org.dromara.system.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.system.domain.SysMessageTemplate;
|
||||
import org.dromara.system.domain.bo.SysMessageTemplateBo;
|
||||
import org.dromara.system.domain.vo.SysMessageTemplateVo;
|
||||
import org.dromara.system.mapper.SysMessageTemplateMapper;
|
||||
import org.dromara.system.service.ISysMessageTemplateService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息模板Service业务层处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class SysMessageTemplateServiceImpl extends ServiceImpl<SysMessageTemplateMapper, SysMessageTemplate> implements ISysMessageTemplateService {
|
||||
|
||||
private final SysMessageTemplateMapper templateMapper;
|
||||
|
||||
@Override
|
||||
public TableDataInfo<SysMessageTemplateVo> selectTemplatePage(SysMessageTemplateBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<SysMessageTemplate> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getTemplateType()), SysMessageTemplate::getTemplateType, bo.getTemplateType())
|
||||
// .eq(StringUtils.isNotBlank(bo.getStatus()), SysMessageTemplate::getStatus, bo.getStatus())
|
||||
.like(StringUtils.isNotBlank(bo.getTemplateName()), SysMessageTemplate::getTemplateName, bo.getTemplateName())
|
||||
.like(StringUtils.isNotBlank(bo.getTemplateCode()), SysMessageTemplate::getTemplateCode, bo.getTemplateCode())
|
||||
.orderByDesc(SysMessageTemplate::getCreateTime);
|
||||
|
||||
Page<SysMessageTemplate> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
|
||||
Page<SysMessageTemplate> resultPage = templateMapper.selectPage(page, lqw);
|
||||
List<SysMessageTemplateVo> records = MapstructUtils.convert(resultPage.getRecords(), SysMessageTemplateVo.class);
|
||||
Page<SysMessageTemplateVo> voPage = new Page<>(resultPage.getCurrent(), resultPage.getSize(), resultPage.getTotal());
|
||||
voPage.setRecords(records);
|
||||
return TableDataInfo.build(voPage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SysMessageTemplateVo> selectTemplateList(SysMessageTemplateBo bo) {
|
||||
LambdaQueryWrapper<SysMessageTemplate> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getTemplateType()), SysMessageTemplate::getTemplateType, bo.getTemplateType())
|
||||
// .eq(StringUtils.isNotBlank(bo.getStatus()), SysMessageTemplate::getStatus, bo.getStatus())
|
||||
.like(StringUtils.isNotBlank(bo.getTemplateName()), SysMessageTemplate::getTemplateName, bo.getTemplateName())
|
||||
.like(StringUtils.isNotBlank(bo.getTemplateCode()), SysMessageTemplate::getTemplateCode, bo.getTemplateCode())
|
||||
.orderByDesc(SysMessageTemplate::getCreateTime);
|
||||
return MapstructUtils.convert(templateMapper.selectList(lqw), SysMessageTemplateVo.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SysMessageTemplateVo selectTemplateById(Long id) {
|
||||
return MapstructUtils.convert(templateMapper.selectById(id), SysMessageTemplateVo.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int insertTemplate(SysMessageTemplateBo bo) {
|
||||
return templateMapper.insert(bo.toEntity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateTemplate(SysMessageTemplateBo bo) {
|
||||
return templateMapper.updateById(bo.toEntity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteTemplateByIds(Long[] ids) {
|
||||
return templateMapper.deleteBatchIds(List.of(ids));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteTemplateById(Long id) {
|
||||
return templateMapper.deleteById(id);
|
||||
}
|
||||
}
|
@ -179,7 +179,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
|
||||
for (SysDictType dictType : dictTypeList) {
|
||||
dictType.setDictId(null);
|
||||
dictType.setTenantId(tenantId);
|
||||
dictType.setCreateDept(null);
|
||||
// dictType.setCreateDept(null);
|
||||
dictType.setCreateBy(null);
|
||||
dictType.setCreateTime(null);
|
||||
dictType.setUpdateBy(null);
|
||||
@ -188,7 +188,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
|
||||
for (SysDictData dictData : dictDataList) {
|
||||
dictData.setDictCode(null);
|
||||
dictData.setTenantId(tenantId);
|
||||
dictData.setCreateDept(null);
|
||||
// dictData.setCreateDept(null);
|
||||
dictData.setCreateBy(null);
|
||||
dictData.setCreateTime(null);
|
||||
dictData.setUpdateBy(null);
|
||||
@ -202,7 +202,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
|
||||
for (SysConfig config : sysConfigList) {
|
||||
config.setConfigId(null);
|
||||
config.setTenantId(tenantId);
|
||||
config.setCreateDept(null);
|
||||
// config.setCreateDept(null);
|
||||
config.setCreateBy(null);
|
||||
config.setCreateTime(null);
|
||||
config.setUpdateBy(null);
|
||||
@ -448,7 +448,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
|
||||
data.setTenantId(tenantId);
|
||||
data.setCreateTime(null);
|
||||
data.setUpdateTime(null);
|
||||
data.setCreateDept(null);
|
||||
// data.setCreateDept(null);
|
||||
data.setCreateBy(null);
|
||||
data.setUpdateBy(null);
|
||||
set.add(tenantId);
|
||||
@ -472,7 +472,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
|
||||
data.setTenantId(tenantId);
|
||||
data.setCreateTime(null);
|
||||
data.setUpdateTime(null);
|
||||
data.setCreateDept(null);
|
||||
// data.setCreateDept(null);
|
||||
data.setCreateBy(null);
|
||||
data.setUpdateBy(null);
|
||||
set.add(tenantId);
|
||||
|
@ -0,0 +1,78 @@
|
||||
package org.dromara.system.task;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.system.domain.SysMessage;
|
||||
//import org.dromara.system.domain.SysMessageUser;
|
||||
import org.dromara.system.domain.SysMessageUser;
|
||||
import org.dromara.system.domain.vo.SysMessageVo;
|
||||
import org.dromara.system.mapper.SysMessageMapper;
|
||||
//import org.dromara.system.mapper.SysMessageUserMapper
|
||||
import org.dromara.system.mapper.SysMessageUserMapper;
|
||||
import org.dromara.system.websocket.MessageWebSocketServer;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息定时任务
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class MessageScheduledTask {
|
||||
|
||||
private final SysMessageMapper messageMapper;
|
||||
private final SysMessageUserMapper messageUserMapper;
|
||||
private final MessageWebSocketServer messageWebSocketServer;
|
||||
|
||||
/**
|
||||
* 每分钟执行一次,处理待发送的消息
|
||||
*/
|
||||
@Scheduled(cron = "0 */1 * * * ?")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void processScheduledMessages() {
|
||||
log.info("开始处理定时消息...");
|
||||
try {
|
||||
// 查询待发送的消息
|
||||
LambdaQueryWrapper<SysMessage> lqw = new LambdaQueryWrapper<>();
|
||||
// lqw.eq(SysMessage::getStatus, "0")
|
||||
// .le(SysMessage::getScheduledTime, LocalDateTime.now())
|
||||
// .isNotNull(SysMessage::getScheduledTime);
|
||||
|
||||
List<SysMessage> messages = messageMapper.selectList(lqw);
|
||||
|
||||
for (SysMessage message : messages) {
|
||||
// 查询消息接收者
|
||||
LambdaQueryWrapper<SysMessageUser> userLqw = new LambdaQueryWrapper<>();
|
||||
userLqw.eq(SysMessageUser::getMessageId, message.getId());
|
||||
List<SysMessageUser> messageUsers = messageUserMapper.selectList(userLqw);
|
||||
|
||||
// 发送消息
|
||||
SysMessageVo messageVo = MapstructUtils.convert(message, SysMessageVo.class);
|
||||
for (SysMessageUser messageUser : messageUsers) {
|
||||
try {
|
||||
messageWebSocketServer.sendMessage(messageUser.getUserId(), String.valueOf(messageVo));
|
||||
} catch (Exception e) {
|
||||
log.error("发送消息失败,消息ID:{},用户ID:{}", message.getId(), messageUser.getUserId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新消息状态为已发送
|
||||
// message.setStatus("1");
|
||||
messageMapper.updateById(message);
|
||||
}
|
||||
|
||||
log.info("定时消息处理完成,共处理{}条消息", messages.size());
|
||||
} catch (Exception e) {
|
||||
log.error("处理定时消息时发生错误", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
package org.dromara.system.websocket;
|
||||
|
||||
import jakarta.websocket.*;
|
||||
import jakarta.websocket.server.ServerEndpoint;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.domain.model.LoginUser;
|
||||
import org.dromara.common.websocket.holder.WebSocketSessionHolder;
|
||||
import org.dromara.common.websocket.utils.WebSocketUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 站内信 WebSocket 服务
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@ServerEndpoint("/websocket/message")
|
||||
public class MessageWebSocketServer {
|
||||
|
||||
/**
|
||||
* 用户ID和会话的映射关系
|
||||
*/
|
||||
private static final Map<Long, Session> SESSION_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 连接建立成功调用的方法
|
||||
*/
|
||||
@OnOpen
|
||||
public void onOpen(Session session) {
|
||||
log.info("[WebSocket] 新的连接建立,sessionId: {}", session.getId());
|
||||
try {
|
||||
// 获取当前登录用户
|
||||
LoginUser loginUser = (LoginUser) session.getUserProperties().get("loginUser");
|
||||
if (loginUser != null) {
|
||||
SESSION_MAP.put(loginUser.getUserId(), session);
|
||||
log.info("[WebSocket] 用户 {} 连接成功", loginUser.getUserId());
|
||||
} else {
|
||||
log.warn("[WebSocket] 未获取到用户信息,关闭连接");
|
||||
session.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("[WebSocket] 连接建立失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接关闭调用的方法
|
||||
*/
|
||||
@OnClose
|
||||
public void onClose(Session session) {
|
||||
log.info("[WebSocket] 连接关闭,sessionId: {}", session.getId());
|
||||
// 从映射中移除会话
|
||||
SESSION_MAP.values().removeIf(s -> s.getId().equals(session.getId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 收到客户端消息后调用的方法
|
||||
*/
|
||||
@OnMessage
|
||||
public void onMessage(String message, Session session) {
|
||||
log.info("[WebSocket] 收到消息: {}", message);
|
||||
// 这里可以处理客户端发送的消息
|
||||
}
|
||||
|
||||
/**
|
||||
* 发生错误时调用
|
||||
*/
|
||||
@OnError
|
||||
public void onError(Session session, Throwable error) {
|
||||
log.error("[WebSocket] 发生错误", error);
|
||||
// 从映射中移除会话
|
||||
SESSION_MAP.values().removeIf(s -> s.getId().equals(session.getId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息给指定用户
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param message 消息内容
|
||||
*/
|
||||
public void sendMessage(Long userId, String message) {
|
||||
Session session = SESSION_MAP.get(userId);
|
||||
if (session != null && session.isOpen()) {
|
||||
try {
|
||||
session.getBasicRemote().sendText(message);
|
||||
log.info("[WebSocket] 消息发送成功,接收者: {}", userId);
|
||||
} catch (IOException e) {
|
||||
log.error("[WebSocket] 消息发送失败", e);
|
||||
}
|
||||
} else {
|
||||
log.warn("[WebSocket] 用户 {} 不在线或会话已关闭", userId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 广播消息给所有在线用户
|
||||
*
|
||||
* @param message 消息内容
|
||||
*/
|
||||
public void broadcastMessage(String message) {
|
||||
SESSION_MAP.forEach((userId, session) -> {
|
||||
if (session.isOpen()) {
|
||||
try {
|
||||
session.getBasicRemote().sendText(message);
|
||||
log.info("[WebSocket] 广播消息发送成功,接收者: {}", userId);
|
||||
} catch (IOException e) {
|
||||
log.error("[WebSocket] 广播消息发送失败,接收者: {}", userId, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
java包使用 `.` 分割 resource 目录使用 `/` 分割
|
||||
<br>
|
||||
此文件目的 防止文件夹粘连找不到 `xml` 文件
|
@ -0,0 +1,32 @@
|
||||
<?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="org.dromara.system.mapper.SysMessageMapper">
|
||||
|
||||
<resultMap type="org.dromara.system.domain.vo.SysMessageVo" id="SysMessageResult">
|
||||
<id property="id" column="id" />
|
||||
<result property="title" column="title" />
|
||||
<result property="content" column="content" />
|
||||
<result property="msgType" column="msg_type" />
|
||||
<result property="subType" column="sub_type" />
|
||||
<result property="senderId" column="sender_id" />
|
||||
<result property="scheduledTime" column="scheduled_time"/>
|
||||
<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" />
|
||||
</resultMap>
|
||||
|
||||
<select id="selectPageUnreadMessages" resultMap="SysMessageResult">
|
||||
SELECT m.*
|
||||
FROM sys_message m
|
||||
INNER JOIN sys_message_user mu ON m.id = mu.message_id
|
||||
WHERE mu.user_id = #{userId}
|
||||
AND mu.is_read = 0
|
||||
AND m.status = '0'
|
||||
ORDER BY m.create_time DESC
|
||||
</select>
|
||||
|
||||
</mapper>
|
@ -0,0 +1,33 @@
|
||||
<?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="org.dromara.system.mapper.SysMessageUserMapper">
|
||||
|
||||
<resultMap type="org.dromara.system.domain.vo.SysMessageUserVo" id="SysMessageUserResult">
|
||||
<id property="id" column="id" />
|
||||
<result property="messageId" column="message_id" />
|
||||
<result property="userId" column="user_id" />
|
||||
<result property="isRead" column="is_read" />
|
||||
<result property="readTime" column="read_time" />
|
||||
<!-- <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="tenantId" column="tenant_id" />-->
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectSysMessageUserVo">
|
||||
select id, message_id, user_id, is_read, read_time, create_time, update_time
|
||||
from sys_message_user
|
||||
</sql>
|
||||
|
||||
<update id="updateReadStatus">
|
||||
update sys_message_user
|
||||
set is_read = #{isRead},
|
||||
read_time = sysdate()
|
||||
where message_id = #{messageId}
|
||||
and user_id = #{userId}
|
||||
</update>
|
||||
|
||||
</mapper>
|
@ -69,5 +69,19 @@
|
||||
select count(*) from sys_user where del_flag = '0' and user_id = #{userId}
|
||||
</select>
|
||||
|
||||
<select id="selectUserIdsByType" resultType="java.lang.Long">
|
||||
select user_id
|
||||
from sys_user
|
||||
where user_type = #{userType}
|
||||
and del_flag = '0'
|
||||
and status = '0'
|
||||
</select>
|
||||
|
||||
<select id="selectAllUserIds" resultType="java.lang.Long">
|
||||
select user_id
|
||||
from sys_user
|
||||
where del_flag = '0'
|
||||
and status = '0'
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
Loading…
x
Reference in New Issue
Block a user