Spring MVC

Spring MVC 是 Spring 框架中用于构建 Web 应用程序的核心模块,它基于经典的 MVC (Model-View-Controller) 设计模式。本教程只针对注解开发,可以快速上手。

(一)快速入门

  1. 创建一个WEB项目,并导入依赖

    注意:Tomcat9.0.97版本低于10使用依赖javax.servlet,但如果Tomcat版本大于10使用jakarta.servlet,即tomcat版本与spring的版本要对应,否则可能会出现一些问题

     <dependencies>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-webmvc</artifactId>
             <version>5.3.30</version> <!-- Spring 5 最新稳定版本 -->
         </dependency>
     ​
         <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>
             <version>4.0.1</version>
             <scope>provided</scope>
         </dependency>
     </dependencies>
  2. 在config包下设置servlet容器的配置
     public class ServletContainerInitConfig extends AbstractDispatcherServletInitializer {
     ​
         /**
          * 创建Servlet的容器,加载springMVC对应的bean并放入其中
          * @return
          */
         @Override
         protected WebApplicationContext createServletApplicationContext() {
             AnnotationConfigWebApplicationContext ctx=new AnnotationConfigWebApplicationContext();
             ctx.register(SpringMvcConfig.class);
             return ctx;
         }
     ​
         /**
          * 配置请求路径,设置为 / 表示拦截所有请求
          */
         @Override
         protected String[] getServletMappings() {
             return new String[]{"/"};
         }
     ​
         /**
          * 如果加载Servlet容器时,需要加载非sprintMVC对应的类用到该方法
          * @return
          */
         @Override
         protected WebApplicationContext createRootApplicationContext() {
             AnnotationConfigWebApplicationContext ctx=new AnnotationConfigWebApplicationContext();
             ctx.register(SpringConfig.class);
             return ctx;
         }
     }

  3. 在config包下设置springMVC的配置类

     import org.springframework.context.annotation.ComponentScan;
     import org.springframework.context.annotation.Configuration;
     ​
     @Configuration
     @ComponentScan("com.cqut.controller")
     public class SpringMvcConfig {
     }
  4. 实现简单的controller

     import org.springframework.stereotype.Controller;
     import org.springframework.web.bind.annotation.RequestMapping;
     import org.springframework.web.bind.annotation.RequestMethod;
     import org.springframework.web.bind.annotation.ResponseBody;
     ​
     @Controller
     @RequestMapping("/user")
     public class UserController {
     ​
         @RequestMapping(value="/save",method={RequestMethod.POST,RequestMethod.GET})
         @ResponseBody
         public String save(){
             System.out.println("springMVC...");
             return "{'success':'hello'}";
         }
     ​
         @RequestMapping("/delete")
         @ResponseBody
         public void delete(){
             System.out.println("6");
         }
     }

执行流程

(二)Bean的加载控制

一般情况springMVC对应的Bean(controller中的Bean)与spring中的Bean要分开加载,下面是两种控制Bean加载的方法。

  1. 精准扫描包

     @Configuration
     @ComponentScan({"com.cqut.service","com.cqut.dao"})
     ​
     public class SpringConfig {
     }
  2. 配置过滤器

     @Configuration
     @ComponentScan(
             value = "com.cqut",
             excludeFilters = @ComponentScan.Filter(
                     type = FilterType.ANNOTATION,
                     classes = Controller.class
             )
     ​
     )
     public class SpringConfig {
     }

配置Servlet容器的简化开发

 /**
  * 配置Servlet的容器
  */
 public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
 ​
 ​
     @Override
     protected Class<?>[] getRootConfigClasses() {
         return new Class[]{SpringConfig.class};
     }
 ​
     @Override
     protected Class<?>[] getServletConfigClasses() {
         return new Class[]{SpringMvcConfig.class};
     }
 ​
     @Override
     protected String[] getServletMappings() {
         return new String[]{"/"};
     }
 }

(三)请求与响应

普通参数配置

 @RequestMapping("/commonParam")
 @ResponseBody
 public void add(String name,int age){
     System.out.println("name :" + name);
     System.out.println("age :" + age);
 ​
 }

处理中文乱码

在容器Servlet配置新增拦截器

 @Override
 protected Filter[] getServletFilters() {
     CharacterEncodingFilter filter = new CharacterEncodingFilter();
     filter.setEncoding("UTF-8");
     return new Filter[]{filter};
 }

特殊类型参数配置

注意对于json数据转换需要导入依赖并在SpringMVC配置类添加 @EnableWebMvc

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.16.1</version> <!-- 最新稳定版本 -->
</dependency>
@RequestMapping("/diffParam")
@ResponseBody
public void diffParamMethod(@RequestParam("name") String userName, int age){
    System.out.println("name :" + userName);
    System.out.println("age :" + age);

}

// 引用类型
@RequestMapping("/pojoParam")
@ResponseBody
public void pojoParamMethod(User user){
    System.out.println("age :" + user);

}

// 嵌套引用
@RequestMapping("/pojoParamDemo")
@ResponseBody
public void pojoParamMethodDemo(User user){
    System.out.println("age :" + user);

}

@RequestMapping("/arrayParam")
@ResponseBody
public void arrayParamMethod(String[] likes){
    System.out.println("age :" + likes);

}

@RequestMapping("/listParam")
@ResponseBody
public void listParamMethod(@RequestParam List<String> list){
    System.out.println("age :" + list);
}

// 接受json数据
@RequestMapping("/arrayJsonParam")
@ResponseBody
public void arrayJsonParamMethod(@RequestBody String[] list){
    System.out.println("age :" + list);
}

// 接受json数据
@RequestMapping("/listJsonParam")
@ResponseBody
public void listJsonParamMethod(@RequestBody List<User> list){
    System.out.println("age :" + list);
}

// 接受json数据
@RequestMapping("/pojoJsonParam")
@ResponseBody
public void pojoJsonParamMethod(@RequestBody User user){
    System.out.println("age :" + user);
}

(四)常用注解功能

注解名称功能说明使用示例
@Controller标记一个类为 Spring MVC 控制器。负责处理 HTTP 请求,通常与方法级的 @RequestMapping 及其变体结合使用。@Controller public class UserController { ... }
@RestController@Controller@ResponseBody 的组合注解。标记的类中所有方法返回值默认直接写入 HTTP 响应体(如 JSON/XML),用于构建 RESTful Web 服务。@RestController @RequestMapping("/api/users") public class UserApiController { ... }
@RequestMapping将 HTTP 请求映射到 MVC 控制器方法。可指定 URL 路径、HTTP 方法(GET/POST/PUT/DELETE 等)、请求参数、请求头等条件。@RequestMapping(value = "/users", method = RequestMethod.GET) public List<User> listUsers() { ... }
@GetMapping @PostMapping @PutMapping @DeleteMapping @PatchMapping@RequestMapping 的特定 HTTP 方法快捷方式。分别用于映射 GET、POST、PUT、DELETE、PATCH 请求。更简洁常用。@GetMapping("/users/{id}") public User getUser(@PathVariable Long id) { ... } @PostMapping("/users") public User createUser(@RequestBody User user) { ... }
@PathVariable将 URI 模板变量绑定到方法参数。用于从 URL 路径中提取值。@GetMapping("/users/{userId}/orders/{orderId}") public Order getOrder( @PathVariable("userId") Long userId, @PathVariable Long orderId) { ... } // 名称匹配时可省略("orderId")
@RequestParam将 HTTP 请求参数绑定到方法参数。用于获取查询字符串(?name=value)或表单数据(application/x-www-form-urlencoded)。@GetMapping("/search") public List<User> searchUsers( @RequestParam("name") String name, @RequestParam(value = "page", defaultValue = "1") int page) { ... }
@RequestBody将 HTTP 请求体(通常是 JSON/XML)绑定到方法参数对象。常用于接收 POST/PUT 提交的复杂数据。@PostMapping("/users") public ResponseEntity<User> createUser( @RequestBody @Valid User newUser) { ... } // @Valid 用于触发数据校验
@ResponseBody指示方法返回值应直接写入 HTTP 响应体(而非视图解析)。通常用于返回 JSON/XML 数据。@RestController 已包含此注解。@GetMapping("/users/{id}") @ResponseBody // 在 @Controller 类中需要显式添加 public User getUser(@PathVariable Long id) { ... }
@ModelAttribute1. 方法参数: 将请求参数绑定到命令/表单对象。 2. 方法上: 在控制器方法执行前向模型添加属性。参数: @PostMapping("/submitForm") public String submitForm(@ModelAttribute("userForm") User user) { ... } 方法: @ModelAttribute("categories") public List<String> populateCategories() { ... } // 此方法在所有控制器方法前执行
@RequestHeader将 HTTP 请求头绑定到方法参数@GetMapping("/someEndpoint") public String handle( @RequestHeader("User-Agent") String userAgent, @RequestHeader(value = "Accept", defaultValue = "application/json") String accept) { ... }
@CookieValue将 HTTP Cookie 的值绑定到方法参数@GetMapping("/dashboard") public String dashboard( @CookieValue("JSESSIONID") String sessionId) { ... }
@SessionAttribute将 HTTP Session 中的属性绑定到方法参数@GetMapping("/checkout") public String checkout( @SessionAttribute("cart") ShoppingCart cart) { ... }
@Valid / @Validated触发对绑定到方法参数(如 @RequestBody, @ModelAttribute)的对象进行 Bean Validation (JSR 380) 校验@PostMapping("/users") public ResponseEntity<?> createUser( @RequestBody @Valid User newUser, BindingResult result) { ... } // BindingResult 接收校验错误

(五)响应

一般情况的响应,不添加 @RequestBody注解,会直接解析成视图(页面)

 @RequestMapping(value="/save",method={RequestMethod.POST,RequestMethod.GET})
 public String save(){
     System.out.println("springMVC...");
     return "{'success':'hello'}";
 }

返回json数据直接添加 @RequestBody注解,这个数据转换是HttpMessageConvert

 // 接受json数据
 @RequestMapping("/pojoJsonParam")
 @ResponseBody
 public User pojoJsonParamMethod(@RequestBody User user){
     System.out.println("age :" + user);
     return user;
 }

(六)RESTful开发

REST 全称是 Representational State Transfer(表述性状态转移),对请求路径的约束,描述模块名称用复数

REST风格简介

具体原则

  1. 资源与 URI:

    • URI 标识资源: URI 应该表示资源本身,而不是对资源的操作。

      • 好: /users, /users/123, /orders/456/items

      • 坏: /getUsers, /createUser, /updateUser?id=123

    • 使用名词(复数): 通常使用名词复数形式表示资源集合。

      • /users (用户集合), /products (产品集合)

    • 层次关系: 使用路径表示资源间的关系。

      • /users/123/orders (用户 123 的所有订单)

      • /users/123/orders/456 (用户 123 的订单 456)

    • 避免文件扩展名: 使用 AcceptContent-Type 头部协商媒体类型,而不是在 URI 中用 .json.xml

      • 好: GET /users/123 with Accept: application/json

      • 坏: GET /users/123.json

  2. HTTP 方法:

    • 使用标准的 HTTP 方法来定义对资源的操作:

      • GET 获取资源(一个或列表)。安全(不修改资源)且幂等(多次请求结果相同)。

      • POST 创建新资源。不安全(修改资源)且不幂等(多次创建多个资源)。通常用于向集合提交新资源。

      • PUT 完整更新资源(客户端提供完整的更新后资源表述)。不安全幂等(多次更新效果与一次相同)。通常用于更新已知 URI 的资源。

      • PATCH 部分更新资源(客户端只提供需要修改的字段)。不安全幂等(需要正确实现)。用于更新资源的部分属性。

      • DELETE 删除资源。不安全幂等(删除一次或多次,资源最终不存在)。

      • (较少直接使用: HEAD - 获取资源元信息; OPTIONS - 获取资源支持的通信选项)

    • URI 与方法结合: 同一个 URI 配合不同的 HTTP 方法,执行不同的操作。

      • GET /users/123 -> 获取用户 123 的信息

      • PUT /users/123 -> 更新用户 123 的完整信息

      • DELETE /users/123 -> 删除用户 123

      • POST /users -> 创建一个新用户(ID 通常由服务器生成)

 @RequestMapping(value="/users",method=RequestMethod.POST)
 @ResponseBody
 public String save(){
     System.out.println("springMVC...");
     return "{'success':'hello'}";
 }
 ​
 // @Pathvvaribale 路径变量
 @RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
 @ResponseBody
 public void delete(@PathVariable Integer id){
     System.out.println("id :" + id);
 }

RESTful简化开发

 @RestController
 @RequestMapping("/books")
 public class BookController {
 ​
     @GetMapping
     public void getAll(){
         System.out.println("get all ...");
     }
 ​
     @GetMapping("/{id}")
     public void getById(@PathVariable Integer id){
         System.out.println(id);
     }
 ​
     @PostMapping
     public void add(@RequestBody Book  book){
         System.out.println(book);
     }
 ​
     @PutMapping
     public void update(@RequestBody Book  book){
         System.out.println(book);
     }
 ​
     @DeleteMapping("/{id}")
     public void delete(@PathVariable Integer id){
         System.out.println(id);
     }
 ​
 }

设置访问静态资源的路径

 /**
  * 设置静态资源访问路径
  * @param registry
  */
 @Override
 protected void addResourceHandlers(ResourceHandlerRegistry registry) {
 ​
     registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
 }

(七)SSM整合开发

异常处理

异常处理一般放到表现层进行,采用Aop进行同一处理

 // 异常处理的注解
 @RestControllerAdvice
 public class ProjectExceptionAdvice {
 ​
     // 定义拦截异常的类型
     @ExceptionHandler(Exception.class)
     public void doException(){
         System.out.println("出现异常");
     }
 }

针对一下情况出现异常,需要自己封装异常进行处理

(八)拦截器

拦截器是 Spring MVC 框架的核心组件之一,用于在请求处理的不同阶段执行预处理和后处理操作。它类似于 Servlet 中的过滤器(Filter),但提供了更细粒度的控制。

拦截器 vs 过滤器

特性拦截器 (Interceptor)过滤器 (Filter)
作用范围Spring MVC 框架内部Servlet 容器级别
依赖依赖 Spring 容器依赖 Servlet 容器(如 Tomcat)
拦截目标只拦截 Controller 请求拦截所有请求(包括静态资源)
控制粒度可精确到 Handler 方法级别较粗粒度(基于 URL 模式)
获取信息可直接获取 Handler 方法、ModelAndView 等只能获取 Servlet API 对象

拦截器核心

 @Component
 public class ProjectInterceptor implements HandlerInterceptor {
 ​
     // 执行controller之前
     @Override
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
         System.out.println("preHandler ...");
         // 返回为true代表,放行原方法,
         // 返回值为false代表,拦截原方法,在原方法执行之后的都不会执行
         return true;
     }
 ​
     // 执行controller之后
     @Override
     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
         System.out.println("postHandler ...");
         HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
     }
 ​
     // 执行postHandle之后
     @Override
     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
         System.out.println("after ...");
         HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
     }
 }

多拦截器的执行顺序

  1. 当配置多个拦截器时,形成拦截器链

    拦截器链是指一系列按照特定顺序排列的拦截器,它们会依次对请求进行处理。
  2. 拦截器链的运行顺序参照拦截器添加顺序为准

    拦截器的执行顺序与其在配置文件中的添加顺序一致。例如,如果添加了三个拦截器(pre1、pre2、pre3),它们将按此顺序执行。
  3. 当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行

    如果某个拦截器返回false,表示该拦截器阻止了请求的继续处理,后续的拦截器将不再执行。例如,如果pre2返回false,则pre3和controller及其后的拦截器都不会被执行。
  4. 当拦截器运行中断,仅运行配置在前面的拦截器的afterCompletion操作

    如果某个拦截器中断了请求处理流程,只有在该拦截器之前的拦截器的afterCompletion方法会被调用。例如,如果pre2返回false,则只有pre1的afterCompletion方法会被调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值