初始化项目

This commit is contained in:
easonzhu 2025-01-27 21:47:33 +08:00
commit 329f071e09
771 changed files with 83248 additions and 0 deletions

12
.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
*.log

155
pom.xml Normal file
View File

@ -0,0 +1,155 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>AdvisorServer</artifactId>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.7</version>
<relativePath/>
</parent>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1.1-jre</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.2.0.Final</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-all</artifactId>
<version>4.2.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<!--https://doc.xiaominfo.com/knife4j/documentation/-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.2.1</version>
</dependency>
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
<version>1.27.2</version>
</dependency>
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.3</version>
</dependency>
<dependency>
<groupId>org.ahocorasick</groupId>
<artifactId>ahocorasick</artifactId>
<version>0.6.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java</artifactId>
<!-- go to https://search.maven.org/search?q=tencentcloud-sdk-java and get the latest version. -->
<!-- 请到https://search.maven.org/search?q=tencentcloud-sdk-java查询所有版本最新版本如下 -->
<version>3.1.1142</version>
</dependency>
<!-- websocket -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>5.3.23</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>5.3.23</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.66</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,25 @@
package com.taf.server.startup;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import java.io.File;
@ComponentScan("com.upchina")
@SpringBootApplication
@EnableCaching
@EnableTransactionManagement
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
@EnableAsync
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}

View File

@ -0,0 +1,56 @@
package com.upchina.advisor.constant;
import com.upchina.common.handler.BizException;
import com.upchina.common.result.ResponseStatus;
import java.util.Arrays;
import java.util.Optional;
public enum AdvisorInfoStatus {
INIT(1, "未提交"),
TO_AUDIT(2, "待审核"),
PASS(3, "已上架"),
REJECTED(4, "已驳回"),
SOLD_OUT(5, "已下架"),
// 动作
EVENT_UPDATE(100, "编辑"),
EVENT_SUBMIT(101, "提交"),
EVENT_PASS(103, "通过"),
EVENT_REJECT(104, "驳回"),
EVENT_PUT_ON(105, "上架"),
EVENT_SOLD_OUT(106, "下架"),
;
public final Integer value;
public final String name;
AdvisorInfoStatus(Integer value, String name) {
this.value = value;
this.name = name;
}
public static AdvisorInfoStatus fromValue(Integer value) {
Optional<AdvisorInfoStatus> optional = Arrays.stream(AdvisorInfoStatus.values()).filter(s -> s.value.equals(value)).findFirst();
if (!optional.isPresent()) {
throw new BizException(ResponseStatus.PARM_ERROR, "状态值:" + value + "不存在");
}
return optional.get();
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
@Override
public String toString() {
return this.name + ":" + this.value;
}
}

View File

@ -0,0 +1,17 @@
package com.upchina.advisor.constant;
public enum FollowChannel {
OTHER_CHANNEL(1, "其它渠道"),
VIDEO_CHANNEL(2, "视频直播"),
;
public final Integer value;
public final String name;
FollowChannel(Integer value, String name) {
this.value = value;
this.name = name;
}
}

View File

@ -0,0 +1,26 @@
package com.upchina.advisor.constant;
public enum FollowOption {
FOLLOW(1, "关注"),
UN_FOLLOW(2, "取消关注"),
;
public final Integer value;
public final String name;
FollowOption(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,129 @@
package com.upchina.advisor.controller;
import com.upchina.advisor.query.*;
import com.upchina.advisor.service.AdvisorInfoService;
import com.upchina.advisor.vo.AdvisorBasicVO;
import com.upchina.advisor.vo.AdvisorInfoAdminVO;
import com.upchina.advisor.vo.AdvisorInfoAppVO;
import com.upchina.common.annotation.Auth;
import com.upchina.common.annotation.Operation;
import com.upchina.common.constant.AccessRole;
import com.upchina.common.constant.ProductType;
import com.upchina.common.handler.BizException;
import com.upchina.common.result.AppPager;
import com.upchina.common.result.CommonResult;
import com.upchina.common.result.Pager;
import com.upchina.common.result.ResponseStatus;
import com.upchina.common.vo.BackendUserVO;
import com.upchina.common.vo.CountVO;
import com.upchina.common.vo.FrontUserVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;
/**
* <p>
* 投顾信息 前端控制器
* </p>
*
* @author easonzhu
* @since 2022-08-30
*/
@Api(tags = "投顾信息")
@RestController
public class AdvisorInfoController {
@Resource
private AdvisorInfoService advisorInfoService;
@ApiOperation("后台查询投顾列表")
@PostMapping("/admin/advisor/info/list")
@Auth(role = AccessRole.ALL)
public CommonResult<Pager<AdvisorInfoAdminVO>> list(@Validated @RequestBody @ApiParam(required = true) ListAdvisorInfoQuery query,
@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) {
Pager<AdvisorInfoAdminVO> page = advisorInfoService.list(query, backendUserVO);
return CommonResult.success(page);
}
@ApiOperation("后台查询投顾详情")
@GetMapping("/admin/advisor/info/detail")
@Auth(role = AccessRole.LOGIN)
public CommonResult<AdvisorInfoAdminVO> get(@RequestParam("id") @Validated @NotNull @Min(1) @ApiParam(required = true) Integer id) {
AdvisorInfoAdminVO advisorInfoAdminVO = advisorInfoService.get(id);
return CommonResult.success(advisorInfoAdminVO);
}
@ApiOperation("后台修改投顾信息")
@PostMapping("/admin/advisor/info/update")
@Auth(role = AccessRole.LOGIN)
@Operation(module = ProductType.ADVISOR_INFO)
public CommonResult<Void> update(@Validated @RequestBody @ApiParam(required = true) UpdateAdvisorInfoQuery query,
@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) {
advisorInfoService.update(query, backendUserVO);
return CommonResult.success(null);
}
@ApiOperation("后台修改投顾状态")
@PostMapping("/admin/advisor/info/updateStatus")
@Auth(role = AccessRole.LOGIN)
@Operation(module = ProductType.ADVISOR_INFO, statusKey = "event")
public CommonResult<Void> updateStatus(@Validated @RequestBody @ApiParam(required = true) UpdateAdvisorInfoStatusQuery query,
@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) {
advisorInfoService.updateStatus(query, backendUserVO);
return CommonResult.success(null);
}
@ApiOperation("APP查询投顾列表")
@PostMapping("/app/advisor/info/list")
public CommonResult<AppPager<AdvisorInfoAppVO>> listForApp(@Validated @RequestBody @ApiParam(required = true) ListAdvisorAppQuery query,
@RequestAttribute("frontUser") FrontUserVO frontUserVO) {
AppPager<AdvisorInfoAppVO> page = advisorInfoService.listForApp(query, frontUserVO);
return CommonResult.success(page);
}
@ApiOperation("APP查询投顾详情")
@GetMapping("/app/advisor/info/get")
public CommonResult<AdvisorInfoAppVO> getForApp(@RequestParam("id") @Validated @NotNull @Min(1) @ApiParam(required = true) Integer id,
@RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) {
String userId = frontUserVO == null ? null : frontUserVO.getUserId();
AdvisorInfoAppVO advisorInfoAppVO = advisorInfoService.getForApp(id, userId);
return CommonResult.success(advisorInfoAppVO);
}
@ApiOperation("APP批量查询投顾/团队基本信息")
@GetMapping("/app/advisor/info/listBasic")
public CommonResult<Map<Integer, AdvisorBasicVO>> listBasicForApp(@RequestParam("ids") @Validated @NotNull @Min(1) @ApiParam(required = true) Integer[] ids) {
Map<Integer, AdvisorBasicVO> map = advisorInfoService.listBasicForApp(ids);
return CommonResult.success(map);
}
@ApiOperation("APP关注投顾")
@PostMapping("/app/advisor/info/follow")
public CommonResult<CountVO> follow(@Validated @RequestBody @ApiParam(required = true) FollowAdvisorAppQuery query,
@RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) {
if (frontUserVO == null) {
throw new BizException(ResponseStatus.SESSION_EXPIRY);
}
CountVO countVO = advisorInfoService.follow(query, frontUserVO.getUserId());
return CommonResult.success(countVO);
}
@ApiOperation("APP获取关注投顾列表")
@GetMapping("/app/advisor/info/listFollow")
public CommonResult<List<AdvisorInfoAppVO>> listFollow(@RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) {
if (frontUserVO == null) {
throw new BizException(ResponseStatus.SESSION_EXPIRY);
}
List<AdvisorInfoAppVO> list = advisorInfoService.listFollow(frontUserVO.getUserId());
return CommonResult.success(list);
}
}

View File

@ -0,0 +1,130 @@
package com.upchina.advisor.entity;
import java.io.Serializable;
public class AdvisorBasic implements Serializable {
private static final long serialVersionUID = 1L;
public Integer id;
public Integer userId;
public String name;
public String showName;
public String avatar;
public Integer status;
public String staffNo;
public String license;
public String deptName;
public String deptId;
public String profile;
public String phone;
public AdvisorBasic(AdvisorInfo advisorInfo, String deptName) {
this.id = advisorInfo.getId();
this.userId = advisorInfo.getUserId();
this.name = advisorInfo.getName();
this.showName = advisorInfo.getShowName();
this.avatar = advisorInfo.getAvatar();
this.status = advisorInfo.getStatus();
this.staffNo = advisorInfo.getStaffNo();
this.license = advisorInfo.getLicense();
this.deptId = advisorInfo.getDeptId();
this.deptName = deptName;
this.profile = advisorInfo.getProfile();
this.phone = advisorInfo.getPhone();
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getProfile() {
return profile;
}
public void setProfile(String profile) {
this.profile = profile;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getShowName() {
return showName;
}
public void setShowName(String showName) {
this.showName = showName;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public String getStaffNo() {
return staffNo;
}
public void setStaffNo(String staffNo) {
this.staffNo = staffNo;
}
public String getLicense() {
return license;
}
public void setLicense(String license) {
this.license = license;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public String getDeptId() {
return deptId;
}
public void setDeptId(String deptId) {
this.deptId = deptId;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}

View File

@ -0,0 +1,99 @@
package com.upchina.advisor.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 用户关注投顾信息
* </p>
*
* @author easonzhu
* @since 2022-08-27
*/
public class AdvisorFollow implements Serializable {
@TableField("user_id")
private String userId;
@TableField("advisor_id")
private Integer advisorId;
@TableField("follow_time")
private LocalDateTime followTime;
/**
* 1:关注 2:取消关注
*/
private Integer status;
/**
* 关注渠道1其他渠道关注 2视频直播关注
*/
private Integer channel;
private Integer videoId;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public Integer getAdvisorId() {
return advisorId;
}
public void setAdvisorId(Integer advisorId) {
this.advisorId = advisorId;
}
public LocalDateTime getFollowTime() {
return followTime;
}
public void setFollowTime(LocalDateTime followTime) {
this.followTime = followTime;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Integer getChannel() {
return channel;
}
public void setChannel(Integer channel) {
this.channel = channel;
}
public Integer getVideoId() {
return videoId;
}
public void setVideoId(Integer videoId) {
this.videoId = videoId;
}
@Override
public String toString() {
return "AdvisorFollow{" +
"userId='" + userId + '\'' +
", advisorId=" + advisorId +
", followTime=" + followTime +
", status=" + status +
", channel=" + channel +
", videoId=" + videoId +
'}';
}
}

View File

@ -0,0 +1,280 @@
package com.upchina.advisor.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 投顾信息
* </p>
*
* @author easonzhu
* @since 2022-08-27
*/
public class AdvisorInfo implements Serializable {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 后台用户ID
*/
@TableField("user_id")
private Integer userId;
/**
* 员工编号
*/
@TableField("staff_no")
private String staffNo;
/**
* 展业名称
*/
@TableField("show_name")
private String showName;
/**
* 投顾姓名
*/
private String name;
/**
* 性别
*/
private Integer sex;
/**
* 执照号
*/
private String license;
/**
* 投顾头像
*/
private String avatar;
/**
* 简介
*/
private String profile;
/**
* 投顾所在营业部ID
*/
@TableField("dept_id")
private String deptId;
/**
* 状态 0:待提交;1: 待审核;2: 已上架;3: 已驳回;4: 已下架
*/
private Integer status;
/**
* 审核时间
*/
@TableField("audit_time")
private LocalDateTime auditTime;
/**
* 上架时间
*/
@TableField("publish_time")
private LocalDateTime publishTime;
/**
* 创建时间
*/
@TableField("create_time")
private LocalDateTime createTime;
/**
* 修改时间
*/
@TableField("update_time")
private LocalDateTime updateTime;
/**
* 审核理由
*/
private String reason;
/**
* 手机号
*/
private String phone;
public AdvisorInfo(Integer advisorId, String tgName, String avatar, String orgId) {
this.id = advisorId;
this.name = tgName;
this.avatar = avatar;
this.deptId = orgId;
}
public AdvisorInfo() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getStaffNo() {
return staffNo;
}
public void setStaffNo(String staffNo) {
this.staffNo = staffNo;
}
public String getShowName() {
return showName;
}
public void setShowName(String showName) {
this.showName = showName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public String getLicense() {
return license;
}
public void setLicense(String license) {
this.license = license;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public String getProfile() {
return profile;
}
public void setProfile(String profile) {
this.profile = profile;
}
public String getDeptId() {
return deptId;
}
public void setDeptId(String deptId) {
this.deptId = deptId;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public LocalDateTime getAuditTime() {
return auditTime;
}
public void setAuditTime(LocalDateTime auditTime) {
this.auditTime = auditTime;
}
public LocalDateTime getPublishTime() {
return publishTime;
}
public void setPublishTime(LocalDateTime publishTime) {
this.publishTime = publishTime;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "AdvisorInfo{" +
"id=" + id +
", userId=" + userId +
", staffNo='" + staffNo + '\'' +
", showName='" + showName + '\'' +
", name='" + name + '\'' +
", sex=" + sex +
", license='" + license + '\'' +
", avatar='" + avatar + '\'' +
", profile='" + profile + '\'' +
", deptId='" + deptId + '\'' +
", status=" + status +
", auditTime=" + auditTime +
", publishTime=" + publishTime +
", createTime=" + createTime +
", updateTime=" + updateTime +
", reason='" + reason + '\'' +
", phone='" + phone + '\'' +
'}';
}
}

View File

@ -0,0 +1,20 @@
package com.upchina.advisor.entity;
import com.google.common.collect.ComparisonChain;
import java.io.Serializable;
import java.util.Comparator;
public abstract class AdvisorSortComparator implements Comparator<AdvisorSortEntity>, Serializable {
private static final long serialVersionUID = 1L;
public static final Comparator<AdvisorSortEntity> COUNT_COMPARATOR = new AdvisorSortComparator() {
@Override
public int compare(AdvisorSortEntity o1, AdvisorSortEntity o2) {
return ComparisonChain.start()
.compare(o2.getCount(), o1.getCount())
.compare(o2.getId(), o1.getId()).result();
}
};
}

View File

@ -0,0 +1,85 @@
package com.upchina.advisor.entity;
import com.google.common.collect.ComparisonChain;
import java.io.Serializable;
import java.util.Objects;
/**
* <p>
* 投顾基本信息
* </p>
*
* @author easonzhu
* @since 2022-08-27
*/
public class AdvisorSortEntity implements Serializable, Comparable<AdvisorSortEntity> {
private static final long serialVersionUID = 1L;
private Integer id;
private Integer count;
private String name;
public AdvisorSortEntity() {
}
public AdvisorSortEntity(Integer id, Integer count) {
this.id = id;
this.count = count;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AdvisorSortEntity that = (AdvisorSortEntity) o;
return id.equals(that.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
@Override
public int compareTo(AdvisorSortEntity o) {
return ComparisonChain.start()
.compare(this.count, o.count)
.compare(this.id, o.id).result();
}
@Override
public String toString() {
return "AdvisorSortEntity{" +
"id=" + id +
", count=" + count +
'}';
}
}

View File

@ -0,0 +1,53 @@
package com.upchina.advisor.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
/**
* <p>
* 投顾标签关系表
* </p>
*
* @author easonzhu
* @since 2022-08-27
*/
public class AdvisorTagRel implements Serializable {
/**
* 投顾ID
*/
@TableField("advisor_id")
private Integer advisorId;
/**
* 投顾标签ID
*/
@TableField("tag_id")
private Integer tagId;
public Integer getAdvisorId() {
return advisorId;
}
public void setAdvisorId(Integer advisorId) {
this.advisorId = advisorId;
}
public Integer getTagId() {
return tagId;
}
public void setTagId(Integer tagId) {
this.tagId = tagId;
}
@Override
public String toString() {
return "AdvisorTagRel{" +
"advisorId=" + advisorId +
", tagId=" + tagId +
"}";
}
}

View File

@ -0,0 +1,16 @@
package com.upchina.advisor.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.upchina.advisor.entity.AdvisorFollow;
/**
* <p>
* 用户关注投顾信息 Mapper 接口
* </p>
*
* @author easonzhu
* @since 2022-08-27
*/
public interface AdvisorFollowMapper extends BaseMapper<AdvisorFollow> {
}

View File

@ -0,0 +1,29 @@
package com.upchina.advisor.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.upchina.advisor.entity.AdvisorInfo;
import com.upchina.advisor.entity.AdvisorSortEntity;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* <p>
* 投顾信息 Mapper 接口
* </p>
*
* @author easonzhu
* @since 2022-08-27
*/
public interface AdvisorInfoMapper extends BaseMapper<AdvisorInfo> {
@Select("SELECT ai.id, ifnull(af.follow_count, 0) as count, ai.publish_time as time, ai.show_name as name\n" +
"FROM advisor_info ai\n" +
"LEFT JOIN (SELECT advisor_id, COUNT(0) AS follow_count FROM advisor_follow WHERE STATUS = 1 GROUP BY advisor_id) af\n" +
"ON ai.id = af.advisor_id\n" +
"WHERE status = #{status}\n" +
"ORDER BY id DESC")
List<AdvisorSortEntity> selectFollowCountSortList(@Param("status") Integer status);
}

View File

@ -0,0 +1,27 @@
package com.upchina.advisor.mapper;
import com.upchina.advisor.entity.AdvisorTagRel;
import com.upchina.common.entity.Tag;
import com.upchina.common.mapper.EasyBaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* <p>
* 投顾标签关系表 Mapper 接口
* </p>
*
* @author easonzhu
* @since 2022-08-27
*/
public interface AdvisorTagRelMapper extends EasyBaseMapper<AdvisorTagRel> {
@Select("select t.id, t.name, t.status from tag t " +
"join advisor_tag_rel at " +
"on t.id = at.tag_id " +
"where at.advisor_id = #{advisorId} and t.status = 1")
List<Tag> selectTagByAdvisorId(@Param("advisorId") Integer advisorId);
}

View File

@ -0,0 +1,75 @@
package com.upchina.advisor.query;
import com.upchina.advisor.entity.AdvisorFollow;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
public class FollowAdvisorAppQuery {
@ApiModelProperty("投顾/团队ID")
@NotNull
@Min(1)
private Integer advisorId;
@ApiModelProperty("选项 1:关注; 2:取消关注")
@NotNull
@Min(1)
@Max(2)
private Integer option;
@ApiModelProperty("关注渠道1其他渠道关注 2视频直播关注")
@NotNull
@Min(1)
@Max(2)
private Integer channel;
@ApiModelProperty("直播间id")
private Integer videoId;
public AdvisorFollow toAdvisorFollow(String userId) {
AdvisorFollow advisorFollow = new AdvisorFollow();
advisorFollow.setAdvisorId(this.getAdvisorId());
advisorFollow.setUserId(userId);
advisorFollow.setStatus(this.option);
advisorFollow.setChannel(this.channel);
advisorFollow.setFollowTime(LocalDateTime.now());
advisorFollow.setVideoId(videoId);
return advisorFollow;
}
public Integer getAdvisorId() {
return advisorId;
}
public void setAdvisorId(Integer advisorId) {
this.advisorId = advisorId;
}
public Integer getOption() {
return option;
}
public void setOption(Integer option) {
this.option = option;
}
public Integer getChannel() {
return channel;
}
public void setChannel(Integer channel) {
this.channel = channel;
}
public Integer getVideoId() {
return videoId;
}
public void setVideoId(Integer videoId) {
this.videoId = videoId;
}
}

View File

@ -0,0 +1,55 @@
package com.upchina.advisor.query;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
public class ListAdvisorAppQuery {
@ApiModelProperty("上页最后粉丝数,首页传null或不传")
private Integer lastFollowCount;
@ApiModelProperty("上页最后ID,首页传null或不传")
private Integer lastId;
@ApiModelProperty("关键字")
private String keyword;
@ApiModelProperty("每页记录数")
@NotNull
@Min(1)
private Integer size;
public Integer getLastFollowCount() {
return lastFollowCount;
}
public void setLastFollowCount(Integer lastFollowCount) {
this.lastFollowCount = lastFollowCount;
}
public Integer getLastId() {
return lastId;
}
public void setLastId(Integer lastId) {
this.lastId = lastId;
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public Integer getSize() {
return size;
}
public void setSize(Integer size) {
this.size = size;
}
}

View File

@ -0,0 +1,73 @@
package com.upchina.advisor.query;
import com.upchina.common.query.PageQuery;
import io.swagger.annotations.ApiModelProperty;
public class ListAdvisorInfoQuery extends PageQuery {
@ApiModelProperty("名称")
private String name;
@ApiModelProperty("员工号")
private String staffNo;
@ApiModelProperty("展业名称")
private String showName;
@ApiModelProperty("状态 1:待提交; 2:待审核; 3:已上架; 4:已驳回, 5:已下架")
private Integer status;
@ApiModelProperty("营业部id")
private String deptId;
@ApiModelProperty("是否过滤掉自己 1:过滤 2:不过滤")
private Integer filterSelf;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getStaffNo() {
return staffNo;
}
public void setStaffNo(String staffNo) {
this.staffNo = staffNo;
}
public String getShowName() {
return showName;
}
public void setShowName(String showName) {
this.showName = showName;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public String getDeptId() {
return deptId;
}
public void setDeptId(String deptId) {
this.deptId = deptId;
}
public Integer getFilterSelf() {
return filterSelf;
}
public void setFilterSelf(Integer filterSelf) {
this.filterSelf = filterSelf;
}
}

View File

@ -0,0 +1,140 @@
package com.upchina.advisor.query;
import com.upchina.advisor.entity.AdvisorInfo;
import com.upchina.advisor.entity.AdvisorTagRel;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class UpdateAdvisorInfoQuery {
@ApiModelProperty("投顾ID")
@NotNull
@Min(1)
private Integer id;
@ApiModelProperty("展业名称")
@NotBlank
private String showName;
@ApiModelProperty("性别 1:男 2")
@Min(1)
@Max(2)
private Integer sex;
@ApiModelProperty("头像")
@NotBlank
private String avatar;
@ApiModelProperty("简介")
@NotBlank
private String profile;
@ApiModelProperty("执业证号")
@NotBlank
private String license;
@ApiModelProperty("手机号")
private String phone;
@ApiModelProperty("标签IDs")
private Integer[] tags;
public AdvisorInfo toPO(Integer status) {
AdvisorInfo advisorInfo = new AdvisorInfo();
advisorInfo.setId(this.id);
advisorInfo.setShowName(this.showName);
advisorInfo.setSex(this.sex);
advisorInfo.setAvatar(this.avatar);
advisorInfo.setProfile(this.profile);
advisorInfo.setLicense(this.license);
advisorInfo.setPhone(this.phone);
advisorInfo.setStatus(status);
advisorInfo.setUpdateTime(LocalDateTime.now());
return advisorInfo;
}
public List<AdvisorTagRel> toTagListPO() {
if (tags == null || tags.length == 0) {
return Collections.emptyList();
}
return Arrays.stream(tags).map(tagId -> {
AdvisorTagRel advisorTag = new AdvisorTagRel();
advisorTag.setAdvisorId(this.getId());
advisorTag.setTagId(tagId);
return advisorTag;
}).collect(Collectors.toList());
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getShowName() {
return showName;
}
public void setShowName(String showName) {
this.showName = showName;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public String getProfile() {
return profile;
}
public void setProfile(String profile) {
this.profile = profile;
}
public Integer[] getTags() {
return tags;
}
public void setTags(Integer[] tags) {
this.tags = tags;
}
public String getLicense() {
return license;
}
public void setLicense(String license) {
this.license = license;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}

View File

@ -0,0 +1,70 @@
package com.upchina.advisor.query;
import com.upchina.advisor.constant.AdvisorInfoStatus;
import com.upchina.advisor.entity.AdvisorInfo;
import com.upchina.common.validation.IntArrayValidator;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
public class UpdateAdvisorInfoStatusQuery {
@ApiModelProperty("投顾ID")
@NotNull
@Min(1)
private Integer id;
@ApiModelProperty("动作 101:提交 103:通过 104:驳回 105:上架 106:下架")
@NotNull
@IntArrayValidator({101, 103, 104, 105, 106})
private Integer event;
@ApiModelProperty("驳回原因,仅当status=4时传入")
private String reason;
public AdvisorInfo toPO(Integer status, boolean isFirstPass) {
AdvisorInfo advisorInfo = new AdvisorInfo();
advisorInfo.setId(this.id);
advisorInfo.setStatus(status);
LocalDateTime now = LocalDateTime.now();
advisorInfo.setUpdateTime(now);
if (AdvisorInfoStatus.PASS.value.equals(status)) {
advisorInfo.setPublishTime(now);
}
if (isFirstPass) {
advisorInfo.setAuditTime(now);
}
if (AdvisorInfoStatus.REJECTED.value.equals(status)) {
advisorInfo.setReason(this.reason);
} else {
advisorInfo.setReason("");
}
return advisorInfo;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getEvent() {
return event;
}
public void setEvent(Integer event) {
this.event = event;
}
}

View File

@ -0,0 +1,487 @@
package com.upchina.advisor.service;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.ImmutableSet;
import com.hazelcast.core.HazelcastInstance;
import com.upchina.advisor.constant.AdvisorInfoStatus;
import com.upchina.advisor.constant.FollowChannel;
import com.upchina.advisor.constant.FollowOption;
import com.upchina.advisor.entity.*;
import com.upchina.advisor.mapper.AdvisorFollowMapper;
import com.upchina.advisor.mapper.AdvisorInfoMapper;
import com.upchina.advisor.mapper.AdvisorTagRelMapper;
import com.upchina.advisor.query.*;
import com.upchina.advisor.vo.AdvisorBasicVO;
import com.upchina.advisor.vo.AdvisorInfoAdminVO;
import com.upchina.advisor.vo.AdvisorInfoAppVO;
import com.upchina.common.constant.AdvertPosition;
import com.upchina.common.constant.IsOrNot;
import com.upchina.common.constant.ProductType;
import com.upchina.common.entity.Tag;
import com.upchina.common.handler.BizException;
import com.upchina.common.result.AppPager;
import com.upchina.common.result.Pager;
import com.upchina.common.result.ResponseStatus;
import com.upchina.common.service.AdvertService;
import com.upchina.common.service.CacheService;
import com.upchina.common.service.RecommendService;
import com.upchina.common.service.SensitiveWordService;
import com.upchina.common.state.StateMachine;
import com.upchina.common.vo.BackendUserVO;
import com.upchina.common.vo.CountVO;
import com.upchina.common.vo.FrontUserVO;
import com.upchina.rbac.constant.DeptType;
import com.upchina.rbac.entity.Dept;
import com.upchina.rbac.entity.UserDept;
import com.upchina.rbac.entity.UserLogin;
import com.upchina.rbac.entity.UsersRoles;
import com.upchina.rbac.mapper.UsersRolesMapper;
import com.upchina.rbac.service.DeptService;
import com.upchina.rbac.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.upchina.common.config.cache.CacheKey.ADVISOR_INFO;
import static com.upchina.common.config.cache.CacheKey.AdvisorInfoKey;
@Service
public class AdvisorInfoService {
@Resource
private AdvisorInfoMapper advisorInfoMapper;
@Resource
private AdvisorTagRelMapper advisorTagRelMapper;
@Resource
private DeptService deptService;
@Resource
private AdvisorFollowMapper advisorFollowMapper;
@Resource
HazelcastInstance hazelcastInstance;
@Resource
private CacheService cacheService;
@Resource
private UsersRolesMapper usersRolesMapper;
@Resource
private SensitiveWordService sensitiveWordService;
@Resource
private StateMachine<AdvisorInfoStatus> advisorInfoSM;
@Resource
private RecommendService recommendService;
@Resource
private AdvertService advertService;
@Value("${advisor.roleId}")
private Integer advisorRoleId;
public static final Set<Integer> TG_SHOW_STATUS = ImmutableSet.of(
AdvisorInfoStatus.PASS.value,
AdvisorInfoStatus.EVENT_SUBMIT.value,
AdvisorInfoStatus.EVENT_PASS.value
);
@Autowired
private UserService userService;
public Map<Integer, AdvisorBasic> getAdvisorMap() {
return cacheService.get(ADVISOR_INFO, AdvisorInfoKey.ADVISOR_MAP, () -> {
List<AdvisorInfo> advisorList = advisorInfoMapper.selectList(Wrappers.emptyWrapper());
return advisorList.stream().collect(Collectors.toMap(AdvisorInfo::getId, advisor ->
new AdvisorBasic(advisor, deptService.getDeptNameByAdvisorId(advisor.getId()))));
});
}
public Map<Integer, AdvisorBasicVO> getAdvisorVoMap() {
return cacheService.get(ADVISOR_INFO, AdvisorInfoKey.ADVISOR_VO_MAP, () -> {
List<AdvisorInfo> advisorList = advisorInfoMapper.selectList(Wrappers.emptyWrapper());
return advisorList.stream().collect(Collectors.toMap(AdvisorInfo::getId, advisor ->
new AdvisorBasicVO(new AdvisorBasic(advisor, deptService.getDeptNameByAdvisorId(advisor.getId())))));
});
}
public Map<Integer, AdvisorBasic> getUserIdAdvisorMap() {
return cacheService.get(ADVISOR_INFO, AdvisorInfoKey.USER_ADVISOR_MAP, () -> {
List<AdvisorInfo> advisorList = advisorInfoMapper.selectList(Wrappers.emptyWrapper());
return advisorList.stream().filter(advisor -> advisor.getUserId() != null).collect(Collectors.toMap(AdvisorInfo::getUserId, advisor ->
new AdvisorBasic(advisor, deptService.getDeptNameByAdvisorId(advisor.getId()))));
});
}
public Map<String, List<AdvisorBasic>> getDeptIdAdvisorMap() {
return cacheService.get(ADVISOR_INFO, AdvisorInfoKey.USER_ADVISOR_DEPT_MAP, () -> {
List<AdvisorInfo> advisorList = advisorInfoMapper.selectList(Wrappers.emptyWrapper());
return advisorList.stream().filter(advisor -> StrUtil.isNotBlank(advisor.getDeptId())).map(advisor ->
new AdvisorBasic(advisor, deptService.getDeptNameByAdvisorId(advisor.getId()))).collect(Collectors.groupingBy(AdvisorBasic::getDeptId));
});
}
public Pager<AdvisorInfoAdminVO> list(ListAdvisorInfoQuery query, BackendUserVO backendUserVO) {
QueryWrapper<AdvisorInfo> wrapper = Wrappers.query();
String name = query.getName();
String staffNo = query.getStaffNo();
String showName = query.getShowName();
Integer status = query.getStatus();
String deptId = query.getDeptId();
Integer filterSelf = query.getFilterSelf();
Map<String, Dept> deptMap = deptService.getDeptMap();
Dept dept = deptMap.get(deptId);
if (dept != null && DeptType.HEAD.value.equals(dept.getType())) {
deptId = null;
}
if (backendUserVO.getRoles().contains(StateMachine.ROLE.ADMIN)) {
deptId = null;
}
Map<Integer, UserLogin> userLoginMap = userService.getUserLoginMap();
wrapper.like(StrUtil.isNotEmpty(name), "name", name)
.like(StrUtil.isNotEmpty(staffNo), "staff_no", staffNo)
.like(StrUtil.isNotEmpty(showName), "show_name", showName)
.eq(status != null, "status", status)
.eq(StrUtil.isNotBlank(deptId), "dept_id", deptId)
.ne(IsOrNot.IS.value.equals(filterSelf) && backendUserVO.getAdvisorId() != null, "id", backendUserVO.getAdvisorId());
Page<AdvisorInfo> page = advisorInfoMapper.selectPage(query.toPage(), wrapper);
List<AdvisorInfoAdminVO> list = page.getRecords().stream().map(advisorInfo -> {
Integer followCount = this.getFollowCount(advisorInfo.getId(), 0);
return new AdvisorInfoAdminVO(advisorInfo,
userLoginMap.get(advisorInfo.getUserId()),
deptService.getDeptNameByAdvisorId(advisorInfo.getId()),
null, followCount);
}).collect(Collectors.toList());
return new Pager<>(list, page.getTotal());
}
public AdvisorInfoAdminVO get(Integer id) {
AdvisorInfo advisorInfo = advisorInfoMapper.selectById(id);
if (advisorInfo == null) {
return null;
}
Integer followCount = this.getFollowCount(advisorInfo.getId(), 0);
List<Tag> tagList = advisorTagRelMapper.selectTagByAdvisorId(id);
Map<Integer, UserLogin> userLoginMap = userService.getUserLoginMap();
return new AdvisorInfoAdminVO(advisorInfo,
userLoginMap.get(advisorInfo.getUserId()),
deptService.getDeptNameByAdvisorId(id),
tagList, followCount);
}
@Transactional
public void save(UserLogin userLogin, UserDept userDept) {
AdvisorBasic advisorBasic = this.getUserIdAdvisorMap().get(userDept.getUserId());
Integer advisorId = advisorBasic == null ? null : advisorBasic.id;
AdvisorInfo advisorInfo = this.convertUserToAdvisorInfo(userLogin, userDept, advisorId);
if (advisorId == null) {
advisorInfoMapper.insert(advisorInfo);
} else {
advisorInfoMapper.updateById(advisorInfo);
}
this.clearCache(null, null);
}
@Transactional(rollbackFor = Exception.class)
public void update(UpdateAdvisorInfoQuery query, BackendUserVO backendUserVO) {
sensitiveWordService.check(query.getShowName(), query.getProfile());
Integer advisorId = query.getId();
AdvisorInfo advisorInDB = advisorInfoMapper.selectById(advisorId);
if (advisorInDB == null) {
throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR);
}
AdvisorInfoStatus dbStatus = AdvisorInfoStatus.fromValue(advisorInDB.getStatus());
// 状态机扭转
AdvisorInfoStatus targetStatus = advisorInfoSM.send(dbStatus, AdvisorInfoStatus.EVENT_UPDATE, backendUserVO);
// 修改原表
AdvisorInfo advisorInfo = query.toPO(targetStatus.value);
advisorInfoMapper.updateById(advisorInfo);
// 修改标签关联表
QueryWrapper<AdvisorTagRel> tagWrapper = Wrappers.query();
advisorTagRelMapper.delete(tagWrapper.eq("advisor_id", advisorId));
List<AdvisorTagRel> tagList = query.toTagListPO();
if (CollUtil.isNotEmpty(tagList)) {
advisorTagRelMapper.insertBatchSomeColumn(tagList);
}
this.clearCache(advisorId, null);
deptService.clearCache();
}
/**
* <p>方法说明: 检查是否使用标签 </p>
* <p>参数名称: [id] </p>
* <p>参数类型: [java.lang.Integer] </p>
*
* @return boolean
* @author haojunjin
* @since 2023/3/7 10:45
*/
public boolean checkUseTag(Integer id) {
QueryWrapper<AdvisorTagRel> wrapper = Wrappers.query();
wrapper.eq("tag_id", id);
Long count = advisorTagRelMapper.selectCount(wrapper);
return count > 0;
}
@Transactional(rollbackFor = Exception.class)
public void updateStatus(UpdateAdvisorInfoStatusQuery query, BackendUserVO backendUserVO) {
Integer id = query.getId();
String reason = query.getReason();
AdvisorInfoStatus event = AdvisorInfoStatus.fromValue(query.getEvent());
if (AdvisorInfoStatus.EVENT_REJECT.equals(event) && StrUtil.isEmpty(reason)) {
throw new BizException(ResponseStatus.PARM_ERROR, "驳回原因为空");
}
AdvisorInfo advisorInDB = advisorInfoMapper.selectById(id);
if (advisorInDB == null) {
throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR);
}
AdvisorInfoStatus dbStatus = AdvisorInfoStatus.fromValue(advisorInDB.getStatus());
// 状态机检查
AdvisorInfoStatus targetStatus = advisorInfoSM.send(dbStatus, event, backendUserVO);
// 下架前验证各类产品及推荐位
if (AdvisorInfoStatus.SOLD_OUT.equals(targetStatus)) {
validateReference(id);
}
boolean isFirstPass = AdvisorInfoStatus.PASS.equals(targetStatus) && advisorInDB.getAuditTime() == null;
AdvisorInfo advisorInfo = query.toPO(targetStatus.value, isFirstPass);
advisorInfoMapper.updateById(advisorInfo);
if (AdvisorInfoStatus.PASS.equals(targetStatus)) {
// 上架时添加投顾角色
removeAdvisorRole(advisorInDB);
addAdvisorRole(advisorInDB);
} else if (AdvisorInfoStatus.SOLD_OUT.equals(targetStatus)) {
// 下架时删除投顾角色
removeAdvisorRole(advisorInDB);
}
this.clearCache(id, null);
recommendService.clearCache(ProductType.ADVISOR_INFO);
advertService.clearCache(AdvertPosition.HOME_PAGE);
}
private void addAdvisorRole(AdvisorInfo advisorInfo) {
UsersRoles ur = new UsersRoles();
ur.setUserId(advisorInfo.getUserId());
ur.setRoleId(advisorRoleId);
usersRolesMapper.insert(ur);
}
private void removeAdvisorRole(AdvisorInfo advisorInfo) {
QueryWrapper<UsersRoles> delRoleWrapper = Wrappers.query();
delRoleWrapper.eq("user_id", advisorInfo.getUserId()).eq("role_id", advisorRoleId);
usersRolesMapper.delete(delRoleWrapper);
}
public AppPager<AdvisorInfoAppVO> listForApp(ListAdvisorAppQuery query, FrontUserVO userVO) {
Integer lastFollowCount = query.getLastFollowCount();
String keyword = query.getKeyword();
Integer lastId = query.getLastId();
Integer size = query.getSize();
NavigableSet<AdvisorSortEntity> set = new TreeSet<>(AdvisorSortComparator.COUNT_COMPARATOR);
Map<String, Object> cacheMap = hazelcastInstance.getMap(ADVISOR_INFO);
NavigableSet<AdvisorSortEntity> sortedSet = cacheService.get(cacheMap, AdvisorInfoKey.APP_FOLLOW_COUNT_LIST, () -> {
List<AdvisorSortEntity> advisorList = advisorInfoMapper.selectFollowCountSortList(AdvisorInfoStatus.PASS.value);
set.addAll(advisorList);
return set;
});
AdvisorSortEntity lastEntity = lastId == null || lastFollowCount == null ? null : new AdvisorSortEntity(lastId, lastFollowCount);
if (lastEntity != null) {
sortedSet = sortedSet.tailSet(lastEntity, false);
}
List<AdvisorInfoAppVO> voList = new ArrayList<>(size);
Iterator<AdvisorSortEntity> it = sortedSet.iterator();
while (it.hasNext()) {
AdvisorSortEntity entity = it.next();
if (StrUtil.isNotEmpty(keyword) && !entity.getName().contains(keyword)) {
continue;
}
voList.add(this.getForApp(entity.getId(), userVO == null ? null : userVO.getUserId()));
if (--size == 0) {
break;
}
}
return new AppPager<>(voList, it.hasNext());
}
public AdvisorInfoAppVO getForApp(Integer advisorId, String userId) {
final Map<String, Object> cacheMap = hazelcastInstance.getMap(ADVISOR_INFO);
AdvisorInfoAppVO vo = cacheService.get(cacheMap, AdvisorInfoKey.APP_OBJ + advisorId, () -> {
AdvisorInfo advisorInfo = advisorInfoMapper.selectById(advisorId);
if (advisorInfo == null) {
return null;
}
List<Tag> tagList = advisorTagRelMapper.selectTagByAdvisorId(advisorId);
return new AdvisorInfoAppVO(advisorInfo, tagList,
this.getFollowCount(advisorId, 0),
deptService.getDeptNameByAdvisorId(advisorId)
);
});
if (vo == null) {
return null;
}
if (userId != null) {
vo.setIsFollow(isFollow(userId, advisorId));
}
return vo;
}
public List<AdvisorInfoAppVO> listForAppByIds(List<Integer> ids) {
return ids.stream().filter(Objects::nonNull).map(id -> this.getForApp(id, null)).filter(Objects::nonNull).collect(Collectors.toList());
}
@Transactional
public CountVO follow(FollowAdvisorAppQuery query, String userId) {
Integer advisorId = query.getAdvisorId();
Integer option = query.getOption();
AdvisorInfo advisorInDB = advisorInfoMapper.selectById(advisorId);
if (advisorInDB == null) {
throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR);
}
AdvisorFollow advisorFollow = query.toAdvisorFollow(userId);
QueryWrapper<AdvisorFollow> wrapper = Wrappers.query();
wrapper.eq("user_id", userId).eq("advisor_id", advisorId);
AdvisorFollow advisorFollowInDB = advisorFollowMapper.selectOne(wrapper);
Integer followCount;
if (advisorFollowInDB == null) {
// 之前没有关注也没有取消关注的直接插入
followCount = this.getFollowCount(advisorId, 1);
advisorFollowMapper.insert(advisorFollow);
} else {
if (query.getOption().equals(advisorFollowInDB.getStatus())) {
// 之前有记录但是记录和本次请求预期状态相同不做任何数据库操作
followCount = this.getFollowCount(advisorId, 0);
} else {
// 之前有记录需要变更状态时根据状态增减关注数
followCount = this.getFollowCount(advisorId, FollowOption.FOLLOW.value.equals(option) ? 1 : -1);
advisorFollowMapper.update(advisorFollow, wrapper);
}
}
this.clearCache(advisorId, userId);
return new CountVO(followCount);
}
public List<AdvisorInfoAppVO> listFollow(String userId) {
List<Integer> followAdvisorIds = getFollowAdvisorIds(userId);
return followAdvisorIds.stream().map(advisorId -> this.getForApp(advisorId, userId))
.filter(Objects::nonNull).collect(Collectors.toList());
}
public List<String> listFollowUserIdList(Integer advisorId) {
QueryWrapper<AdvisorFollow> wrapper = Wrappers.query();
wrapper.select("user_id")
.eq("advisor_id", advisorId)
.eq("status", FollowOption.FOLLOW.value);
return advisorFollowMapper.selectObjs(wrapper).stream().map(obj -> (String) obj).collect(Collectors.toList());
}
public List<Integer> getFollowAdvisorIds(String userId) {
return cacheService.get(ADVISOR_INFO, AdvisorInfoKey.USER_FOLLOW_ADVISOR + userId, () -> {
QueryWrapper<AdvisorFollow> followWrapper = Wrappers.query();
followWrapper.select("advisor_id")
.eq("user_id", userId)
.eq("status", FollowOption.FOLLOW.value)
.orderByDesc("follow_time");
return advisorFollowMapper.selectList(followWrapper).stream().map(AdvisorFollow::getAdvisorId).collect(Collectors.toList());
});
}
public Integer getFollowCount(Integer advisorId, int delta) {
return cacheService.getLong(AdvisorInfoKey.APP_FOLLOW_COUNT + advisorId, () -> {
QueryWrapper<AdvisorFollow> wrapper = Wrappers.query();
wrapper.eq("advisor_id", advisorId).eq("status", FollowOption.FOLLOW.value);
return advisorFollowMapper.selectCount(wrapper).intValue();
}, delta);
}
public Integer isFollow(String userId, Integer advisorId) {
List<Integer> followAdvisorIds = getFollowAdvisorIds(userId);
return followAdvisorIds.stream().anyMatch(advisorId::equals) ? FollowOption.FOLLOW.value : FollowOption.UN_FOLLOW.value;
}
public void validateReference(Integer advisorId) {
// 下架验证推荐位
recommendService.validateRecommendExist(ProductType.ADVISOR_INFO, advisorId);
}
public void clearCache(Integer advisorId, String userId) {
Map<String, Object> cacheMap = hazelcastInstance.getMap(ADVISOR_INFO);
cacheMap.remove(AdvisorInfoKey.ADVISOR_MAP);
cacheMap.remove(AdvisorInfoKey.USER_ADVISOR_MAP);
cacheMap.remove(AdvisorInfoKey.APP_FOLLOW_COUNT_LIST);
cacheMap.remove(AdvisorInfoKey.APP_READ_COUNT_LIST);
cacheMap.remove(AdvisorInfoKey.APP_PRODUCT_COUNT_LIST);
cacheMap.remove(AdvisorInfoKey.USER_ADVISOR_DEPT_MAP);
if (advisorId != null) {
cacheMap.remove(AdvisorInfoKey.APP_OBJ + advisorId);
}
if (userId != null) {
cacheMap.remove(AdvisorInfoKey.USER_FOLLOW_ADVISOR + userId);
}
}
private AdvisorInfo convertUserToAdvisorInfo(UserLogin userLogin, UserDept userDept, Integer advisorId) {
AdvisorInfo advisorInfo = new AdvisorInfo();
advisorInfo.setUserId(userDept.getUserId());
advisorInfo.setStaffNo(userLogin.getStaffNo());
advisorInfo.setShowName(userDept.getName());
advisorInfo.setName(userLogin.getName());
advisorInfo.setDeptId(userDept.getDeptId());
advisorInfo.setStatus(AdvisorInfoStatus.INIT.value);
if (advisorId != null) {
advisorInfo.setId(advisorId);
advisorInfo.setUpdateTime(LocalDateTime.now());
} else {
advisorInfo.setCreateTime(LocalDateTime.now());
}
return advisorInfo;
}
public Map<Integer, AdvisorBasicVO> listBasicForApp(Integer[] ids) {
Map<Integer, AdvisorBasic> advisorMap = this.getAdvisorMap();
return Arrays.stream(ids).filter(advisorMap::containsKey).collect(Collectors.toMap(
Function.identity(), id -> new AdvisorBasicVO(advisorMap.get(id))));
}
public void validateAdvisor(Integer productUserId, boolean isAudit, BackendUserVO backendUserVO) {
AdvisorBasic advisorBasic = this.getUserIdAdvisorMap().get(productUserId);
if (advisorBasic == null) {
throw new BizException(ResponseStatus.ADVISOR_NOT_EXIST_ERROR);
}
// 投顾不能审核自己和自己团队的产品
if (isAudit) {
Integer loginUserId = backendUserVO.getUserId();
if (loginUserId == null) return;
if (advisorBasic.getId().equals(loginUserId)) {
throw new BizException(ResponseStatus.AUDIT_LEFT_PRODUCT_ERROR);
}
}
}
public AdvisorFollow selectOne(Integer advisorId, String userId) {
QueryWrapper<AdvisorFollow> wrapper = Wrappers.query();
wrapper
.eq("user_id", userId)
.eq("status", FollowOption.FOLLOW.value)
.eq("advisor_id", advisorId)
.eq("channel", FollowChannel.VIDEO_CHANNEL.value);
return advisorFollowMapper.selectOne(wrapper);
}
}

View File

@ -0,0 +1,111 @@
package com.upchina.advisor.vo;
import com.upchina.advisor.entity.AdvisorBasic;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
public class AdvisorBasicVO implements Serializable {
@ApiModelProperty("投顾ID")
private Integer id;
@ApiModelProperty("用户id")
private Integer userId;
@ApiModelProperty("投顾名称")
private String name;
@ApiModelProperty("展业名称")
public String showName;
@ApiModelProperty("投顾头像")
private String avatar;
@ApiModelProperty("投顾营业部名称")
private String deptName;
@ApiModelProperty("执照号")
private String license;
@ApiModelProperty("简介")
private String profile;
public AdvisorBasicVO() {
}
public AdvisorBasicVO(AdvisorBasic advisorBasic) {
this.id = advisorBasic.id;
this.userId = advisorBasic.userId;
this.name = advisorBasic.name;
this.showName = advisorBasic.showName;
this.avatar = advisorBasic.avatar;
this.deptName = advisorBasic.deptName;
this.license = advisorBasic.license;
this.profile = advisorBasic.profile;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getShowName() {
return showName;
}
public void setShowName(String showName) {
this.showName = showName;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public String getLicense() {
return license;
}
public void setLicense(String license) {
this.license = license;
}
public String getProfile() {
return profile;
}
public void setProfile(String profile) {
this.profile = profile;
}
}

View File

@ -0,0 +1,261 @@
package com.upchina.advisor.vo;
import com.upchina.advisor.entity.AdvisorInfo;
import com.upchina.common.entity.Tag;
import com.upchina.common.vo.TagVO;
import com.upchina.rbac.entity.UserLogin;
import io.swagger.annotations.ApiModelProperty;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
public class AdvisorInfoAdminVO {
@ApiModelProperty("ID")
private Integer id;
@ApiModelProperty("用户ID")
private Integer userId;
@ApiModelProperty("员工号")
private String staffNo;
@ApiModelProperty("UPID")
private String upId;
@ApiModelProperty("展业名称")
private String showName;
@ApiModelProperty("投顾姓名")
private String name;
@ApiModelProperty("简介")
private String profile;
@ApiModelProperty("手机号")
private String phone;
@ApiModelProperty("营业部ID")
private String deptId;
@ApiModelProperty("营业部名称")
private String deptName;
@ApiModelProperty("执业证号")
private String license;
@ApiModelProperty("头像")
private String avatar;
@ApiModelProperty("状态 1:待提交; 2:待审核; 3:已上架; 4:已驳回, 5:已下架")
private Integer status;
@ApiModelProperty("审核时间(首次发布时间)")
private LocalDateTime auditTime;
@ApiModelProperty("发布时间")
private LocalDateTime publishTime;
@ApiModelProperty("驳回理由")
private String reason;
@ApiModelProperty("标签")
private List<TagVO> tagList;
@ApiModelProperty("创建时间")
private LocalDateTime createTime;
@ApiModelProperty("粉丝数")
private Integer followCount;
@ApiModelProperty("性别 1:男 2")
private Integer sex;
public AdvisorInfoAdminVO(AdvisorInfo advisorInfo, UserLogin userLogin, String deptName, List<Tag> tagList, Integer followCount) {
this.id = advisorInfo.getId();
this.userId = advisorInfo.getUserId();
this.staffNo = advisorInfo.getStaffNo();
if (userLogin != null) {
this.upId = userLogin.getUpId();
}
this.showName = advisorInfo.getShowName();
this.name = advisorInfo.getName();
this.profile = advisorInfo.getProfile();
this.phone = advisorInfo.getPhone();
this.deptId = advisorInfo.getDeptId();
this.deptName = deptName;
this.license = advisorInfo.getLicense();
this.avatar = advisorInfo.getAvatar();
this.status = advisorInfo.getStatus();
this.auditTime = advisorInfo.getAuditTime();
this.publishTime = advisorInfo.getPublishTime();
this.reason = advisorInfo.getReason();
this.deptName = deptName;
if (tagList != null) {
this.tagList = tagList.stream().map(TagVO::new).collect(Collectors.toList());
}
this.followCount = followCount;
this.sex = advisorInfo.getSex();
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getStaffNo() {
return staffNo;
}
public void setStaffNo(String staffNo) {
this.staffNo = staffNo;
}
public String getUpId() {
return upId;
}
public void setUpId(String upId) {
this.upId = upId;
}
public String getShowName() {
return showName;
}
public void setShowName(String showName) {
this.showName = showName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getProfile() {
return profile;
}
public void setProfile(String profile) {
this.profile = profile;
}
public String getDeptId() {
return deptId;
}
public void setDeptId(String deptId) {
this.deptId = deptId;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public String getLicense() {
return license;
}
public void setLicense(String license) {
this.license = license;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public LocalDateTime getAuditTime() {
return auditTime;
}
public void setAuditTime(LocalDateTime auditTime) {
this.auditTime = auditTime;
}
public LocalDateTime getPublishTime() {
return publishTime;
}
public void setPublishTime(LocalDateTime publishTime) {
this.publishTime = publishTime;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public List<TagVO> getTagList() {
return tagList;
}
public void setTagList(List<TagVO> tagList) {
this.tagList = tagList;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public Integer getFollowCount() {
return followCount;
}
public void setFollowCount(Integer followCount) {
this.followCount = followCount;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
}

View File

@ -0,0 +1,197 @@
package com.upchina.advisor.vo;
import com.upchina.advisor.entity.AdvisorInfo;
import com.upchina.common.entity.Tag;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
public class AdvisorInfoAppVO implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("ID")
private Integer id;
@ApiModelProperty("员工号")
private String staffNo;
@ApiModelProperty("投顾姓名")
private String name;
@ApiModelProperty("展业名称")
private String showName;
@ApiModelProperty("执照号")
private String license;
@ApiModelProperty("头像")
private String avatar;
@ApiModelProperty("简介")
private String profile;
@ApiModelProperty("状态")
private Integer status;
@ApiModelProperty("营业部ID")
private String deptId;
@ApiModelProperty("营业部名称")
private String deptName;
@ApiModelProperty("创建时间")
private LocalDateTime createTime;
@ApiModelProperty("发布时间")
private LocalDateTime publishTime;
@ApiModelProperty("标签")
private List<String> tagList;
@ApiModelProperty("粉丝数")
private Integer followCount;
@ApiModelProperty("是否关注 1:已关注;2:未关注")
private Integer isFollow;
public AdvisorInfoAppVO(AdvisorInfo advisorInfo, List<Tag> tagList, Integer followCount, String deptName) {
this.id = advisorInfo.getId();
this.staffNo = advisorInfo.getStaffNo();
this.name = advisorInfo.getName();
this.showName = advisorInfo.getShowName();
this.license = advisorInfo.getLicense();
this.avatar = advisorInfo.getAvatar();
this.profile = advisorInfo.getProfile();
this.followCount = followCount == null ? 0 : followCount;
this.tagList = tagList.stream().map(Tag::getName).collect(Collectors.toList());
this.deptId = advisorInfo.getDeptId();
this.deptName = deptName;
this.status = advisorInfo.getStatus();
this.createTime = advisorInfo.getCreateTime();
this.publishTime = advisorInfo.getPublishTime();
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getShowName() {
return showName;
}
public void setShowName(String showName) {
this.showName = showName;
}
public String getLicense() {
return license;
}
public void setLicense(String license) {
this.license = license;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public String getProfile() {
return profile;
}
public void setProfile(String profile) {
this.profile = profile;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public List<String> getTagList() {
return tagList;
}
public void setTagList(List<String> tagList) {
this.tagList = tagList;
}
public Integer getFollowCount() {
return followCount;
}
public void setFollowCount(Integer followCount) {
this.followCount = followCount;
}
public Integer getIsFollow() {
return isFollow;
}
public void setIsFollow(Integer isFollow) {
this.isFollow = isFollow;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public String getDeptId() {
return deptId;
}
public void setDeptId(String deptId) {
this.deptId = deptId;
}
public String getStaffNo() {
return staffNo;
}
public void setStaffNo(String staffNo) {
this.staffNo = staffNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getPublishTime() {
return publishTime;
}
public void setPublishTime(LocalDateTime publishTime) {
this.publishTime = publishTime;
}
}

View File

@ -0,0 +1,20 @@
package com.upchina.app.constants;
// 订单状态 新订单180已开通220已停用/已退款90已过期80已取消70关闭权限但未退款230
public enum AppOrderStatus {
NEW(180, "新订单"),
OPENED(220, "已开通"),
REFUNDED(90, "已停用/已退款"),
EXPIRED(80, "已过期"),
CANCELED(70, "已取消"),
CLOSED_UN_REFUNDED(230, "关闭权限但未退款");
public final Integer value;
public final String name;
AppOrderStatus(Integer value, String name) {
this.value = value;
this.name = name;
}
}

View File

@ -0,0 +1,33 @@
package com.upchina.app.controller;
import com.upchina.common.query.AppUserInfoQuery;
import com.upchina.common.result.CommonResult;
import com.upchina.common.service.AppUserService;
import com.upchina.common.vo.AppCUserInfoVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@Api(tags = "App用户信息")
@RestController
@RequestMapping("/app/user/")
@Validated
public class AppUserController {
@Resource
private AppUserService appUserService;
@ApiOperation("获取C端用户信息")
@PostMapping("getUserInfo")
public CommonResult<AppCUserInfoVO> getUserInfo(@Validated @RequestBody AppUserInfoQuery query) {
AppCUserInfoVO vo = appUserService.getUserInfo(query);
return CommonResult.success(vo);
}
}

View File

@ -0,0 +1,292 @@
package com.upchina.app.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* <p>
* C端订单
* </p>
*
* @author easonzhu
* @since 2024-11-07
*/
public class AppOrder implements Serializable {
/**
* 订单号
*/
@TableId("order_id")
private String orderId;
/**
* 产品ID
*/
@TableField("product_id")
private String productId;
/**
* 产品名称
*/
@TableField("product_name")
private String productName;
/**
* 用户名\UPID
*/
@TableField("user_name")
private String userName;
/**
* 订单状态 新订单180已开通220已停用/已退款90已过期80已取消70关闭权限但未退款230
*/
private Integer status;
/**
* 支付状态 1:已支付 2:未支付
*/
@TableField("pay_status")
private Integer payStatus;
/**
* 订单金额
*/
@TableField("total_price")
private BigDecimal totalPrice;
/**
* 支付金额
*/
@TableField("pay_total")
private BigDecimal payTotal;
/**
* 下单渠道
*/
private Integer currch;
/**
* 扩展信息
*/
@TableField("ext_info")
private String extInfo;
/**
* 传参
*/
private String bvideo;
/**
* 视频ID
*/
@TableField("video_id")
private Integer videoId;
/**
* 视频类型 3:直播
*/
@TableField("product_type")
private Integer productType;
/**
* 营销人员
*/
@TableField("sale_user_id")
private Integer saleUserId;
/**
* 下单时间
*/
@TableField("order_time")
private LocalDateTime orderTime;
/**
* 支付时间
*/
@TableField("pay_time")
private LocalDateTime payTime;
/**
* 创建时间
*/
@TableField("create_time")
private LocalDateTime createTime;
/**
* 更新时间
*/
@TableField("update_time")
private LocalDateTime updateTime;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Integer getPayStatus() {
return payStatus;
}
public void setPayStatus(Integer payStatus) {
this.payStatus = payStatus;
}
public BigDecimal getTotalPrice() {
return totalPrice;
}
public void setTotalPrice(BigDecimal totalPrice) {
this.totalPrice = totalPrice;
}
public BigDecimal getPayTotal() {
return payTotal;
}
public void setPayTotal(BigDecimal payTotal) {
this.payTotal = payTotal;
}
public Integer getCurrch() {
return currch;
}
public void setCurrch(Integer currch) {
this.currch = currch;
}
public String getExtInfo() {
return extInfo;
}
public void setExtInfo(String extInfo) {
this.extInfo = extInfo;
}
public String getBvideo() {
return bvideo;
}
public void setBvideo(String bvideo) {
this.bvideo = bvideo;
}
public Integer getVideoId() {
return videoId;
}
public void setVideoId(Integer videoId) {
this.videoId = videoId;
}
public Integer getProductType() {
return productType;
}
public void setProductType(Integer productType) {
this.productType = productType;
}
public Integer getSaleUserId() {
return saleUserId;
}
public void setSaleUserId(Integer saleUserId) {
this.saleUserId = saleUserId;
}
public LocalDateTime getOrderTime() {
return orderTime;
}
public void setOrderTime(LocalDateTime orderTime) {
this.orderTime = orderTime;
}
public LocalDateTime getPayTime() {
return payTime;
}
public void setPayTime(LocalDateTime payTime) {
this.payTime = payTime;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
@Override
public String toString() {
return "AppOrder{" +
"orderId=" + orderId +
", productId=" + productId +
", productName=" + productName +
", userName=" + userName +
", status=" + status +
", totalPrice=" + totalPrice +
", payTotal=" + payTotal +
", currch=" + currch +
", extInfo=" + extInfo +
", bvideo=" + bvideo +
", videoId=" + videoId +
", productType=" + productType +
", saleUserId=" + saleUserId +
", orderTime=" + orderTime +
", payTime=" + payTime +
", createTime=" + createTime +
", updateTime=" + updateTime +
"}";
}
}

View File

@ -0,0 +1,108 @@
package com.upchina.app.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
/**
* <p>
* B端C端关系表
* </p>
*
* @author easonzhu
* @since 2024-10-29
*/
public class AppRels implements Serializable {
/**
* B端ID
*/
private String bid;
/**
* C端ID
*/
private String cid;
/**
* 名称
*/
private String name;
/**
* 类型 1:部门 2:员工
*/
private Integer type;
/**
* 子类型
*/
@TableField("sub_type")
private Integer subType;
/**
* 状态 1:有效 2:无效
*/
private Integer status;
public String getBid() {
return bid;
}
public void setBid(String bid) {
this.bid = bid;
}
public String getCid() {
return cid;
}
public void setCid(String cid) {
this.cid = cid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
public Integer getSubType() {
return subType;
}
public void setSubType(Integer subType) {
this.subType = subType;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
@Override
public String toString() {
return "AppRels{" +
"bid=" + bid +
", cid=" + cid +
", name=" + name +
", type=" + type +
", subType=" + subType +
", status=" + status +
"}";
}
}

View File

@ -0,0 +1,16 @@
package com.upchina.app.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.upchina.app.entity.AppOrder;
/**
* <p>
* C端订单 Mapper 接口
* </p>
*
* @author easonzhu
* @since 2024-11-07
*/
public interface AppOrderMapper extends BaseMapper<AppOrder> {
}

View File

@ -0,0 +1,16 @@
package com.upchina.app.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.upchina.app.entity.AppRels;
/**
* <p>
* B端C端关系表 Mapper 接口
* </p>
*
* @author easonzhu
* @since 2024-10-29
*/
public interface AppRelsMapper extends BaseMapper<AppRels> {
}

View File

@ -0,0 +1,52 @@
package com.upchina.app.schedule;
import com.upchina.app.service.OrderSyncService;
import com.upchina.common.config.cache.CacheKey;
import com.upchina.common.service.CacheService;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;
@Component
public class AppTask {
@Resource
private CacheService cacheService;
@Resource
private OrderSyncService orderSyncService;
/**
* 拉取云端视频转码状态
*/
@Scheduled(cron = "${cron.syncAppOrderRecent}")
public void syncAppOrder() {
cacheService.lock(CacheKey.LockKey.SYNC_APP_ORDER,
0, TimeUnit.SECONDS,
4, TimeUnit.MINUTES,
() -> {
LocalDateTime now = LocalDateTime.now();
LocalDateTime startTime = now.plusDays(-1);
orderSyncService.syncAppOrder(startTime, now);
}
);
}
@Scheduled(cron = "${cron.syncAppOrderHistory}")
public void saveWatchSeconds() {
cacheService.lock(CacheKey.LockKey.SYNC_APP_ORDER,
0, TimeUnit.SECONDS,
4, TimeUnit.MINUTES,
() -> {
LocalDateTime now = LocalDateTime.now();
LocalDateTime startTime = now.plusDays(-7);
LocalDateTime endTime = now.plusDays(-1);
orderSyncService.syncAppOrder(startTime, endTime);
}
);
}
}

View File

@ -0,0 +1,47 @@
package com.upchina.app.service;
import cn.hutool.core.util.StrUtil;
import com.hazelcast.org.apache.calcite.util.Holder;
import com.upchina.common.util.LoggerUtil;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@Service
public class CouponService {
private final int pageSize = 100;
/**
* 查询视频优惠券
*
* @param videoId 视频ID
* @return 优惠券Map key: 用户ID value: 优惠券列表
*/
public Map<String, List<Object>> queryVideoCoupon(Integer videoId) {
return null;
}
/**
* 查询用户优惠券
*
* @param userId 用户ID
* @return 优惠券Map key: 视频ID value: 优惠券列表
*/
public Map<Integer, List<Object>> queryUserCoupon(String userId) {
return null;
}
public int queryCouponCount(Integer videoId) {
return 0;
}
private List<Object> queryCoupon(Integer videoId, String userId) {
return null;
}
}

View File

@ -0,0 +1,73 @@
package com.upchina.app.service;
import cn.hutool.core.util.StrUtil;
import com.hazelcast.org.apache.calcite.util.Holder;
import com.upchina.common.util.LoggerUtil;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@Service
public class CouponService {
private final int pageSize = 100;
/**
* 查询视频优惠券
*
* @param videoId 视频ID
* @return 优惠券Map key: 用户ID value: 优惠券列表
*/
public Map<String, List<Object>> queryVideoCoupon(Integer videoId) {
return null;
}
/**
* 查询用户优惠券
*
* @param userId 用户ID
* @return 优惠券Map key: 视频ID value: 优惠券列表
*/
public Map<Integer, List<Object>> queryUserCoupon(String userId) {
return null;
}
public int queryCouponCount(Integer videoId) {
return 0;
}
private List<UserCoupon> queryCoupon(Integer videoId, String userId) {
List<UserCoupon> results = new ArrayList<>();
// 先查第一页获取总数
LiveCouponReq req = new LiveCouponReq();
if (videoId != null && videoId > 0) {
req.setLiveId(videoId);
}
if (StrUtil.isNotEmpty(userId)) {
req.setFundId(userId);
}
req.setCurrent(1);
req.setSize(pageSize);
Holder<LiveCouponRsp> holder = new Holder<>();
orderSystemPrx.getLiveCoupons(req, holder);
LiveCouponRsp firstPage = holder.getValue();
results.addAll(firstPage.getUserCoupon());
// 计算总页数如果总页数超过1再查剩下的页
long total = firstPage.getTotal();
int totalPage = total % pageSize == 0 ? (int) (total / pageSize) : (int) (total / pageSize) + 1;
LoggerUtil.info("优惠券总数:" + total, "页数:" + totalPage);
for (int i = 2; i <= totalPage; i++) {
req.setCurrent(i);
holder = new Holder<>();
orderSystemPrx.getLiveCoupons(req, holder);
LiveCouponRsp page = holder.getValue();
results.addAll(page.getUserCoupon());
}
return results;
}
}

View File

@ -0,0 +1,296 @@
package com.upchina.app.service;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Table;
import com.upchina.app.constants.AppOrderStatus;
import com.upchina.app.entity.AppOrder;
import com.upchina.app.mapper.AppOrderMapper;
import com.upchina.app.vo.OrderStatCollect;
import com.upchina.common.constant.IsOrNot;
import com.upchina.common.constant.ProductType;
import com.upchina.video.vo.statistic.VideoLiveProductSaleVO;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class OrderQueryService {
@Resource
private AppOrderMapper appOrderMapper;
/*
* 订单状态 新订单180已开通220已停用/已退款90已过期80已取消70关闭权限但未退款230
* 已支付包含: 已开通220已停用/已退款90已过期80关闭权限但未退款230
* 未支付包含: 新订单180已取消70
*/
public static final Set<Integer> PAID_STATUS = ImmutableSet.of(AppOrderStatus.OPENED.value, AppOrderStatus.REFUNDED.value, AppOrderStatus.EXPIRED.value, AppOrderStatus.CLOSED_UN_REFUNDED.value);
public static final Set<Integer> UNPAID_STATUS = ImmutableSet.of(AppOrderStatus.NEW.value, AppOrderStatus.CANCELED.value);
public static final String PAID_STATUS_STR = PAID_STATUS.stream().map(String::valueOf).collect(Collectors.joining(","));
public static final String UNPAID_STATUS_STR = UNPAID_STATUS.stream().map(String::valueOf).collect(Collectors.joining(","));
public OrderStatCollect queryOrderCollect(Integer videoId, ProductType productType) {
return queryOrderCollect(videoId, null, productType);
}
public OrderStatCollect queryOrderCollect(Collection<Integer> videoIds, ProductType productType) {
return queryOrderCollect(null, videoIds, productType);
}
/**
* 查询订单支付状态Map
*
* @param videoId 视频ID
* @param productType 产品类型
* @return 订单支付状态Map key: 是否支付 value: 订单统计
*/
public OrderStatCollect queryOrderCollect(Integer videoId, Collection<Integer> videoIds, @NotNull ProductType productType) {
// 计算订单汇总
QueryWrapper<AppOrder> orderWrapper = Wrappers.<AppOrder>query()
// 用sale_user_id保存订单数量
.select("pay_status",
"ifnull(count(1), 0) as sale_user_id",
"IFNULL(SUM(total_price), 0) AS total_price",
"IFNULL(SUM(pay_total), 0) AS pay_total",
"IFNULL(COUNT(distinct user_name), 0) AS product_type")
.eq(videoId != null, "video_id", videoId)
.in(CollUtil.isNotEmpty(videoIds), "video_id", videoIds)
.eq("product_type", productType.value)
.isNotNull("pay_status")
.groupBy("pay_status WITH ROLLUP");
List<AppOrder> orders = appOrderMapper.selectList(orderWrapper);
OrderStatCollect result = new OrderStatCollect();
for (AppOrder order : orders) {
if (IsOrNot.IS.value.equals(order.getPayStatus())) {
result.setPayCount(order.getSaleUserId());
result.setPayAmount(order.getPayTotal());
result.setPayUserCount(order.getProductType());
} else if (IsOrNot.NOT.value.equals(order.getPayStatus())) {
result.setUnPayCount(order.getSaleUserId());
result.setUnPayAmount(order.getTotalPrice());
result.setUnPayUserCount(order.getProductType());
} else if (order.getPayStatus() == null) {
result.setCount(order.getSaleUserId());
result.setOrderAmount(order.getTotalPrice());
result.setUserCount(order.getProductType());
}
}
return result;
}
/**
* 查询某位营销人员产生的订阅用户ID集合
*
* @param saleUserId 营销人员ID
* @return 订阅用户ID集合
*/
public Set<String> querySubUserBySaleUser(Integer saleUserId) {
QueryWrapper<AppOrder> wrapper = Wrappers.<AppOrder>query()
.select("distinct user_name")
.eq(saleUserId != null && saleUserId != 0, "sale_user_id", saleUserId);
List<AppOrder> orders = appOrderMapper.selectList(wrapper);
return orders.stream().map(AppOrder::getUserName).collect(Collectors.toSet());
}
/**
* 查询某些用户的已支付订单统计
*
* @param userIds 用户ID集合
* @return 用户订单统计Map key: 用户ID value: 订单统计
*/
public Map<String, OrderStatCollect> queryUserPayOrderCollect(Set<String> userIds) {
if (CollUtil.isEmpty(userIds)) {
return Collections.emptyMap();
}
QueryWrapper<AppOrder> wrapper = Wrappers.<AppOrder>query()
.select("user_name",
"IFNULL(SUM(total_price), 0) AS total_price",
"IFNULL(SUM(pay_total), 0) AS pay_total",
"IFNULL(COUNT(1), 0) AS sale_user_id")
.in("user_name", userIds)
.eq("pay_status", IsOrNot.IS.value)
.groupBy("user_name");
List<AppOrder> orders = appOrderMapper.selectList(wrapper);
return orders.stream().collect(Collectors.toMap(AppOrder::getUserName, order -> {
OrderStatCollect orderStatCollect = new OrderStatCollect();
orderStatCollect.setOrderAmount(order.getTotalPrice());
orderStatCollect.setPayAmount(order.getPayTotal());
orderStatCollect.setPayCount(order.getSaleUserId());
return orderStatCollect;
}));
}
/**
* 查询某位用户各产品的订阅订单
*
* @param userId 用户ID
* @return Table row:产品类型 column:视频ID value:订单列表
*/
public Table<Integer, Integer, List<AppOrder>> queryUserSignVideoOrders(String userId) {
Table<Integer, Integer, List<AppOrder>> table = HashBasedTable.create();
if (StrUtil.isEmpty(userId)) {
return table;
}
QueryWrapper<AppOrder> wrapper = Wrappers.<AppOrder>query()
.eq("user_name", userId)
.eq("pay_status", IsOrNot.IS.value);
List<AppOrder> orders = appOrderMapper.selectList(wrapper);
for (AppOrder order : orders) {
Integer productType = order.getProductType();
Integer videoId = order.getVideoId();
List<AppOrder> list = table.get(productType, videoId);
if (list == null) {
list = CollUtil.newArrayList();
table.put(productType, videoId, list);
}
list.add(order);
}
return table;
}
/**
* 查询某些视频的订单周期汇总数据
*
* @param productType 产品类型
* @param videoIds 视频ID集合
* @param format 周期格式
* @return 订单周期汇总Map key:周期 value:订单统计
*/
public Map<String, OrderStatCollect> queryCycleOrderCollect(@NotNull ProductType productType, Set<Integer> videoIds, CycleFormat format) {
QueryWrapper<AppOrder> totalWrapper = Wrappers.<AppOrder>query()
.select("DATE_FORMAT(order_time, '" + format + "') AS order_id",
"IFNULL(SUM(total_price), 0) AS total_price",
"IFNULL(COUNT(1), 0) AS sale_user_id")
.in(CollUtil.isNotEmpty(videoIds), "video_id", videoIds)
.eq(productType != null, "product_type", productType.value)
.groupBy("DATE_FORMAT(order_time, '" + format.format + "')")
// 必须用last替代orderBy不然MyBatis会移除格式里面的空格
.last("ORDER BY DATE_FORMAT(order_time, '" + format.format + "')");
List<AppOrder> totalOrders = appOrderMapper.selectList(totalWrapper);
QueryWrapper<AppOrder> paidWrapper = Wrappers.<AppOrder>query()
.select("DATE_FORMAT(order_time, '" + format.format + "') AS order_id",
"IFNULL(SUM(pay_total), 0) AS pay_total",
"IFNULL(COUNT(1), 0) AS sale_user_id")
.in(CollUtil.isNotEmpty(videoIds), "video_id", videoIds)
.eq(productType != null, "product_type", productType.value)
.eq("pay_status", IsOrNot.IS.value)
.groupBy("DATE_FORMAT(order_time, '" + format.format + "')")
// 必须用last替代orderBy不然MyBatis会移除格式里面的空格
.last("ORDER BY DATE_FORMAT(order_time, '" + format.format + "')");
List<AppOrder> paidOrders = appOrderMapper.selectList(paidWrapper);
Map<String, AppOrder> paidOrderMap = paidOrders.stream().collect(Collectors.toMap(AppOrder::getOrderId, order -> order));
return totalOrders.stream().collect(Collectors.toMap(AppOrder::getOrderId, order -> {
OrderStatCollect orderStatCollect = new OrderStatCollect();
orderStatCollect.setCount(order.getSaleUserId());
orderStatCollect.setOrderAmount(order.getTotalPrice());
AppOrder paidOrder = paidOrderMap.get(order.getOrderId());
if (paidOrder != null) {
orderStatCollect.setPayCount(paidOrder.getSaleUserId());
orderStatCollect.setPayAmount(paidOrder.getPayTotal());
orderStatCollect.setUnPayCount(order.getSaleUserId() - paidOrder.getSaleUserId());
} else {
orderStatCollect.setPayCount(0);
orderStatCollect.setPayAmount(BigDecimal.ZERO);
orderStatCollect.setUnPayCount(order.getSaleUserId());
}
return orderStatCollect;
}));
}
/**
* 查询某些视频的订单统计数据
*/
public Map<Integer, OrderStatCollect> queryVideoOrderCollect(ProductType productType, Set<Integer> videoIds) {
QueryWrapper<AppOrder> wrapper = Wrappers.<AppOrder>query()
.select("video_id",
"IFNULL(SUM(total_price), 0) AS total_price",
"IFNULL(SUM(pay_total), 0) AS pay_total",
"IFNULL(COUNT(1), 0) AS sale_user_id")
.in(CollUtil.isNotEmpty(videoIds), "video_id", videoIds)
.eq(productType != null, "product_type", productType.value)
.eq("pay_status", IsOrNot.IS.value)
.groupBy("video_id");
List<AppOrder> orders = appOrderMapper.selectList(wrapper);
return orders.stream().collect(Collectors.toMap(AppOrder::getVideoId, order -> {
OrderStatCollect orderStatCollect = new OrderStatCollect();
orderStatCollect.setCount(order.getSaleUserId());
orderStatCollect.setPayCount(order.getSaleUserId());
orderStatCollect.setOrderAmount(order.getTotalPrice());
orderStatCollect.setPayAmount(order.getPayTotal());
return orderStatCollect;
}));
}
/**
* 查询直播间产品销量
*/
public List<VideoLiveProductSaleVO> queryVideoLiveProductSale(Integer videoId) {
QueryWrapper<AppOrder> wrapper = Wrappers.<AppOrder>query()
.select("product_id, product_name",
"IFNULL(SUM(pay_total), 0) AS pay_total",
"IFNULL(COUNT(1), 0) AS sale_user_id")
.eq("video_id", videoId)
.eq("product_type", ProductType.VIDEO_SINGLE.value)
.eq("pay_status", IsOrNot.IS.value)
.groupBy("product_id", "product_name")
.orderByDesc("IFNULL(COUNT(1), 0)");
List<AppOrder> orders = appOrderMapper.selectList(wrapper);
return orders.stream().map(order -> new VideoLiveProductSaleVO(order.getProductName(), order.getSaleUserId(), order.getPayTotal())).collect(Collectors.toList());
}
/**
* 查询某视频的订单用户订阅的产品名称
*
* @param videoId 视频ID
* @param payStatus 支付状态
* @return 用户订阅的产品名称Map key: 用户名 value: 产品名称列表
*/
public Map<String, List<String>> calUserOrderName(Integer videoId, Integer payStatus) {
LambdaQueryWrapper<AppOrder> wrapper = Wrappers.<AppOrder>lambdaQuery()
.eq(AppOrder::getVideoId, videoId)
.in(payStatus != null, AppOrder::getPayStatus, payStatus);
List<AppOrder> orderList = appOrderMapper.selectList(wrapper);
return orderList.stream()
.collect(Collectors.groupingBy(AppOrder::getUserName,
Collectors.mapping(AppOrder::getProductName, Collectors.toList())));
}
/**
* 订单周期格式
* 符合MySQL DATE_FORMAT函数格式
*/
public static class CycleFormat {
private final String format;
private CycleFormat(String format) {
this.format = format;
}
public static final CycleFormat YEAR = new CycleFormat("%Y");
public static final CycleFormat MONTH = new CycleFormat("%Y-%m");
public static final CycleFormat DAY = new CycleFormat("%Y-%m-%d");
public static final CycleFormat HOUR = new CycleFormat("%Y-%m-%d %H");
public static final CycleFormat MINUTE = new CycleFormat("%Y-%m-%d %H:%i");
@Override
public String toString() {
return format;
}
}
}

View File

@ -0,0 +1,48 @@
package com.upchina.app.service;
import com.upchina.app.entity.AppOrder;
import com.upchina.app.mapper.AppOrderMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Objects;
@Service
public class OrderSyncService {
@Resource
private AppOrderMapper appOrderMapper;
@Transactional(rollbackFor = Exception.class)
public void syncAppOrder(LocalDateTime startTime, LocalDateTime endTime) {
// TODO
}
private boolean isEqual(AppOrder a, AppOrder b) {
return Objects.equals(a.getOrderId(), b.getOrderId())
&& Objects.equals(a.getProductId(), b.getProductId())
&& Objects.equals(a.getProductName(), b.getProductName())
&& Objects.equals(a.getUserName(), b.getUserName())
&& Objects.equals(a.getStatus(), b.getStatus())
&& Objects.equals(a.getPayStatus(), b.getPayStatus())
&& isEqual(a.getTotalPrice(), b.getTotalPrice())
&& isEqual(a.getPayTotal(), b.getPayTotal())
&& Objects.equals(a.getCurrch(), b.getCurrch())
&& Objects.equals(a.getExtInfo(), b.getExtInfo())
&& Objects.equals(a.getBvideo(), b.getBvideo())
&& Objects.equals(a.getVideoId(), b.getVideoId())
&& Objects.equals(a.getProductType(), b.getProductType())
&& Objects.equals(a.getSaleUserId(), b.getSaleUserId())
&& Objects.equals(a.getOrderTime(), b.getOrderTime())
&& Objects.equals(a.getPayTime(), b.getPayTime());
}
// BigDecimal忽略精度比较
private boolean isEqual(BigDecimal a, BigDecimal b) {
return a == null ? b == null : a.compareTo(b) == 0;
}
}

View File

@ -0,0 +1,189 @@
package com.upchina.app.vo;
import cn.hutool.core.date.DatePattern;
import com.upchina.advisor.entity.AdvisorBasic;
import com.upchina.video.entity.VideoLive;
import java.io.Serializable;
public class LiveDetailVO implements Serializable {
private Integer id;
private String title;
private String listCoverUrl;
private String coverUrl;
private Integer advisorId;
private String advisorName;
private String advisorAvatar;
private String liveUrl;
private Integer liveStatus;
private Integer status;
private String startTime;
private String endTime;
private Integer readCount;
private Integer messageCount;
private Integer favorCount;
private Integer isRecommend;
private Integer isDisplay;
public LiveDetailVO() {
}
public LiveDetailVO(VideoLive live, AdvisorBasic advisor, String liveUrl, Integer readCount, Integer messageCount, Integer favorCount) {
this.id = live.getId();
this.title = live.getTitle();
this.listCoverUrl = live.getListCoverUrl();
this.advisorId = live.getAdvisorId();
if (advisor != null) {
this.advisorName = advisor.getShowName();
this.advisorAvatar = advisor.getAvatar();
}
this.liveUrl = liveUrl;
this.coverUrl = live.getImgUrl();
this.liveStatus = live.getLiveStatus();
this.status = live.getStatus();
this.startTime = live.getStartTime().format(DatePattern.NORM_DATETIME_FORMATTER);
this.endTime = live.getEndTime().format(DatePattern.NORM_DATETIME_FORMATTER);
this.readCount = readCount;
this.messageCount = messageCount;
this.favorCount = favorCount;
this.isRecommend = live.getIsRecommend();
this.isDisplay = live.getIsDisplay();
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getListCoverUrl() {
return listCoverUrl;
}
public void setListCoverUrl(String listCoverUrl) {
this.listCoverUrl = listCoverUrl;
}
public String getCoverUrl() {
return coverUrl;
}
public void setCoverUrl(String coverUrl) {
this.coverUrl = coverUrl;
}
public Integer getAdvisorId() {
return advisorId;
}
public void setAdvisorId(Integer advisorId) {
this.advisorId = advisorId;
}
public String getAdvisorName() {
return advisorName;
}
public void setAdvisorName(String advisorName) {
this.advisorName = advisorName;
}
public String getAdvisorAvatar() {
return advisorAvatar;
}
public void setAdvisorAvatar(String advisorAvatar) {
this.advisorAvatar = advisorAvatar;
}
public String getLiveUrl() {
return liveUrl;
}
public void setLiveUrl(String liveUrl) {
this.liveUrl = liveUrl;
}
public Integer getLiveStatus() {
return liveStatus;
}
public void setLiveStatus(Integer liveStatus) {
this.liveStatus = liveStatus;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public String getStartTime() {
return startTime;
}
public void setStartTime(String startTime) {
this.startTime = startTime;
}
public String getEndTime() {
return endTime;
}
public void setEndTime(String endTime) {
this.endTime = endTime;
}
public Integer getReadCount() {
return readCount;
}
public void setReadCount(Integer readCount) {
this.readCount = readCount;
}
public Integer getMessageCount() {
return messageCount;
}
public void setMessageCount(Integer messageCount) {
this.messageCount = messageCount;
}
public Integer getFavorCount() {
return favorCount;
}
public void setFavorCount(Integer favorCount) {
this.favorCount = favorCount;
}
public Integer getIsRecommend() {
return isRecommend;
}
public void setIsRecommend(Integer isRecommend) {
this.isRecommend = isRecommend;
}
public Integer getIsDisplay() {
return isDisplay;
}
public void setIsDisplay(Integer isDisplay) {
this.isDisplay = isDisplay;
}
}

View File

@ -0,0 +1,45 @@
package com.upchina.app.vo;
import java.io.Serializable;
import java.util.List;
import java.util.stream.Collectors;
public class LiveListVO implements Serializable {
public List<LiveDetailVO> result;
public Integer total;
public String listUrl;
public LiveListVO() {
}
public LiveListVO(List<LiveDetailVO> result, Integer total, String listUrl) {
this.result = result;
this.total = total;
this.listUrl = listUrl;
}
public List<LiveDetailVO> getResult() {
return result;
}
public void setResult(List<LiveDetailVO> result) {
this.result = result;
}
public Integer getTotal() {
return total;
}
public void setTotal(Integer total) {
this.total = total;
}
public String getListUrl() {
return listUrl;
}
public void setListUrl(String listUrl) {
this.listUrl = listUrl;
}
}

View File

@ -0,0 +1,135 @@
package com.upchina.app.vo;
import java.io.Serializable;
import java.math.BigDecimal;
public class OrderStatCollect implements Serializable {
// 订单数量
private Integer count;
// 未支付数量
private Integer unPayCount;
// 支付数量
private Integer payCount;
// 订单金额
private BigDecimal orderAmount;
// 未支付金额
private BigDecimal unPayAmount;
// 支付金额
private BigDecimal payAmount;
// 用户数
private Integer userCount;
// 未支付用户数
private Integer unPayUserCount;
// 支付用户数
private Integer payUserCount;
public OrderStatCollect() {
this.count = 0;
this.unPayCount = 0;
this.payCount = 0;
this.orderAmount = BigDecimal.ZERO;
this.unPayAmount = BigDecimal.ZERO;
this.payAmount = BigDecimal.ZERO;
this.userCount = 0;
this.unPayUserCount = 0;
this.payUserCount = 0;
}
public Integer getPayUserCount() {
return payUserCount;
}
public void setPayUserCount(Integer payUserCount) {
this.payUserCount = payUserCount;
}
public Integer getUnPayUserCount() {
return unPayUserCount;
}
public void setUnPayUserCount(Integer unPayUserCount) {
this.unPayUserCount = unPayUserCount;
}
public Integer getUserCount() {
return userCount;
}
public void setUserCount(Integer userCount) {
this.userCount = userCount;
}
public BigDecimal getPayAmount() {
return payAmount;
}
public void setPayAmount(BigDecimal payAmount) {
this.payAmount = payAmount;
}
public BigDecimal getUnPayAmount() {
return unPayAmount;
}
public void setUnPayAmount(BigDecimal unPayAmount) {
this.unPayAmount = unPayAmount;
}
public BigDecimal getOrderAmount() {
return orderAmount;
}
public void setOrderAmount(BigDecimal orderAmount) {
this.orderAmount = orderAmount;
}
public Integer getPayCount() {
return payCount;
}
public void setPayCount(Integer payCount) {
this.payCount = payCount;
}
public Integer getUnPayCount() {
return unPayCount;
}
public void setUnPayCount(Integer unPayCount) {
this.unPayCount = unPayCount;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
@Override
public String toString() {
return "OrderStatCollect{" +
"count=" + count +
", unPayCount=" + unPayCount +
", payCount=" + payCount +
", orderAmount=" + orderAmount +
", unPayAmount=" + unPayAmount +
", payAmount=" + payAmount +
", userCount=" + userCount +
", unPayUserCount=" + unPayUserCount +
", payUserCount=" + payUserCount +
'}';
}
}

View File

@ -0,0 +1,20 @@
package com.upchina.common.annotation;
import com.upchina.common.constant.AccessRole;
import java.lang.annotation.*;
@Target({ElementType.METHOD}) // 作用在方法上
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在在运行时可以通过反射获取到
@Documented // 说明该注解将被包含在javadoc中
public @interface Auth {
/**
* 角色
* 0普通员工
* 1管理员
* 2全部只验证登录状态不验证操作权限
*/
AccessRole role() default AccessRole.LOGIN;
}

View File

@ -0,0 +1,24 @@
package com.upchina.common.annotation;
import com.upchina.common.constant.ProductType;
import java.lang.annotation.*;
@Target({ElementType.METHOD}) // 作用在方法上
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在在运行时可以通过反射获取到
@Documented // 说明该注解将被包含在javadoc中
public @interface Operation {
// 业务类型0投顾 1观点包 2单篇观点 3视频产品类型5交易圈 6图文直播 7组合 8锦囊
ProductType module() default ProductType.ADVISOR_INFO;
// 业务对象主键id的key
String idKey() default "id";
// 业务对象状态的key
String statusKey() default "status";
// 操作理由的key
String reasonKey() default "reason";
}

View File

@ -0,0 +1,51 @@
package com.upchina.common.aspect;
import com.upchina.common.annotation.Auth;
import com.upchina.common.constant.AccessRole;
import com.upchina.common.vo.BackendUserVO;
import com.upchina.rbac.service.AuthService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
@Aspect
@Component
public class AuthAspect {
@Resource
AuthService authService;
@Pointcut("@annotation(com.upchina.common.annotation.Auth)")
private void pointcut() {
}
// 前置通知
@Before("pointcut()")
public void beforeCall(JoinPoint joinPoint) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
BackendUserVO backendUser = (BackendUserVO) request.getAttribute("backendUser");
// 获取注解中的参数值
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
// 获取注解
Auth annotation = method.getAnnotation(Auth.class);
// 获取注解参数的值
AccessRole role = annotation.role();
// 验证帐号的合法性
authService.checkUserStatus(backendUser, role);
String callUrl = request.getRequestURI();
// 校验权限
//authService.checkUserPermission(backendUser, callUrl);
}
}

View File

@ -0,0 +1,102 @@
package com.upchina.common.aspect;
import com.alibaba.fastjson.JSONObject;
import com.upchina.common.annotation.Operation;
import com.upchina.common.constant.ProductType;
import com.upchina.common.entity.OperationLog;
import com.upchina.common.handler.BizException;
import com.upchina.common.result.CommonResult;
import com.upchina.common.result.ResponseStatus;
import com.upchina.common.service.OperationLogService;
import com.upchina.common.vo.BackendUserVO;
import com.upchina.common.vo.InsertIdVO;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
@Aspect
@Component
public class OperationLogAspect {
@Resource
private OperationLogService operationLogService;
@Pointcut("@annotation(com.upchina.common.annotation.Operation)")
private void pointcut() {
}
@Around("pointcut()")
public Object log(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
BackendUserVO backendUser = (BackendUserVO) request.getAttribute("backendUser");
if (backendUser == null) {
throw new BizException(ResponseStatus.PARM_ERROR, "日志组件未找到backendUser");
}
// 获取传入进来的参数
Object[] args = proceedingJoinPoint.getArgs();
List<Object> ls = Arrays.asList(args);
Optional<Object> businessParam = ls.stream().filter(obj -> !(obj instanceof BackendUserVO)).findFirst();
if (!businessParam.isPresent()) {
throw new BizException(ResponseStatus.PARM_ERROR, "日志组件未找到业务参数data");
}
Object object = businessParam.get();
String param = JSONObject.toJSONString(object);
JSONObject busObject = JSONObject.parseObject(param);
// 获取注解中的参数值
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
Method method = methodSignature.getMethod();
Operation annotation = method.getAnnotation(Operation.class);
// 获取注解参数的值
ProductType module = annotation.module();
String idKey = annotation.idKey();
String statusKey = annotation.statusKey();
String reasonKey = annotation.reasonKey();
// 取业务数据
Integer id = busObject.getInteger(idKey);
Integer status = busObject.getInteger(statusKey);
String remark = busObject.getString(reasonKey);
CommonResult result = (CommonResult) proceedingJoinPoint.proceed();
if (result.isSuccess()) {
OperationLog operationLog = new OperationLog();
if (id != null) {
// 如果是仅修改数据不改状态的场景可能拿不到status就默认赋值99代表修改
operationLog.setOperateType(status == null ? 99 : status);
} else if (result.getData() instanceof Integer) {
id = (Integer) result.getData();
// 98代表新增
operationLog.setOperateType(98);
} else if (result.getData() instanceof InsertIdVO) {
InsertIdVO insertIdVO = (InsertIdVO) result.getData();
id = insertIdVO.getId();
// 98代表新增
operationLog.setOperateType(98);
} else {
return result;
}
operationLog.setBusinessId(id);
operationLog.setBusinessType(module.getValue());
operationLog.setOperatorId(backendUser.getUserId());
operationLog.setOperatorName(backendUser.getUserName());
operationLog.setCreateTime(LocalDateTime.now());
operationLog.setOperateParam(param);
operationLog.setRemark(remark);
operationLogService.saveOperationLog(operationLog);
}
return result;
}
}

View File

@ -0,0 +1,55 @@
package com.upchina.common.aspect;
import com.alibaba.fastjson.JSONObject;
import com.upchina.common.util.LoggerUtil;
import com.upchina.common.util.RequestIdUtil;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Date;
@Aspect
@Component
public class TafAspect {
@Pointcut("execution(public * com.upchina.tafserver..*.*(..))")
private void pointcut() {
}
// 前置通知
@Before("pointcut()")
public void beforeCall(JoinPoint joinPoint) {
RequestIdUtil.setTime();
RequestIdUtil.setValue();
// 获取注解中的参数值
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
LoggerUtil.info(String.format("taf:%s:param:%s", method.getName(), JSONObject.toJSONString(joinPoint.getArgs())));
}
// 最终通知
@AfterReturning(returning = "returnOb", pointcut = "pointcut())")
public void afterReturningCall(JoinPoint joinPoint, Object returnOb) {
long start = RequestIdUtil.getTime();
long time = new Date().getTime() - start;
// 获取注解中的参数值
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
LoggerUtil.info(String.format("taf:%s:耗时:%d", method.getName(), time));
LoggerUtil.info(String.format("taf:%s:result:%s", method.getName(), JSONObject.toJSONString(returnOb)));
}
// 异常通知
@AfterThrowing(value = "pointcut()", throwing = "ex")
public void afterThrowing(JoinPoint joinPoint, Exception ex) {
// 获取注解中的参数值
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
LoggerUtil.info(String.format("taf:%s:exception:%s", method.getName(), ExceptionUtils.getStackTrace(ex)));
}
}

View File

@ -0,0 +1,45 @@
package com.upchina.common.aspect;
import com.upchina.common.util.LoggerUtil;
import com.upchina.common.util.RequestIdUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Date;
@Aspect
@Component
public class TaskAspect {
@Pointcut("@annotation(org.springframework.scheduling.annotation.Scheduled)")
private void scheduledPointcut() {
}
// 前置通知
@Before("scheduledPointcut()")
public void beforeCall(JoinPoint joinPoint) {
RequestIdUtil.setTime();
RequestIdUtil.setValue("TIME");
// 获取注解中的参数值
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
LoggerUtil.data.info(String.format("定时任务:%s:启动了", method.getName()));
}
// 最终通知
@AfterReturning(pointcut = "scheduledPointcut()")
public void afterReturningCall(JoinPoint joinPoint) {
long start = RequestIdUtil.getTime();
long time = new Date().getTime() - start;
// 获取注解中的参数值
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
LoggerUtil.data.info(String.format("定时任务:%s:耗时:%d", method.getName(), time));
}
}

View File

@ -0,0 +1,82 @@
package com.upchina.common.aspect;
import com.alibaba.fastjson.JSONObject;
import com.upchina.common.util.LoggerUtil;
import com.upchina.common.util.RequestIdUtil;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.http.HttpEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Aspect
@Component
public class WebLogAspect {
@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
private void requestPointcut() {
}
@Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")
private void getPointcut() {
}
@Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)")
private void postPointcut() {
}
// 前置通知
@Before("requestPointcut() || getPointcut() || postPointcut()")
public void beforeCall(JoinPoint joinPoint) {
RequestIdUtil.setTime();
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
Object[] args = joinPoint.getArgs();
List<Object> arguments = new ArrayList<>();
for (Object arg : args) {
if (arg instanceof ServletRequest || arg instanceof ServletResponse || arg instanceof MultipartFile) {
//ServletRequest不能序列化从入参里排除否则报异常java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
//ServletResponse不能序列化 从入参里排除否则报异常java.lang.IllegalStateException: getOutputStream() has already been called for this response
continue;
}
arguments.add(arg);
}
if (!request.getRequestURI().contains("/swagger") && !request.getRequestURI().contains("/v3/api-docs")) {
LoggerUtil.data.info(String.format("%s:param:%s", request.getRequestURI(), JSONObject.toJSONString(arguments)));
}
}
// 最终通知
@AfterReturning(returning = "returnOb", pointcut = "requestPointcut() || getPointcut() || postPointcut())")
public void afterReturningCall(JoinPoint joinPoint, Object returnOb) {
long start = RequestIdUtil.getTime();
long time = new Date().getTime() - start;
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
if (!request.getRequestURI().contains("/swagger") && !request.getRequestURI().contains("/v3/api-docs") && !(returnOb instanceof HttpEntity)) {
LoggerUtil.data.info(String.format("%s:耗时:%d", request.getRequestURI(), time));
LoggerUtil.data.info(String.format("%s:result:%s", request.getRequestURI(), JSONObject.toJSONString(returnOb)));
}
}
// 异常通知
@AfterThrowing(value = "requestPointcut() || getPointcut() || postPointcut()", throwing = "ex")
public void afterThrowing(JoinPoint joinPoint, Exception ex) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
if (!request.getRequestURI().contains("/swagger") && !request.getRequestURI().contains("/v3/api-docs")) {
LoggerUtil.data.info(String.format("%s:exception:%s", request.getRequestURI(), ExceptionUtils.getStackTrace(ex)));
}
}
}

View File

@ -0,0 +1,78 @@
package com.upchina.common.aspect;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.upchina.common.handler.BizException;
import com.upchina.common.result.ResponseStatus;
import com.upchina.common.util.LoggerUtil;
import com.upchina.common.util.RequestIdUtil;
import com.upchina.common.vo.BackendUserVO;
import com.upchina.common.vo.FrontUserVO;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.stereotype.Component;
import java.util.*;
@Aspect
@Component
public class WebSocketAspect {
@Pointcut("@annotation(org.springframework.messaging.handler.annotation.MessageMapping)")
private void pointcut() {
}
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
RequestIdUtil.setValue();
Object[] args = joinPoint.getArgs();
List<Object> arguments = new ArrayList<>();
String destination = "";
for (Object arg : args) {
if (arg instanceof SimpMessageHeaderAccessor) {
SimpMessageHeaderAccessor accessor = (SimpMessageHeaderAccessor) arg;
destination = accessor.getDestination();
Map<String, Object> attributes = accessor.getSessionAttributes();
BackendUserVO backendUser = (BackendUserVO) attributes.get("backendUser");
FrontUserVO frontUser = (FrontUserVO) attributes.get("frontUser");
if (backendUser != null) {
arguments.add(backendUser);
}
if (frontUser != null) {
arguments.add(frontUser);
}
} else {
arguments.add(arg);
}
}
LoggerUtil.info(String.format("%s:param:%s", destination, JSONObject.toJSONString(arguments)));
}
@AfterThrowing(value = "pointcut()", throwing = "ex")
public void afterThrowing(JoinPoint joinPoint, Exception ex) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Class<?> clazz = methodSignature.getDeclaringType();
Object[] args = joinPoint.getArgs();
Optional<Object> accessorOptional = Arrays.stream(args).filter(obj -> obj instanceof SimpMessageHeaderAccessor).findFirst();
if (!accessorOptional.isPresent()) {
throw new BizException(ResponseStatus.PARM_ERROR, "WebSocket异常拦截未检查到accessor,请检查:" + clazz.getSimpleName() + "." + methodSignature.getMethod().getName() + "的入参");
}
SimpMessageHeaderAccessor accessor = (SimpMessageHeaderAccessor) accessorOptional.get();
Map<String, Object> attributes = accessor.getSessionAttributes();
// String sessionId = (String) attributes.get("sessionId");
// if (StrUtil.isEmpty(sessionId)) {
// throw new BizException(ResponseStatus.PARM_ERROR, "header里没有包含sessionId");
// }
// BackendUserVO backendUser = (BackendUserVO) attributes.get("backendUser");
// FrontUserVO frontUser = (FrontUserVO) attributes.get("frontUser");
if (ex instanceof TokenExpiredException) {
throw new BizException(ResponseStatus.SESSION_USER_LOGOUT);
}
}
}

View File

@ -0,0 +1,78 @@
package com.upchina.common.aspect;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.upchina.common.handler.BizException;
import com.upchina.common.result.ResponseStatus;
import com.upchina.common.util.LoggerUtil;
import com.upchina.common.util.RequestIdUtil;
import com.upchina.common.vo.BackendUserVO;
import com.upchina.common.vo.FrontUserVO;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.stereotype.Component;
import java.util.*;
@Aspect
@Component
public class WebSocketAspect {
@Pointcut("@annotation(org.springframework.messaging.handler.annotation.MessageMapping)")
private void pointcut() {
}
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
RequestIdUtil.setValue();
Object[] args = joinPoint.getArgs();
List<Object> arguments = new ArrayList<>();
String destination = "";
for (Object arg : args) {
if (arg instanceof SimpMessageHeaderAccessor) {
SimpMessageHeaderAccessor accessor = (SimpMessageHeaderAccessor) arg;
destination = accessor.getDestination();
Map<String, Object> attributes = accessor.getSessionAttributes();
BackendUserVO backendUser = (BackendUserVO) attributes.get("backendUser");
FrontUserVO frontUser = (FrontUserVO) attributes.get("frontUser");
if (backendUser != null) {
arguments.add(backendUser);
}
if (frontUser != null) {
arguments.add(frontUser);
}
} else {
arguments.add(arg);
}
}
LoggerUtil.info(String.format("%s:param:%s", destination, JSONObject.toJSONString(arguments)));
}
@AfterThrowing(value = "pointcut()", throwing = "ex")
public void afterThrowing(JoinPoint joinPoint, Exception ex) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Class<?> clazz = methodSignature.getDeclaringType();
Object[] args = joinPoint.getArgs();
Optional<Object> accessorOptional = Arrays.stream(args).filter(obj -> obj instanceof SimpMessageHeaderAccessor).findFirst();
if (!accessorOptional.isPresent()) {
throw new BizException(ResponseStatus.PARM_ERROR, "WebSocket异常拦截未检查到accessor,请检查:" + clazz.getSimpleName() + "." + methodSignature.getMethod().getName() + "的入参");
}
SimpMessageHeaderAccessor accessor = (SimpMessageHeaderAccessor) accessorOptional.get();
Map<String, Object> attributes = accessor.getSessionAttributes();
// String sessionId = (String) attributes.get("sessionId");
// if (StringUtils.isEmpty(sessionId)) {
// throw new BizException(ResponseStatus.PARM_ERROR, "header里没有包含sessionId");
// }
// BackendUserVO backendUser = (BackendUserVO) attributes.get("backendUser");
// FrontUserVO frontUser = (FrontUserVO) attributes.get("frontUser");
if (ex instanceof TokenExpiredException) {
throw new BizException(ResponseStatus.SESSION_USER_LOGOUT);
}
}
}

View File

@ -0,0 +1,15 @@
package com.upchina.common.config;
import com.github.tobato.fastdfs.FdfsClientConfig;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableMBeanExport;
import org.springframework.context.annotation.Import;
import org.springframework.jmx.support.RegistrationPolicy;
@Configuration
@Import(FdfsClientConfig.class)
// 解决jmx重复注册bean的问题
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
public class FastDFSConfig {
}

View File

@ -0,0 +1,47 @@
package com.upchina.common.config;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class JsonConfig {
static {
ParserConfig.getGlobalInstance().setSafeMode(true);
}
@Bean // 使用@Bean注入fastJsonHttpMessageConvert
public HttpMessageConverters fastJsonHttpMessageConverters() {
// 1.需要定义一个Convert转换消息的对象
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
// 2.添加fastjson的配置信息比如是否要格式化返回的json数据
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteMapNullValue, // 是否输出值为null的字段
SerializerFeature.WriteNullListAsEmpty, // 将Collection类型字段的字段空值输出为[]
// SerializerFeature.WriteNullNumberAsZero, // 将数值类型字段的空值输出为0
SerializerFeature.DisableCircularReferenceDetect, // 禁用循环引用
SerializerFeature.WriteDateUseDateFormat); //时间格式化
// 中文乱码解决方案
List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(new MediaType("application", "json", StandardCharsets.UTF_8));//设定json格式且编码为UTF-8
fastConverter.setSupportedMediaTypes(mediaTypes);
// 3.在convert中添加配置信息
fastConverter.setFastJsonConfig(fastJsonConfig);
return new HttpMessageConverters(fastConverter);
}
}

View File

@ -0,0 +1,24 @@
package com.upchina.common.config;
import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class OrikaConfig {
@Bean
public MapperFactory mapperFactory() {
return new DefaultMapperFactory.Builder().build();
}
// https://mp.weixin.qq.com/s?__biz=MzUxMzQ0Njc1NQ==&mid=2247493097&idx=2&sn=b5b64d84b474ddee51e4ffa53159db25&chksm=f957a3e5ce202af38cee3169bf26895693c53e2efcb129b66acad37cef9a0b2505e4ed500ca4&mpshare=1&scene=1&srcid=0625QYwhk4AMpon2SOzyWDap&sharer_sharetime=1625023400860&sharer_shareid=daeff53cf02c0a24905e98788b17a15c&version=3.1.11.3009&platform=win#rd
// https://www.cnblogs.com/liang-chen-fly/p/14475283.html
@Bean
public MapperFacade mapperFacade() {
return mapperFactory().getMapperFacade();
}
}

View File

@ -0,0 +1,22 @@
package com.upchina.common.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.Executors;
@Configuration
@ConditionalOnProperty(name = "scheduledEnable", havingValue = "true")
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// 开启定时任务多线程防止默认单线程阻塞问题超过核心线程数后还是会阻塞
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
}
}

View File

@ -0,0 +1,52 @@
package com.upchina.common.config;
import com.upchina.common.vo.BackendUserVO;
import com.upchina.common.vo.FrontUserVO;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.annotations.ApiIgnore;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* 利用swagger3构建API
*
* @author yuanchao
*/
@Configuration
public class Swagger3Config {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.enable(true)
.select()
.apis(RequestHandlerSelectors.basePackage("com.upchina")) //扫描该包下的所有需要在Swagger中展示的API@ApiIgnore注解标注的除外
.paths(PathSelectors.any())
.build()
.ignoredParameterTypes(HttpSession.class, HttpServletRequest.class, HttpServletResponse.class, FrontUserVO.class, BackendUserVO.class)
.ignoredParameterTypes(ApiIgnore.class);
}
//创建API的基本信息这些信息会在Swagger UI中进行显示
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("私域直播-投顾平台数据API")
.description("投顾平台数据API")
.termsOfServiceUrl("https://www.upchina.com/")
.contact(new Contact("", "", "martinyuan@upchina.com"))
.version("1.0")
.build();
}
}

View File

@ -0,0 +1,371 @@
package com.upchina.common.config;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.live.v20180801.LiveClient;
import com.tencentcloudapi.vod.v20180717.VodClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* <p>
* 腾讯云点播直播配置
* </p>
*
* @author fangliangbao
* @since 2022-09-16
*/
@Configuration
public class TencentCloudConfig {
/**
* 用于标识 API 调用者身份可以简单类比为用户名
*/
@Value("${tencent.secretId}")
private String secretId;
/**
* 用于验证 API 调用者的身份可以简单类比为密码
*/
@Value("${tencent.secretKey}")
private String secretKey;
/**
* 云点播请求域名
*/
@Value("${tencent.vodEndpoint}")
private String vodEndpoint;
/**
* 云直播请求域名
*/
@Value("${tencent.liveEndpoint}")
private String liveEndpoint;
/**
* 地域参数
*/
@Value("${tencent.region}")
private String region;
/**
* 当前账号AppId
*/
@Value("${tencent.appId}")
private Integer appId;
/**
* 推流路径
*/
@Value("${tencent.appName}")
private String appName;
/**
* 推流域名
*/
@Value("${tencent.pushHost}")
private String pushHost;
/**
* 推流地址
*/
@Value("${tencent.pushUrl}")
private String pushUrl;
/**
* 推流鉴权Key
*/
@Value("${tencent.pushKey}")
private String pushKey;
/**
* 播流域名
*/
@Value("${tencent.liveHost}")
private String liveHost;
/**
* 播流地址
*/
@Value("${tencent.liveUrl}")
private String liveUrl;
/**
* 播流鉴权Key
*/
@Value("${tencent.liveKey}")
private String liveKey;
/**
* 播流鉴权Key
*/
@Value("${tencent.liveFormat}")
private String liveFormat;
/**
* 防盗链Key
*/
@Value("${tencent.key}")
private String key;
/**
* 视频播放地址有效时间单位小时
*/
@Value("${tencent.expireHours}")
private Integer expireHours;
/**
* 播放的音视频类型可选值
* RawAdaptive未加密的 转自适应码流 输出
* ProtectedAdaptive私有加密或 DRM 保护的 转自适应码流 输出
* Transcode转码 后输出
* Original上传 的原始音视频
*/
@Value("${tencent.playKey}")
private String playKey;
/**
* 上传视频转码任务流
*/
@Value("${tencent.taskStream:TranscodePreset}")
private String taskStream;
/**
* 播放的音视频类型可选值
* RawAdaptive未加密的 转自适应码流 输出
* ProtectedAdaptive私有加密或 DRM 保护的 转自适应码流 输出
* Transcode转码 后输出
* Original上传 的原始音视频
*/
@Value("${tencent.audioVideoType}")
private String audioVideoType;
/**
* 允许输出的未加密的 转自适应码流模板 ID
*/
@Value("${tencent.rawAdaptiveDefinition}")
private Integer rawAdaptiveDefinition;
/**
* 模板ID
*/
@Value("${tencent.templateId}")
private Integer templateId;
/**
* 下载转码视频清晰度
*/
@Value("${tencent.downloadDefinition}")
private Long downloadDefinition;
@Bean
public VodClient vodClient() {
// 实例化一个认证对象入参需要传入腾讯云账户secretIdsecretKey,此处还需注意密钥对的保密
// 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取
Credential cred = new Credential(this.secretId, this.secretKey);
// 实例化一个http选项可选的没有特殊需求可以跳过
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint(this.vodEndpoint);
// 实例化一个client选项可选的没有特殊需求可以跳过
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
// 实例化要请求产品的client对象,clientProfile是可选的
return new VodClient(cred, this.region, clientProfile);
}
@Bean
public LiveClient liveClient() {
// 实例化一个认证对象入参需要传入腾讯云账户secretIdsecretKey,此处还需注意密钥对的保密
// 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取
Credential cred = new Credential(this.secretId, this.secretKey);
// 实例化一个http选项可选的没有特殊需求可以跳过
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint(this.liveEndpoint);
// 实例化一个client选项可选的没有特殊需求可以跳过
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
// 实例化要请求产品的client对象,clientProfile是可选的
return new LiveClient(cred, this.region, clientProfile);
}
public String getSecretId() {
return secretId;
}
public void setSecretId(String secretId) {
this.secretId = secretId;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public String getVodEndpoint() {
return vodEndpoint;
}
public void setVodEndpoint(String vodEndpoint) {
this.vodEndpoint = vodEndpoint;
}
public String getLiveEndpoint() {
return liveEndpoint;
}
public void setLiveEndpoint(String liveEndpoint) {
this.liveEndpoint = liveEndpoint;
}
public String getRegion() {
return region;
}
public void setRegion(String region) {
this.region = region;
}
public Integer getAppId() {
return appId;
}
public void setAppId(Integer appId) {
this.appId = appId;
}
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
public String getPushHost() {
return pushHost;
}
public void setPushHost(String pushHost) {
this.pushHost = pushHost;
}
public String getPushUrl() {
return pushUrl;
}
public void setPushUrl(String pushUrl) {
this.pushUrl = pushUrl;
}
public String getPushKey() {
return pushKey;
}
public void setPushKey(String pushKey) {
this.pushKey = pushKey;
}
public String getLiveHost() {
return liveHost;
}
public void setLiveHost(String liveHost) {
this.liveHost = liveHost;
}
public String getLiveUrl() {
return liveUrl;
}
public void setLiveUrl(String liveUrl) {
this.liveUrl = liveUrl;
}
public String getLiveKey() {
return liveKey;
}
public void setLiveKey(String liveKey) {
this.liveKey = liveKey;
}
public String getLiveFormat() {
return liveFormat;
}
public void setLiveFormat(String liveFormat) {
this.liveFormat = liveFormat;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public Integer getExpireHours() {
return expireHours;
}
public void setExpireHours(Integer expireHours) {
this.expireHours = expireHours;
}
public String getPlayKey() {
return playKey;
}
public void setPlayKey(String playKey) {
this.playKey = playKey;
}
public String getTaskStream() {
return taskStream;
}
public void setTaskStream(String taskStream) {
this.taskStream = taskStream;
}
public String getAudioVideoType() {
return audioVideoType;
}
public void setAudioVideoType(String audioVideoType) {
this.audioVideoType = audioVideoType;
}
public Integer getRawAdaptiveDefinition() {
return rawAdaptiveDefinition;
}
public void setRawAdaptiveDefinition(Integer rawAdaptiveDefinition) {
this.rawAdaptiveDefinition = rawAdaptiveDefinition;
}
public Integer getTemplateId() {
return templateId;
}
public void setTemplateId(Integer templateId) {
this.templateId = templateId;
}
public Long getDownloadDefinition() {
return downloadDefinition;
}
public void setDownloadDefinition(Long downloadDefinition) {
this.downloadDefinition = downloadDefinition;
}
}

View File

@ -0,0 +1,32 @@
package com.upchina.common.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.Collections;
@Configuration
public class UpCorsConfiguration {
@Bean("upCorsFilter")
@ConditionalOnProperty(name = "cors.enable", havingValue = "true")
public CorsFilter corsFilter() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
//1,允许任何来源
corsConfiguration.setAllowedOriginPatterns(Collections.singletonList("*"));
//2,允许任何请求头
corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);
//3,允许任何方法
corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);
//4,允许凭证
corsConfiguration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(source);
}
}

View File

@ -0,0 +1,19 @@
package com.upchina.common.config;
import com.upchina.common.util.UpDes;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class UpDesConfig {
@Value("${des.key}")
private String desKey;
@Bean
public UpDes upDes() {
return new UpDes(desKey);
}
}

View File

@ -0,0 +1,137 @@
package com.upchina.common.config;
import com.upchina.common.handler.WebSocketErrorHandler;
import com.upchina.common.interceptor.WebSocketAuthChannelInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration;
import javax.annotation.Resource;
/**
* <p>
* websocket核心配置类
* </p>
*
* @author fangliangbao
* @since 2022-09-28
*/
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
private static final long heartbeatServer = 10000;
private static final long heartbeatClient = 10000;
@Resource
private WebSocketErrorHandler webSocketErrorHandler;
@Resource
private WebSocketAuthChannelInterceptor clientInChannelInterceptor;
/**
* 添加这个Endpoint这样在网页中就可以通过websocket连接上服务,
* 也就是我们配置websocket的服务地址,并且可以指定是否使用socketJs
*/
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
/*
* 1. /chat 路径注册为STOMP的端点
* 用户连接了这个端点后就可以进行websocket通讯支持socketJs
* 2. setAllowedOriginPatterns("*")表示可以跨域
* 3. withSockJS()表示支持socketJS访问
*/
// 允许sockJS请求地址:http://ip:port/chat允许跨域
registry.addEndpoint("/tgim/chat")
.setAllowedOriginPatterns("*")
.withSockJS();
/*
* 添加多个端点
* 它的实现类是WebMvcStompEndpointRegistry
* addEndpoint是添加到WebMvcStompWebSocketEndpointRegistration的集合中
* 所以可以添加多个端点
*/
// 允许原生的websocket请求地址:ws://ip:port/chat允许跨域
registry.addEndpoint("/tgim/chat")
.setAllowedOriginPatterns("*");
// 异常处理
registry.setErrorHandler(webSocketErrorHandler);
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
ThreadPoolTaskScheduler heartbeatScheduler = new ThreadPoolTaskScheduler();
heartbeatScheduler.setPoolSize(8);
heartbeatScheduler.setThreadNamePrefix("wss-heartbeat-thread-");
heartbeatScheduler.initialize();
// 启用SimpleBroker使得订阅到此前缀的客户端可以收到消息.
config.enableSimpleBroker("/sub", "/user", "/app", "/admin")
.setHeartbeatValue(new long[]{heartbeatServer, heartbeatClient})
.setTaskScheduler(heartbeatScheduler);
/*
* 1如果地址前缀是/app此消息会关联到
* == @MessageMapping(send命令会到这个注解)
* == @SubscribeMapping(subscribe命令会到这个注解)
* 2如果没有/app则不会映射到任何注解上去
*/
config.setApplicationDestinationPrefixes("/app", "/admin");
// 指定用户发送一对一的前缀 /user/
config.setUserDestinationPrefix("/user");
}
/**
* 配置发送与接收的消息参数可以指定消息字节大小缓存大小发送超时时间
*/
@Override
public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
/*
* 1. setMessageSizeLimit 设置消息缓存的字节数大小 字节
* 2. setSendBufferSizeLimit 设置websocket会话时缓存的大小 字节
* 3. setSendTimeLimit 设置消息发送会话超时时间毫秒
*/
registration.setMessageSizeLimit(2048)
.setSendBufferSizeLimit(2048)
.setSendTimeLimit(10000);
}
/**
* 配置客户端入站通道拦截器
* 设置输入消息通道的线程数默认线程为1可以自己自定义线程数最大线程数线程存活时间
*/
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
/*
* 配置消息线程池
* 1. corePoolSize 配置核心线程池当线程数小于此配置时不管线程中有无空闲的线程都会产生新线程处理任务
* 2. maxPoolSize 配置线程池最大数当线程池数等于此配置时不会产生新线程
* 3. keepAliveSeconds 线程池维护线程所允许的空闲时间单位秒
*/
registration.taskExecutor()
.corePoolSize(32)
.maxPoolSize(64)
.keepAliveSeconds(120);
registration.interceptors(clientInChannelInterceptor);
}
/**
* 设置输出消息通道的线程数默认线程为1可以自己自定义线程数最大线程数线程存活时间
*/
@Override
public void configureClientOutboundChannel(ChannelRegistration registration) {
registration.taskExecutor()
.corePoolSize(32)
.maxPoolSize(64)
.keepAliveSeconds(120);
}
}

View File

@ -0,0 +1,437 @@
package com.upchina.common.config.cache;
import java.io.Serializable;
public class CacheKey {
public static class OnlyKeyObj implements Serializable {
private static final long serialVersionUID = 1L;
@Override
public boolean equals(Object obj) {
return obj instanceof OnlyKeyObj;
}
}
// 缓存空对象,防止缓存穿透
public static final Object ONLY_KEY_OBJ = new OnlyKeyObj();
// 分布式锁
public static final String DISTRIBUTED_LOCK = "distributed_lock";
public static class LockKey {
// 从cache刷新观点互动数量到DB 分布式锁(字符串常量)
public static final String SAVE_VIEW_COUNT_TO_DB_LOCK = "save_view_count_to_db_lock";
// 清除多余定时器日志
public static final String CLEAR_HISTORY_SCHEDULE_LOG = "clearHistoryScheduleLog";
// 自动解除锁定用户
public static final String UN_LOCK_USER = "un_lock_user";
// 结束直播中/暂停中的直播 分布式锁(字符串常量)
public static final String STOP_LIVING_VIDEO_LOCK = "stop_living_video_lock";
// 刷新视频直播状态 分布式锁(字符串常量)
public static final String UPDATE_VIDEO_LIVE_STATUS_LOCK = "update_video_live_status_lock";
// 从cache刷新视频直播播放量到DB 分布式锁(字符串常量)
public static final String SAVE_VIDEO_COUNT_TO_DB_LOCK = "save_video_count_to_db_lock";
// 购物车分布式锁
public static final String VIDEO_LIVE_HISTORY_LOCK = "video_live_history_lock";
public static final String SAVE_VIDEO_USER_DATA_TO_DB_LOCK = "save_video_user_data_to_db_lock";
public static final String SAVE_VIDEO_CUSTOMER_DATA_TO_DB_LOCK = "save_video_customer_data_to_db_lock";
public static final String LIVE_NOTIFY_LOCK = "live_notify_lock";
public static final String REFRESH_TRANSCODE_STATUS = "refresh_transcode_status";
public static final String SAVE_SHORT_VIDEO_WATCH_SECONDS = "save_short_video_watch_seconds";
public static final String COLLECT_LAST_WEEK_LOCK = "collect_last_week_lock";
public static final String COLLECT_LIVING_VIDEO_LOCK = "collect_living_video_lock";
public static final String COLLECT_RECENT_END_VIDEO_LOCK = "collect_recent_end_video_lock";
public static final String SYNC_APP_ORDER = "sync_app_order";
public static final String LOAD_USER_BLACK_LIST = "load_user_black_list";
}
// 消息主题
public static class MessageTopicKey {
public static final String VIDEO_MSG = "video_msg";
public static final String VIDEO_NOTIFY = "video_notify";
public static final String ADMIN_USER = "admin_user";
public static final String VIDEO_REPORT = "video_report";
public static final String PC_ADVISOR = "pc_advisor";
public static final String PC_AUDIENCE = "pc_audience";
public static final String SESSION_VIDEO_MSG = "session_video_msg";
}
// 后台用户
public static final String USER = "user";
public static final class UserKey {
// userId -> userName
public static final String USER_MAP = "user_map";
// staffNo -> User
public static final String STAFF_MAP = "staff_map";
public static final String JWT_EXPIRE_MAP = "jwt_expire_map";
public static final String LOGOUT_JWT_MAP = "logout_jwt_map";
public static final String USER_DEPT_MAP = "user_dept_map";
public static final String USER_BLACK_LIST = "user_black_list";
public static final String USER_LOGIN_MAP = "user_login_map";
}
// 部门(营业部/分公司)
public static final String DEPT = "dept";
public static class DeptKey {
// deptId -> deptName
public static final String DEPT_MAP = "dept_map";
// advisorId -> dept
public static final String ADVISOR_DEPT_MAP = "advisor_dept_map";
// advisorId -> deptId
public static final String ADVISOR_DEPT_ID_MAP = "advisor_dept_id_map";
// advisorId -> dept
public static final String ADVISOR_RELATION_DEPT_MAP = "advisor_relation_dept_map";
// userId -> deptId
public static final String USER_DEPT_MAP = "user_dept_map";
}
// RBAC权限
public static final String RBAC = "rbac";
public static class RbacKey {
public static final String ROLE_PERMISSIONS_URL = "role_permissions_url|";
public static final String ALL_PERMISSIONS_URL = "all_permissions_url|";
}
// 管理后台图形验证码
public static final String CAPTCHA = "captcha";
// 标签
public static final String TAG = "tag";
public static class TagKey {
// tagId -> tagName
public static final String TAG_MAP = "tag_map";
}
// 投顾信息
public static final String ADVISOR_INFO = "advisor_info";
public static final class AdvisorInfoKey {
// advisorId -> AdvisorBasic
public static final String ADVISOR_MAP = "advisor_map";
// advisorId -> AdvisorBasicVO
public static final String ADVISOR_VO_MAP = "advisor_vo_map";
// userId -> AdvisorBasic
public static final String USER_ADVISOR_MAP = "user_advisor_map";
// SortedMap<AdvisorSortEntity, Integer> (followCount, advisorId) -> advisorId
public static final String APP_FOLLOW_COUNT_LIST = "app_follow_count_list";
// SortedMap<AdvisorSortEntity, Integer> (readCount, advisorId) -> advisorId
public static final String APP_READ_COUNT_LIST = "app_read_count_list";
// SortedMap<AdvisorSortEntity, Integer> (productCount, advisorId) -> advisorId
public static final String APP_PRODUCT_COUNT_LIST = "app_product_count_list";
// AdvisorInfoAppVO
public static final String APP_OBJ = "app_obj|";
// advisorId -> PN Counter<followCount>
public static final String APP_FOLLOW_COUNT = "app_follow_count|";
// userId -> List<AdvisorFollow>
public static final String USER_FOLLOW_ADVISOR = "user_follow_advisor|";
public static final String USER_ADVISOR_DEPT_MAP = "user_advisor_dept_map";
}
// 观点栏目
public static final String VIEW_COLUMN = "view_column";
public static final class ViewColumnKey {
// columnId -> columnName
public static final String VIEW_COLUMN_MAP = "column_map";
// List<ViewColumnAppVO>
public static final String APP_COLUMN_LIST = "app_column_list|";
}
// 观点
public static final String VIEW_INFO = "view_info";
public static class ViewInfoKey {
// SortedSet<ViewSortEntity, Integer> (publishTime, viewId)
public static final String APP_PUBLISH_TIME_LIST = "app_publish_time_list";
// SortedSet<ViewSortEntity, Integer> (readCount, viewId)
public static final String APP_READ_COUNT_LIST = "app_read_count_list";
// SortedSet<ViewSortEntity, Integer> (publishTime, viewId)
public static final String APP_KEYWORD_LIST = "app_keyword_all|";
// SortedSet<ViewSortEntity, Integer> (publishTime, viewId)
public static final String APP_COLUMN_LIST = "app_column_list|";
// SortedSet<ViewSortEntity, Integer> (publishTime, viewId)
public static final String APP_ADVISOR_LIST = "app_advisor_list|";
// SortedSet<ViewSortEntity, Integer> (publishTime, viewId)
public static final String APP_PACKAGE_LIST = "app_package_list|";
// ViewInfoAppVO
public static final String APP_OBJ = "app_obj|";
// ViewDetailAppVO
public static final String APP_DETAIL_OBJ = "app_detail_obj|";
// userId -> Set<ViewId>
public static final String USER_FAVOR_VIEW_IDS = "user_favor_view_ids|";
// viewId -> PN Counter<favorCount>
public static final String APP_FAVOR_COUNT = "app_favor_count|";
// viewId -> PN Counter<readCount>
public static final String APP_READ_COUNT = "app_read_count|";
// Set<ViewRead>
public static final String TEMP_READ_COUNT_SET = "temp_read_count_set";
}
// 观点包
public static final String VIEW_PACKAGE = "view_package";
public static class ViewPackageKey {
// id -> ViewPackageAppVO
public static final String APP_OBJ = "app_obj|";
// SortedSet<ViewSortEntity> (weight, subCount, packageId)
public static final String APP_LIST = "app_list";
// SortedSet<ViewSortEntity> (inPackageWeight, subCount, packageId)
public static final String APP_KEYWORD_LIST = "app_keyword_list|";
// SortedSet<ViewSortEntity, Integer> (publishTime, viewId)
public static final String APP_COLUMN_LIST = "app_column_list|";
// SortedSet<ViewSortEntity, Integer> (publishTime, viewId)
public static final String APP_ADVISOR_LIST = "app_advisor_list|";
public static final String APP_ADVISOR_ORDER_BY_SUBCOUNT_LIST = "app_advisor_order_by_subcount_list|";
}
//观点卡片
public static final String VIEW_CARD = "view_card";
public static class ViewCardKey {
//viewId --> List<ViewCard>
public static final String VIEW_CARD_LIST = "view_card_list|";
}
public static final String ADVERT = "advert";
public static class AdvertKey {
public static final String APP_ADVERT_LIST = "app_advert_list|";
}
public static final String RECOMMEND = "recommend";
public static class RecommendKey {
public static final String APP_RECOMMEND_LIST = "app_recommend_list|";
}
//定价策略
public static final String PRICING_STRATEGY = "pricing_strategy";
public static class PricingStrategyKey {
// id -> PricingFeesVO
public static final String PRICING_FEES = "pricing_fees|";
public static final String PRICING_STRATEGY_DETAIL = "pricing_strategy_detail|";
}
// 组合详情map
public static final String PORTFOLIO = "portfolio";
public static class PortfolioKey {
// id -> PortfolioVO
public static final String PORTFOLIO_OBJ = "portfolio_obj|";
// type -> List<PortfolioVO>
public static final String PORTFOLIO_SORT_MAP = "portfolio_sort_map|";
// id:startDate:endDate -> List<ProfitRateVO>
public static final String PORTFOLIO_HIS_MAP = "portfolio_his_map|";
// id:startDate:endDate -> List<orderId>
public static final String PORTFOLIO_HIS_TRADE_LIST = "portfolio_his_trade_list|";
// orderId -> PortfolioTradeVO
public static final String PORTFOLIO_TRADE_OBJ = "portfolio_trade_obj|";
}
// 视频直播信息
public static final String VIDEO_LIVE = "video_live";
// 视频直播自定义缓存过期时间put方法设置的过期时间不生效所以这样处理
public static final String VIDEO_LIVE_DELAY = "video_live_delay";
public static class VideoLiveKey {
// videoId -> VideoLive
public static final String VIDEO_INFO = "video_info|";
// videoId -> VideoLive 10s缓存
public static final String VIDEO_INFO_DELAY = "video_info_delay|";
// SortedSet<VideoSortEntity> (startTime auditTime)
public static final String APP_LIST = "app_list";
public static final String APP_VIDEO_CART = "app_video_cart|";
public static final String APP_VIDEO_TAG = "app_video_tag|";
public static final String VIDEO_INFO_TAG = "video_info_tag|";
public static final String ADVISOR_NO_PLAY_LIST = "advisor_no_play_list";
// 与直播相关产品的权限
public static final String VIDEO_OTHER_AUTH = "video_other_auth|";
public static final String VIDEO_LIVE_RECENT_PUSH_CART = "video_live_recent_push_cart|";
public static final String ONLINE_COUNT = "online_count|";
public static final String APP_ADVISOR_LIST = "app_advisor_list|";
public static final String APP_DEPT_LIST = "app_dept_list|";
public static final String APP_ADVISOR_KEY_SET = "app_advisor_key_set|";
public static final String APP_DEPT_KEY_SET = "app_dept_key_set|";
}
// 视频直播专栏
public static final String VIDEO_LIVE_COLUMN = "video_live_column";
public static class VideoLiveColumnKey {
// List<columnId>
public static final String COLUMN_IDS = "column_ids";
// columnId -> VideoLiveColumn
public static final String COLUMN_INFO = "column_info|";
// columnId -> Sort<Integer> (videoId)
public static final String VIDEO_IDS = "video_ids|";
public static final String LATEST_LIVING_VIDEO = "latest_living_video|";
public static final String HIS_GUEST = "his_guest|";
public static final String APP_FOLLOW_COUNT = "app_follow_count|";
public static final String APP_PLAN_LIST = "app_plan_list";
public static final String VIDEO_COLUMN = "video_column";
}
// 视频直播资源
public static final String VIDEO_LIVE_LIBRARY = "video_live_library";
public static class VideoLiveLibraryKey {
// libraryId -> VideoLiveLibrary
public static final String LIBRARY_INFO = "library_info|";
// videoId -> List<libraryId>
public static final String LIBRARY_IDS = "library_ids|";
}
public static class VideoRecordKey {
// 购物车点击数
public static final String CART_READ_COUNT = "cart_read_count|";
// 浏览数
// videoId -> PV Counter<Integer>
public static final String READ_COUNT = "read_count|";
// 用户点赞
// videoId -> UV Counter<Integer>
public static final String FAVOR_USER_COUNT = "favor_user_count|";
// videoId -> Set<Integer> (userId)
public static final String USER_FAVOR_IDS = "user_favor_ids|";
// 视频分享
// videoId -> PV Counter<Integer>
public static final String SHARE_COUNT = "share_count|";
// 视频评论
// videoId -> PV Counter<Integer>
public static final String MESS_COUNT = "mess_count|";
// 用户预约
// userId -> Set<Integer> (videoId)
public static final String USER_SUBSCRIBE_IDS = "user_subscribe_ids|";
// videoId -> Set<String> (userId)
public static final String VIDEO_SUBSCRIBE_IDS = "user_subscribe_ids|";
public static final String USER_BROWSE_IDS = "user_browse_ids|";
public static final String USER_FOLLOW_COLUMN = "user_follow_column|";
public static final String TEMP_FAVOR_LIST = "temp_favor_list";
// 投顾关注
// advisorId -> Set<String> (userId)
public static final String ADVISOR_FOLLOW_IDS = "advisor_follow_ids|";
}
// 视频互动消息
public static final String VIDEO_LIVE_MESSAGE = "video_live_message";
public static class VideoLiveMessageKey {
// messageId -> VideoLiveMessage
public static final String MESSAGE_INFO = "message_info|";
// videoId -> List<Integer>(messageId)
public static final String MESSAGE_IDS = "message_ids|";
public static final String MESSAGE_IDS_ADVISOR = "message_ids_advisor|";
// 互动人数
// videoId -> UV Counter<Integer>
public static final String USER_COUNT = "read_user_count|";
public static final String MESSAGE_TOP_20 = "message_top_20|";
public static final String MESSAGE_ADVISOR_TOP_20 = "message_advisor_top_20|";
public static final String MESSAGE_COUNT = "message_count|";
}
// 评论
public static final String COMMENT = "comment";
public static class CommentKey {
public static final String APP_COMMENT_SORT_LIST = "app_comment_sort_list|";
public static final String APP_COMMENT_OBJ = "app_comment_obj|";
}
// 评论禁言
public static final String COMMENT_BLACK = "comment_black";
public static class CommentBlackKey {
public static final String ALL_BLACK_USER = "all_black_user";
}
public static final String VIDEO_ACTIVITY = "video_activity";
public static class VideoActivityKey {
public static final String VIDEO_ACTIVITY_LIST = "video_activity_list";
public static final String VIDEO_ACTIVITY_OBJ = "video_activity_obj|";
}
public static final String VIDEO_LIVE_HIS_DATE = "video_live_his_date";
public static final String QUESTION = "question";
public static class QuestionKey {
public static final String QUESTION_DETAILS = "question_details|";
}
public static final class OnlineLineKey {
public static final String USER_VIDEO_TOTAL_ONLINE = "user_video_total_online|";
}
public static final String URL_MAP = "url_map";
public static final class URL_KEY {
public static final String URL_KEY = "url_key|";
public static final String URL_KEY_VIDEO_ID = "url_key_video_id|";
public static final String URL_KEY_SHORT_VIDEO_ID = "url_key_short_video_id|";
}
public static final String VIDEO_TX_ONLINE = "video_tx_online|";
public static final class TXKey {
public static final String VIDEO_ONLINE_TX = "video_online_tx|";
}
public static final String CUSTOMER_MAP = "customer_map";
public static final class CustomerKey {
public static final String CUSTOMER_DETAILS = "customer_details|";
public static final String VIDEO_CUSTOMER_SET = "video_customer_set";
public static final String VIDEO_CUSTOMER_SALE_SET = "video_customer_sale_set";
public static final String CUSTOMER_SALE = "customer_sale|";
}
public static final String SCREEN = "screen";
public static final class ScreenKey {
public static final String SCREEN_VIDEO_INFO = "screen_video_info|";
}
public static final String VIDEO_LIVE_USER_MAP = "video_live_user_map";
public static final class VideoLiveUserKey {
public static final String LIVE_USER_OBJ = "live_user_obj|";
}
public static final String COURSE = "course";
public static final class CourseKey {
public static final String COURSE_INFO = "course_info|";
public static final String COURSE_CONTENT = "course_content|";
public static final String SERIAL_INFO = "serial_info|";
public static final String SERIAL_CONTENT = "serial_content|";
public static final String PAGE = "page|";
public static final String SHORT_VIDEO = "short_video|";
public static final String SHORT_VIDEO_FAVOR_USER_IDS = "favor_user_ids|";
public static final String MAIN_TAB = "main_tab|";
public static final String MAIN_COURSE_LIST = "main_course_list|";
public static final String MAIN_SHORT_VIDEO_LIST = "main_short_video_list|";
public static final String PC_COURSE_LIST = "pc_course_list|";
public static final String SALE_USER_WORK_WEIXIN_QRCODE_IMAGE = "sale_user_work_weixin_qrcode_image|";
public static final String SHORT_VIDEO_WATCH_LIST = "short_video_watch_list";
public static final String COURSE_PACKAGE = "course_package|";
public static final String COURSE_PACKAGE_CONTENT = "course_package_content|";
}
// C端APP缓存
public static final String APP = "app";
public static final class AppKey {
public static final String APP_RELS_LIST = "app_rels_list|";
public static final String LIVE_LIST = "live_list|";
}
}

View File

@ -0,0 +1,150 @@
package com.upchina.common.config.cache;
import com.hazelcast.config.*;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.upchina.common.config.cache.CacheKey.*;
@Configuration
public class HazelcastConfiguration {
@Value("${hazelcast.members}")
private String members;
@Value("${hazelcast.serverPort}")
private Integer serverPort;
private static final String DEFAULT_MAP_NAME = "default";
private static final Map<String, LocalMapConfig> configMap = new HashMap<>();
public static class LocalMapConfig {
private final int maxSize;
private final int liveSeconds;
private final InMemoryFormat inMemoryFormat;
LocalMapConfig(int maxSize, int liveSeconds) {
this.maxSize = maxSize;
this.liveSeconds = liveSeconds;
this.inMemoryFormat = InMemoryFormat.BINARY;
}
LocalMapConfig(int maxSize, int liveSeconds, InMemoryFormat inMemoryFormat) {
this.maxSize = maxSize;
this.liveSeconds = liveSeconds;
this.inMemoryFormat = inMemoryFormat;
}
}
static {
// 设置近地缓存实时同步,不采用批量提交策略
System.setProperty("hazelcast.map.invalidation.batch.enabled", "false");
// PER_NODEmax-size指定单个集群成员中map条目的最大数量这是max-size的默认策略如果使用这个配置需要注意max-size的值必须大于分区的数量默认为271
// PER_PARTITIONmax-size指定每个分区存储的map条目最大数这个策略建议不要在小规模的集群中使用因为小规模的集群单个节点包含了大量的分区在执行回收策略时会去按照分区的划分组个检查回收条件导致效率低下
// USED_HEAP_SIZE指在每个Hazelcast实例中max-size指定map所占用的内存堆的以megabytes计算兆字节最大值需要注意这个策略不能工作在in-memory-format=OBJECT因为当数据被设置为OBJECT时无法确定所占用的内存大小
// USED_HEAP_PERCENTAGE每个Hazelcast实例中max-size指定map占用内存堆的百分比例如JVM被设置有1000MB而这个值设置为max-size=10当map条目数占用的堆数据超过100MB时Hazelcast开始执行数据释放工作需要注意的是当使用这个策略时不能将in-memory-format设置为OBJECT理由同上
// FREE_HEAP_SIZEmax-size指定了单个JVM的堆最小空闲空间单位为megabytes
// FREE_HEAP_PERCENTAGEmax-size指定单个JVM的最小空闲空间的百分比例如JVM分配了1000MB的空间这个值设置为10当空闲堆只有100MB时会引发map的数据清除放行为
// 当map条数超过10000会引发map的数据清除行为
configMap.put(DISTRIBUTED_LOCK, new LocalMapConfig(1000, 0));
configMap.put(DEPT, new LocalMapConfig(10000, 3600));
configMap.put(TAG, new LocalMapConfig(10000, 3600));
configMap.put(VIEW_COLUMN, new LocalMapConfig(10000, 3600));
configMap.put(ADVISOR_INFO, new LocalMapConfig(10000, 300));
configMap.put(VIEW_INFO, new LocalMapConfig(10000, 300));
configMap.put(VIEW_PACKAGE, new LocalMapConfig(10000, 300));
configMap.put(VIEW_CARD, new LocalMapConfig(10000, 300));
configMap.put(RECOMMEND, new LocalMapConfig(10000, 300));
configMap.put(PRICING_STRATEGY, new LocalMapConfig(500, 300));
configMap.put(USER, new LocalMapConfig(10000, 3600));
configMap.put(CAPTCHA, new LocalMapConfig(10000, 300));
configMap.put(PORTFOLIO, new LocalMapConfig(10000, 60));
configMap.put(RBAC, new LocalMapConfig(10000, 300));
configMap.put(URL_MAP, new LocalMapConfig(10000, 300, InMemoryFormat.OBJECT));
configMap.put(SCREEN, new LocalMapConfig(1000, 10, InMemoryFormat.OBJECT));
configMap.put(VIDEO_TX_ONLINE, new LocalMapConfig(1000, 20, InMemoryFormat.OBJECT));
configMap.put(VIDEO_LIVE_MESSAGE, new LocalMapConfig(10000, 86400));
configMap.put(VIDEO_LIVE, new LocalMapConfig(10000, 300));
configMap.put(VIDEO_LIVE_DELAY, new LocalMapConfig(10000, 10));
configMap.put(VIDEO_LIVE_COLUMN, new LocalMapConfig(10000, 300));
configMap.put(VIDEO_ACTIVITY, new LocalMapConfig(1000, 300));
configMap.put(VIDEO_LIVE_LIBRARY, new LocalMapConfig(1000, 300));
configMap.put(VIDEO_LIVE_USER_MAP, new LocalMapConfig(10000, 300));
configMap.put(CUSTOMER_MAP, new LocalMapConfig(10000, 3600));
configMap.put(QUESTION, new LocalMapConfig(1000, 30));
configMap.put(COURSE, new LocalMapConfig(10000, 300));
configMap.put(APP, new LocalMapConfig(1000, 10, InMemoryFormat.OBJECT));
}
@Bean
public Config hazelCastConfig() {
List<String> memberList = Arrays.asList(members.split(","));
Config config = new Config();
// hazelcast作为缓存服务端监听的端口
config.getNetworkConfig().setPort(serverPort);
// 如果目标缓存端口被占用禁止重试其他端口
config.getNetworkConfig().setPortAutoIncrement(false);
config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(false);
config.getNetworkConfig().getJoin().getTcpIpConfig().setEnabled(true).setMembers(memberList);
String clusterName = "hazelcast-cluster";
String instanceName = clusterName + "." + "localIP";
config.setInstanceName(instanceName);
config.setClusterName(clusterName);
for (Map.Entry<String, LocalMapConfig> entry : configMap.entrySet()) {
config.addMapConfig(new MapConfig()
.setName(entry.getKey())
.setEvictionConfig(new EvictionConfig()
.setEvictionPolicy(EvictionPolicy.LFU)
.setSize(entry.getValue().maxSize)
.setMaxSizePolicy(MaxSizePolicy.PER_NODE))
.setTimeToLiveSeconds(entry.getValue().liveSeconds)
// 近地缓存设置
.setNearCacheConfig(new NearCacheConfig()
.setInMemoryFormat(entry.getValue().inMemoryFormat)
.setCacheLocalEntries(true)
.setTimeToLiveSeconds(entry.getValue().liveSeconds / 2)
.setEvictionConfig(new EvictionConfig()
.setMaxSizePolicy(MaxSizePolicy.ENTRY_COUNT)
.setSize(entry.getValue().maxSize / 2))
// 预加载近地缓存,防止近地缓存穿透(暂时不启用)
// .setPreloaderConfig(new NearCachePreloaderConfig()
// .setEnabled(true))
)
);
}
// 默认map配置主要用于USER_VIDEO_TOTAL_ONLINE + videoId
config.addMapConfig(new MapConfig()
.setName(DEFAULT_MAP_NAME)
.setNearCacheConfig(new NearCacheConfig()
.setInMemoryFormat(InMemoryFormat.OBJECT)
.setCacheLocalEntries(true)
.setTimeToLiveSeconds(3600 * 10)
.setMaxIdleSeconds(3600 * 2)
.setEvictionConfig(new EvictionConfig()
.setMaxSizePolicy(MaxSizePolicy.ENTRY_COUNT)
.setSize(100000))
));
return config;
}
@Bean
public HazelcastInstance hazelcastInstance() {
return Hazelcast.newHazelcastInstance(this.hazelCastConfig());
}
}

View File

@ -0,0 +1,21 @@
package com.upchina.common.config.mybatis;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;
import java.util.List;
public class EasySqlInjector extends DefaultSqlInjector {
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
methodList.add(new InsertBatchSomeColumn());
methodList.add(new SaveBatchSomeColumn(i -> i.getFieldFill() == FieldFill.INSERT_UPDATE));
methodList.add(new Save());
return methodList;
}
}

View File

@ -0,0 +1,26 @@
package com.upchina.common.config.mybatis;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.upchina")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
@Bean
public EasySqlInjector easySqlInjector() {
return new EasySqlInjector();
}
}

View File

@ -0,0 +1,65 @@
package com.upchina.common.config.mybatis;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import java.util.stream.Collectors;
public class Save extends AbstractMethod {
public static String saveSql = "<script>\nINSERT INTO %s %s VALUES %s ON DUPLICATE KEY UPDATE %s\n</script>";
public static final String methodName = "save";
public Save() {
super(methodName);
}
public Save(String name) {
super(name);
}
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;
String columnScript = SqlScriptUtils.convertTrim(tableInfo.getAllInsertSqlColumnMaybeIf(null),
LEFT_BRACKET, RIGHT_BRACKET, null, COMMA);
String valuesScript = SqlScriptUtils.convertTrim(tableInfo.getAllInsertSqlPropertyMaybeIf(null),
LEFT_BRACKET, RIGHT_BRACKET, null, COMMA);
String updateScript = tableInfo.getFieldList().stream().map(TableFieldInfo::getColumn).map(column ->
String.format("<if test=\"%s != null\">%s = VALUES(%s),</if>", column, column, column)
).collect(Collectors.joining(NEWLINE));
updateScript = SqlScriptUtils.convertTrim(updateScript, EMPTY, EMPTY, null, COMMA);
String keyProperty = null;
String keyColumn = null;
// 表包含主键处理逻辑,如果不包含主键当普通字段处理
if (StrUtil.isNotBlank(tableInfo.getKeyProperty())) {
if (tableInfo.getIdType() == IdType.AUTO) {
/* 自增主键 */
keyGenerator = Jdbc3KeyGenerator.INSTANCE;
keyProperty = tableInfo.getKeyProperty();
keyColumn = tableInfo.getKeyColumn();
} else {
if (null != tableInfo.getKeySequence()) {
keyGenerator = TableInfoHelper.genKeyGenerator(methodName, tableInfo, builderAssistant);
keyProperty = tableInfo.getKeyProperty();
keyColumn = tableInfo.getKeyColumn();
}
}
}
String sql = String.format(saveSql, tableInfo.getTableName(), columnScript, valuesScript, updateScript);
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return this.addInsertMappedStatement(mapperClass, modelClass, methodName, sqlSource, keyGenerator, keyProperty, keyColumn);
}
}

View File

@ -0,0 +1,99 @@
package com.upchina.common.config.mybatis;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class SaveBatchSomeColumn extends AbstractMethod {
private static final String methodName = "saveBatchSomeColumn";
/**
* 字段筛选条件
*/
private Predicate<TableFieldInfo> predicate;
public Predicate<TableFieldInfo> getPredicate() {
return predicate;
}
public void setPredicate(Predicate<TableFieldInfo> predicate) {
this.predicate = predicate;
}
/**
* 默认方法名
*/
public SaveBatchSomeColumn() {
super(methodName);
}
/**
* 默认方法名
*
* @param predicate 字段筛选条件
*/
public SaveBatchSomeColumn(Predicate<TableFieldInfo> predicate) {
super(methodName);
this.predicate = predicate;
}
/**
* @param name 方法名
* @param predicate 字段筛选条件
* @since 3.5.0
*/
public SaveBatchSomeColumn(String name, Predicate<TableFieldInfo> predicate) {
super(name);
this.predicate = predicate;
}
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;
List<TableFieldInfo> fieldList = tableInfo.getFieldList();
String insertSqlColumn = tableInfo.getKeyInsertSqlColumn(true, false) +
this.filterTableFieldInfo(fieldList, predicate, TableFieldInfo::getInsertSqlColumn, EMPTY);
String columnScript = LEFT_BRACKET + (insertSqlColumn.isEmpty() ? "" : insertSqlColumn.substring(0, insertSqlColumn.length() - 1)) + RIGHT_BRACKET;
String insertSqlProperty = tableInfo.getKeyInsertSqlProperty(true, ENTITY_DOT, false) +
this.filterTableFieldInfo(fieldList, predicate, i -> i.getInsertSqlProperty(ENTITY_DOT), EMPTY);
insertSqlProperty = LEFT_BRACKET + (insertSqlProperty.isEmpty() ? "" : insertSqlProperty.substring(0, insertSqlProperty.length() - 1)) + RIGHT_BRACKET;
String valuesScript = SqlScriptUtils.convertForeach(insertSqlProperty, "list", null, ENTITY, COMMA);
String updateScript = fieldList.stream().filter(predicate == null ? x -> true : predicate).map(TableFieldInfo::getColumn).map(column ->
String.format("%s = VALUES(%s),", column, column)).collect(Collectors.joining(NEWLINE));
updateScript = SqlScriptUtils.convertTrim(updateScript, EMPTY, EMPTY, null, COMMA);
String keyProperty = null;
String keyColumn = null;
// 表包含主键处理逻辑,如果不包含主键当普通字段处理
if (tableInfo.havePK()) {
if (tableInfo.getIdType() == IdType.AUTO) {
/* 自增主键 */
keyGenerator = Jdbc3KeyGenerator.INSTANCE;
keyProperty = tableInfo.getKeyProperty();
keyColumn = tableInfo.getKeyColumn();
} else {
if (null != tableInfo.getKeySequence()) {
keyGenerator = TableInfoHelper.genKeyGenerator(methodName, tableInfo, builderAssistant);
keyProperty = tableInfo.getKeyProperty();
keyColumn = tableInfo.getKeyColumn();
}
}
}
String sql = String.format(Save.saveSql, tableInfo.getTableName(), columnScript, valuesScript, updateScript);
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return this.addInsertMappedStatement(mapperClass, modelClass, methodName, sqlSource, keyGenerator, keyProperty, keyColumn);
}
}

View File

@ -0,0 +1,13 @@
package com.upchina.common.constant;
/**
* 能调用的角色
* ADVISOR_ACTIVE已上架投顾
* ADMIN运营
* ALL投顾&运营
* LOGIN仅登录
* SUPER_ADMIN超级管理员
*/
public enum AccessRole {
ADVISOR_ACTIVE, ADMIN, ALL, LOGIN, SUPER_ADMIN
}

View File

@ -0,0 +1,25 @@
package com.upchina.common.constant;
public enum AddOrSub {
ADD(1, "添加"),
SUB(2, "移除"),
;
public final Integer value;
public final String name;
AddOrSub(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,38 @@
package com.upchina.common.constant;
import com.upchina.common.handler.BizException;
import com.upchina.common.result.ResponseStatus;
import java.util.Arrays;
import java.util.Optional;
public enum AdvertPosition {
HOME_PAGE(1, "首页"),
;
public final Integer value;
public final String name;
AdvertPosition(Integer value, String name) {
this.value = value;
this.name = name;
}
public static AdvertPosition fromValue(Integer value) {
Optional<AdvertPosition> optional = Arrays.stream(AdvertPosition.values()).filter(t -> t.value.equals(value)).findFirst();
if (!optional.isPresent()) {
throw new BizException(ResponseStatus.PARM_ERROR, "值:" + value + "不存在");
}
return optional.get();
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,38 @@
package com.upchina.common.constant;
public enum ClientType {
UNKOWN(0),
PC(1),
APP(2),
Web(3),
H5(4),
TEACH_APP(5),
ADVISOR_APP(6),
HW_FAST_APP(7),
Other(99);
private final int value;
private ClientType(int value) {
this.value = value;
}
public int value() {
return this.value;
}
@Override
public String toString() {
return this.name() + ":" + this.value;
}
public static ClientType convert(int value) {
for(ClientType v : values()) {
if(v.value() == value) {
return v;
}
}
return null;
}
}

View File

@ -0,0 +1,19 @@
package com.upchina.common.constant;
public enum CommentBlackStatus {
EFFECT(0, "生效中"),
REMOVED(1, "已解除"),
EXPIRED(2, "自然过期"),
;
public final Integer value;
public final String name;
CommentBlackStatus(Integer value, String name) {
this.value = value;
this.name = name;
}
}

View File

@ -0,0 +1,27 @@
package com.upchina.common.constant;
public enum CommentBlackType {
DAY(0, "次日解禁"),
MONTH(1, "一个月之后解禁"),
FOREVER(2, "永久禁言"),
;
public final Integer value;
public final String name;
CommentBlackType(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,28 @@
package com.upchina.common.constant;
public enum CommentUserType {
// 客户
CUSTOMER(1, "客户"),
ADVISOR(2, "一个月之后解禁"),
ASSISTANT(3, "助教"),
;
public final Integer value;
public final String name;
CommentUserType(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,25 @@
package com.upchina.common.constant;
public enum IsActive {
YES(1, "有效"),
NO(2, "无效"),
;
public final Integer value;
public final String name;
IsActive(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,25 @@
package com.upchina.common.constant;
public enum IsDisplay {
YES(1, "显示"),
NO(2, "隐藏"),
DELETE(3, "删除");
public final Integer value;
public final String name;
IsDisplay(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,25 @@
package com.upchina.common.constant;
public enum IsFollow {
YES(1, "已关注"),
NO(2, "未关注"),
;
public final Integer value;
public final String name;
IsFollow(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,25 @@
package com.upchina.common.constant;
public enum IsFree {
YES(1, "免费"),
NO(2, "收费"),
;
public final Integer value;
public final String name;
IsFree(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,25 @@
package com.upchina.common.constant;
public enum IsLike {
YES(1, "已点赞"),
NO(2, "未点赞"),
;
public final Integer value;
public final String name;
IsLike(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,28 @@
package com.upchina.common.constant;
import java.util.Arrays;
public enum IsOrNot {
IS(1, ""),
NOT(2, ""),
;
public final Integer value;
public final String name;
IsOrNot(Integer value, String name) {
this.value = value;
this.name = name;
}
public static String parse(Integer value) {
return Arrays.stream(IsOrNot.values())
.filter(e -> e.value.equals(value))
.findFirst()
.map(e -> e.name)
.orElse(null);
}
}

View File

@ -0,0 +1,24 @@
package com.upchina.common.constant;
public enum IsRecommend {
NO(0, "不推荐"),
;
public final Integer value;
public final String name;
IsRecommend(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,25 @@
package com.upchina.common.constant;
public enum IsSub {
YES(1, "已订阅"),
NO(2, "未订阅"),
;
public final Integer value;
public final String name;
IsSub(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,27 @@
package com.upchina.common.constant;
public enum ListColumnType {
VIEW_INFO(1, "观点"),
VIEW_PACKAGE(2, "观点包"),
COURSE_INFO(3, "课程"),
COURSE_PACKAGE(4, "课程包"),
;
public final Integer value;
public final String name;
ListColumnType(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,43 @@
package com.upchina.common.constant;
public enum Market {
SZ(0, "深市"),
SH(1, "沪市"),
;
public final Integer value;
public final String name;
Market(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
public static String getName(Integer value) {
for (Market market : Market.values()) {
if (market.value.equals(value)) {
return market.name;
}
}
return null;
}
public static Integer getValue(String name) {
for (Market market : Market.values()) {
if (market.name.equals(name)) {
return market.value;
}
}
return null;
}
}

View File

@ -0,0 +1,26 @@
package com.upchina.common.constant;
public enum OrderBy {
ASC(1, "升序"),
DESC(0, "降序"),
;
public final Integer value;
public final String name;
OrderBy(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,65 @@
package com.upchina.common.constant;
import com.upchina.common.handler.BizException;
import com.upchina.common.result.ResponseStatus;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public enum ProductType {
CUSTOM_PRODUCT(111, "自定义产品"),
ADVISOR_INFO(0, "投顾"), // 仅用于推荐位&Banner
VIEW_PACKAGE(1, "观点包"),
VIEW_SINGLE(2, "单篇观点"),
VIDEO_SINGLE(3, "视频"),
// COURSE(4, "课程"),
CIRCLE(5, "交易圈"),
LIVE(6, "图文直播"),
PORTFOLIO(7, "组合"),
TIPS(8, "股票池"),
PACKAGE_PRODUCT(9, "套餐产品"),
H5(10, "H5"), // 仅用于推荐位&Banner
VIDEO_COLUMN(11, "栏目"), //
THIRD_VALUE_PRODUCT(21, "三方产品-增值产品"),
THIRD_COURSE(22, "三方产品-课程"),
THIRD_ETF(23, "三方产品-ETF专区"),
THIRD_STOCK_TOOL(24, "三方产品-选股工具"),
SMALL_PLANE_FINANCE(25, "三方产品-小飞机理财"),
COURSE_PACKAGE(31, "课程包"),
COURSE_SINGLE(32, "课程"),
SERIAL(33, "合集"),
PAGE(34, "落地页"),
SHORT_VIDEO(35, "短视频"),
;
public final Integer value;
public final String name;
public static final List<Integer> THIRD_PRODUCTS = Arrays.asList(THIRD_VALUE_PRODUCT.value, THIRD_COURSE.value, THIRD_ETF.value, THIRD_STOCK_TOOL.value, SMALL_PLANE_FINANCE.value);
ProductType(Integer value, String name) {
this.value = value;
this.name = name;
}
public static ProductType fromValue(Integer value) {
Optional<ProductType> optional = Arrays.stream(ProductType.values()).filter(t -> t.value.equals(value)).findFirst();
if (!optional.isPresent()) {
throw new BizException(ResponseStatus.PARM_ERROR, "值:" + value + "不存在");
}
return optional.get();
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,18 @@
package com.upchina.common.constant;
public enum RecommendOption {
RECOMMEND(1, "添加推荐"),
UN_RECOMMEND(2, "取消推荐"),
;
public final Integer value;
public final String name;
RecommendOption(Integer value, String name) {
this.value = value;
this.name = name;
}
}

View File

@ -0,0 +1,41 @@
package com.upchina.common.constant;
import java.util.Arrays;
public enum RiskLevel {
LOW_RISK(1, "低风险"),
LOW_MIDDLE_RISK(2, "中低风险"),
MIDDLE_RISK(3, "中风险"),
MIDDLE_HIGH_RISK(4, "中高风险"),
HIGH_RISK(5, "高风险"),
;
public final Integer value;
public final String name;
RiskLevel(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
/**
* 获取风险等级描述
*
* @param riskLevel 风险等级code
* @return 风险等级描述
*/
public static String parseName(Integer riskLevel) {
return Arrays.stream(RiskLevel.values())
.filter(s -> s.value.equals(riskLevel)).findFirst()
.map(logicType -> logicType.name).orElse(null);
}
}

View File

@ -0,0 +1,25 @@
package com.upchina.common.constant;
public enum ScheduleLogResult {
RUNNING(1, "执行中"),
SUCCESS(2, "成功"),
FAILURE(3, "失败");
public final Integer value;
public final String name;
ScheduleLogResult(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,27 @@
package com.upchina.common.constant;
public enum SimUserType {
TG(0, "投顾"),
NORMAL(1, "普通用户"),
MAJOR(2, "自研用户"),
;
public final Integer value;
public final String name;
SimUserType(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,26 @@
package com.upchina.common.constant;
public enum ThirdPartyProductStatus {
INIT(1, "待上架"),
PASS(2, "已上架"),
SOLD_OUT(3, "下架");
public final Integer value;
public final String name;
ThirdPartyProductStatus(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,26 @@
package com.upchina.common.constant;
public enum UserStatus {
ACTIVE(1, "启用"),
INACTIVE(2, "禁用"),
;
public final Integer value;
public final String name;
UserStatus(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,35 @@
package com.upchina.common.constant;
public enum UserType {
ADVISOR(1, "投顾"),
NOT_ADVISOR(2, "非投顾"),
;
public final Integer value;
public final String name;
UserType(Integer value, String name) {
this.value = value;
this.name = name;
}
public static UserType format(Integer userType) {
UserType[] values = UserType.values();
for (UserType type : values) {
if (type.getValue().equals(userType)) {
return type;
}
}
return null;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,84 @@
package com.upchina.common.controller;
import com.upchina.common.annotation.Auth;
import com.upchina.common.constant.AccessRole;
import com.upchina.common.query.ListAdvertQuery;
import com.upchina.common.query.OnlyIdQuery;
import com.upchina.common.query.SaveAdvertQuery;
import com.upchina.common.query.UpdateAdvertQuery;
import com.upchina.common.result.CommonResult;
import com.upchina.common.result.Pager;
import com.upchina.common.service.AdvertService;
import com.upchina.common.vo.AdvertAppVO;
import com.upchina.common.vo.AdvertVO;
import com.upchina.common.vo.BackendUserVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* <p>
* 广告位 前端控制器
* </p>
*
* @author easonzhu
* @since 2022-08-30
*/
@Api(tags = "广告位")
@RestController
public class AdvertController {
@Resource
private AdvertService advertService;
@ApiOperation("后台查询广告位列表")
@PostMapping("/admin/common/advert/list")
@Auth(role = AccessRole.LOGIN)
public CommonResult<Pager<AdvertVO>> list(@Validated @RequestBody @ApiParam(required = true) ListAdvertQuery query) {
Pager<AdvertVO> list = advertService.list(query);
return CommonResult.success(list);
}
@ApiOperation("后台保存广告位")
@PostMapping("/admin/common/advert/save")
@Auth(role = AccessRole.ADMIN)
public CommonResult<Void> save(@Validated @RequestBody @ApiParam(required = true) SaveAdvertQuery query,
@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) {
advertService.save(query, backendUserVO);
return CommonResult.success();
}
@ApiOperation("后台修改广告位")
@PostMapping("/admin/common/advert/update")
@Auth(role = AccessRole.ADMIN)
public CommonResult<Void> update(@Validated @RequestBody @ApiParam(required = true) UpdateAdvertQuery query,
@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) {
advertService.update(query, backendUserVO);
return CommonResult.success();
}
@ApiOperation("后台删除广告位")
@PostMapping("/admin/common/advert/delete")
@Auth(role = AccessRole.ADMIN)
public CommonResult<Void> delete(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query,
@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) {
advertService.delete(query, backendUserVO);
return CommonResult.success();
}
@ApiOperation("APP查询广告位列表")
@GetMapping("/app/common/advert/list")
public CommonResult<List<AdvertAppVO>> listForApp(
@ApiParam(value = "位置 1:投顾首页 2:App首页 3:小程序首页", required = true)
@RequestParam("position") @Validated @NotNull Integer position) {
List<AdvertAppVO> list = advertService.listForApp(position);
return CommonResult.success(list);
}
}

View File

@ -0,0 +1,50 @@
package com.upchina.common.controller;
import com.upchina.common.query.AddCommentBlackQuery;
import com.upchina.common.query.CommentBlackQuery;
import com.upchina.common.result.CommonResult;
import com.upchina.common.result.Pager;
import com.upchina.common.service.CommentBlackService;
import com.upchina.common.vo.BackendUserVO;
import com.upchina.common.vo.CommentBlackVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
@Api(tags = "通用评论-禁言")
@RestController
@Validated
public class CommentBlackController {
@Resource
private CommentBlackService commentBlackService;
@ApiOperation("添加用户禁言")
@PostMapping("/admin/comment/addCommentBlack")
public CommonResult<Integer> addCommentBlack(@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO,
@Validated @RequestBody AddCommentBlackQuery addCommentBlackQuery) {
Integer id = commentBlackService.addCommentBlack(backendUserVO, addCommentBlackQuery);
return CommonResult.success(id);
}
@ApiOperation("解除用户禁言")
@GetMapping("/admin/comment/removeCommentBlack")
public CommonResult<Void> removeCommentBlack(@NotNull @ApiParam(value = "用户手机号") @RequestParam("phone") String phone) {
commentBlackService.removeCommentBlack(phone);
return CommonResult.success();
}
@ApiOperation("中台查询禁言列表")
@PostMapping("/admin/comment/queryCommentBlackList")
public CommonResult<Pager<CommentBlackVO>> queryCommentBlackList(@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO,
@Validated @RequestBody CommentBlackQuery commentBlackQuery) {
Pager<CommentBlackVO> pager = commentBlackService.queryCommentBlackList(backendUserVO, commentBlackQuery);
return CommonResult.success(pager);
}
}

View File

@ -0,0 +1,107 @@
package com.upchina.common.controller;
import cn.hutool.core.util.StrUtil;
import com.upchina.common.annotation.Auth;
import com.upchina.common.constant.AccessRole;
import com.upchina.common.handler.BizException;
import com.upchina.common.query.*;
import com.upchina.common.result.AppPager;
import com.upchina.common.result.CommonResult;
import com.upchina.common.result.Pager;
import com.upchina.common.result.ResponseStatus;
import com.upchina.common.service.CommentService;
import com.upchina.common.vo.BackendUserVO;
import com.upchina.common.vo.CommentAppVO;
import com.upchina.common.vo.CommentVO;
import com.upchina.common.vo.FrontUserVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
@Api(tags = "通用评论")
@RestController
@Validated
public class CommentController {
@Resource
private CommentService commentService;
@ApiOperation("用户保存评论")
@PostMapping("/app/comment/saveComment")
public CommonResult<Integer> saveComment(@Validated @RequestBody SaveCommentQuery query,
@RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) {
if (frontUserVO == null || StrUtil.isEmpty(frontUserVO.getUserId())) {
throw new BizException(ResponseStatus.SESSION_EXPIRY);
}
int id = commentService.saveComment(query, frontUserVO);
return CommonResult.success(id);
}
@ApiOperation("中台保存评论")
@PostMapping("/admin/comment/saveComment")
public CommonResult<CommentVO> saveComment(@Validated @RequestBody SaveCommentQuery query,
@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) {
query.setSource(9);
CommentVO vo = commentService.saveCommentAdmin(query, backendUserVO);
return CommonResult.success(vo);
}
@Auth(role = AccessRole.ALL)
@ApiOperation("中台查询评论")
@PostMapping("/admin/comment/queryCommentList")
public CommonResult<Pager<CommentVO>> queryCommentList(@Validated @RequestBody CommentQuery query,
@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) {
Pager<CommentVO> result = commentService.queryCommentList(query, backendUserVO);
return CommonResult.success(result);
}
@Auth(role = AccessRole.ALL)
@ApiOperation("公开评论")
@PostMapping("/admin/comment/setCommentOpen")
public CommonResult<Void> setCommentOpen(@Validated @RequestBody SetCommentOpenQuery query) {
commentService.setCommentOpen(query);
return CommonResult.success();
}
@Auth(role = AccessRole.ALL)
@ApiOperation("置顶评论")
@PostMapping("/admin/comment/setCommentTop")
public CommonResult<Void> setCommentTop(@Validated @RequestBody SetCommentTopQuery query) {
commentService.setCommentTop(query);
return CommonResult.success();
}
@Auth(role = AccessRole.ALL)
@ApiOperation("回复评论")
@PostMapping("/admin/comment/replyComment")
public CommonResult<CommentVO> replyComment(@Validated @RequestBody ReplyCommentQuery query,
@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) {
CommentVO vo = commentService.replyComment(query, backendUserVO);
return CommonResult.success(vo);
}
@Auth(role = AccessRole.ALL)
@ApiOperation("删除评论")
@GetMapping("/admin/comment/deleteComment")
public CommonResult<Void> deleteComment(@NotNull @ApiParam(value = "评论id") @RequestParam("id") Integer id) {
commentService.deleteComment(id);
return CommonResult.success();
}
@ApiOperation("用户查看评论列表")
@PostMapping("/app/comment/queryCommentForApp")
public CommonResult<AppPager<CommentAppVO>> queryCommentForApp(@Validated @RequestBody CommentAppQuery query,
@RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) {
if (frontUserVO == null || !StrUtil.isNotEmpty(frontUserVO.getUserId())) {
throw new BizException(ResponseStatus.SESSION_EXPIRY);
}
AppPager<CommentAppVO> result = commentService.queryCommentForApp(query, frontUserVO);
return CommonResult.success(result);
}
}

View File

@ -0,0 +1,54 @@
package com.upchina.common.controller;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.upchina.common.result.CommonResult;
import com.upchina.common.util.CodecUtil;
import com.upchina.common.vo.UploadVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.IOException;
@Api(tags = "文件接口")
@RestController
@RequestMapping("/admin/common/file")
public class FileController {
@Resource
private FastFileStorageClient storageClient;
@Value("${file.domain.prefix}")
String domainPrefix;
@Value("${file.domain.resizePrefix}")
String domainResizePrefix;
@ApiOperation("上传")
@PostMapping("/upload")
public CommonResult<UploadVO> upload(@Parameter(content = @Content(mediaType = MediaType.MULTIPART_FORM_DATA_VALUE))
@RequestPart("file") @Validated @ApiParam(required = true) MultipartFile file) throws IOException {
StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(), FilenameUtils.getExtension(file.getOriginalFilename()), null);
String path = storePath.getFullPath();
String fullPath = domainPrefix + path;
// 使用nginx
String resizePath = domainResizePrefix + path;
// md5用于文件排重
String md5 = CodecUtil.md5(file.getBytes());
return CommonResult.success(new UploadVO(fullPath, resizePath, md5));
}
}

View File

@ -0,0 +1,33 @@
package com.upchina.common.controller;
import com.upchina.common.result.CommonResult;
import com.upchina.common.service.GlobalConfigService;
import com.upchina.common.vo.WebSocketConfigVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
@Api(tags = "全局配置")
@RestController
public class GlobalConfigController {
@Resource
private GlobalConfigService globalConfigService;
@ApiOperation("查询WebSocket配置")
@GetMapping("/admin/common/getWebSocketConf")
public CommonResult<WebSocketConfigVO> getWebSocketConf(
@RequestParam("type") @Validated @NotNull @Min(1) @ApiParam(required = true, value = "产品类型3直播互动9交易圈") Integer type,
@RequestParam("id") @Validated @NotNull @Min(1) @ApiParam(required = true, value = "产品ID") Integer id) {
WebSocketConfigVO conf = globalConfigService.getWebSocketConf(type, id);
return CommonResult.success(conf);
}
}

View File

@ -0,0 +1,33 @@
package com.upchina.common.controller;
import com.upchina.common.query.OperationLogQuery;
import com.upchina.common.result.CommonResult;
import com.upchina.common.result.Pager;
import com.upchina.common.service.OperationLogService;
import com.upchina.common.vo.OperationLogVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@Api(tags = "业务操作日志")
@RestController
@RequestMapping("/admin/operation")
public class OperationLogController {
@Resource
private OperationLogService operationLogService;
@ApiOperation("查询操作日志")
@PostMapping("/queryOperationLogList")
public CommonResult<Pager<OperationLogVO>> queryOperationLogList(@Validated @RequestBody @ApiParam(required = true) OperationLogQuery query) {
return operationLogService.queryOperationLogList(query);
}
}

View File

@ -0,0 +1,83 @@
package com.upchina.common.controller;
import com.upchina.common.annotation.Auth;
import com.upchina.common.constant.AccessRole;
import com.upchina.common.query.ListRecommendQuery;
import com.upchina.common.query.OnlyIdQuery;
import com.upchina.common.query.SaveRecommendQuery;
import com.upchina.common.query.UpdateRecommendQuery;
import com.upchina.common.result.CommonResult;
import com.upchina.common.result.Pager;
import com.upchina.common.service.RecommendService;
import com.upchina.common.vo.BackendUserVO;
import com.upchina.common.vo.RecommendVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* <p>
* 推荐位 前端控制器
* </p>
*
* @author easonzhu
* @since 2022-08-30
*/
@Api(tags = "推荐位")
@RestController
public class RecommendController {
@Resource
private RecommendService recommendService;
@ApiOperation("后台查询推荐位列表")
@PostMapping("/admin/common/recommend/list")
@Auth(role = AccessRole.LOGIN)
public CommonResult<Pager<RecommendVO>> list(@Validated @RequestBody @ApiParam(required = true) ListRecommendQuery query) {
Pager<RecommendVO> list = recommendService.list(query);
return CommonResult.success(list);
}
@ApiOperation("后台保存推荐位")
@PostMapping("/admin/common/recommend/save")
@Auth(role = AccessRole.ADMIN)
public CommonResult<Void> save(@Validated @RequestBody @ApiParam(required = true) SaveRecommendQuery query,
@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) {
recommendService.save(query, backendUserVO);
return CommonResult.success();
}
@ApiOperation("后台修改推荐位")
@PostMapping("/admin/common/recommend/update")
@Auth(role = AccessRole.ADMIN)
public CommonResult<Void> update(@Validated @RequestBody @ApiParam(required = true) UpdateRecommendQuery query,
@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) {
recommendService.update(query, backendUserVO);
return CommonResult.success();
}
@ApiOperation("后台删除广告位")
@PostMapping("/admin/common/recommend/delete")
@Auth(role = AccessRole.ADMIN)
public CommonResult<Void> delete(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query,
@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) {
recommendService.delete(query, backendUserVO);
return CommonResult.success();
}
@ApiOperation("APP查询推荐位列表")
@GetMapping("/app/common/recommend/list")
public CommonResult<List<Object>> listForApp(
@ApiParam(value = "产品类型0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊 10H5 11栏目", required = true)
@RequestParam("productType") @Validated @NotNull Integer productType) {
List<Object> list = recommendService.listForApp(productType);
return CommonResult.success(list);
}
}

View File

@ -0,0 +1,55 @@
package com.upchina.common.controller;
import com.upchina.common.annotation.Auth;
import com.upchina.common.constant.AccessRole;
import com.upchina.common.handler.BizException;
import com.upchina.common.query.UpdateRiskLevelQuery;
import com.upchina.common.result.CommonResult;
import com.upchina.common.result.ResponseStatus;
import com.upchina.common.service.RiskLevelService;
import com.upchina.common.vo.BackendUserVO;
import com.upchina.common.vo.OnlyRiskLevelVO;
import com.upchina.common.vo.RiskLevelVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@Api(tags = "风险等级配置")
@RestController
@RequestMapping("/admin/common/riskLevel")
public class RiskLevelController {
@Resource
private RiskLevelService riskLevelService;
@ApiOperation("风险等级列表查询")
@GetMapping("/list")
@Auth(role = AccessRole.ALL)
public CommonResult<List<RiskLevelVO>> list() {
return CommonResult.success(riskLevelService.list());
}
@ApiOperation("更新风险等级")
@PostMapping("/update")
@Auth(role = AccessRole.ADMIN)
public CommonResult<Void> update(@Validated @RequestBody @ApiParam(required = true) UpdateRiskLevelQuery query, @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) {
if (backendUserVO == null) {
throw new BizException(ResponseStatus.SESSION_EXPIRY);
}
riskLevelService.update(query, backendUserVO);
return CommonResult.success();
}
@ApiOperation("产品类型获风险等级")
@GetMapping("/getRiskLevel")
@Auth(role = AccessRole.ALL)
public CommonResult<OnlyRiskLevelVO> getRiskLevel(@Validated @RequestParam("productType") @ApiParam(value = "产品类型1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊", required = true) Integer productType) {
return CommonResult.success(riskLevelService.getRisk(productType));
}
}

View File

@ -0,0 +1,39 @@
package com.upchina.common.controller;
import com.upchina.common.entity.ScheduleLog;
import com.upchina.common.query.ListScheduleLogQuery;
import com.upchina.common.result.CommonResult;
import com.upchina.common.service.ScheduleLogService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* <p>
* 前端控制器
* </p>
*
* @author easonzhu
* @since 2021-11-23
*/
@Api(tags = "定时任务查询")
@RestController
@RequestMapping("/app/common/schedule-log")
public class ScheduleLogController {
@Resource
private ScheduleLogService scheduleLogService;
@ApiOperation("")
@PostMapping("/list")
public CommonResult<List<ScheduleLog>> list(ListScheduleLogQuery query) {
List<ScheduleLog> list = scheduleLogService.list(query);
return CommonResult.success(list);
}
}

View File

@ -0,0 +1,52 @@
package com.upchina.common.controller;
import com.upchina.advisor.query.ListAdvisorAppQuery;
import com.upchina.common.query.SearchUnionQuery;
import com.upchina.common.result.CommonResult;
import com.upchina.common.service.SearchService;
import com.upchina.common.vo.FrontUserVO;
import com.upchina.common.vo.SearchResultVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
/**
* @author tianye
* @version 1.0.0
* @ClassName SearchController.java
* @Description 搜索控制器
* @createTime 2022年10月25日 13:39:00
*/
@Api(tags = "搜索")
@RestController
public class SearchController {
@Resource
private SearchService searchService;
@ApiOperation("综合搜索")
@PostMapping("/app/common/search/union")
public CommonResult<Map<String, List<SearchResultVO>>> searchUnion(@Validated @RequestBody @ApiParam(required = true) SearchUnionQuery query,
@RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) {
Map<String, List<SearchResultVO>> map = searchService.searchUnion(query, frontUserVO);
return CommonResult.success(map);
}
@ApiOperation("投顾搜索")
@PostMapping("/app/common/search/advisor")
public CommonResult<List<SearchResultVO>> searchAdvisor(@Validated @RequestBody @ApiParam(required = true) ListAdvisorAppQuery query,
@RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) {
List<SearchResultVO> map = searchService.searchAdvisor(query, frontUserVO);
return CommonResult.success(map);
}
}

View File

@ -0,0 +1,100 @@
package com.upchina.common.controller;
import com.google.common.base.Charsets;
import com.upchina.common.annotation.Auth;
import com.upchina.common.constant.AccessRole;
import com.upchina.common.query.KeywordPageQuery;
import com.upchina.common.query.OnlyIdQuery;
import com.upchina.common.query.SaveSensitiveQuery;
import com.upchina.common.result.CommonResult;
import com.upchina.common.result.Pager;
import com.upchina.common.service.SensitiveWordService;
import com.upchina.common.vo.BackendUserVO;
import com.upchina.common.vo.SensitiveWordVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>
* 前端控制器
* </p>
*
* @author easonzhu
* @since 2022-08-30
*/
@Api(tags = "敏感词")
@RestController
@RequestMapping("/admin/common/sensitiveWord")
public class SensitiveWordController {
@Resource
private SensitiveWordService sensitiveWordService;
@ApiOperation("敏感词列表")
@PostMapping("list")
@Auth(role = AccessRole.ALL)
public CommonResult<Pager<SensitiveWordVO>> list(@Validated @RequestBody @ApiParam KeywordPageQuery query) {
Pager<SensitiveWordVO> page = sensitiveWordService.list(query);
return CommonResult.success(page);
}
@ApiOperation("敏感词保存")
@PostMapping("save")
@Auth(role = AccessRole.ADMIN)
public CommonResult<Void> save(@Validated @RequestBody @ApiParam(required = true) SaveSensitiveQuery query,
@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) {
sensitiveWordService.save(query, backendUserVO);
return CommonResult.success();
}
@ApiOperation("删除敏感词")
@PostMapping("delete")
@Auth(role = AccessRole.ADMIN)
public CommonResult<Void> delete(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query,
@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) {
sensitiveWordService.delete(query, backendUserVO);
return CommonResult.success();
}
@ApiOperation("上传敏感词")
@PostMapping("upload")
@Auth(role = AccessRole.ADMIN)
public CommonResult<List> upload(@RequestParam("file") @Validated @ApiParam(required = true) MultipartFile file) throws IOException {
String[] list = sensitiveWordService.upload(file);
return CommonResult.success(Arrays.asList(list));
}
@ApiOperation("敏感词下载")
@GetMapping("download")
@Auth(role = AccessRole.ADMIN)
public ResponseEntity<org.springframework.core.io.Resource> download() {
KeywordPageQuery query = new KeywordPageQuery();
query.setCurrent(1);
query.setSize(Integer.MAX_VALUE);
Pager<SensitiveWordVO> page = sensitiveWordService.list(query);
String text = page.getList().stream().map(SensitiveWordVO::getWord).collect(Collectors.joining("\r\n"));
ByteArrayResource resource = new ByteArrayResource(text.getBytes(Charsets.UTF_8));
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=listForAdmin.txt");
return ResponseEntity.ok()
.headers(headers)
.contentLength(resource.getByteArray().length)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(resource);
}
}

Some files were not shown because too many files have changed in this diff Show More