使用 IntelliJ IDEA 新建一个 Maven 工程,项目类型选择 Maven,然后点 Next

填入 Maven 工程的必要信息

将新建的 Maven 工程改造成 Web 工程:在 IDEA 点击 File -> Project Structure(或快捷键:Ctrl + Shift + Alt + S)进入设置界面
在 Facts 下为当前工程添加 Web 模块

选择自己的刚刚创建的 Maven 工程,点击 OK

为 Web 工程添加核心配置文件 web.xml,并修改 web.xml 文件路径为 src\main\webapp\WEB-INF\web.xml(没有则点击 + 号新建 web.xml 文件)


指定 Web 工程的上下文路径为 src\main\webapp,而后点击 OK 即可


为方便后续操作,在 pom.xml 中一次性引入所需相关依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>edu.whut.springbear</groupId>
<artifactId>uims</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<!-- Spring 版本号统一管理 -->
<spring.version>5.3.1</spring.version>
<!-- Maven 打包编码指定为 UTF-8,避免工程部署到远程服务器后乱码 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- Maven 打包时跳过测试 -->
<maven.test.skip>true</maven.test.skip>
</properties>
<dependencies>
<!-- Spring5 整合 Thymeleaf -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
<!-- SpringMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring 整合 MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!-- Mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!-- Servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- Spring JDBC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- MySQL 驱动文件 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<!-- 阿里巴巴德鲁伊数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.15</version>
</dependency>
<!-- Spring Test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<!-- JUnit 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- Jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<!-- Lombok 简化 POJO 类开发 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- 文件上传 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
</project>
在 src\main\webapp\WEB-INF\web.xml 中配置 Spring IOC 容器、编码过滤器、HTTP 请求方法过滤器、SpringMVC 的前端控制器
注:编码过滤器应配置为第一个过滤器,否则依旧会中文乱码(因为过滤器的安装配置的顺序依次拦截执行)
<!-- web.xml -->
<?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">
<!-- Spring IOC 容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 编码过滤器解决中文乱码 -->
<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>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Http 请求方法过滤器以支持 RESTful 风格编程 -->
<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>
<!-- SpringMVC 前端控制器 -->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMVC-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
在 src\main\resources\ 目录下新建 Spring 和 SpringMVC 的核心配置文件 applicationContext.xml、springMVC-config.xml
- Spring 核心配置文件 applicationContext.xml
<!-- applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
- SpringMVC 核心配置文件 springMVC-config.xml
<!-- springMVC-config.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
- 项目结构如下

在 src\main\resources\applicationContext.xml 进行 Spring 的相关配置
注:IDEA 中 context 爆红使用
Alt + Enter引入 context 名称空间即可,其余爆红在后续的配置过程自动消失
<!-- applicationContext.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:context="http://www.springframework.org/schema/context"
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">
<!-- 组件扫描 -->
<context:component-scan base-package="edu.whut.springbear.uims.pojo,edu.whut.springbear.uims.dao,
edu.whut.springbear.uims.service,edu.whut.springbear.uims.util"/>
<!-- 引入数据库连接配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClass}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- MyBatis SQL 会话工厂实例 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- MyBatis 核心配置文件路径 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- MyBatis Mapper.xml 文件路径 -->
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
<!-- MyBatis Mapper.xml 对应接口的包路径 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!-- Mapper.xml 对应接口所在包路径 -->
<property name="basePackage" value="edu.whut.springbear.uims.dao"/>
</bean>
</beans>
src\main\java 下新建组件扫描时所扫描到的相关常用包
src\main\resources\ 目录下新建数据库连接配置文件 jdbc.properties,并配置相关 MySQL 连接信息# jdbc.properties
jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/uims?characterEncoding=utf-8&serverTimezone=Asia/Shanghai
jdbc.username=admin
jdbc.password=admin
src\main\resources\ 目录下新建 MyBatis 的核心配置文件 mybatis-config.xml<!-- mybatis-config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
</configuration>
src\main\resources\ 目录下新建 MyBatis 数据库操作 *Mapper.xml 文件所在目录 mapper
applicationContext.xml中指定 MyBatis Mapper.xml 对应接口的所在包路径
在 src\main\resources\springMVC-config.xml 进行 SpringMVC 的相关配置
注:此配置文件中 IDEA 爆红问题可以不予理会,运行正常
<!-- springMVC-config.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: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">
<!-- 组件扫描 -->
<context:component-scan base-package="edu.whut.springbear.uims.controller"/>
<!-- 默认 Servlet 处理静态资源 -->
<mvc:default-servlet-handler/>
<!-- MVC 注解驱动以支持高级功能 -->
<mvc:annotation-driven/>
<!-- Thymeleaf 视图解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/"/>
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
</property>
</bean>
</property>
</bean>
<!-- 视图控制器 -->
<mvc:view-controller path="/" view-name="index"/>
</beans>
springMVC-config.xml 中开启 SpringMVC 的组件扫描,扫描 Controller 控制器所在包

springMVC-config.xml 配置默认 Servlet 处理静态资源、配置 MVC 注解驱动以支持高级功能
springMVC-config.xml 配置 Thymeleaf 视图解析器
- 在
src\main\webapp\WEB-INF下创建视图文件即*.html所在目录templates- 在 templates 目录下新建
index.html
<!-- index.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>成功</title>
</head>
<body>
<h1>Success</h1>
</body>
</html>

springMVC-config.xml 配置视图控制器,转发 / 请求到 index.html 页面

mybatis-config.xml 中配置自动驼峰命名转换和 POJO 类别名
<!-- mybatis-config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!-- POJO 类与数据库表字段驼峰命名自动转换 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<typeAliases>
<!-- 以包为单位指定 POJO 类别名,默认为类名 -->
<package name="edu.whut.springbear.uims.pojo"/>
</typeAliases>
</configuration>
在 edu.whut.springbear.uims.pojo POJO 类所在包中配置 User 类
package edu.whut.springbear.uims.pojo;
/**
* @author Spring-_-Bear
* @datetime 2022-06-25 18:05 Saturday
*/
public class User {
}

edu.whut.springbear.uims.dao 包中配置 User 类对应的持久层操作接口 UserMapper 并使用注解扫描
package edu.whut.springbear.uims.dao;
import org.springframework.stereotype.Repository;
/**
* @author Spring-_-Bear
* @datetime 2022-06-25 18:07 Saturday
*/
@Repository
public interface UserMapper {
}

src\main\resources\mapper\ 目录下创建 UserMapper 接口对应的 MyBatis 配置文件 UserMapper.xml,并在 UserMapper.xml 中指定所对应的 Mapper 接口 edu.whut.springbear.uims.dao.UserMapper
<?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">
<!-- namespace 指定当前 Mapper.xml 所对应的 Mapper 接口类 -->
<mapper namespace="edu.whut.springbear.uims.dao.UserMapper">
</mapper>

生成 .war exployded文件:在项目结构中(快捷键Ctrl + Shift + Alt + S)依据当前模块生成 .war exployded 文件供 Tomcat 部署访问,而后点击 Apply、OK 即可

IDEA 中为当前工程添加 Tomcat Web 服务器

选择本地 Tomcat 应用(需提前自行安装)

在 Tomcat 中选择第 1 步中创建的 war 包,点击 Apply、OK 即可

启动 Tomcat,成功访问 index.html

在 MySQL 控制台创建 uims 数据库,生成用户信息表 t_user 并插入测试数据
CREATE DATABASE uims;
USE uims;
CREATE TABLE t_user (
id INT NOT NULL auto_increment PRIMARY KEY,
username VARCHAR(32) NOT NULL,
password VARCHAR(32) NOT NULL
);
INSERT INTO t_user VALUES (NULL,'springbear','springbear');
修改对应的 User 实体类 edu.whut.springbear.uims.pojo.User,并且使用 Lombok 注解自动生成方法以简化开发
package edu.whut.springbear.uims.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* @author Spring-_-Bear
* @datetime 2022-06-25 18:05 Saturday
*/
@Data
@AllArgsConstructor
public class User {
private Integer id;
private String username;
private String password;
}
在 edu.whut.springbear.uims.dao.UserMapper 类中添加接口方法,根据用户名和密码查询用户信息
package edu.whut.springbear.uims.dao;
import edu.whut.springbear.uims.pojo.User;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
/**
* @author Spring-_-Bear
* @datetime 2022-06-25 18:07 Saturday
*/
@Repository
public interface UserMapper {
/**
* 通过用户名和密码查询用户信息
*/
User getUserByUsernameAndPassword(@Param("username") String username, @Param("password") String password);
}
在 src\main\resources\mapper\UserMapper.xml 中创建接口方法对应的 SQL 语句,MyBatis 框架会根据接口方法自动生成代理实现类
<?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">
<!-- namespace 指定当前 Mapper.xml 所对应的 Mapper 接口类 -->
<mapper namespace="edu.whut.springbear.uims.dao.UserMapper">
<!-- User getUserByUsernameAndPassword(@Param("username") String username, @Param("password") String password); -->
<select id="getUserByUsernameAndPassword" resultType="User">
select *
from t_user
where username = #{username}
and password = #{password}
</select>
</mapper>
在 edu.whut.springbear.uims.dao.UserMapper 接口中选中 getUserByUsernameAndPassword 方法,使用 IDEA 快捷键 Ctrl + Shift + T 生成单元测试,生成的测试文件位于 src\test\java\edu.whut.springbear.uims.dao.UserMapperTest 目录下


在生成的测试类 edu.whut.springbear.uims.dao.UserMapperTest 中使用 Spring 的方式进行测试,即指定 Spring 核心配置文件和 Spring 整合的 Junit4 测试类,如下所示
package edu.whut.springbear.uims.dao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Spring-_-Bear
* @datetime 2022-06-25 22:12 Saturday
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void getUserByUsernameAndPassword() {
// Output: User(id=1, username=springbear, password=springbear)
System.out.println(userMapper.getUserByUsernameAndPassword("springbear", "springbear"));
}
}

edu.whut.springbear.uims.interceptor 包下自定义类实现 HandlerInterceptor 接口以自定义拦截器功能,此处定义一个判断用户是否登录的拦截器,登陆后放行,否则拦截请求
package edu.whut.springbear.uims.interceptor;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* 登录拦截器,登录成功则放行
*
* @author Spring-_-Bear
* @datetime 2022-06-25 22:22 Saturday
*/
@Component
public class LoginInterceptor implements HandlerInterceptor {
/**
* 控制器方法执行之前执行拦截器的 preHandle 方法
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 查看用户是否登录
HttpSession session = request.getSession();
Object user = session.getAttribute("user");
// 用户未登录则拦截请求,不执行对应的控制器方法
return user != null;
}
}
在 SpringMVC 的核心配置文件 springMVC-config.xml 中进行登录拦截器的配置
<!-- 开启拦截器所在包组件扫描 -->
<context:component-scan base-package="edu.whut.springbear.uims.controller
edu.whut.springbear.uims.interceptor"/>
<!-- 拦截器 -->
<mvc:interceptors>
<!-- 用户登录检查 -->
<mvc:interceptor>
<!-- 拦截除主页、登录、静态资源外的所有请求 -->
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/"/>
<mvc:exclude-mapping path="/login"/>
<mvc:exclude-mapping path="/static/**"/>
<ref bean="loginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
主页 index.html 改为登录表单,并发送请求
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
</head>
<body>
<h1>欢迎登录</h1>
<form method="get" th:action="@{/login}">
<label><input type="text" name="username" placeholder="用户名"/></label>
<label><input type="password" name="password" placeholder="密码"/></label>
<input type="submit" value="登录">
</form>
</body>
</html>
在 edu.whut.springbear.uims.service 包下创建用户业务操作接口类 UserService 及其实现类 UserServiceImpl,供 Controller 调用
- UserService 接口
package edu.whut.springbear.uims.service;
import edu.whut.springbear.uims.pojo.User;
import org.springframework.stereotype.Service;
/**
* @author Spring-_-Bear
* @datetime 2022-06-25 22:38 Saturday
*/
@Service
public interface UserService {
/**
* 用户通过用户名和密码登录
*/
User userLogin(String username, String password);
}
- UserServiceImpl 实现类
package edu.whut.springbear.uims.service.impl;
import edu.whut.springbear.uims.dao.UserMapper;
import edu.whut.springbear.uims.pojo.User;
import edu.whut.springbear.uims.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author Spring-_-Bear
* @datetime 2022-06-25 22:39 Saturday
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User userLogin(String username, String password) {
return userMapper.getUserByUsernameAndPassword(username, password);
}
}
- 项目结构

在 edu.whut.springbear.uims.controller 包下创建用户控制器,处理用户操作业务
package edu.whut.springbear.uims.controller;
import edu.whut.springbear.uims.pojo.User;
import edu.whut.springbear.uims.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpSession;
/**
* @author Spring-_-Bear
* @datetime 2022-06-25 22:36 Saturday
*/
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/login")
public String userLogin(HttpSession session,
@RequestParam("username") String username,
@RequestParam("password") String password) {
// 验证用户名和是否正确
User user = userService.userLogin(username, password);
// 用户名不存在或密码错误,返回登录页面
if (user == null) {
return "index";
}
// 用户名、密码正确,将用户信息放进 Session 域
session.setAttribute("user", user);
// 登录成功,重定向到成功页面
return "redirect:/success";
}
}
创建成功页面 success.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Success</title>
</head>
<body>
<h1 th:text="${'欢迎您:【'+session.user.username}+'】'">登录成功</h1>
</body>
</html>

在 SpringMVC 的核心配置文件 springMVC-config.xml 中配置 success.html 页面的视图控制器
<!-- 视图控制器 -->
<mvc:view-controller path="/" view-name="index"/>
<mvc:view-controller path="/success" view-name="success"/>
启动 Tomcat,输入用户名及密码进行登录验证。若出现异常,可尝试删除 target 目录后重新启动 Tomcat
- 用户名不存在或密码错误,返回到登录页面

- 用户名密码正确,重定向请求到成功页面

登录拦截器的使用场景测试
- 用户未登录,直接从浏览器地址栏访问
success请求,被拦截器拦截,拒绝访问


- 用户输入用户名、密码登录成功后,直接从浏览器地址栏访问 success.html 页面,登录拦截器放行,访问成功

edu.whut.springbear.uims.exception 包下自定义异常类 InterceptorException
package edu.whut.springbear.uims.exception;
import org.springframework.stereotype.Component;
/**
* @author Spring-_-Bear
* @datetime 2022-06-25 23:17 Saturday
*/
@Component
public class InterceptorException extends Exception {
private String msg;
public InterceptorException() {
}
public InterceptorException(String msg) {
super(msg);
this.msg = msg;
}
@Override
public String toString() {
return msg;
}
}
在 SpringMVC 的核心配置文件 springMVC-config.xml 中开启自定义异常类所在包组件扫描
<!-- 组件扫描 -->
<context:component-scan base-package="edu.whut.springbear.uims.controller
edu.whut.springbear.uims.interceptor,
edu.whut.springbear.uims.exception"/>
在 SpringMVC 的核心配置文件 springMVC-config.xml 中配置异常解析器处理异常信息
<!-- 异常处理器 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<!-- 当遇到自定义的拦截器异常时,跳转到首页 -->
<prop key="edu.whut.springbear.uims.exception.InterceptorException">index</prop>
</props>
</property>
<!-- 为异常信息设置一个属性名,值为 loginMsg,默认在 request 域中进行共享 -->
<property name="exceptionAttribute" value="loginMsg"/>
</bean>
edu.whut.springbear.uims.interceptor.LoginInterceptor 登录拦截方法修改为未登录时抛出自定义的异常
package edu.whut.springbear.uims.interceptor;
import edu.whut.springbear.uims.exception.InterceptorException;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* 登录拦截器,登录成功则放行
*
* @author Spring-_-Bear
* @datetime 2022-06-25 22:22 Saturday
*/
@Component
public class LoginInterceptor implements HandlerInterceptor {
/**
* 控制器方法执行之前执行拦截器的 preHandle 方法
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 查看用户是否登录
HttpSession session = request.getSession();
Object user = session.getAttribute("user");
// 用户未登录则拦截请求,抛出登录拦截异常
if (user == null) {
throw new InterceptorException("请先登录您的账号");
}
return true;
}
}
在首页 index.html 中添加显示登录信息的元素
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
</head>
<body>
<h1>欢迎登录</h1>
<form method="get" th:action="@{/login}">
<span th:text="${loginMsg}">欢迎登录您的账号</span>
<label><input type="text" name="username" placeholder="用户名"/></label>
<label><input type="password" name="password" placeholder="密码"/></label>
<input type="submit" value="登录">
</form>
</body>
</html>
在 UserController 添加当用户名不存在或密码错误时的验证信息,友好提示用户
package edu.whut.springbear.uims.controller;
import edu.whut.springbear.uims.pojo.User;
import edu.whut.springbear.uims.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* @author Spring-_-Bear
* @datetime 2022-06-25 22:36 Saturday
*/
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/login")
public String userLogin(HttpSession session, HttpServletRequest request,
@RequestParam("username") String username,
@RequestParam("password") String password) {
// 验证用户名和是否正确
User user = userService.userLogin(username, password);
// 用户名不存在或密码错误,返回登录页面
if (user == null) {
request.setAttribute("loginMsg", "用户名不存在或密码错误");
return "index";
}
// 用户名、密码正确,将用户信息放进 Session 域
session.setAttribute("user", user);
// 登录成功,重定向到成功页面
return "redirect:/success";
}
}
当用户未登录账号而尝试访问 success 请求时,由登录拦截器抛出自定义的异常,在异常处理器中转发到主页并共享异常信息

当用户名或密码错误时友好提示用户

在 SpringMVC 的核心配置文件 springMVC-config.xml 中配置文件上传解析器
<!-- 文件上传解析器 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 允许上传的最大文件大小 10M -->
<property name="maxUploadSize" value="10485760"/>
<property name="defaultEncoding" value="utf-8"/>
</bean>
新建 TransferController 并在控制器方法中处理文件上传业务
package edu.whut.springbear.uims.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
/**
* @author Spring-_-Bear
* @datetime 2022-06-26 08:29 Sunday
*/
@Controller
public class TransferController {
@PostMapping("/upload")
public String filesUpload(HttpSession session,
@RequestParam("img") MultipartFile img,
@RequestParam("pdf") MultipartFile pdf) {
// 获取文件原文件名
String imgOriginalFilename = img.getOriginalFilename();
String pdfOriginalFilename = pdf.getOriginalFilename();
// 获取指定目录在磁盘上的真实路径,即上传文件保存至 src\main\webapp\static\files\ 目录下
String realPath = session.getServletContext().getRealPath("/static/files/");
File file = new File(realPath);
// 如果文件夹不存在则创建
if (!file.exists()) {
if (!file.mkdirs()) {
return "index";
}
}
try {
// 图片文件写入磁盘
img.transferTo(new File(realPath + "/" + imgOriginalFilename));
} catch (IOException e) {
return "index";
}
try {
// PDF 文件写入磁盘
pdf.transferTo(new File(realPath + "/" + pdfOriginalFilename));
} catch (IOException e) {
return "index";
}
return "success";
}
}
在 index.html 中添加文件上传表单
- 表单的请求方法 method 属性必须为 POST
- 必须设置 enctype 的属性值为
multipart/form-data- 使用类型为 file 的 input 标签元素选择文件,且必须正确 name 的属性值,否则表单项不会提交到服务器
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
</head>
<body>
<h1>欢迎登录</h1>
<!-- 登录表单 -->
<form method="get" th:action="@{/login}">
<span th:text="${loginMsg}">欢迎登录您的账号</span><br/>
<label><input type="text" name="username" placeholder="用户名"/></label>
<label><input type="password" name="password" placeholder="密码"/></label>
<input type="submit" value="登录">
</form>
<hr/>
<!-- 文件上传表单 -->
<form method="post" enctype="multipart/form-data" th:action="@{/upload}">
请选择图片文件:<input type="file" name="img" accept="image/*"/><br/>
请选择 PDF 文件:<input type="file" name="pdf" accept="application/pdf"/><br/>
<input type="submit" value="上传"/>
</form>
</body>
</html>
启动 Tomcat,进行上传文件测试。若出现异常,可尝试删除 target 目录后重新启动 Tomcat
依次选择图片和 PDF 文件,而后提交

此时将配登录拦截器拦截文件上传请求,登录账号后再上传文件

输入正确的账号、密码,登录成功后重新访问首页请求,选择文件并上传

文件上传成功,跳转到 success.html 页面,并在服务器目录 项目名\static\files目录下成功保存所上传的文件,对应 IDEA 中的 target\static\files\ 目录


注:更多配置及项目源码参考开源项目:两码一查
