1、发送邮件
1.1 qq开启smtp
1.2 spring email
导入jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
properties配置
# MailProperties
spring.mail.host=smtp.qq.com
spring.mail.port=465
spring.mail.username=nowcoder@sina.com //邮箱账号
spring.mail.password=nowcoder123 //smtp授权码
spring.mail.protocol=smtps //协议
spring.mail.properties.mail.smtp.ssl.enable=true
工具类
@Component
public class MailClient {
private static final Logger logger = LoggerFactory.getLogger(MailClient.class);
@Autowired
private JavaMailSender mailSender; //java核心组件JavaMailSender
@Value("${spring.mail.username}")
private String from; //发件人
public void sendMail(String to, String subject, String content) {
try {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, true);
mailSender.send(helper.getMimeMessage());
} catch (MessagingException e) {
logger.error("发送邮件失败:" + e.getMessage());
}
}
}
//测试代码
@Autowired
private MailClient mailClient;
@Autowired
private TemplateEngine templateEngine;
@Test
public void testTextMail() {
mailClient.sendMail("**8*@163.com", "TEST", "Welcome.");
}
邮件模板
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>邮件示例</title>
</head>
<body>
<p>欢迎你, <span style="color:red;" th:text="${username}"></span>!</p>
</body>
</html>
2、注册功能
分为注册和激活两个步
2.1 注册
- 在注册页面填写信息(账号、密码、确认密码、邮箱),点击注册
- 之后根据路由(http://localhost:8080/community/register)post提交,之后由相应的controller处理,调用userService判断
- ①提交的表单是否为空
- ②账号是否已存在
- ③邮箱是否已注册
- ④若以上都没,则将调用userMapper该用户存储在数据库中,status设为0,此时还没激活,
- ⑤并给邮箱发送激活邮件,其中包含跳转路径(http://localhost:8080/community/activation/userId/activationCode)
Controller层
@RequestMapping(path = "/register", method = RequestMethod.POST)
public String register(Model model, User user){
Map<String, Object> map = userService.register(user);
if(map == null || map.isEmpty()){
//注册成果,前端提示,并跳转到首页,需要激活
model.addAttribute("msg", "注册成功,我们已经向您的邮箱发送了一封激活邮件,请尽快激活!");
model.addAttribute("target", "/index");
return "/site/operate-result";
}else {
//将消息发送给前端
model.addAttribute("usernameMsg", map.get("usernameMsg"));
model.addAttribute("passwordMsg", map.get("passwordMsg"));
model.addAttribute("emailMsg", map.get("emailMsg"));
return "/site/register";
}
}
Service层
public Map<String, Object> register(User user){
HashMap<String, Object> map = new HashMap<>();
//空值进行判断处理
if(user == null){
throw new IllegalArgumentException("参数不能为空");
}
if(StringUtils.isBlank(user.getUsername())){
//将信息返回给客户端
map.put("usernameMsg", "账号不能为空");
return map;
}
if(StringUtils.isBlank(user.getPassword())){
//将信息返回给客户端
map.put("userPasswordMsg", "密码不能为空");
return map;
}
if(StringUtils.isBlank(user.getEmail())){
//将信息返回给客户端
map.put("emailMsg", "邮箱不能为空");
return map;
}
//输入,业务逻辑判断
//验证账号
User u = userMapper.selectByName(user.getUsername());
if(u != null){
map.put("usernameMsg", "该账号以存在");
return map;
}
//验证邮箱
u = userMapper.selectByEmail(user.getEmail());
if(u != null){
map.put("emailMsg", "该邮箱以被注册");
return map;
}
//用户注册
//密码加密
user.setSalt(CommunityUtil.generateUUID().substring(0,5));
user.setPassword(CommunityUtil.md5(user.getPassword() + user.getSalt()));
user.setType(0);
user.setStatus(0);
user.setActivationCode(CommunityUtil.generateUUID());
user.setHeaderUrl(String.format("http://images.nowcoder.com/head/%dt.png", new Random().nextInt(1000)));
user.setCreateTime(new Date());
userMapper.insertUser(user);
//发送激活邮件
Context context = new Context();
context.setVariable("email", user.getEmail());
//http://localhost:8080/community/activation/userid/激活码
String url = domain + contextPath + "/activation/" + user.getId() + "/" + user.getActivationCode();
context.setVariable("url", url);
//使用模板引擎
String content = templateEngine.process("/mail/activation", context);
mailClient.sendMail(user.getEmail(), "激活账号", content);
return null;
}
2.2 激活
- 用户点击激活邮件里的路径,服务器匹配相应的controller处理用户请求,该controller调用service主要处理:
- ①根据路径中的激活码与userId对应的激活码,返回激活成功、已激活、失败信息
- ②controller根据相应返回值,进行页面跳转
Controller层
@RequestMapping(path = "/activation/{userId}/{code}", method = RequestMethod.GET)
public String activation(Model model, @PathVariable("userId") int userId, @PathVariable("code") String code){
int activation = userService.activation(userId, code);
if(activation == ACTIVATION_SUCCESS){
model.addAttribute("msg", "激活成功");
model.addAttribute("target", "/login"); //激活成功,跳转到登录页面
}else if(activation == ACTIVATION_REPEAT){
model.addAttribute("msg", "无效操作,该账号已被激活");
model.addAttribute("target", "/index");
}else if(activation == ACTIVATION_FAILURE){
model.addAttribute("msg", "激活失败,您提供的激活码不正确!");
model.addAttribute("target", "/index");
}
return "/site/operate-result";
}
Service层
//激活账号
public int activation(int userId, String code){
//用户输入激活码,检查是否与数据库中的一致
User user = userMapper.selectById(userId);
if(user.getStatus() == 1){
//表示已经被激活
return ACTIVATION_REPEAT;
}else if(user.getActivationCode().equals(code)){
//激活成功,将status改为1
userMapper.updateStatus(userId, 1);
return ACTIVATION_SUCCESS;
}else{
//激活失败
return ACTIVATION_FAILURE;
}
}
3、登录
生成验证码
@Configuration
public class KaptchaConfig {
@Bean
public Producer kaptchaProducer() {
Properties properties = new Properties();
properties.setProperty("kaptcha.image.width", "100");
properties.setProperty("kaptcha.image.height", "40");
properties.setProperty("kaptcha.textproducer.font.size", "32");
properties.setProperty("kaptcha.textproducer.font.color", "0,0,0");
properties.setProperty("kaptcha.textproducer.char.string", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYAZ");
properties.setProperty("kaptcha.textproducer.char.length", "4");
properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise");
DefaultKaptcha kaptcha = new DefaultKaptcha();
Config config = new Config(properties);
kaptcha.setConfig(config);
return kaptcha;
}
}
Controller
@RequestMapping(path = "/login", method = RequestMethod.POST)
public String login(String username, String password, String code, boolean rememberme,
Model model, HttpSession session, HttpServletResponse response) {
// 检查验证码
String kaptcha = (String) session.getAttribute("kaptcha");
if (StringUtils.isBlank(kaptcha) || StringUtils.isBlank(code) || !kaptcha.equalsIgnoreCase(code)) {
model.addAttribute("codeMsg", "验证码不正确!");
return "/site/login";
}
// 检查账号,密码
int expiredSeconds = rememberme ? REMEMBER_EXPIRED_SECONDS : DEFAULT_EXPIRED_SECONDS;
Map<String, Object> map = userService.login(username, password, expiredSeconds);
if (map.containsKey("ticket")) {
Cookie cookie = new Cookie("ticket", map.get("ticket").toString());
//整个项目都有效
cookie.setPath(contextPath);
cookie.setMaxAge(expiredSeconds);
response.addCookie(cookie);
return "redirect:/index";
} else {
model.addAttribute("usernameMsg", map.get("usernameMsg"));
model.addAttribute("passwordMsg", map.get("passwordMsg"));
return "/site/login";
}
}
Service
//登录
public Map<String, Object> login(String username, String password, int expiredSeconds) {
Map<String, Object> map = new HashMap<>();
// 空值处理
if (StringUtils.isBlank(username)) {
map.put("usernameMsg", "账号不能为空!");
return map;
}
if (StringUtils.isBlank(password)) {
map.put("passwordMsg", "密码不能为空!");
return map;
}
// 验证账号
User user = userMapper.selectByName(username);
if (user == null) {
map.put("usernameMsg", "该账号不存在!");
return map;
}
// 验证状态
if (user.getStatus() == 0) {
map.put("usernameMsg", "该账号未激活!");
return map;
}
// 验证密码
password = CommunityUtil.md5(password + user.getSalt());
if (!user.getPassword().equals(password)) {
map.put("passwordMsg", "密码不正确!");
return map;
}
// 生成登录凭证
LoginTicket loginTicket = new LoginTicket();
loginTicket.setUserId(user.getId());
loginTicket.setTicket(CommunityUtil.generateUUID());
loginTicket.setStatus(0);
loginTicket.setExpired(new Date(System.currentTimeMillis() + expiredSeconds * 1000));
loginTicketMapper.insertLoginTicket(loginTicket);
map.put("ticket", loginTicket.getTicket());
return map;
}
4、退出
Controller
@RequestMapping(path = "/logout", method = RequestMethod.GET)
public String logout(@CookieValue("ticket") String ticket) {
userService.logout(ticket);
return "redirect:/login";
}
Service
public void logout(String ticket) {
loginTicketMapper.updateStatus(ticket, 1);
}
5、显示登录信息
5.1 拦截器示例
1、定义拦截器,实现 HandlerInterceptor;
@Component
public class AlphaInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(AlphaInterceptor.class);
// 在Controller之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
logger.debug("preHandle: " + handler.toString());
return true;
}
// 在Controller之后执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
logger.debug("postHandle: " + handler.toString());
}
// 在TemplateEngine之后执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
logger.debug("afterCompletion: " + handler.toString());
}
}
2、配置拦截器,为它指定拦截、排除的路径;
3、配置 MVC 的时候要实现 WebMvcConfigurer 这个类才可以;
4、将拦截器注入;
5、重写 addInterceptors 方法
- 将拦截器添加进来: registry.addInterceptor
- 排除所有静态资源:registry.excludePathPatterns
- 设置拦截哪些路径:registry.addPathPatterns
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private AlphaInterceptor alphaInterceptor;
@Autowired
private LoginTicketInterceptor loginTicketInterceptor;
@Autowired
private LoginRequiredInterceptor loginRequiredInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(alphaInterceptor)
.excludePathPatterns("/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg")
.addPathPatterns("/register", "/login");
registry.addInterceptor(loginTicketInterceptor)
.excludePathPatterns("/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg");
registry.addInterceptor(loginRequiredInterceptor)
.excludePathPatterns("/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg");
}
}
测试一下是否拦截成功,index 页面不拦截,登录、注册页面被拦截:
5.2 拦截器应用(使用线程隔离批量处理用户请求)
- 在请求开始时查询登录用户
- 在本次请求中持有用户数据
- 在模板视图上显示用户数据
- 在请求结束时清理用户数据
登录成功时
5.2.1 新建 LoginTicketInterceptor 拦截器
1、将从 cookie 中获取特定信息的方法包装成一个工具类;
public class CookieUtil {
public static String getValue(HttpServletRequest request, String name) {
if (request == null || name == null) {
throw new IllegalArgumentException("参数为空!");
}
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(name)) {
return cookie.getValue();
}
}
}
return null;
}
}
request.getCookies()
;返回的是所有 cookie 信息,我们要从中取我们想要的信息。
2、实现 prehandle 方法:
- 通过 cookie 得到 ticket 信息,用户登录之后会重定向到首页,这时我们可以从第二次请求中获取用户信息;
- 在 prehandle 中只能通过请求 request 来获取 cookie;
- 如果 ticket 不为空,调用 UserService 层去获取该凭证对应的所有登录信息(UserService 层要加一个方法);
- 检查凭证是否有效:LoginTicket 不为空,状态码为0,且有效时长没有超时的情况是有效的,调用 UserService 层查询 user 数据;
@Component
public class LoginTicketInterceptor implements HandlerInterceptor {
@Autowired
private UserService userService;
@Autowired
private HostHolder hostHolder;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 从cookie中获取凭证 cookie从request传过来
String ticket = CookieUtil.getValue(request, "ticket");
if (ticket != null) {
// 查询凭证
LoginTicket loginTicket = userService.findLoginTicket(ticket);
// 检查凭证是否有效
if (loginTicket != null && loginTicket.getStatus() == 0 && loginTicket.getExpired().after(new Date())) {
// 根据凭证查询用户
User user = userService.findUserById(loginTicket.getUserId());
// 在本次请求中持有用户
hostHolder.setUser(user);
}
}
return true;
}
//在thymeleaf模板引擎之前用user,所以需在引用模板引擎之前调用,放入postHandler
//postHandler模板引擎之前调用
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
User user = hostHolder.getUser();
if (user != null && modelAndView != null) {
modelAndView.addObject("loginUser", user);
}
}
//清理数据
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
hostHolder.clear();
}
}
解释:
- 线程隔离存放用户信息,实现 HostHolde r类,使用 ThreadLocal 模拟 session 存放用户信息;
- ThreadLocal 以线程为 key 实现存取值;
- 将 HostHolder 注入,调用其中的 setUser 方法,将用户信息存到某一线程对应的map容器中;
- HostHolder可以持有用户信息,hostHolder.setUser(user);将当前数据存入当前线程对应的map里,只要该请求没有结束,该线程一直在,当请求处理完,服务器向浏览器做出响应之后,该线程被销毁
5.2.2 UserService层
public LoginTicket findLoginTicket(String ticket) {
return loginTicketMapper.selectByTicket(ticket);
}
5.2.3WebMVC拦截器
registry.addInterceptor(loginTicketInterceptor)
.excludePathPatterns("/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg");
5.2.4 html页面
<ul class="navbar-nav mr-auto">
<li class="nav-item ml-3 btn-group-vertical">
<a class="nav-link" th:href="@{/index}">首页</a>
</li>
<li class="nav-item ml-3 btn-group-vertical" th:if="${loginUser!=null}">
<a class="nav-link position-relative" href="site/letter.html">消息<span class="badge badge-danger">12</span></a>
</li>
<li class="nav-item ml-3 btn-group-vertical" th:if="${loginUser==null}">
<a class="nav-link" th:href="@{/register}">注册</a>
</li>
<li class="nav-item ml-3 btn-group-vertical" th:if="${loginUser==null}">
<a class="nav-link" th:href="@{/login}">登录</a>
</li>
<li class="nav-item ml-3 btn-group-vertical dropdown" th:if="${loginUser!=null}">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img th:src="${loginUser.headerUrl}" class="rounded-circle" style="width:30px;"/>
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item text-center" href="site/profile.html">个人主页</a>
<a class="dropdown-item text-center" href="site/setting.html">账号设置</a>
<a class="dropdown-item text-center" th:href="@{/logout}">退出登录</a>
<div class="dropdown-divider"></div>
<span class="dropdown-item text-center text-secondary" th:utext="${loginUser.username}">nowcoder</span>
</div>
</li>
</ul>
5.2.5测试结果
1、登录之前
2、登录之后
3、退出登录
6、账号设置
6.1 上传头像
6.1.1 新建UserController类
@RequestMapping(path = "/setting", method = RequestMethod.GET)
public String getSettingPage() {
return "/site/setting";
6.1.2 测试
6.1.3 配置资源上传的路径(上传头像)
community.path.upload=d:/work/data/upload
我们只在 Controller 中处理上传文件的逻辑,而不调用 service 层,因为 MultipartFile 是表现层 SpringMVC 的一个组件,不要在 service 层调用;
6.1.4 UserService 层
实现更新用户头像方法,即根据用户的 userId 更新用户头像的 url 地址;
public int updateHeader(int userId, String headerUrl) {
return userMapper.updateHeader(userId, headerUrl);
}
6.1.5 UserController 层(客户端到服务器)
- 判断文件是否为空,或者文件格式是否正确;
- 生成随机文件名: 使用生成随机字符串工具类生成 随机字符+后缀 作为文件名
- 确定文件目录是否为空,为空则创建目录;
- 确定文件存放的位置:新建一个 file,其中是上传路径+/+文件名字
- 存储文件:使用 transferTo(File file) 方法传到服务器中;
- 更新当前用户的头像的路径(web访问路径):http://localhost:8080/community/user/header/xxx.png, 调用 UserService 层更新数据库中用户头像的 url 地址;
- 重定向到首页。
@RequestMapping(path = "/upload", method = RequestMethod.POST)
public String uploadHeader(MultipartFile headerImage, Model model) {
if (headerImage == null) {
model.addAttribute("error", "您还没有选择图片!");
return "/site/setting";
}
String fileName = headerImage.getOriginalFilename();
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;
userService.updateHeader(user.getId(), headerUrl);
return "redirect:/index";
}
6.1.6 UserController 层:获取头像(服务器响应给客户端)
@RequestMapping(path = "/header/{fileName}", method = RequestMethod.GET)
public void getHeader(@PathVariable("fileName") String fileName, HttpServletResponse response) {
// 服务器存放路径
fileName = uploadPath + "/" + fileName;
// 文件后缀
String suffix = fileName.substring(fileName.lastIndexOf("."));
// 响应图片
response.setContentType("image/" + suffix);
try (
FileInputStream fis = new FileInputStream(fileName);
OutputStream os = response.getOutputStream();
) {
byte[] buffer = new byte[1024];
int b = 0;
while ((b = fis.read(buffer)) != -1) {
os.write(buffer, 0, b);
}
} catch (IOException e) {
logger.error("读取头像失败: " + e.getMessage());
}
}
6.1.7 测试页面
不上传头像(前端逻辑也过不去)
上传不带文件后缀的文件:
正确上传头像:
6.2 修改密码
6.2.1 UserService 层
实现修改密码功能:
- 空值处理:输入旧密码不能为空,输入的新密码不能为空,输入的新密码的确认密码不能为空;
- 验证状态:
- 判断两次输入的新密码是否一致,验证输入的旧密码是否正确;
- 将用户输入的旧密码使用 MD5 加密算法进行加密得到加密后的密码,将这个密码和当前用户的密码进行比较,如果不一致,代表输入的密码错误
- 使登录凭证失效:
- 调用 DAO 层修改登录凭证状态码为 1 ;
@Override
public Map<String, Object> updatePassword(User user,String oldPassword, String newPassword, String confirmPassword,String ticket) {
Map<String, Object> map = new HashMap<>();
//空值处理
if (StringUtils.isBlank(user.getPassword())) {
map.put("oldPasswordMsg", "请输入您原来的密码!");
return map;
}
if (StringUtils.isBlank(newPassword)) {
map.put("newPasswordMsg", "请输入您的新密码!");
return map;
}
if (StringUtils.isBlank(confirmPassword)) {
map.put("confirmPasswordMsg", "请再次输入您的新密码!");
return map;
}
//两次输入的新密码是否一致
if (!newPassword.equals(confirmPassword)) {
map.put("confirmPasswordMsg", "两次输入密码不一致!");
return map;
}
//验证旧密码是否正确,注册的时候在末尾加盐,这里也一样
oldPassword = CommunityUtil.md5(oldPassword + user.getSalt());
if (!user.getPassword().equals(oldPassword)){
map.put("oldPasswordMsg", "您输入的密码不正确!");
return map;
}
//修改密码
newPassword = CommunityUtil.md5(newPassword + user.getSalt());
userMapper.updatePassword(user.getId(),newPassword);
//修改用户登录状态,修改密码之后让用户重新登陆,所以要将原来的登录状态改为退出
loginTicketMapper.updateStatus(ticket, 1);
return map;
}
6.2.2 UserController 层
- 实现修改密码的功能:
- 从当前线程获取用户信息
- 调用 UserService 层进行密码的校验;
- 根据返回的 map 集合信息判断要跳转的页面,并且显示错误信息,或者修改成功的信息。
//修改密码
@RequestMapping(path = "/update", method = RequestMethod.POST)
public String updatePassword(Model model, String oldPassword,
String newPassword, String confirmPassword,
@CookieValue("ticket") String ticket
) {
User user = hostHolder.getUser();
Map<String, Object> map = userService.updatePassword(user, oldPassword, newPassword, confirmPassword, ticket);
if (map == null || map.isEmpty()) {
model.addAttribute("msg", "密码修改成功,请重新登录!");
model.addAttribute("target", "/login");
return "site/operate-result";
}else {
model.addAttribute("oldPasswordMsg",map.get("oldPasswordMsg"));
model.addAttribute("newPasswordMsg",map.get("newPasswordMsg"));
model.addAttribute("confirmPasswordMsg",map.get("confirmPasswordMsg"));
return "/site/setting";
}
}
7、检查登录状态
在用户没有登录的情况下,拦截一些请求,防止知道访问路径的人可以通过手动修改访问路径去访问一下页面;
常用的元注解(主要定义前两个就可以了):
@Target:定义在类、方法、属性等上面
@Retention:编译时有效or运行时有效
@Document:生成文档的时候要不要带这个注解
@Inherited:子类要不要继承父类的这个注解
如何读取注解:
Method.getDeclaredAnnotations ():获取方法上的所有注解
Method.getAnnotation (Class annotationClass):尝试获取某个类型的注解
7.1 在 annotation 包下新建 LoginRequired 类
1、其中定义一个登录之后才能访问的页面的注解
2、给所有登录后才能访问的方法,加上这个自定义注解(所有关于用户设置的,都要在方法上方加上这个注解,但是获取用户头像不用这个注解,因为在首页的时候要显示所有帖子的用户头像)
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginRequired {
}
7.2 新建 LoginRequiredInterceptor 类
1、注入 Hostholder,获取当前是否有用户信息
2、如果拦截到的是一个方法的话,将他转型
3、从方法上面取对应的自定义注解类型的注解
4、如果获取到了该注解,但是获取到的用户为空,我们就进行拦截,即返回false,同时强制重定向到登录页面
@Component
public class LoginRequiredInterceptor implements HandlerInterceptor {
@Autowired
private HostHolder hostHolder;
//在请求前拦截
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
LoginRequired loginRequired = method.getAnnotation(LoginRequired.class);
if (loginRequired != null && hostHolder.getUser() == null) {
response.sendRedirect(request.getContextPath() + "/login");
return false;
}
}
return true;
}
}
7.3 配置拦截器:
@Autowired
private LoginRequiredInterceptor loginRequiredInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginRequiredInterceptor)
.excludePathPatterns("/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg");
}