SSM 框架整合(基于 XML)
SSM(Spring + SpringMVC + MyBatis)框架集由 Spring、MyBatis 两个开源框架整合而成(SpringMVC 是 Spring 中的部分内容),常作为数据源较简单的 Web 项目的框架。
文章目录
一、创建 Web 工程
-
使用 IntelliJ IDEA 开发工具新建一个工程,项目类型选择 Maven,然后点击 Next。若配置过程中发现自己的图标与图片中的不一致,那是因为笔者使用了图标插件的原因,无需在意。
-
填入 Maven 工程必要信息,如工程名、组织名和模块名等,而后点击 Finish。此处我们的工程和模块名称均为 uims,意为用户信息管理系统(User Information Management System)。
-
将上一步新建的 Maven 工程改造为 Web 工程。在 IDEA 中依次点击 File => Project Structure(或使用快捷键:Ctrl + Shift + Alt + S)进入工程结构设置页面。
-
在工程结构设置页面中依次点击 Facets => + => Web,而后将弹出当前工程下的所有模块。
-
选择自己的刚刚创建的 Maven 工程 uims,点击 OK。
-
为 Web 工程添加核心配置文件 web.xml,若 web.xml 不存在则点击 + 号新建即可。
-
修改 web.xml 的文件路径为 src\main\webapp\WEB-INFO\web.xml,即将原有路径中的 web 修改为 src\main\webapp。
-
指定当前 Web 工程的上下文路径为 webapp 目录,即将原有路径中的 web 修改为 src\main\webapp,而后一直点击 OK 即可。
至此,标准目录格式的 Web 工程创建完成,下一步将引入 Maven 工程依赖,而后进行 Spring、Spring MVC 和 Mybatis 框架的整合。为方便后续操作,此处在 pom.xml 中一次性引入所有相关依赖,各依赖的作用见注释。
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>cn.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>
</properties>
<dependencies>
<!-- Spring MVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring JDBC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</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>
<!-- Mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!-- Spring 整合 MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</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>
<!-- Servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- Spring5 整合 Thymeleaf -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</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>
二、配置 web.xml
在 src\main\webapp\WEB-INF\web.xml 中配置 Spring IOC 容器、编码过滤器、HTTP 请求方法过滤器和 Spring MVC 的前端控制器等。
注:编码过滤器应配置为第一个过滤器,否则将出现中文乱码情况,因为过滤器的按配置顺序依次拦截执行。
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:spring-mvc-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>
如下图所示,此时 IDE 中将会出现两处 “爆红” 现象,本文后续内容中若无特殊说明,否则无需在意 IDE 出现的 “爆红” 现象,因为该情况会在后续的配置过程中自动消失。
在 src\main\resources 目录下新建 Spring 的核心配置文件 applicationContext.xml 和 Spring MVC 的核心配置文件 spring-mvc-config.xml。
Spring 的核心配置文件 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>
Spring MVC 的核心配置文件 spring-mvc-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>
此时再次点击 web.xml 查看文件内容,将会发现之前的 “爆红” 情况已经消失。至此,项目结构如下图所示:
三、配置 Spring
在 src\main\resources\applicationContext.xml 中进行 Spring 的相关核心配置。如配置组件扫描规则、配置数据源和整合 MyBatis 等。
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="cn.edu.whut.springbear.uims.mapper,
cn.edu.whut.springbear.uims.pojo,
cn.edu.whut.springbear.uims.service"
/>
<!-- 引入数据库配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.className}"/>
<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="cn.edu.whut.springbear.uims.mapper"/>
</bean>
</beans>
如下图所示,此时 <context> 标签出现 “爆红” 现象,可通过点击该标签后使用 Alt + Enter 引入 context 名称解决,其余 “爆红” 问题在后续配置中自动消失。
在 src\main\java 下新建组件扫描规则和 MyBatis XML 文件对应的接口包,需注意包全路径应做到一一对应,如下图所示:
在 src\main\resources 目录下新建 MySQL 数据库配置文件 jdbc.properties,并填入你自己的数据库连接信息,请务必确保 jdbc.url 中配置的数据库存在。jdbc.properties 的文件内容如下:
jdbc.className=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/uims?characterEncoding=utf-8&serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=root
在 src\main\resources 目录下新建 MyBatis 的核心配置文件 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 数据库操作 XML 文件的存储目录,名为 mapper,如下图所示:
四、配置 Spring MVC
在 src\main\resources\spring-mvc-config.xml 中进行 Spring MVC 的核心配置,如配置控制器扫描路径、静态资源处理器、开启注解驱动、配置视图解析器和视图控制器等。此时出现的标签爆红情况仍可通过点击该标签后,使用 Alt + Enter 引入对应的名称空间解决。
spring-mvc-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="cn.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>
<!-- 视图控制器,此处 IDE 爆红问题可不予理会 -->
<mvc:view-controller path="/" view-name="index"/>
</beans>
同 Spring 的配置一样,此时需要在 src\main\java 目录下新建 cn.edu.whut.springbear.uims.controller 包,因为 Spring MVC 的配置文件中扫描了此包路径。需要注意的问题是 controller 包交给 MVC 扫描,其余组件包交给 Spring 扫描,不可在 Spring 的配置文件 applicationContext.xml 重复扫描 controller 包。
而后在 src\main\webapp\WEB-INF 目录下创建视图文件(HTML)的保存目录 templates,并在 templates 目录中创建首页 index.html 文件,文件内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Spring MVC</title>
</head>
<body>
<h1>Hello, Spring MVC</h1>
</body>
</html>
此时的工程结构如下图所示:
五、配置 MyBatis
在 Mybatis 的核心配置文件 src\main\resources\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="cn.edu.whut.springbear.uims.pojo"/>
</typeAliases>
</configuration>
在 cn.edu.whut.springbear.uims.pojo 包中创建用户信息实体类 User,文件内容如下:
package cn.edu.whut.springbear.uims.pojo;
import lombok.Data;
import java.io.Serializable;
/**
* @author Spring-_-Bear
* @datetime 2022-06-25 18:05 Saturday
*/
@Data
public class User implements Serializable {
}
在 cn.edu.whut.springbear.uims.mapper 包中新建 User 类对应的持久层操作接口 UserMapper,文件内容如下:
package cn.edu.whut.springbear.uims.mapper;
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 Mapper 文件 UserMapper.xml,并在 namespace 标签中指定当前 UserMapper.xml 文件所对应的接口全路径。文件内容如下:
<?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="cn.edu.whut.springbear.uims.mapper.UserMapper"></mapper>
六、部署 Tomcat
-
生成 war 包:在项目结构设置中(快捷键:Ctrl + Shift + Alt + S)依据当前模块生成 .war exployded 文件供 Tomcat 部署访问,而后选择当前工程模块 uims,最后一直点击 OK 即可。
-
在 IDEA 中为当前工程添加 Tomcat Web 服务器。
-
选择本地 Tomcat 应用(需提前自行安装)。
-
在 Tomcat 中选择第 1 步中创建的 war 包。
-
修改 Tomcat 工程上下文路径为 /uims。完成第 4 步之后滚动鼠标滚轮,修改 Application context 的路径为 /uims,如下图所示:
-
启动 Tomcat,成功访问 index.html。访问路径为 http://localhost:8080/uims/,基础访问路径前缀为 /uims,请务必注意。
至此,成功通过 XML 配置文件方式整合 Spring、Spring MVC 和 MyBatis 框架的基本功能,完整的项目结构如下图所示:
下一步将在前六步的基础上整合 MyBatis 和 Spring MVC 的常用功能,如通过 MyBatis 进行基本的 CRUD 操作,整合 Spring MVC 的拦截器、异常解析器和文件上传解析器等。
七、MyBatis 基本使用
-
在 MySQL 控制台创建 uims 数据库,并在 uims 数据库中创建用户基本信息表 user 并插入测试数据。SQL 脚本内容如下:
-- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', `username` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名', `password` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of user -- ---------------------------- INSERT INTO `user` VALUES (1, 'spring', 'spring'); INSERT INTO `user` VALUES (2, 'bear', 'bear'); INSERT INTO `user` VALUES (3, 'Spring-_-Bear', 'Spring-_-Bear');
-
修改 cn.edu.whut.springbear.uims.pojo.User 内容,使用 Lombok 注解简化 JavaBean 的开发。修改后的文件内容如下:
package cn.edu.whut.springbear.uims.pojo; import lombok.Data; import java.io.Serializable; /** * @author Spring-_-Bear * @datetime 2022-06-25 18:05 Saturday */ @Data public class User implements Serializable { private static final long serialVersionUID = -2525965567162864217L; private Long id; private String username; private String password; }
-
在 cn.edu.whut.springbear.uims.mapper.UserMapper 接口中添加接口方法,根据用户名和密码查询用户信息。修改后的文件内容如下:
package cn.edu.whut.springbear.uims.mapper; import cn.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 { /** * 根据用户名和密码查询用户信息 * * @param username 用户名 * @param password 密码 * @return 用户信息或 null */ User getByUsernameAndPassword(@Param("username") String username, @Param("password") String password); }
-
在 src\main\resources\mapper\UserMapepr.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="cn.edu.whut.springbear.uims.mapper.UserMapper"> <!-- User getByUsernameAndPassword(@Param("username") String username, @Param("password") String password); --> <select id="getByUsernameAndPassword" resultType="User"> select * from user where username = #{username} and password = #{password} </select> </mapper>
-
选中 cn.edu.whut.springbear.uims.mapper.UserMapper#getByUsernameAndPassword 接口方法,使用 IDEA 快捷键 Ctrl + Shift + T 为该方法生成单元测试,在弹框中测试框架选择 Junit4,勾选需要进行测试的方法,最后点击 OK。
-
生成的测试类位于 src\test\cn.edu.whut.springbear.uims.mapper.UserMapperTest 目录下,在 UserMapperTest 中使用 Spring 的方式进行测试,即指定 Spring 核心配置文件和 Spring 整合的 Junit4 测试类,文件内容如下:
package cn.edu.whut.springbear.uims.mapper; import cn.edu.whut.springbear.uims.pojo.User; 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 getByUsernameAndPassword() { User user = userMapper.getByUsernameAndPassword("bear", "bear"); System.out.println(user); } }
-
运行测试方法 cn.edu.whut.springbear.uims.mapper.UserMapperTest#getByUsernameAndPassword,测试结果如下图所示:
八、Spring MVC 拦截器
-
在 cn.edu.whut.springbear.uims.interceptor 包下新建登录拦截器类 LoginInterceptor,让其实现 HandlerInterceptor 接口以自定义拦截器功能,此处定义一个判断用户是否登录的拦截器,登录后放行,否则拦截请求。文件内容如下:
package cn.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; /** * @author Spring-_-Bear * @datetime 2022-06-25 22:22 Saturday */ @Component public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 检查 session 类中是否存在 user,存在则已登录并放行,否则拦截请求 return request.getSession().getAttribute("user") != null; } }
-
在 Spring MVC 的核心配置文件 spring-mvc-config.xml 中进行登录拦截器的相关配置。
<!-- 包扫描规则 --> <context:component-scan base-package="cn.edu.whut.springbear.uims.controller, cn.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>
-
将 src\main\webapp\WEB-INF\templates\index.html 文件内容修改为登录表单。修改后的文件内容如下:
<!DOCTYPE html> <html lang="zh-CN" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>用户登录</title> <style> body { font-family: Arial, sans-serif; background-color: #f1f1f1; } .container { max-width: 400px; margin: auto auto; padding: 20px; background-color: #fff; border-radius: 5px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); display: flex; flex-direction: column; align-items: center; } h1 { text-align: center; margin-bottom: 20px; } form { display: flex; flex-direction: column; } label { margin-bottom: 10px; font-weight: bold; } input[type="text"], input[type="password"] { padding: 10px; border-radius: 3px; border: 1px solid #ccc; margin-bottom: 15px; } button { padding: 10px; background-color: #4CAF50; color: #fff; border: none; border-radius: 3px; cursor: pointer; } button:hover { background-color: #45a049; } </style> </head> <body> <div class="container"> <h1>用户登录</h1> <form method="post" th:action="@{/login}"> <label for="username">用户名</label> <input type="text" id="username" name="username" required> <label for="password">密码</label> <input type="password" id="password" name="password" required> <button type="submit">立即登录</button> </form> </div> </body> </html>
-
在 cn.edu.whut.springbear.uims.service 包下新建用户登录接口 UserService。文件内容如下:
package cn.edu.whut.springbear.uims.service; import cn.edu.whut.springbear.uims.pojo.User; /** * @author Spring-_-Bear * @datetime 2022-06-25 22:38 Saturday */ public interface UserService { /** * 用户登录 * * @param username 用户名 * @param password 密码 * @return 用户名和密码正确返回用户信息,否则返回 null */ User login(String username, String password); }
-
在 cn.edu.whut.springbear.uims.service.impl 包下新建 UserService 接口的实现类 UserServiceImpl,实现用户登录接口相关逻辑,并使用 @Service 注解将该类标识为 Spring 组件供 IOC 容器管理。文件内容如下:
package cn.edu.whut.springbear.uims.service.impl; import cn.edu.whut.springbear.uims.mapper.UserMapper; import cn.edu.whut.springbear.uims.pojo.User; import cn.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 login(String username, String password) { return this.userMapper.getByUsernameAndPassword(username, password); } }
-
在 cn.edu.whut.springbear.uims.controller 包下创建用户控制器类 UserController,处理用户相关业务逻辑。文件内容如下:
package cn.edu.whut.springbear.uims.controller; import cn.edu.whut.springbear.uims.pojo.User; import cn.edu.whut.springbear.uims.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; 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; @PostMapping("/login") public String login(HttpSession session, @RequestParam String username, @RequestParam String password) { User user = this.userService.login(username, password); // 用户名不存在或密码错误,返回首页视图名称 index,跳转到首页 index.html if (user == null) { return "index"; } // session 域记录用户登录信息 session.setAttribute("user", user); // 登录成功,重定向到成功页面 return "redirect:/success"; } }
-
在 src\main\webapp\WEB-INF\templates 目录下新建成功视图页面 success.html。文件内容如下:
<!DOCTYPE html> <html lang="zh-CN" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>登录成功</title> <style> body { font-family: Arial, sans-serif; background-color: #f1f1f1; } .container { max-width: 400px; margin: 0 auto; padding: 20px; background-color: #fff; border-radius: 5px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); text-align: center; } h1 { margin-bottom: 20px; } a { color: #4CAF50; text-decoration: none; } a:hover { text-decoration: underline; } </style> </head> <body> <div class="container"> <h1 th:text="${'欢迎 '+session.user.username}+',登录成功!'">欢迎张三,登录成功!</h1> <p>登录时间:<span id="username">2023-06-14 10:21:34</span></p> <p>IP 属地:<span id="location">湖北省武汉市</span></p> <a href="#">退出登录</a> </div> </body> </html>
-
在 Spring MVC 的核心配置文件 src\main\resources\spring-mvc-config.xml 中增加登录成功视图 success.html 的视图控制器配置。
<!-- 视图控制器,此处 IDE 爆红问题可不予理会 --> <mvc:view-controller path="/" view-name="index"/> <mvc:view-controller path="/success" view-name="success"/>
-
启动 Tomcat,进行登录拦截器功能测试。若启动出现异常,可尝试删除 target 目录后重新启动 Tomcat。
-
用户未登录,通过浏览器地址栏直接访问 success 请求,请求将被拦截器拦截,不返回任何信息。
-
输入不正确的用户名和密码,登录后验证失败将跳转到 index.html 页面。
-
用户名密码正确,登录成功重定向到成功页面 success.html,并展示用户信息。
-
九、Spring MVC 异常解析器
-
在 cn.edu.whut.springbear.uims.exception 包下新建自定义异常类 InterceptorException。文件内容如下:
package cn.edu.whut.springbear.uims.exception; /** * @author Spring-_-Bear * @datetime 2022-06-25 23:17 Saturday */ public class InterceptorException extends RuntimeException { private static final long serialVersionUID = 2339004307463021785L; public InterceptorException(String message) { super(message); } }
-
在 Spring MVC 的核心配置文件 src\main\resources\spring-mvc-config.xml 中配置异常解析器处理异常信息。
<!-- 异常解析器 --> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <!-- 当遇到自定义的 InterceptorException 异常时,跳转视图名称为 index 的视图页面,也即 index.html --> <prop key="cn.edu.whut.springbear.uims.exception.InterceptorException">index</prop> </props> </property> <!-- 为异常信息设置一个属性名 msg,默认在 request 域中进行共享 --> <property name="exceptionAttribute" value="msg"/> </bean>
-
修改 cn.edu.whut.springbear.uims.interceptor.LoginInterceptor 登录拦截器逻辑,当用户未登录时手动抛出自定义的 InterceptorException 异常,交由异常解析器处理。修改后的文件内容如下:
package cn.edu.whut.springbear.uims.interceptor; import cn.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; /** * @author Spring-_-Bear * @datetime 2022-06-25 22:22 Saturday */ @Component public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object user = request.getSession().getAttribute("user"); // 检查用户是否登录,未登录则抛出自定义异常,否则放行 if (user == null) { throw new InterceptorException("请先登录您的账号"); } return true; } }
-
修改 src\main\webapp\WEB-INF\index.html 中的登录表单,增加错误信息展示元素。
<div class="container"> <h1>用户登录</h1> <form method="post" th:action="@{/login}"> <label for="username">用户名</label> <input type="text" id="username" name="username" required> <label for="password">密码</label> <input type="password" id="password" name="password" required> <!-- 取出 request 域中保存的 msg 异常信息并展示 --> <div style="margin-bottom: 15px; color: #ee0a24" th:text="${msg}"></div> <button type="submit">立即登录</button> </form> </div>
-
修改 cn.edu.whut.springbear.uims.controller.UserController#login 登录逻辑,当用户登录信息验证失败时手动抛出异常以友好提示用户,修改后的文件内容如下:
package cn.edu.whut.springbear.uims.controller; import cn.edu.whut.springbear.uims.exception.InterceptorException; import cn.edu.whut.springbear.uims.pojo.User; import cn.edu.whut.springbear.uims.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; 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; @PostMapping("/login") public String login(HttpSession session, @RequestParam String username, @RequestParam String password) { User user = this.userService.login(username, password); // 用户名不存在或密码错误,返回首页视图名称 index,跳转到首页 index.html if (user == null) { throw new InterceptorException("用户名不存在或密码错误"); } // session 域记录用户登录信息 session.setAttribute("user", user); // 登录成功,重定向到成功页面 return "redirect:/success"; } }
-
启动 Tomcat,进行异常解析器功能测试。
-
未登录账号直接访问 /success 请求时通过自定义的异常解析器跳转到 index.html 页面,并展示提示信息 “请先登录您的账号”。
-
当用户登录时输入错误的用户名和密码,跳转到 index.html,并友好提示用户 “用户名不存在或密码错误”。
-
十、Spring MVC 文件上传解析器
-
在 Spring MVC 的核心配置文件 src\main\resources\spring-mvc-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>
-
在 cn.edu.whut.springbear.uims.controller 包下新增 TransferController 类处理文件上传业务逻辑。文件内容如下:
package cn.edu.whut.springbear.uims.controller; import cn.edu.whut.springbear.uims.exception.InterceptorException; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpSession; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; /** * @author Spring-_-Bear * @since 23/06/14 14:41 */ @Controller public class TransferController { @ResponseBody @PostMapping("/upload") public Map<String, Object> fileUpload(HttpSession session, @RequestParam MultipartFile file) { // 获取文件上传保存目录在磁盘上的真实路径,相对路径为 ../src/main/webapp/static/upload String realPath = session.getServletContext().getRealPath("/static/upload"); // 如果文件夹不存在则新建 File directory = new File(realPath); if (!directory.exists()) { if (!directory.mkdirs()) { throw new InterceptorException("文件上传保存目录创建失败"); } } Map<String, Object> resultMap = new HashMap<>(); // 将文件写入到磁盘 File imgFile = new File(realPath + "/" + file.getOriginalFilename()); try { file.transferTo(imgFile); } catch (IOException e) { resultMap.put("data", "文件保存失败"); } resultMap.put("data", "文件上传成功"); return resultMap; } }
-
修改 src\main\webapp\WEB-INF\success.html,增加图片上传表单和图片上传业务逻辑。需要注意以下事项:
- 表单的请求方法 method 属性必须为 POST
- 必须设置 enctype 的属性值为 multipart/form-data
<!DOCTYPE html> <html lang="zh-CN" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>登录成功</title> <style> body { font-family: Arial, sans-serif; background-color: #f1f1f1; } .container { max-width: 400px; margin: 0 auto; padding: 20px; background-color: #fff; border-radius: 5px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); text-align: center; } h1 { margin-bottom: 20px; } a { color: #4CAF50; text-decoration: none; } a:hover { text-decoration: underline; } .form-container { max-width: 400px; margin: 0 auto; } .form-container h2 { text-align: center; } .form-container label { display: block; margin-bottom: 10px; } .form-container input[type="file"] { margin-bottom: 20px; } .form-container button { display: block; margin: 0 auto; } #output { margin-top: 30px; padding: 10px; border: 1px solid #ccc; background-color: #f9f9f9; display: none; } #output pre { white-space: pre-wrap; } </style> </head> <body> <div class="container"> <h1 th:text="${'欢迎 '+session.user.username}+',登录成功!'">欢迎张三,登录成功!</h1> <p>登录时间:<span id="username">2023-06-14 10:21:34</span></p> <p>IP 属地:<span id="location">湖北省武汉市</span></p> <a href="#">退出登录</a> </div> <div class="form-container"> <h2>图片上传表单</h2> <form id="uploadForm" enctype="multipart/form-data"> <label for="fileInput">选择图片:</label> <input type="file" id="fileInput" accept="image/*" required> <button type="submit">上传</button> </form> </div> <div id="output"> <h3>服务器返回的 JSON 数据:</h3> <pre id="jsonData"></pre> </div> <script> // 获取表单元素和输出区域元素 const uploadForm = document.getElementById('uploadForm'); const fileInput = document.getElementById('fileInput'); const outputDiv = document.getElementById('output'); const jsonDataPre = document.getElementById('jsonData'); // 监听表单的提交事件 uploadForm.addEventListener('submit', function (event) { event.preventDefault(); // 阻止表单默认提交行为 // 创建 FormData 对象 const formData = new FormData(); formData.append('file', fileInput.files[0]); // 创建 XMLHttpRequest 对象 const xhr = new XMLHttpRequest(); // 设置请求处理的回调函数 xhr.onreadystatechange = function () { if (xhr.readyState === XMLHttpRequest.DONE) { console.log(xhr) if (xhr.status === 200) { const response = JSON.parse(xhr.responseText); // 在输出区域展示 JSON 数据 jsonDataPre.textContent = JSON.stringify(response, null, 2); outputDiv.style.display = 'block'; // 显示输出区域 } else { alert('发生错误,无法上传文件!'); } } }; // 发送 POST 请求到服务器 xhr.open('POST', 'http://localhost:8080/uims/upload', true); xhr.send(formData); }); </script> </body> </html>
-
启动 Tomcat,在 index.html 中输入正确的账号和密码,系统验证通过后跳转到 success.html 中进行图片上传。
-
查看服务器保存的图片文件,位于 target 目录下。
至此,通过 XML 配置文件方式成功整合 Spring、Spring MVC 和 MyBatis 三大框架,并整合了一些开发过程中的常用功能,如单元测试、拦截器、异常解析器和文件上传解析器等。完整的工程目录结构图如下所示:
完成 XML 配置文件方式整合 SSM 框架后,在此基础上推荐 全注解方式整合 SSM 框架 。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)