feat(work): 添加关注和作品收藏功能

- 新增 TpFollow 和 TpWorks 表及相关实体类
- 实现关注和作品收藏的 CRUD 接口和业务逻辑
- 添加相关控制器和 Mapper 接口
- 更新 TpOrder 表,增加备用字段
This commit is contained in:
清晨
2025-07-26 18:07:15 +08:00
parent 9c1c9f7e35
commit 5a0aa3993f
58 changed files with 3569 additions and 76 deletions

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
*
* https://www.mall4j.com/
*
* 未经允许,不可做商业用途!
*
* 版权所有,侵权必究!
*/
package org.dromara.web.common;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* @author lanhai
*/
public class HttpContextUtils {
public static HttpServletRequest getHttpServletRequest() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
}
public static String getDomain(){
HttpServletRequest request = getHttpServletRequest();
StringBuffer url = request.getRequestURL();
return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();
}
public static String getOrigin(){
HttpServletRequest request = getHttpServletRequest();
return request.getHeader("Origin");
}
}

View File

@@ -0,0 +1,38 @@
package org.dromara.web.common;
/**
* @author 菠萝凤梨
* @date 2022/3/28 14:32
*/
public interface OauthCacheNames {
/**
* oauth 授权相关key
*/
String OAUTH_PREFIX = "mall4j_oauth:";
/**
* token 授权相关key
*/
String OAUTH_TOKEN_PREFIX = OAUTH_PREFIX + "token:";
/**
* 保存token 缓存使用key
*/
String ACCESS = OAUTH_TOKEN_PREFIX + "access:";
/**
* 刷新token 缓存使用key
*/
String REFRESH_TO_ACCESS = OAUTH_TOKEN_PREFIX + "refresh_to_access:";
/**
* 根据uid获取保存的token key缓存使用的key
*/
String UID_TO_ACCESS = OAUTH_TOKEN_PREFIX + "uid_to_access:";
/**
* 保存token的用户信息使用的key
*/
String USER_INFO = OAUTH_TOKEN_PREFIX + "user_info:";
}

View File

@@ -0,0 +1,128 @@
/*
* Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
*
* https://www.mall4j.com/
*
* 未经允许,不可做商业用途!
*
* 版权所有,侵权必究!
*/
package org.dromara.web.common;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.media.Schema;
import org.springdoc.core.annotations.ParameterObject;
import java.util.List;
/**
* @author lanhai
*/
@Schema
@ParameterObject
public class PageParam<T> extends Page<T> {
/**
* 每页显示条数,默认 10
*/
@Schema(description = "每页大小默认10")
private long size = 10;
/**
* 当前页
*/
@Schema(description = "当前页默认1")
private long current = 1;
/**
* 查询数据列表
*/
@Hidden
private List<T> records;
/**
* 总数
*/
@Hidden
private long total = 0;
/**
* 是否进行 count 查询
*/
@JsonIgnore
private boolean isSearchCount = true;
@JsonIgnore
private String countId;
@JsonIgnore
private Long maxLimit;
@JsonIgnore
private boolean optimizeCountSql;
@Override
public List<T> getRecords() {
return this.records;
}
@Override
public Page<T> setRecords(List<T> records) {
this.records = records;
return this;
}
@Override
public long getTotal() {
return this.total;
}
@Override
public Page<T> setTotal(long total) {
this.total = total;
return this;
}
@JsonIgnore
public boolean getSearchCount() {
if (total < 0) {
return false;
}
return isSearchCount;
}
@Override
public Page<T> setSearchCount(boolean isSearchCount) {
this.isSearchCount = isSearchCount;
return this;
}
@Override
public long getSize() {
return this.size;
}
@Override
public Page<T> setSize(long size) {
int maxSize = 100;
if (size > maxSize) {
this.size = maxSize;
} else {
this.size = size;
}
return this;
}
@Override
public long getCurrent() {
return this.current;
}
@Override
public Page<T> setCurrent(long current) {
this.current = current;
return this;
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
*
* https://www.mall4j.com/
*
* 未经允许,不可做商业用途!
*
* 版权所有,侵权必究!
*/
package org.dromara.web.common;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import org.dromara.common.core.exception.user.UserException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.nio.charset.StandardCharsets;
/**
* @author 菠萝凤梨
* @date 2022/1/19 16:02
*/
@Component
public class PasswordManager {
private static final Logger logger = LoggerFactory.getLogger(PasswordManager.class);
/**
* 用于aes签名的key16位
*/
@Value("${auth.password.signKey:-mall4j-password}")
public String passwordSignKey;
public String decryptPassword(String data) {
// 在使用oracle的JDK时JAR包必须签署特殊的证书才能使用。
// 解决方案 1.使用openJDK或者非oracle的JDK建议 2.添加证书
// hutool的aes报错可以打开下面那段代码
SecureUtil.disableBouncyCastle();
AES aes = new AES(passwordSignKey.getBytes(StandardCharsets.UTF_8));
String decryptStr;
String decryptPassword;
try {
decryptStr = aes.decryptStr(data);
decryptPassword = decryptStr.substring(13);
} catch (Exception e) {
logger.error("Exception:", e);
throw new UserException("AES解密错误", e);
}
return decryptPassword;
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
*
* https://www.mall4j.com/
*
* 未经允许,不可做商业用途!
*
* 版权所有,侵权必究!
*/
package org.dromara.web.common;
/**
* @author FrozenWatermelon
* @date 2020/7/9
*/
public enum ResponseEnum {
/**
* ok
*/
OK("00000", "ok"),
SHOW_FAIL("A00001", ""),
/**
* 用于直接显示提示用户的错误,内容由输入内容决定
*/
/**
* 用于直接显示提示系统的成功,内容由输入内容决定
*/
SHOW_SUCCESS("A00002", ""),
/**
* 未授权
*/
UNAUTHORIZED("A00004", "Unauthorized"),
/**
* 服务器出了点小差
*/
EXCEPTION("A00005", "服务器出了点小差"),
/**
* 方法参数没有校验,内容由输入内容决定
*/
METHOD_ARGUMENT_NOT_VALID("A00014", "方法参数没有校验");
private final String code;
private final String msg;
public String value() {
return code;
}
public String getMsg() {
return msg;
}
ResponseEnum(String code, String msg) {
this.code = code;
this.msg = msg;
}
@Override
public String toString() {
return "ResponseEnum{" + "code='" + code + '\'' + ", msg='" + msg + '\'' + "} " + super.toString();
}
}

View File

@@ -0,0 +1,49 @@
package org.dromara.web.common;
import lombok.experimental.UtilityClass;
/**
* @author LGH
*/
@UtilityClass
public class SecurityUtils {
private static final String USER_REQUEST = "/api/";
/**
* 获取用户
*/
public YamiUser getUser() {
if (!HttpContextUtils.getHttpServletRequest().getRequestURI().startsWith(USER_REQUEST)) {
// 用户相关的请求,应该以/p开头
throw new RuntimeException("登录过期或已失效");
}
String accessToken = HttpContextUtils.getHttpServletRequest().getHeader("accessToken");
TokenStore tokenStore = new TokenStore();
UserInfoInTokenBO userInfoInTokenBO = tokenStore.getUserInfoByAccessToken(accessToken,false);
YamiUser yamiUser = new YamiUser();
yamiUser.setUserId(userInfoInTokenBO.getUserId());
yamiUser.setBizUserId(userInfoInTokenBO.getBizUserId());
yamiUser.setEnabled(userInfoInTokenBO.getEnabled());
yamiUser.setShopId(userInfoInTokenBO.getShopId());
yamiUser.setStationId(userInfoInTokenBO.getOtherId());
return yamiUser;
}
/**
* 获取用户ID
*/
public Long getUserInfo() {
Long userId = null;
try {
userId = getUser().getUserId();
} catch (RuntimeException e) {
// 处理异常
System.out.println(e.getMessage());
}
return userId;
}
}

View File

@@ -0,0 +1,199 @@
package org.dromara.web.common;
import lombok.extern.slf4j.Slf4j;
import java.io.Serializable;
import java.util.Objects;
/**
* @author lanhai
*/
@Slf4j
public class ServerResponseEntity<T> implements Serializable {
/**
* 状态码
*/
private String code;
/**
* 信息
*/
private String msg;
/**
* 数据
*/
private T data;
/**
* 版本
*/
private String version;
/**
* 时间
*/
private Long timestamp;
/* private String sign;
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}*/
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public ServerResponseEntity setData(T data) {
this.data = data;
return this;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public Long getTimestamp() {
return timestamp;
}
public void setTimestamp(Long timestamp) {
this.timestamp = timestamp;
}
public boolean isSuccess() {
return Objects.equals(ResponseEnum.OK.value(), this.code);
}
public boolean isFail() {
return !Objects.equals(ResponseEnum.OK.value(), this.code);
}
public ServerResponseEntity() {
// 版本号
this.version = "1.0";
}
public static <T> ServerResponseEntity<T> success(T data) {
ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setData(data);
serverResponseEntity.setCode(ResponseEnum.OK.value());
serverResponseEntity.setTimestamp(System.currentTimeMillis());
serverResponseEntity.setMsg("success");
return serverResponseEntity;
}
public static <T> ServerResponseEntity<T> success() {
ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setCode(ResponseEnum.OK.value());
serverResponseEntity.setMsg(ResponseEnum.OK.getMsg());
serverResponseEntity.setMsg("success");
serverResponseEntity.setTimestamp(System.currentTimeMillis());
return serverResponseEntity;
}
public static <T> ServerResponseEntity<T> success(Integer code, T data) {
return success(String.valueOf(code), data);
}
public static <T> ServerResponseEntity<T> success(String code, T data) {
ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setCode(code);
serverResponseEntity.setData(data);
serverResponseEntity.setMsg("success");
serverResponseEntity.setTimestamp(System.currentTimeMillis());
return serverResponseEntity;
}
/**
* 前端显示失败消息
* @param msg 失败消息
* @return
*/
public static <T> ServerResponseEntity<T> showFailMsg(String msg) {
log.error(msg);
ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setMsg(msg);
serverResponseEntity.setCode(ResponseEnum.SHOW_FAIL.value());
serverResponseEntity.setTimestamp(System.currentTimeMillis());
return serverResponseEntity;
}
public static <T> ServerResponseEntity<T> fail(ResponseEnum responseEnum) {
log.error(responseEnum.toString());
ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setMsg(responseEnum.getMsg());
serverResponseEntity.setCode(responseEnum.value());
serverResponseEntity.setTimestamp(System.currentTimeMillis());
return serverResponseEntity;
}
public static <T> ServerResponseEntity<T> fail(ResponseEnum responseEnum, T data) {
log.error(responseEnum.toString());
ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setMsg(responseEnum.getMsg());
serverResponseEntity.setCode(responseEnum.value());
serverResponseEntity.setData(data);
serverResponseEntity.setTimestamp(System.currentTimeMillis());
return serverResponseEntity;
}
public static <T> ServerResponseEntity<T> fail(String code, String msg, T data) {
log.error(msg);
ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setMsg(msg);
serverResponseEntity.setCode(code);
serverResponseEntity.setData(data);
serverResponseEntity.setTimestamp(System.currentTimeMillis());
return serverResponseEntity;
}
public static <T> ServerResponseEntity<T> fail(String code, String msg) {
return fail(code, msg, null);
}
public static <T> ServerResponseEntity<T> fail(Integer code, T data) {
ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setCode(String.valueOf(code));
serverResponseEntity.setData(data);
serverResponseEntity.setTimestamp(System.currentTimeMillis());
return serverResponseEntity;
}
@Override
public String toString() {
return "ServerResponseEntity{" +
"code='" + code + '\'' +
", msg='" + msg + '\'' +
", data=" + data +
", version='" + version + '\'' +
", timestamp=" + timestamp +
// ", sign='" + sign + '\'' +
'}';
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
*
* https://www.mall4j.com/
*
* 未经允许,不可做商业用途!
*
* 版权所有,侵权必究!
*/
package org.dromara.web.common;
import lombok.Data;
/**
* token信息该信息存在redis中
*
* @author 菠萝凤梨
* @date 2022/3/25 17:33
*/
@Data
public class TokenInfoBO {
/**
* 保存在token信息里面的用户信息
*/
private UserInfoInTokenBO userInfoInToken;
private String accessToken;
private String refreshToken;
/**
* 在多少秒后过期
*/
private Integer expiresIn;
}

View File

@@ -0,0 +1,23 @@
package org.dromara.web.common;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* token信息该信息用户返回给前端前端请求携带accessToken进行用户校验
*
* @author FrozenWatermelon
* @date 2020/7/2
*/
@Data
public class TokenInfoVO {
@Schema(description = "accessToken" )
private String accessToken;
@Schema(description = "refreshToken" )
private String refreshToken;
@Schema(description = "在多少秒后过期" )
private Integer expiresIn;
}

View File

@@ -0,0 +1,171 @@
package org.dromara.web.common;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import org.dromara.common.core.exception.user.UserException;
import org.dromara.common.redis.utils.RedisUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* token管理 1. 登陆返回token 2. 刷新token 3. 清除用户过去token 4. 校验token
*
* @author FrozenWatermelon
* @date 2020/7/2
*/
@Component
public class TokenStore {
private static final Logger logger = LoggerFactory.getLogger(TokenStore.class);
// private final RedisTemplate<String, Object> redisTemplate;
/*public TokenStore(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}*/
/**
* 以Sa-Token技术生成token并返回token信息
* @param userInfoInToken
* @return
*/
public TokenInfoBO storeAccessSaToken(UserInfoInTokenBO userInfoInToken) {
//生成过期时间
int timeoutSecond = getExpiresIn(userInfoInToken.getSysType());
Duration accessTokenExpires = Duration.ofSeconds(timeoutSecond);
String uid = this.getUid(userInfoInToken.getSysType().toString(), userInfoInToken.getUserId());
StpUtil.login(uid, timeoutSecond);
String token = StpUtil.getTokenValue();
// 用户信息存入缓存 token生成
String keyName = OauthCacheNames.USER_INFO + token;
RedisUtils.deleteObject(keyName);
RedisUtils.setCacheObject(keyName, userInfoInToken, accessTokenExpires);
// 数据封装返回(token不用加密)
TokenInfoBO tokenInfoBO = new TokenInfoBO();
tokenInfoBO.setUserInfoInToken(userInfoInToken);
tokenInfoBO.setExpiresIn(timeoutSecond);
tokenInfoBO.setAccessToken(token);
tokenInfoBO.setRefreshToken(token);
return tokenInfoBO;
}
/**
* 计算过期时间(单位:秒)
* @param sysType
* @return
*/
private int getExpiresIn(int sysType) {
// 3600秒
int expiresIn = 3600;
// 普通用户token过期时间
if (Objects.equals(sysType, 0)) {
expiresIn = expiresIn * 24 * 30;
}
// 系统管理员的token过期时间
if (Objects.equals(sysType, 1)) {
expiresIn = expiresIn * 24 * 30;
}
return expiresIn;
}
/**
* 根据accessToken 获取用户信息
* @param accessToken accessToken
* @param needDecrypt 是否需要解密
* @return 用户信息
*/
public UserInfoInTokenBO getUserInfoByAccessToken(String accessToken, boolean needDecrypt) {
if (StrUtil.isBlank(accessToken)) {
throw new UserException("accessToken is blank");
}
String keyName = OauthCacheNames.USER_INFO + accessToken;
Object redisCache = RedisUtils.getCacheObject(keyName);
if (redisCache == null) {
throw new UserException("-2","登录过期,请重新登录");
}
return (UserInfoInTokenBO) redisCache;
}
/**
* 刷新token并返回新的token
* @param refreshToken
* @return
*/
public TokenInfoBO refreshToken(String refreshToken) {
if (StrUtil.isBlank(refreshToken)) {
throw new UserException("refreshToken is blank");
}
// 删除旧token
UserInfoInTokenBO userInfoInTokenBO = getUserInfoByAccessToken(refreshToken, false);
this.deleteCurrentToken(refreshToken);
// 保存一份新的token
return storeAccessSaToken(userInfoInTokenBO);
}
/**
* 删除指定用户的全部的token
*/
public void deleteAllToken(String sysType, Long userId) {
// 删除用户缓存
String uid = this.getUid(sysType, userId);
List<String> tokens = StpUtil.getTokenValueListByLoginId(uid);
if (!CollectionUtils.isEmpty(tokens)) {
List<String> keyNames = new ArrayList<>();
for (String token : tokens) {
keyNames.add(OauthCacheNames.USER_INFO + token);
}
RedisUtils.deleteObject(keyNames);
}
// 移除token
StpUtil.logout(userId);
}
/**
* 生成token并返回token展示信息
* @param userInfoInToken
* @return
*/
public TokenInfoVO storeAndGetVo(UserInfoInTokenBO userInfoInToken) {
if (!userInfoInToken.getEnabled()){
// 用户已禁用,请联系客服
throw new UserException("用户已禁用,请联系客服");
}
TokenInfoBO tokenInfoBO = storeAccessSaToken(userInfoInToken);
// 数据封装返回
TokenInfoVO tokenInfoVO = new TokenInfoVO();
tokenInfoVO.setAccessToken(tokenInfoBO.getAccessToken());
tokenInfoVO.setRefreshToken(tokenInfoBO.getRefreshToken());
tokenInfoVO.setExpiresIn(tokenInfoBO.getExpiresIn());
return tokenInfoVO;
}
/**
* 删除当前登录的token
* @param accessToken 令牌
*/
public void deleteCurrentToken(String accessToken) {
// 删除用户缓存
String keyName = OauthCacheNames.USER_INFO + accessToken;
RedisUtils.deleteObject(keyName);
// 移除token
StpUtil.logoutByTokenValue(accessToken);
}
/**
* 生成各系统唯一uid
* @param sysType 系统类型
* @param userId 用户id
* @return
*/
private String getUid(String sysType, Long userId) {
return sysType + ":" + userId;
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
*
* https://www.mall4j.com/
*
* 未经允许,不可做商业用途!
*
* 版权所有,侵权必究!
*/
package org.dromara.web.common;
import lombok.Data;
import java.util.Set;
/**
* 保存在token信息里面的用户信息
*
* @author 菠萝凤梨
* @date 2022/3/25 17:33
*/
@Data
public class UserInfoInTokenBO {
/**
* 用户在自己系统的用户id
*/
private Long userId;
/**
* 租户id (商家id)
*/
private Long shopId;
/**
* 昵称
*/
private String nickName;
/**
* 系统类型 0:普通用户 1系统管理员
*
*/
private Integer sysType;
/**
* 是否是管理员
*/
private Integer isAdmin;
/**
* 业务系统用户id
*/
private String bizUserId;
/**
* 权限列表
*/
private Set<String> perms;
/**
* 状态 1 正常 0 无效
*/
private Boolean enabled;
/**
* 其他Id
*/
private Long otherId;
}

View File

@@ -0,0 +1,45 @@
package org.dromara.web.common;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import org.dromara.common.core.validate.AddGroup;
/**
* @author lh
*/
@Data
@Schema(description = "用户登录信息")
public class UserRegisterParam {
@Schema(description = "密码")
private String passWord;
@Schema(description = "邮箱")
private String userMail;
@Schema(description = "昵称")
private String nickName;
@Schema(description = "用户名")
private String userName;
@Schema(description = "手机号")
@NotBlank(message = "手机号码不能为空", groups = { AddGroup.class})
private String mobile;
@Schema(description = "头像")
private String img;
@Schema(description = "校验登陆注册验证码成功的标识")
private String checkRegisterSmsFlag;
@Schema(description = "当账户未绑定时临时的uid")
private String tempUid;
@Schema(description = "用户id")
private Long userId;
@Schema(description = "微信openId")
private String openId;
}

View File

@@ -0,0 +1,35 @@
package org.dromara.web.common;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
/**
* @author Maosw
*/
public class WxXcxUtils {
static String appid = "wxf1d78a0b58fc890c";
static String secret = "e1a3e888471d48addf1a23e4c9ea7f84";
public static String getAccessToken(){
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appid+"&secret="+secret;
String result = HttpUtil.get(url);
JSONObject jsonObject = JSONObject.parseObject(result);
return jsonObject.get("access_token").toString();
}
public static JSONObject getUserPhoneNumber(String code){
String accessToken = getAccessToken();
String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token="+accessToken;
JSONObject json = new JSONObject();
json.put("code", code);
String result = HttpRequest.post(url).body(json.toString()).execute().body();
JSONObject jsonObject = JSONObject.parseObject(result);
return jsonObject;
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
*
* https://www.mall4j.com/
*
* 未经允许,不可做商业用途!
*
* 版权所有,侵权必究!
*/
package org.dromara.web.common;
import lombok.Data;
/**
* 用户详细信息
* @author LGH
*/
@Data
public class YamiUser {
/**
* 用户ID
*/
private Long userId;
private String bizUserId;
private Boolean enabled;
/**
* 自提点Id
*/
private Long stationId;
/**
* 店铺Id
*/
private Long shopId;
}

View File

@@ -26,10 +26,7 @@ import org.dromara.system.service.ISysPictureService;
import org.dromara.system.service.ISysUserService;
import org.dromara.web.utils.WxXcxUtils;
import org.dromara.work.domain.TpReceipt;
import org.dromara.work.domain.bo.OrderRankingBo;
import org.dromara.work.domain.bo.TpProdBo;
import org.dromara.work.domain.bo.TpReceiptBo;
import org.dromara.work.domain.bo.TpWechatBo;
import org.dromara.work.domain.bo.*;
import org.dromara.work.domain.vo.*;
import org.dromara.work.service.*;
import org.springframework.web.bind.annotation.*;
@@ -73,6 +70,10 @@ public class IndexController {
private final ITpProdService tpProdService;
private final ITpFollowService tpFollowService;
private final ITpWorksService tpWorksService;
/**
* 访问首页,提示语
*/
@@ -123,6 +124,106 @@ public class IndexController {
return R.ok(WxXcxUtils.generateSignature(url));
}
/**
* 分页获取我的关注列表
*/
@GetMapping("/follow")
public R<TableDataInfo<TpFollowVo>> list(TpFollowBo bo, PageQuery pageQuery) {
return R.ok(tpFollowService.queryPageList(bo, pageQuery));
}
/**
* 关注
*/
@PostMapping("/AddFollow")
public R<Boolean> insert(@RequestBody TpFollowBo bo) {
//判断是否已经关注
TpFollowVo tpFollow = tpFollowService.queryByTpFollow(bo);
if(tpFollow != null){
return R.fail("已关注");
}
return R.ok(tpFollowService.insertByBo(bo));
}
/**
* 取消关注
*/
@DeleteMapping("/delFollow")
public R<Boolean> delete(@RequestBody TpFollowBo bo) {
if(bo.getId() != null){
return R.ok(tpFollowService.deleteWithValidByIds(List.of(bo.getId()), false));
}
TpFollowVo tpFollow = tpFollowService.queryByTpFollow(bo);
return R.ok(tpFollowService.deleteWithValidByIds(List.of(tpFollow.getId()), false));
}
/**
* 查询我是否关注此用户
*/
@PostMapping("/isFollow")
public R<Boolean> isFollow(@RequestBody TpFollowBo bo) {
return R.ok(tpFollowService.queryByTpFollow(bo) != null);
}
/**
* 分页获取我的收藏作品列表
*/
@GetMapping("/tpWorks")
public R<TableDataInfo<TpWorksVo>> list(TpWorksBo bo, PageQuery pageQuery) {
return R.ok(tpWorksService.queryPageList(bo, pageQuery));
}
/**
* 收藏作品
*/
@PostMapping("/AddWorks")
public R<Boolean> insert(@RequestBody TpWorksBo bo) {
//查询我是否已经收藏了此作品
TpWorksVo tpWorks = tpWorksService.queryByTpWorks(bo);
if(tpWorks != null){
return R.fail("已收藏");
}
return R.ok(tpWorksService.insertByBo(bo));
}
/**
* 取消收藏
*/
@DeleteMapping("/delWorks")
public R<Boolean> delete(@RequestBody TpWorksBo bo) {
if(bo.getId() != null){
return R.ok(tpWorksService.deleteWithValidByIds(List.of(bo.getId()), false));
}
TpWorksVo tpWorks = tpWorksService.queryByTpWorks(bo);
return R.ok(tpWorksService.deleteWithValidByIds(List.of(tpWorks.getId()), false));
}
/**
* 查询我是否收藏此作品
*/
@PostMapping("/isWorks")
public R<Boolean> isWorks(@RequestBody TpWorksBo bo) {
return R.ok(tpWorksService.queryByTpWorks(bo) != null);
}
/**
* 分页获取表现师列表
*/
@GetMapping("/tpSysUser")
public R<TableDataInfo<SysUserVo>> list(SysUserBo bo, PageQuery pageQuery) {
bo.setIdentity(2);
return R.ok(sysUserService.selectPageList(bo, pageQuery));
}
/**
* 根据用户ID查询用户信息
*/
@GetMapping("/sysUser/{id}")
public R<SysUserVo> getSysUserInfo(@NotNull(message = "用户ID不能为空") @PathVariable Long id) {
return R.ok(sysUserService.selectUserById(id));
}
/**
* 银盛支付回调
* @param params

View File

@@ -0,0 +1,123 @@
package org.dromara.web.controller;
import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.work.domain.TzUser;
import org.dromara.work.domain.vo.TzUserVo;
import org.dromara.work.service.ITzUserService;
import org.dromara.web.common.*;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
/**
* @author Maosw
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/user/login")
@Tag(name = "登录接口")
public class LoginController {
private final ITzUserService tzUserService;
private final TokenStore tokenStore;
@PostMapping("/getUserPhoneNumber")
@Operation(summary = "微信接口获取手机号码" , description = "微信接口获取手机号码")
@Parameter(name = "code", description = "code", required = true)
public ServerResponseEntity<JSONObject> getUserPhoneNumber(@RequestParam(value = "code") String code) {
// String phone = WxXcxUtils.getUserPhoneNumber(code);
return ServerResponseEntity.success(WxXcxUtils.getUserPhoneNumber(code));
}
@PostMapping("/register")
@Operation(summary = "注册登录" , description = "用户绑定手机号注册登录")
public ServerResponseEntity<TokenInfoVO> register(@Valid @RequestBody UserRegisterParam userRegisterParam) {
if (StrUtil.isBlank(userRegisterParam.getNickName())) {
userRegisterParam.setNickName(userRegisterParam.getUserName());
}
TzUser tzUser = tzUserService.getOne(new LambdaQueryWrapper<TzUser>().eq(TzUser::getUserMobile, userRegisterParam.getMobile()));
if (ObjectUtil.isNotEmpty(tzUser)) {
//登录
UserInfoInTokenBO userInfoInTokenBO = new UserInfoInTokenBO();
userInfoInTokenBO.setUserId(tzUser.getUserId());
userInfoInTokenBO.setSysType(0);
userInfoInTokenBO.setEnabled(true);
return ServerResponseEntity.success(tokenStore.storeAndGetVo(userInfoInTokenBO));
}else {
//注册并登录
Date now = new Date();
TzUser user = new TzUser();
user.setModifyTime(now);
user.setUserRegtime(now);
user.setStatus(1);
user.setUserMobile(userRegisterParam.getMobile());
user.setNickName(userRegisterParam.getNickName());
user.setUserMail(userRegisterParam.getUserMail());
user.setPic(userRegisterParam.getImg());
user.setLoginPassword(BCrypt.hashpw(userRegisterParam.getPassWord()));
user.setOpenId(userRegisterParam.getOpenId());
tzUserService.save(user);
// 2. 登录
UserInfoInTokenBO userInfoInTokenBO = new UserInfoInTokenBO();
userInfoInTokenBO.setUserId(user.getUserId());
userInfoInTokenBO.setSysType(0);
userInfoInTokenBO.setEnabled(true);
return ServerResponseEntity.success(tokenStore.storeAndGetVo(userInfoInTokenBO));
}
}
@PutMapping("/updatePwd")
@Operation(summary = "修改密码" , description = "修改密码")
public ServerResponseEntity<Boolean> updatePwd(@Valid @RequestBody UserRegisterParam userPwdUpdateParam) {
Long userId = SecurityUtils.getUser().getUserId();
TzUserVo user = tzUserService.queryById(userId);
if (user == null) {
// 无法获取用户信息
throw new ServiceException("无法获取用户信息");
}
if (StrUtil.isBlank(userPwdUpdateParam.getPassWord())) {
// 新密码不能为空
throw new ServiceException("新密码不能为空");
}
String password = BCrypt.hashpw(userPwdUpdateParam.getPassWord());
if (StrUtil.equals(password, user.getLoginPassword())) {
// 新密码不能与原密码相同
throw new ServiceException("新密码不能与原密码相同");
}
user.setModifyTime(new Date());
user.setLoginPassword(password);
TzUser tzUser = MapstructUtils.convert(user, TzUser.class);
return ServerResponseEntity.success(tzUserService.updateById(tzUser));
}
/**
* 获取登录用户信息
*/
@GetMapping("/info")
@Operation(summary = "获取登录用户信息" , description = "获取登录用户信息")
public ServerResponseEntity<TzUserVo> info() {
Long userId = SecurityUtils.getUser().getUserId();
TzUserVo user = tzUserService.queryById(userId);
return ServerResponseEntity.success(user);
}
}

View File

@@ -15,8 +15,8 @@ import java.util.*;
*/
public class WxXcxUtils {
private static final String APPID = "wx35c33a8a60d06fa9";
private static final String SECRET = "0c96a172d7bbe2bd8aa7dcee4ccbfb46";
private static final String APPID = "wxf1d78a0b58fc890c";
private static final String SECRET = "e1a3e888471d48addf1a23e4c9ea7f84";
private static final String TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
private static final String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";

View File

@@ -47,41 +47,27 @@ spring:
driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://erp9.52o.site:13308/erp20241208?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: erp20241208
password: a2aLeLYbzfZY4MZH
# url: jdbc:mysql://erp9.52o.site:13308/sjzxerp-test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username: sjzxerp-test
# password: EYpxAtdHmzHrTNGL
# url: jdbc:mysql://123.60.57.176:3306/sjzxerp20250618?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username: sjzx0618
# password: 2b1%Hk3#1Uolol
url: jdbc:mysql://erp9.52o.site:13308/hmsj?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: hmsj
password: s4xjHffmwG58RADk
# 从库数据源
slave:
lazy: false
type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://124.223.56.113:13306/erp2024?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username: erp2024
# password: KYrWzcXSaNDAC4pw
url: jdbc:mysql://localhost:3306/new_xgt?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: root
password: root
# oracle:
# type: ${spring.datasource.type}
# driverClassName: oracle.jdbc.OracleDriver
# url: jdbc:oracle:thin:@//localhost:1521/XE
# username: ROOT
# password: root
# postgres:
# type: ${spring.datasource.type}
# driverClassName: org.postgresql.Driver
# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
# username: root
# password: root
# sqlserver:
# type: ${spring.datasource.type}
# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true
# username: SA
# password: root
# url: jdbc:mysql://123.60.57.176:3306/sjzxerp20250618?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username: sjzx0618
# password: 2b1%Hk3#1Uolol
url: jdbc:mysql://erp9.52o.site:13308/hmsj?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: hmsj
password: s4xjHffmwG58RADk
hikari:
# 最大连接池数量
maxPoolSize: 20
@@ -102,13 +88,13 @@ spring:
spring.data:
redis:
# 地址
host: localhost
host: sh-crs-2xoizlg8.sql.tencentcdb.com
# 端口默认为6379
port: 6379
port: 22002
# 数据库索引
database: 1
# redis 密码必须配置
password: Huitu123
password: Songhaihua999
# 连接超时时间
timeout: 10s
# 是否开启ssl

View File

@@ -50,41 +50,26 @@ spring:
driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://erp9.52o.site:13308/erp20241208?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: erp20241208
password: a2aLeLYbzfZY4MZH
# url: jdbc:mysql://erp9.52o.site:13308/sjzxerp-test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username: sjzxerp-test
# password: EYpxAtdHmzHrTNGL
# url: jdbc:mysql://123.60.57.176:3306/sjzxerp20250618?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username: sjzx0618
# password: 2b1%Hk3#1Uolol
url: jdbc:mysql://erp9.52o.site:13308/hmsj?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: hmsj
password: s4xjHffmwG58RADk
# 从库数据源
slave:
lazy: false
type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://124.223.56.113:13306/erp2024?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: erp2024
password: KYrWzcXSaNDAC4pw
# url: jdbc:mysql://localhost:3306/new_xgt?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username: root
# password: root
# oracle:
# type: ${spring.datasource.type}
# driverClassName: oracle.jdbc.OracleDriver
# url: jdbc:oracle:thin:@//localhost:1521/XE
# username: ROOT
# password: root
# postgres:
# type: ${spring.datasource.type}
# driverClassName: org.postgresql.Driver
# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
# username: root
# password: root
# sqlserver:
# type: ${spring.datasource.type}
# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true
# username: SA
# password: root
# url: jdbc:mysql://123.60.57.176:3306/sjzxerp20250618?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username: sjzx0618
# password: 2b1%Hk3#1Uolol
url: jdbc:mysql://erp9.52o.site:13308/hmsj?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: hmsj
password: s4xjHffmwG58RADk
hikari:
# 最大连接池数量
maxPoolSize: 20
@@ -105,13 +90,13 @@ spring:
spring.data:
redis:
# 地址
host: localhost
host: sh-crs-2xoizlg8.sql.tencentcdb.com
# 端口默认为6379
port: 6379
port: 22002
# 数据库索引
database: 0
database: 5
# redis 密码必须配置
password: Huitu123
password: Songhaihua999
# 连接超时时间
timeout: 10s
# 是否开启ssl

View File

@@ -129,6 +129,7 @@ security:
- /system/dict/data/**
- /work/panorama/listByOrderId
- /wx/jssdk
- /api/user/**
# 多租户配置
tenant: