当前位置: 首页 > news >正文

公司做网站一定要钱吗国内域名注册平台

公司做网站一定要钱吗,国内域名注册平台,天津搜索引擎优化,怎样黑网站目录 开发准备 注册阿里短信服务 依赖坐标 阿里短信 依赖 mybatis-plus 依赖 redis 依赖 配置文件 导入数据库表 短信发送工具类 生成随机验证码的工具类 校验合法手机号的工具类 ThreadLocal 线程工具类 消息工具类 基于 session 的短信登录的问题 开发教程 Redis 结构设计 … 目录 开发准备 注册阿里短信服务 依赖坐标 阿里短信 依赖 mybatis-plus 依赖  redis 依赖  配置文件 导入数据库表 短信发送工具类 生成随机验证码的工具类 校验合法手机号的工具类 ThreadLocal 线程工具类 消息工具类 基于 session 的短信登录的问题 开发教程 Redis 结构设计 实现效果 代码地址手机短信认证 开发准备 注册阿里短信服务 首先我们需要获取阿里的短信服务进入之后点击国内消息按照流程申请模板即可。详细教程可以参考这篇文章如何注册阿里短信服务 依赖坐标 阿里短信 依赖 dependencygroupIdcom.aliyun/groupIdartifactIdaliyun-java-sdk-core/artifactIdversion4.5.16/version/dependencydependencygroupIdcom.aliyun/groupIdartifactIdaliyun-java-sdk-dysmsapi/artifactIdversion2.1.0/version/dependency mybatis-plus 依赖  dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.4.3/version/dependency redis 依赖  dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactIdversion2.4.0/version /dependency配置文件 server:port: 8081 spring:application:name: hmdpdatasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/hmdp?useSSLfalseuseUnicodetruecharacterEncodingutf8username: rootpassword:redis:host: localhostport: 6379password:lettuce:pool:max-active: 10max-idle: 10min-idle: 1time-between-eviction-runs: 10sjackson:default-property-inclusion: non_null # JSON 处理时忽略非空字段 mybatis-plus:type-aliases-package: com.hmdp.entity # 别名扫描包 logging:level:com.hmdp: debug # 打印日志 注意数据库的信息需要填成你自己的。 导入数据库表 DROP TABLE IF EXISTS tb_user; CREATE TABLE tb_user (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 主键,phone varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 手机号码,password varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT COMMENT 密码加密存储,nick_name varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT COMMENT 昵称默认是用户id,icon varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT COMMENT 人物头像,create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间,update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间,PRIMARY KEY (id) USING BTREE,UNIQUE INDEX uniqe_key_phone(phone) USING BTREE ) ENGINE InnoDB AUTO_INCREMENT 1010 CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci ROW_FORMAT Compact; 短信发送工具类 /*** 短信发送工具类*/ public class SMSUtils {/*** 发送短信* param signName 签名* param templateCode 模板* param phoneNumbers 手机号* param param 参数*/public static void sendMessage(String signName, String templateCode,String phoneNumbers,String param){// 此处需要替换成开发者自己的(在阿里云访问控制台寻找)DefaultProfile profile DefaultProfile.getProfile(cn-hangzhou, 自己的AccessKeyId, 自己的accesskeySecret);IAcsClient client new DefaultAcsClient(profile);SendSmsRequest request new SendSmsRequest();request.setSysRegionId(cn-hangzhou);// 要发送给那个人的电话号码request.setPhoneNumbers(phoneNumbers);// 我们在阿里云设置的签名request.setSignName(signName);// 我们在阿里云设置的模板request.setTemplateCode(templateCode);// 在设置模板的时候有一个占位符request.setTemplateParam({\code\:\param\});try {SendSmsResponse response client.getAcsResponse(request);System.out.println(短信发送成功);}catch (ClientException e) {e.printStackTrace();}}} 生成随机验证码的工具类 public class RandomUtil {public static final String BASE_NUMBER 0123456789;public static final String BASE_CHAR abcdefghijklmnopqrstuvwxyz;public static final String BASE_CHAR_NUMBER abcdefghijklmnopqrstuvwxyz0123456789;public RandomUtil() {}public static ThreadLocalRandom getRandom() {return ThreadLocalRandom.current();}public static SecureRandom createSecureRandom(byte[] seed) {return null seed ? new SecureRandom() : new SecureRandom(seed);}public static SecureRandom getSecureRandom() {return getSecureRandom((byte[])null);}public static SecureRandom getSecureRandom(byte[] seed) {return createSecureRandom(seed);}public static SecureRandom getSHA1PRNGRandom(byte[] seed) {SecureRandom random;try {random SecureRandom.getInstance(SHA1PRNG);} catch (NoSuchAlgorithmException var3) {NoSuchAlgorithmException e var3;throw new UtilException(e);}if (null ! seed) {random.setSeed(seed);}return random;}public static SecureRandom getSecureRandomStrong() {try {return SecureRandom.getInstanceStrong();} catch (NoSuchAlgorithmException var1) {NoSuchAlgorithmException e var1;throw new UtilException(e);}}public static Random getRandom(boolean isSecure) {return (Random)(isSecure ? getSecureRandom() : getRandom());}public static boolean randomBoolean() {return 0 randomInt(2);}public static char randomChinese() {return (char)randomInt(19968, 40959);}public static int randomInt(int min, int max) {return getRandom().nextInt(min, max);}public static int randomInt() {return getRandom().nextInt();}public static int randomInt(int limit) {return getRandom().nextInt(limit);}public static long randomLong(long min, long max) {return getRandom().nextLong(min, max);}public static long randomLong() {return getRandom().nextLong();}public static long randomLong(long limit) {return getRandom().nextLong(limit);}public static double randomDouble(double min, double max) {return getRandom().nextDouble(min, max);}public static double randomDouble(double min, double max, int scale, RoundingMode roundingMode) {return NumberUtil.round(randomDouble(min, max), scale, roundingMode).doubleValue();}public static double randomDouble() {return getRandom().nextDouble();}public static double randomDouble(int scale, RoundingMode roundingMode) {return NumberUtil.round(randomDouble(), scale, roundingMode).doubleValue();}public static double randomDouble(double limit) {return getRandom().nextDouble(limit);}public static double randomDouble(double limit, int scale, RoundingMode roundingMode) {return NumberUtil.round(randomDouble(limit), scale, roundingMode).doubleValue();}public static BigDecimal randomBigDecimal() {return NumberUtil.toBigDecimal(getRandom().nextDouble());}public static BigDecimal randomBigDecimal(BigDecimal limit) {return NumberUtil.toBigDecimal(getRandom().nextDouble(limit.doubleValue()));}public static BigDecimal randomBigDecimal(BigDecimal min, BigDecimal max) {return NumberUtil.toBigDecimal(getRandom().nextDouble(min.doubleValue(), max.doubleValue()));}public static byte[] randomBytes(int length) {byte[] bytes new byte[length];getRandom().nextBytes(bytes);return bytes;}public static T T randomEle(ListT list) {return randomEle(list, list.size());}public static T T randomEle(ListT list, int limit) {if (list.size() limit) {limit list.size();}return list.get(randomInt(limit));}public static T T randomEle(T[] array) {return randomEle(array, array.length);}public static T T randomEle(T[] array, int limit) {if (array.length limit) {limit array.length;}return array[randomInt(limit)];}public static T ListT randomEles(ListT list, int count) {ListT result new ArrayList(count);int limit list.size();while(result.size() count) {result.add(randomEle(list, limit));}return result;}public static T ListT randomEleList(ListT source, int count) {if (count source.size()) {return ListUtil.toList(source);} else {int[] randomList ArrayUtil.sub(randomInts(source.size()), 0, count);ListT result new ArrayList();int[] var4 randomList;int var5 randomList.length;for(int var6 0; var6 var5; var6) {int e var4[var6];result.add(source.get(e));}return result;}}public static T SetT randomEleSet(CollectionT collection, int count) {ArrayListT source CollUtil.distinct(collection);if (count source.size()) {throw new IllegalArgumentException(Count is larger than collection distinct size !);} else {SetT result new LinkedHashSet(count);int limit source.size();while(result.size() count) {result.add(randomEle((List)source, limit));}return result;}}public static int[] randomInts(int length) {int[] range ArrayUtil.range(length);for(int i 0; i length; i) {int random randomInt(i, length);ArrayUtil.swap(range, i, random);}return range;}public static String randomString(int length) {return randomString(abcdefghijklmnopqrstuvwxyz0123456789, length);}public static String randomStringUpper(int length) {return randomString(abcdefghijklmnopqrstuvwxyz0123456789, length).toUpperCase();}public static String randomStringWithoutStr(int length, String elemData) {String baseStr abcdefghijklmnopqrstuvwxyz0123456789;baseStr StrUtil.removeAll(baseStr, elemData.toCharArray());return randomString(baseStr, length);}public static String randomNumbers(int length) {return randomString(0123456789, length);}public static String randomString(String baseString, int length) {if (StrUtil.isEmpty(baseString)) {return ;} else {StringBuilder sb new StringBuilder(length);if (length 1) {length 1;}int baseLength baseString.length();for(int i 0; i length; i) {int number randomInt(baseLength);sb.append(baseString.charAt(number));}return sb.toString();}}public static char randomNumber() {return randomChar(0123456789);}public static char randomChar() {return randomChar(abcdefghijklmnopqrstuvwxyz0123456789);}public static char randomChar(String baseString) {return baseString.charAt(randomInt(baseString.length()));}/** deprecated */Deprecatedpublic static Color randomColor() {Random random getRandom();return new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));}public static T WeightRandomT weightRandom(WeightRandom.WeightObjT[] weightObjs) {return new WeightRandom(weightObjs);}public static T WeightRandomT weightRandom(IterableWeightRandom.WeightObjT weightObjs) {return new WeightRandom(weightObjs);}public static DateTime randomDay(int min, int max) {return randomDate(DateUtil.date(), DateField.DAY_OF_YEAR, min, max);}public static DateTime randomDate(Date baseDate, DateField dateField, int min, int max) {if (null baseDate) {baseDate DateUtil.date();}return DateUtil.offset((Date)baseDate, dateField, randomInt(min, max));} }校验合法手机号的工具类 public abstract class RegexPatterns {/*** 手机号正则*/public static final String PHONE_REGEX ^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\\d{8}$;/*** 邮箱正则*/public static final String EMAIL_REGEX ^[a-zA-Z0-9_-][a-zA-Z0-9_-](\\.[a-zA-Z0-9_-])$;/*** 密码正则。4~32位的字母、数字、下划线*/public static final String PASSWORD_REGEX ^\\w{4,32}$;/*** 验证码正则, 6位数字或字母*/public static final String VERIFY_CODE_REGEX ^[a-zA-Z\\d]{6}$;} public class RegexUtils {/*** 是否是无效手机格式* param phone 要校验的手机号* return true:符合false不符合*/public static boolean isPhoneInvalid(String phone){return mismatch(phone, RegexPatterns.PHONE_REGEX);}/*** 是否是无效邮箱格式* param email 要校验的邮箱* return true:符合false不符合*/public static boolean isEmailInvalid(String email){return mismatch(email, RegexPatterns.EMAIL_REGEX);}/*** 是否是无效验证码格式* param code 要校验的验证码* return true:符合false不符合*/public static boolean isCodeInvalid(String code){return mismatch(code, RegexPatterns.VERIFY_CODE_REGEX);}// 校验是否不符合正则格式private static boolean mismatch(String str, String regex){if (StrUtil.isBlank(str)) {return true;}return !str.matches(regex);} }ThreadLocal 线程工具类 public class UserHolder {private static final ThreadLocalUserDTO tl new ThreadLocal();public static void saveUser(UserDTO user){tl.set(user);}public static UserDTO getUser(){return tl.get();}public static void removeUser(){tl.remove();} }消息工具类 Data NoArgsConstructor AllArgsConstructor public class Result {private Boolean success;private String errorMsg;private Object data;private Long total;public static Result ok(){return new Result(true, null, null, null);}public static Result ok(Object data){return new Result(true, null, data, null);}public static Result ok(List? data, Long total){return new Result(true, null, data, total);}public static Result fail(String errorMsg){return new Result(false, errorMsg, null, null);} } 基于 session 的短信登录的问题 多台 tomcat 并不共享 session 存储空间当请求切换到不同服务器会导致数据丢失问题。虽然可以用 tomcat 间的数据同步解决这个问题但还是会出现数据不一致和占用内存问题。 session 代替方案应该满足 数据共享内存存储keyvalue结构 使用 redis 代替 session 是完全可以的 开发教程 Redis 结构设计 1之前的生成验证码后我们会将其存放在 Session 中每一个不同的请求就会对应一个 Session它们 SessionID 肯定是唯一的。因为我们的程序上线面对的是庞大用户量。在高并发的场景下生成的验证码是有可能相同的如果使用验证码作为 key那么就会造成数据覆盖。         所以我们使用手机号作为key验证码作为value这样保证key的唯一性。从而保证我们的数据安全。 2登入注册时创建用户用户信息需要保存到 Redis 中此时的 key 建议用一个随机的 token建议不要用手机号码因为之后这个 token 会传入前端有泄露风险value 存放用户信息。所以这里返回 token 给客户端为的就是之后在校验的时候可以拿着 token 去 Redis 中取数据进行校验。 3之前的登入校验是 Session 与 Cookie当使用了 Session它会自动将 SessionID 传入 Cookie 中每次请求都会携带 Cookie就相当于带着 SessionID 去查找用户。         而现在是用请求中携带的 token 去 Redis 中获取用户数据。 4 Redis 中的 String 与 Hash 结构都能对用户信息进行存储但是考虑到内存的占用Hash 结构无疑是最好的。 5Redis 是基于内存的而我们知道内存的空间是十分有限的那么用户退出系统了还需要保留用户的 token 吗。答案肯定是不需要的。那么我们就需要设置 token 的有效期。我们不能设置了 token 有效期就高枕无忧了还需要判断当前用户是否还在使用。如果用户还在使用而你的 token 有限期恰恰失效了那么这就是一个不合格的系统。我们可以使用一个拦截器判断当前用户是否还在使用如果正在使用就刷新 token。 Controller /*** 发送手机验证码*/PostMapping(code)public Result sendCode(RequestParam(phone) String phone, HttpSession session) {// 发送短信验证码并保存验证码return userService.sendCode(phone,session);}/*** 登录功能* param 登录参数包含手机号、验证码或者手机号、密码*/PostMapping(/login)public Result login(RequestBody LoginFormDTO loginForm, HttpSession session){// 实现登录功能return userService.login(loginForm,session);} Service Service public class UserServiceImpl extends ServiceImplUserMapper, User implements IUserService {Resourceprivate StringRedisTemplate stringRedisTemplate;Overridepublic Result sendCode(String phone, HttpSession session) {// 校验手机号if(RegexUtils.isPhoneInvalid(phone)){return Result.fail(手机格式错误);}// 校验符合生成验证码String code RandomUtil.randomNumbers(6);MapString,Object param new HashMap();param.put(code, code);// 保存验证码到 redisstringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY phone, code, LOGIN_CODE_TTL, TimeUnit.MINUTES);// 发送验证码log.debug(发送验证码成功,验证码为:code);String templateCode 【验证码】您的验证码为 code 。3分钟内有效请勿泄露和转发。如非本人操作请忽略此短信。;SMSUtils.sendMessage(东方,templateCode,phone,code);// 返回成功return Result.ok();}Overridepublic Result login(LoginFormDTO loginForm, HttpSession session) {// 校验手机号String phone loginForm.getPhone();if(RegexUtils.isPhoneInvalid(phone)){return Result.fail(手机格式错误);}// 输入验证码String code loginForm.getCode();// 生成的验证码String cacheCode stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY phone);// 校验验证码if(cacheCode null || !cacheCode.equals(code)){// 验证码不一致return Result.fail(验证码不一致);}// 如果一致判断用户是否存在User user query().eq(phone, phone).one();// 用户不存在if(user null){// 创建一个新用户并保存用户信息user createUserWithPhone(phone);}// 随机生成 token 作为登入令牌String token UUID.randomUUID().toString();// 将user对象转化成hashmap存储UserDTO userDTO BeanUtil.copyProperties(user, UserDTO.class);MapString, Object userMap BeanUtil.beanToMap(userDTO, new HashMap(),CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((fieldName, fieldValue) - fieldValue.toString()));// 存储String tokenKey LOGIN_USER_KEY token;stringRedisTemplate.opsForHash().putAll(tokenKey,userMap);// 设置 token 的有效期stringRedisTemplate.expire(tokenKey,CACHE_SHOP_TTL, TimeUnit.MINUTES);return Result.ok(token);} } 拦截器 刷新拦截器 public class RefreshTokenInterceptor implements HandlerInterceptor {private StringRedisTemplate stringRedisTemplate;public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate stringRedisTemplate;}Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1.获取请求头中的tokenString token request.getHeader(authorization);if (StrUtil.isBlank(token)) {return true;}// 2.基于 token 获取 redis 中的用户String key LOGIN_USER_KEY token;MapObject, Object userMap stringRedisTemplate.opsForHash().entries(key);// 3.判断用户是否存在if (userMap.isEmpty()) {return true;}// 5.将查询到的hash数据转为UserDTOUserDTO userDTO BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);// 6.存在保存用户信息到 ThreadLocalUserHolder.saveUser(userDTO);// 7.刷新token有效期stringRedisTemplate.expire(key, LOGIN_USER_TTL, TimeUnit.MINUTES);// 8.放行return true;}Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 移除用户UserHolder.removeUser();} } 登入拦截器 public class LoginInterceptor implements HandlerInterceptor {Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1.判断是否需要拦截ThreadLocal中是否有用户if (UserHolder.getUser() null) {// 没有需要拦截设置状态码response.setStatus(401);// 拦截return false;}// 有用户则放行return true;} } 简单说一下刷新功能         假设此时用户的 token 失效了那么就会被刷新拦截器拦截因为当前用户是在线状态。所以前两条 return 都不会返回直到刷新了有效期才能返回。 配置拦截器 Configuration public class MvcConfig implements WebMvcConfigurer {Resourceprivate StringRedisTemplate stringRedisTemplate;Overridepublic void addInterceptors(InterceptorRegistry registry) {// 登录拦截器registry.addInterceptor(new LoginInterceptor()).excludePathPatterns(/user/code,/user/login).order(1);// token 刷新的拦截器registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).addPathPatterns(/**).order(0);} }当项目中存在多个拦截器那么的执行顺序是根据方法而定的拦截器所有的 preHandle 方法是按照拦截器的 order 升序执行的如果 order  一致则按照添加顺序执行。 静态变量 public static final String LOGIN_CODE_KEY login:code:;public static final Long LOGIN_CODE_TTL 3L;public static final String LOGIN_USER_KEY login:token:;public static final Long LOGIN_USER_TTL 30L; 实现效果 手机号验证登入 Redis 存储到验证码 Redis 存储用户信息
http://www.yingshimen.cn/news/40532/

相关文章:

  • 做网站的害处如何做网站的百科
  • 室内装饰装修资质证书北京seo网站内部优化
  • 本地旅游网站模版优帮云查询数据云查询
  • 建购物网站需要些什么精品课程网站建设情况
  • 商务网站页面设计技术ps做网站大小
  • 网站开发网站制作报价自己做网站用什么软件
  • 国外建设工程网站wordpress模板怎么修改字体
  • 知名响应式网站企业wordpress调试主题
  • 如何建立网站服务器国内vps做网站要备案吗
  • wordpress全站背景图片生成在线
  • 网站设计制作的价格低廉做一个网站平台需要什么
  • 电子商务网站开发原则长沙网站关键词排名推广公司
  • 合肥城乡建设网站首页长沙县网页设计培训
  • 湖州市网站建设公司淘宝电商设计
  • 怎么做创意短视频网站台州市建设监理协会网站
  • 做英文网站可以申请补贴吗做淘宝客需要建网站吗
  • 网站seo诊断工具怎么躲避wordpress审核评论
  • 网站官方认证怎么做信息发布
  • 用ps做的网站样图怎么切南昌市科协网站
  • 卖域名的网站上海网站建设价位
  • 巴南市政建设网站宜昌哪里做网站
  • wordpress_子网站重命名适合小白的室内设计软件
  • m99ww094cn 苍井空做的网站哈尔滨seo优化科技
  • 北京网站建设定制如何制作app课件教程
  • 龙之向导外贸网站东阳市建设局网站
  • 自己做的网站背景怎么设置江西昌宇建设工程公司网站
  • 做婚姻网站流程wordpress使用php版本号
  • 网站建设流程图在线制作wordpress微信登录页面
  • 陕西金顶建设公司网站菏泽网站开发
  • 一个网站同时做竞价和seo机加工订单网