SpringMVC
Spring MVC 是一种基于 Java 的Web框架,它采用了模型-视图-控制器(MVC)设计模式,用于开发Web应用程序。在 Spring MVC 中,控制器负责处理用户请求并返回响应,模型用于表示和管理应用程序中的数据,视图负责呈现模型数据以及接收用户输入。Spring MVC 旨在提供一个灵活的开发框架,使开发人员可以轻松地组合多个已有的模块以构建复杂的 Web 应用程序,同时提供了很多常用的功能,如请求映射、数据绑定、校验、拦截器等。
三层架构
Spring MVC 的三层架构指的是将应用程序分为模型(Model)、视图(View)和控制器(Controller)这三个层次,这是典型的基于模型-视图-控制器(MVC)设计模式的架构。
- 模型(Model):模型层负责表示和管理应用程序中的数据和业务逻辑。它包括数据模型、持久化操作、业务规则和数据验证等。模型层通常通过 POJO(Plain Old Java Objects)或者持久化框架如 Hibernate、MyBatis 等来表示和操作数据。它并不关心数据如何被展示和用户如何操作,它只是提供了对数据的访问和操作接口。
- 视图(View):视图层负责呈现模型数据,并与用户进行交互。它能够将模型中的数据以适当的方式展示给用户,如以 HTML、XML、JSON 等形式。视图层通常包括模板引擎(如 JSP、Thymeleaf 等)以及其他前端技术(如 JavaScript、CSS 等),用于生成并展示最终的用户界面。
- 控制器(Controller):控制器层负责处理用户请求并协调模型和视图之间的交互。它接收用户的输入,调用合适的模型来处理业务逻辑,然后将结果传递给适当的视图进行展示。控制器层通常由方法(也称为处理器方法)组成,这些方法被触发来处理特定的请求,并根据请求处理结果选择合适的视图进行响应。
核心组成
- 前端控制器(Front Controller):在 Spring MVC 中DispatcherServlet 充当了前端控制器的角色。它是整个请求处理流程的入口点,负责接收所有的请求并将其分发给合适的处理器进行处理。
- 处理器映射器(Handler Mapping):处理器映射器负责将请求映射到合适的处理器(controller)上。Spring MVC 内置了多种处理器映射器,如注解驱动的 RequestMappingHandlerMapping、基于 URL 映射的 SimpleUrlHandlerMapping 等。
- 处理器适配器(Handler Adapter):处理器适配器负责将处理器(controller)和前端控制器进行适配,确保能够正确调用处理器的方法。Spring MVC 内置了多种处理器适配器,如注解驱动的RequestMappingHandlerAdapter、基于 URL 映射的 SimpleControllerHandlerAdapter 等。
- 视图解析器(View Resolver):视图解析器负责将处理器返回的逻辑视图名称解析为真正的视图对象。Spring MVC 内置了多种视图解析器,如 InternalResourceViewResolver(用于 JSP 视图解析)、FreemarkerViewResolver、ThymeleafViewResolver 等。
- 视图(View):视图负责将模型数据显示给用户,一般是通过渲染模板来实现。常见的视图包括 JSP、Thymeleaf 模板、Freemarker 模板等。
- 模型(Model):模型表示应用程序中的数据,一般由处理器方法设置并传递给视图进行显示。Spring MVC 使用 ModelAndView 对象来封装模型数据。
- 拦截器(Interceptor):拦截器可以在请求的前后进行拦截和处理,可以用于实现日志记录、权限验证、字符编码等功能。
- 处理器异常解析器(HandlerExceptionResolver):处理器异常解析器负责捕获处理器方法中抛出的异常,并根据配置来处理异常,并返回友好的错误信息。
执行流程
(1)用户发送请求至前端控制器DispatcherServlet
(2)DispatcherServlet收到请求调用HandlerMapping处理器映射器。
(3)处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
(4)DispatcherServlet调用HandlerAdapter处理器适配器。
(5)HandlerAdapter经过适配调用具体的Handler处理器(Controller,也叫后端控制器)。Controller执行完成返回ModelAndView。
(6)HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet。
(7)DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
(8)ViewReslover解析后返回具体View视图。
(9)DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
(10)DispatcherServlet响应用户。
项目搭建
1.手动添加模块
(1)创建普通maven项目
(2)在项目的main文件夹下新建文件夹webapps
(3)选择File—>Project Structure
(4)选择Facets—>±–>web
(5)选择项目中的对应模块
(6)修改Deployment Descriptors下web.xml路径
(7)修改Web Resource Directory路径
2.通过Archetype添加模块
3.添加tomact
配置Tomcat并启动
-
选择Run—>Edit Configurations
-
选择±–>Tomcat Server—>Local
-
选择本地tomcat所在的地址【tomcat的bin目录上一层路径】,点击Fix
-
选择Artifacts—>Web Application:Exploded—>From Modules
-
选择项目中的对应模块,选择OK—>继续选择OK
-
启动Tomcat
注解
-
@Controller:标识一个类为 Spring MVC 的控制器。
@Controller public class UserController { // Controller 方法 }
在spiing-mvc下添加
扫描控制器所在的包<context:component-scan base-package="controller"/>
-
@RequestMapping:将请求映射到处理器类或方法上。作为类级别注解时,用于对控制器中所有请求进行 URL 路径的映射;作为方法级别注解时,用于对某个请求进行处理。
- 作用:用于建立请求URL和处理请求方法之间的对应关系
- 位置:
- 类上,请求URL的第一级访问目录。此处不写的话,就相当于应用的根目录
- 方法上,请求URL的第二级访问目录,与类上的使用@ReqquestMapping标注的一级目录一起组成访问虚拟路径
- 属性:
- value:用于指定请求的URL。它和path属性的作用是一样的
- method:用于指定请求的方式
- params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的key和value必须和配置的一模一样
- 例如:
- params = {“accountName”},表示请求参数必须有accountName
- 例如:
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/home") public String home() { return "home"; } }
-
@RequestParam:用于将请求中的参数绑定到控制器处理方法的参数上。
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/profile") public String userProfile(@RequestParam("id") int id) { // 使用 id 参数处理逻辑 return "profile"; } }
-
@PathVariable:用于将请求 URI 中的模板变量绑定到控制器处理方法的参数上。
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/profile/{id}") public String userProfile(@PathVariable("id") int id) { // 使用 id 参数处理逻辑 return "profile"; } }
-
@ResponseBody:将返回值作为响应体返回给客户端,一般用于返回 JSON 或 XML 数据。
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/profile/{id}") @ResponseBody public User getUserProfile(@PathVariable("id") int id) { User user = userService.getUserById(id); return user; } }
-
@RequestBody:用于将请求体绑定到方法参数或方法返回值中。
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/update") public String updateUserProfile(@RequestBody User user) { // 处理更新用户信息的逻辑 return "success"; } }
-
@ModelAttribute:将请求中的某个参数绑定到模型对象上,并将此对象添加到请求模型中。
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/add") public String addUser(@ModelAttribute("user") User user) { // 处理添加用户的逻辑 return "success"; } }
-
@SessionAttributes:将模型中的某些属性存入 session 中,方便后续请求获取。
@Controller @RequestMapping("/user") @SessionAttributes("user") public class UserController { @RequestMapping("/profile") public String getUserProfile(Model model) { User user = userService.getUser(); model.addAttribute("user", user); return "profile"; } }
-
@InitBinder:用于处理表单数据的绑定,自定义格式转换器等。
@Controller public class UserController { @InitBinder public void initBinder(WebDataBinder binder) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true)); } @RequestMapping("/submit") public String submitForm(@ModelAttribute("user") User user) { // 处理提交表单的逻辑 return "success"; } }
-
@ControllerAdvice:定义控制器通知,作为全局异常处理器等。@ExceptionHandler:用于处理指定类型的异常。
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public ModelAndView handleException(Exception ex) { // 处理异常 ModelAndView mav = new ModelAndView("error"); mav.addObject("error", ex.getMessage()); return mav; } }
-
@ResponseStatus:用于指定异常时返回的 HTTP 状态码。
@RestController public class MyController { @ResponseStatus(HttpStatus.NOT_FOUND) @ExceptionHandler(ResourceNotFoundException.class) public String handleResourceNotFoundException(ResourceNotFoundException ex) { return ex.getMessage(); } }
数据响应方式
1.返回视图页面:在控制器方法中使用字符串作为返回值,表示要返回的视图页面的名称。框架将根据配置的视图解析器找到对应的视图页面,并将其渲染后返回给客户端。
@Controller
public class MyController {
@RequestMapping("/home")
public String home(Model model) {
model.addAttribute("message", "Hello, World!");
return "home";
}
}
2.返回JSON数据:在控制器方法中使用@ResponseBody
注解将方法返回的对象序列化为JSON格式,并将其作为响应的内容返回给客户端。
@RestController
public class MyRestController {
@RequestMapping("/data")
public ResponseEntity<Map<String, String>> getData() {
Map<String, String> data = new HashMap<>();
data.put("message", "Hello, World!");
return ResponseEntity.ok(data);
}
}
3.返回XML数据:类似于返回JSON数据,可以使用@ResponseBody
注解将方法返回的对象序列化为XML格式,并将其作为响应的内容返回给客户端。
@RestController
public class MyRestController {
@RequestMapping(value = "/data", produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<MyObject> getData() {
MyObject obj = new MyObject();
obj.setMessage("Hello, World!");
return ResponseEntity.ok(obj);
}
}
数据传递和处理
-
Map:Map是Java中的接口,用于存储键值对的集合。在Spring MVC中,你可以使用Map对象来存储需要传递给View的数据。在控制器方法中,直接将Map对象作为参数传递,并向其中添加键值对来存储数据。这些数据可以在视图页面中使用对应的键来进行访问。
@RequestMapping("/home") public String home(Map<String, Object> model) { model.put("message", "Hello, World!"); return "home"; }
-
Model:Model是Spring MVC中用于向View传递数据的接口,它是对Map的封装。在控制器方法中,可以直接使用Model对象作为参数,并调用其
addAttribute
方法来添加数据。@RequestMapping("/home") public String home(Model model) { model.addAttribute("message", "Hello, World!"); return "home"; }
-
ModelAndView:ModelAndView是Spring MVC中用于同时传递数据和指定视图的一个封装类。你可以通过创建一个ModelAndView对象,设置视图名称并添加数据,然后将其返回给DispatcherServlet。
@RequestMapping("/home") public ModelAndView home() { ModelAndView modelAndView = new ModelAndView("home"); modelAndView.addObject("message", "Hello, World!"); return modelAndView; }
-
@SessionAttribute:@SessionAttribute注解用于将模型属性与会话中的属性进行绑定。通过在控制器类或控制器方法上添加@SessionAttribute注解,并指定要绑定的属性名称,就可以让这些属性在多个请求之间保持一致。
@Controller @SessionAttributes("user") public class MyController { @ModelAttribute("user") public User getUser() { return new User(); } @RequestMapping("/profile") public String showProfile(@ModelAttribute("user") User user) { // 使用user对象进行处理 return "profile"; } }
-
@ModelAttribute:@ModelAttribute注解用于将表单提交的数据或路径变量绑定到控制器方法的参数或返回值上。在控制器方法中,你可以使用@ModelAttribute注解将表单数据自动绑定到参数对象中,或者从数据库或其他来源获取数据并将其包装为一个对象。在返回视图时,@ModelAttribute注解可以将对象添加到模型中,供视图使用。
@RequestMapping("/save") public String saveData(@ModelAttribute("user") User user) { // 处理提交的表单数据 return "success"; }
4.返回文件下载:可以通过控制器方法返回ResponseEntity<Resource>
来实现文件下载。将文件内容封装为Resource
对象,并设置相应的HTTP头信息,然后将Resource
对象包装到ResponseEntity
中返回给客户端。
@Controller
public class MyController {
@RequestMapping("/download")
public ResponseEntity<Resource> downloadFile() throws IOException {
File file = new File("path/to/file.pdf");
Resource resource = new FileSystemResource(file);
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + file.getName());
return ResponseEntity.ok()
.headers(headers)
.contentLength(file.length())
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(resource);
}
}
配置文件
1.在web.xml中配置DispatcherServlet
<!-- 配置DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 配置DispatcherServlet接受所有URL请求 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
2.在 web.xml添加 SpringMVC的一个过滤器,用于将请求和响应进行编码,以免中文乱码
<!-- 编码过滤器,解决中文乱码问题 -->
<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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3.创建Spring MVC的配置文件“spring-mvc.xml”
1.①在“resources”下创建配置文件“spring-mvc.xml”
2.
<?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
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 这里添加其他配置 -->
</beans>
修改“web.xml”,配置在tomcat启动的时候自动加载“spring-mvc.xml”配置
<!-- 配置DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 加载类路径下的spring-mvc.xml -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
示例
(1)配置视图解析器
-
xml方式:
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"></property> <property name="suffix" value=".jsp"></property> </bean>
-
注解方式:
//在spring配置类中加入视图解析器的配置 @Bean public InternalResourceViewResolver internalResourceViewResolver(){ InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setPrefix("/WEB-INF/views/"); viewResolver.setSuffix(".jsp"); return viewResolver; }
-
编写控制器和处理请求的方法
@Controller public class HelloController { @RequestMapping("/hello") public String hello(){ System.out.println("hello···"); return "hello"; } }
(2)返回字符串
-
直接返回字符串:此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转
资源地址:/WEB-INF/views/hello.jsp
-
返回带有前缀的字符串:
转发:forward:/WEB-INF/views/hello.jsp
重定向:redirect:/index.jsp
@RequestMapping("/forward")
public String forword(){
System.out.println("forward···");
return "forward:/WEB-INF/views/index.jsp";
}
@RequestMapping("/redirect")
public String redirect(){
System.out.println("redirect···");
return "redirect:/login.jsp";
}
(3)返回ModelAndView对象
- 修改hello.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
你好,SpringMVC!${username}
</body>
</html>
- 编写控制器中处理请求的方法
@RequestMapping("/hello2")
public ModelAndView hello2(){
//Model:模型,用于封装数据
//View:视图,用于展示数据
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("username","pep7chiao");
modelAndView.setViewName("hello");
return modelAndView;
}
@RequestMapping("/hello3")
public ModelAndView hello3(ModelAndView modelAndView){
modelAndView.addObject("username","pep7chiao");
modelAndView.setViewName("hello");
return modelAndView;
}
@RequestMapping("/hello4")
public String hello4(Model model){
model.addAttribute("username","messi");
return "hello";
}
@RequestMapping("/hello5")
public String hello5(HttpServletRequest reqest){ //HttpServletRequest需要添加依赖
reqest.setAttribute("username","ronaldo");
return "hello";
}
3.回写数据
(1)直接返回字符串
-
通过SpringMVC框架注入的response对象,使用response.getWriter().print(“hello world”)回写数据,此时不需要视图跳转,业务方法返回值为void。
@RequestMapping("/data1") public void data1(HttpServletResponse response) throws IOException { response.setContentType("text/html;charset=utf-8"); response.getWriter().print("重庆工程学院"); }
-
将需要回写的字符串直接返回,但此时需要通过**@ResponseBody**注解告知SpringMVC框架,方法返回的字符串不是跳
转,而是直接在http响应体中返回。
@RequestMapping(value = "/data2",produces = "text/html;charset=utf-8") @ResponseBody public String data2(){ return "软件工程研究所"; }
(2)返回对象或集合
- 导入json相关依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
-
开启mvc的注解驱动
-
xml方式:spring核心配置文件中加以下配置
<mvc:annotation-driven/>
-
注解方式:spring配置类上加以下注解
@EnableWebMvc
-
-
在com.cqgcxy.entity包下创建实体类
回写数据
(1)直接返回字符串
-
通过SpringMVC框架注入的response对象,使用response.getWriter().print(“hello world”)回写数据,此时不需要视图跳转,业务方法返回值为void。
@RequestMapping("/data1") public void data1(HttpServletResponse response) throws IOException { response.setContentType("text/html;charset=utf-8"); response.getWriter().print("重庆工程学院"); }
-
将需要回写的字符串直接返回,但此时需要通过**@ResponseBody**注解告知SpringMVC框架,方法返回的字符串不是跳
转,而是直接在http响应体中返回。
@RequestMapping(value = "/data2",produces = "text/html;charset=utf-8") @ResponseBody public String data2(){ return "软件工程研究所"; }
(2)返回对象或集合
- 导入json相关依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
-
开启mvc的注解驱动
-
xml方式:spring核心配置文件中加以下配置
<mvc:annotation-driven/>
-
注解方式:spring配置类上加以下注解
@EnableWebMvc
-
-
在com.cqgcxy.entity包下创建实体类
- 编写控制器中处理请求的方法
@RequestMapping("/data3")
@ResponseBody
public Phone data3() {
Phone phone = new Phone();
phone.setPhoneId(1L);
phone.setBrandId(1L);
phone.setModelNumber("mate60");
phone.setCapacity(256);
return phone;
}
2(){
return “软件工程研究所”;
}
(2)返回对象或集合
* 导入json相关依赖
```xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
-
开启mvc的注解驱动
-
xml方式:spring核心配置文件中加以下配置
<mvc:annotation-driven/>
-
注解方式:spring配置类上加以下注解
@EnableWebMvc
-
-
在com.cqgcxy.entity包下创建实体类
- 编写控制器中处理请求的方法
@RequestMapping("/data3")
@ResponseBody
public Phone data3() {
Phone phone = new Phone();
phone.setPhoneId(1L);
phone.setBrandId(1L);
phone.setModelNumber("mate60");
phone.setCapacity(256);
return phone;
}