更新sql和代码规范修改
This commit is contained in:
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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";
|
||||
|
||||
}
|
||||
|
@ -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";
|
||||
|
||||
|
||||
|
@ -13,7 +13,7 @@ import java.util.Arrays;
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DeletedEnum {
|
||||
public enum DeletedEnum {
|
||||
|
||||
NO(false, "默认"),
|
||||
YES(true, "已逻辑删除");
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 后面
|
||||
|
||||
|
@ -6,10 +6,10 @@ import lombok.Data;
|
||||
|
||||
/**
|
||||
* 错误码对象
|
||||
*
|
||||
* <p>
|
||||
* 全局错误码,占用 [0, 999], 参见 {@link GlobalErrorCodeConstants}
|
||||
* 业务异常错误码,占用 [1 000 000 000, +∞),参见 {@link ServiceErrorCodeRange}
|
||||
*
|
||||
* <p>
|
||||
* TODO 错误码设计成对象的原因,为未来的 i18 国际化做准备
|
||||
*/
|
||||
@Data
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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 异常
|
||||
*/
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* 基础的通用类,和框架无关
|
||||
*
|
||||
* <p>
|
||||
* 例如说,CommonResult 为通用返回
|
||||
*/
|
||||
package co.yixiang.yshop.framework.common;
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -4,7 +4,7 @@ import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 排序字段 DTO
|
||||
*
|
||||
* <p>
|
||||
* 类名加了 ing 的原因是,避免和 ES SortField 重名。
|
||||
*/
|
||||
public class SortingField implements Serializable {
|
||||
|
@ -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 + "");
|
||||
|
@ -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 + "");
|
||||
|
@ -20,9 +20,9 @@ public class ArrayUtils {
|
||||
/**
|
||||
* 将 object 和 newElements 合并成一个数组
|
||||
*
|
||||
* @param object 对象
|
||||
* @param object 对象
|
||||
* @param newElements 数组
|
||||
* @param <T> 泛型
|
||||
* @param <T> 泛型
|
||||
* @return 结果数组
|
||||
*/
|
||||
@SafeVarargs
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ public class LocalDateTimeUtils {
|
||||
* 判断当前时间是否在该时间范围内
|
||||
*
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @param endTime 结束时间
|
||||
* @return 是否
|
||||
*/
|
||||
public static boolean isBetween(LocalDateTime startTime, LocalDateTime endTime) {
|
||||
|
@ -18,6 +18,7 @@ public class DistanceCalculatorUtil {
|
||||
|
||||
/**
|
||||
* 计算两地之间距离
|
||||
*
|
||||
* @param lat1 第一个点的纬度
|
||||
* @param lon1 第一个点的经度
|
||||
* @param lat2 第二个点的纬度
|
||||
|
@ -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();
|
||||
|
@ -16,7 +16,7 @@ public class IoUtils {
|
||||
/**
|
||||
* 从流中读取 UTF8 编码的内容
|
||||
*
|
||||
* @param in 输入流
|
||||
* @param in 输入流
|
||||
* @param isClose 是否关闭
|
||||
* @return 内容
|
||||
* @throws IORuntimeException IO 异常
|
||||
|
@ -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 对象
|
||||
*/
|
||||
|
@ -4,7 +4,7 @@ import org.apache.skywalking.apm.toolkit.trace.TraceContext;
|
||||
|
||||
/**
|
||||
* 链路追踪工具类
|
||||
*
|
||||
* <p>
|
||||
* 考虑到每个 starter 都需要用到该工具类,所以放到 common 模块下的 util 包下
|
||||
*
|
||||
* @author yshop
|
||||
|
@ -17,7 +17,7 @@ public class ObjectUtils {
|
||||
/**
|
||||
* 复制对象,并忽略 Id 编号
|
||||
*
|
||||
* @param object 被复制对象
|
||||
* @param object 被复制对象
|
||||
* @param consumer 消费者,可以二次编辑被复制对象
|
||||
* @return 复制后的对象
|
||||
*/
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* 对于工具类的选择,优先查找 Hutool 中有没对应的方法
|
||||
* 如果没有,则自己封装对应的工具类,以 Utils 结尾,用于区分
|
||||
*
|
||||
* <p>
|
||||
* ps:如果担心 Hutool 存在坑的问题,可以阅读 Hutool 的实现源码,以确保可靠性。并且,可以补充相关的单元测试。
|
||||
*/
|
||||
package co.yixiang.yshop.framework.common.util;
|
||||
|
@ -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
|
||||
|
@ -7,7 +7,7 @@ import org.springframework.aop.support.AopUtils;
|
||||
|
||||
/**
|
||||
* Spring AOP 工具类
|
||||
*
|
||||
* <p>
|
||||
* 参考波克尔 http://www.bubuko.com/infodetail-3471885.html 实现
|
||||
*/
|
||||
public class SpringAopUtils {
|
||||
|
@ -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 为对应值
|
||||
*/
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ public class DataPermissionContextHolder {
|
||||
|
||||
/**
|
||||
* 清空上下文
|
||||
*
|
||||
* <p>
|
||||
* 目前仅仅用于单测
|
||||
*/
|
||||
public static void clear() {
|
||||
|
@ -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) {
|
||||
|
@ -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 表达式
|
||||
*/
|
||||
|
@ -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) {
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* 字典数据模块,提供 {@link co.yixiang.yshop.framework.dict.core.util.DictFrameworkUtils} 工具类
|
||||
*
|
||||
* <p>
|
||||
* 通过将字典缓存在内存中,保证性能
|
||||
*/
|
||||
package co.yixiang.yshop.framework.dict;
|
||||
|
@ -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>
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -15,7 +15,7 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* ErrorCodeLoader 的实现类,从 infra 的数据库中,加载错误码。
|
||||
*
|
||||
* <p>
|
||||
* 考虑到错误码会刷新,所以按照 {@link #REFRESH_ERROR_CODE_PERIOD} 频率,增量加载错误码。
|
||||
*
|
||||
* @author dlyan
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* 错误码 ErrorCode 的自动配置功能,提供如下功能:
|
||||
*
|
||||
* <p>
|
||||
* 1. 远程读取:项目启动时,从 system-service 服务,读取数据库中的 ErrorCode 错误码,实现错误码的提水可配置;
|
||||
* 2. 自动更新:管理员在管理后台修数据库中的 ErrorCode 错误码时,项目自动从 system-service 服务加载最新的 ErrorCode 错误码;
|
||||
* 3. 自动写入:项目启动时,将项目本地的错误码写到 system-server 服务中,方便管理员在管理后台编辑;
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -10,7 +10,7 @@ import java.io.IOException;
|
||||
|
||||
/**
|
||||
* IP 工具类
|
||||
*
|
||||
* <p>
|
||||
* IP 数据源来自 ip2region.xdb 精简版,基于 <a href="https://gitee.com/zhijiantianya/ip2region"/> 项目
|
||||
*
|
||||
* @author wanglhup
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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), "蒙古");
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
/**
|
||||
* 是否记录方法结果的数据
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ public enum OperateTypeEnum {
|
||||
|
||||
/**
|
||||
* 查询
|
||||
*
|
||||
* <p>
|
||||
* 绝大多数情况下,不会记录查询动作,因为过于大量显得没有意义。
|
||||
* 在有需要的时候,通过声明 {@link OperateLog} 注解来记录
|
||||
*/
|
||||
@ -42,7 +42,7 @@ public enum OperateTypeEnum {
|
||||
IMPORT(6),
|
||||
/**
|
||||
* 其它
|
||||
*
|
||||
* <p>
|
||||
* 在无法归类时,可以选择使用其它。因为还有操作名可以进一步标识
|
||||
*/
|
||||
OTHER(0);
|
||||
|
@ -8,7 +8,7 @@ import org.springframework.scheduling.annotation.Async;
|
||||
|
||||
/**
|
||||
* 操作日志 Framework Service 实现类
|
||||
*
|
||||
* <p>
|
||||
* 基于 {@link OperateLogApi} 实现,记录操作日志
|
||||
*
|
||||
* @author yshop
|
||||
|
@ -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 短信发送结果
|
||||
*/
|
||||
|
@ -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> {
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -40,7 +40,7 @@ public class SmsReceiveRespDTO {
|
||||
private String serialNo;
|
||||
/**
|
||||
* 短信日志编号
|
||||
*
|
||||
* <p>
|
||||
* 对应 SysSmsLogDO 的编号
|
||||
*/
|
||||
private Long logId;
|
||||
|
@ -21,7 +21,7 @@ public class SmsTemplateRespDTO {
|
||||
private String content;
|
||||
/**
|
||||
* 审核状态
|
||||
*
|
||||
* <p>
|
||||
* 枚举 {@link SmsTemplateAuditStatusEnum}
|
||||
*/
|
||||
private Integer auditStatus;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
// 创建失败,错误日志 + 抛出异常
|
||||
|
@ -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")
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 请求路径
|
||||
|
@ -189,6 +189,7 @@ public class TencentSmsClient extends AbstractSmsClient {
|
||||
|
||||
/**
|
||||
* 封装查询模版审核状态请求
|
||||
*
|
||||
* @param apiTemplateId api 的模版 id
|
||||
* @return 查询模版审核状态请求
|
||||
*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import co.yixiang.yshop.framework.common.exception.ErrorCode;
|
||||
|
||||
/**
|
||||
* 短信框架的错误码枚举
|
||||
*
|
||||
* <p>
|
||||
* 短信框架,使用 2-001-000-000 段
|
||||
*
|
||||
* @author yshop
|
||||
|
@ -29,7 +29,7 @@ public class SmsChannelProperties {
|
||||
private String signature;
|
||||
/**
|
||||
* 渠道编码
|
||||
*
|
||||
* <p>
|
||||
* 枚举 {@link SmsChannelEnum}
|
||||
*/
|
||||
@NotEmpty(message = "渠道编码不能为空")
|
||||
|
@ -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 文档
|
||||
|
@ -16,7 +16,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
/**
|
||||
* 微信小程序登陆 Request 请求
|
||||
*
|
||||
* <p>
|
||||
* 由于 JustAuth 定位是面向 Web 为主的三方登录,所以微信小程序只能自己封装
|
||||
*
|
||||
* @author timfruit
|
||||
|
@ -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();
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -4,7 +4,7 @@ import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 忽略租户,标记指定方法不进行租户的自动过滤
|
||||
*
|
||||
* <p>
|
||||
* 注意,只有 DB 的场景会过滤,其它场景暂时不过滤:
|
||||
* 1、Redis 场景:因为是基于 Key 实现多租户的能力,所以忽略没有意义,不像 DB 是一个 column 实现的
|
||||
* 2、MQ 场景:有点难以抉择,目前可以通过 Consumer 手动在消费的方法上,添加 @TenantIgnore 进行忽略
|
||||
|
@ -11,7 +11,7 @@ import org.aspectj.lang.annotation.Aspect;
|
||||
* 忽略多租户的 Aspect,基于 {@link TenantIgnore} 注解实现,用于一些全局的逻辑。
|
||||
* 例如说,一个定时任务,读取所有数据,进行处理。
|
||||
* 又例如说,读取所有数据,进行缓存。
|
||||
*
|
||||
* <p>
|
||||
* 整体逻辑的实现,和 {@link TenantUtils#executeIgnore(Runnable)} 需要保持一致
|
||||
*
|
||||
* @author yshop
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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); // 情况二,忽略多租户的表
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
/**
|
||||
* 多租户 JobHandler 装饰器
|
||||
* 任务执行时,会按照租户逐个执行 Job 的逻辑
|
||||
*
|
||||
* <p>
|
||||
* 注意,需要保证 JobHandler 的幂等性。因为 Job 因为某个租户执行失败重试时,之前执行成功的租户也会再次执行。
|
||||
*
|
||||
* @author yshop
|
||||
|
@ -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} 中
|
||||
*
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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,则他们会存在冲突的问题
|
||||
*
|
||||
|
@ -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(),
|
||||
|
@ -16,7 +16,7 @@ public class TenantUtils {
|
||||
|
||||
/**
|
||||
* 使用指定租户,执行对应的逻辑
|
||||
*
|
||||
* <p>
|
||||
* 注意,如果当前是忽略租户的情况下,会被强制设置成不忽略租户
|
||||
* 当然,执行完成后,还是会恢复回去
|
||||
*
|
||||
@ -39,7 +39,7 @@ public class TenantUtils {
|
||||
|
||||
/**
|
||||
* 使用指定租户,执行对应的逻辑
|
||||
*
|
||||
* <p>
|
||||
* 注意,如果当前是忽略租户的情况下,会被强制设置成不忽略租户
|
||||
* 当然,执行完成后,还是会恢复回去
|
||||
*
|
||||
|
@ -7,11 +7,10 @@
|
||||
* 5. Job:在 JobHandler 执行任务时,会按照每个租户,都独立并行执行一次。
|
||||
* 6. MQ:在 Producer 发送消息时,Header 带上 tenant-id 租户编号;在 Consumer 消费消息时,将 Header 的 tenant-id 租户编号,添加到租户上下文。
|
||||
* 7. Async:异步需要保证 ThreadLocal 的传递性,通过使用阿里开源的 TransmittableThreadLocal 实现。相关的改造点,可见:
|
||||
* 1)Spring Async:
|
||||
* {@link co.yixiang.yshop.framework.quartz.config.YshopAsyncAutoConfiguration#threadPoolTaskExecutorBeanPostProcessor()}
|
||||
* 2)Spring Security:
|
||||
* TransmittableThreadLocalSecurityContextHolderStrategy
|
||||
* 和 YshopSecurityAutoConfiguration#securityContextHolderMethodInvokingFactoryBean() 方法
|
||||
*
|
||||
* 1)Spring Async:
|
||||
* {@link co.yixiang.yshop.framework.quartz.config.YshopAsyncAutoConfiguration#threadPoolTaskExecutorBeanPostProcessor()}
|
||||
* 2)Spring Security:
|
||||
* TransmittableThreadLocalSecurityContextHolderStrategy
|
||||
* 和 YshopSecurityAutoConfiguration#securityContextHolderMethodInvokingFactoryBean() 方法
|
||||
*/
|
||||
package co.yixiang.yshop.framework.tenant;
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* 脱敏序列化器
|
||||
*
|
||||
* <p>
|
||||
* 实现 JSON 返回数据时,使用 {@link DesensitizationHandler} 对声明脱敏注解的字段,进行脱敏处理。
|
||||
*
|
||||
* @author gaibu
|
||||
|
@ -29,7 +29,7 @@ public @interface EmailDesensitize {
|
||||
|
||||
/**
|
||||
* 替换规则,邮箱;
|
||||
*
|
||||
* <p>
|
||||
* 比如:example@gmail.com 脱敏之后为 e****@gmail.com
|
||||
*/
|
||||
String replacer() default "$1****$2";
|
||||
|
@ -29,7 +29,7 @@ public @interface RegexDesensitize {
|
||||
|
||||
/**
|
||||
* 替换规则,会将匹配到的字符串全部替换成 replacer
|
||||
*
|
||||
* <p>
|
||||
* 例如:regex=123; replacer=******
|
||||
* 原始字符串 123456789
|
||||
* 脱敏后字符串 ******456789
|
||||
|
@ -34,7 +34,7 @@ public @interface PasswordDesensitize {
|
||||
|
||||
/**
|
||||
* 替换规则,密码;
|
||||
*
|
||||
* <p>
|
||||
* 比如:123456 脱敏之后为 ******
|
||||
*/
|
||||
String replacer() default "*";
|
||||
|
@ -29,7 +29,7 @@ public @interface SliderDesensitize {
|
||||
|
||||
/**
|
||||
* 替换规则,会将前缀后缀保留后,全部替换成 replacer
|
||||
*
|
||||
* <p>
|
||||
* 例如:prefixKeep = 1; suffixKeep = 2; replacer = "*";
|
||||
* 原始字符串 123456
|
||||
* 脱敏后 1***56
|
||||
|
@ -13,7 +13,7 @@ import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 地址
|
||||
*
|
||||
* <p>
|
||||
* 用于 {@link DesensitizeTest} 测试使用
|
||||
*
|
||||
* @author gaibu
|
||||
|
@ -6,7 +6,7 @@ import co.yixiang.yshop.framework.desensitize.core.annotation.Address;
|
||||
|
||||
/**
|
||||
* {@link Address} 的脱敏处理器
|
||||
*
|
||||
* <p>
|
||||
* 用于 {@link DesensitizeTest} 测试使用
|
||||
*/
|
||||
public class AddressHandler implements DesensitizationHandler<Address> {
|
||||
|
@ -4,7 +4,7 @@ import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 字典格式化
|
||||
*
|
||||
* <p>
|
||||
* 实现将字典数据的值,格式化成字典数据的标签
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
Reference in New Issue
Block a user