功能需求:
springboot登陆页面进行登陆验证,并完成登陆跳转。错误的账户提示用户名密码错误,正确的账户跳转到index页面。
同时加上登陆拦截器,对于错误的账户不允许直接访问index页面。
一 登陆验证
实现输入正确的用户名密码直接进入index页面,输入错误提示用户名密码错误。
1. 要实现登录,我们需要先编写一个登录的controller类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42package com.example.demo.controller; import org.springframework.stereotype.Controller; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import javax.servlet.http.HttpSession; import java.util.Map; @Controller public class LoginController { @RequestMapping("login") public String tologin() { return "login"; } @PostMapping(value="/login") public String login(@RequestParam("username") String username, @RequestParam("password") String password, Map<String,Object> map, HttpSession session){ //验证用户名和密码,输入正确,跳转到index if(!StringUtils.isEmpty(username)&&"lss".equals(password)){ session.setAttribute("userName",username); System.out.println("username===" + username); return "redirect:/index"; } else //输入错误,清空session,提示用户名密码错误 { session.invalidate(); map.put("msg","用户名密码错误"); return "login"; } } @RequestMapping("index") public String goIndex(Map<String,Object> map) { map.put("name","lishanshan"); map.put("age",29); map.put("sex","女"); return "index"; } }
说明:
(1) 跳转页面时使用 return ”redirect:/ index“,而不是 return ”index“ .
return ”redirect:/ index“,会直接调用controller, return ”index“ 只会访问目录下的文件
2. 登陆页面 login.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="description" content=""> <meta name="author" content=""> <title>首页</title> </head> <body> <form th:action="@{/login}" method="post"> <!-- 取值替换原来默认的值--> <h1>Please sign in</h1> <p style="color:#ff0000" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p> <label>Username</label> <input type="text" name="username" placeholder="Username" required="" autofocus=""> <label>Password</label> <input type="password" name="password" placeholder="Password" required=""> <button type="submit" >Sign in</button> </form> </body>
说明:
(1)action 配置为th:action="@{/login}" method="post"
添加th:action,告诉模板,我们要跳转的请求是/login,而且是post请求的;
3.简单index页面
1
2
3
4
5
6
7
8
9
10
11
12
13<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>注册成功</h1> 姓名:<spn th:text="${name}"></spn> 年龄:<spn th:text="${age}"></spn> 性别:<spn th:text="${sex}"></spn> </body> </html>
4. properties配置
1
2server.port=8002 spring.thymeleaf.cache=false
说明:为了开发方便,我们还可以将application.properties中添加一个 禁用缓存的参数: spring.thymeleaf.cache=fasle ,这样html页面有改动的时候,我们只需要用快捷键crtl+F9或者点击如图的编译按钮,重新编译下就可以在页面看结果,而不需要再次启动Tomcat服务了
二. 配置拦截器
我们在不输入用户名密码的时候,在地址栏里直接输入
http://localhost:8002/index也能直接访问地址。这是不允许的。所以需要配置拦截器,当用户密码不正确的时候,页面直接跳转到登陆页面,并显示无权限访问。
1.注册拦截器
新建类 webConfigurer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34package com.example.demo.configure; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfigurer implements WebMvcConfigurer { // 这个方法是用来配置静态资源的,比如html,js,css,等等 @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/"); WebMvcConfigurer.super.addResourceHandlers(registry); } // 这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效 @Override public void addInterceptors(InterceptorRegistry registry) { // addPathPatterns("/**") 表示拦截所有的请求, // excludePathPatterns("/login", "/register") 表示除了登陆与注册之外,因为登陆注册不需要登陆也可以访问 registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**").excludePathPatterns("/login"); WebMvcConfigurer.super.addInterceptors(registry); } //设置默认页面 @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("forward:/login"); //设置优先级 当请求地址有重复的时候 执行优先级最高的 registry.setOrder(Ordered.HIGHEST_PRECEDENCE); WebMvcConfigurer.super.addViewControllers(registry); } }
2.拦截器
实现 HandlerInterceptor
三个方法分别是
- 1.preHandle:在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制、权限校验等处理;
- 2.postHandle:在业务处理器处理请求执行完成后,生成视图之前执行。后处理(调用了Service并返回ModelAndView,但未进行页面渲染),有机会修改ModelAndView (这个博主就基本不怎么用了);
- 3.afterCompletion:在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面); 复制代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42package com.example.demo.configure; import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; @Component public class LoginInterceptor implements HandlerInterceptor { //这个方法是在访问接口之前执行的,我们只需要在这里写验证登陆状态的业务逻辑,就可以在用户调用指定接口之前验证登陆状态了 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException, ServletException { //每一个项目对于登陆的实现逻辑都有所区别,我这里使用最简单的Session提取User来验证登陆。 HttpSession session = request.getSession(); //这里的User是登陆时放入session的 //如果session中没有user,表示没登陆 Object user = request.getSession().getAttribute("userName"); System.out.println("preHandle----" + user + " ::: " + request.getRequestURL()); if (user == null) { request.setAttribute("msg","无权限请先登录"); // 获取request返回页面到登录页 request.getRequestDispatcher("/login").forward(request, response); //response.sendRedirect("/login"); return false; } else { //如果session里有user,表示该用户已经登陆,放行,用户即可继续调用自己需要的接口 System.out.println("进入拦截器......"); System.out.println(request.getRequestURL()); return true; } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { } }
上边配置的session需要取值才能做判断,那么我们需要在loginController中设置这个session值,以让它生效: session.setAttribute("userName",username);
补充:请求转发与请求重定向的区别
请求重定向和转发
1、请求重定向:浏览器的行为(通过响应对象HttpServletResponse来执行)
特点:可以重新定向访问其他Web应用下的资源
浏览器发出了2次请求,得到了2次响应
地址栏地址会变,跳转到要求指定的Servlet
代码演示:
//请求重定向方式一:
1
2
3
4
5public void sent1(HttpServletResponse response) { response.setStatus(302); response.setHeader("Location", "/ServletStudy/servlet/ServletDemo2"); //这个地址是要求浏览器重新访问的。 }
//请求重定向方式二:
1
2
3
4
5
6
7
8public void send2(HttpServletRequest request,HttpServletResponse response) throws IOException { //服务器向访问的浏览器的请求中添加属性,当被请求重定向后,在新的Servlet中不能得到添加的属性。 //因为请求重定向后的请求request对象不懂,这就是request的生命周期。 request.setAttribute("name", "zhangsan"); //与方式一实现的原理相同,较为常用 response.sendRedirect("/ServletStudy/servlet/ServletDemo2"); }
2、请求转发:服务器的行为(转发的瞬间是一个ServletRequest的生命周期)
特点:转发只能发生在当前Web应用下
浏览器发出了1次请求,得到了1次响应
(源组件和目标组件共享request和response中的数据)
地址栏地址不会发生变化。
应用:
(1)可以利用request的域对象的特点,由源组件向其中存放写数据。
(2)可以让用户访问到存放在WEB-INF目录中的目标资源
代码演示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23//请求转发 public void send3(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException{ //在请求转发之前进行属性添加,在新的Servlet资源中能获取这个属性 request.setAttribute("name", "zhangsan"); //获取当前Servlet资源的转发器对象RequestDispatcher,传入当前应用的下要访问的那个Servlet资源 RequestDispatcher rd = getServletContext() .getRequestDispatcher("/servlet/ServletDemo2"); //注意:传入的要访问的Servlet资源的地址中/代表的就是当前应用,所以就可以访问当前应用中WEB-INF中的信息 rd = getServletContext() .getRequestDispatcher("/WEB-INF/form.html"); //也可以通过request得到转发器对象,用request得到的转发器在传入路径时,可以传入相对路径,不用加/ rd = request.getRequestDispatcher("/servlet/ServletDemo2"); //这里传入的路径地址:相对去被转发地址不同地方 //被转发地址: http://localhost:8080/ServletStudy/servlet/ServletDemo1 //转发地址: http://localhost:8080/ServletStudy/servlet/ServletDemo2 //所以填写相对资源地址:ServletDemo2 rd = request.getRequestDispatcher("ServletDemo2"); //调用转发器的forward()方法,进行请求转发 rd.forward(request, response); }
3.RequestDispatcher中forward()转发和include()包含的区别
forword()转发:源组件<--->头+体
源组件转向目标组件,由目标组件显示响应正文结果(只有目标的响应)
转发前,容器会清空response对象的缓存,源组件的任何页面输出都无效,也就是会清空源组件的体
转发前不要刷新或关闭response的流
include()包含:
源组件包含目标组件,由源组件显示响应正文结果(还会把目标的响应结果包含进来)
包含前,容器会清空目标组件设置的响应头信息,目标组件所有设置的所有头都无效。
代码演示:
//RequestDispatch转发器中的:forward()和include()方法的区别
/*forword()转发:
源组件转向目标组件,由目标组件显示响应结果(只有目标的响应)
转发前,容器会清空response对象的缓存,源组件的任何页面输出都无效。
转发前不要刷新或关闭response的流
include()包含:
源组件包含目标组件,由源组件显示响应结果(还会把目标的响应结果包含进来)
包含前,容器会清空目标组件设置的响应头信息,目标组件所有设置的所有头都无效*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24public class ServletDemo3 extends HttpServlet { //当做源组件 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { forwardTest(request, response); } public void forwardTest(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { //response.setHeader("Refresh", "2"); OutputStream out = response.getOutputStream(); System.out.println("转发前向控制台输出"); out.write("转发前向页面输出".getBytes()); RequestDispatcher rd = request.getRequestDispatcher("ServletDemo4"); rd.forward(request, response); System.out.println("转发后向控制台输出"); out.write("转发后向页面输出".getBytes()); } public class ServletDemo4 extends HttpServlet { //当做目标组件 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setHeader("Refresh", "2"); response.getOutputStream().write("目标组件".getBytes()); }
4.ServletContext和ServletRequest都能得到RequestDispatcher区别
(1)ServletContext
RequestDispatcher getRequestDispatcher(String path):path必须以"/"开头,代表当前的应用。这种写法,叫做绝对路径写法。
(2)ServletRequest
RequestDispatcher getRequestDispatcher(String path):
path可以以"/"开头:代表当前的应用。这种写法,叫做绝对路径写法。
也可以不以"/"开头:代表相对路径。
5.各种URL的写法:绝对路径和相对路径,建议大家使用绝对路径
绝对路径:如:/day05 地址前加了/就是一个绝对路径
原则:要不要加应用名称,看地址为谁服务的?
如果是给服务器用的,就不用加/MyApp,"/"代表的是当前应用。
如果是给客户端用的,要加上"/MyApp","/"代表的是要访问的服务器的URL地址(域名+端口),
getRequestDispatcher(String path):
path是一个路径。 不要加"/MyApp",只需要"/"即可
form action="url":要加"/MyApp"
a href="url":要加"/MyApp"
img src="url":要加"/MyApp"
link href="url":要加"/MyApp"
script src="url":要加"/MyApp"
302+Location="url":要加"/MyApp"
最后
以上就是笑点低大船最近收集整理的关于springboot实现登录功能和拦截器功能实例功能需求:补充:请求转发与请求重定向的区别的全部内容,更多相关springboot实现登录功能和拦截器功能实例功能需求:补充:请求转发与请求重定向内容请搜索靠谱客的其他文章。
发表评论 取消回复