前言
首先登陆界面首先还是基于session实现(我当时也很惊讶,怎么用这个😯,结果看了目录,后面就用Redis和Jwt令牌)可能就是一个过渡吧,先用Session实现一遍,然后才能突出后面的很厉害。其实里面还是有很多小知识点的(Java正则表达式)很值得学习,这个Session实现就当小配角,陪跑🤪我们学。
先来看看概念什么是正则表达式?
对于给定的字符串进行判断,如果字符串符合我们的规则,那么就返回真,否则返回假
先来看一个简单的例子:
java
public static void main(String[] args) {
String str = "oooo";
//matches方法用于对给定正则表达式进行匹配,匹配成功返回true,否则返回false
System.out.println(str.matches("o+")); //+表示对前面这个字符匹配一次或多次,这里字符串是oooo,正好可以匹配
}
🧱 正则基本语法卡片(常用符号)
字符 | 描述 |
---|---|
* | 匹配前面的子表达式零次或多次。例如:zo*能匹配"z"以及"zoo" |
+ | 匹配前面的子表达式一次或多次,例如:zo+ 能匹配"zoo",但不能匹配"z"。 |
* | 匹配前面的子表达式零次或多次。例如:zo*能匹配"z"以及"zoo" |
+ | 匹配前面的子表达式一次或多次,例如:zo+ 能匹配"zoo",但不能匹配"z"。 |
{n} | 前面的字符重复n次, |
{m,n} | 前面的字符重复m到n次 例:\d{8,11} → 8~11个数字 |
^ | 表示"字符串开始 例如:^abc → 必须以 abc 开头 |
$ | 表示"字符串结束,例如:xyz$ → 必须以 xyz 结尾。 |
. | 匹配任意一个字符 例如:a.c → 可匹配 abc、a2c |
\d | 匹配一个数字(0-9)例如:\d\d → 匹配两个数字 |
[0-9] | 匹配括号内的任意一个字符,例:[aeiou] → 匹配元音字母 |
[a-z] | 匹配一个小写字母,例: |
[A-Z] | 匹配一个大写字母 |
[3-9] | 前面的字符重复m到n次 |
了解了正则表达式,我们来看看它在具体项目中怎么使用,先来看看实现流程图

其中涉及到了好多细小的知识点,下面我们以代码为例,慢慢展开来看:
UserController类 :
java
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private IUserService userService;
/**
* 发送手机验证码
*/
@PostMapping("code")
public Result sendCode(@RequestParam("phone") String phone, HttpSession session) {
// TODO 发送短信验证码并保存验证码
return userService.sendCode(phone, session);
}
/**
* 登录功能
* @param loginForm 登录参数,包含手机号、验证码;或者手机号、密码
*/
@PostMapping("/login")
public Result login(@RequestBody LoginFormDTO loginForm, HttpSession session){
// TODO 实现登录功能
return userService.login(loginForm, session);
}
IUserService 接口:
java
package com.hmdp.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hmdp.dto.LoginFormDTO;
import com.hmdp.dto.Result;
import com.hmdp.entity.User;
import javax.servlet.http.HttpSession;
/**
* <p>
* 服务类
* </p>
*
* @author 虎哥
* @since 2021-12-22
*/
public interface IUserService extends IService<User> {
Result sendCode(String phone, HttpSession session);
Result login(LoginFormDTO loginForm, HttpSession session);
}
IUserService 接口实现类:
java
package com.hmdp.service.impl;
import...
/**
* <p>
* 服务实现类
* </p>
*
* @author 虎哥
* @since 2021-12-22
*/
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
public Result sendCode(String phone, HttpSession session) {
//1.校验手机号
if (RegexUtils.isPhoneInvalid(phone)) {
// 2.如果不符合,返回错误信息
return Result.fail("手机号格式错误!");
}
//3.符合,生成验证码
String code = RandomUtil.randomNumbers(6);
//4.保存验证码到session
session.setAttribute("code", code);
//5.发送验证码
System.out.println("发送短信验证码成功,验证码:" + code);
//5.返回ok
return Result.ok();
}
@Override
public Result login(LoginFormDTO loginForm, HttpSession session) {
//1.校验手机号
String phone = loginForm.getPhone();
if (RegexUtils.isPhoneInvalid(phone)) {
// 2.如果不符合,返回错误信息
return Result.fail("手机号格式错误!");
}
//2.校验验证码 不一致直接报错 从session中获取
Object cachecode = session.getAttribute("code");
String code = loginForm.getCode();
if (cachecode == null || !cachecode.toString().equals(code)) {
return Result.fail("验证码错误!");
}
//3.一致,根据手机号查询用户 select * from tb_user where phone = ?
User user = query().eq("phone", phone).one();
//4.判断用户是否存在
if (user == null) {
//5.不存在,创建新用户
user = createUserWithPhone(phone);
}
//6.存在,保存用户信息到session
session.setAttribute("user", BeanUtil.copyProperties(user, UserDTO.class));
return Result.ok();
}
private User createUserWithPhone(String phone) {
//1.创建用户
User user = new User();
user.setPhone(phone);
user.setNickName(USER_NICK_NAME_PREFIX + RandomUtil.randomString(10));
//2.保存用户
save(user);
return user;
}
}
LoginInterceptor类:
java
package com.hmdp.utils;
import...
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1.获取session
HttpSession session = request.getSession();
//2.获取session中的用户
Object user = session.getAttribute("user");
//3.判断用户是否存在
if (user == null) {
//4.不存在,拦截,跳转到登录页面
log.debug("用户已登录,用户:{}", user);
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
return false;
}
//5.存在,保存用户信息到ThreadLocal
UserHolder.saveUser((UserDTO) user);
// 6.放行
return true;
}
java
package com.hmdp.config;
import...
@Configuration
public class MvcConfig implements WebMvcConfigurer {
//配置拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//登录拦截器
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**")
.excludePathPatterns(
"/user/code",
"/user/login",
"/blog/hot",
"/shop/**",
"/shop-type/**",
"/upload/**",
"/voucher/**"
).order(1);
}
}
就是很常见的基于session存储来实现的登陆界面,以及Interceptor拦截器,很简单,之前写苍穹外卖的时候都写过了,所以只总结一些新的东西。
🙌首先就是手机号校验(这里就用到了正则表达式)
java
//1.校验手机号
if (RegexUtils.isPhoneInvalid(phone)) {
// 2.如果不符合,返回错误信息
return Result.fail("手机号格式错误!");
}
是一个来自一个工具类 RegexUtils的方法实现的,它是一个自定义的工具类,用于处理正则表达式 相关的验证。
方法名含义:
- isPhoneInvalid(phone):判断手机号 是否无效
- 如果返回 true → 手机号不合法
- 如果返回 false → 手机号合法
来看看RegexUtils 的源码
java
// 校验是否不符合正则格式
private static boolean mismatch(String str, String regex){
if (StrUtil.isBlank(str)) {
return true;
}
return !str.matches(regex);
}
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}$";
}
💡:这里注意一下因为整个项目是黑马很早之前就推出的,手机号的正则表达式已经不正确,需要改一下
中国的手机号通常是:
总共 11位
必须以 1 开头
第二位一般是 3 4 5 6 7 8 9(目前没有 10x、11x、12x 的公众号段)
后面9位是任意数字
r
^1(3[0-9]|4[579]|5[0-35-9]|6[6]|7[0135678]|8[0-9]|9[89])\d{8}$
我们拆解一下:
(3[0-9]) → 130~139
(4[579]) → 145、147、149
(5[0-35-9]) → 150153、155159(跳过154)
(6[6]) → 166
(7[0135678]) → 170、171、173、175、176、177、178
(8[0-9]) → 180~189
(9[89]) → 198、199
小白啊!!!写的不好轻喷啊🤯如果觉得写的不好,点个赞吧🤪(批评是我写作的动力)
...。。。。。。。。。。。...
...。。。。。。。。。。。...