Compare commits
213 Commits
Author | SHA1 | Date |
---|---|---|
sj | a27b0c8deb | 2 years ago |
sj | c424bc0ca8 | 2 years ago |
sj | 010132f237 | 2 years ago |
sj | 91188fe1a0 | 2 years ago |
sj | a5cdf202f1 | 2 years ago |
sj | a30fb508de | 2 years ago |
sj | aa792a10b1 | 2 years ago |
sj | bcdd99eb4a | 2 years ago |
sj | 50c1f73901 | 2 years ago |
sj | 0d93550e43 | 2 years ago |
sj | 3b05b235bc | 2 years ago |
sj | 2fa9950933 | 2 years ago |
sj | 76bd360e92 | 2 years ago |
sj | f459579768 | 2 years ago |
sj | cb388c8e85 | 2 years ago |
sj | b26c158c84 | 2 years ago |
sj | 26f6a38c6b | 2 years ago |
sj | e80ff782e7 | 2 years ago |
sj | 44110bd059 | 2 years ago |
sj | 9bc5869abd | 2 years ago |
sj | 2b25c63f4e | 2 years ago |
sj | 5f259398a2 | 2 years ago |
sj | ddc1cddcb9 | 2 years ago |
sj | a0a6040437 | 2 years ago |
sj | f46f56e5b0 | 2 years ago |
sj | b6a9c87e2a | 2 years ago |
sj | ddb28dc5c8 | 2 years ago |
1304317391@qq.com | 92e2c99b89 | 2 years ago |
1304317391@qq.com | a6cf439160 | 2 years ago |
sj | b0a0785501 | 2 years ago |
sj | a22fa10cb8 | 2 years ago |
sj | 200346ee71 | 2 years ago |
sj | efa1a331bb | 2 years ago |
sj | 49d46c391a | 2 years ago |
Loki | 69c9c00c16 | 2 years ago |
sj | 226518b3a4 | 2 years ago |
sj | e265d9620b | 2 years ago |
sj | 4180aa5567 | 2 years ago |
sj | e7bc4f312a | 2 years ago |
sj | 6d15e1fa32 | 2 years ago |
sj | aa8a171ccc | 2 years ago |
sj | 6e7adc20cb | 2 years ago |
sj | 5bb10fe988 | 2 years ago |
sj | 37acc6ebae | 2 years ago |
sj | ac911e41e1 | 2 years ago |
sj | 4f69fb5d3a | 2 years ago |
sj | 61eb0c7177 | 2 years ago |
sj | 1f07dde9d2 | 2 years ago |
sj | 822d5e8207 | 2 years ago |
sj | 0125a6598c | 2 years ago |
sj | 173a6145af | 2 years ago |
sj | 8d66f53be5 | 2 years ago |
Loki | 0c83d79684 | 2 years ago |
Loki | 91741b3224 | 2 years ago |
Loki | 4a7e7c2595 | 2 years ago |
Loki | 49c3e34b23 | 2 years ago |
Loki | 4686861ad2 | 2 years ago |
zhanyunjiu | 10a6b8fc57 | 2 years ago |
zhanyunjiu | 92a7db0031 | 2 years ago |
zhanyunjiu | 2072a3cbc9 | 2 years ago |
zhanyunjiu | c903ff31e3 | 2 years ago |
zhanyunjiu | 8f96db1483 | 2 years ago |
zhanyunjiu | 13323608a9 | 2 years ago |
zhanyunjiu | 6a88008a51 | 2 years ago |
zhanyunjiu | 0b96c77838 | 2 years ago |
zhanyunjiu | a2e22e1478 | 2 years ago |
zhanyunjiu | 18928deb2e | 3 years ago |
zhanyunjiu | e44e0e662e | 3 years ago |
zhanyunjiu | eaf7faa12b | 3 years ago |
zhanyunjiu | 6b2c8ec70c | 3 years ago |
zhanyunjiu | 126251e113 | 3 years ago |
zhanyunjiu | 04814bbd89 | 3 years ago |
zhanyunjiu | dc52c30581 | 3 years ago |
zhanyunjiu | 32250adc85 | 3 years ago |
zhanyunjiu | afcecc3c73 | 3 years ago |
zhanyunjiu | 333c63bb62 | 3 years ago |
Loki | bc6c88d89d | 3 years ago |
Loki | f1b8d3b47d | 3 years ago |
zhanyunjiu | 4453f13b37 | 3 years ago |
zhanyunjiu | 53316b0b71 | 3 years ago |
zhanyunjiu | 1697bd8fef | 3 years ago |
zhanyunjiu | f034ce1b1a | 3 years ago |
zhanyunjiu | 21a3f1e166 | 3 years ago |
zhanyunjiu | a3555407a1 | 3 years ago |
zhanyunjiu | 711bf01e62 | 3 years ago |
WIN-IDGBLFHC1K6\Administrator | 27ba31bf4f | 3 years ago |
WIN-IDGBLFHC1K6\Administrator | a71bc7d6b2 | 3 years ago |
WIN-IDGBLFHC1K6\Administrator | d4c7fa2fc1 | 3 years ago |
WIN-IDGBLFHC1K6\Administrator | ab09d4a524 | 3 years ago |
WIN-IDGBLFHC1K6\Administrator | 8ec6f213d4 | 3 years ago |
WIN-IDGBLFHC1K6\Administrator | bebca3004d | 3 years ago |
WIN-IDGBLFHC1K6\Administrator | 103837e0f3 | 3 years ago |
WIN-IDGBLFHC1K6\Administrator | 4d011a2a51 | 3 years ago |
WIN-IDGBLFHC1K6\Administrator | 4011874184 | 3 years ago |
Loki | cd55670218 | 3 years ago |
小久哥 | 59c86e3aca | 3 years ago |
小久哥 | f1232e7981 | 3 years ago |
Loki | 4d7af16b05 | 3 years ago |
小久哥 | 510fb3814f | 3 years ago |
小久哥 | 8d89747fe4 | 3 years ago |
小久哥 | 6063523f30 | 3 years ago |
小久哥 | e9fe435aef | 3 years ago |
小久哥 | 1a88fca5b6 | 3 years ago |
小久哥 | 658663c61a | 3 years ago |
小久哥 | e8a5668da4 | 3 years ago |
小久哥 | 7380a37431 | 3 years ago |
小久哥 | cc80a97dba | 3 years ago |
小久哥 | 41dd169a97 | 3 years ago |
Loki | 5dd48e50a0 | 3 years ago |
Loki | f77d753264 | 3 years ago |
小久哥 | fe84dea084 | 3 years ago |
Loki | 8fc86bebff | 3 years ago |
小久哥 | 73a8bf4a35 | 3 years ago |
小久哥 | d662c8dec1 | 3 years ago |
小久哥 | 4e8c2178ba | 3 years ago |
小久哥 | 9e3968cbda | 3 years ago |
小久哥 | 44fee2cf6e | 3 years ago |
小久哥 | 13610a7bb6 | 3 years ago |
小久哥 | f29fa0b508 | 3 years ago |
小久哥 | 79b5eb0836 | 3 years ago |
小久哥 | b36951a4fb | 3 years ago |
小久哥 | 97901204b7 | 3 years ago |
小久哥 | c43bf99629 | 3 years ago |
小久哥 | 0ea7bf55b3 | 3 years ago |
小久哥 | c0e6c171a6 | 3 years ago |
小久哥 | b75d12cb83 | 3 years ago |
小久哥 | 9bc848dd96 | 3 years ago |
小久哥 | d18238dbab | 3 years ago |
小久哥 | 63761c9d3a | 3 years ago |
小久哥 | ca489012f5 | 3 years ago |
小久哥 | 14439a203b | 3 years ago |
小久哥 | 92e340ae09 | 3 years ago |
小久哥 | 3de354c111 | 3 years ago |
小久哥 | e67f42f033 | 3 years ago |
小久哥 | 8589fd38e0 | 3 years ago |
小久哥 | 99eb3bcb7f | 3 years ago |
小久哥 | 09eb23318e | 3 years ago |
小久哥 | f0084754ca | 3 years ago |
小久哥 | cc0c7f374e | 3 years ago |
小久哥 | f42644e836 | 3 years ago |
小久哥 | d4dc0a25c7 | 3 years ago |
小久哥 | b4fc7db6d0 | 3 years ago |
小久哥 | 69a53a5f2a | 3 years ago |
小久哥 | 84c53c545f | 3 years ago |
小久哥 | cbfec821da | 3 years ago |
小久哥 | d26d0a4ae5 | 3 years ago |
小久哥 | 6d9be42340 | 3 years ago |
小久哥 | 71bc4b45dc | 3 years ago |
小久哥 | 35abd199bc | 3 years ago |
小久哥 | e7cc44c502 | 3 years ago |
小久哥 | d96de82d5f | 3 years ago |
小久哥 | 6745fecc6f | 3 years ago |
小久哥 | b188e3dcb9 | 3 years ago |
小久哥 | ccada6c25d | 3 years ago |
小久哥 | 83c78c96dd | 3 years ago |
小久哥 | 2bf333cc90 | 3 years ago |
小久哥 | f51ae91df0 | 3 years ago |
小久哥 | 51a987670c | 3 years ago |
小久哥 | dff81402bb | 3 years ago |
小久哥 | 672f0e7514 | 3 years ago |
小久哥 | a3ff0accb6 | 3 years ago |
小久哥 | c14f984d89 | 3 years ago |
小久哥 | 8503e7a69f | 3 years ago |
Loki | aceb2811ef | 3 years ago |
小久哥 | e3843fdad8 | 3 years ago |
小久哥 | 49c4ba8652 | 3 years ago |
小久哥 | e80a44320a | 3 years ago |
小久哥 | e3098cf8d9 | 3 years ago |
Loki | 7a6f346404 | 3 years ago |
小久哥 | 612e4a428c | 3 years ago |
小久哥 | fbfaea3926 | 3 years ago |
小久哥 | 7ee83372b6 | 3 years ago |
小久哥 | db52846a6c | 3 years ago |
小久哥 | 8105b62737 | 3 years ago |
小久哥 | a2d00e3ab7 | 3 years ago |
Loki | 09b9e92585 | 3 years ago |
小久哥 | 243b9066cf | 3 years ago |
小久哥 | 461e4e6457 | 3 years ago |
小久哥 | e4d90c4252 | 3 years ago |
小久哥 | 4cead507ae | 3 years ago |
Loki | e6b21e3a49 | 3 years ago |
小久哥 | d434b2084f | 3 years ago |
小久哥 | c55aa8f97a | 3 years ago |
Loki | a059ab9e00 | 3 years ago |
小久哥 | 80e0289e4b | 3 years ago |
小久哥 | 66489db865 | 3 years ago |
Loki | 7a1f3c787f | 3 years ago |
小久哥 | 0174e14455 | 3 years ago |
Loki | e01f90088f | 3 years ago |
小久哥 | 9f394d71a1 | 3 years ago |
小久哥 | 1273f011b4 | 3 years ago |
小久哥 | 67eb497114 | 3 years ago |
小久哥 | 54772ded8f | 3 years ago |
小久哥 | 94eb1b7141 | 3 years ago |
小久哥 | 7b742c1701 | 3 years ago |
Loki | 2d23f468df | 3 years ago |
小久哥 | d18ce96c45 | 3 years ago |
小久哥 | 04bed3ba3d | 3 years ago |
小久哥 | 70623c5712 | 3 years ago |
Loki | 73877d675a | 3 years ago |
Loki | e9d29ef2df | 3 years ago |
Loki | 186feb98da | 3 years ago |
Loki | 4d3b8caf21 | 3 years ago |
Loki | a89a69b145 | 3 years ago |
Loki | 50fa31c6ad | 3 years ago |
Loki | b1e3fabea3 | 3 years ago |
小久哥 | ac70ccf30f | 3 years ago |
小久哥 | 211afafeaf | 3 years ago |
Loki | 01ab4d2b4f | 3 years ago |
小久哥 | 1971f3031c | 3 years ago |
小久哥 | a746c1be84 | 3 years ago |
小久哥 | fba23a61e7 | 3 years ago |
小久哥 | 2ab2593f45 | 3 years ago |
2042 changed files with 154071 additions and 36394 deletions
@ -0,0 +1 @@
|
||||
rsync yudao-server/target/yudao-server.jar root@39.105.46.0:/root/project/zen/yudao.jar |
@ -0,0 +1,6 @@
|
||||
{ |
||||
"name": "zsw-farm", |
||||
"lockfileVersion": 2, |
||||
"requires": true, |
||||
"packages": {} |
||||
} |
After Width: | Height: | Size: 29 KiB |
Binary file not shown.
@ -0,0 +1,126 @@
|
||||
/** |
||||
* Copyright (C) 2018-2022 |
||||
* All rights reserved, Designed By www.yixiang.co |
||||
* 注意: |
||||
* 本软件为www.yixiang.co开发研制,未经购买不得使用 |
||||
* 购买后可获得全部源代码(禁止转卖、分享、上传到码云、github等开源平台) |
||||
* 一经发现盗用、分享等行为,将追究法律责任,后果自负 |
||||
*/ |
||||
package cn.iocoder.yudao.framework.common.exception; |
||||
|
||||
|
||||
/** |
||||
* API 响应码 |
||||
* @author hupeng |
||||
* @date 2020-04-30 |
||||
*/ |
||||
public enum ApiCode { |
||||
|
||||
/** |
||||
* 操作成功 |
||||
**/ |
||||
SUCCESS(200, "操作成功"), |
||||
/** |
||||
* 登录状态失效 请重新登录 |
||||
**/ |
||||
UNAUTHORIZED(401, "登录状态失效 请重新登录"), |
||||
/** |
||||
* 没有权限 |
||||
**/ |
||||
NOT_PERMISSION(403, "没有权限"), |
||||
/** |
||||
* 你请求的资源不存在 |
||||
**/ |
||||
NOT_FOUND(404, "你请求的资源不存在"), |
||||
/** |
||||
* 操作失败 |
||||
**/ |
||||
FAIL(500, "操作失败"), |
||||
/** |
||||
* 登录失败 |
||||
**/ |
||||
LOGIN_EXCEPTION(4000, "登录失败"), |
||||
/** |
||||
* 系统异常 |
||||
**/ |
||||
SYSTEM_EXCEPTION(5000, "系统异常"), |
||||
/** |
||||
* 请求参数校验异常 |
||||
**/ |
||||
PARAMETER_EXCEPTION(5001, "请求参数校验异常"), |
||||
/** |
||||
* 请求参数解析异常 |
||||
**/ |
||||
PARAMETER_PARSE_EXCEPTION(5002, "请求参数解析异常"), |
||||
/** |
||||
* HTTP内容类型异常 |
||||
**/ |
||||
HTTP_MEDIA_TYPE_EXCEPTION(5003, "HTTP内容类型异常"), |
||||
/** |
||||
* 系统处理异常 |
||||
**/ |
||||
YSHOP_SYSTEM_EXCEPTION(5100, "系统处理异常"), |
||||
/** |
||||
* 业务处理异常 |
||||
**/ |
||||
BUSINESS_EXCEPTION(5101, "业务处理异常"), |
||||
/** |
||||
* 数据库处理异常 |
||||
**/ |
||||
DAO_EXCEPTION(5102, "数据库处理异常"), |
||||
/** |
||||
* 验证码校验异常 |
||||
**/ |
||||
VERIFICATION_CODE_EXCEPTION(5103, "验证码校验异常"), |
||||
/** |
||||
* 登录授权异常 |
||||
**/ |
||||
AUTHENTICATION_EXCEPTION(5104, "登录授权异常"), |
||||
/** |
||||
* 没有访问权限 |
||||
**/ |
||||
UNAUTHENTICATED_EXCEPTION(5105, "没有访问权限"), |
||||
/** |
||||
* 没有访问权限 |
||||
**/ |
||||
UNAUTHORIZED_EXCEPTION(5106, "没有访问权限"), |
||||
/** |
||||
* JWT Token解析异常 |
||||
**/ |
||||
JWTDECODE_EXCEPTION(5107, "Token解析异常"), |
||||
|
||||
HTTP_REQUEST_METHOD_NOT_SUPPORTED_EXCEPTION(5108, "METHOD NOT SUPPORTED"), |
||||
|
||||
/** |
||||
* 访问次数受限制 |
||||
**/ |
||||
BAD_LIMIT_EXCEPTION(5109, "访问次数受限制"), |
||||
; |
||||
|
||||
private final int code; |
||||
private final String message; |
||||
|
||||
ApiCode(final int code, final String message) { |
||||
this.code = code; |
||||
this.message = message; |
||||
} |
||||
|
||||
public static ApiCode getApiCode(int code) { |
||||
ApiCode[] ecs = ApiCode.values(); |
||||
for (ApiCode ec : ecs) { |
||||
if (ec.getCode() == code) { |
||||
return ec; |
||||
} |
||||
} |
||||
return SUCCESS; |
||||
} |
||||
|
||||
public int getCode() { |
||||
return code; |
||||
} |
||||
|
||||
public String getMessage() { |
||||
return message; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,59 @@
|
||||
/** |
||||
* Copyright (C) 2018-2022 |
||||
* All rights reserved, Designed By www.yixiang.co |
||||
* 注意: |
||||
* 本软件为www.yixiang.co开发研制,未经购买不得使用 |
||||
* 购买后可获得全部源代码(禁止转卖、分享、上传到码云、github等开源平台) |
||||
* 一经发现盗用、分享等行为,将追究法律责任,后果自负 |
||||
*/ |
||||
package cn.iocoder.yudao.framework.common.exception; |
||||
|
||||
|
||||
import lombok.Data; |
||||
import lombok.EqualsAndHashCode; |
||||
|
||||
/** |
||||
* 自定义异常 |
||||
* @author hupeng |
||||
* @date 2020-04-30 |
||||
*/ |
||||
@Data |
||||
@EqualsAndHashCode(callSuper = true) |
||||
public class YshopException extends RuntimeException{ |
||||
|
||||
private static final long serialVersionUID = -2470461654663264392L; |
||||
|
||||
private Integer errorCode; |
||||
private String message; |
||||
|
||||
public YshopException() { |
||||
super(); |
||||
} |
||||
|
||||
public YshopException(String message) { |
||||
super(message); |
||||
this.errorCode = ApiCode.FAIL.getCode(); |
||||
this.message = message; |
||||
} |
||||
|
||||
public YshopException(Integer errorCode, String message) { |
||||
super(message); |
||||
this.errorCode = errorCode; |
||||
this.message = message; |
||||
} |
||||
|
||||
public YshopException(ApiCode apiCode) { |
||||
super(apiCode.getMessage()); |
||||
this.errorCode = apiCode.getCode(); |
||||
this.message = apiCode.getMessage(); |
||||
} |
||||
|
||||
public YshopException(String message, Throwable cause) { |
||||
super(message, cause); |
||||
} |
||||
|
||||
public YshopException(Throwable cause) { |
||||
super(cause); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,23 @@
|
||||
package cn.iocoder.yudao.framework.common.page; |
||||
|
||||
import io.swagger.annotations.ApiModel; |
||||
import io.swagger.annotations.ApiModelProperty; |
||||
import lombok.Data; |
||||
|
||||
import java.io.Serializable; |
||||
|
||||
@Data |
||||
@ApiModel(value = "PageDTO", description = "分页对象") |
||||
public class PageDTO implements Serializable { |
||||
|
||||
private static final long serialVersionUID = 1L; |
||||
|
||||
@ApiModelProperty("页码") |
||||
private Integer pageNum = 1; |
||||
|
||||
@ApiModelProperty("每页数量") |
||||
private Integer pageSize = 10; |
||||
|
||||
@ApiModelProperty("搜索关键字") |
||||
private String searchKey; |
||||
} |
@ -0,0 +1,98 @@
|
||||
package cn.iocoder.yudao.framework.common.page; |
||||
|
||||
import cn.hutool.core.bean.BeanUtil; |
||||
import com.github.pagehelper.PageHelper; |
||||
import com.github.pagehelper.PageInfo; |
||||
import lombok.experimental.UtilityClass; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* 分页工具类 |
||||
* |
||||
* @author xggz <yyimba@qq.com> |
||||
* @since 2021/6/4 11:50 |
||||
*/ |
||||
@UtilityClass |
||||
public class PageUtil<T> { |
||||
|
||||
/** |
||||
* 转换PageHelper插件的分页数据 |
||||
* |
||||
* @param pageInfo |
||||
* @param <T> |
||||
* @return |
||||
*/ |
||||
public <T> PageVO<T> convertPageInfo(PageInfo<T> pageInfo) { |
||||
return BeanUtil.copyProperties(pageInfo, PageVO.class); |
||||
} |
||||
|
||||
/** |
||||
* 转换PageHelper插件的分页数据 |
||||
* |
||||
* @param list |
||||
* @param <T> |
||||
* @return |
||||
*/ |
||||
public <T> PageVO<T> convertPageInfo(List<T> list) { |
||||
return BeanUtil.copyProperties(new PageInfo<T>(list), PageVO.class); |
||||
} |
||||
|
||||
/** |
||||
* 复制分页数据 |
||||
* |
||||
* @param sourcePage |
||||
* @param results |
||||
* @param <T> |
||||
* @return |
||||
*/ |
||||
public <T> PageVO<T> copyPage(Object sourcePage, List<T> results) { |
||||
PageVO<T> targetPage = BeanUtil.copyProperties(sourcePage, PageVO.class); |
||||
targetPage.setList(results); |
||||
return targetPage; |
||||
} |
||||
|
||||
/** |
||||
* 返回空白的分页对象 |
||||
* |
||||
* @param pageNum |
||||
* @param pageSize |
||||
* @param dataClass |
||||
* @param <T> |
||||
* @return |
||||
*/ |
||||
public <T> PageVO<T> emptyPage(Integer pageNum, Integer pageSize, Class<T> dataClass) { |
||||
PageVO page = new PageVO<>(); |
||||
page.setPageNum(pageNum); |
||||
page.setPageSize(pageSize); |
||||
page.setSize(0); |
||||
page.setPages(0); |
||||
page.setTotal(0); |
||||
page.setHasNextPage(false); |
||||
page.setHasPreviousPage(false); |
||||
page.setList(new ArrayList()); |
||||
return page; |
||||
} |
||||
|
||||
/** |
||||
* 返回空白的分页对象 |
||||
* |
||||
* @param pageDTO |
||||
* @param dataClass |
||||
* @param <T> |
||||
* @return |
||||
*/ |
||||
public <T> PageVO<T> emptyPage(PageDTO pageDTO, Class<T> dataClass) { |
||||
return emptyPage(pageDTO.getPageNum(), pageDTO.getPageSize(), dataClass); |
||||
} |
||||
|
||||
/** |
||||
* 使用PageHelper设置分页参数 |
||||
* |
||||
* @param pageDTO |
||||
*/ |
||||
public void startPage(PageDTO pageDTO) { |
||||
PageHelper.startPage(pageDTO.getPageNum(), pageDTO.getPageSize()); |
||||
} |
||||
} |
@ -0,0 +1,45 @@
|
||||
package cn.iocoder.yudao.framework.common.page; |
||||
|
||||
import io.swagger.annotations.ApiModel; |
||||
import io.swagger.annotations.ApiModelProperty; |
||||
import lombok.Data; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* 分页结果 |
||||
* |
||||
* @author xggz <yyimba@qq.com> |
||||
* @since 2021/6/4 10:53 |
||||
*/ |
||||
@Data |
||||
@ApiModel(value = "PageVO", description = "分页结果") |
||||
public class PageVO<T> implements Serializable { |
||||
|
||||
private static final long serialVersionUID = 1L; |
||||
|
||||
@ApiModelProperty("当前页") |
||||
private int pageNum; |
||||
|
||||
@ApiModelProperty("每页的数量") |
||||
private int pageSize; |
||||
|
||||
@ApiModelProperty("当前页的数量") |
||||
private int size; |
||||
|
||||
@ApiModelProperty("总页数") |
||||
private int pages; |
||||
|
||||
@ApiModelProperty("是否有前一页") |
||||
private boolean hasPreviousPage = false; |
||||
|
||||
@ApiModelProperty("是否有后一页") |
||||
private boolean hasNextPage = false; |
||||
|
||||
@ApiModelProperty("总记录数") |
||||
private long total; |
||||
|
||||
@ApiModelProperty("结果集") |
||||
private List<T> list; |
||||
} |
@ -0,0 +1,231 @@
|
||||
/** |
||||
* Copyright (C) 2018-2022 |
||||
* All rights reserved, Designed By www.yixiang.co |
||||
* 注意: |
||||
* 本软件为www.yixiang.co开发研制,未经购买不得使用 |
||||
* 购买后可获得全部源代码(禁止转卖、分享、上传到码云、github等开源平台) |
||||
* 一经发现盗用、分享等行为,将追究法律责任,后果自负 |
||||
*/ |
||||
package cn.iocoder.yudao.framework.common.pojo; |
||||
|
||||
|
||||
import cn.hutool.core.util.StrUtil; |
||||
import cn.iocoder.yudao.framework.common.exception.ApiCode; |
||||
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
import io.swagger.annotations.ApiModelProperty; |
||||
import lombok.AllArgsConstructor; |
||||
import lombok.Builder; |
||||
import lombok.Data; |
||||
import lombok.experimental.Accessors; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.Date; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
|
||||
/** |
||||
* API 返回结果 |
||||
* @author hupeng |
||||
* @date 2020-04-30 |
||||
*/ |
||||
@Data |
||||
@Accessors(chain = true) |
||||
@Builder |
||||
@AllArgsConstructor |
||||
public class ApiResult<T> implements Serializable { |
||||
private static final long serialVersionUID = 8004487252556526569L; |
||||
|
||||
/** |
||||
* 响应码 |
||||
*/ |
||||
@ApiModelProperty(value = "响应码") |
||||
private int status; |
||||
|
||||
/** |
||||
* 是否成功 |
||||
*/ |
||||
@ApiModelProperty(value = "是否成功:成功true,失败false") |
||||
private boolean success; |
||||
|
||||
/** |
||||
* 响应消息 |
||||
*/ |
||||
@ApiModelProperty(value = "响应消息") |
||||
private String msg; |
||||
|
||||
/** |
||||
* 总条数 |
||||
*/ |
||||
@ApiModelProperty(value = "总条数") |
||||
private Integer total; |
||||
|
||||
/** |
||||
* 总页数 |
||||
*/ |
||||
@ApiModelProperty(value = "总页数") |
||||
private Integer totalPage; |
||||
|
||||
/** |
||||
* 响应数据 |
||||
*/ |
||||
@ApiModelProperty(value = "响应数据") |
||||
private T data; |
||||
|
||||
/** |
||||
* 响应时间 |
||||
*/ |
||||
@ApiModelProperty(value = "响应时间") |
||||
//@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8") |
||||
private Date time; |
||||
|
||||
public ApiResult() { |
||||
time = new Date(); |
||||
} |
||||
|
||||
public static ApiResult<Boolean> result(boolean flag){ |
||||
if (flag){ |
||||
return ok(); |
||||
} |
||||
return fail(); |
||||
} |
||||
|
||||
public static ApiResult<Boolean> result(ApiCode apiCode){ |
||||
return result(apiCode,null); |
||||
} |
||||
|
||||
public static <T> ApiResult<T> result(ApiCode apiCode, T data){ |
||||
return result(apiCode,null,data); |
||||
} |
||||
|
||||
public static <T> ApiResult<T> resultPage(Integer total, Integer totalPage, T data){ |
||||
return (ApiResult<T>) ApiResult.builder() |
||||
.total(total) |
||||
.totalPage(totalPage) |
||||
.status(200) |
||||
.msg(null) |
||||
.data(data) |
||||
.success(true) |
||||
.time(new Date()) |
||||
.build(); |
||||
} |
||||
|
||||
|
||||
public static <T> ApiResult<T> result(ApiCode apiCode, String message, T data){ |
||||
boolean success = false; |
||||
if (apiCode.getCode() == ApiCode.SUCCESS.getCode()){ |
||||
success = true; |
||||
} |
||||
if (StrUtil.isBlank(message)){ |
||||
message = apiCode.getMessage(); |
||||
} |
||||
return (ApiResult<T>) ApiResult.builder() |
||||
.status(apiCode.getCode()) |
||||
.msg(message) |
||||
.data(data) |
||||
.success(success) |
||||
.time(new Date()) |
||||
.build(); |
||||
} |
||||
|
||||
public static ApiResult<Boolean> ok(){ |
||||
return ok(null); |
||||
} |
||||
|
||||
public static <T> ApiResult<T> ok(T data){ |
||||
return result(ApiCode.SUCCESS,data); |
||||
} |
||||
|
||||
public static <T> ApiResult<T> ok(T data, String message){ |
||||
return result(ApiCode.SUCCESS,message,data); |
||||
} |
||||
|
||||
public static ApiResult<Map<String,Object>> okMap(String key, Object value){ |
||||
Map<String,Object> map = new HashMap<>(1); |
||||
map.put(key,value); |
||||
return ok(map); |
||||
} |
||||
|
||||
public static ApiResult<Boolean> fail(ApiCode apiCode){ |
||||
return result(apiCode,null); |
||||
} |
||||
|
||||
public static ApiResult<String> fail(String message){ |
||||
return result(ApiCode.FAIL,message,null); |
||||
|
||||
} |
||||
|
||||
public static <T> ApiResult<T> fail(ApiCode apiCode, T data){ |
||||
if (ApiCode.SUCCESS == apiCode){ |
||||
throw new RuntimeException("失败结果状态码不能为" + ApiCode.SUCCESS.getCode()); |
||||
} |
||||
return result(apiCode,data); |
||||
|
||||
} |
||||
|
||||
public static ApiResult<String> fail(Integer errorCode, String message){ |
||||
return new ApiResult<String>() |
||||
.setSuccess(false) |
||||
.setStatus(errorCode) |
||||
.setMsg(message); |
||||
} |
||||
|
||||
public static ApiResult<Map<String,Object>> fail(String key, Object value){ |
||||
Map<String,Object> map = new HashMap<>(1); |
||||
map.put(key,value); |
||||
return result(ApiCode.FAIL,map); |
||||
} |
||||
|
||||
public static <T> ApiResult<T> resultPage(T t, int limit){ |
||||
List<Object> list = (List<Object>) t; |
||||
int count = list.size() / limit; |
||||
if (list.size() == 0) { |
||||
return (ApiResult<T>) ApiResult.builder() |
||||
.total(0) |
||||
.totalPage(0) |
||||
.status(200) |
||||
.msg(null) |
||||
.data(list) |
||||
.success(true) |
||||
.time(new Date()) |
||||
.build(); |
||||
} |
||||
if (list.size() <= limit) { |
||||
return (ApiResult<T>) ApiResult.builder() |
||||
.total(list.size()) |
||||
.totalPage(1) |
||||
.status(200) |
||||
.msg(null) |
||||
.data(list) |
||||
.success(true) |
||||
.time(new Date()) |
||||
.build(); |
||||
} else if (count % limit == 0) { |
||||
return (ApiResult<T>) ApiResult.builder() |
||||
.total(list.size()) |
||||
.totalPage(count) |
||||
.status(200) |
||||
.msg(null) |
||||
.data(list) |
||||
.success(true) |
||||
.time(new Date()) |
||||
.build(); |
||||
} else { |
||||
return (ApiResult<T>) ApiResult.builder() |
||||
.total(list.size()) |
||||
.totalPage(count+1) |
||||
.status(200) |
||||
.msg(null) |
||||
.data(list) |
||||
.success(true) |
||||
.time(new Date()) |
||||
.build(); |
||||
} |
||||
} |
||||
|
||||
public static ApiResult<Boolean> fail() { |
||||
return fail(ApiCode.FAIL); |
||||
} |
||||
} |
@ -0,0 +1,40 @@
|
||||
package cn.iocoder.yudao.config; |
||||
|
||||
import lombok.extern.slf4j.Slf4j; |
||||
import me.chanjar.weixin.cp.api.WxCpService; |
||||
import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; |
||||
import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl; |
||||
import org.springframework.beans.factory.annotation.Value; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.context.annotation.Scope; |
||||
|
||||
@Configuration |
||||
@Slf4j |
||||
public class WxCpConfigure { |
||||
@Value("${wxcp.corpId}") |
||||
private String corpId; |
||||
@Value("${wxcp.secret}") |
||||
private String secret; |
||||
@Value("${wxcp.agentId}") |
||||
private Integer agentId; |
||||
|
||||
@Bean |
||||
@Scope("prototype") |
||||
public WxCpService wxCpService(){ |
||||
|
||||
WxCpDefaultConfigImpl config = new WxCpDefaultConfigImpl(); |
||||
config.setCorpId(corpId); |
||||
config.setCorpSecret(secret); |
||||
config.setAgentId(agentId); |
||||
|
||||
WxCpServiceImpl wxCpService = new WxCpServiceImpl(); |
||||
wxCpService.setWxCpConfigStorage(config); |
||||
|
||||
log.info("企业微信初始化:{}",wxCpService); |
||||
|
||||
return wxCpService; |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,42 @@
|
||||
package cn.iocoder.yudao.config; |
||||
|
||||
|
||||
import cn.binarywang.wx.miniapp.api.WxMaService; |
||||
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; |
||||
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.springframework.beans.factory.annotation.Value; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.context.annotation.Scope; |
||||
import org.springframework.context.annotation.ScopedProxyMode; |
||||
|
||||
|
||||
/** |
||||
* Created by kellen on 2020/5/3. 微信小程序服务配置 |
||||
*/ |
||||
@Configuration |
||||
@Slf4j |
||||
public class WxMaConfiguration { |
||||
|
||||
@Value("${wxma.app_id}") |
||||
private String appId; |
||||
@Value("${wxma.app_secret}") |
||||
private String appSecret; |
||||
|
||||
@Bean |
||||
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS) |
||||
public WxMaService wxMaService() { |
||||
|
||||
WxMaDefaultConfigImpl wxMaDefaultConfig = new WxMaDefaultConfigImpl(); |
||||
wxMaDefaultConfig.setAppid(appId); |
||||
wxMaDefaultConfig.setSecret(appSecret); |
||||
|
||||
WxMaServiceImpl wxMaService = new WxMaServiceImpl(); |
||||
wxMaService.setWxMaConfig(wxMaDefaultConfig); |
||||
|
||||
return wxMaService; |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,3 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ |
||||
cn.iocoder.yudao.config.WxCpConfigure,\ |
||||
cn.iocoder.yudao.config.WxMaConfiguration |
@ -0,0 +1,69 @@
|
||||
package cn.iocoder.yudao.framework.quartz.config; |
||||
|
||||
import org.springframework.beans.factory.ObjectProvider; |
||||
import org.springframework.beans.factory.annotation.Qualifier; |
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; |
||||
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.quartz.*; |
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
||||
import org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.context.annotation.Import; |
||||
import org.springframework.core.annotation.Order; |
||||
import org.springframework.core.io.ResourceLoader; |
||||
import org.springframework.transaction.PlatformTransactionManager; |
||||
import org.springframework.transaction.TransactionManager; |
||||
|
||||
import javax.sql.DataSource; |
||||
@Configuration |
||||
@ConditionalOnProperty(prefix = "spring.quartz", name = "job-store-type", havingValue = "jdbc") |
||||
@Import(DatabaseInitializationDependencyConfigurer.class) |
||||
@EnableConfigurationProperties(QuartzProperties.class) |
||||
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, |
||||
LiquibaseAutoConfiguration.class, FlywayAutoConfiguration.class }) |
||||
public class JdbcStoreTypeConfiguration { |
||||
|
||||
|
||||
@Bean |
||||
@Order(0) |
||||
public SchedulerFactoryBeanCustomizer dataSourceCustomizer(QuartzProperties properties, |
||||
DataSource dataSource, |
||||
@QuartzDataSource ObjectProvider<DataSource> quartzDataSource, |
||||
TransactionManager transactionManager |
||||
) { |
||||
return (schedulerFactoryBean) -> { |
||||
DataSource dataSourceToUse = getDataSource(dataSource, quartzDataSource); |
||||
schedulerFactoryBean.setDataSource(dataSourceToUse); |
||||
schedulerFactoryBean.setTransactionManager((PlatformTransactionManager) transactionManager); |
||||
}; |
||||
} |
||||
|
||||
private DataSource getDataSource(DataSource dataSource, ObjectProvider<DataSource> quartzDataSource) { |
||||
DataSource dataSourceIfAvailable = quartzDataSource.getIfAvailable(); |
||||
return (dataSourceIfAvailable != null) ? dataSourceIfAvailable : dataSource; |
||||
} |
||||
|
||||
private PlatformTransactionManager getTransactionManager( |
||||
ObjectProvider<PlatformTransactionManager> transactionManager, |
||||
ObjectProvider<PlatformTransactionManager> quartzTransactionManager) { |
||||
PlatformTransactionManager transactionManagerIfAvailable = quartzTransactionManager.getIfAvailable(); |
||||
return (transactionManagerIfAvailable != null) ? transactionManagerIfAvailable |
||||
: transactionManager.getIfUnique(); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean |
||||
public QuartzDataSourceInitializer quartzDataSourceInitializer(DataSource dataSource, |
||||
@QuartzDataSource ObjectProvider<DataSource> quartzDataSource, ResourceLoader resourceLoader, |
||||
QuartzProperties properties) { |
||||
DataSource dataSourceToUse = getDataSource(dataSource, quartzDataSource); |
||||
return new QuartzDataSourceInitializer(dataSourceToUse, resourceLoader, properties); |
||||
} |
||||
} |
@ -1,3 +1,4 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ |
||||
cn.iocoder.yudao.framework.quartz.config.YudaoQuartzAutoConfiguration,\ |
||||
cn.iocoder.yudao.framework.quartz.config.YudaoAsyncAutoConfiguration |
||||
cn.iocoder.yudao.framework.quartz.config.YudaoAsyncAutoConfiguration,\ |
||||
cn.iocoder.yudao.framework.quartz.config.JdbcStoreTypeConfiguration |
||||
|
@ -0,0 +1,39 @@
|
||||
package cn.iocoder.yudao.framework.mybatis.core.dataobject; |
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill; |
||||
import com.baomidou.mybatisplus.annotation.TableField; |
||||
import com.baomidou.mybatisplus.annotation.TableLogic; |
||||
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
import com.fasterxml.jackson.annotation.JsonIgnore; |
||||
import lombok.Getter; |
||||
import lombok.Setter; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.Date; |
||||
|
||||
|
||||
/** |
||||
* @ClassName 公共模型 |
||||
* @Author hupeng <610796224@qq.com> |
||||
* @Date 2020/6/13 |
||||
**/ |
||||
@Getter |
||||
@Setter |
||||
public class BaseDomain implements Serializable { |
||||
|
||||
private static final long serialVersionUID = 1L; |
||||
|
||||
|
||||
@TableField(fill= FieldFill.INSERT) |
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8") |
||||
private Date createTime; |
||||
|
||||
@TableField(fill= FieldFill.UPDATE) |
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8") |
||||
private Date updateTime; |
||||
|
||||
@TableLogic |
||||
@JsonIgnore |
||||
@TableField(fill= FieldFill.INSERT) |
||||
private Integer isDel; |
||||
} |
@ -0,0 +1,68 @@
|
||||
package cn.iocoder.yudao.framework.mybatis.core.handler; |
||||
|
||||
import cn.hutool.core.util.ObjectUtil; |
||||
import cn.hutool.json.JSONUtil; |
||||
import com.fasterxml.jackson.core.JsonProcessingException; |
||||
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
import com.fasterxml.jackson.databind.type.CollectionType; |
||||
import org.apache.ibatis.type.BaseTypeHandler; |
||||
import org.apache.ibatis.type.JdbcType; |
||||
import org.apache.ibatis.type.MappedJdbcTypes; |
||||
import org.apache.ibatis.type.MappedTypes; |
||||
|
||||
|
||||
import java.sql.CallableStatement; |
||||
import java.sql.PreparedStatement; |
||||
import java.sql.ResultSet; |
||||
import java.sql.SQLException; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* zyj |
||||
*/ |
||||
@MappedJdbcTypes(JdbcType.VARCHAR) // 数据库中该字段存储的类型
|
||||
@MappedTypes(List.class) // 需要转换的对象
|
||||
public class ListIntToListLongTypeHandler extends BaseTypeHandler<List<Long>> { |
||||
|
||||
private static ObjectMapper mObjectMapper = new ObjectMapper(); |
||||
|
||||
@Override |
||||
public void setNonNullParameter(PreparedStatement preparedStatement, int i, List<Long> longs, JdbcType jdbcType) throws SQLException { |
||||
String json = JSONUtil.toJsonStr(longs); |
||||
preparedStatement.setObject(i, json); |
||||
} |
||||
|
||||
@Override |
||||
public List<Long> getNullableResult(ResultSet resultSet, String columnName) throws SQLException { |
||||
String value = resultSet.getString(columnName); |
||||
return getLongs(value); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public List<Long> getNullableResult(ResultSet resultSet, int i) throws SQLException { |
||||
String value = resultSet.getString(i); |
||||
return getLongs(value); |
||||
} |
||||
|
||||
@Override |
||||
public List<Long> getNullableResult(CallableStatement callableStatement, int i) throws SQLException { |
||||
String value = callableStatement.getString(i); |
||||
return getLongs(value); |
||||
} |
||||
|
||||
private List<Long> getLongs(String value) { |
||||
if (ObjectUtil.isNotEmpty(value)) { |
||||
try { |
||||
CollectionType type = mObjectMapper.getTypeFactory().constructCollectionType(ArrayList.class, Long.class); |
||||
List<Long> longs = mObjectMapper.readValue(value , type); |
||||
return longs; |
||||
} catch (JsonProcessingException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
} |
||||
|
@ -0,0 +1,26 @@
|
||||
/** |
||||
* Copyright (C) 2018-2022 |
||||
* All rights reserved, Designed By www.yixiang.co |
||||
* 注意: |
||||
* 本软件为www.yixiang.co开发研制,未经购买不得使用 |
||||
* 购买后可获得全部源代码(禁止转卖、分享、上传到码云、github等开源平台) |
||||
* 一经发现盗用、分享等行为,将追究法律责任,后果自负 |
||||
*/ |
||||
package cn.iocoder.yudao.framework.security.core.annotations; |
||||
|
||||
|
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
/** |
||||
* @ClassName 自定义权限注解 |
||||
* @Author hupeng <610796224@qq.com> |
||||
* @Date 2020/4/30 |
||||
**/ |
||||
@Target({ElementType.METHOD, ElementType.TYPE}) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
public @interface AuthCheck { |
||||
int value() default 4; |
||||
} |
@ -0,0 +1,17 @@
|
||||
package cn.iocoder.yudao.module.member.controller.app.weixin; |
||||
|
||||
import me.chanjar.weixin.mp.api.WxMpService; |
||||
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
|
||||
@Configuration |
||||
public class TestConfigure { |
||||
|
||||
@Bean |
||||
public WxMpService wxMpService(){ |
||||
WxMpService wxMpService = new WxMpServiceImpl(); |
||||
return wxMpService; |
||||
} |
||||
|
||||
} |
@ -1,137 +1,137 @@
|
||||
package cn.iocoder.yudao.module.member.service.user; |
||||
|
||||
import cn.hutool.core.util.RandomUtil; |
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
||||
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; |
||||
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; |
||||
import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest; |
||||
import cn.iocoder.yudao.module.infra.api.file.FileApi; |
||||
import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO; |
||||
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; |
||||
import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper; |
||||
import cn.iocoder.yudao.module.member.service.auth.MemberAuthServiceImpl; |
||||
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; |
||||
import org.junit.jupiter.api.Test; |
||||
import org.springframework.boot.test.mock.mockito.MockBean; |
||||
import org.springframework.context.annotation.Import; |
||||
import org.springframework.data.redis.core.StringRedisTemplate; |
||||
import org.springframework.security.crypto.password.PasswordEncoder; |
||||
|
||||
import javax.annotation.Resource; |
||||
import java.io.ByteArrayInputStream; |
||||
import java.util.function.Consumer; |
||||
|
||||
import static cn.hutool.core.util.RandomUtil.*; |
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; |
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; |
||||
import static org.junit.jupiter.api.Assertions.assertEquals; |
||||
import static org.mockito.Mockito.eq; |
||||
import static org.mockito.Mockito.when; |
||||
|
||||
// TODO @芋艿:单测的 review,等逻辑都达成一致后
|
||||
/** |
||||
* {@link MemberUserServiceImpl} 的单元测试类 |
||||
* |
||||
* @author 宋天 |
||||
*/ |
||||
@Import({MemberUserServiceImpl.class, YudaoRedisAutoConfiguration.class}) |
||||
public class MemberUserServiceImplTest extends BaseDbAndRedisUnitTest { |
||||
|
||||
@Resource |
||||
private MemberUserServiceImpl memberUserService; |
||||
|
||||
@Resource |
||||
private StringRedisTemplate stringRedisTemplate; |
||||
|
||||
@Resource |
||||
private MemberUserMapper userMapper; |
||||
|
||||
@MockBean |
||||
private MemberAuthServiceImpl authService; |
||||
|
||||
@MockBean |
||||
private PasswordEncoder passwordEncoder; |
||||
|
||||
@MockBean |
||||
private SmsCodeApi smsCodeApi; |
||||
@MockBean |
||||
private FileApi fileApi; |
||||
|
||||
@Test |
||||
public void testUpdateNickName_success(){ |
||||
// mock 数据
|
||||
MemberUserDO userDO = randomUserDO(); |
||||
userMapper.insert(userDO); |
||||
|
||||
// 随机昵称
|
||||
String newNickName = randomString(); |
||||
|
||||
// 调用接口修改昵称
|
||||
memberUserService.updateUserNickname(userDO.getId(),newNickName); |
||||
// 查询新修改后的昵称
|
||||
String nickname = memberUserService.getUser(userDO.getId()).getNickname(); |
||||
// 断言
|
||||
assertEquals(newNickName,nickname); |
||||
} |
||||
|
||||
@Test |
||||
public void testUpdateAvatar_success() throws Exception { |
||||
// mock 数据
|
||||
MemberUserDO dbUser = randomUserDO(); |
||||
userMapper.insert(dbUser); |
||||
|
||||
// 准备参数
|
||||
Long userId = dbUser.getId(); |
||||
byte[] avatarFileBytes = randomBytes(10); |
||||
ByteArrayInputStream avatarFile = new ByteArrayInputStream(avatarFileBytes); |
||||
// mock 方法
|
||||
String avatar = randomString(); |
||||
when(fileApi.createFile(eq(avatarFileBytes))).thenReturn(avatar); |
||||
// 调用
|
||||
String str = memberUserService.updateUserAvatar(userId, avatarFile); |
||||
// 断言
|
||||
assertEquals(avatar, str); |
||||
} |
||||
|
||||
@Test |
||||
public void updateMobile_success(){ |
||||
// mock数据
|
||||
String oldMobile = randomNumbers(11); |
||||
MemberUserDO userDO = randomUserDO(); |
||||
userDO.setMobile(oldMobile); |
||||
userMapper.insert(userDO); |
||||
|
||||
// TODO 芋艿:需要修复该单元测试,重构多模块带来的
|
||||
// 旧手机和旧验证码
|
||||
// SmsCodeDO codeDO = new SmsCodeDO();
|
||||
String oldCode = RandomUtil.randomString(4); |
||||
// codeDO.setMobile(userDO.getMobile());
|
||||
// codeDO.setCode(oldCode);
|
||||
// codeDO.setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene());
|
||||
// codeDO.setUsed(Boolean.FALSE);
|
||||
// when(smsCodeService.checkCodeIsExpired(codeDO.getMobile(),codeDO.getCode(),codeDO.getScene())).thenReturn(codeDO);
|
||||
|
||||
// 更新手机号
|
||||
String newMobile = randomNumbers(11); |
||||
String newCode = randomNumbers(4); |
||||
AppUserUpdateMobileReqVO reqVO = new AppUserUpdateMobileReqVO(); |
||||
reqVO.setMobile(newMobile); |
||||
reqVO.setCode(newCode); |
||||
reqVO.setOldMobile(oldMobile); |
||||
reqVO.setOldCode(oldCode); |
||||
memberUserService.updateUserMobile(userDO.getId(),reqVO); |
||||
|
||||
assertEquals(memberUserService.getUser(userDO.getId()).getMobile(),newMobile); |
||||
} |
||||
|
||||
// ========== 随机对象 ==========
|
||||
|
||||
@SafeVarargs |
||||
private static MemberUserDO randomUserDO(Consumer<MemberUserDO>... consumers) { |
||||
Consumer<MemberUserDO> consumer = (o) -> { |
||||
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
|
||||
}; |
||||
return randomPojo(MemberUserDO.class, ArrayUtils.append(consumer, consumers)); |
||||
} |
||||
|
||||
} |
||||
//package cn.iocoder.yudao.module.member.service.user;
|
||||
//
|
||||
//import cn.hutool.core.util.RandomUtil;
|
||||
//import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
//import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
||||
//import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
|
||||
//import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest;
|
||||
//import cn.iocoder.yudao.module.infra.api.file.FileApi;
|
||||
//import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO;
|
||||
//import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
|
||||
//import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
|
||||
//import cn.iocoder.yudao.module.member.service.auth.MemberAuthServiceImpl;
|
||||
//import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
|
||||
//import org.junit.jupiter.api.Test;
|
||||
//import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
//import org.springframework.context.annotation.Import;
|
||||
//import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
//import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
//
|
||||
//import javax.annotation.Resource;
|
||||
//import java.io.ByteArrayInputStream;
|
||||
//import java.util.function.Consumer;
|
||||
//
|
||||
//import static cn.hutool.core.util.RandomUtil.*;
|
||||
//import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||
//import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
|
||||
//import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
//import static org.mockito.Mockito.eq;
|
||||
//import static org.mockito.Mockito.when;
|
||||
//
|
||||
//// TODO @芋艿:单测的 review,等逻辑都达成一致后
|
||||
///**
|
||||
// * {@link MemberUserServiceImpl} 的单元测试类
|
||||
// *
|
||||
// * @author 宋天
|
||||
// */
|
||||
//@Import({MemberUserServiceImpl.class, YudaoRedisAutoConfiguration.class})
|
||||
//public class MemberUserServiceImplTest extends BaseDbAndRedisUnitTest {
|
||||
//
|
||||
// @Resource
|
||||
// private MemberUserServiceImpl memberUserService;
|
||||
//
|
||||
// @Resource
|
||||
// private StringRedisTemplate stringRedisTemplate;
|
||||
//
|
||||
// @Resource
|
||||
// private MemberUserMapper userMapper;
|
||||
//
|
||||
// @MockBean
|
||||
// private MemberAuthServiceImpl authService;
|
||||
//
|
||||
// @MockBean
|
||||
// private PasswordEncoder passwordEncoder;
|
||||
//
|
||||
// @MockBean
|
||||
// private SmsCodeApi smsCodeApi;
|
||||
// @MockBean
|
||||
// private FileApi fileApi;
|
||||
//
|
||||
// @Test
|
||||
// public void testUpdateNickName_success(){
|
||||
// // mock 数据
|
||||
// MemberUserDO userDO = randomUserDO();
|
||||
// userMapper.insert(userDO);
|
||||
//
|
||||
// // 随机昵称
|
||||
// String newNickName = randomString();
|
||||
//
|
||||
// // 调用接口修改昵称
|
||||
// memberUserService.updateUserNickname(userDO.getId(),newNickName);
|
||||
// // 查询新修改后的昵称
|
||||
// String nickname = memberUserService.getUser(userDO.getId()).getNickname();
|
||||
// // 断言
|
||||
// assertEquals(newNickName,nickname);
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testUpdateAvatar_success() throws Exception {
|
||||
// // mock 数据
|
||||
// MemberUserDO dbUser = randomUserDO();
|
||||
// userMapper.insert(dbUser);
|
||||
//
|
||||
// // 准备参数
|
||||
// Long userId = dbUser.getId();
|
||||
// byte[] avatarFileBytes = randomBytes(10);
|
||||
// ByteArrayInputStream avatarFile = new ByteArrayInputStream(avatarFileBytes);
|
||||
// // mock 方法
|
||||
// String avatar = randomString();
|
||||
// when(fileApi.createFile(eq(avatarFileBytes))).thenReturn(avatar);
|
||||
// // 调用
|
||||
// String str = memberUserService.updateUserAvatar(userId, avatarFile);
|
||||
// // 断言
|
||||
// assertEquals(avatar, str);
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void updateMobile_success(){
|
||||
// // mock数据
|
||||
// String oldMobile = randomNumbers(11);
|
||||
// MemberUserDO userDO = randomUserDO();
|
||||
// userDO.setMobile(oldMobile);
|
||||
// userMapper.insert(userDO);
|
||||
//
|
||||
// // TODO 芋艿:需要修复该单元测试,重构多模块带来的
|
||||
// // 旧手机和旧验证码
|
||||
//// SmsCodeDO codeDO = new SmsCodeDO();
|
||||
// String oldCode = RandomUtil.randomString(4);
|
||||
//// codeDO.setMobile(userDO.getMobile());
|
||||
//// codeDO.setCode(oldCode);
|
||||
//// codeDO.setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene());
|
||||
//// codeDO.setUsed(Boolean.FALSE);
|
||||
//// when(smsCodeService.checkCodeIsExpired(codeDO.getMobile(),codeDO.getCode(),codeDO.getScene())).thenReturn(codeDO);
|
||||
//
|
||||
// // 更新手机号
|
||||
// String newMobile = randomNumbers(11);
|
||||
// String newCode = randomNumbers(4);
|
||||
// AppUserUpdateMobileReqVO reqVO = new AppUserUpdateMobileReqVO();
|
||||
// reqVO.setMobile(newMobile);
|
||||
// reqVO.setCode(newCode);
|
||||
// reqVO.setOldMobile(oldMobile);
|
||||
// reqVO.setOldCode(oldCode);
|
||||
// memberUserService.updateUserMobile(userDO.getId(),reqVO);
|
||||
//
|
||||
// assertEquals(memberUserService.getUser(userDO.getId()).getMobile(),newMobile);
|
||||
// }
|
||||
//
|
||||
// // ========== 随机对象 ==========
|
||||
//
|
||||
// @SafeVarargs
|
||||
// private static MemberUserDO randomUserDO(Consumer<MemberUserDO>... consumers) {
|
||||
// Consumer<MemberUserDO> consumer = (o) -> {
|
||||
// o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
|
||||
// };
|
||||
// return randomPojo(MemberUserDO.class, ArrayUtils.append(consumer, consumers));
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
@ -0,0 +1,15 @@
|
||||
package cn.iocoder.yudao.module.system.enums.wxcp; |
||||
|
||||
import lombok.AllArgsConstructor; |
||||
import lombok.Getter; |
||||
|
||||
@Getter |
||||
@AllArgsConstructor |
||||
public enum WxCpMsgTypeEnum { |
||||
|
||||
project, |
||||
|
||||
task; |
||||
|
||||
|
||||
} |
@ -0,0 +1,100 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.CpUser; |
||||
|
||||
import org.springframework.web.bind.annotation.*; |
||||
import javax.annotation.Resource; |
||||
import org.springframework.validation.annotation.Validated; |
||||
import org.springframework.security.access.prepost.PreAuthorize; |
||||
import io.swagger.annotations.*; |
||||
|
||||
import javax.validation.constraints.*; |
||||
import javax.validation.*; |
||||
import javax.servlet.http.*; |
||||
import java.util.*; |
||||
import java.io.IOException; |
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult; |
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
||||
|
||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
||||
|
||||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
||||
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*; |
||||
|
||||
import cn.iocoder.yudao.module.system.controller.admin.CpUser.vo.*; |
||||
import cn.iocoder.yudao.module.system.dal.dataobject.CpUser.CpUserDO; |
||||
import cn.iocoder.yudao.module.system.convert.CpUser.CpUserConvert; |
||||
import cn.iocoder.yudao.module.system.service.CpUser.CpUserService; |
||||
|
||||
@Api(tags = "管理后台 - 企业微信成员") |
||||
@RestController |
||||
@RequestMapping("/system/cp-user") |
||||
@Validated |
||||
public class CpUserController { |
||||
|
||||
@Resource |
||||
private CpUserService cpUserService; |
||||
|
||||
@PostMapping("/create") |
||||
@ApiOperation("创建企业微信成员") |
||||
@PreAuthorize("@ss.hasPermission('system:cp-user:create')") |
||||
public CommonResult<Long> createCpUser(@Valid @RequestBody CpUserCreateReqVO createReqVO) { |
||||
return success(cpUserService.createCpUser(createReqVO)); |
||||
} |
||||
|
||||
@PutMapping("/update") |
||||
@ApiOperation("更新企业微信成员") |
||||
@PreAuthorize("@ss.hasPermission('system:cp-user:update')") |
||||
public CommonResult<Boolean> updateCpUser(@Valid @RequestBody CpUserUpdateReqVO updateReqVO) { |
||||
cpUserService.updateCpUser(updateReqVO); |
||||
return success(true); |
||||
} |
||||
|
||||
@DeleteMapping("/delete") |
||||
@ApiOperation("删除企业微信成员") |
||||
@ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) |
||||
@PreAuthorize("@ss.hasPermission('system:cp-user:delete')") |
||||
public CommonResult<Boolean> deleteCpUser(@RequestParam("id") Long id) { |
||||
cpUserService.deleteCpUser(id); |
||||
return success(true); |
||||
} |
||||
|
||||
@GetMapping("/get") |
||||
@ApiOperation("获得企业微信成员") |
||||
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) |
||||
@PreAuthorize("@ss.hasPermission('system:cp-user:query')") |
||||
public CommonResult<CpUserRespVO> getCpUser(@RequestParam("id") Long id) { |
||||
CpUserDO cpUser = cpUserService.getCpUser(id); |
||||
return success(CpUserConvert.INSTANCE.convert(cpUser)); |
||||
} |
||||
|
||||
@GetMapping("/list") |
||||
@ApiOperation("获得企业微信成员列表") |
||||
@ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class) |
||||
@PreAuthorize("@ss.hasPermission('system:cp-user:query')") |
||||
public CommonResult<List<CpUserRespVO>> getCpUserList(@RequestParam("ids") Collection<Long> ids) { |
||||
List<CpUserDO> list = cpUserService.getCpUserList(ids); |
||||
return success(CpUserConvert.INSTANCE.convertList(list)); |
||||
} |
||||
|
||||
@GetMapping("/page") |
||||
@ApiOperation("获得企业微信成员分页") |
||||
@PreAuthorize("@ss.hasPermission('system:cp-user:query')") |
||||
public CommonResult<PageResult<CpUserRespVO>> getCpUserPage(@Valid CpUserPageReqVO pageVO) { |
||||
PageResult<CpUserDO> pageResult = cpUserService.getCpUserPage(pageVO); |
||||
return success(CpUserConvert.INSTANCE.convertPage(pageResult)); |
||||
} |
||||
|
||||
@GetMapping("/export-excel") |
||||
@ApiOperation("导出企业微信成员 Excel") |
||||
@PreAuthorize("@ss.hasPermission('system:cp-user:export')") |
||||
@OperateLog(type = EXPORT) |
||||
public void exportCpUserExcel(@Valid CpUserExportReqVO exportReqVO, |
||||
HttpServletResponse response) throws IOException { |
||||
List<CpUserDO> list = cpUserService.getCpUserList(exportReqVO); |
||||
// 导出 Excel
|
||||
List<CpUserExcelVO> datas = CpUserConvert.INSTANCE.convertList02(list); |
||||
ExcelUtils.write(response, "企业微信成员.xls", "数据", CpUserExcelVO.class, datas); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,44 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.CpUser.dto; |
||||
|
||||
import cn.iocoder.yudao.module.system.enums.wxcp.WxCpMsgTypeEnum; |
||||
import io.swagger.annotations.ApiModel; |
||||
import lombok.AllArgsConstructor; |
||||
import lombok.Builder; |
||||
import lombok.Data; |
||||
import lombok.NoArgsConstructor; |
||||
|
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
@Data |
||||
@ApiModel("企业微信发送推送消息") |
||||
@Builder |
||||
@AllArgsConstructor |
||||
@NoArgsConstructor |
||||
public class CpMessageDto { |
||||
|
||||
private WxCpMsgTypeEnum typeEnum; |
||||
|
||||
private Long id; |
||||
|
||||
// 标题
|
||||
private String title; |
||||
|
||||
// 子标题
|
||||
private String description; |
||||
private Map<String,String> contentItems; |
||||
|
||||
// 是否放大第一对item
|
||||
private Boolean emphasisFirstItem; |
||||
|
||||
/** |
||||
* 用于微信消息推送的 - 模板ID 不一定适用于企业微信 |
||||
*/ |
||||
private String templateId; |
||||
|
||||
/** |
||||
* 接收人userid |
||||
*/ |
||||
private List<String> reciveIds; |
||||
|
||||
} |
@ -0,0 +1,49 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.CpUser.vo; |
||||
|
||||
import lombok.*; |
||||
import java.util.*; |
||||
import io.swagger.annotations.*; |
||||
import javax.validation.constraints.*; |
||||
|
||||
/** |
||||
* 企业微信成员 Base VO,提供给添加、修改、详细的子 VO 使用 |
||||
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 |
||||
*/ |
||||
@Data |
||||
public class CpUserBaseVO { |
||||
|
||||
@ApiModelProperty(value = "用户昵称", required = true) |
||||
@NotNull(message = "用户昵称不能为空") |
||||
private String userid; |
||||
|
||||
@ApiModelProperty(value = "头像", required = true) |
||||
@NotNull(message = "头像不能为空") |
||||
private String avatar; |
||||
|
||||
@ApiModelProperty(value = "状态", required = true) |
||||
@NotNull(message = "状态不能为空") |
||||
private Integer status; |
||||
|
||||
@ApiModelProperty(value = "手机号", required = true) |
||||
@NotNull(message = "手机号不能为空") |
||||
private String mobile; |
||||
|
||||
@ApiModelProperty(value = "姓名") |
||||
private String name; |
||||
|
||||
@ApiModelProperty(value = "部门") |
||||
private Object department; |
||||
|
||||
@ApiModelProperty(value = "职位") |
||||
private String position; |
||||
|
||||
@ApiModelProperty(value = "邮件") |
||||
private String email; |
||||
|
||||
@ApiModelProperty(value = "企业邮件") |
||||
private String bizMail; |
||||
|
||||
@ApiModelProperty(value = "工时") |
||||
private Integer workHour; |
||||
|
||||
} |
@ -0,0 +1,14 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.CpUser.vo; |
||||
|
||||
import lombok.*; |
||||
import java.util.*; |
||||
import io.swagger.annotations.*; |
||||
import javax.validation.constraints.*; |
||||
|
||||
@ApiModel("管理后台 - 企业微信成员创建 Request VO") |
||||
@Data |
||||
@EqualsAndHashCode(callSuper = true) |
||||
@ToString(callSuper = true) |
||||
public class CpUserCreateReqVO extends CpUserBaseVO { |
||||
|
||||
} |
@ -0,0 +1,53 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.CpUser.vo; |
||||
|
||||
import lombok.*; |
||||
import java.util.*; |
||||
import io.swagger.annotations.*; |
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty; |
||||
|
||||
/** |
||||
* 企业微信成员 Excel VO |
||||
* |
||||
* @author 系统管理员 |
||||
*/ |
||||
@Data |
||||
public class CpUserExcelVO { |
||||
|
||||
@ExcelProperty("编号") |
||||
private Long id; |
||||
|
||||
@ExcelProperty("用户昵称") |
||||
private String userid; |
||||
|
||||
@ExcelProperty("头像") |
||||
private String avatar; |
||||
|
||||
@ExcelProperty("状态") |
||||
private Integer status; |
||||
|
||||
@ExcelProperty("手机号") |
||||
private String mobile; |
||||
|
||||
@ExcelProperty("创建时间") |
||||
private Date createTime; |
||||
|
||||
@ExcelProperty("姓名") |
||||
private String name; |
||||
|
||||
@ExcelProperty("部门") |
||||
private Object department; |
||||
|
||||
@ExcelProperty("职位") |
||||
private String position; |
||||
|
||||
@ExcelProperty("邮件") |
||||
private String email; |
||||
|
||||
@ExcelProperty("企业邮件") |
||||
private String bizMail; |
||||
|
||||
@ApiModelProperty(value = "工时") |
||||
private Integer workHour; |
||||
|
||||
} |
@ -0,0 +1,52 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.CpUser.vo; |
||||
|
||||
import lombok.*; |
||||
import java.util.*; |
||||
import io.swagger.annotations.*; |
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam; |
||||
import org.springframework.format.annotation.DateTimeFormat; |
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
||||
|
||||
@ApiModel(value = "管理后台 - 企业微信成员 Excel 导出 Request VO", description = "参数和 CpUserPageReqVO 是一致的") |
||||
@Data |
||||
public class CpUserExportReqVO { |
||||
|
||||
@ApiModelProperty(value = "用户昵称") |
||||
private String userid; |
||||
|
||||
@ApiModelProperty(value = "头像") |
||||
private String avatar; |
||||
|
||||
@ApiModelProperty(value = "状态") |
||||
private Integer status; |
||||
|
||||
@ApiModelProperty(value = "手机号") |
||||
private String mobile; |
||||
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
||||
@ApiModelProperty(value = "开始创建时间") |
||||
private Date beginCreateTime; |
||||
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
||||
@ApiModelProperty(value = "结束创建时间") |
||||
private Date endCreateTime; |
||||
|
||||
@ApiModelProperty(value = "姓名") |
||||
private String name; |
||||
|
||||
@ApiModelProperty(value = "部门") |
||||
private Object department; |
||||
|
||||
@ApiModelProperty(value = "职位") |
||||
private String position; |
||||
|
||||
@ApiModelProperty(value = "邮件") |
||||
private String email; |
||||
|
||||
@ApiModelProperty(value = "企业邮件") |
||||
private String bizMail; |
||||
|
||||
@ApiModelProperty(value = "工时") |
||||
private Integer workHour; |
||||
} |
@ -0,0 +1,54 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.CpUser.vo; |
||||
|
||||
import lombok.*; |
||||
import java.util.*; |
||||
import io.swagger.annotations.*; |
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam; |
||||
import org.springframework.format.annotation.DateTimeFormat; |
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
||||
|
||||
@ApiModel("管理后台 - 企业微信成员分页 Request VO") |
||||
@Data |
||||
@EqualsAndHashCode(callSuper = true) |
||||
@ToString(callSuper = true) |
||||
public class CpUserPageReqVO extends PageParam { |
||||
|
||||
@ApiModelProperty(value = "用户昵称") |
||||
private String userid; |
||||
|
||||
@ApiModelProperty(value = "头像") |
||||
private String avatar; |
||||
|
||||
@ApiModelProperty(value = "状态") |
||||
private Integer status; |
||||
|
||||
@ApiModelProperty(value = "手机号") |
||||
private String mobile; |
||||
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
||||
@ApiModelProperty(value = "开始创建时间") |
||||
private Date beginCreateTime; |
||||
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
||||
@ApiModelProperty(value = "结束创建时间") |
||||
private Date endCreateTime; |
||||
|
||||
@ApiModelProperty(value = "姓名") |
||||
private String name; |
||||
|
||||
@ApiModelProperty(value = "部门") |
||||
private Object department; |
||||
|
||||
@ApiModelProperty(value = "职位") |
||||
private String position; |
||||
|
||||
@ApiModelProperty(value = "邮件") |
||||
private String email; |
||||
|
||||
@ApiModelProperty(value = "企业邮件") |
||||
private String bizMail; |
||||
|
||||
@ApiModelProperty(value = "工时") |
||||
private Integer workHour; |
||||
} |
@ -0,0 +1,19 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.CpUser.vo; |
||||
|
||||
import lombok.*; |
||||
import java.util.*; |
||||
import io.swagger.annotations.*; |
||||
|
||||
@ApiModel("管理后台 - 企业微信成员 Response VO") |
||||
@Data |
||||
@EqualsAndHashCode(callSuper = true) |
||||
@ToString(callSuper = true) |
||||
public class CpUserRespVO extends CpUserBaseVO { |
||||
|
||||
@ApiModelProperty(value = "编号", required = true) |
||||
private Long id; |
||||
|
||||
@ApiModelProperty(value = "创建时间", required = true) |
||||
private Date createTime; |
||||
|
||||
} |
@ -0,0 +1,18 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.CpUser.vo; |
||||
|
||||
import lombok.*; |
||||
import java.util.*; |
||||
import io.swagger.annotations.*; |
||||
import javax.validation.constraints.*; |
||||
|
||||
@ApiModel("管理后台 - 企业微信成员更新 Request VO") |
||||
@Data |
||||
@EqualsAndHashCode(callSuper = true) |
||||
@ToString(callSuper = true) |
||||
public class CpUserUpdateReqVO extends CpUserBaseVO { |
||||
|
||||
@ApiModelProperty(value = "编号", required = true) |
||||
@NotNull(message = "编号不能为空") |
||||
private Long id; |
||||
|
||||
} |
@ -0,0 +1,15 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.auth.param; |
||||
|
||||
import lombok.Data; |
||||
|
||||
import javax.validation.constraints.NotEmpty; |
||||
|
||||
@Data |
||||
public class WxCpLoginDto { |
||||
|
||||
@NotEmpty(message = "CODE不能为空") |
||||
private String code; |
||||
|
||||
private String platform; |
||||
|
||||
} |
@ -0,0 +1,37 @@
|
||||
package cn.iocoder.yudao.module.system.convert.CpUser; |
||||
|
||||
import java.util.*; |
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult; |
||||
|
||||
import me.chanjar.weixin.cp.bean.WxCpUser; |
||||
import org.mapstruct.Mapper; |
||||
import org.mapstruct.factory.Mappers; |
||||
import cn.iocoder.yudao.module.system.controller.admin.CpUser.vo.*; |
||||
import cn.iocoder.yudao.module.system.dal.dataobject.CpUser.CpUserDO; |
||||
|
||||
/** |
||||
* 企业微信成员 Convert |
||||
* |
||||
* @author 系统管理员 |
||||
*/ |
||||
@Mapper |
||||
public interface CpUserConvert { |
||||
|
||||
CpUserConvert INSTANCE = Mappers.getMapper(CpUserConvert.class); |
||||
|
||||
CpUserDO convert(CpUserCreateReqVO bean); |
||||
|
||||
CpUserDO convert(CpUserUpdateReqVO bean); |
||||
|
||||
CpUserRespVO convert(CpUserDO bean); |
||||
|
||||
List<CpUserRespVO> convertList(List<CpUserDO> list); |
||||
|
||||
PageResult<CpUserRespVO> convertPage(PageResult<CpUserDO> page); |
||||
|
||||
List<CpUserExcelVO> convertList02(List<CpUserDO> list); |
||||
|
||||
List<CpUserDO> convertListFromWxApi(List<WxCpUser> list); |
||||
|
||||
} |
@ -0,0 +1,67 @@
|
||||
package cn.iocoder.yudao.module.system.dal.dataobject.CpUser; |
||||
|
||||
import lombok.*; |
||||
import java.util.*; |
||||
import com.baomidou.mybatisplus.annotation.*; |
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
||||
|
||||
/** |
||||
* 企业微信成员 DO |
||||
* |
||||
* @author 系统管理员 |
||||
*/ |
||||
@TableName("wxcp_users") |
||||
@Data |
||||
@EqualsAndHashCode(callSuper = true) |
||||
@ToString(callSuper = true) |
||||
@Builder |
||||
@NoArgsConstructor |
||||
@AllArgsConstructor |
||||
public class CpUserDO extends BaseDO { |
||||
|
||||
/** |
||||
* 编号 |
||||
*/ |
||||
@TableId |
||||
private Long id; |
||||
/** |
||||
* 用户昵称 |
||||
*/ |
||||
@TableField(value = "user_id") |
||||
private String userId; |
||||
/** |
||||
* 头像 |
||||
*/ |
||||
private String avatar; |
||||
/** |
||||
* 状态 |
||||
*/ |
||||
private Integer status; |
||||
/** |
||||
* 手机号 |
||||
*/ |
||||
private String mobile; |
||||
/** |
||||
* 姓名 |
||||
*/ |
||||
private String name; |
||||
/** |
||||
* 部门 |
||||
*/ |
||||
private Object department; |
||||
/** |
||||
* 职位 |
||||
*/ |
||||
private String position; |
||||
/** |
||||
* 邮件 |
||||
*/ |
||||
private String email; |
||||
/** |
||||
* 企业邮件 |
||||
*/ |
||||
private String bizMail; |
||||
|
||||
private Integer workHour; |
||||
|
||||
} |
@ -0,0 +1,50 @@
|
||||
package cn.iocoder.yudao.module.system.dal.mysql.CpUser; |
||||
|
||||
import java.util.*; |
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult; |
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
||||
import cn.iocoder.yudao.module.system.dal.dataobject.CpUser.CpUserDO; |
||||
import org.apache.ibatis.annotations.Mapper; |
||||
import cn.iocoder.yudao.module.system.controller.admin.CpUser.vo.*; |
||||
|
||||
/** |
||||
* 企业微信成员 Mapper |
||||
* |
||||
* @author 系统管理员 |
||||
*/ |
||||
@Mapper |
||||
public interface CpUserMapper extends BaseMapperX<CpUserDO> { |
||||
|
||||
default PageResult<CpUserDO> selectPage(CpUserPageReqVO reqVO) { |
||||
return selectPage(reqVO, new LambdaQueryWrapperX<CpUserDO>() |
||||
.eqIfPresent(CpUserDO::getUserId, reqVO.getUserid()) |
||||
.eqIfPresent(CpUserDO::getAvatar, reqVO.getAvatar()) |
||||
.eqIfPresent(CpUserDO::getStatus, reqVO.getStatus()) |
||||
.eqIfPresent(CpUserDO::getMobile, reqVO.getMobile()) |
||||
.betweenIfPresent(CpUserDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) |
||||
.likeIfPresent(CpUserDO::getName, reqVO.getName()) |
||||
.eqIfPresent(CpUserDO::getDepartment, reqVO.getDepartment()) |
||||
.eqIfPresent(CpUserDO::getPosition, reqVO.getPosition()) |
||||
.eqIfPresent(CpUserDO::getEmail, reqVO.getEmail()) |
||||
.eqIfPresent(CpUserDO::getBizMail, reqVO.getBizMail()) |
||||
.orderByDesc(CpUserDO::getId)); |
||||
} |
||||
|
||||
default List<CpUserDO> selectList(CpUserExportReqVO reqVO) { |
||||
return selectList(new LambdaQueryWrapperX<CpUserDO>() |
||||
.eqIfPresent(CpUserDO::getUserId, reqVO.getUserid()) |
||||
.eqIfPresent(CpUserDO::getAvatar, reqVO.getAvatar()) |
||||
.eqIfPresent(CpUserDO::getStatus, reqVO.getStatus()) |
||||
.eqIfPresent(CpUserDO::getMobile, reqVO.getMobile()) |
||||
.betweenIfPresent(CpUserDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) |
||||
.likeIfPresent(CpUserDO::getName, reqVO.getName()) |
||||
.eqIfPresent(CpUserDO::getDepartment, reqVO.getDepartment()) |
||||
.eqIfPresent(CpUserDO::getPosition, reqVO.getPosition()) |
||||
.eqIfPresent(CpUserDO::getEmail, reqVO.getEmail()) |
||||
.eqIfPresent(CpUserDO::getBizMail, reqVO.getBizMail()) |
||||
.orderByDesc(CpUserDO::getId)); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,15 @@
|
||||
package cn.iocoder.yudao.module.system.dal.mysql.dict; |
||||
|
||||
import cn.iocoder.yudao.module.system.dict.DictModel; |
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||
import org.apache.ibatis.annotations.Mapper; |
||||
import org.apache.ibatis.annotations.Param; |
||||
|
||||
import java.util.List; |
||||
|
||||
@Mapper |
||||
public interface DictMapper extends BaseMapper<DictModel> { |
||||
|
||||
List<DictModel> queryTableDictByKeysAndFilterSql(@Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("filterSql") String filterSql, @Param("codeValues") List<String> codeValues); |
||||
|
||||
} |
@ -0,0 +1,43 @@
|
||||
package cn.iocoder.yudao.module.system.dict; |
||||
|
||||
|
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
/** |
||||
* 字典注解 |
||||
* @author: dangzhenghui |
||||
* @date: 2019年03月17日-下午9:37:16 |
||||
*/ |
||||
@Target(ElementType.FIELD) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
public @interface Dict { |
||||
/** |
||||
* 方法描述: 数据code |
||||
* 作 者: dangzhenghui |
||||
* 日 期: 2019年03月17日-下午9:37:16 |
||||
* |
||||
* @return 返回类型: String |
||||
*/ |
||||
String dicCode(); |
||||
|
||||
/** |
||||
* 方法描述: 数据Text |
||||
* 作 者: dangzhenghui |
||||
* 日 期: 2019年03月17日-下午9:37:16 |
||||
* |
||||
* @return 返回类型: String |
||||
*/ |
||||
String dicText() default ""; |
||||
|
||||
/** |
||||
* 方法描述: 数据字典表 |
||||
* 作 者: dangzhenghui |
||||
* 日 期: 2019年03月17日-下午9:37:16 |
||||
* |
||||
* @return 返回类型: String |
||||
*/ |
||||
String dictTable() default ""; |
||||
} |
@ -0,0 +1,327 @@
|
||||
package cn.iocoder.yudao.module.system.dict; |
||||
|
||||
import cn.hutool.core.util.ObjectUtil; |
||||
import cn.hutool.json.JSONUtil; |
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult; |
||||
import cn.iocoder.yudao.module.system.service.dict.DictDataService; |
||||
import com.alibaba.druid.support.json.JSONUtils; |
||||
import com.alibaba.fastjson.JSON; |
||||
import com.alibaba.fastjson.JSONObject; |
||||
import com.alibaba.fastjson.parser.Feature; |
||||
import com.fasterxml.jackson.core.JsonProcessingException; |
||||
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.aspectj.lang.ProceedingJoinPoint; |
||||
import org.aspectj.lang.annotation.Around; |
||||
import org.aspectj.lang.annotation.Aspect; |
||||
import org.aspectj.lang.annotation.Pointcut; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.context.annotation.Lazy; |
||||
import org.springframework.data.redis.core.RedisTemplate; |
||||
import org.springframework.stereotype.Component; |
||||
import org.springframework.util.StringUtils; |
||||
|
||||
import java.lang.reflect.Field; |
||||
import java.util.*; |
||||
import java.util.concurrent.TimeUnit; |
||||
import java.util.stream.Collectors; |
||||
|
||||
/** |
||||
* @Description: 字典aop类 |
||||
* @Author: dangzhenghui |
||||
* @Date: 2019-3-17 21:50 |
||||
* @Version: 1.0 |
||||
*/ |
||||
@Aspect |
||||
@Component |
||||
@Slf4j |
||||
public class DictAspect { |
||||
|
||||
@Autowired |
||||
private DictDataService dictDataService; |
||||
@Autowired |
||||
public RedisTemplate redisTemplate; |
||||
|
||||
public static final String DICT_TEXT_SUFFIX = "_dictText"; |
||||
|
||||
/** |
||||
* 定义切点Pointcut |
||||
*/ |
||||
@Pointcut("execution(public * cn.iocoder.yudao.module.*.controller..*.*Controller.*(..))") |
||||
public void excudeService() { |
||||
} |
||||
|
||||
@Around("excudeService()") |
||||
public Object doAround(ProceedingJoinPoint pjp) throws Throwable { |
||||
long time1=System.currentTimeMillis(); |
||||
Object result = pjp.proceed(); |
||||
long time2=System.currentTimeMillis(); |
||||
log.debug("获取JSON数据 耗时:"+(time2-time1)+"ms"); |
||||
long start=System.currentTimeMillis(); |
||||
this.parseDictText(result); |
||||
long end=System.currentTimeMillis(); |
||||
log.debug("注入字典到JSON数据 耗时"+(end-start)+"ms"); |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 本方法针对返回对象为Result 的IPage的分页列表数据进行动态字典注入 |
||||
* 字典注入实现 通过对实体类添加注解@dict 来标识需要的字典内容,字典分为单字典code即可 ,table字典 code table text配合使用与原来jeecg的用法相同 |
||||
* 示例为SysUser 字段为sex 添加了注解@Dict(dicCode = "sex") 会在字典服务立马查出来对应的text 然后在请求list的时候将这个字典text,已字段名称加_dictText形式返回到前端 |
||||
* 例输入当前返回值的就会多出一个sex_dictText字段 |
||||
* { |
||||
* sex:1, |
||||
* sex_dictText:"男" |
||||
* } |
||||
* 前端直接取值sext_dictText在table里面无需再进行前端的字典转换了 |
||||
* customRender:function (text) { |
||||
* if(text==1){ |
||||
* return "男"; |
||||
* }else if(text==2){ |
||||
* return "女"; |
||||
* }else{ |
||||
* return text; |
||||
* } |
||||
* } |
||||
* 目前vue是这么进行字典渲染到table上的多了就很麻烦了 这个直接在服务端渲染完成前端可以直接用 |
||||
* @param result |
||||
*/ |
||||
private void parseDictText(Object result) { |
||||
if (result instanceof CommonResult) { |
||||
if (((CommonResult) result).getData() instanceof PageResult) { |
||||
List<JSONObject> items = new ArrayList<>(); |
||||
|
||||
//step.1 筛选出加了 Dict 注解的字段列表
|
||||
List<Field> dictFieldList = new ArrayList<>(); |
||||
// 字典数据列表, key = 字典code,value=数据列表
|
||||
Map<String, List<String>> dataListMap = new HashMap<>(5); |
||||
|
||||
for (Object record : ((PageResult) ((CommonResult) result).getData()).getList()) { |
||||
ObjectMapper mapper = new ObjectMapper(); |
||||
// 1String json="{}";
|
||||
String json = JSONUtil.toJsonStr(record); |
||||
|
||||
// try {
|
||||
// //解决@JsonFormat注解解析不了的问题详见SysAnnouncement类的@JsonFormat
|
||||
// json = mapper.writeValueAsString(record);
|
||||
// } catch (JsonProcessingException e) {
|
||||
// log.error("json解析失败"+e.getMessage(),e);
|
||||
// }
|
||||
//update-begin--Author:scott -- Date:20211223 ----for:【issues/3303】restcontroller返回json数据后key顺序错乱 -----
|
||||
JSONObject item = JSONObject.parseObject(json, Feature.OrderedField); |
||||
//update-end--Author:scott -- Date:20211223 ----for:【issues/3303】restcontroller返回json数据后key顺序错乱 -----
|
||||
|
||||
//update-begin--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------
|
||||
//for (Field field : record.getClass().getDeclaredFields()) {
|
||||
// 遍历所有字段,把字典Code取出来,放到 map 里
|
||||
for (Field field : getAllFields(record)) { |
||||
String value = item.getString(field.getName()); |
||||
if (ObjectUtil.isEmpty(value)) { |
||||
continue; |
||||
} |
||||
//update-end--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------
|
||||
if (field.getAnnotation(Dict.class) != null) { |
||||
if (!dictFieldList.contains(field)) { |
||||
dictFieldList.add(field); |
||||
} |
||||
String code = field.getAnnotation(Dict.class).dicCode(); |
||||
String text = field.getAnnotation(Dict.class).dicText(); |
||||
String table = field.getAnnotation(Dict.class).dictTable(); |
||||
|
||||
List<String> dataList; |
||||
String dictCode = code; |
||||
if (!StringUtils.isEmpty(table)) { |
||||
dictCode = String.format("%s,%s,%s", table, text, code); |
||||
} |
||||
dataList = dataListMap.computeIfAbsent(dictCode, k -> new ArrayList<>()); |
||||
this.listAddAllDeduplicate(dataList, Arrays.asList(value.split(","))); |
||||
} |
||||
//date类型默认转换string格式化日期
|
||||
// if (CommonConstant.JAVA_UTIL_DATE.equals(field.getType().getName())&&field.getAnnotation(JsonFormat.class)==null&&item.get(field.getName())!=null){
|
||||
// SimpleDateFormat aDate=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
// item.put(field.getName(), aDate.format(new Date((Long) item.get(field.getName()))));
|
||||
// }
|
||||
} |
||||
items.add(item); |
||||
} |
||||
|
||||
//step.2 调用翻译方法,一次性翻译
|
||||
Map<String, List<DictModel>> translText = this.translateAllDict(dataListMap); |
||||
|
||||
//step.3 将翻译结果填充到返回结果里
|
||||
for (JSONObject record : items) { |
||||
for (Field field : dictFieldList) { |
||||
String code = field.getAnnotation(Dict.class).dicCode(); |
||||
String text = field.getAnnotation(Dict.class).dicText(); |
||||
String table = field.getAnnotation(Dict.class).dictTable(); |
||||
|
||||
String fieldDictCode = code; |
||||
if (!StringUtils.isEmpty(table)) { |
||||
fieldDictCode = String.format("%s,%s,%s", table, text, code); |
||||
} |
||||
|
||||
String value = record.getString(field.getName()); |
||||
if (ObjectUtil.isNotEmpty(value)) { |
||||
List<DictModel> dictModels = translText.get(fieldDictCode); |
||||
if(dictModels==null || dictModels.size()==0){ |
||||
continue; |
||||
} |
||||
|
||||
String textValue = this.translDictText(dictModels, value); |
||||
log.debug(" 字典Val : " + textValue); |
||||
log.debug(" __翻译字典字段__ " + field.getName() + DICT_TEXT_SUFFIX + ": " + textValue); |
||||
|
||||
// TODO-sun 测试输出,待删
|
||||
log.debug(" ---- dictCode: " + fieldDictCode); |
||||
log.debug(" ---- value: " + value); |
||||
log.debug(" ----- text: " + textValue); |
||||
log.debug(" ---- dictModels: " + JSON.toJSONString(dictModels)); |
||||
|
||||
record.put(field.getName() + DICT_TEXT_SUFFIX, textValue); |
||||
} |
||||
} |
||||
} |
||||
|
||||
((PageResult)((CommonResult) result).getData()).setList(items); |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* list 去重添加 |
||||
*/ |
||||
private void listAddAllDeduplicate(List<String> dataList, List<String> addList) { |
||||
// 筛选出dataList中没有的数据
|
||||
List<String> filterList = addList.stream().filter(i -> !dataList.contains(i)).collect(Collectors.toList()); |
||||
dataList.addAll(filterList); |
||||
} |
||||
|
||||
/** |
||||
* 一次性把所有的字典都翻译了 |
||||
* 1. 所有的普通数据字典的所有数据只执行一次SQL |
||||
* 2. 表字典相同的所有数据只执行一次SQL |
||||
* @param dataListMap |
||||
* @return |
||||
*/ |
||||
private Map<String, List<DictModel>> translateAllDict(Map<String, List<String>> dataListMap) { |
||||
// 翻译后的字典文本,key=dictCode
|
||||
Map<String, List<DictModel>> translText = new HashMap<>(5); |
||||
// 需要翻译的数据(有些可以从redis缓存中获取,就不走数据库查询)
|
||||
List<String> needTranslData = new ArrayList<>(); |
||||
//step.1 先通过redis中获取缓存字典数据
|
||||
for (String dictCode : dataListMap.keySet()) { |
||||
List<String> dataList = dataListMap.get(dictCode); |
||||
if (dataList.size() == 0) { |
||||
continue; |
||||
} |
||||
// 表字典需要翻译的数据
|
||||
List<String> needTranslDataTable = new ArrayList<>(); |
||||
for (String s : dataList) { |
||||
String data = s.trim(); |
||||
if (data.length() == 0) { |
||||
continue; //跳过循环
|
||||
} |
||||
if (dictCode.contains(",")) { |
||||
String keyString = String.format("sys:cache:dictTable::SimpleKey [%s,%s]", dictCode, data); |
||||
if (redisTemplate.hasKey(keyString)) { |
||||
try { |
||||
String text = redisTemplate.opsForValue().get(keyString).toString(); |
||||
List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>()); |
||||
list.add(new DictModel(data, text)); |
||||
} catch (Exception e) { |
||||
log.warn(e.getMessage()); |
||||
} |
||||
} else if (!needTranslDataTable.contains(data)) { |
||||
// 去重添加
|
||||
needTranslDataTable.add(data); |
||||
} |
||||
} else { |
||||
String keyString = String.format("sys:cache:dict::%s:%s", dictCode, data); |
||||
if (redisTemplate.hasKey(keyString)) { |
||||
try { |
||||
String text = redisTemplate.opsForValue().get(keyString).toString(); |
||||
List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>()); |
||||
list.add(new DictModel(data, text)); |
||||
} catch (Exception e) { |
||||
log.warn(e.getMessage()); |
||||
} |
||||
} else if (!needTranslData.contains(data)) { |
||||
// 去重添加
|
||||
needTranslData.add(data); |
||||
} |
||||
} |
||||
|
||||
} |
||||
//step.2 调用数据库翻译表字典
|
||||
if (needTranslDataTable.size() > 0) { |
||||
String[] arr = dictCode.split(","); |
||||
String table = arr[0], text = arr[1], code = arr[2]; |
||||
String values = String.join(",", needTranslDataTable); |
||||
log.info("translateDictFromTableByKeys.dictCode:" + dictCode); |
||||
log.info("translateDictFromTableByKeys.values:" + values); |
||||
List<DictModel> texts = dictDataService.queryTableDictTextByKeys(table,text,code,needTranslDataTable); |
||||
log.info("translateDictFromTableByKeys.result:" + texts); |
||||
List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>()); |
||||
list.addAll(texts); |
||||
|
||||
// 做 redis 缓存
|
||||
for (DictModel dict : texts) { |
||||
String redisKey = String.format("sys:cache:dictTable::SimpleKey [%s,%s]", dictCode, dict.getValue()); |
||||
try { |
||||
// update-begin-author:taoyan date:20211012 for: 字典表翻译注解缓存未更新 issues/3061
|
||||
// 保留5分钟
|
||||
redisTemplate.opsForValue().set(redisKey, dict.getText(), 300, TimeUnit.SECONDS); |
||||
// update-end-author:taoyan date:20211012 for: 字典表翻译注解缓存未更新 issues/3061
|
||||
} catch (Exception e) { |
||||
log.warn(e.getMessage(), e); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
//step.3 调用数据库进行翻译普通字典
|
||||
return translText; |
||||
} |
||||
|
||||
/** |
||||
* 字典值替换文本 |
||||
* |
||||
* @param dictModels |
||||
* @param values |
||||
* @return |
||||
*/ |
||||
private String translDictText(List<DictModel> dictModels, String values) { |
||||
List<String> result = new ArrayList<>(); |
||||
|
||||
// 允许多个逗号分隔,允许传数组对象
|
||||
String[] splitVal = values.split(","); |
||||
for (String val : splitVal) { |
||||
String dictText = val; |
||||
for (DictModel dict : dictModels) { |
||||
if (val.equals(dict.getValue())) { |
||||
dictText = dict.getText(); |
||||
break; |
||||
} |
||||
} |
||||
result.add(dictText); |
||||
} |
||||
return String.join(",", result); |
||||
} |
||||
|
||||
|
||||
|
||||
public static Field[] getAllFields(Object object) { |
||||
Class<?> clazz = object.getClass(); |
||||
List<Field> fieldList = new ArrayList<>(); |
||||
while (clazz != null) { |
||||
fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()))); |
||||
clazz = clazz.getSuperclass(); |
||||
} |
||||
Field[] fields = new Field[fieldList.size()]; |
||||
fieldList.toArray(fields); |
||||
return fields; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,52 @@
|
||||
package cn.iocoder.yudao.module.system.dict; |
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
||||
import lombok.Data; |
||||
import lombok.EqualsAndHashCode; |
||||
import lombok.experimental.Accessors; |
||||
|
||||
import java.io.Serializable; |
||||
|
||||
/** |
||||
* @Description: 字典类 |
||||
* @author: jeecg-boot |
||||
*/ |
||||
@Data |
||||
@EqualsAndHashCode(callSuper = false) |
||||
@Accessors(chain = true) |
||||
@JsonIgnoreProperties(ignoreUnknown = true) |
||||
public class DictModel implements Serializable{ |
||||
private static final long serialVersionUID = 1L; |
||||
|
||||
public DictModel() { |
||||
} |
||||
|
||||
public DictModel(String value, String text) { |
||||
this.value = value; |
||||
this.text = text; |
||||
} |
||||
|
||||
/** |
||||
* 字典value |
||||
*/ |
||||
private String value; |
||||
/** |
||||
* 字典文本 |
||||
*/ |
||||
private String text; |
||||
|
||||
/** |
||||
* 特殊用途: JgEditableTable |
||||
* @return |
||||
*/ |
||||
public String getTitle() { |
||||
return this.text; |
||||
} |
||||
/** |
||||
* 特殊用途: vue3 Select组件 |
||||
*/ |
||||
public String getLabel() { |
||||
return this.text; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,25 @@
|
||||
package cn.iocoder.yudao.module.system.job.cpuser; |
||||
|
||||
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; |
||||
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; |
||||
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; |
||||
import cn.iocoder.yudao.module.system.service.CpUser.CpUserService; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.springframework.stereotype.Component; |
||||
|
||||
import javax.annotation.Resource; |
||||
|
||||
@Component |
||||
@Slf4j |
||||
public class CpWeixinUserSyncJob implements JobHandler { |
||||
|
||||
@Resource |
||||
private CpUserService cpUserService; |
||||
|
||||
@Override |
||||
public String execute(String param) throws Exception { |
||||
TenantContextHolder.setTenantId(1L); |
||||
cpUserService.cpUserSync(); |
||||
return "企业微信同步完成..."; |
||||
} |
||||
} |
@ -0,0 +1,79 @@
|
||||
package cn.iocoder.yudao.module.system.service.CpUser; |
||||
|
||||
import java.util.*; |
||||
import javax.validation.*; |
||||
|
||||
import cn.iocoder.yudao.module.system.controller.admin.CpUser.dto.CpMessageDto; |
||||
import cn.iocoder.yudao.module.system.controller.admin.CpUser.vo.*; |
||||
import cn.iocoder.yudao.module.system.dal.dataobject.CpUser.CpUserDO; |
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult; |
||||
import com.baomidou.mybatisplus.extension.service.IService; |
||||
import me.chanjar.weixin.common.error.WxErrorException; |
||||
|
||||
/** |
||||
* 企业微信成员 Service 接口 |
||||
* |
||||
* @author 系统管理员 |
||||
*/ |
||||
public interface CpUserService extends IService<CpUserDO> { |
||||
|
||||
/** |
||||
* 创建企业微信成员 |
||||
* |
||||
* @param createReqVO 创建信息 |
||||
* @return 编号 |
||||
*/ |
||||
Long createCpUser(@Valid CpUserCreateReqVO createReqVO); |
||||
|
||||
/** |
||||
* 更新企业微信成员 |
||||
* |
||||
* @param updateReqVO 更新信息 |
||||
*/ |
||||
void updateCpUser(@Valid CpUserUpdateReqVO updateReqVO); |
||||
|
||||
/** |
||||
* 删除企业微信成员 |
||||
* |
||||
* @param id 编号 |
||||
*/ |
||||
void deleteCpUser(Long id); |
||||
|
||||
/** |
||||
* 获得企业微信成员 |
||||
* |
||||
* @param id 编号 |
||||
* @return 企业微信成员 |
||||
*/ |
||||
CpUserDO getCpUser(Long id); |
||||
|
||||
CpUserDO getByUserId(String userId); |
||||
|
||||
/** |
||||
* 获得企业微信成员列表 |
||||
* |
||||
* @param ids 编号 |
||||
* @return 企业微信成员列表 |
||||
*/ |
||||
List<CpUserDO> getCpUserList(Collection<Long> ids); |
||||
|
||||
/** |
||||
* 获得企业微信成员分页 |
||||
* |
||||
* @param pageReqVO 分页查询 |
||||
* @return 企业微信成员分页 |
||||
*/ |
||||
PageResult<CpUserDO> getCpUserPage(CpUserPageReqVO pageReqVO); |
||||
|
||||
/** |
||||
* 获得企业微信成员列表, 用于 Excel 导出 |
||||
* |
||||
* @param exportReqVO 查询条件 |
||||
* @return 企业微信成员列表 |
||||
*/ |
||||
List<CpUserDO> getCpUserList(CpUserExportReqVO exportReqVO); |
||||
|
||||
void cpUserSync() throws WxErrorException; |
||||
|
||||
void sendMessage(CpMessageDto cpMessage) throws WxErrorException; |
||||
} |
@ -0,0 +1,164 @@
|
||||
package cn.iocoder.yudao.module.system.service.CpUser; |
||||
|
||||
import cn.hutool.core.util.ObjectUtil; |
||||
import cn.hutool.core.util.StrUtil; |
||||
import cn.iocoder.yudao.module.system.controller.admin.CpUser.dto.CpMessageDto; |
||||
import cn.iocoder.yudao.module.system.enums.wxcp.WxCpMsgTypeEnum; |
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import me.chanjar.weixin.common.error.WxErrorException; |
||||
import me.chanjar.weixin.cp.api.WxCpService; |
||||
import me.chanjar.weixin.cp.bean.WxCpDepart; |
||||
import me.chanjar.weixin.cp.bean.WxCpUser; |
||||
import me.chanjar.weixin.cp.bean.message.WxCpMessage; |
||||
import me.chanjar.weixin.cp.config.WxCpConfigStorage; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.stereotype.Service; |
||||
|
||||
import javax.annotation.Resource; |
||||
import org.springframework.validation.annotation.Validated; |
||||
|
||||
import java.util.*; |
||||
import java.util.stream.Collectors; |
||||
|
||||
import cn.iocoder.yudao.module.system.controller.admin.CpUser.vo.*; |
||||
import cn.iocoder.yudao.module.system.dal.dataobject.CpUser.CpUserDO; |
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult; |
||||
|
||||
import cn.iocoder.yudao.module.system.convert.CpUser.CpUserConvert; |
||||
import cn.iocoder.yudao.module.system.dal.mysql.CpUser.CpUserMapper; |
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; |
||||
|
||||
/** |
||||
* 企业微信成员 Service 实现类 |
||||
* |
||||
* @author 系统管理员 |
||||
*/ |
||||
@Service |
||||
@Validated |
||||
@Slf4j |
||||
public class CpUserServiceImpl extends ServiceImpl<CpUserMapper,CpUserDO> implements CpUserService { |
||||
|
||||
@Resource |
||||
private CpUserMapper cpUserMapper; |
||||
|
||||
@Autowired |
||||
private WxCpService wxCpService; |
||||
|
||||
|
||||
@Override |
||||
public Long createCpUser(CpUserCreateReqVO createReqVO) { |
||||
// 插入
|
||||
CpUserDO cpUser = CpUserConvert.INSTANCE.convert(createReqVO); |
||||
cpUserMapper.insert(cpUser); |
||||
// 返回
|
||||
return cpUser.getId(); |
||||
} |
||||
|
||||
@Override |
||||
public void updateCpUser(CpUserUpdateReqVO updateReqVO) { |
||||
// 校验存在
|
||||
this.validateCpUserExists(updateReqVO.getId()); |
||||
// 更新
|
||||
CpUserDO updateObj = CpUserConvert.INSTANCE.convert(updateReqVO); |
||||
cpUserMapper.updateById(updateObj); |
||||
} |
||||
|
||||
@Override |
||||
public void deleteCpUser(Long id) { |
||||
// 校验存在
|
||||
this.validateCpUserExists(id); |
||||
// 删除
|
||||
cpUserMapper.deleteById(id); |
||||
} |
||||
|
||||
private void validateCpUserExists(Long id) { |
||||
if (cpUserMapper.selectById(id) == null) { |
||||
throw exception(CP_USER_NOT_EXISTS); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public CpUserDO getCpUser(Long id) { |
||||
return cpUserMapper.selectById(id); |
||||
} |
||||
|
||||
@Override |
||||
public CpUserDO getByUserId(String userId) { |
||||
return this.getOne(Wrappers.<CpUserDO>lambdaQuery().eq(CpUserDO::getUserId,userId),false); |
||||
} |
||||
|
||||
@Override |
||||
public List<CpUserDO> getCpUserList(Collection<Long> ids) { |
||||
return cpUserMapper.selectBatchIds(ids); |
||||
} |
||||
|
||||
@Override |
||||
public PageResult<CpUserDO> getCpUserPage(CpUserPageReqVO pageReqVO) { |
||||
return cpUserMapper.selectPage(pageReqVO); |
||||
} |
||||
|
||||
@Override |
||||
public List<CpUserDO> getCpUserList(CpUserExportReqVO exportReqVO) { |
||||
return cpUserMapper.selectList(exportReqVO); |
||||
} |
||||
|
||||
|
||||
public void cpUserSync() throws WxErrorException { |
||||
WxCpConfigStorage config = wxCpService.getWxCpConfigStorage(); |
||||
List<WxCpDepart> departList = wxCpService.getDepartmentService().list(null); |
||||
|
||||
//根据部门id获取部门成员信息
|
||||
//6 旭清回鄉生態農業發展公司
|
||||
//35 回鄉信息技术公司
|
||||
List<WxCpUser> userList = wxCpService.getUserService().listByDepartment(6L, true, 0); |
||||
userList.addAll(wxCpService.getUserService().listByDepartment(35L, true, 0)); |
||||
|
||||
|
||||
List<CpUserDO> rs = CpUserConvert.INSTANCE.convertListFromWxApi(userList); |
||||
|
||||
List<CpUserDO> nowUsers = this.cpUserMapper.selectList(); |
||||
|
||||
// 已经存在的员工
|
||||
List<String> nowUsersIds = nowUsers.stream().map(CpUserDO::getUserId).collect(Collectors.toList()); |
||||
|
||||
rs.removeIf(cpUserDO -> nowUsersIds.contains(cpUserDO.getUserId())); |
||||
this.saveBatch(rs); |
||||
|
||||
// 已经离职的员工 设置删除
|
||||
List<String> leaveUserIds = userList.stream().filter(wxCpUser -> wxCpUser.getStatus() == 0) |
||||
.map(WxCpUser::getUserId).collect(Collectors.toList()); |
||||
|
||||
if (ObjectUtil.isNotEmpty(leaveUserIds)) { |
||||
List<CpUserDO> leaveUsers = this.list(Wrappers.<CpUserDO>lambdaQuery() |
||||
.in(CpUserDO::getUserId, leaveUserIds)); |
||||
leaveUsers.forEach(cpUserDO -> cpUserDO.setDeleted(true)); |
||||
this.updateBatchById(leaveUsers); |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void sendMessage(CpMessageDto cpMessage) throws WxErrorException { |
||||
WxCpMessage message = new WxCpMessage(); |
||||
String agentId = wxCpService.getWxCpConfigStorage().getAgentId().toString(); |
||||
|
||||
String page = String.format("/pages/task/%sDetail/index?id=%d", |
||||
cpMessage.getTypeEnum().equals(WxCpMsgTypeEnum.project) ? "project" : "task", |
||||
cpMessage.getId()); |
||||
|
||||
message.setMsgType("miniprogram_notice"); |
||||
message.setAppId(agentId); |
||||
message.setPage(page); |
||||
message.setTitle(cpMessage.getTitle()); |
||||
message.setDescription(cpMessage.getDescription()); |
||||
message.setContentItems(cpMessage.getContentItems()); |
||||
message.setToUser(String.join("|", cpMessage.getReciveIds())); |
||||
wxCpService.getMessageService().send(message); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
<mapper namespace="cn.iocoder.yudao.module.system.dal.mysql.CpUser.CpUserMapper"> |
||||
|
||||
<!-- |
||||
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。 |
||||
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。 |
||||
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。 |
||||
文档可见:https://www.iocoder.cn/MyBatis/x-plugins/ |
||||
--> |
||||
|
||||
</mapper> |
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
<mapper namespace="cn.iocoder.yudao.module.system.dal.mysql.dict.DictMapper"> |
||||
|
||||
<!-- 查询字典表的数据 支持设置过滤条件、设置存储值作为in查询条件 --> |
||||
<select id="queryTableDictByKeysAndFilterSql" parameterType="String" resultType="org.jeecg.common.system.vo.DictModel"> |
||||
select ${text} as "text", ${code} as "value" from ${table} where ${code} IN ( |
||||
<foreach item="key" collection="codeValues" separator=","> |
||||
#{key} |
||||
</foreach> |
||||
) |
||||
<if test="filterSql != null and filterSql != ''"> |
||||
and ${filterSql} |
||||
</if> |
||||
</select> |
||||
|
||||
</mapper> |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue