话不多说,先上代码:
userservice层代码:
1、发送验证码,使用随机数生成验证码,将验证码放到session域中,并且将验证码发送给手机(这里我是直接将验证码打印到控制台,你们可以掉第三方的发送验证码服务)
@Override
public Result setCode(String phone, HttpSession session) {
//验证手机号格式
if (RegexUtils.isPhoneInvalid(phone)) {
//格式错误
return Result.fail("手机号格式错误");
}
//格式正确,生成验证码,将验证码保存到session中
String code = RandomUtil.randomNumbers(6);
session.setAttribute("code",code);
//发送验证码
System.out.println("验证码是: "+code);
return Result.ok();
}
2、用户登录,这里先从session域中拿到验证码的值并且进行校验,在从数据库中查询手机号如果手机号不存在就新建一个用户,存在就查询。将新建或查询到的用户放到session域中。
@Override
public Result login(LoginFormDTO loginForm, HttpSession session) {
String phone = loginForm.getPhone();
if (RegexUtils.isPhoneInvalid(phone)) {
//格式错误
return Result.fail("手机号格式错误");
}
Object cacheCode = session.getAttribute("code");
String code = loginForm.getCode();
if (cacheCode==null || !cacheCode.toString().equals(code)) {
return Result.fail("验证码输入错误");
}
User user = query().eq("phone", phone).one();
if (user==null) {
user = creatUserByphone(phone);
}
UserDTO userDTO = new UserDTO();
userDTO.setNickName(user.getNickName());
userDTO.setId(user.getId());
userDTO.setIcon(user.getIcon());
session.setAttribute("user",userDTO);
return Result.ok();
}
private User creatUserByphone(String phone) {
User user = new User();
user.setPhone(phone);
user.setNickName(USER_NICK_NAME_PREFIX+RandomUtil.randomString(10));
save(user);
return user;
}
以上就是userservice层的全部代码了,然而这样就结束了吗?并不是,在访问一些主流服务前端页面的时候我们发现有的页面是只有我们登录了才可以进行访问,后端数据也是一样。所以我们要对一些接口加上拦截器,让这些接口只有登录后才可以被访问。
拦截器代码
拦截器,实现服务拦截功能,代码中从请求拿到session,然后在session中拿到user值,不为空则放行。
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
Object user = session.getAttribute("user");
if (user==null) {
return false;
}
UserHolder.saveUser((UserDTO) user);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserHolder.removeUser();
}
}
spring配置,在代码中可以添加你想放行的接口,这里我就放行了登录和获取验证码的接口,你们可以放行一些直接不想拦截的接口。
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.excludePathPatterns(
"/user/login",
"/user/code"
);
}
}
在上面拦截器代码中我们可以发现一个特别的类UserHolder,这是我自己写的工具类。这里的拦截器虽然获得了user对象,但拦截器后面的接口可能还需要用到这个user对象,所以我就就使用了这样一个工具类来,实现对象的传递、我们都知道在tomcat中每一个请求都是一个独立的线程。我们就可以使用Java中的ThreadLocal来实现没一个线程的user数据隔离,使得每个线程都拥有一个user对象,在需要使用的时候,可以在里面拿。下面是工具类,以及controler怎么拿user对象。
public class UserHolder {
private static final ThreadLocal<UserDTO> 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();
}
}
//在control中拿到user对象
@GetMapping("/me")
public Result me(){
UserDTO user = UserHolder.getUser();
// TODO 获取当前登录的用户并返回
return Result.ok(user);
}
到这今天的代码就讲完了,如果有什么地方写的不对,希望大家指正。一起进步。