为什么要检查登录状态
没有登录是 看不到个人设置相关内容。
但是万一有人知道用户设置相关路径,直接点击路径 就可以尽情修改个人设置
如:
即使没有登录,但仍然可以访问这个界面,编辑用户信息,
这是系统的漏洞,有较大安全隐患。
所以,要保证 没要登录的时候,一定访问不了这个页面。
需要在服务端判断,如果状态是登录,则可以访问这个页面,否则不可以。
所以需要使用:
@target 用来声明自定义的注解 在哪个位置,作用在哪种类型上(类or方法)。
@retention 声明自定义注解 保留时间,有效时间(编译时有效or 运行时有效)
@document 声明自定义注解在 生成文档的时候 要不要带上此 注解
@inherited 用于继承
因此新建一个 annotation包,在此包下 新建一个“注解”。
package com.nowcoder.community.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)// 拦截类型METHOD,方法
@Retention(RetentionPolicy.RUNTIME)//注解有效时长,程序运行时有效
public @interface LoginRequired {
}
在UserController中的getSettingPage,uploadHeader前 添加自定义的注解
@LoginRequired
@RequestMapping(path = "/setting", method = RequestMethod.GET)//设置方法访问路径,和访问方式
public String getSettingPage() {
return "/site/setting";
}//返回路径
@LoginRequired
@RequestMapping(path = "/upload", method = RequestMethod.POST)//上传必须为POST 请求
public String uploadHeader(MultipartFile headerImage, Model model) {
if (headerImage == null) {
model.addAttribute("error", "您还没有选择图片!");
return "/site/setting";
}
//读取图片后缀,是jpg,png还是什么
String fileName = headerImage.getOriginalFilename();//读取原始文件名fileName
String suffix = fileName.substring(fileName.lastIndexOf("."));//原始文件名 最后一个点 的索引 之后的
if (StringUtils.isBlank(suffix)) {//如果后缀为空
model.addAttribute("error", "文件的格式不正确!");
return "/site/setting";
}
// 生成随机文件名
fileName = CommunityUtil.generateUUID() + suffix;
// 确定文件存放的路径
File dest = new File(uploadPath + "/" + fileName);
try {
// 存储文件
headerImage.transferTo(dest);
} catch (IOException e) {
logger.error("上传文件失败: " + e.getMessage());
throw new RuntimeException("上传文件失败,服务器发生异常!", e);
}
// 更新当前用户的头像的路径(web访问路径)
// http://localhost:8080/community/user/header/xxx.png
User user = hostHolder.getUser();//获取当前用户
String headerUrl = domain + contextPath + "/user/header/" + fileName;//允许外界访问的web路径;domain=http://localhost:8080;contextPath=community;
userService.updateHeader(user.getId(), headerUrl);//把当前用户的id、更新以后的headerUrl传入
return "redirect:/index";//更新成功后跳至首页
}
下面将使用拦截器 尝试拦截 自带注解的方法
在interceptor目录下,写一个拦截器LoginRequiredInterceptor。
package com.nowcoder.community.controller.interceptor;
import com.nowcoder.community.annotation.LoginRequired;
import com.nowcoder.community.util.HostHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
@Component
public class LoginRequiredInterceptor implements HandlerInterceptor {
@Autowired
private HostHolder hostHolder;
@Override//重写preHandle 以判断有无登录。
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//Object handler是我们拦截的目标
if (handler instanceof HandlerMethod) {//判断handler是否为HandlerMethod类型
HandlerMethod handlerMethod = (HandlerMethod) handler;//把Object 类型转变为 HandlerMethod类型,方便获取其内容
Method method = handlerMethod.getMethod();//获取其拦截到的方法
LoginRequired loginRequired = method.getAnnotation(LoginRequired.class);//尝试取方法中的注解
if (loginRequired != null && hostHolder.getUser() == null) {//loginRequired != null意味着 该方法需要登录 然后才能使用。hostHolder.getUser() == null表示没有登录。
response.sendRedirect(request.getContextPath() + "/login");//因为没有登录,因此强制返回登录界面
return false;//因此返回false,拒绝后续请求
}
}
return true;
}
}
拦截器要在WebMvcConfig中进行配置:
配置目的:把静态资源的请求排除掉,因为不需要拦截静态资源的请求,仅仅是浪费效率。
registry.addInterceptor(loginRequiredInterceptor)
.excludePathPatterns("/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg");
}
其他资源都要处理,但是我们人为的挑选了 有注解的进行处理。
我们希望处理谁,就在其上面加注解。
全部设置完毕后,发现当我们访问之前界面,自动跳到 登录界面。
第二章登录模块主要的功能就此完成