更新sql和代码规范修改

This commit is contained in:
moxiangrong
2024-02-18 15:26:45 +08:00
parent 6f5e6e4662
commit c132b68745
1293 changed files with 43935 additions and 18456 deletions

View File

@ -46,12 +46,12 @@
<artifactId>yshop-framework</artifactId>
<description>
该包是技术组件,每个子包,代表一个组件。每个组件包括两部分:
1. core 包:是该组件的核心封装
2. config 包:是该组件基于 Spring 的配置
1. core 包:是该组件的核心封装
2. config 包:是该组件基于 Spring 的配置
技术组件,也分成两类:
1. 框架组件:和我们熟悉的 MyBatis、Redis 等等的拓展
2. 业务组件:和业务相关的组件的封装,例如说数据字典、操作日志等等。
1. 框架组件:和我们熟悉的 MyBatis、Redis 等等的拓展
2. 业务组件:和业务相关的组件的封装,例如说数据字典、操作日志等等。
如果是业务组件Maven 名字会包含 biz
</description>
<url>https://github.com/guchengwuyue/yshop-pro</url>

View File

@ -103,7 +103,7 @@
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<!-- <scope>provided</scope>-->
<!-- <scope>provided</scope>-->
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>

View File

@ -1,7 +1,6 @@
/**
* Copyright (C) 2018-2022
* All rights reserved, Designed By www.yixiang.co
*/
package co.yixiang.yshop.framework.common.constant;
@ -12,209 +11,209 @@ package co.yixiang.yshop.framework.common.constant;
*/
public interface ShopConstants {
/**
* 订单自动取消时间(分钟)
*/
long ORDER_OUTTIME_UNPAY = 30;
/**
* 订单自动收货时间(天)
*/
long ORDER_OUTTIME_UNCONFIRM = 7;
/**
* 订单自动取消时间(分钟)
*/
long ORDER_OUTTIME_UNPAY = 30;
/**
* 订单自动收货时间(天)
*/
long ORDER_OUTTIME_UNCONFIRM = 7;
/**
* 订单自动收货时间(天)
*/
long AFTER_SALES_ORDER_OUTTIME_UNCONFIRM = 7;
/**
* redis订单未付款key
*/
String REDIS_ORDER_OUTTIME_UNPAY_QUEUE = "order-unpay-cancel-queue";
/**
* redis订单收货key
*/
String REDIS_ORDER_OUTTIME_UNCONFIRM = "order-unconfirm-queue";
/**
* 订单自动收货时间(天)
*/
long AFTER_SALES_ORDER_OUTTIME_UNCONFIRM = 7;
/**
* redis订单未付款key
*/
String REDIS_ORDER_OUTTIME_UNPAY_QUEUE = "order-unpay-cancel-queue";
/**
* redis订单收货key
*/
String REDIS_ORDER_OUTTIME_UNCONFIRM = "order-unconfirm-queue";
/**
* redis订单收货key
*/
String REDIS_AFTERSALESORDER_UNCONFIRM = "order-aftersalesorder-unconfirm-queue";
/**
* redis订单收货key
*/
String REDIS_AFTERSALESORDER_UNCONFIRM = "order-aftersalesorder-unconfirm-queue";
/**
* redis拼团key
*/
String REDIS_PINK_CANCEL_KEY = "pink:cancel:";
/**
* redis拼团key
*/
String REDIS_PINK_CANCEL_KEY = "pink:cancel:";
/**
* 微信支付service
*/
String YSHOP_WEIXIN_PAY_SERVICE = "yshop_weixin_pay_service";
/**
* 微信支付service
*/
String YSHOP_WEIXIN_PAY_SERVICE = "yshop_weixin_pay_service";
/**
* 微信支付小程序service
*/
String YSHOP_WEIXIN_MINI_PAY_SERVICE = "yshop_weixin_mini_pay_service";
/**
* 微信支付小程序service
*/
String YSHOP_WEIXIN_MINI_PAY_SERVICE = "yshop_weixin_mini_pay_service";
/**
* 微信支付app service
*/
String YSHOP_WEIXIN_APP_PAY_SERVICE = "yshop_weixin_app_pay_service";
/**
* 微信支付app service
*/
String YSHOP_WEIXIN_APP_PAY_SERVICE = "yshop_weixin_app_pay_service";
/**
* 微信公众号service
*/
String YSHOP_WEIXIN_MP_SERVICE = "yshop_weixin_mp_service";
/**
* 微信小程序service
*/
String YSHOP_WEIXIN_MA_SERVICE = "yshop_weixin_ma_service";
/**
* 微信公众号service
*/
String YSHOP_WEIXIN_MP_SERVICE = "yshop_weixin_mp_service";
/**
* 微信小程序service
*/
String YSHOP_WEIXIN_MA_SERVICE = "yshop_weixin_ma_service";
/**
* 商城默认密码
*/
String YSHOP_DEFAULT_PWD = "123456";
/**
* 商城默认密码
*/
String YSHOP_DEFAULT_PWD = "123456";
/**
* 商城默认注册图片
*/
String YSHOP_DEFAULT_AVATAR = "https://image.dayouqiantu.cn/5e79f6cfd33b6.png";
/**
* 商城默认注册图片
*/
String YSHOP_DEFAULT_AVATAR = "https://image.dayouqiantu.cn/5e79f6cfd33b6.png";
/**
* 腾讯地图地址解析
*/
String QQ_MAP_URL = "https://apis.map.qq.com/ws/geocoder/v1/";
/**
* 腾讯地图地址解析
*/
String QQ_MAP_URL = "https://apis.map.qq.com/ws/geocoder/v1/";
/**
* redis首页键
*/
String YSHOP_REDIS_INDEX_KEY = "yshop:index_data";
/**
* redis首页键
*/
String YSHOP_REDIS_INDEX_KEY = "yshop:index_data";
/**
* 配置列表缓存
*/
String YSHOP_REDIS_CONFIG_DATAS = "yshop:config_datas";
/**
* 配置列表缓存
*/
String YSHOP_REDIS_CONFIG_DATAS = "yshop:config_datas";
/**
* 充值方案
*/
String YSHOP_RECHARGE_PRICE_WAYS = "yshop_recharge_price_ways";
/**
* 首页banner
*/
String YSHOP_HOME_BANNER = "yshop_home_banner";
/**
* 首页菜单
*/
String YSHOP_HOME_MENUS = "yshop_home_menus";
/**
* 首页滚动新闻
*/
String YSHOP_HOME_ROLL_NEWS = "yshop_home_roll_news";
/**
* 热门搜索
*/
String YSHOP_HOT_SEARCH = "yshop_hot_search";
/**
* 个人中心菜单
*/
String YSHOP_MY_MENUES = "yshop_my_menus";
/**
* 秒杀时间段
*/
String YSHOP_SECKILL_TIME = "yshop_seckill_time";
/**
* 签到天数
*/
String YSHOP_SIGN_DAY_NUM = "yshop_sign_day_num";
/**
* 充值方案
*/
String YSHOP_RECHARGE_PRICE_WAYS = "yshop_recharge_price_ways";
/**
* 首页banner
*/
String YSHOP_HOME_BANNER = "yshop_home_banner";
/**
* 首页菜单
*/
String YSHOP_HOME_MENUS = "yshop_home_menus";
/**
* 首页滚动新闻
*/
String YSHOP_HOME_ROLL_NEWS = "yshop_home_roll_news";
/**
* 热门搜索
*/
String YSHOP_HOT_SEARCH = "yshop_hot_search";
/**
* 个人中心菜单
*/
String YSHOP_MY_MENUES = "yshop_my_menus";
/**
* 秒杀时间段
*/
String YSHOP_SECKILL_TIME = "yshop_seckill_time";
/**
* 签到天数
*/
String YSHOP_SIGN_DAY_NUM = "yshop_sign_day_num";
/**
* 打印机配置
*/
String YSHOP_ORDER_PRINT_COUNT = "order_print_count";
/**
* 飞蛾用户信息
*/
String YSHOP_FEI_E_USER = "fei_e_user";
/**
* 飞蛾用户密钥
*/
String YSHOP_FEI_E_UKEY= "fei_e_ukey";
/**
* 打印机配置
*/
String YSHOP_ORDER_PRINT_COUNT = "order_print_count";
/**
* 飞蛾用户信息
*/
String YSHOP_FEI_E_USER = "fei_e_user";
/**
* 飞蛾用户密钥
*/
String YSHOP_FEI_E_UKEY = "fei_e_ukey";
/**
* 打印机配置
*/
String YSHOP_ORDER_PRINT_COUNT_DETAIL = "order_print_count_detail";
/**
* 打印机配置
*/
String YSHOP_ORDER_PRINT_COUNT_DETAIL = "order_print_count_detail";
/**
* 短信验证码长度
*/
int YSHOP_SMS_SIZE = 6;
/**
* 短信验证码长度
*/
int YSHOP_SMS_SIZE = 6;
/**
* 短信缓存时间
*/
long YSHOP_SMS_REDIS_TIME = 600L;
/**
* 短信缓存时间
*/
long YSHOP_SMS_REDIS_TIME = 600L;
//零标识
String YSHOP_ZERO = "0";
//零标识
String YSHOP_ZERO = "0";
//业务标识标识
String YSHOP_ONE = "1";
//业务标识标识
String YSHOP_ONE = "1";
//目前完成任务数量是3
int TASK_FINISH_COUNT = 3;
//目前完成任务数量是3
int TASK_FINISH_COUNT = 3;
int YSHOP_ONE_NUM = 1;
int YSHOP_ONE_NUM = 1;
String YSHOP_ORDER_CACHE_KEY = "yshop:order";
String YSHOP_ORDER_CACHE_KEY = "yshop:order";
String YSHOP_ORDER_SALE_STATUS_KEY = "yshop:order:sale:status";
String YSHOP_ORDER_SALE_STATUS_KEY = "yshop:order:sale:status";
long YSHOP_ORDER_CACHE_TIME = 3600L;
long YSHOP_ORDER_CACHE_TIME = 3600L;
String WECHAT_MENUS = "wechat_menus";
String WECHAT_MENUS = "wechat_menus";
String YSHOP_EXPRESS_SERVICE = "yshop_express_service";
String YSHOP_EXPRESS_SERVICE = "yshop_express_service";
String YSHOP_REDIS_SYS_CITY_KEY = "yshop:city_list";
String YSHOP_REDIS_SYS_CITY_KEY = "yshop:city_list";
String YSHOP_REDIS_CITY_KEY = "yshop:city";
String YSHOP_REDIS_CITY_KEY = "yshop:city";
String YSHOP_APP_LOGIN_USER = "app-online-token:";
String YSHOP_APP_LOGIN_USER = "app-online-token:";
String YSHOP_WECHAT_PUSH_REMARK = "yshop为您服务";
String YSHOP_WECHAT_PUSH_REMARK = "yshop为您服务";
String DEFAULT_UNI_H5_URL = "https://h5.yixiang.co";
String DEFAULT_UNI_H5_URL = "https://h5.yixiang.co";
String YSHOP_MINI_SESSION_KET = "yshop:session_key:";
String YSHOP_MINI_SESSION_KET = "yshop:session_key:";
/**公众号二维码*/
String WECHAT_FOLLOW_IMG="wechat_follow_img";
/**后台api地址*/
String ADMIN_API_URL="admin_api_url";
/**公众号二维码*/
String WECHAT_FOLLOW_IMG = "wechat_follow_img";
/**后台api地址*/
String ADMIN_API_URL = "admin_api_url";
//快递查询接口Logistic
String KDNIAO_LOGISTIC_QUERY="https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx";
//快递查询接口Logistic
String KDNIAO_LOGISTIC_QUERY = "https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx";
/**
* redis营销活动状态变更key
*/
String CAMPAIGN_CHANGE = "campaign-change-queue";
/**
* redis营销活动状态变更key
*/
String CAMPAIGN_CHANGE = "campaign-change-queue";
/**
* redis广告弹窗状态变更key
*/
String POPUP_CHANGE = "popup-change-queue";
/**
* redis广告弹窗状态变更key
*/
String POPUP_CHANGE = "popup-change-queue";
/**
* redis拼团状态变更key
*/
String TEAMWORK_CHANGE = "teamwork-change-queue";
/**
* redis拼团状态变更key
*/
String TEAMWORK_CHANGE = "teamwork-change-queue";
String DAY_FORMAT_STR = "yyyy-MM-dd";
String DAY_FORMAT_STR = "yyyy-MM-dd";
/**
* redis 订单收货后不可关闭售后 key
*/
String CLOSE_AFTER_SALE_KEY = "close-after-sale-key";
/**
* redis 订单收货后不可关闭售后 key
*/
String CLOSE_AFTER_SALE_KEY = "close-after-sale-key";
}

View File

@ -2,52 +2,52 @@ package co.yixiang.yshop.framework.common.constant;
public class SystemConfigConstants {
//地址配置
public final static String API="api";
public final static String API_URL="api_url";
public final static String SITE_URL="site_url";
public final static String UNI_SITE_URL="uni_site_url";
public final static String TENGXUN_MAP_KEY="tengxun_map_key";
public final static String FILE_STORE_MODE="file_store_mode";
public final static String API = "api";
public final static String API_URL = "api_url";
public final static String SITE_URL = "site_url";
public final static String UNI_SITE_URL = "uni_site_url";
public final static String TENGXUN_MAP_KEY = "tengxun_map_key";
public final static String FILE_STORE_MODE = "file_store_mode";
//业务相关配置
public final static String IMAGEARR="imageArr";
public final static String INTERGRAL_FULL="integral_full";
public final static String INTERGRAL_MAX="integral_max";
public final static String INTERGRAL_RATIO="integral_ratio";
public final static String ORDER_CANCEL_JOB_TIME="order_cancel_job_time";
public final static String STORE_BROKERAGE_OPEN="store_brokerage_open";
public final static String STORE_BROKERAGE_RATIO="store_brokerage_ratio";
public final static String STORE_BROKERAGE_STATU="store_brokerage_statu";
public final static String STORE_BROKERAGE_TWO="store_brokerage_two";
public final static String STORE_FREE_POSTAGE="store_free_postage";
public final static String STORE_POSTAGE="store_postage";
public final static String STORE_SEFL_MENTION="store_self_mention";
public final static String STORE_USER_MIN_RECHARGE="store_user_min_recharge";
public final static String USER_EXTRACT_MIN_PRICE="user_extract_min_price";
public final static String IMAGEARR = "imageArr";
public final static String INTERGRAL_FULL = "integral_full";
public final static String INTERGRAL_MAX = "integral_max";
public final static String INTERGRAL_RATIO = "integral_ratio";
public final static String ORDER_CANCEL_JOB_TIME = "order_cancel_job_time";
public final static String STORE_BROKERAGE_OPEN = "store_brokerage_open";
public final static String STORE_BROKERAGE_RATIO = "store_brokerage_ratio";
public final static String STORE_BROKERAGE_STATU = "store_brokerage_statu";
public final static String STORE_BROKERAGE_TWO = "store_brokerage_two";
public final static String STORE_FREE_POSTAGE = "store_free_postage";
public final static String STORE_POSTAGE = "store_postage";
public final static String STORE_SEFL_MENTION = "store_self_mention";
public final static String STORE_USER_MIN_RECHARGE = "store_user_min_recharge";
public final static String USER_EXTRACT_MIN_PRICE = "user_extract_min_price";
public final static String YSHOP_SHOW_RECHARGE = "yshop_show_recharge";
//微信相关配置
public final static String WECHAT_APPID="wechat_appid";
public final static String WECHAT_APPSECRET="wechat_appsecret";
public final static String WECHAT_AVATAR="wechat_avatar";
public final static String WECHAT_ENCODE="wechat_encode";
public final static String WECHAT_ENCODINGAESKEY="wechat_encodingaeskey";
public final static String WECHAT_ID="wechat_id";
public final static String WECHAT_NAME="wechat_name";
public final static String WECHAT_QRCODE="wechat_qrcode";
public final static String WECHAT_SHARE_IMG="wechat_share_img";
public final static String WECHAT_SHARE_SYNOPSIS="wechat_share_synopsis";
public final static String WECHAT_SHARE_TITLE="wechat_share_title";
public final static String WECHAT_SOURCEID="wechat_sourceid";
public final static String WECHAT_TOKEN="wechat_token";
public final static String WECHAT_MA_TOKEN="wechat_ma_token";
public final static String WECHAT_MA_ENCODINGAESKEY="wechat_ma_encodingaeskey";
public final static String WECHAT_TYPE="wechat_type";
public final static String WXAPP_APPID="wxapp_appId";
public final static String WXAPP_SECRET="wxapp_secret";
public final static String WXPAY_APPID="wxpay_appId";
public final static String WXPAY_KEYPATH="wxpay_keyPath";
public final static String WXPAY_MCHID="wxpay_mchId";
public final static String WXPAY_MCHKEY="wxpay_mchKey";
public final static String WX_NATIVE_APP_APPID="wx_native_app_appId";
public final static String WECHAT_APPID = "wechat_appid";
public final static String WECHAT_APPSECRET = "wechat_appsecret";
public final static String WECHAT_AVATAR = "wechat_avatar";
public final static String WECHAT_ENCODE = "wechat_encode";
public final static String WECHAT_ENCODINGAESKEY = "wechat_encodingaeskey";
public final static String WECHAT_ID = "wechat_id";
public final static String WECHAT_NAME = "wechat_name";
public final static String WECHAT_QRCODE = "wechat_qrcode";
public final static String WECHAT_SHARE_IMG = "wechat_share_img";
public final static String WECHAT_SHARE_SYNOPSIS = "wechat_share_synopsis";
public final static String WECHAT_SHARE_TITLE = "wechat_share_title";
public final static String WECHAT_SOURCEID = "wechat_sourceid";
public final static String WECHAT_TOKEN = "wechat_token";
public final static String WECHAT_MA_TOKEN = "wechat_ma_token";
public final static String WECHAT_MA_ENCODINGAESKEY = "wechat_ma_encodingaeskey";
public final static String WECHAT_TYPE = "wechat_type";
public final static String WXAPP_APPID = "wxapp_appId";
public final static String WXAPP_SECRET = "wxapp_secret";
public final static String WXPAY_APPID = "wxpay_appId";
public final static String WXPAY_KEYPATH = "wxpay_keyPath";
public final static String WXPAY_MCHID = "wxpay_mchId";
public final static String WXPAY_MCHKEY = "wxpay_mchKey";
public final static String WX_NATIVE_APP_APPID = "wx_native_app_appId";
public final static String EXP_APPID = "exp_appId";

View File

@ -13,7 +13,7 @@ import java.util.Arrays;
*/
@Getter
@AllArgsConstructor
public enum DeletedEnum {
public enum DeletedEnum {
NO(false, "默认"),
YES(true, "已逻辑删除");

View File

@ -8,14 +8,14 @@ import lombok.Getter;
**/
@Getter
public enum EnableEnum {
DISABLE(0,"禁用"),
ENABLE(1,"启用"),
DISABLE(0, "禁用"),
ENABLE(1, "启用"),
;
private final Integer value;
private final String desc;
EnableEnum(Integer value, String desc) {
EnableEnum(Integer value, String desc) {
this.value = value;
this.desc = desc;
}

View File

@ -1,7 +1,6 @@
/**
* Copyright (C) 2018-2022
* All rights reserved, Designed By www.yixiang.co
*/
package co.yixiang.yshop.framework.common.enums;
@ -18,66 +17,65 @@ import java.util.stream.Stream;
@AllArgsConstructor
public enum OrderInfoEnum {
STATUS_APPLY_REFUND(-1,"申请退款"),
STATUS_REFUND_SUCCESS(-2,"退款成功"),
STATUS_GROUP_FAILURE(-4,"成团失败"),
STATUS_DEFAULT(0,"默认"),
STATUS_WAIT_RECEIVED(1,"待收货"),
STATUS_RECEIVED(2,"已收货"),
STATUS_FINISHED(3,"已完成"),
STATUS_CANCEL(4,"取消"),
STATUS_WAIT_GROUP(5,"待成团"),
STATUS_APPLY_REFUND(-1, "申请退款"),
STATUS_REFUND_SUCCESS(-2, "退款成功"),
STATUS_GROUP_FAILURE(-4, "成团失败"),
STATUS_DEFAULT(0, "默认"),
STATUS_WAIT_RECEIVED(1, "待收货"),
STATUS_RECEIVED(2, "已收货"),
STATUS_FINISHED(3, "已完成"),
STATUS_CANCEL(4, "取消"),
STATUS_WAIT_GROUP(5, "待成团"),
PAY_STATUS_UNPAID(0,"未支付"),
PAY_STATUS_HAVE_PAID(1,"已支付"),
PAY_STATUS_UNPAID(0, "未支付"),
PAY_STATUS_HAVE_PAID(1, "已支付"),
REFUND_STATUS_NORMAL(0,"正常"),
REFUND_STATUS_BEING_REFUNDED(1,"退款中"),
REFUND_STATUS_HAVE_REFUNDED(2,"已退款"),
REFUND_STATUS_NORMAL(0, "正常"),
REFUND_STATUS_BEING_REFUNDED(1, "退款中"),
REFUND_STATUS_HAVE_REFUNDED(2, "已退款"),
BARGAIN_STATUS_ONGOING(1,"参与中"),
BARGAIN_STATUS_FAIL(2,"参与失败"),
BARGAIN_STATUS_SUCCESS(3,"参与成功"),
BARGAIN_STATUS_ONGOING(1, "参与中"),
BARGAIN_STATUS_FAIL(2, "参与失败"),
BARGAIN_STATUS_SUCCESS(3, "参与成功"),
PINK_STATUS_ONGOING(1,"进行中"),
PINK_STATUS_FINISHED(2,"已完成"),
PINK_STATUS_UNFINISHED(3,"未完成"),
PINK_STATUS_ONGOING(1, "进行中"),
PINK_STATUS_FINISHED(2, "已完成"),
PINK_STATUS_UNFINISHED(3, "未完成"),
PINK_REFUND_STATUS_NORMAL(0,"拼团正常"),
PINK_REFUND_STATUS_REFUNDED(1,"拼团已退款"),
PINK_REFUND_STATUS_NORMAL(0, "拼团正常"),
PINK_REFUND_STATUS_REFUNDED(1, "拼团已退款"),
CANCEL_STATUS_NORMAL(0,"正常"),
CANCEL_STATUS_CANCELED(1,"已取消"),
CANCEL_STATUS_NORMAL(0, "正常"),
CANCEL_STATUS_CANCELED(1, "已取消"),
CONFIRM_STATUS_NORMAL(0,"正常"),
CONFIRM_STATUS_CONFIRM(1,"确认"),
CONFIRM_STATUS_NORMAL(0, "正常"),
CONFIRM_STATUS_CONFIRM(1, "确认"),
PAY_CHANNEL_PUBLIC_ACCOUNT_H5(0,"公众号/H5支付渠道"),
PAY_CHANNEL_MINI_PROGRAM(1,"小程序支付渠道"),
PAY_CHANNEL_PUBLIC_ACCOUNT_H5(0, "公众号/H5支付渠道"),
PAY_CHANNEL_MINI_PROGRAM(1, "小程序支付渠道"),
NO(0,""),
YES(1,""),
NO(0, ""),
YES(1, ""),
SHIPPING_TYPE_DELIVERY(1,"快递"),
SHIPPING_TYPE_STORE_PICKUP(2,"门店自提"),
SHIPPING_TYPE_DELIVERY(1, "快递"),
SHIPPING_TYPE_STORE_PICKUP(2, "门店自提"),
UNABLE_AFTER_SALES(0,"不能售后"),
ABLE_AFTER_SALES(1,"能售后"),
UNABLE_AFTER_SALES(0, "不能售后"),
ABLE_AFTER_SALES(1, "能售后"),
CAMPAIGN_ORDER(2,"活动订单");
CAMPAIGN_ORDER(2, "活动订单");
private final Integer value;
private final String desc;
private final Integer value;
private final String desc;
public static OrderInfoEnum toType(int value) {
return Stream.of(OrderInfoEnum.values())
.filter(p -> p.value == value)
.findAny()
.orElse(null);
}
public static OrderInfoEnum toType(int value) {
return Stream.of(OrderInfoEnum.values())
.filter(p -> p.value == value)
.findAny()
.orElse(null);
}
}

View File

@ -11,57 +11,55 @@ import lombok.Getter;
@AllArgsConstructor
public enum ShopCommonEnum {
STORE_MODE_LOCAL(1,"本地存储"),
STORE_MODE_CLOUD(2,"云存储"),
STORE_MODE_LOCAL(1, "本地存储"),
STORE_MODE_CLOUD(2, "云存储"),
ENABLE(1,"开启"),
DISABLE(2,"关闭"),
ENABLE(1, "开启"),
DISABLE(2, "关闭"),
EXTRACT_MINUS_NOT_PASS(-1,"提现未通过"),
EXTRACT_UNDER_REVIEW(0,"提现审核中"),
EXTRACT_FINISHED(1,"提现已完成"),
EXTRACT_MINUS_NOT_PASS(-1, "提现未通过"),
EXTRACT_UNDER_REVIEW(0, "提现审核中"),
EXTRACT_FINISHED(1, "提现已完成"),
UNFINISHED(0,"未完成"),
FINISHED(1,"已完成"),
UNFINISHED(0, "未完成"),
FINISHED(1, "已完成"),
NOT_FOREVER(0,"不是永久"),
FOREVER(1,"永久"),
NOT_FOREVER(0, "不是永久"),
FOREVER(1, "永久"),
AGREE(1,"同意"),
REFUSED(2,"拒绝"),
AGREE(1, "同意"),
REFUSED(2, "拒绝"),
LIMIT(0,"限制"),
UN_LIMIT(1,"不限制"),
LIMIT(0, "限制"),
UN_LIMIT(1, "不限制"),
NO(0,""),
YES(1,""),
NO(0, ""),
YES(1, ""),
DEFAULT(0,"默认"),
NEW(1,"新品"),
DEFAULT(0, "默认"),
NEW(1, "新品"),
IS_SUB_0(0,"不单独分佣"),
IS_SUB_1(1,"单独分佣"),
IS_SUB_0(0, "不单独分佣"),
IS_SUB_1(1, "单独分佣"),
GRADE_ONE(0,"一级推荐人"),
GRADE_TWO(1,"二级推荐人"),
GRADE_ONE(0, "一级推荐人"),
GRADE_TWO(1, "二级推荐人"),
UN_REPLY(0,"未回复"),
REPLIED(1,"已回复"),
UN_REPLY(0, "未回复"),
REPLIED(1, "已回复"),
ADD_1(1,"增加"),
ADD_2(2,"减少"),
ADD_1(1, "增加"),
ADD_2(2, "减少"),
DELETE_0(0,"未删除"),
DELETE_1(1,"已删除"),
NO_SHOW(0,"不显示"),
SHOW(1,"显示"),
NON_DEFAULT(0,"不是默认"),
IS_DEFAULT(1,"默认");
DELETE_0(0, "未删除"),
DELETE_1(1, "已删除"),
NO_SHOW(0, "不显示"),
SHOW(1, "显示"),
NON_DEFAULT(0, "不是默认"),
IS_DEFAULT(1, "默认");
private final Integer value;

View File

@ -2,8 +2,8 @@ package co.yixiang.yshop.framework.common.enums;
/**
* Web 过滤器顺序的枚举类,保证过滤器按照符合我们的预期
*
* 考虑到每个 starter 都需要用到该工具类,所以放到 common 模块下的 enums 包下
* <p>
* 考虑到每个 starter 都需要用到该工具类,所以放到 common 模块下的 enums 包下
*
* @author yshop
*/
@ -17,7 +17,7 @@ public interface WebFilterOrderEnum {
// OrderedRequestContextFilter 默认为 -105用于国际化上下文等等
int TENANT_CONTEXT_FILTER = - 104; // 需要保证在 ApiAccessLogFilter 前面
int TENANT_CONTEXT_FILTER = -104; // 需要保证在 ApiAccessLogFilter 前面
int API_ACCESS_LOG_FILTER = -103; // 需要保证在 RequestBodyCacheFilter 后面

View File

@ -6,10 +6,10 @@ import lombok.Data;
/**
* 错误码对象
*
* <p>
* 全局错误码,占用 [0, 999], 参见 {@link GlobalErrorCodeConstants}
* 业务异常错误码,占用 [1 000 000 000, +∞),参见 {@link ServiceErrorCodeRange}
*
* <p>
* TODO 错误码设计成对象的原因,为未来的 i18 国际化做准备
*/
@Data

View File

@ -5,7 +5,7 @@ import co.yixiang.yshop.framework.common.exception.ErrorCode;
/**
* 全局错误码枚举
* 0-999 系统异常编码保留
*
* <p>
* 一般情况下,使用 HTTP 响应状态码 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
* 虽然说HTTP 响应状态码作为业务使用表达能力偏弱,但是使用在系统层面还是非常不错的
* 比较特殊的是,因为之前一直使用 0 作为成功,就不使用 200 啦。
@ -43,9 +43,9 @@ public interface GlobalErrorCodeConstants {
* @param code 错误码
* @return 是否
*/
static boolean isServerErrorCode(Integer code) {
return code != null
&& code >= INTERNAL_SERVER_ERROR.getCode() && code <= INTERNAL_SERVER_ERROR.getCode() + 99;
}
static boolean isServerErrorCode(Integer code) {
return code != null
&& code >= INTERNAL_SERVER_ERROR.getCode() && code <= INTERNAL_SERVER_ERROR.getCode() + 99;
}
}

View File

@ -2,28 +2,28 @@ package co.yixiang.yshop.framework.common.exception.enums;
/**
* 业务异常的错误码区间,解决:解决各模块错误码定义,避免重复,在此只声明不做实际使用
*
* <p>
* 一共 10 位,分成四段
*
* <p>
* 第一段1 位,类型
* 1 - 业务级别异常
* x - 预留
* 1 - 业务级别异常
* x - 预留
* 第二段3 位,系统类型
* 001 - 用户系统
* 002 - 商品系统
* 003 - 订单系统
* 004 - 支付系统
* 005 - 优惠劵系统
* ... - ...
* 001 - 用户系统
* 002 - 商品系统
* 003 - 订单系统
* 004 - 支付系统
* 005 - 优惠劵系统
* ... - ...
* 第三段3 位,模块
* 不限制规则。
* 一般建议,每个系统里面,可能有多个模块,可以再去做分段。以用户系统为例子:
* 001 - OAuth2 模块
* 002 - User 模块
* 003 - MobileCode 模块
* 不限制规则。
* 一般建议,每个系统里面,可能有多个模块,可以再去做分段。以用户系统为例子:
* 001 - OAuth2 模块
* 002 - User 模块
* 003 - MobileCode 模块
* 第四段3 位,错误码
* 不限制规则。
* 一般建议,每个模块自增。
* 不限制规则。
* 一般建议,每个模块自增。
*
* @author yshop
*/

View File

@ -11,12 +11,12 @@ import java.util.concurrent.ConcurrentMap;
/**
* {@link ServiceException} 工具类
*
* <p>
* 目的在于,格式化异常信息提示。
* 考虑到 String.format 在参数不正确时会报错,因此使用 {} 作为占位符,并使用 {@link #doFormat(int, String, Object...)} 方法来格式化
*
* <p>
* 因为 {@link #MESSAGES} 里面默认是没有异常信息提示的模板的,所以需要使用方自己初始化进去。目前想到的有几种方式:
*
* <p>
* 1. 异常提示信息写在枚举类中例如说cn.iocoder.oceans.user.api.constants.ErrorCodeEnum 类 + ServiceExceptionConfiguration
* 2. 异常提示信息,写在 .properties 等等配置文件
* 3. 异常提示信息,写在 Apollo 等等配置中心中,从而实现可动态刷新
@ -67,7 +67,7 @@ public class ServiceExceptionUtil {
/**
* 创建指定编号的 ServiceException 的异常
*
* @param code 编号
* @param code 编号
* @param params 消息提示的占位符对应的参数
* @return 异常
*/

View File

@ -1,6 +1,6 @@
/**
* 基础的通用类,和框架无关
*
* <p>
* 例如说CommonResult 为通用返回
*/
package co.yixiang.yshop.framework.common;

View File

@ -1,7 +1,6 @@
/**
* Copyright (C) 2018-2022
* All rights reserved, Designed By www.yixiang.co
*/
package co.yixiang.yshop.framework.common.params;
@ -13,14 +12,14 @@ import java.io.Serializable;
@Data
@Schema(description = "用户 APP - 查询参数对象")
public abstract class QueryParam implements Serializable{
public abstract class QueryParam implements Serializable {
private static final long serialVersionUID = -3263921252635611410L;
@Schema(description = "页码,默认为1", requiredMode = Schema.RequiredMode.REQUIRED)
private Integer page =1;
private Integer page = 1;
@Schema(description = "页大小,默认为10", requiredMode = Schema.RequiredMode.REQUIRED)
private Integer limit = 10;
private Integer limit = 10;
@Schema(description = "搜索字符串", requiredMode = Schema.RequiredMode.REQUIRED)
private String keyword;

View File

@ -38,11 +38,11 @@ public class CommonResult<T> implements Serializable {
/**
* 将传入的 result 对象,转换成另外一个泛型结果的对象
*
* <p>
* 因为 A 方法返回的 CommonResult 对象,不满足调用其的 B 方法的返回,所以需要进行转换。
*
* @param result 传入的 result 对象
* @param <T> 返回的泛型
* @param <T> 返回的泛型
* @return 新的 CommonResult 对象
*/
public static <T> CommonResult<T> error(CommonResult<?> result) {

View File

@ -8,14 +8,14 @@ import javax.validation.constraints.Max;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
@Schema(description="分页参数")
@Schema(description = "分页参数")
@Data
public class PageParam implements Serializable {
private static final Integer PAGE_NO = 1;
private static final Integer PAGE_SIZE = 10;
@Schema(description = "页码,从 1 开始", requiredMode = Schema.RequiredMode.REQUIRED,example = "1")
@Schema(description = "页码,从 1 开始", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "页码不能为空")
@Min(value = 1, message = "页码最小值为 1")
private Integer pageNo = PAGE_NO;

View File

@ -4,7 +4,7 @@ import java.io.Serializable;
/**
* 排序字段 DTO
*
* <p>
* 类名加了 ing 的原因是,避免和 ES SortField 重名。
*/
public class SortingField implements Serializable {

View File

@ -19,7 +19,7 @@ public class BigDecimalSerializer extends JsonSerializer<BigDecimal> {
@Override
public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializerProvider) throws IOException {
if (value != null && !"".equals(value)) {
DecimalFormat df2 =new DecimalFormat("0.00");
DecimalFormat df2 = new DecimalFormat("0.00");
gen.writeString(df2.format(value));
} else {
gen.writeString(value + "");

View File

@ -18,7 +18,7 @@ public class DoubleSerializer extends JsonSerializer<Double> {
@Override
public void serialize(Double value, JsonGenerator gen, SerializerProvider serializerProvider) throws IOException {
if (value != null && !"".equals(value)) {
DecimalFormat df2 =new DecimalFormat("0.00");
DecimalFormat df2 = new DecimalFormat("0.00");
gen.writeString(df2.format(value));
} else {
gen.writeString(value + "");

View File

@ -20,9 +20,9 @@ public class ArrayUtils {
/**
* 将 object 和 newElements 合并成一个数组
*
* @param object 对象
* @param object 对象
* @param newElements 数组
* @param <T> 泛型
* @param <T> 泛型
* @return 结果数组
*/
@SafeVarargs

View File

@ -23,7 +23,7 @@ public class MapUtils {
* 从哈希表表中,获得 keys 对应的所有 value 数组
*
* @param multimap 哈希表
* @param keys keys
* @param keys keys
* @return value 数组
*/
public static <K, V> List<V> getList(Multimap<K, V> multimap, Collection<K> keys) {
@ -42,8 +42,8 @@ public class MapUtils {
* 从哈希表查找到 key 对应的 value然后进一步处理
* 注意,如果查找到的 value 为 null 时,不进行处理
*
* @param map 哈希表
* @param key key
* @param map 哈希表
* @param key key
* @param consumer 进一步处理的逻辑
*/
public static <K, V> void findAndThen(Map<K, V> map, K key, Consumer<V> consumer) {

View File

@ -179,7 +179,7 @@ public class DateUtils {
* @param end
* @return 是否
*/
public static boolean isBelong(LocalDateTime start,LocalDateTime end) {
public static boolean isBelong(LocalDateTime start, LocalDateTime end) {
return isBefore(end) && isAfter(start);
}
@ -238,15 +238,14 @@ public class DateUtils {
/**
* 判断两个日期是否同一天
*
* @param date1 /
* @param date2 /
* @return /
*/
public static Boolean isSameDay(Date date1,Date date2){
return DateUtil.formatDate(date1).equals(DateUtil.formatDate(date2));
public static Boolean isSameDay(Date date1, Date date2) {
return DateUtil.formatDate(date1).equals(DateUtil.formatDate(date2));
}
}

View File

@ -53,7 +53,7 @@ public class LocalDateTimeUtils {
* 判断当前时间是否在该时间范围内
*
* @param startTime 开始时间
* @param endTime 结束时间
* @param endTime 结束时间
* @return 是否
*/
public static boolean isBetween(LocalDateTime startTime, LocalDateTime endTime) {

View File

@ -18,6 +18,7 @@ public class DistanceCalculatorUtil {
/**
* 计算两地之间距离
*
* @param lat1 第一个点的纬度
* @param lon1 第一个点的经度
* @param lat2 第二个点的纬度

View File

@ -135,13 +135,13 @@ public class HttpUtils {
return response.body().string();
}
public static String sendAppletNotice(String token,String bodyString) throws IOException {
public static String sendAppletNotice(String token, String bodyString) throws IOException {
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = RequestBody.create(mediaType, bodyString);
Request request = new Request.Builder()
.url("https://api.weixin.qq.com/wxa/sec/order/upload_shipping_info?access_token="+token)
.url("https://api.weixin.qq.com/wxa/sec/order/upload_shipping_info?access_token=" + token)
.method("POST", body)
.build();
Response response = client.newCall(request).execute();

View File

@ -16,7 +16,7 @@ public class IoUtils {
/**
* 从流中读取 UTF8 编码的内容
*
* @param in 输入流
* @param in 输入流
* @param isClose 是否关闭
* @return 内容
* @throws IORuntimeException IO 异常

View File

@ -75,7 +75,7 @@ public class JsonUtils {
* 使用 {@link #parseObject(String, Class)} 时,在@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 的场景下,
* 如果 text 没有 class 属性,则会报错。此时,使用这个方法,可以解决。
*
* @param text 字符串
* @param text 字符串
* @param clazz 类型
* @return 对象
*/

View File

@ -4,7 +4,7 @@ import org.apache.skywalking.apm.toolkit.trace.TraceContext;
/**
* 链路追踪工具类
*
* <p>
* 考虑到每个 starter 都需要用到该工具类,所以放到 common 模块下的 util 包下
*
* @author yshop

View File

@ -17,7 +17,7 @@ public class ObjectUtils {
/**
* 复制对象,并忽略 Id 编号
*
* @param object 被复制对象
* @param object 被复制对象
* @param consumer 消费者,可以二次编辑被复制对象
* @return 复制后的对象
*/

View File

@ -1,7 +1,7 @@
/**
* 对于工具类的选择,优先查找 Hutool 中有没对应的方法
* 如果没有,则自己封装对应的工具类,以 Utils 结尾,用于区分
*
* <p>
* ps如果担心 Hutool 存在坑的问题,可以阅读 Hutool 的实现源码,以确保可靠性。并且,可以补充相关的单元测试。
*/
package co.yixiang.yshop.framework.common.util;

View File

@ -27,7 +27,7 @@ public class ServletUtils {
* 返回 JSON 字符串
*
* @param response 响应
* @param object 对象,会序列化成 JSON 字符串
* @param object 对象,会序列化成 JSON 字符串
*/
@SuppressWarnings("deprecation") // 必须使用 APPLICATION_JSON_UTF8_VALUE否则会乱码
public static void writeJSON(HttpServletResponse response, Object object) {
@ -40,7 +40,7 @@ public class ServletUtils {
*
* @param response 响应
* @param filename 文件名
* @param content 附件内容
* @param content 附件内容
*/
public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException {
// 设置 header 和 contentType

View File

@ -7,7 +7,7 @@ import org.springframework.aop.support.AopUtils;
/**
* Spring AOP 工具类
*
* <p>
* 参考波克尔 http://www.bubuko.com/infodetail-3471885.html 实现
*/
public class SpringAopUtils {

View File

@ -33,7 +33,7 @@ public class SpringExpressionUtils {
/**
* 从切面中,单个解析 EL 表达式的结果
*
* @param joinPoint 切面点
* @param joinPoint 切面点
* @param expressionString EL 表达式数组
* @return 执行界面
*/
@ -45,7 +45,7 @@ public class SpringExpressionUtils {
/**
* 从切面中,批量解析 EL 表达式的结果
*
* @param joinPoint 切面点
* @param joinPoint 切面点
* @param expressionStrings EL 表达式数组
* @return 结果key 为表达式value 为对应值
*/

View File

@ -40,7 +40,7 @@ public class StrUtils {
return false;
}
public static List<Long> splitToLong(String value, CharSequence separator) {
public static List<Long> splitToLong(String value, CharSequence separator) {
long[] longs = StrUtil.splitToLong(value, separator);
return Arrays.stream(longs).boxed().collect(Collectors.toList());
}

View File

@ -62,7 +62,7 @@ public class DataPermissionContextHolder {
/**
* 清空上下文
*
* <p>
* 目前仅仅用于单测
*/
public static void clear() {

View File

@ -37,7 +37,7 @@ import java.util.concurrent.ConcurrentHashMap;
/**
* 数据权限拦截器,通过 {@link DataPermissionRule} 数据权限规则,重写 SQL 的方式来实现
* 主要的 SQL 重写方法,可见 {@link #builderExpression(Expression, List)} 方法
*
* <p>
* 整体的代码实现上,参考 {@link com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor} 实现。
* 所以每次 MyBatis Plus 升级时,需要 Review 下其具体的实现是否有变更!
*
@ -450,7 +450,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
* 处理条件
*
* @param currentExpression 当前 where 条件
* @param tables 多个表
* @param tables 多个表
*/
protected Expression builderExpression(Expression currentExpression, List<Table> tables) {
// 没有表需要处理直接返回
@ -580,7 +580,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
/**
* 指定数据权限规则,对指定 MappedStatement 无需重写(不生效)的缓存
*
* <p>
* value{@link MappedStatement#getId()} 编号
*/
@Getter
@ -590,7 +590,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
* 判断是否无需重写
* ps虽然有点中文式英语但是容易读懂即可
*
* @param ms MappedStatement
* @param ms MappedStatement
* @param rules 数据权限规则数组
* @return 是否无需重写
*/
@ -612,7 +612,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
/**
* 添加无需重写的 MappedStatement
*
* @param ms MappedStatement
* @param ms MappedStatement
* @param rules 数据权限规则数组
*/
public void addNoRewritable(MappedStatement ms, List<DataPermissionRule> rules) {

View File

@ -17,7 +17,7 @@ public interface DataPermissionRule {
/**
* 返回需要生效的表名数组
* 为什么需要该方法Data Permission 数组基于 SQL 重写,通过 Where 返回只有权限的数据
*
* <p>
* 如果需要基于实体名获得表名,可调用 {@link TableInfoHelper#getTableInfo(Class)} 获得
*
* @return 表名数组
@ -27,7 +27,7 @@ public interface DataPermissionRule {
/**
* 根据表名和别名,生成对应的 WHERE / OR 过滤条件
*
* @param tableName 表名
* @param tableName 表名
* @param tableAlias 别名,可能为空
* @return 过滤条件 Expression 表达式
*/

View File

@ -32,18 +32,18 @@ import java.util.Set;
/**
* 基于部门的 {@link DataPermissionRule} 数据权限规则实现
*
* <p>
* 注意,使用 DeptDataPermissionRule 时,需要保证表中有 dept_id 部门编号的字段,可自定义。
*
* <p>
* 实际业务场景下,会存在一个经典的问题?当用户修改部门时,冗余的 dept_id 是否需要修改?
* 1. 一般情况下dept_id 不进行修改则会导致用户看到之前的数据。【yshop-server 采用该方案】
* 2. 部分情况下,希望该用户还是能看到之前的数据,则有两种方式解决:【需要你改造该 DeptDataPermissionRule 的实现代码】
* 1编写洗数据的脚本将 dept_id 修改成新部门的编号;【建议】
* 最终过滤条件是 WHERE dept_id = ?
* 2洗数据的话可能涉及的数据量较大也可以采用 user_id 进行过滤的方式,此时需要获取到 dept_id 对应的所有 user_id 用户编号;
* 最终过滤条件是 WHERE user_id IN (?, ?, ? ...)
* 3想要保证原 dept_id 和 user_id 都可以看的到,此时使用 dept_id 和 user_id 一起过滤;
* 最终过滤条件是 WHERE dept_id = ? OR user_id IN (?, ?, ? ...)
* 1编写洗数据的脚本将 dept_id 修改成新部门的编号;【建议】
* 最终过滤条件是 WHERE dept_id = ?
* 2洗数据的话可能涉及的数据量较大也可以采用 user_id 进行过滤的方式,此时需要获取到 dept_id 对应的所有 user_id 用户编号;
* 最终过滤条件是 WHERE user_id IN (?, ?, ? ...)
* 3想要保证原 dept_id 和 user_id 都可以看的到,此时使用 dept_id 和 user_id 一起过滤;
* 最终过滤条件是 WHERE dept_id = ? OR user_id IN (?, ?, ? ...)
*
* @author yshop
*/
@ -66,7 +66,7 @@ public class DeptDataPermissionRule implements DataPermissionRule {
/**
* 基于部门的表字段配置
* 一般情况下,每个表的部门编号字段是 dept_id通过该配置自定义。
*
* <p>
* key表名
* value字段名
*/
@ -74,7 +74,7 @@ public class DeptDataPermissionRule implements DataPermissionRule {
/**
* 基于用户的表字段配置
* 一般情况下,每个表的部门编号字段是 dept_id通过该配置自定义。
*
* <p>
* key表名
* value字段名
*/
@ -122,12 +122,12 @@ public class DeptDataPermissionRule implements DataPermissionRule {
// 情况二,即不能查看部门,又不能查看自己,则说明 100% 无权限
if (CollUtil.isEmpty(deptDataPermission.getDeptIds())
&& Boolean.FALSE.equals(deptDataPermission.getSelf())) {
&& Boolean.FALSE.equals(deptDataPermission.getSelf())) {
return new EqualsTo(null, null); // WHERE null = null可以保证返回的数据为空
}
// 情况三,拼接 Dept 和 User 的条件,最后组合
Expression deptExpression = buildDeptExpression(tableName,tableAlias, deptDataPermission.getDeptIds());
Expression deptExpression = buildDeptExpression(tableName, tableAlias, deptDataPermission.getDeptIds());
Expression userExpression = buildUserExpression(tableName, tableAlias, deptDataPermission.getSelf(), loginUser.getId());
if (deptExpression == null && userExpression == null) {
// TODO yshop获得不到条件的时候暂时不抛出异常而是不返回数据
@ -183,7 +183,7 @@ public class DeptDataPermissionRule implements DataPermissionRule {
public void addDeptColumn(Class<? extends BaseDO> entityClass, String columnName) {
String tableName = TableInfoHelper.getTableInfo(entityClass).getTableName();
addDeptColumn(tableName, columnName);
addDeptColumn(tableName, columnName);
}
public void addDeptColumn(String tableName, String columnName) {

View File

@ -525,9 +525,9 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
// 没有 On 的 inner join
assertSql("SELECT * FROM entity,entity1 " +
"WHERE entity.id = entity1.id",
"SELECT * FROM entity, entity1 " +
"WHERE entity.id = entity1.id AND entity.tenant_id = 1 AND entity1.tenant_id = 1");
"WHERE entity.id = entity1.id",
"SELECT * FROM entity, entity1 " +
"WHERE entity.id = entity1.id AND entity.tenant_id = 1 AND entity1.tenant_id = 1");
}
}

View File

@ -103,16 +103,20 @@ class DataPermissionRuleFactoryImplTest extends BaseMockitoUnitTest {
}
@DataPermission(enable = false)
static class TestClass03 {}
static class TestClass03 {
}
@DataPermission(includeRules = DataPermissionRule01.class)
static class TestClass04 {}
static class TestClass04 {
}
@DataPermission(excludeRules = DataPermissionRule01.class)
static class TestClass05 {}
static class TestClass05 {
}
@DataPermission
static class TestClass06 {}
static class TestClass06 {
}
static class DataPermissionRule01 implements DataPermissionRule {

View File

@ -1,6 +1,6 @@
/**
* 字典数据模块,提供 {@link co.yixiang.yshop.framework.dict.core.util.DictFrameworkUtils} 工具类
*
* <p>
* 通过将字典缓存在内存中,保证性能
*/
package co.yixiang.yshop.framework.dict;

View File

@ -15,7 +15,8 @@
<description>
错误码 ErrorCode 的自动配置功能,提供如下功能:
1. 远程读取:项目启动时,从 system-server 服务,读取数据库中的 ErrorCode 错误码,实现错误码的提水可配置;
2. 自动更新:管理员在管理后台修数据库中的 ErrorCode 错误码时,项目自动从 system-server 服务加载最新的 ErrorCode 错误码;
2. 自动更新:管理员在管理后台修数据库中的 ErrorCode 错误码时,项目自动从 system-server 服务加载最新的 ErrorCode
错误码;
3. 自动写入:项目启动时,将项目本地的错误码写到 system-server 服务中,方便管理员在管理后台编辑;
</description>
<url>https://github.com/guchengwuyue/yshop-pro</url>

View File

@ -18,7 +18,8 @@ import org.springframework.scheduling.annotation.EnableScheduling;
* @author yshop
*/
@AutoConfiguration
@ConditionalOnProperty(prefix = "yshop.error-code", value = "enable", matchIfMissing = true) // 允许使用 yshop.error-code.enable=false 禁用访问日志
@ConditionalOnProperty(prefix = "yshop.error-code", value = "enable", matchIfMissing = true)
// 允许使用 yshop.error-code.enable=false 禁用访问日志
@EnableConfigurationProperties(ErrorCodeProperties.class)
@EnableScheduling // 开启调度任务的功能,因为 ErrorCodeRemoteLoader 通过定时刷新错误码
public class YshopErrorCodeConfiguration {

View File

@ -4,7 +4,7 @@ import co.yixiang.yshop.framework.common.exception.util.ServiceExceptionUtil;
/**
* 错误码加载器
*
* <p>
* 注意,错误码最终加载到 {@link ServiceExceptionUtil} 的 MESSAGES 变量中!
*
* @author dlyan
@ -15,7 +15,7 @@ public interface ErrorCodeLoader {
* 添加错误码
*
* @param code 错误码的编号
* @param msg 错误码的提示
* @param msg 错误码的提示
*/
default void putErrorCode(Integer code, String msg) {
ServiceExceptionUtil.put(code, msg);

View File

@ -15,7 +15,7 @@ import java.util.List;
/**
* ErrorCodeLoader 的实现类,从 infra 的数据库中,加载错误码。
*
* <p>
* 考虑到错误码会刷新,所以按照 {@link #REFRESH_ERROR_CODE_PERIOD} 频率,增量加载错误码。
*
* @author dlyan

View File

@ -1,6 +1,6 @@
/**
* 错误码 ErrorCode 的自动配置功能,提供如下功能:
*
* <p>
* 1. 远程读取:项目启动时,从 system-service 服务,读取数据库中的 ErrorCode 错误码,实现错误码的提水可配置;
* 2. 自动更新:管理员在管理后台修数据库中的 ErrorCode 错误码时,项目自动从 system-service 服务加载最新的 ErrorCode 错误码;
* 3. 自动写入:项目启动时,将项目本地的错误码写到 system-server 服务中,方便管理员在管理后台编辑;

View File

@ -14,9 +14,9 @@
<name>${project.artifactId}</name>
<description>IP 拓展,支持如下功能:
1. IP 功能:查询 IP 对应的城市信息
基于 https://gitee.com/lionsoul/ip2region 实现
基于 https://gitee.com/lionsoul/ip2region 实现
2. 城市功能:查询城市编码对应的城市信息
基于 https://github.com/modood/Administrative-divisions-of-China 实现
基于 https://github.com/modood/Administrative-divisions-of-China 实现
</description>
<url>https://github.com/guchengwuyue/yshop-pro</url>

View File

@ -9,7 +9,7 @@ import java.util.List;
/**
* 区域节点,包括国家、省份、城市、地区等信息
*
* <p>
* 数据可见 resources/area.csv 文件
*
* @author yshop
@ -38,7 +38,7 @@ public class Area {
private String name;
/**
* 类型
*
* <p>
* 枚举 {@link AreaTypeEnum}
*/
private Integer type;

View File

@ -82,15 +82,15 @@ public class AreaUtils {
/**
* 格式化区域
*
* <p>
* 例如说:
* 1. id = “静安区”时:上海 上海市 静安区
* 2. id = “上海市”时:上海 上海市
* 3. id = “上海”时:上海
* 4. id = “美国”时:美国
* 1. id = “静安区”时:上海 上海市 静安区
* 2. id = “上海市”时:上海 上海市
* 3. id = “上海”时:上海
* 4. id = “美国”时:美国
* 当区域在中国时,默认不显示中国
*
* @param id 区域编号
* @param id 区域编号
* @param separator 分隔符
* @return 格式化后的区域
*/
@ -108,7 +108,7 @@ public class AreaUtils {
// “递归”父节点
area = area.getParent();
if (area == null
|| ObjectUtils.equalsAny(area.getId(), Area.ID_GLOBAL, Area.ID_CHINA)) { // 跳过父节点为中国的情况
|| ObjectUtils.equalsAny(area.getId(), Area.ID_GLOBAL, Area.ID_CHINA)) { // 跳过父节点为中国的情况
break;
}
sb.insert(0, separator);

View File

@ -10,7 +10,7 @@ import java.io.IOException;
/**
* IP 工具类
*
* <p>
* IP 数据源来自 ip2region.xdb 精简版,基于 <a href="https://gitee.com/zhijiantianya/ip2region"/> 项目
*
* @author wanglhup

View File

@ -1,10 +1,10 @@
/**
* IP 拓展,支持如下功能:
*
* <p>
* 1. IP 功能:查询 IP 对应的城市信息
* 基于 https://gitee.com/lionsoul/ip2region 实现
* 基于 https://gitee.com/lionsoul/ip2region 实现
* 2. 城市功能:查询城市编码对应的城市信息
* 基于 https://github.com/modood/Administrative-divisions-of-China 实现
* 基于 https://github.com/modood/Administrative-divisions-of-China 实现
*
* @author yshop
*/

View File

@ -1,36 +0,0 @@
package co.yixiang.yshop.framework.ip.core.utils;
import co.yixiang.yshop.framework.ip.core.Area;
import co.yixiang.yshop.framework.ip.core.enums.AreaTypeEnum;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* {@link AreaUtils} 的单元测试
*
* @author yshop
*/
public class AreaUtilsTest {
@Test
public void testGetArea() {
// 调用:北京
Area area = AreaUtils.getArea(110100);
// 断言
assertEquals(area.getId(), 110100);
assertEquals(area.getName(), "北京市");
assertEquals(area.getType(), AreaTypeEnum.CITY.getType());
assertEquals(area.getParent().getId(), 110000);
assertEquals(area.getChildren().size(), 16);
}
@Test
public void testFormat() {
assertEquals(AreaUtils.format(110105), "北京 北京市 朝阳区");
assertEquals(AreaUtils.format(1), "中国");
assertEquals(AreaUtils.format(2), "蒙古");
}
}

View File

@ -1,47 +0,0 @@
package co.yixiang.yshop.framework.ip.core.utils;
import co.yixiang.yshop.framework.ip.core.Area;
import org.junit.jupiter.api.Test;
import org.lionsoul.ip2region.xdb.Searcher;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* {@link IPUtils} 的单元测试
*
* @author wanglhup
*/
public class IPUtilsTest {
@Test
public void testGetAreaId_string() {
// 120.202.4.0|120.202.4.255|420600
Integer areaId = IPUtils.getAreaId("120.202.4.50");
assertEquals(420600, areaId);
}
@Test
public void testGetAreaId_long() throws Exception {
// 120.203.123.0|120.203.133.255|360900
long ip = Searcher.checkIP("120.203.123.250");
Integer areaId = IPUtils.getAreaId(ip);
assertEquals(360900, areaId);
}
@Test
public void testGetArea_string() {
// 120.202.4.0|120.202.4.255|420600
Area area = IPUtils.getArea("120.202.4.50");
assertEquals("襄阳市", area.getName());
}
@Test
public void testGetArea_long() throws Exception {
// 120.203.123.0|120.203.133.255|360900
long ip = Searcher.checkIP("120.203.123.252");
Area area = IPUtils.getArea(ip);
assertEquals("宜春市", area.getName());
}
}

View File

@ -22,19 +22,21 @@ public @interface OperateLog {
/**
* 操作模块
*
* <p>
* 为空时,会尝试读取 {@link Tag#name()} 属性
*/
String module() default "";
/**
* 操作名
*
* <p>
* 为空时,会尝试读取 {@link Operation#summary()} 属性
*/
String name() default "";
/**
* 操作分类
*
* <p>
* 实际并不是数组,因为枚举不能设置 null 作为默认值
*/
OperateTypeEnum[] type() default {};
@ -45,10 +47,12 @@ public @interface OperateLog {
* 是否记录操作日志
*/
boolean enable() default true;
/**
* 是否记录方法参数
*/
boolean logArgs() default true;
/**
* 是否记录方法结果的数据
*/

View File

@ -267,9 +267,9 @@ public class OperateLogAspect {
return null;
}
return Arrays.stream(requestMethods).filter(requestMethod ->
requestMethod == RequestMethod.POST
|| requestMethod == RequestMethod.PUT
|| requestMethod == RequestMethod.DELETE)
requestMethod == RequestMethod.POST
|| requestMethod == RequestMethod.PUT
|| requestMethod == RequestMethod.DELETE)
.findFirst().orElse(null);
}

View File

@ -15,7 +15,7 @@ public enum OperateTypeEnum {
/**
* 查询
*
* <p>
* 绝大多数情况下,不会记录查询动作,因为过于大量显得没有意义。
* 在有需要的时候,通过声明 {@link OperateLog} 注解来记录
*/
@ -42,7 +42,7 @@ public enum OperateTypeEnum {
IMPORT(6),
/**
* 其它
*
* <p>
* 在无法归类时,可以选择使用其它。因为还有操作名可以进一步标识
*/
OTHER(0);

View File

@ -8,7 +8,7 @@ import org.springframework.scheduling.annotation.Async;
/**
* 操作日志 Framework Service 实现类
*
* <p>
* 基于 {@link OperateLogApi} 实现,记录操作日志
*
* @author yshop

View File

@ -25,9 +25,9 @@ public interface SmsClient {
/**
* 发送消息
*
* @param logId 日志编号
* @param mobile 手机号
* @param apiTemplateId 短信 API 的模板编号
* @param logId 日志编号
* @param mobile 手机号
* @param apiTemplateId 短信 API 的模板编号
* @param templateParams 短信模板参数。通过 List 数组,保证参数的顺序
* @return 短信发送结果
*/

View File

@ -8,10 +8,9 @@ import java.util.function.Function;
/**
* 将 API 的错误码,转换为通用的错误码
*
* @author yshop
* @see SmsCommonResult
* @see SmsFrameworkErrorCodeConstants
*
* @author yshop
*/
public interface SmsCodeMapping extends Function<String, ErrorCode> {
}

View File

@ -11,9 +11,9 @@ import lombok.ToString;
/**
* 短信的 CommonResult 拓展类
*
* <p>
* 考虑到不同的平台,返回的 code 和 msg 是不同的,所以统一额外返回 {@link #apiCode} 和 {@link #apiMsg} 字段
*
* <p>
* 另外,一些短信平台(例如说阿里云、腾讯云)会返回一个请求编号,用于排查请求失败的问题,我们设置到 {@link #apiRequestId} 字段
*
* @author yshop
@ -25,7 +25,7 @@ public class SmsCommonResult<T> extends CommonResult<T> {
/**
* API 返回错误码
*
* <p>
* 由于第三方的错误码可能是字符串,所以使用 String 类型
*/
private String apiCode;

View File

@ -40,7 +40,7 @@ public class SmsReceiveRespDTO {
private String serialNo;
/**
* 短信日志编号
*
* <p>
* 对应 SysSmsLogDO 的编号
*/
private Long logId;

View File

@ -21,7 +21,7 @@ public class SmsTemplateRespDTO {
private String content;
/**
* 审核状态
*
* <p>
* 枚举 {@link SmsTemplateAuditStatusEnum}
*/
private Integer auditStatus;

View File

@ -87,10 +87,12 @@ public class SmsClientFactoryImpl implements SmsClientFactory {
Assert.notNull(channelEnum, String.format("渠道类型(%s) 为空", channelEnum));
// 创建客户端
switch (channelEnum) {
case ALIYUN: return new AliyunSmsClient(properties);
case ALIYUN:
return new AliyunSmsClient(properties);
// case DEBUG_DING_TALK: return new DebugDingTalkSmsClient(properties);
// case TENCENT: return new TencentSmsClient(properties);
default: return new AliyunSmsClient(properties);
default:
return new AliyunSmsClient(properties);
}
// 创建失败,错误日志 + 抛出异常

View File

@ -114,10 +114,14 @@ public class AliyunSmsClient extends AbstractSmsClient {
@VisibleForTesting
Integer convertSmsTemplateAuditStatus(Integer templateStatus) {
switch (templateStatus) {
case 0: return SmsTemplateAuditStatusEnum.CHECKING.getStatus();
case 1: return SmsTemplateAuditStatusEnum.SUCCESS.getStatus();
case 2: return SmsTemplateAuditStatusEnum.FAIL.getStatus();
default: throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus));
case 0:
return SmsTemplateAuditStatusEnum.CHECKING.getStatus();
case 1:
return SmsTemplateAuditStatusEnum.SUCCESS.getStatus();
case 2:
return SmsTemplateAuditStatusEnum.FAIL.getStatus();
default:
throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus));
}
}
@ -150,7 +154,7 @@ public class AliyunSmsClient extends AbstractSmsClient {
/**
* 短信接收状态
*
* <p>
* 参见 https://help.aliyun.com/document_detail/101867.html 文档
*
* @author yshop
@ -196,14 +200,14 @@ public class AliyunSmsClient extends AbstractSmsClient {
private String bizId;
/**
* 用户序列号
*
* <p>
* 这里我们传递的是 SysSmsLogDO 的日志编号
*/
@JsonProperty("out_id")
private String outId;
/**
* 短信长度,例如说 1、2、3
*
* <p>
* 140 字节算一条短信,短信长度超过 140 字节时会拆分成多条短信发送
*/
@JsonProperty("sms_size")

View File

@ -7,7 +7,7 @@ import co.yixiang.yshop.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
/**
* 阿里云的 SmsCodeMapping 实现类
*
* <p>
* 参见 https://help.aliyun.com/document_detail/101346.htm 文档
*
* @author yshop
@ -17,25 +17,38 @@ public class AliyunSmsCodeMapping implements SmsCodeMapping {
@Override
public ErrorCode apply(String apiCode) {
switch (apiCode) {
case "OK": return GlobalErrorCodeConstants.SUCCESS;
case "OK":
return GlobalErrorCodeConstants.SUCCESS;
case "isv.ACCOUNT_NOT_EXISTS":
case "isv.ACCOUNT_ABNORMAL":
case "MissingAccessKeyId": return SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID;
case "isp.RAM_PERMISSION_DENY": return SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY;
case "MissingAccessKeyId":
return SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID;
case "isp.RAM_PERMISSION_DENY":
return SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY;
case "isv.INVALID_JSON_PARAM":
case "isv.INVALID_PARAMETERS": return SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR;
case "isv.BUSINESS_LIMIT_CONTROL": return SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL;
case "isv.DAY_LIMIT_CONTROL": return SmsFrameworkErrorCodeConstants.SMS_SEND_DAY_LIMIT_CONTROL;
case "isv.SMS_CONTENT_ILLEGAL": return SmsFrameworkErrorCodeConstants.SMS_SEND_CONTENT_INVALID;
case "isv.SMS_TEMPLATE_ILLEGAL": return SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID;
case "isv.INVALID_PARAMETERS":
return SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR;
case "isv.BUSINESS_LIMIT_CONTROL":
return SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL;
case "isv.DAY_LIMIT_CONTROL":
return SmsFrameworkErrorCodeConstants.SMS_SEND_DAY_LIMIT_CONTROL;
case "isv.SMS_CONTENT_ILLEGAL":
return SmsFrameworkErrorCodeConstants.SMS_SEND_CONTENT_INVALID;
case "isv.SMS_TEMPLATE_ILLEGAL":
return SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID;
case "isv.SMS_SIGNATURE_ILLEGAL":
case "isv.SIGN_NAME_ILLEGAL":
case "isv.SMS_SIGN_ILLEGAL": return SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID;
case "isv.SMS_SIGN_ILLEGAL":
return SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID;
case "isv.AMOUNT_NOT_ENOUGH":
case "isv.OUT_OF_SERVICE": return SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH;
case "isv.MOBILE_NUMBER_ILLEGAL": return SmsFrameworkErrorCodeConstants.SMS_MOBILE_INVALID;
case "isv.TEMPLATE_MISSING_PARAMETERS": return SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR;
default: return SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;
case "isv.OUT_OF_SERVICE":
return SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH;
case "isv.MOBILE_NUMBER_ILLEGAL":
return SmsFrameworkErrorCodeConstants.SMS_MOBILE_INVALID;
case "isv.TEMPLATE_MISSING_PARAMETERS":
return SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR;
default:
return SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;
}
}

View File

@ -24,7 +24,7 @@ import java.util.Map;
/**
* 基于钉钉 WebHook 实现的调试的短信客户端实现类
*
* <p>
* 考虑到省钱,我们使用钉钉 WebHook 模拟发送短信,方便调试。
*
* @author yshop
@ -61,7 +61,7 @@ public class DebugDingTalkSmsClient extends AbstractSmsClient {
/**
* 构建请求地址
*
* <p>
* 参见 https://developers.dingtalk.com/document/app/custom-robot-access/title-nfv-794-g71 文档
*
* @param path 请求路径

View File

@ -189,6 +189,7 @@ public class TencentSmsClient extends AbstractSmsClient {
/**
* 封装查询模版审核状态请求
*
* @param apiTemplateId api 的模版 id
* @return 查询模版审核状态请求
*/

View File

@ -9,7 +9,7 @@ import static co.yixiang.yshop.framework.sms.core.enums.SmsFrameworkErrorCodeCon
/**
* 腾讯云的 SmsCodeMapping 实现类
*
* <p>
* 参见 https://cloud.tencent.com/document/api/382/52075#.E5.85.AC.E5.85.B1.E9.94.99.E8.AF.AF.E7.A0.81
*
* @author : shiwp
@ -19,31 +19,47 @@ public class TencentSmsCodeMapping implements SmsCodeMapping {
@Override
public ErrorCode apply(String apiCode) {
switch (apiCode) {
case TencentSmsClient.API_SUCCESS_CODE: return GlobalErrorCodeConstants.SUCCESS;
case "FailedOperation.ContainSensitiveWord": return SMS_SEND_CONTENT_INVALID;
case TencentSmsClient.API_SUCCESS_CODE:
return GlobalErrorCodeConstants.SUCCESS;
case "FailedOperation.ContainSensitiveWord":
return SMS_SEND_CONTENT_INVALID;
case "FailedOperation.JsonParseFail":
case "MissingParameter.EmptyPhoneNumberSet":
case "LimitExceeded.PhoneNumberCountLimit":
case "FailedOperation.FailResolvePacket": return GlobalErrorCodeConstants.BAD_REQUEST;
case "FailedOperation.InsufficientBalanceInSmsPackage": return SMS_ACCOUNT_MONEY_NOT_ENOUGH;
case "FailedOperation.MarketingSendTimeConstraint": return SMS_SEND_MARKET_LIMIT_CONTROL;
case "FailedOperation.PhoneNumberInBlacklist": return SMS_MOBILE_BLACK;
case "FailedOperation.SignatureIncorrectOrUnapproved": return SMS_SIGN_INVALID;
case "FailedOperation.FailResolvePacket":
return GlobalErrorCodeConstants.BAD_REQUEST;
case "FailedOperation.InsufficientBalanceInSmsPackage":
return SMS_ACCOUNT_MONEY_NOT_ENOUGH;
case "FailedOperation.MarketingSendTimeConstraint":
return SMS_SEND_MARKET_LIMIT_CONTROL;
case "FailedOperation.PhoneNumberInBlacklist":
return SMS_MOBILE_BLACK;
case "FailedOperation.SignatureIncorrectOrUnapproved":
return SMS_SIGN_INVALID;
case "FailedOperation.MissingTemplateToModify":
case "FailedOperation.TemplateIncorrectOrUnapproved": return SMS_TEMPLATE_INVALID;
case "InvalidParameterValue.IncorrectPhoneNumber": return SMS_MOBILE_INVALID;
case "InvalidParameterValue.SdkAppIdNotExist": return SMS_APP_ID_INVALID;
case "FailedOperation.TemplateIncorrectOrUnapproved":
return SMS_TEMPLATE_INVALID;
case "InvalidParameterValue.IncorrectPhoneNumber":
return SMS_MOBILE_INVALID;
case "InvalidParameterValue.SdkAppIdNotExist":
return SMS_APP_ID_INVALID;
case "InvalidParameterValue.TemplateParameterLengthLimit":
case "InvalidParameterValue.TemplateParameterFormatError": return SMS_TEMPLATE_PARAM_ERROR;
case "LimitExceeded.PhoneNumberDailyLimit": return SMS_SEND_DAY_LIMIT_CONTROL;
case "InvalidParameterValue.TemplateParameterFormatError":
return SMS_TEMPLATE_PARAM_ERROR;
case "LimitExceeded.PhoneNumberDailyLimit":
return SMS_SEND_DAY_LIMIT_CONTROL;
case "LimitExceeded.PhoneNumberThirtySecondLimit":
case "LimitExceeded.PhoneNumberOneHourLimit": return SMS_SEND_BUSINESS_LIMIT_CONTROL;
case "LimitExceeded.PhoneNumberOneHourLimit":
return SMS_SEND_BUSINESS_LIMIT_CONTROL;
case "UnauthorizedOperation.RequestPermissionDeny":
case "FailedOperation.ForbidAddMarketingTemplates":
case "FailedOperation.NotEnterpriseCertification":
case "UnauthorizedOperation.IndividualUserMarketingSmsPermissionDeny": return SMS_PERMISSION_DENY;
case "UnauthorizedOperation.RequestIpNotInWhitelist": return SMS_IP_DENY;
case "AuthFailure.SecretIdNotFound": return SMS_ACCOUNT_INVALID;
case "UnauthorizedOperation.IndividualUserMarketingSmsPermissionDeny":
return SMS_PERMISSION_DENY;
case "UnauthorizedOperation.RequestIpNotInWhitelist":
return SMS_IP_DENY;
case "AuthFailure.SecretIdNotFound":
return SMS_ACCOUNT_INVALID;
}
return SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;
}

View File

@ -4,7 +4,7 @@ import co.yixiang.yshop.framework.common.exception.ErrorCode;
/**
* 短信框架的错误码枚举
*
* <p>
* 短信框架,使用 2-001-000-000 段
*
* @author yshop

View File

@ -29,7 +29,7 @@ public class SmsChannelProperties {
private String signature;
/**
* 渠道编码
*
* <p>
* 枚举 {@link SmsChannelEnum}
*/
@NotEmpty(message = "渠道编码不能为空")

View File

@ -4,7 +4,7 @@ import me.zhyd.oauth.config.AuthSource;
/**
* 拓展 JustAuth 各 api 需要的 url 用枚举类分平台类型管理
*
* <p>
* 默认配置 {@link me.zhyd.oauth.config.AuthDefaultSource}
*
* @author timfruit
@ -15,7 +15,6 @@ public enum AuthExtendSource implements AuthSource {
* 微信小程序授权登录
*/
WECHAT_MINI_APP {
@Override
public String authorize() {
// 参见 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html 文档

View File

@ -16,7 +16,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
/**
* 微信小程序登陆 Request 请求
*
* <p>
* 由于 JustAuth 定位是面向 Web 为主的三方登录,所以微信小程序只能自己封装
*
* @author timfruit

View File

@ -27,14 +27,14 @@ public class TenantProperties {
/**
* 需要忽略多租户的请求
*
* <p>
* 默认情况下,每个请求需要带上 tenant-id 的请求头。但是,部分请求是无需带上的,例如说短信回调、支付回调等 Open API
*/
private Set<String> ignoreUrls = Collections.emptySet();
/**
* 需要忽略多租户的表
*
* <p>
* 即默认所有表都开启多租户的功能,所以记得添加对应的 tenant_id 字段哟
*/
private Set<String> ignoreTables = Collections.emptySet();

View File

@ -36,7 +36,8 @@ import org.springframework.data.redis.core.RedisTemplate;
import java.util.Objects;
@AutoConfiguration
@ConditionalOnProperty(prefix = "yshop.tenant", value = "enable", matchIfMissing = true) // 允许使用 yshop.tenant.enable=false 禁用多租户
@ConditionalOnProperty(prefix = "yshop.tenant", value = "enable", matchIfMissing = true)
// 允许使用 yshop.tenant.enable=false 禁用多租户
@EnableConfigurationProperties(TenantProperties.class)
public class YshopTenantAutoConfiguration {

View File

@ -4,7 +4,7 @@ import java.lang.annotation.*;
/**
* 忽略租户,标记指定方法不进行租户的自动过滤
*
* <p>
* 注意,只有 DB 的场景会过滤,其它场景暂时不过滤:
* 1、Redis 场景:因为是基于 Key 实现多租户的能力,所以忽略没有意义,不像 DB 是一个 column 实现的
* 2、MQ 场景:有点难以抉择,目前可以通过 Consumer 手动在消费的方法上,添加 @TenantIgnore 进行忽略

View File

@ -11,7 +11,7 @@ import org.aspectj.lang.annotation.Aspect;
* 忽略多租户的 Aspect基于 {@link TenantIgnore} 注解实现,用于一些全局的逻辑。
* 例如说,一个定时任务,读取所有数据,进行处理。
* 又例如说,读取所有数据,进行缓存。
*
* <p>
* 整体逻辑的实现,和 {@link TenantUtils#executeIgnore(Runnable)} 需要保持一致
*
* @author yshop

View File

@ -38,7 +38,7 @@ public class TenantContextHolder {
Long tenantId = getTenantId();
if (tenantId == null) {
throw new NullPointerException("TenantContextHolder 不存在租户编号!可参考文档:"
+ DocumentEnum.TENANT.getUrl());
+ DocumentEnum.TENANT.getUrl());
}
return tenantId;
}

View File

@ -37,7 +37,7 @@ public class TenantDatabaseInterceptor implements TenantLineHandler {
@Override
public boolean ignoreTable(String tableName) {
return TenantContextHolder.isIgnore() // 情况一,全局忽略多租户
|| CollUtil.contains(ignoreTables, tableName); // 情况二,忽略多租户的表
|| CollUtil.contains(ignoreTables, tableName); // 情况二,忽略多租户的表
}
}

View File

@ -14,7 +14,7 @@ import java.util.concurrent.ConcurrentHashMap;
/**
* 多租户 JobHandler 装饰器
* 任务执行时,会按照租户逐个执行 Job 的逻辑
*
* <p>
* 注意,需要保证 JobHandler 的幂等性。因为 Job 因为某个租户执行失败重试时,之前执行成功的租户也会再次执行。
*
* @author yshop

View File

@ -9,7 +9,7 @@ import static co.yixiang.yshop.framework.web.core.util.WebFrameworkUtils.HEADER_
/**
* 多租户 {@link AbstractRedisMessage} 拦截器
*
* <p>
* 1. Producer 发送消息时,将 {@link TenantContextHolder} 租户编号,添加到消息的 Header 中
* 2. Consumer 消费消息时,将消息的 Header 的租户编号,添加到 {@link TenantContextHolder} 中
*

View File

@ -9,7 +9,7 @@ import org.springframework.data.redis.cache.RedisCacheWriter;
/**
* 多租户的 {@link RedisCacheManager} 实现类
*
* <p>
* 操作指定 name 的 {@link Cache} 时,自动拼接租户后缀,格式为 name + ":" + tenantId + 后缀
*
* @author airhead
@ -26,7 +26,7 @@ public class TenantRedisCacheManager extends RedisCacheManager {
public Cache getCache(String name) {
// 如果开启多租户,则 name 拼接租户后缀
if (!TenantContextHolder.isIgnore()
&& TenantContextHolder.getTenantId() != null) {
&& TenantContextHolder.getTenantId() != null) {
name = name + ":" + TenantContextHolder.getTenantId();
}

View File

@ -8,12 +8,12 @@ import java.time.Duration;
/**
* 多租户拓展的 RedisKeyDefine 实现类
*
* <p>
* 由于 Redis 不同于 MySQL 有 column 字段,无法通过类似 WHERE tenant_id = ? 的方式过滤
* 所以需要通过在 Redis Key 上增加后缀的方式,进行租户之间的隔离。具体的步骤是:
* 1. 假设 Redis Key 是 user:%d示例是 user:1对应到多租户的 Redis Key 是 user:%d:%d
* 2. 在 Redis DAO 中,需要使用 {@link #formatKey(Object...)} 方法,进行 Redis Key 的格式化
*
* <p>
* 注意,大多数情况下,并不用使用 TenantRedisKeyDefine 实现。主要的使用场景,还是 Redis Key 可能存在冲突的情况。
* 例如说,租户 1 和 2 都有一个手机号作为 Key则他们会存在冲突的问题
*

View File

@ -62,7 +62,7 @@ public class TenantSecurityWebFilter extends ApiRequestFilter {
if (tenantId == null) {
tenantId = user.getTenantId();
TenantContextHolder.setTenantId(tenantId);
// 如果传递了租户编号,则进行比对租户编号,避免越权问题
// 如果传递了租户编号,则进行比对租户编号,避免越权问题
} else if (!Objects.equals(user.getTenantId(), TenantContextHolder.getTenantId())) {
log.error("[doFilterInternal][租户({}) User({}/{}) 越权访问租户({}) URL({}/{})]",
user.getTenantId(), user.getId(), user.getUserType(),

View File

@ -16,7 +16,7 @@ public class TenantUtils {
/**
* 使用指定租户,执行对应的逻辑
*
* <p>
* 注意,如果当前是忽略租户的情况下,会被强制设置成不忽略租户
* 当然,执行完成后,还是会恢复回去
*
@ -39,7 +39,7 @@ public class TenantUtils {
/**
* 使用指定租户,执行对应的逻辑
*
* <p>
* 注意,如果当前是忽略租户的情况下,会被强制设置成不忽略租户
* 当然,执行完成后,还是会恢复回去
*

View File

@ -7,11 +7,10 @@
* 5. Job在 JobHandler 执行任务时,会按照每个租户,都独立并行执行一次。
* 6. MQ在 Producer 发送消息时Header 带上 tenant-id 租户编号;在 Consumer 消费消息时,将 Header 的 tenant-id 租户编号,添加到租户上下文。
* 7. Async异步需要保证 ThreadLocal 的传递性,通过使用阿里开源的 TransmittableThreadLocal 实现。相关的改造点,可见:
* 1Spring Async
* {@link co.yixiang.yshop.framework.quartz.config.YshopAsyncAutoConfiguration#threadPoolTaskExecutorBeanPostProcessor()}
* 2Spring Security
* TransmittableThreadLocalSecurityContextHolderStrategy
* 和 YshopSecurityAutoConfiguration#securityContextHolderMethodInvokingFactoryBean() 方法
*
* 1Spring Async
* {@link co.yixiang.yshop.framework.quartz.config.YshopAsyncAutoConfiguration#threadPoolTaskExecutorBeanPostProcessor()}
* 2Spring Security
* TransmittableThreadLocalSecurityContextHolderStrategy
* 和 YshopSecurityAutoConfiguration#securityContextHolderMethodInvokingFactoryBean() 方法
*/
package co.yixiang.yshop.framework.tenant;

View File

@ -34,7 +34,7 @@
<!-- 三方云服务相关 -->
<dependency>
<groupId>com.github.binarywang</groupId>
<!-- <artifactId>weixin-java-mp</artifactId>-->
<!-- <artifactId>weixin-java-mp</artifactId>-->
<artifactId>wx-java-mp-spring-boot-starter</artifactId>
<version>4.4.0</version>
</dependency>

View File

@ -1,4 +1,5 @@
package co.yixiang.yshop.framework.weixin.config;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.config.WxMaConfig;

View File

@ -47,7 +47,7 @@ public class RedisCaptchaServiceImpl implements CaptchaCacheService {
@Override
public Long increment(String key, long val) {
return stringRedisTemplate.opsForValue().increment(key,val);
return stringRedisTemplate.opsForValue().increment(key, val);
}
}

View File

@ -22,7 +22,7 @@ import java.lang.reflect.Field;
/**
* 脱敏序列化器
*
* <p>
* 实现 JSON 返回数据时,使用 {@link DesensitizationHandler} 对声明脱敏注解的字段,进行脱敏处理。
*
* @author gaibu

View File

@ -29,7 +29,7 @@ public @interface EmailDesensitize {
/**
* 替换规则,邮箱;
*
* <p>
* 比如example@gmail.com 脱敏之后为 e****@gmail.com
*/
String replacer() default "$1****$2";

View File

@ -29,7 +29,7 @@ public @interface RegexDesensitize {
/**
* 替换规则,会将匹配到的字符串全部替换成 replacer
*
* <p>
* 例如regex=123; replacer=******
* 原始字符串 123456789
* 脱敏后字符串 ******456789

View File

@ -34,7 +34,7 @@ public @interface PasswordDesensitize {
/**
* 替换规则,密码;
*
* <p>
* 比如123456 脱敏之后为 ******
*/
String replacer() default "*";

View File

@ -29,7 +29,7 @@ public @interface SliderDesensitize {
/**
* 替换规则,会将前缀后缀保留后,全部替换成 replacer
*
* <p>
* 例如prefixKeep = 1; suffixKeep = 2; replacer = "*";
* 原始字符串 123456
* 脱敏后 1***56

View File

@ -13,7 +13,7 @@ import java.lang.annotation.Target;
/**
* 地址
*
* <p>
* 用于 {@link DesensitizeTest} 测试使用
*
* @author gaibu

View File

@ -6,7 +6,7 @@ import co.yixiang.yshop.framework.desensitize.core.annotation.Address;
/**
* {@link Address} 的脱敏处理器
*
* <p>
* 用于 {@link DesensitizeTest} 测试使用
*/
public class AddressHandler implements DesensitizationHandler<Address> {

View File

@ -4,7 +4,7 @@ import java.lang.annotation.*;
/**
* 字典格式化
*
* <p>
* 实现将字典数据的值,格式化成字典数据的标签
*/
@Target({ElementType.FIELD})

View File

@ -19,12 +19,12 @@ public class ExcelUtils {
/**
* 将列表以 Excel 响应给前端
*
* @param response 响应
* @param filename 文件名
* @param response 响应
* @param filename 文件名
* @param sheetName Excel sheet 名
* @param head Excel head 头
* @param data 数据列表哦
* @param <T> 泛型,保证 head 和 data 类型的一致性
* @param head Excel head 头
* @param data 数据列表哦
* @param <T> 泛型,保证 head 和 data 类型的一致性
* @throws IOException 写入失败的情况
*/
public static <T> void write(HttpServletResponse response, String filename, String sheetName,
@ -40,7 +40,7 @@ public class ExcelUtils {
}
public static <T> List<T> read(MultipartFile file, Class<T> head) throws IOException {
return EasyExcel.read(file.getInputStream(), head, null)
return EasyExcel.read(file.getInputStream(), head, null)
.autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理
.doReadAllSync();
}

View File

@ -59,7 +59,7 @@ public abstract class AbstractFileClient<Config extends FileClientConfig> implem
* 使用场景local、ftp、db通过 FileController 的 getFile 来获取文件内容
*
* @param domain 自定义域名
* @param path 文件路径
* @param path 文件路径
* @return URL 访问地址
*/
protected String formatFileUrl(String domain, String path) {

View File

@ -18,11 +18,11 @@ public interface FileClient {
* 上传文件
*
* @param content 文件流
* @param path 相对路径
* @param path 相对路径
* @return 完整路径,即 HTTP 访问地址
* @throws Exception 上传文件时,抛出 Exception 异常
*/
String upload(byte[] content, String path, String type) throws Exception;
String upload(byte[] content, String path, String type) throws Exception;
/**
* 删除文件

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