Spring MVC 什么是Spring MVC? 是Spring框架的一部分,是一个基于Java的Web开发框架,遵循经典的MVC设计模式 。它通过分离应用程序的输入逻辑、业务逻辑和显示逻辑,帮助开发者构建灵活、可扩展且易于维护的Web应用程序。
MVC模式:
Model(模型) :负责处理数据和业务逻辑,通常由JavaBean或POJO(Plain Old Java Object)组成,可能涉及服务层(Service)和数据访问层(DAO)。
View(视图) :负责展示数据,支持多种视图技术(如JSP、Thymeleaf、FreeMarker等),通过逻辑视图名称与具体模板关联。
Controller(控制器) :处理用户请求,协调模型和视图。通过注解(如@Controller)标识,并使用@RequestMapping等注解映射HTTP请求到具体方法。
核心组件:
DispatcherServlet: 前端控制器,接收所有请求并分发给对应的处理器(Handler),是Spring MVC的入口。
HandlerMapping: 根据请求URL找到对应的Controller方法(处理器)。
HandlerAdapter: 调用处理器方法,并将结果封装为ModelAndView对象(模型数据+视图名称)。
ViewResolver: 解析逻辑视图名称为具体的视图对象(如JSP页面),并渲染模型数据。
web.xml: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <?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 > <init-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:springmvc-servlet.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > springmvc</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping > <welcome-file-list > <welcome-file > /WEB-INF/jsp/welcome.jsp</welcome-file > </welcome-file-list > <filter > <filter-name > encoding</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 > </filter > <filter-mapping > <filter-name > encoding</filter-name > <url-pattern > /*</url-pattern > </filter-mapping > </web-app >
springmvc-servlet.xml: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <?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:mvc ="http://www.springframework.org/schema/mvc" 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 http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd" > <bean class ="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> <bean class ="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" /> <context:component-scan base-package ="com.itcast.controller" /> <mvc:annotation-driven /> <mvc:resources mapping ="/resources/**" location ="/resources/" /> <bean class ="org.springframework.web.servlet.view.InternalResourceViewResolver" id ="InternalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/jsp/" /> <property name ="suffix" value =".jsp" /> </bean > </beans >
使用Spring MVC框架的流程: 1.用户发送HTTP请求到DispatcherServlet。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <servlet > <servlet-name > springmvc</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class > <init-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:springmvc-servlet.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > springmvc</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping >
2.DispatcherServlet通过HandlerMapping找到对应的Controller方法(处理器)。 1 2 <bean class ="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Override protected String[] determineUrlsForHandler(String beanName) { List<String> urls = new ArrayList <>(); if (beanName.startsWith("/" )) { urls.add(beanName); } String[] aliases = obtainApplicationContext().getAliases(beanName); for (String alias : aliases) { if (alias.startsWith("/" )) { urls.add(alias); } } return StringUtils.toStringArray(urls); }
3.HandlerAdapter调用处理器方法,处理业务逻辑并返回ModelAndView。 1 2 <bean class ="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 public class SimpleControllerHandlerAdapter implements HandlerAdapter { @Override public boolean supports (Object handler) { return (handler instanceof Controller); } @Override @Nullable public ModelAndView handle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return ((Controller) handler).handleRequest(request, response); } @Override public long getLastModified (HttpServletRequest request, Object handler) { if (handler instanceof LastModified) { return ((LastModified) handler).getLastModified(request); } return -1L ; } }
4.ViewResolver根据视图名称解析具体的视图资源(如JSP页面)。 5.视图渲染模型数据,生成HTML等响应内容返回给用户。 SSM整合(登录案例) 项目结构
1.配置文件
1.1 pom.xml: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <groupId > com.itcast</groupId > <artifactId > ssm</artifactId > <version > 1.0-SNAPSHOT</version > <name > ssm</name > <packaging > war</packaging > <properties > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > <maven.compiler.target > 1.8</maven.compiler.target > <maven.compiler.source > 1.8</maven.compiler.source > <junit.version > 5.9.2</junit.version > </properties > <dependencies > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.12</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.33</version > </dependency > <dependency > <groupId > com.alibaba</groupId > <artifactId > druid</artifactId > <version > 1.2.8</version > </dependency > <dependency > <groupId > javax.servlet</groupId > <artifactId > servlet-api</artifactId > <version > 2.5</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 > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.2</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-spring</artifactId > <version > 2.0.2</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > 5.1.9.RELEASE</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > 5.1.9.RELEASE</version > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > RELEASE</version > <scope > provided</scope > </dependency > </dependencies > <build > <resources > <resource > <directory > src/main/java</directory > <includes > <include > **/*.properties</include > <include > **/*.xml</include > </includes > <filtering > false</filtering > </resource > <resource > <directory > src/main/resources</directory > <includes > <include > **/*.properties</include > <include > **/*.xml</include > </includes > <filtering > false</filtering > </resource > </resources > </build > </project >
1.2 web.xml: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 <?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 > DispatcherServlet</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class > <init-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:applicationContext.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 > <filter > <filter-name > encodingFilter</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 > </filter > <filter-mapping > <filter-name > encodingFilter</filter-name > <url-pattern > /*</url-pattern > </filter-mapping > <session-config > <session-timeout > 15</session-timeout > </session-config > <welcome-file-list > <welcome-file > /WEB-INF/jsp/login.jsp</welcome-file > </welcome-file-list > </web-app >
1.3 applicationContext.xml(总配置): 1 2 3 4 5 6 7 8 9 <?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" > <import resource ="spring-dao.xml" /> <import resource ="spring-bean.xml" /> <import resource ="spring-mvc.xml" /> </beans >
1.4 spring-dao.xml(Spring和MyBatis整合): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <?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:property-placeholder location ="classpath:database.properties" /> <bean id ="dataSource" class ="com.alibaba.druid.pool.DruidDataSource" > <property name ="driverClassName" value ="${jdbc.driver}" /> <property name ="url" value ="${jdbc.url}" /> <property name ="username" value ="${jdbc.username}" /> <property name ="password" value ="${jdbc.password}" /> <property name ="initialSize" value ="1" /> <property name ="maxActive" value ="10" /> <property name ="minIdle" value ="1" /> <property name ="maxWait" value ="6000" /> <property name ="timeBetweenEvictionRunsMillis" value ="6000" /> </bean > <bean id ="sqlSessionFactory" class ="org.mybatis.spring.SqlSessionFactoryBean" > <property name ="dataSource" ref ="dataSource" /> <property name ="configLocation" value ="classpath:mybatis-config.xml" /> </bean > <bean class ="org.mybatis.spring.mapper.MapperScannerConfigurer" > <property name ="sqlSessionFactoryBeanName" value ="sqlSessionFactory" /> <property name ="basePackage" value ="com.itcast.dao" /> </bean > </beans >
mybatis-config.xml:
1 2 3 4 5 6 7 8 9 10 11 12 <?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 > <typeAliases > <package name ="com.itcast.pojo" /> </typeAliases > <mappers > <mapper resource ="com/itcast/dao/UserMapper.xml" /> </mappers > </configuration >
database.properties:
1 2 3 4 jdbc.driver =com.mysql.cj.jdbc.Driver jdbc.url =jdbc:mysql://localhost:3306/mybatis jdbc.username =root jdbc.password =root
1.5 spring-mvc.xml(Spring和SpringMVC整合): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <?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 http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd" > <mvc:annotation-driven /> <mvc:default-servlet-handler /> <bean class ="org.springframework.web.servlet.view.InternalResourceViewResolver" > <property name ="viewClass" value ="org.springframework.web.servlet.view.JstlView" /> <property name ="prefix" value ="/WEB-INF/jsp/" /> <property name ="suffix" value =".jsp" /> </bean > <context:component-scan base-package ="com.itcast.controller" /> </beans >
1.6 spring-bean.xml(Spring配置bean) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?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 http://www.springframework.org/schema/context/spring-context.xsd" > <context:component-scan base-package ="com.itcast.service" /> <bean id ="UserServiceImpl" class ="com.itcast.service.UserServiceImpl" > <property name ="userMapper" ref ="userMapper" /> </bean > <bean id ="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" /> </bean > </beans >
1.7 user表: 1 2 3 4 5 6 7 create table if not exists user ( id varchar (50 ) not null primary key , username varchar (50 ) null , password varchar (50 ) null );
2.编写pojo实体类层: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.itcast.pojo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data @NoArgsConstructor @AllArgsConstructor public class User { private String id; private String username; private String password; public User (String username, String password) { this .username = username; this .password = password; } }
3.编写Dao层 数据库交互层
UserMapper.class:
1 2 3 4 5 6 7 8 9 10 package com.itcast.dao;import com.itcast.pojo.User;public interface UserMapper { User getUserById (Integer id) ; User getUserByName (String name) ; void addUser (User user) ; User login (User user) ; }
UserMapper.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?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.itcast.dao.UserMapper" > <select id ="getUserById" parameterType ="int" resultType ="com.itcast.pojo.User" > select * from user where id = #{id} </select > <select id ="getUserByName" parameterType ="java.lang.String" resultType ="com.itcast.pojo.User" > select * from user where username = #{username} </select > <select id ="login" resultType ="com.itcast.pojo.User" parameterType ="com.itcast.pojo.User" > select * from user where username = #{username} and password = #{password} </select > <insert id ="addUser" parameterType ="com.itcast.pojo.User" > insert into user values (#{id},#{username},#{password}) </insert > </mapper >
4.编写Service层: UserService.interface
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.itcast.service;import com.itcast.pojo.User;import org.springframework.ui.Model;public interface UserService { User getUserById (Integer id) ; User getUserByName (String name) ; void addUser (User user) ; String login (Model model, User user) ; String register (Model model, String username, String password, String confirm) ; }
UserServiceImpl.class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 package com.itcast.service;import com.itcast.dao.UserMapper;import com.itcast.pojo.User;import org.springframework.ui.Model;import java.util.UUID;public class UserServiceImpl implements UserService { private UserMapper userMapper; public void setUserMapper (UserMapper userMapper) { this .userMapper = userMapper; } @Override public String login (Model model, User user) { User user1 = userMapper.login(user); if (user1 != null ){ return "success" ; }else { model.addAttribute("msg" , "用户名或密码错误" ); return "fail" ; } } @Override public String register (Model model, String username, String password, String confirm) { if (password.equals(confirm)){ User user = userMapper.getUserByName(username); if (user == null ) { User register = new User (username, password); UUID uuid = UUID.randomUUID(); register.setId(uuid.toString()); userMapper.addUser(register); return "login" ; }else { model.addAttribute("msg" , "该用户已经注册" ); return "fail" ; } }else { model.addAttribute("msg" , "两次密码不一致" ); return "fail" ; } } }
6.编写Controller层: UserController.class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package com.itcast.controller;import com.itcast.pojo.User;import com.itcast.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;@Controller public class UserController { @Autowired private UserService userService; @RequestMapping("/login") public String login (Model model, String username, String password) { model.addAttribute("username" ,username); return userService.login(model, new User (username,password)); } @RequestMapping("/register") public String register (Model model, String username, String password, String confirm) { return userService.register(model, username, password, confirm); } @RequestMapping("/register_forward") public String forwardRegisterPage () { return "register" ; } }
7.Web层界面 login.jsp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>登录</title> <style> body { font-family: Arial, sans-serif; background-color: #f4f4f9; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0 ; } form { background-color: #fff; padding: 20px; border-radius: 5px; box-shadow: 0 0 10px rgba (0 , 0 , 0 , 0.1 ) ; } input[type="text" ], input[type="password" ] { width: 100 %; padding: 10px; margin: 10px 0 ; border: 1px solid #ccc; border-radius: 5px; } input[type="submit" ] { background-color: #007bff; color: white; padding: 10px 15px; border: none; border-radius: 5px; cursor: pointer; } input[type="submit" ]:hover { background-color: #0056b3; } a { display: block; text-align: center; margin-top: 10px; color: #007bff; text-decoration: none; } a:hover { text-decoration: underline; } </style> </head> <body> <form action="/login" method="post" > <div> <label for ="username" >用户名:</label> <input type="text" id="username" name="username" required> </div> <div> <label for ="password" >密码:</label> <input type="password" id="password" name="password" required> </div> <input type="submit" value="登录" > <button onclick="window.location.href='/register_forward'" >注册</button> </form> </body> </html>
register.jsp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>注册</title> <style> body { font-family: Arial, sans-serif; background-color: #f4f4f9; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0 ; } form { background-color: #fff; padding: 20px; border-radius: 5px; box-shadow: 0 0 10px rgba (0 , 0 , 0 , 0.1 ) ; width: 300px; } input[type="text" ], input[type="email" ], input[type="password" ], input[type="confirm" ] { width: 100 %; padding: 10px; margin: 10px 0 ; border: 1px solid #ccc; border-radius: 5px; } input[type="submit" ] { background-color: #28a745; color: white; padding: 10px 15px; border: none; border-radius: 5px; cursor: pointer; width: 100 %; } input[type="submit" ]:hover { background-color: #218838 ; } label { display: block; margin-bottom: 5px; font-weight: bold; } </style> </head> <body> <form action="/register" method="post" > <div> <label for ="username" >用户名:</label> <input type="text" id="username" name="username" required> </div> <div> <label for ="password" >密码:</label> <input type="password" id="password" name="password" required> </div> <div> <label for ="confirm" >确认密码:</label> <input type="confirm" id="confirm" name="confirm" required> </div> <input type="submit" value="注册" > </form> </body> </html>
fail.jsp:
1 2 3 4 5 6 7 8 9 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Error</title> </head> <body> ${msg} </body> </html>
success.jsp:
1 2 3 4 5 6 7 8 9 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Success</title> </head> <body> 登录成功,${username} </body> </html>