diff --git a/pqs-common/common-core/src/main/java/com/njcn/common/utils/PubUtils.java b/pqs-common/common-core/src/main/java/com/njcn/common/utils/PubUtils.java index 85cd302f1..3b4c19ace 100644 --- a/pqs-common/common-core/src/main/java/com/njcn/common/utils/PubUtils.java +++ b/pqs-common/common-core/src/main/java/com/njcn/common/utils/PubUtils.java @@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.type.TypeFactory; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.njcn.common.pojo.constant.PatternRegex; import com.njcn.common.pojo.enums.response.CommonResponseEnum; import com.njcn.common.pojo.exception.BusinessException; @@ -26,6 +27,8 @@ import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static java.lang.Integer.parseInt; @@ -306,4 +309,22 @@ public class PubUtils { return -1; } } + + //*****************************************xuyang添加,用于App******************************************************** + /** + * 正则表达式字符串 + * 要匹配的字符串 + * + * @return 如果str 符合 regex的正则表达式格式,返回true, 否则返回 false; + */ + public static boolean match(String regex, String str) { + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(str); + return matcher.matches(); + } + + public static boolean patternPasswordPhone(String password) { + return match(PatternRegex.PASSWORD_PHONE_REGEX, password); + } + //***************************************************添加结束******************************************************** } diff --git a/pqs-common/common-web/src/main/java/com/njcn/web/utils/app/AESUtil.java b/pqs-common/common-web/src/main/java/com/njcn/web/utils/app/AESUtil.java new file mode 100644 index 000000000..c47d6f687 --- /dev/null +++ b/pqs-common/common-web/src/main/java/com/njcn/web/utils/app/AESUtil.java @@ -0,0 +1,88 @@ +package com.njcn.web.utils.app; +import org.apache.commons.codec.binary.Base64; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import java.security.Security; + +/** + * @author hongawen + * @date: 2019/10/28 14:37 + */ +public class AESUtil { + + private static final Logger logger = LoggerFactory.getLogger(AESUtil.class); + + private static final String key ="f81804778c89c779"; + + private static final String EncryptAlg ="AES"; + + private static final String Cipher_Mode="AES/ECB/PKCS5Padding"; + + private static final String Encode="UTF-8"; + + private static final int Secret_Key_Size=16; + + private static final String Key_Encode="UTF-8"; + + /** + * @param content 加密内容 + * @return aes加密后 转base64 + */ + public static String aesPKCS5PaddingEncrypt(String content) throws Exception { + try { + Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); + Cipher cipher = Cipher.getInstance(Cipher_Mode); + byte[] realKey=getSecretKey(key); + cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(realKey,EncryptAlg)); + byte[] data=cipher.doFinal(content.getBytes(Encode)); + String result=new Base64().encodeToString(data); + return result; + } catch (Exception e) { + throw new Exception("AES加密失败:content=" +content +" key="+key); + } + } + + /** + * AES/ECB/PKCS7Padding 解密 + * @param content 解密内容 + * @return 先转base64 再解密 + */ + public static String aesPKCS5PaddingDecrypt(String content) throws Exception { + try { + byte[] decodeBytes= Base64.decodeBase64(content); + Cipher cipher = Cipher.getInstance(Cipher_Mode); + byte[] realKey=getSecretKey(key); + cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(realKey,EncryptAlg)); + byte[] realBytes=cipher.doFinal(decodeBytes); + return new String(realBytes, Encode); + } catch (Exception e) { + throw new Exception("AES解密失败:Aescontent = " +e.fillInStackTrace(),e); + } + } + + /** + * 对密钥key进行处理:如密钥长度不够位数的则 以指定paddingChar 进行填充; + * 此处用空格字符填充,也可以 0 填充,具体可根据实际项目需求做变更 + * @param key + * @return + * @throws Exception + */ + public static byte[] getSecretKey(String key) throws Exception{ + final byte paddingChar=' '; + + byte[] realKey = new byte[Secret_Key_Size]; + byte[] byteKey = key.getBytes(Key_Encode); + for (int i =0;i parameters) { + if (CollectionUtils.isEmpty(parameters)) { + return null; + } + int count = parameters.size(); + String[] encodedValues = new String[count]; + for (int i = 0; i < count; i++) { + encodedValues[i] = dealString(parameters.get(i)); + } + return encodedValues; + } + + /** + * 滤除content中的危险 HTML 代码, 主要是脚本代码, 滚动字幕代码以及脚本事件处理代码 + * + * @param content + * 需要滤除的字符串 + * @return 过滤的结果 + */ + public static String replaceHtmlCode(String content) { + if (null == content) { + return null; + } + if (0 == content.length()) { + return ""; + } + // 需要滤除的脚本事件关键字 + String[] eventKeywords = { "onmouseover", "onmouseout", "onmousedown", + "onmouseup", "onmousemove", "onclick", "ondblclick", + "onkeypress", "onkeydown", "onkeyup", "ondragstart", + "onerrorupdate", "onhelp", "onreadystatechange", "onrowenter", + "onrowexit", "onselectstart", "onload", "onunload", + "onbeforeunload", "onblur", "onerror", "onfocus", "onresize", + "onscroll", "oncontextmenu", "alert" }; + content = replace(content, " -1) { + int b = 0; + String str1, str2, str3, str4, strA, strB; + str1 = source; + str2 = str1.toLowerCase(); + str3 = oldStr; + str4 = str3.toLowerCase(); + if (matchCase) { + strA = str1; + strB = str3; + } else { + strA = str2; + strB = str4; + } + a = strA.indexOf(strB, findStartPos); + if (a > -1) { + b = oldStr.length(); + findStartPos = a + b; + StringBuffer bbuf = new StringBuffer(source); + source = bbuf.replace(a, a + b, newStr) + ""; + // 新的查找开始点位于替换后的字符串的结尾 + findStartPos = findStartPos + newStr.length() - b; + } + } + return source; + } + + public static String xssEncode(String s) { + if (s == null || s.isEmpty()) { + return s; + } + StringBuilder sb = new StringBuilder(s.length() + 16); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + switch (c) { + case '>': + sb.append('>');// 全角大于号 + break; + case '<': + sb.append('<');// 全角小于号 + break; +// case '\'': +// sb.append('‘');// 全角单引号 +// break; +// case '\"': +// sb.append('“');// 全角双引号 +// break; +// case '&': +// sb.append('&');// 全角 +// break; + case '\\': + sb.append('\');// 全角斜线 + break; + /*case '#': + sb.append('#');// 全角井号 + break;*/ +// case '(': +// sb.append('(');// +// break; +// case ')': +// sb.append(')');// +// break; + default: + sb.append(c); + break; + } + } + String resultStr = sb.toString(); +// resultStr=StringEscapeUtils.escapeSql(resultStr); +// resultStr=StringEscapeUtils.escapeHtml(resultStr); +// resultStr=StringEscapeUtils.escapeJavaScript(resultStr); + return resultStr; + } + + /** + * 字符串处理包括SQL的注入处理 + * @author hongawen + * @param value 字符串 + */ + public static String dealString(String value) { + if (!StringUtils.isBlank(value)) { + value = xssEncode(value); + value=replaceHtmlCode(value); + value= StringEscapeUtils.escapeSql(value); + return value; + }else{ + return ""; + } + } +} diff --git a/pqs-influx/src/main/resources/application.yml b/pqs-influx/src/main/resources/application.yml index d9a43b67b..f41c18a13 100644 --- a/pqs-influx/src/main/resources/application.yml +++ b/pqs-influx/src/main/resources/application.yml @@ -3,5 +3,5 @@ spring: url: http://192.168.1.16:8086 user: admin password: 123456 - database: pqsbase_sjzx + database: pqsbase_zl mapper-location: com.njcn.influx.imapper \ No newline at end of file diff --git a/pqs-influx/src/test/java/com/njcn/influx/DemoTest.java b/pqs-influx/src/test/java/com/njcn/influx/DemoTest.java index e7ebb2d28..881cbd8d5 100644 --- a/pqs-influx/src/test/java/com/njcn/influx/DemoTest.java +++ b/pqs-influx/src/test/java/com/njcn/influx/DemoTest.java @@ -1,7 +1,9 @@ package com.njcn.influx; import com.njcn.influx.imapper.CldStatisticsFlowMapper; +import com.njcn.influx.pojo.dto.StatisticalDataDTO; import com.njcn.influx.pojo.po.DataV; +import com.njcn.influx.service.CommonService; import com.njcn.influx.service.DataFlickerService; import com.njcn.influx.service.IDataVService; import lombok.SneakyThrows; @@ -26,12 +28,19 @@ public class DemoTest extends BaseJunitTest { @Autowired private IDataVService dataVService; + @Autowired + private CommonService commonService; + @SneakyThrows @Test public void test() { // dataFlickerService.getDataFlicker("ff2d9674c1f1ecce7f33a5bf17fc4f2d","2023-05-02 00:00:00","2023-05-02 23:59:59"); - List ss = dataVService.getDataV("ff2d9674c1f1ecce7f33a5bf17fc4f2d", "2023-05-02 00:00:00", "2023-05-02 23:59:59"); - System.out.println(ss); +// List ss = dataVService.getDataV("ff2d9674c1f1ecce7f33a5bf17fc4f2d", "2023-05-02 00:00:00", "2023-05-02 23:59:59"); +// System.out.println(ss); + + StatisticalDataDTO statisticalDataDTO = commonService.getLineRtData("4","data_harmpower_p","W","A","max"); + System.out.println("statisticalDataDTO==:" + statisticalDataDTO); + } diff --git a/pqs-user/user-api/src/main/java/com/njcn/user/enums/MessageEnum.java b/pqs-user/user-api/src/main/java/com/njcn/user/enums/MessageEnum.java new file mode 100644 index 000000000..bc03415d5 --- /dev/null +++ b/pqs-user/user-api/src/main/java/com/njcn/user/enums/MessageEnum.java @@ -0,0 +1,46 @@ +package com.njcn.user.enums; + +/** + * @author hongawen + * @date: 2019/10/22 14:05 + * 短信模板枚举 + */ +public enum MessageEnum { + /** + * 阿里云短信模板编号 + */ + LOGIN(0, "SMS_176180086"), + REGISTER(1, "SMS_176200101"), + RESET_PWD(2, "SMS_176195072"), + FORGET_PWD(3, "SMS_176195072"), + UPDATE_PHONE(4, "SMS_175583840"), + JUDGE_OLD_PHONE(5, "SMS_176195072"), + EVENT_MESSAGE_NOTICE(6,"SMS_212270827"); + + private final int code; + + private final String templateCode; + + MessageEnum(int code, String templateCode) { + this.code = code; + this.templateCode = templateCode; + } + + public int getCode() { + return code; + } + + public String getTemplateCode() { + return templateCode; + } + + public static String getTemplateByCode(int code) { + for (MessageEnum messageEnum : MessageEnum.values()) { + if (messageEnum.code == code) { + return messageEnum.templateCode; + } + } + return ""; + } + +} diff --git a/pqs-user/user-api/src/main/java/com/njcn/user/enums/UserLevelEnum.java b/pqs-user/user-api/src/main/java/com/njcn/user/enums/UserLevelEnum.java new file mode 100644 index 000000000..474ef9c8e --- /dev/null +++ b/pqs-user/user-api/src/main/java/com/njcn/user/enums/UserLevelEnum.java @@ -0,0 +1,51 @@ +package com.njcn.user.enums; + +/** + * @author hongawen + * @date: 2019/10/28 15:11 + */ +public enum UserLevelEnum { + + HOST_USER("0","主用户"), + CHILD_USER("1","子用户"), + OPERATION_USER("2","运维"), + SPECIFIC_USER("3","专职"), + ENGINEERING_USER("4","工程"), + TOURIST_USER("5","游客"); + + private String code; + + private String msg; + + UserLevelEnum(String code, String msg){ + this.code=code; + this.msg=msg; + } + + public String getCode(){ + return code; + } + + public String getMsg(){ + return msg; + } + + public static String getMsgByCode(String code){ + for (UserLevelEnum userLevelEnum : UserLevelEnum.values()) { + if (userLevelEnum.code.equalsIgnoreCase(code)) { + return userLevelEnum.msg; + } + } + return ""; + } + + + public static String getCodeByMsg(String msg){ + for (UserLevelEnum userLevelEnum : UserLevelEnum.values()) { + if (userLevelEnum.msg.equalsIgnoreCase(msg)) { + return userLevelEnum.code; + } + } + return ""; + } +} diff --git a/pqs-user/user-api/src/main/java/com/njcn/user/enums/UserResponseEnum.java b/pqs-user/user-api/src/main/java/com/njcn/user/enums/UserResponseEnum.java index bd27e9545..59497a30c 100644 --- a/pqs-user/user-api/src/main/java/com/njcn/user/enums/UserResponseEnum.java +++ b/pqs-user/user-api/src/main/java/com/njcn/user/enums/UserResponseEnum.java @@ -22,18 +22,25 @@ public enum UserResponseEnum { */ LOGIN_USERNAME_NOT_FOUND("A0101", "用户不存在"), LOGIN_USERNAME_INVALID("A0101", "用户名非法"), + LOGIN_USER_INDEX_INVALID("A0101", "用户索引非法"), LOGIN_PHONE_NOT_FOUND("A0101", "手机号不存在"), + KEY_WRONG("A0101","登录密码/验证码为空"), LOGIN_WRONG_PWD("A0101", "用户名密码错误"), LOGIN_WRONG_PHONE_CODE("A0101", "短信验证码错误"), LOGIN_WRONG_CODE("A0101", "验证码错误"), + CODE_TYPE_ERROR("A0101","验证码类型非法"), + SEND_CODE_FAIL("A0101","验证码发送失败"), LOGIN_USER_DELETE("A0101", "账号已被注销"), LOGIN_USER_LOCKED("A0101", "账号已被锁定"), LOGIN_USER_UNAUDITED("A0101", "账号未审核"), NEED_MODIFY_PASSWORD("A0101", "密码需修改"), LOGIN_USER_SLEEP("A0101", "账号已休眠"), LOGIN_USER_PASSWORD_EXPIRED("A0101", "账号密码过期"), + LOGIN_ERROR("A0101", "登录失败"), LOGIN_FIRST_LOGIN("A0101", "账号首次登录"), NEED_MODIFY_PWD("A0101", "密码失效,请重置"), + PASSWORD_INVALID("A0101", "密码非法"), + PASSWORD_SET_ERROR("A0101", "密码设置错误"), LACK_USER_STRATEGY("A0101", "缺失用户策略配置"), UNSUPPORTED_GRANT_TYPE("A0101", "非法认证方式"), INVALID_IP("A0101", "非法IP访问系统"), @@ -42,10 +49,13 @@ public enum UserResponseEnum { SPECIAL_PASSWORD("A0101", "密码需要包含特殊字符字母数字,长度为8-16"), REPEAT_PASSWORD("A0101", "新密码与旧密码不能一致"), + REGISTER_FAIL("A0102", "注册失败"), REGISTER_PHONE_FAIL("A0102", "该号码已注册,请检查phone字段"), REGISTER_LOGIN_NAME_FAIL("A0102", "该账号已注册"), REGISTER_PHONE_WRONG("A0102", "手机号非法"), + REGISTER_PHONE_REPEAT("A0102", "手机号已注册"), REGISTER_PASSWORD_WRONG("A0102", "账号密码非法"), + DEV_CODE_WRONG("A0102","设备码非法"), REGISTER_LOGIN_NAME_EXIST("A0102", "该登录名已存在,请检查loginName字段"), REGISTER_HOMEPAGE_NAME_EXIST("A0102", "该驾驶舱名已存在,请检查name字段"), FUNCTION_PATH_EXIST("A0102", "菜单路径已存在,请检查path字段"), @@ -95,4 +105,13 @@ public enum UserResponseEnum { this.message = message; } + public static String getCodeByMsg(String msg){ + for (UserResponseEnum userCodeEnum : UserResponseEnum.values()) { + if (userCodeEnum.message.equalsIgnoreCase(msg)) { + return userCodeEnum.code; + } + } + return ""; + } + } diff --git a/pqs-user/user-api/src/main/java/com/njcn/user/pojo/po/app/AppInfoSet.java b/pqs-user/user-api/src/main/java/com/njcn/user/pojo/po/app/AppInfoSet.java new file mode 100644 index 000000000..0d4913db3 --- /dev/null +++ b/pqs-user/user-api/src/main/java/com/njcn/user/pojo/po/app/AppInfoSet.java @@ -0,0 +1,51 @@ +package com.njcn.user.pojo.po.app; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.njcn.db.bo.BaseEntity; +import java.io.Serializable; + +import lombok.Data; +import lombok.Getter; +import lombok.Setter; + +/** + *

+ * APP用户消息配置表 + *

+ * + * @author xuyang + * @since 2023-06-08 + */ +@Data +@TableName("app_info_set") +public class AppInfoSet { + + private static final long serialVersionUID = 1L; + + /** + * 用户id + */ + private String userIndex; + + /** + * 0:false ;1:true 暂态消息模块 + */ + private Integer eventInfo; + + /** + * 0:false ;1:true 稳态消息模块 + */ + private Integer harmonicInfo; + + /** + * 0:false ;1:true 终端消息模块 + */ + private Integer deviceInfo; + + /** + * 0:false ;1:true 系统消息模块 + */ + private Integer systemInfo; + + +} diff --git a/pqs-user/user-api/src/main/java/com/njcn/user/pojo/po/app/AppSendMsg.java b/pqs-user/user-api/src/main/java/com/njcn/user/pojo/po/app/AppSendMsg.java new file mode 100644 index 000000000..14ff77616 --- /dev/null +++ b/pqs-user/user-api/src/main/java/com/njcn/user/pojo/po/app/AppSendMsg.java @@ -0,0 +1,47 @@ +package com.njcn.user.pojo.po.app; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.njcn.db.bo.BaseEntity; +import java.io.Serializable; +import java.time.LocalDateTime; + +import lombok.Data; +import lombok.Getter; +import lombok.Setter; + +/** + *

+ * App手机验证码发送记录表 + *

+ * + * @author xuyang + * @since 2023-06-07 + */ +@Data +@TableName("app_send_msg") +public class AppSendMsg { + + private static final long serialVersionUID = 1L; + + /** + * 手机号 + */ + private String phone; + + /** + * 消息内容 + */ + private String message; + + /** + * 发送时间 + */ + private LocalDateTime sendTime; + + /** + * 发送状态 + */ + private String sendStatus; + + +} diff --git a/pqs-user/user-api/src/main/java/com/njcn/user/pojo/po/app/AppUser.java b/pqs-user/user-api/src/main/java/com/njcn/user/pojo/po/app/AppUser.java new file mode 100644 index 000000000..feeccce22 --- /dev/null +++ b/pqs-user/user-api/src/main/java/com/njcn/user/pojo/po/app/AppUser.java @@ -0,0 +1,117 @@ +package com.njcn.user.pojo.po.app; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.njcn.db.bo.BaseEntity; +import java.io.Serializable; +import java.time.LocalDateTime; + +import lombok.Data; +import lombok.Getter; +import lombok.Setter; + +/** + *

+ * App用户表 + *

+ * + * @author xuyang + * @since 2023-06-07 + */ +@Data +@TableName("app_user") +public class AppUser extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 用户表Guid + */ + private String userIndex; + + /** + * 用户名(别名) + */ + private String name; + + /** + * 登录名 + */ + private String loginName; + + /** + * 密码 + */ + private String password; + + /** + * 电话号码 + */ + private String phone; + + /** + * 邮箱 + */ + private String email; + + /** + * 注册时间 + */ + private LocalDateTime registerTime; + + /** + * 密码有效期字段(初始化的时候跟注册时间一样) + */ + private LocalDateTime psdValidity; + + /** + * 最后一次登录时间 + */ + private LocalDateTime loginTime; + + /** + * 用户状态0:删除;1:正常;2:锁定; + */ + private Integer state; + + /** + * 密码错误次数 + */ + private Integer loginErrorTimes; + + /** + * 第一次登陆错误的时间 + */ + private LocalDateTime loginFirstErrorTime; + + /** + * 营销人员名称(只针对主用户) + */ + private String semName; + + /** + * 营销人员手机(只针对主用户) + */ + private String semPhone; + + /** + * 推荐码(新增主用户时候生成) + */ + private String referralCode; + + /** + * 设备码 + */ + private String devCode; + + /** + * 用户类型(0:主用户;1:子用户;2:运维;3:专职;4:工程;5:游客) + */ + private Integer userType; + + /** + * 用户等级 + */ + private String userLevel; + + +} diff --git a/pqs-user/user-api/src/main/java/com/njcn/user/pojo/vo/app/AppUserResultVO.java b/pqs-user/user-api/src/main/java/com/njcn/user/pojo/vo/app/AppUserResultVO.java new file mode 100644 index 000000000..8e95d1938 --- /dev/null +++ b/pqs-user/user-api/src/main/java/com/njcn/user/pojo/vo/app/AppUserResultVO.java @@ -0,0 +1,25 @@ +package com.njcn.user.pojo.vo.app; + +import lombok.Data; + +/** + * 类的介绍: + * + * @author xuyang + * @version 1.0.0 + * @createTime 2023/6/8 9:37 + */ +@Data +public class AppUserResultVO { + + private String userId; + + private String roleName; + + private String phone; + + private String userName; + + private String roleCode; + +} diff --git a/pqs-user/user-boot/pom.xml b/pqs-user/user-boot/pom.xml index 9c3f01c77..659bf5d12 100644 --- a/pqs-user/user-boot/pom.xml +++ b/pqs-user/user-boot/pom.xml @@ -44,7 +44,18 @@ common-swagger ${project.version} - + + + com.aliyun + aliyun-java-sdk-dysmsapi + 1.1.0 + + + com.aliyun + aliyun-java-sdk-core + 4.1.0 + + diff --git a/pqs-user/user-boot/src/main/java/com/njcn/user/controller/app/AppUserController.java b/pqs-user/user-boot/src/main/java/com/njcn/user/controller/app/AppUserController.java new file mode 100644 index 000000000..359a55eda --- /dev/null +++ b/pqs-user/user-boot/src/main/java/com/njcn/user/controller/app/AppUserController.java @@ -0,0 +1,141 @@ +package com.njcn.user.controller.app; + +import com.njcn.common.pojo.annotation.OperateInfo; +import com.njcn.common.pojo.constant.PatternRegex; +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.common.utils.HttpResultUtil; +import com.njcn.common.utils.PubUtils; +import com.njcn.user.enums.UserResponseEnum; +import com.njcn.user.pojo.vo.app.AppUserResultVO; +import com.njcn.user.service.IAppUserService; +import com.njcn.web.controller.BaseController; +import com.njcn.web.utils.app.AESUtil; +import com.njcn.web.utils.app.XssFilterUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.bouncycastle.asn1.ocsp.ResponseData; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; + +/** + * 类的介绍: + * + * @author xuyang + * @version 1.0.0 + * @createTime 2023/6/7 8:51 + */ +@Validated +@Slf4j +@RestController +@RequestMapping("/appUser") +@Api(tags = "App用户信息管理") +@AllArgsConstructor +public class AppUserController extends BaseController { + + private static final Logger logger = LoggerFactory.getLogger(AppUserController.class); + + private final IAppUserService appUserService; + + /** + * 获取(登录、注册、忘记密码、重新绑定手机)验证码 + */ + @PostMapping("authCode") + @OperateInfo + @ApiOperation(value = "获取验证码", notes = "获取验证码") + @ApiImplicitParams({ + @ApiImplicitParam(name = "phone", value = "手机号", required = true, paramType = "query"), + @ApiImplicitParam(name = "devCode", value = "设备码", required = true, paramType = "query"), + @ApiImplicitParam(name = "type", value = "验证码类型", required = true, paramType = "query"), + }) + public HttpResult authCode(String phone, String devCode, String type) { + String methodDescribe = getMethodDescribe("authCode"); + appUserService.setMessage(phone,devCode,type); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, "success", methodDescribe); + } + + /** + * 手机app注册 + */ + @PostMapping("register") + @OperateInfo + @ApiOperation(value = "注册入口", notes = "用户注册") + @ApiImplicitParams({ + @ApiImplicitParam(name = "phone", value = "手机号", required = true, paramType = "query"), + @ApiImplicitParam(name = "code", value = "验证码", required = true, paramType = "query"), + @ApiImplicitParam(name = "devCode", value = "设备码", required = true, paramType = "query"), + }) + public HttpResult register(String phone, String code, String devCode) { + String methodDescribe = getMethodDescribe("register"); + AppUserResultVO appUserResultVo = appUserService.register(phone,code,devCode); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, appUserResultVo, methodDescribe); + } + + /** + * 手机app密码设置 + */ + @PostMapping("setPsd") + @OperateInfo + @ApiOperation(value = "设置密码", notes = "设置密码") + @ApiImplicitParams({ + @ApiImplicitParam(name = "userId", value = "用户索引", required = true, paramType = "query"), + @ApiImplicitParam(name = "password", value = "密码", required = true, paramType = "query"), + @ApiImplicitParam(name = "devCode", value = "设备码", required = true, paramType = "query"), + }) + public HttpResult setPsd(String userId, String password, String devCode) { + String methodDescribe = getMethodDescribe("setPsd"); + appUserService.setPsd(userId, devCode, password); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, "success", methodDescribe); + } + + /** + * 手机app登录入口 + */ + @PostMapping("login") + @OperateInfo + @ApiOperation(value = "登录入口", notes = "APP登录") + @ApiImplicitParams({ + @ApiImplicitParam(name = "phone", value = "手机号", required = true, paramType = "query"), + @ApiImplicitParam(name = "type", value = "登录类型", required = true, paramType = "query"), + @ApiImplicitParam(name = "key", value = "验证码/密码", required = true, paramType = "query"), + @ApiImplicitParam(name = "devCode", value = "设备码", required = true, paramType = "query"), + }) + public HttpResult login(String phone, String type, String key, String devCode, HttpServletRequest request) { + String methodDescribe = getMethodDescribe("login"); + AppUserResultVO appUserResultVo = appUserService.login(phone,type,key,devCode); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, appUserResultVo, methodDescribe); + } + + + + + + + + + + + + + + + + + + + + + +} diff --git a/pqs-user/user-boot/src/main/java/com/njcn/user/mapper/AppInfoSetMapper.java b/pqs-user/user-boot/src/main/java/com/njcn/user/mapper/AppInfoSetMapper.java new file mode 100644 index 000000000..eb6211b8a --- /dev/null +++ b/pqs-user/user-boot/src/main/java/com/njcn/user/mapper/AppInfoSetMapper.java @@ -0,0 +1,16 @@ +package com.njcn.user.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.njcn.user.pojo.po.app.AppInfoSet; + +/** + *

+ * APP用户消息配置表 Mapper 接口 + *

+ * + * @author xuyang + * @since 2023-06-08 + */ +public interface AppInfoSetMapper extends BaseMapper { + +} diff --git a/pqs-user/user-boot/src/main/java/com/njcn/user/mapper/AppSendMsgMapper.java b/pqs-user/user-boot/src/main/java/com/njcn/user/mapper/AppSendMsgMapper.java new file mode 100644 index 000000000..c864baf1e --- /dev/null +++ b/pqs-user/user-boot/src/main/java/com/njcn/user/mapper/AppSendMsgMapper.java @@ -0,0 +1,16 @@ +package com.njcn.user.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.njcn.user.pojo.po.app.AppSendMsg; + +/** + *

+ * App手机验证码发送记录表 Mapper 接口 + *

+ * + * @author xuyang + * @since 2023-06-07 + */ +public interface AppSendMsgMapper extends BaseMapper { + +} diff --git a/pqs-user/user-boot/src/main/java/com/njcn/user/mapper/AppUserMapper.java b/pqs-user/user-boot/src/main/java/com/njcn/user/mapper/AppUserMapper.java new file mode 100644 index 000000000..0d541ed34 --- /dev/null +++ b/pqs-user/user-boot/src/main/java/com/njcn/user/mapper/AppUserMapper.java @@ -0,0 +1,16 @@ +package com.njcn.user.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.njcn.user.pojo.po.app.AppUser; + +/** + *

+ * App用户表 Mapper 接口 + *

+ * + * @author xuyang + * @since 2023-06-07 + */ +public interface AppUserMapper extends BaseMapper { + +} diff --git a/pqs-user/user-boot/src/main/java/com/njcn/user/service/IAppInfoSetService.java b/pqs-user/user-boot/src/main/java/com/njcn/user/service/IAppInfoSetService.java new file mode 100644 index 000000000..916eec53e --- /dev/null +++ b/pqs-user/user-boot/src/main/java/com/njcn/user/service/IAppInfoSetService.java @@ -0,0 +1,16 @@ +package com.njcn.user.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.njcn.user.pojo.po.app.AppInfoSet; + +/** + *

+ * APP用户消息配置表 服务类 + *

+ * + * @author xuyang + * @since 2023-06-08 + */ +public interface IAppInfoSetService extends IService { + +} diff --git a/pqs-user/user-boot/src/main/java/com/njcn/user/service/IAppSendMsgService.java b/pqs-user/user-boot/src/main/java/com/njcn/user/service/IAppSendMsgService.java new file mode 100644 index 000000000..f654cc941 --- /dev/null +++ b/pqs-user/user-boot/src/main/java/com/njcn/user/service/IAppSendMsgService.java @@ -0,0 +1,15 @@ +package com.njcn.user.service; +import com.baomidou.mybatisplus.extension.service.IService; +import com.njcn.user.pojo.po.app.AppSendMsg; + +/** + *

+ * App手机验证码发送记录表 服务类 + *

+ * + * @author xuyang + * @since 2023-06-07 + */ +public interface IAppSendMsgService extends IService { + +} diff --git a/pqs-user/user-boot/src/main/java/com/njcn/user/service/IAppUserService.java b/pqs-user/user-boot/src/main/java/com/njcn/user/service/IAppUserService.java new file mode 100644 index 000000000..9acb93697 --- /dev/null +++ b/pqs-user/user-boot/src/main/java/com/njcn/user/service/IAppUserService.java @@ -0,0 +1,43 @@ +package com.njcn.user.service; + +import com.njcn.user.pojo.vo.app.AppUserResultVO; + +/** + * @author xuyang + */ +public interface IAppUserService { + + /** + * 发送短信 + * @param phone 手机号 + * @param devCode 设备码 + * @param type 验证码类型 + */ + void setMessage(String phone, String devCode, String type); + + /** + * 手机app注册(所有用户初始统一为游客,需要特定的码升级) + * @param phone 手机号 + * @param code 验证码 + * @param devCode 设备码 + */ + AppUserResultVO register(String phone, String code, String devCode); + + /** + * 用户设置密码 + * @param userId 用户id + * @param devCode 设备码 + * @param password 密码 + */ + void setPsd(String userId, String devCode, String password); + + /** + * 用户设置密码 + * @param phone 手机号 + * @param type 登陆类型 + * @param key 验证码/密码 + * @param devCode 设备码 + */ + AppUserResultVO login(String phone, String type, String key, String devCode); + +} diff --git a/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/AppInfoSetServiceImpl.java b/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/AppInfoSetServiceImpl.java new file mode 100644 index 000000000..adb8ba966 --- /dev/null +++ b/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/AppInfoSetServiceImpl.java @@ -0,0 +1,20 @@ +package com.njcn.user.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.njcn.user.mapper.AppInfoSetMapper; +import com.njcn.user.pojo.po.app.AppInfoSet; +import com.njcn.user.service.IAppInfoSetService; +import org.springframework.stereotype.Service; + +/** + *

+ * APP用户消息配置表 服务实现类 + *

+ * + * @author xuyang + * @since 2023-06-08 + */ +@Service +public class AppInfoSetServiceImpl extends ServiceImpl implements IAppInfoSetService { + +} diff --git a/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/AppSendMsgServiceImpl.java b/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/AppSendMsgServiceImpl.java new file mode 100644 index 000000000..63389c30b --- /dev/null +++ b/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/AppSendMsgServiceImpl.java @@ -0,0 +1,20 @@ +package com.njcn.user.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.njcn.user.mapper.AppSendMsgMapper; +import com.njcn.user.pojo.po.app.AppSendMsg; +import com.njcn.user.service.IAppSendMsgService; +import org.springframework.stereotype.Service; + +/** + *

+ * App手机验证码发送记录表 服务实现类 + *

+ * + * @author xuyang + * @since 2023-06-07 + */ +@Service +public class AppSendMsgServiceImpl extends ServiceImpl implements IAppSendMsgService { + +} diff --git a/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/AppUserServiceImpl.java b/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/AppUserServiceImpl.java new file mode 100644 index 000000000..1c14d900d --- /dev/null +++ b/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/AppUserServiceImpl.java @@ -0,0 +1,305 @@ +package com.njcn.user.service.impl; + +import com.aliyuncs.DefaultAcsClient; +import com.aliyuncs.IAcsClient; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; +import com.aliyuncs.http.MethodType; +import com.aliyuncs.profile.DefaultProfile; +import com.aliyuncs.profile.IClientProfile; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.njcn.common.pojo.constant.PatternRegex; +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.common.utils.HttpResultUtil; +import com.njcn.common.utils.PubUtils; +import com.njcn.redis.utils.RedisUtil; +import com.njcn.user.enums.MessageEnum; +import com.njcn.user.enums.UserLevelEnum; +import com.njcn.user.enums.UserResponseEnum; +import com.njcn.user.mapper.AppUserMapper; +import com.njcn.user.pojo.po.app.AppInfoSet; +import com.njcn.user.pojo.po.app.AppSendMsg; +import com.njcn.user.pojo.po.app.AppUser; +import com.njcn.user.pojo.vo.app.AppUserResultVO; +import com.njcn.user.service.IAppInfoSetService; +import com.njcn.user.service.IAppSendMsgService; +import com.njcn.user.service.IAppUserService; +import com.njcn.web.utils.app.AESUtil; +import com.njcn.web.utils.app.XssFilterUtil; +import lombok.AllArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.Objects; +import java.util.Random; + +/** + * 类的介绍: + * + * @author xuyang + * @version 1.0.0 + * @createTime 2023/6/7 14:42 + */ +@Service +@AllArgsConstructor +public class AppUserServiceImpl extends ServiceImpl implements IAppUserService { + + private static final Logger logger = LoggerFactory.getLogger(AppUserServiceImpl.class); + + private final RedisUtil redisUtil; + + private final IAppSendMsgService appSendMsgService; + + private final IAppInfoSetService appInfoSetService; + + @Override + @Transactional(rollbackFor = Exception.class) + public void setMessage(String phone, String devCode, String type) { + if (!PubUtils.match(PatternRegex.PHONE_REGEX, XssFilterUtil.dealString(phone))){ + throw new BusinessException(UserResponseEnum.REGISTER_PHONE_WRONG); + } + try { + devCode= AESUtil.aesPKCS5PaddingDecrypt(devCode); + String msgTemplate; + switch (type) { + case "0": + msgTemplate = MessageEnum.getTemplateByCode(0); + break; + case "1": + msgTemplate = MessageEnum.getTemplateByCode(1); + break; + case "2": + msgTemplate = MessageEnum.getTemplateByCode(2); + break; + case "3": + msgTemplate = MessageEnum.getTemplateByCode(3); + break; + case "4": + msgTemplate = MessageEnum.getTemplateByCode(4); + break; + case "5": + msgTemplate = MessageEnum.getTemplateByCode(5); + break; + default: + throw new BusinessException(UserResponseEnum.CODE_TYPE_ERROR); + } + //type为4,账号替换为新手机号 + if (!msgTemplate.equalsIgnoreCase(MessageEnum.REGISTER.getTemplateCode())) { + AppUser appUser = this.lambdaQuery().eq(AppUser::getPhone,phone).one(); + if ("4".equalsIgnoreCase(type)) { + //注册,无需判断手机号与设备的匹配 + if (appUser != null) { + throw new BusinessException(UserResponseEnum.REGISTER_PHONE_FAIL); + } + } else { + if (null == appUser) { + throw new BusinessException(UserResponseEnum.LOGIN_USERNAME_NOT_FOUND); + } else { + appUser.setDevCode(devCode); + logger.info("更新手机id:" + devCode); + this.updateById(appUser); + } + } + } + //开始执行短信发送 + //设置超时时间-可自行调整 + System.setProperty("sun.net.client.defaultConnectTimeout", "10000"); + System.setProperty("sun.net.client.defaultReadTimeout", "10000"); + //初始化ascClient需要的几个参数 + //短信API产品名称(短信产品名固定,无需修改) + final String product = "Dysmsapi"; + //短信API产品域名(接口地址固定,无需修改) + final String domain = "dysmsapi.aliyuncs.com"; + //替换成你的AK + //你的accessKeyId,参考本文档步骤2 + final String accessKeyId = "LTAI4FxsR76x2dq3w9c5puUe"; + //你的accessKeySecret,参考本文档步骤2 + final String accessKeySecret = "GxkTR8fsrvHtixTlD9UPmOGli35tZs"; + //初始化ascClient,暂时不支持多region(请勿修改) + IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret); + DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain); + IAcsClient acsClient = new DefaultAcsClient(profile); + SendSmsRequest request = new SendSmsRequest(); + request.setMethod(MethodType.POST); + request.setPhoneNumbers(phone); + //必填:短信签名-可在短信控制台中找到 + request.setSignName("灿能云"); + //必填:短信模板-可在短信控制台中找到,发送国际/港澳台消息时,请使用国际/港澳台短信模版 + request.setTemplateCode(msgTemplate); + String vcode = getMessageCode(); + String code = "{\"code\":\"" + vcode + "\"}"; + request.setTemplateParam(code); + //请求失败这里会抛ClientException异常 + SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); + String key = phone + devCode; + if (sendSmsResponse.getCode() != null && "OK".equals(sendSmsResponse.getCode())) { + //成功发送短信验证码后,保存进redis + redisUtil.saveByKeyWithExpire(key, vcode, 300L); + } else { + throw new BusinessException(UserResponseEnum.SEND_CODE_FAIL); + } + AppSendMsg appSendMsg = new AppSendMsg(); + appSendMsg.setPhone(phone); + appSendMsg.setMessage(vcode); + appSendMsg.setSendTime(LocalDateTime.now()); + appSendMsg.setSendStatus(sendSmsResponse.getCode() == null ? "无状态" : sendSmsResponse.getCode()); + appSendMsgService.save(appSendMsg); + } catch (Exception e) { + logger.error("发送短信异常,异常为:"+e.getMessage()); + if (e.getMessage().length() < 10) { + throw new BusinessException(UserResponseEnum.getCodeByMsg(e.getMessage())); + } else { + throw new BusinessException(UserResponseEnum.SEND_CODE_FAIL); + } + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public AppUserResultVO register(String phone, String code, String devCode) { + AppUserResultVO appUserResultVo = new AppUserResultVO(); + if (!PubUtils.match(PatternRegex.PHONE_REGEX, XssFilterUtil.dealString(phone))){ + throw new BusinessException(UserResponseEnum.REGISTER_PHONE_WRONG); + } + if (StringUtils.isBlank(devCode)) { + throw new BusinessException(UserResponseEnum.DEV_CODE_WRONG); + } + try { + devCode= AESUtil.aesPKCS5PaddingDecrypt(devCode); + judgeCode(phone, code, devCode); + //先根据手机号查询是否已被注册 + AppUser appUser = this.lambdaQuery().eq(AppUser::getPhone,phone).one(); + if (!Objects.isNull(appUser)){ + throw new BusinessException(UserResponseEnum.REGISTER_PHONE_REPEAT); + } else { + appUser = new AppUser(); + appUser.setPhone(phone); + appUser.setLoginErrorTimes(0); + appUser.setLoginTime(LocalDateTime.now()); + appUser.setPsdValidity(appUser.getLoginTime()); + appUser.setRegisterTime(appUser.getLoginTime()); + appUser.setUserLevel("5"); + appUser.setDevCode(devCode); + logger.info("插入手机id:" + devCode); + appUser.setReferralCode("DUCxda"); + appUser.setState(1); + this.save(appUser); + //消息默认配置 + AppInfoSet appInfoSet = new AppInfoSet(); + appInfoSet.setUserIndex(appUser.getUserIndex()); + appInfoSet.setDeviceInfo(1); + appInfoSet.setEventInfo(1); + appInfoSet.setSystemInfo(1); + appInfoSet.setHarmonicInfo(1); + appInfoSetService.save(appInfoSet); + //配置返回数据 + appUserResultVo.setUserId(appUser.getUserIndex()); + appUserResultVo.setRoleName(UserLevelEnum.getMsgByCode(appUser.getUserLevel())); + appUserResultVo.setPhone(appUser.getPhone()); + appUserResultVo.setRoleCode(appUser.getUserLevel()); + appUserResultVo.setUserName(StringUtils.isEmpty(appUser.getName()) ? null : appUser.getName()); + } + } catch (Exception e) { + logger.error("app用户注册异常:" + e.toString()); + if (e.getMessage().length() < 10) { + throw new BusinessException(UserResponseEnum.getCodeByMsg(e.getMessage())); + } else { + throw new BusinessException(UserResponseEnum.REGISTER_FAIL); + } + } + return appUserResultVo; + } + + @Override + public void setPsd(String userId, String devCode, String password) { + //参数校验 + if (StringUtils.isBlank(userId)) { + throw new BusinessException(UserResponseEnum.LOGIN_USER_INDEX_INVALID); + } + if (StringUtils.isBlank(userId)) { + throw new BusinessException(UserResponseEnum.PASSWORD_INVALID); + } + if (StringUtils.isBlank(devCode)) { + throw new BusinessException(UserResponseEnum.DEV_CODE_WRONG); + } + try { + devCode= AESUtil.aesPKCS5PaddingDecrypt(devCode); + //查看是否存在该用户 + AppUser appUser = this.lambdaQuery().eq(AppUser::getUserIndex,userId).one(); + if (Objects.isNull(appUser)){ + throw new BusinessException(UserResponseEnum.LOGIN_USERNAME_NOT_FOUND); + } else { + String appPwd = AESUtil.aesPKCS5PaddingEncrypt(password); + appUser.setPassword(appPwd); + appUser.setDevCode(devCode); + logger.info("更新手机id:" + devCode); + this.updateById(appUser); + } + } catch (Exception e) { + logger.error("app用户设置密码异常:" + e.toString()); + if (e.getMessage().length() < 10) { + throw new BusinessException(UserResponseEnum.getCodeByMsg(e.getMessage())); + } else { + throw new BusinessException(UserResponseEnum.PASSWORD_SET_ERROR); + } + } + } + + @Override + public AppUserResultVO login(String phone, String type, String key, String devCode) { + //参数校验 + if (!PubUtils.match(PatternRegex.PHONE_REGEX, XssFilterUtil.dealString(phone))){ + throw new BusinessException(UserResponseEnum.REGISTER_PHONE_WRONG); + } + if (StringUtils.isBlank(key)) { + throw new BusinessException(UserResponseEnum.KEY_WRONG); + } + if (StringUtils.isBlank(devCode)) { + throw new BusinessException(UserResponseEnum.DEV_CODE_WRONG); + } + AppUserResultVO vo = new AppUserResultVO(); + try { + devCode= AESUtil.aesPKCS5PaddingDecrypt(devCode); + + } catch (Exception e) { + logger.error("app用户设置密码异常:" + e.toString()); + if (e.getMessage().length() < 10) { + throw new BusinessException(UserResponseEnum.getCodeByMsg(e.getMessage())); + } else { + throw new BusinessException(UserResponseEnum.LOGIN_ERROR); + } + } + return vo; + } + + /** + * 自定义获取验证码,固定为字母和数字的组合 + */ + private String getMessageCode() { + String result = ""; + char[] numbers = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + //填充数字 + for (int i = 0; i < 6; i++) { + int numberIndex = new Random().nextInt(10); + result = result + numbers[numberIndex]; + } + return result; + } + + private void judgeCode(String phone, String code, String devCode) { + String key = phone + devCode; + String redisCode = redisUtil.getStringByKey(key); + if (StringUtils.isEmpty(redisCode) || !code.equalsIgnoreCase(redisCode)) { + throw new BusinessException(UserResponseEnum.LOGIN_WRONG_CODE); + } else { + //存在且正确的验证,用完即删 + redisUtil.delete(key); + } + } + +}