SSM framework construction process
spring+springMVC+MyBatis
Preparation tools:
idea enterprise version + Maven (Ali image + environment variables) + Tomcat (local environment variables)
1. idea to create a project
2. Check IDEA-Maven configuration
3. Delete the generated Servlet case class and rewrite index.jsp
index.jsp empty body content
4. Introduce dependency Spring+SpringMVC+MyBatis+MySQL+JSON
pom.xml add dependencies
properties configuration content
<properties>
<spring-version>5.2.3.RELEASE</spring-version>
<aspectj-version>1.8.9</aspectj-version>
<junit-version>4.11</junit-version>
</properties>
1. Spring dependencies
<!-- Spring依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-version}</version>
</dependency>
2. Spring MVC dependency
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring-version}</version>
</dependency>
3. Proxy package aspectj
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version></version>
</dependency>
4. junit test package
<!--测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
5. servlet-api related packages
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
6. Mysql-j package
<!--mysql驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
7. json and @Responsebody package (jackson)
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.12.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>
<!-- Fastjoson JSON处理工具 --><!-- TODO:gai -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
8. File upload and download
<!-- 文件上传下载-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
9.lombok package
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
10. Mybatis package
<!-- mybatis核心包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!-- mybatis集成spring包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
11. Ali druid connection pool
<!-- 阿里的druid连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
<scope>compile</scope>
</dependency>
12. Data verification package (required verification attribute, email verification)
<!-- 数据校验 -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.1.0.CR2</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.0.Final</version>
</dependency>
13. Captcha
<!--Easy-Captcha Java图形验证码-->
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>1.6.2</version>
</dependency>
14. Log package
<!--日志-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
15.mybatis paging-pagerHepler
<!-- github分页 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.2.1</version>
</dependency>
16. API Documentation Generator-Swagger
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
5. Modify the tomcat configuration
6. Create various configuration files
1.spring configuration file (contains mvc function)
The default content of the spring configuration file, the file name is spring.xml
<?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:p="http://www.springframework.org/schema/p"
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-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<!-- 集成SpringMV的配置 -->
</beans>
2. Create mybatis configuration file
File name: Mybatis.xml
<?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:p="http://www.springframework.org/schema/p"
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-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<!-- 集成SpringMVC时Mybatis配置文件也将使用SpringBean的方式来配置 -->
</beans>
3. Database connection configuration file
Name: database.properties
url= jdbc:mysql://localhost:3306/javatest?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username=root
password=cxk666
driver=com.mysql.cj.jdbc.Driver
7. Modify the web configuration file - web.xml
Set the project name and load the mybatis configuration file
<!-- 设置项目名称 -->
<display-name>ssm</display-name>
<!-- 配置SpringMVC容器加载时的初始化参数 -->
<context-param>
<!-- 加载mybatis配置文件 -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:mybatis.xml</param-value>
</context-param>
<!-- 能够将ServletContext读取的内容加载到SpringMVC的application对象中 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Add springMVC-front controller configuration
<!-- 配置前端控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 当前端控制器加载时要加载springMVC配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</init-param>
<!-- 让前端控制器Servlet在项目启动加载阶段就进行实例 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
character encoding set filter
<!-- 过滤器:字符编码集过滤器(自动将请求和响应的字符编码集按照规则编解码) -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!-- 编码字符集属性 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!-- 是否进行强制字符集转换 -->
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
A filter that implements the RestFul specification
<!-- RestFul规范请求:让mvc支持put、delete等等rest规范的请求 -->
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
8. Define the package structure path of the project
root package node definition
Each business sub-node definition method
Framework core package structure
webapp directory changes
9. Configure Maven packaging
Static files in the source code directory should participate in packaging (such as: mybatis mapping xml file), and the static directory should be added to the packaging, and the resources directory should be added to the packaging
At the end of the pom.xml file (at the same level as the dependencies tag, after that, in the project tag)
<build>
<!-- 静态资源参与打包 -->
<resources>
<!-- resources目录下配置文件参与打包 -->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.js</include>
<include>**/*.css</include>
<include>**/*.html</include>
</includes>
<filtering>false</filtering>
</resource>
<!-- 源代码目录参与打包 -->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.js</include>
<include>**/*.css</include>
<include>**/*.html</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<!-- maven打包工具组件 -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
</plugin>
</plugins>
</build>
10. Write SpringMVC configuration files
view resolver
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp" />
</bean>
Automatic package scanning annotations
<!-- 自动实现ioc注入:@Controller @Component @Service -->
<context:component-scan base-package="com.huawei.ssmdemo2023" />
Data validation related annotations, dependency injection
<mvc:annotation-driven />
File upload and download configuration
<!-- 文件上传下载 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="5000000000" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
Configure static resource access mapping
<!-- 静态资源目录配置(注意:之后controller请求路径不要出现static路径) -->
<mvc:resources location="/static/" mapping="/static/**" />
11. Write mybatis configuration
1. Rewrite the database.properties file
url= jdbc:mysql://localhost:3306/javatest?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username=root
password=cxk666
driver=com.mysql.cj.jdbc.Driver
#定义初始连接数
initialSize=2
#定义最大连接数
maxActive=30
#定义最小空闲
minIdle=1
#定义最长等待时间
maxWait=60000
2. Load the database configuration file project in the mybatis configuration file
<!-- 加载database.proterties配置项目内容 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:database.properties" />
</bean>
3. Configure the Ali druid connection pool under the mybatis configuration file
<!-- druid连接池配置 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<!-- 数据源连接属性 -->
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
<!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="${initialSize}" />
<property name="minIdle" value="${minIdle}" />
<property name="maxActive" value="${maxActive}" />
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="${maxWait}" />
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000" />
<!-- 检测空闲是否开启 -->
<property name="testWhileIdle" value="true" />
<!-- 这里建议配置为TRUE,防止取到的连接不可用 -->
<property name="testOnBorrow" value="true" />
<property name="testOnReturn" value="false" />
<!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
<property name="poolPreparedStatements" value="true" />
<property name="maxPoolPreparedStatementPerConnectionSize" value="50" />
<!-- 这里配置提交方式,默认就是TRUE,可以不用配置 -->
<property name="defaultAutoCommit" value="true" />
<!-- 验证连接有效与否的SQL,不同的数据配置不同 mysql:select 1 ;oracle : select 1 from dual -->
<property name="validationQuery" value="select 1 from dual" />
<property name="filters" value="wall,stat" />
<property name="proxyFilters">
<list>
<ref bean="logFilter" />
<ref bean="stat-filter" />
</list>
</property>
</bean>
<!-- 慢SQL记录 -->
<bean id="stat-filter" class="com.alibaba.druid.filter.stat.StatFilter">
<!-- 慢sql时间设置,即执行时间大于50毫秒的都是慢sql -->
<property name="slowSqlMillis" value="50"/>
<property name="logSlowSql" value="true"/>
</bean>
<!-- 启用慢sql日志记录时,需要引入slf4j日志包 -->
<bean id="logFilter" class="com.alibaba.druid.filter.logging.Slf4jLogFilter">
<property name="dataSourceLogEnabled" value="true" />
<property name="statementExecutableSqlLogEnable" value="true" />
</bean>
4. Configure the druid connection pool data monitoring center in the web.xml file
<!-- druid连接池数据监控中心 -->
<servlet>
<servlet-name>DruidStatView</servlet-name>
<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DruidStatView</servlet-name>
<!-- 监控中心的进入路径 -->
<url-pattern>/druid/*</url-pattern>
</servlet-mapping>
5. Mybatis configuration - instance SQLSessionFactory factory class
<!-- spring和mybatis完美整合,不需要mybatis的配置映射文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- ref指向数据源配置id -->
<property name="dataSource" ref="dataSource" />
<!-- 自动扫描包中的类生成别名,如:com.a.User包 别名可以是User或user -->
<property name="typeAliasesPackage" value="com.huawei.ssmdemo2023" />
<!-- 自动扫描mapping.xml文件 -->
<property name="mapperLocations" value="classpath:com/huawei/ssmdemo2023/mybatis/dao"></property>
</bean>
6. Mybatis configuration - SQLSession class
<!-- SQLsession配置规则 -->
<!-- DAO接口所在的包名,spring会自动查找其下的类,!注意这句 value="sqlSessionFactory",不是ref而是value -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 指向mybatis接口文件所在的包 -->
<property name="basePackage" value="com.huawei.ssmdemo2023.mybatis.dao" />
<!-- value指向配置sqlSessionFactory类的id -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>
11. MyBatis integrates Pagehepler paging tool
1. Introduce paging tool dependencies
<!-- github分页 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.2.1</version>
</dependency>
2. Configure the paging interceptor in the mybatis configuration file
<!-- pageHepler分页拦截器 -->
<bean id="pageInterceptor" class="com.github.pagehelper.PageHelper">
<property name="properties">
<props>
<prop key="helperDialect">mysql</prop>
<prop key="reasonable">true</prop>
<prop key="supportMethodsArguments">true</prop>
<prop key="params">count=countSql</prop>
</props>
</property>
</bean>
3. Add a paging tool configuration item in the SQLSessionFactory configuration
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
... ...
<!-- 配置分页工具 -->
<property name="plugins" ref="pageInterceptor" />
</bean>
12. Open @Mapper for configuration
Write in the mybatis configuration file
<!-- 自动扫描@Mapper注解,将mybatis接口自动实现实例且交由给springMVC管理 -->
<context:component-scan base-package="com.huawei.ssmdemo2023.mybatis.dao">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Service" />
</context:component-scan>
13. Turn on logging
1. Create a log4j.properties in the resources directory
######################## ????DEBUG????????consoleh?file?????, console?file?????????
log4j.rootLogger=DEBUG,console,file
log4j.appender.syslog.encoding=UTF-8
########################??????????
log4j.appender.console = org.apache.log4j.ConsoleAppender
#??????
log4j.appender.console.Target = System.out
#?DEBUG????
log4j.appender.console.Threshold = DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
#????
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
# mybatis日志集成
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
2. Complete business process development case
1. Case 1 - Query a student's information through the student id
controller layer
/**
* 模块名称: 学生信息管理-控制器
* 模块类型:C-控制器
* 编码人:高靖博
* 创建时间:2023/2/22
* 联系电话:18587388612
*/
@Controller
@RequestMapping("/student")
@Slf4j //提供一个日志log对象注入到当前类
public class StudentController {
// 注入业务层实例
@Resource(name = "studentServiceImpl")
private StudentService studentService;
@RequestMapping(value = "/getStudentByID",method = RequestMethod.GET)
@ResponseBody
public MyResult getStudentByID(String id){
log.debug("学生信息管理:获取学生信息通过学生id [param:id"+id+"]");
MyResult result = new MyResult();
//调用业务层
StudentDO studentDO = studentService.getStudentByID(id);
if(studentDO==null){
result.setCode(500);
result.setMsg("没有查询到任何学生数据!");
}else{
result.setMsg("学生信息查询成功!");
result.setData(studentDO);
}
return result;
}
}
business interface
public interface StudentService {
StudentDO getStudentByID(String id);
}
business realization layer
@Service
public class StudentServiceImpl implements StudentService {
// mybatis接口使用自动注入的方法实现实例注入!!!!!!!!!!!!
@Autowired
private StudentMapper studentMapper;
public StudentDO getStudentByID(String id) {
StudentDO studentByID = studentMapper.getStudentByID(id);
return studentByID;
}
}
mybatis-dao interface (the interface name is the same as the xml file name)
@Mapper
public interface StudentMapper {
StudentDO getStudentByID(String id);
}
mybatis-xml mapping file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.huawei.ssmdemo2023.mybatis.dao.student.StudentMapper">
<select id="getStudentByID" resultType="com.huawei.ssmdemo2023.mybatis.domain.student.StudentDO">
select * from student where id = #{id}
</select>
</mapper>
14. PagerHelper use cases
Define an entity that receives paginated data
@Data
public class MyPager<T> implements Serializable {
private Integer page;//当前的页码
private Integer size;//每页显示的行数
private List<T> rows;//当前页码的数据
private Long total;//数据总行数
}
In the business implementation layer, how to deal with paging calls
Case - query student information page
controller layer
@RequestMapping(value = "/getStudentPage",method = RequestMethod.GET)
@ResponseBody
public MyResult getStudentPage(MyPager pager){
//接收前端分页的参数
log.debug("学生信息管理:查询学生信息分页");
MyResult result = new MyResult();
//调用业务层
MyPager<StudentDO> pageData = studentService.getStudentPage(pager);
result.setData(pageData);
result.setMsg("查询成功!");
return result;
}
business interface
MyPager<StudentDO> getStudentPage(MyPager pager);
business realization layer
public MyPager<StudentDO> getStudentPage(MyPager pager) {
//1.创建分页结果集对象
MyPager<StudentDO> resultPageData = new MyPager<StudentDO>();
//2.调用分页工具设置分页参数(页码,每页显示多少行数据)
Page<StudentDO> stuPage = PageHelper.startPage(pager.getPage(), pager.getSize());
//3.正常调用mapper接口方法!!!!!!!!!!!不要返回值,只需要调用
studentMapper.getStudentPage();
//4.此时,pagehepler已经拦截到sql,且把sql分页执行的结果映射到stuPage对象中
//4.1 取出分页的结果集
List<StudentDO> result = stuPage.getResult();// 当前页码下的分页数据
long total = stuPage.getTotal();//数据查询的所有行数值
resultPageData.setTotal(total);
resultPageData.setRows(result);
resultPageData.setPage(pager.getPage());
resultPageData.setSize(pager.getSize());
return resultPageData;
}
mybatis-dao interface (the interface name is the same as the xml file name)
List<StudentDO> getStudentPage();
mybatis-xml mapping file
<select id="getStudentPage" resultType="com.huawei.ssmdemo2023.mybatis.domain.student.StudentDO">
select * from student
</select>
case:
Realize user management functions: (primary) (single table addition, deletion, modification, query-page query)
- Add, modify, delete users
- Query user information (pagination), you can perform conditional query through fields such as user name and mobile phone number
User's function: able to realize system login
Users must be able to implement the integrated login page functionality
Login function requirements:
1. Login requires verification code verification
2. To achieve single sign-on (the same user cannot log in repeatedly, if repeated login needs to give a response prompt) (advanced) (difficulty: thread safety design)
3. Login failure problem: If the user does not operate for 30 minutes after logging in, he will log out to the login interface when operating any function after 30 minutes
4. Question about whether to log in or not: (intermediate) (difficult)
For example: when performing any operation, it is necessary to verify whether the user is logged in and whether the login has timed out. If the above problems exist, return to the login interface directly and prompt a login error message