2024.3.25 Monday
Contents
- 9. Interceptor
- 9.1. Overview
- 9.2. Custom Interceptor
- 9.3. Verifying User Login (Authentication)
9. Interceptor
9.1. Overview
- SpringMVC’s handler interceptors are similar to the filters in Servlet development, used for preprocessing and postprocessing of handlers. Developers can define their own interceptors to implement specific functionalities.
- Difference between filters and interceptors: Interceptors are a specific application of AOP (Aspect-Oriented Programming) ideas.
- Filters
- Part of the Servlet specification, usable by any Java web project
- After configuring with url-pattern as /*, it can intercept all resources that are accessed
- Interceptors
- Interceptors are specific to the SpringMVC framework, only projects using SpringMVC can utilize interceptors
- Interceptors only intercept visits to controller methods, accessing jsp/html/css/image/js will not be intercepted
9.2. Custom Interceptor
9.2.1. How to Implement an Interceptor
Customize a class and then extend the HandlerInterceptor
interface
9.2.2. Create a module
9.2.2.1. Create a springmvc-07-interceptor module
9.2.2.2. Add web support
The location and content of web.xml are the same as in springmvc-06-ajax
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--Bind configuration file-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<!--Load on startup-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param> <!--Solve garbled text-->
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern> <!--Filter all requests-->
</filter-mapping>
</web-app>
9.2.2.3. Add applicationContext.xml, create a controller folder
The location is the same as web.xml in springmvc-06-ajax, the content is only path-modified
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- Automatically scan the specified package, manage all annotated classes in IOC container -->
<context:component-scan base-package="P27.controller"/>
<!--Static resource filter-->
<mvc:default-servlet-handler />
<mvc:annotation-driven/>
<!-- View resolver -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- Prefix -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- Suffix -->
<property name="suffix" value=".jsp" />
</bean>
</beans>
9.2.2.4. Add jar packages
9.2.2.5. Configure Tomcat
9.2.3. Create TestController.java
package P27.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@GetMapping("/t1")
public String test(){
System.out.println("TestController/test() is running");
return "done";
}
}
Verify spring configuration is successful
http://localhost:8080/springmvc_07_interceptor_war_exploded/t1
Server column output
9.2.4. Create MyInterceptor.java and MyFilter.java
9.2.4.1. MyFilter must implement three methods
9.2.4.2. MyInterceptor does not require it, here to rewrite for experience
Use Ctrl+O (shortcut) to insert three methods
package P27.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
// Before the request handler method is executed
// If return true then execute the next interceptor
// If return false then do not execute the next interceptor
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("------------preHandle before processing------------");
return true;
}
// After the request handler method is executed
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("------------postHandle after processing------------");
}
// After dispatcherServlet processing is complete, used for cleanup
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("------------afterCompletion cleanup------------");
}
}
9.2.5. Modify applicationContext.xml (add interceptor configuration)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- Automatically scan the specified package, all annotated classes under it are managed by the IOC container -->
<context:component-scan base-package="P27.controller"/>
<!--Static resource filtering-->
<mvc:default-servlet-handler />
<mvc:annotation-driven/>
<!-- View resolver -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- Prefix -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- Suffix -->
<property name="suffix" value=".jsp" />
</bean>
<!-- Interceptor configuration -->
<mvc:interceptors>
<mvc:interceptor>
<!--"/**" includes all requests under this one, all will be intercepted-->
<!--The following two lines are examples: "/admin/*" intercepts things like /admin/add etc., /admin/add/user won't be intercepted-->
<!--"/admin/**" intercepts all under /admin/-->
<mvc:mapping path="/**"/>
<!--Define the class to be filtered-->
<bean class="P27.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
9.2.6. Modify index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Test1$</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/t1">Interceptor Test</a>
</body>
</html>
9.2.7. Run
Access the base URL of the project to see the initial page:
http://localhost:8080/springmvc_07_interceptor_war_exploded/
When accessing the /t1 endpoint:
http://localhost:8080/springmvc_07_interceptor_war_exploded/t1
Server output:
9.2.7.1. Modify MyInterceptor
Change the return value of the preHandle
function to false
to intercept the request, then:
Server output:
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("------------preHandle before processing------------");
// return true;
return false;
}
9.3. Verifying User Login (Authentication)
9.3.1. Implementation Idea
- Have a login page and write a controller to access it.
- The login page has a form submission action. It needs to be processed in the controller. Check if the username and password are correct. If correct, write user information into the session. Return login success.
- Intercept user requests, determine if the user is logged in. If the user is already logged in, proceed; if not, redirect to the login page.
9.3.2. Create the login page login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Login Page</title>
</head>
<body>
<%--Pages or resources under WEB-INF can only be accessed through controllers or servlets--%>
<h1>Login Page</h1>
<form action="${pageContext.request.contextPath}/user/login" method="post">
Username: <input type="text" name="username">
Password: <input type="password" name="pwd">
<input type="submit" value="SUBMIT">
</form>
</body>
</html>
9.3.3. Create LoginController.java to handle requests
package P27.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;
@Controller
@RequestMapping("/user")
public class LoginController {
// Redirect to login page
@RequestMapping("/jumplogin")
public String jumpLogin() throws Exception {
return "login";
}
// Redirect to success page
@RequestMapping("/jumpSuccess")
public String jumpSuccess() throws Exception {
return "success";
}
// Login submission
@RequestMapping("/login")
public String login(HttpSession session, String username, String pwd) throws Exception {
// Record user identity information in session
System.out.println("Receiving from frontend ===" + username);
session.setAttribute("user", username);
return "success";
}
// Logout
@RequestMapping("logout")
public String logout(HttpSession session) throws Exception {
// Invalidate the session
session.invalidate();
return "login";
}
}
9.3.4. Create LoginInterceptor.java
package P27.interceptor;
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;
public class LoginInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("uri: " + request.getRequestURI());
// Determine the login situation: If the Session is not null, return true
// Allow passing
// 1. When on the login page
if (request.getRequestURI().contains("login")){
return true;
}
HttpSession session = request.getSession();
// 2. When already logged in
if (session.getAttribute("user")!=null){
return true;
}
// Do not allow passing
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response);
return false;
}
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
9.3.5. Create success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>Login Successful Page</h1>
<hr>
<h1><a href="${pageContext.request.contextPath}/index.jsp">TO HOME PAGE</a></h1>
<h1><a href="${pageContext.request.contextPath}/user/logout">EXIT</a></h1>
</body>
</html>
9.3.6. Modify index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Verify Information</title>
</head>
<body>
<h1>HOME PAGE</h1>
<hr>
<h1><a href="${pageContext.request.contextPath}/user/jumplogin">Login Page</a> </h1>
<h1><a href="${pageContext.request.contextPath}/user/jumpSuccess">User Page</a> </h1>
</body>
</html>
9.3.7. Register the Interceptor in the Spring MVC Configuration File
(Very similar to the modification in 9.2.5. applicationContext.xml, only the path is different)
Add the following code to the corresponding position in the diagram
<!--AJAX verification if the user is logged in-->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean id="loginInterceptor" class="P27.interceptor.LoginInterceptor"/>
</mvc:interceptor>
9.3.8. Run
http://localhost:8080/springmvc_07_interceptor_war_exploded/
Clicking on any option will redirect to the following page, prompting the user to log in
http://localhost:8080/springmvc_07_interceptor_war_exploded/user/jumplogin
Enter user information and click SUBMIT
Click TO HOME PAGE to return to the main page, where selecting the User Page does not require re-entering user information
http://localhost:8080/springmvc_07_interceptor_war_exploded/user/jumpSuccess
Click EXIT to log out, and you will be automatically redirected to the input information page
This concludes the functionality demonstration. Operations after logging out are completely the same as when not logged in.