Spring MVC笔记

01 什么是Spring MVC

Spring MVC 是 Spring 框架中的一个核心模块,专门用于构建 Web 应用程序。它基于经典的 MVC 设计模式(Model-View-Controller),但通过 Spring 的特性(如依赖注入、注解驱动)大幅简化了开发流程。


Spring MVC 是什么?

  1. 本质
    一个基于 Java 的 Web 框架,帮助开发者快速、结构化地开发动态网站或 RESTful API。
  2. 核心思想
    将应用程序拆分为 模型(Model)、视图(View)、控制器(Controller) 三个部分,实现职责分离,让代码更易维护和扩展。

Spring MVC 的作用

1. 处理用户请求和响应

• 用户通过浏览器发送请求(如点击链接、提交表单),Spring MVC 的控制器(Controller)接收请求,处理业务逻辑,最终返回响应(如 HTML 页面、JSON 数据)。

2. 解耦代码,分工协作

Model(模型):负责数据和业务逻辑(如数据库操作)。
View(视图):负责展示数据(如 HTML、JSP、Thymeleaf 模板)。
Controller(控制器):负责协调用户请求、调用模型、返回视图。
• 三者独立开发,修改某一层不会影响其他层。

3. 简化传统 Servlet 开发

• 传统 Servlet 需要手动处理 HTTP 请求参数、响应输出等底层细节,代码臃肿。
• Spring MVC 通过 注解(如 @RequestMapping自动绑定 机制,让开发者专注业务逻辑。
• 例如,直接通过注解将请求参数绑定到 Java 对象:

 @PostMapping("/user")
 public String createUser(User user) {  // 自动将表单参数封装到User对象
     userService.save(user);
     return "success";
 }
4. 灵活适配多种技术

视图技术:支持 JSP、Thymeleaf、FreeMarker 等模板引擎,甚至直接返回 JSON(适合前后端分离)。
数据交互:轻松处理 JSON、XML 等数据格式(配合 @RestController)。
整合其他框架:无缝集成 Spring Security(安全)、Spring Data(数据库)等模块。

5. 强大的扩展性

• 通过拦截器(Interceptor)、全局异常处理(@ControllerAdvice)等机制,可以统一处理日志、权限、异常等问题。
• 例如,全局拦截未登录用户:

 public class AuthInterceptor implements HandlerInterceptor {
     @Override
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
         if (user未登录) {
             response.sendRedirect("/login");
             return false;
         }
         return true;
     }
 }

02 创建Spring MVC项目

以下是两种常用的 Spring MVC 项目搭建方式(传统 XML 配置Spring Boot 快速搭建):


一、传统方式:基于 Maven + XML 配置(适合学习底层原理)

1. 创建 Maven 项目
2. 添加依赖(pom.xml

<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-webmvcartifactId>
    <version>5.3.29version>
dependency>


<dependency>
    <groupId>javax.servletgroupId>
    <artifactId>javax.servlet-apiartifactId>
    <version>4.0.1version>
    <scope>providedscope>
dependency>


<dependency>
    <groupId>javax.servlet.jspgroupId>
    <artifactId>jsp-apiartifactId>
    <version>2.2version>
    <scope>providedscope>
dependency>
3. 配置 web.xml(初始化 DispatcherServlet)
<web-app>
    
    <servlet>
        <servlet-name>dispatcherservlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
        <init-param>
            <param-name>contextConfigLocationparam-name>
            <param-value>/WEB-INF/spring-mvc.xmlparam-value>
        init-param>
        <load-on-startup>1load-on-startup>
    servlet>

    
    <servlet-mapping>
        <servlet-name>dispatcherservlet-name>
        <url-pattern>/url-pattern>
    servlet-mapping>
web-app>
4. 创建 Spring MVC 配置文件(/WEB-INF/spring-mvc.xml

<mvc:annotation-driven/>


<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/"/>
    <property name="suffix" value=".jsp"/>
bean>


<context:component-scan base-package="com.example.controller"/>
5. 创建 Controller 和 JSP 视图
// com.example.controller.HomeController.java
@Controller
public class HomeController {
    @GetMapping("/hello")
    public String hello(Model model) {
        model.addAttribute("message", "Hello Spring MVC!");
        return "hello"; // 对应 /WEB-INF/views/hello.jsp
    }
}
<%-- /WEB-INF/views/hello.jsp --%>


    

${message}

6. 部署到 Tomcat

• 将项目打包为 WAR 文件,部署到 Tomcat 服务器,访问 http://localhost:8080/项目名/hello


二、快速方式:基于 Spring Boot

1. 使用 Spring Initializr 创建项目

• 访问 https://start.spring.io,选择:
依赖Spring Web(已包含 Spring MVC)、Thymeleaf(模板引擎)。
打包方式:JAR(内嵌 Tomcat,无需手动部署)。

2. 项目结构
src/
  main/
    java/
      com.example.demo/
        DemoApplication.java  // 启动类
        controller/
          HomeController.java
    resources/
      templates/  // 存放视图(如HTML)
      static/     // 存放静态资源(CSS/JS)
3. 编写 Controller
@Controller
public class HomeController {
    @GetMapping("/hello")
    public String hello(Model model) {
        model.addAttribute("message", "Hello Spring Boot MVC!");
        return "hello"; // 对应 resources/templates/hello.html
    }
}
4. 创建视图(Thymeleaf)

DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
    <h1 th:text="${message}">h1>
body>
html>
5. 运行项目

• 直接运行 DemoApplication.javamain 方法,访问 http://localhost:8080/hello


三、关键配置说明

  1. 视图解析器
    • 传统方式需手动配置 JSP 路径(如 /WEB-INF/views/*.jsp)。
    • Spring Boot 默认使用 templates 目录存放视图(需配合模板引擎如 Thymeleaf)。

  2. 静态资源访问
    • Spring Boot 默认将 static 目录下的文件映射为静态资源(如 http://localhost:8080/css/style.css)。
    • 传统方式需在 XML 中配置


四、常见问题

  1. 404 错误
    • 检查 Controller 是否被扫描(@ComponentScan 包路径是否正确)。
    • 视图文件是否放在正确目录(如 templatesWEB-INF/views)。

  2. 依赖冲突
    • 确保 Spring 版本与依赖库兼容(推荐使用 Spring Boot 自动管理版本)。


03 Spring MVC执行原理

Spring MVC 的执行原理基于前端控制器模式,其核心是 DispatcherServlet,负责协调各组件处理请求。


1. 请求接收

用户发起请求:客户端(浏览器)发送HTTP请求至Web应用。
前端控制器接管:请求首先被 DispatcherServlet(配置在 web.xml 中)拦截,作为统一入口处理所有请求。


2. 处理器映射(Handler Mapping)

查找处理器DispatcherServlet 通过 HandlerMapping 根据请求URL(如 /hello)找到对应的处理器(Handler),通常是@Controller 中标注 @RequestMapping 的方法。
返回处理器链:可能包含拦截器(Interceptor)和具体的控制器方法。


3. 处理器适配器(Handler Adapter)

执行处理器HandlerAdapter 调用具体的处理器方法(如 @GetMapping 方法),处理不同形式的控制器(如基于注解或实现 Controller 接口)。
参数解析与绑定:方法参数通过 ArgumentResolver 解析(如请求参数、模型、@PathVariable 等)。
数据转换/验证:使用 ConverterValidator 进行类型转换和数据校验。


4. 控制器处理

业务逻辑执行:控制器方法调用Service层处理业务,返回结果(如 String 视图名、ModelAndView@ResponseBody 数据)。
模型数据填充:将数据存储在 Model 对象中,供视图渲染使用。


5. 视图解析(View Resolution)

解析视图名ViewResolver 根据控制器返回的视图名(如 "home")解析为具体的 View 对象(如JSP、Thymeleaf模板)。
示例配置InternalResourceViewResolver 可能将 "home" 映射到 /WEB-INF/views/home.jsp


6. 视图渲染

模型数据传递DispatcherServlet 将模型数据传递给 View 对象。
生成响应内容:视图使用模板引擎(如JSP、Freemarker)渲染HTML,写入HTTP响应。


7. 返回响应

响应客户端:渲染后的内容通过 DispatcherServlet 返回给客户端,完成请求-响应周期。


关键组件与扩展点

拦截器(Interceptor):在请求处理前后执行逻辑(如权限检查、日志记录),通过实现 HandlerInterceptor 接口配置。
异常处理@ExceptionHandlerHandlerExceptionResolver 统一处理控制器抛出的异常。
文件上传MultipartResolver 解析 multipart 请求(如文件上传)。


执行流程图示

客户端 → DispatcherServlet → HandlerMapping → HandlerAdapter → Controller → ModelAndView → ViewResolver → View → 响应

示例配置

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    // 视图解析器
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }

    // 静态资源处理
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

@Controller
public class HelloController {
    @GetMapping("/hello")
    public String hello(Model model) {
        model.addAttribute("message", "Hello Spring MVC!");
        return "hello"; // 对应 /WEB-INF/views/hello.jsp
    }
}

04 RequestMapping

在 Spring MVC 中,@RequestMapping 是一个核心注解,用于将 HTTP 请求映射到特定的控制器方法。它提供了灵活的配置选项,支持定义请求路径、HTTP 方法、请求参数、请求头等条件。以下是其详细用法和功能说明:


1. 基本作用

定义请求映射规则:将 URL 请求路径与控制器方法绑定。
支持多种请求类型:GET、POST、PUT、DELETE 等。
支持路径变量、参数过滤、请求头过滤等高级条件。


2. 可用位置

类级别:定义共享的根路径(所有方法映射路径会继承该路径)。
方法级别:定义具体方法的映射规则。

示例
@Controller
@RequestMapping("/user") // 类级别路径:所有方法映射路径以 /user 开头
public class UserController {

    // 实际路径:/user/profile
    @RequestMapping("/profile")
    public String profile() { ... }

    // 实际路径:/user/list
    @RequestMapping("/list")
    public String list() { ... }
}

3. 核心属性

(1) valuepath

定义请求路径:支持字符串或字符串数组(允许多路径映射)。
支持路径变量{variable})和通配符(*, **)。

// 单路径
@RequestMapping("/detail")

// 多路径映射
@RequestMapping({"/info", "/detail"})

// 路径变量
@RequestMapping("/user/{id}")
public String getUser(@PathVariable Long id) { ... }

// 通配符匹配(如 /user/2023/order)
@RequestMapping("/user/*/order")

(2) method

指定允许的 HTTP 方法:如 RequestMethod.GET, RequestMethod.POST
默认支持所有 HTTP 方法

// 只允许 GET 请求
@RequestMapping(value = "/list", method = RequestMethod.GET)

// 允许多个 HTTP 方法
@RequestMapping(value = "/save", method = {RequestMethod.POST, RequestMethod.PUT})

(3) params

过滤请求参数:要求请求必须包含指定参数,或参数满足特定条件。
• 格式:param(必须存在)、!param(必须不存在)、param=value(值匹配)。

// 要求请求必须包含 id 参数
@RequestMapping(params = "id")

// 要求必须包含 id 且值为 100
@RequestMapping(params = "id=100")

// 要求不能包含 debug 参数
@RequestMapping(params = "!debug")

(4) headers

过滤请求头:要求请求头满足特定条件。
• 格式与 params 类似。

// 要求请求头包含 Content-Type=application/json
@RequestMapping(headers = "Content-Type=application/json")

// 要求请求头必须包含 Auth-Token
@RequestMapping(headers = "Auth-Token")

(5) consumes

指定请求的 Content-Type:要求请求体的媒体类型匹配。

// 仅处理 Content-Type 为 application/json 的请求
@RequestMapping(consumes = "application/json")

(6) produces

指定响应的 Content-Type:设置响应体的媒体类型。

// 返回 JSON 数据
@RequestMapping(produces = "application/json")

4. 组合注解

为了简化代码,Spring 提供了基于 @RequestMapping 的快捷组合注解:

组合注解 等效写法 作用
@GetMapping @RequestMapping(method = RequestMethod.GET) 处理 GET 请求
@PostMapping @RequestMapping(method = RequestMethod.POST) 处理 POST 请求
@PutMapping @RequestMapping(method = RequestMethod.PUT) 处理 PUT 请求
@DeleteMapping @RequestMapping(method = RequestMethod.DELETE) 处理 DELETE 请求
@PatchMapping @RequestMapping(method = RequestMethod.PATCH) 处理 PATCH 请求
示例
@GetMapping("/user/{id}") // 等价于 @RequestMapping(value="/user/{id}", method=RequestMethod.GET)
public String getUser(@PathVariable Long id) { ... }

5. 路径匹配规则

(1) 路径变量({variable}

• 使用 @PathVariable 获取路径中的动态值。

// 匹配路径如 /user/123
@GetMapping("/user/{id}")
public String getUser(@PathVariable("id") Long userId) { ... }

(2) 通配符

?:匹配单个字符(如 /user/2023? 匹配 /user/2023a)。
*:匹配同一层级的任意字符(如 /user/*/order 匹配 /user/123/order)。
**:匹配多层路径(如 /user/** 匹配 /user/123/order/456)。


(3) 正则表达式

• 路径变量中可使用正则表达式限制格式。

// 限制 id 必须为数字
@GetMapping("/user/{id:\\d+}")
public String getUser(@PathVariable Long id) { ... }

6. 示例代码

(1) 完整控制器
@Controller
@RequestMapping("/product")
public class ProductController {

    // 匹配 GET /product/detail?id=100
    @GetMapping(value = "/detail", params = "id")
    public String detail(@RequestParam Long id, Model model) {
        model.addAttribute("product", productService.findById(id));
        return "product/detail";
    }

    // 匹配 POST 或 PUT /product/save
    @RequestMapping(value = "/save", method = {RequestMethod.POST, RequestMethod.PUT})
    public String saveProduct(@ModelAttribute Product product) {
        productService.save(product);
        return "redirect:/product/list";
    }

    // 路径变量 + 正则匹配(如 /product/category/electronics)
    @GetMapping("/category/{type:[a-z]+}")
    public String listByCategory(@PathVariable String type, Model model) {
        model.addAttribute("products", productService.findByCategory(type));
        return "product/list";
    }
}

05 Resful风格

RESTful(REpresentational State Transfer)是一种基于 HTTP 协议的 API 设计风格,强调以资源为中心,通过统一的接口和标准方法(GET/POST/PUT/DELETE 等)操作资源。


一、RESTful 的核心原则

  1. 资源(Resource)
    • 所有数据或服务抽象为资源(如用户、订单),通过 URI(统一资源标识符) 唯一标识。
    • 示例:/users(用户集合)、/users/1001(ID 为 1001 的用户)。

  2. 统一接口(Uniform Interface)
    • 使用标准的 HTTP 方法 操作资源:
    GET:获取资源
    POST:创建资源
    PUT:更新资源(全量替换)
    PATCH:部分更新资源
    DELETE:删除资源

  3. 无状态(Stateless)
    • 服务端不保存客户端状态,每个请求必须包含所有必要信息。

  4. 表述(Representation)
    • 资源的表现形式(如 JSON、XML),客户端通过 HTTP 头(Accept/Content-Type)协商格式。

  5. 超媒体驱动(HATEOAS)
    • 响应中包含相关资源的链接,客户端通过链接导航(可选约束,实际使用较少)。


二、RESTful API 设计规范

1. URI 设计规范

使用名词,而非动词:URI 表示资源,动作由 HTTP 方法表达。

❌ 非 RESTful: /getUser?id=1001  
✅ RESTful: GET /users/1001

层级关系使用 / 分隔

GET /users/1001/orders  # 获取用户 1001 的所有订单

复数形式命名集合

GET /users       # 用户集合
POST /users      # 创建用户

过滤、排序、分页通过查询参数实现

GET /users?page=2&size=10&sort=name,asc  # 分页排序
GET /users?name=John&age=30              # 过滤
2. HTTP 方法使用规范
HTTP 方法 操作类型 幂等性 示例
GET 查询资源 GET /users/1001
POST 创建资源 POST /users
PUT 全量更新 PUT /users/1001
PATCH 部分更新 PATCH /users/1001
DELETE 删除资源 DELETE /users/1001
3. 状态码(Status Code)

2xx:成功
200 OK:常规成功
201 Created:资源创建成功
204 No Content:成功但无返回体(如删除操作)

4xx:客户端错误
400 Bad Request:请求参数错误
401 Unauthorized:未认证
403 Forbidden:无权限
404 Not Found:资源不存在

5xx:服务端错误
500 Internal Server Error:服务器内部错误

4. 数据格式

• 使用 JSON 作为主流数据交换格式。
• 请求头指定 Content-Type: application/json
• 响应头包含 Content-Type: application/json


三、在 Spring 中实现 RESTful API

1. 使用 @RestController 注解

• 替代 @Controller + @ResponseBody,直接返回 JSON 数据。

@RestController
@RequestMapping("/api/users")
public class UserController {
    // ...
}
2. 映射 HTTP 方法

• 使用组合注解:@GetMapping, @PostMapping, @PutMapping, @DeleteMapping

@GetMapping("/{id}")
public User getUser(@PathVariable Long id) { ... }

@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) { ... }
3. 处理请求和响应

路径变量@PathVariable

@GetMapping("/{id}")
public User getUser(@PathVariable Long id) { ... }

请求体@RequestBody

@PostMapping
public User createUser(@RequestBody User user) { ... }

返回 ResponseEntity:自定义状态码和响应头

@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
    User savedUser = userService.save(user);
    return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
}
4. 统一异常处理

• 使用 @ExceptionHandler@ControllerAdvice 返回标准错误响应。

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException e) {
        ErrorResponse error = new ErrorResponse(404, e.getMessage());
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
    }
}

四、完整示例

1. 实体类
public class User {
    private Long id;
    private String name;
    private String email;
    // Getters and Setters
}
2. 控制器
@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    // 获取所有用户
    @GetMapping
    public List<User> getAllUsers() {
        return userService.findAll();
    }

    // 创建用户
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        User savedUser = userService.save(user);
        return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
    }

    // 获取单个用户
    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("User not found"));
    }

    // 更新用户(全量)
    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        user.setId(id);
        return userService.update(user);
    }

    // 删除用户
    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void deleteUser(@PathVariable Long id) {
        userService.deleteById(id);
    }
}
3. 请求与响应示例

请求POST /api/users

{
  "name": "Alice",
  "email": "[email protected]"
}

响应(状态码 201):

{
  "id": 1001,
  "name": "Alice",
  "email": "[email protected]"
}

06 重定向和转发

在 Spring MVC 中,重定向(Redirect)转发(Forward) 是两种不同的请求跳转方式,理解它们的区别和适用场景对开发至关重要。以下是详细对比及具体用法:


一、核心区别

特性 转发(Forward) 重定向(Redirect)
发起方 服务端内部跳转(客户端无感知) 服务端通知客户端重新发起请求
请求次数 1 次请求,1 次响应 2 次请求,2 次响应
地址栏变化 地址栏 URL 不变 地址栏 URL 变为目标地址
数据共享 共享同一 Request 作用域(request.setAttribute 不共享 Request 作用域,需通过 URL 参数或 Session 传递
性能 更高(无额外请求) 较低(多一次网络往返)
使用场景 服务器内部资源跳转(如 JSP 间共享数据) 跨应用跳转、防止表单重复提交(POST-REDIRECT-GET)

二、在 Spring MVC 中的实现方式

1. 转发(Forward)

原理:服务端内部将请求转发到另一个资源(如 JSP、控制器方法)。
语法:在返回值前加 forward: 前缀。
示例

@GetMapping("/page1")
public String forwardDemo() {
    // 转发到 /page2(客户端 URL 仍为 /page1)
    return "forward:/page2";
}

@GetMapping("/page2")
public String page2() {
    return "page2"; // 视图名对应视图解析器路径
}

数据传递:通过 ModelHttpServletRequest 传递数据。

@GetMapping("/forward")
public String forward(Model model) {
    model.addAttribute("message", "Hello from forward!");
    return "forward:/targetPage";
}

2. 重定向(Redirect)

原理:服务端返回 302 状态码和 Location 头,客户端自动发起新请求。
语法:在返回值前加 redirect: 前缀。
示例

@PostMapping("/submit")
public String submitForm(FormData formData, RedirectAttributes redirectAttributes) {
    // 处理表单数据...
    // 重定向到 /result,传递参数
    redirectAttributes.addAttribute("status", "success");
    redirectAttributes.addFlashAttribute("message", "操作成功!");
    return "redirect:/result";
}

@GetMapping("/result")
public String resultPage(@RequestParam String status, Model model) {
    // 接收 URL 参数和 Flash 属性
    return "result";
}

数据传递
URL 参数RedirectAttributes.addAttribute("key", value) → 参数暴露在 URL 中。
Flash 属性RedirectAttributes.addFlashAttribute("key", value) → 数据暂存 Session,一次请求后自动删除。


三、适用场景

1. 转发(Forward)

共享请求数据:需要在多个视图或控制器间传递数据(如 JSP 到 JSP)。
隐藏实际资源路径:保护内部资源路径,客户端无法直接访问。
统一预处理:在转发前进行权限验证、日志记录等。

2. 重定向(Redirect)

防止表单重复提交:提交后重定向到结果页(POST-REDIRECT-GET 模式)。
跨应用跳转:跳转到外部网站或其他服务。
切换上下文路径:如从 HTTP 跳转到 HTTPS,或更换域名。


五、完整代码示例

1. 转发示例
@Controller
public class ForwardController {

    @GetMapping("/source")
    public String sourcePage(Model model) {
        model.addAttribute("data", "来自源页面的数据");
        return "forward:/target"; // 转发到 /target
    }

    @GetMapping("/target")
    public String targetPage(Model model) {
        // 可以访问 model 中的 data
        return "target-page"; // 视图模板路径
    }
}
2. 重定向示例
@Controller
public class RedirectController {

    @PostMapping("/save")
    public String saveData(User user, RedirectAttributes redirectAttributes) {
        userService.save(user);
        // 添加 URL 参数(暴露在地址栏)
        redirectAttributes.addAttribute("userId", user.getId());
        // 添加 Flash 属性(安全传递敏感数据)
        redirectAttributes.addFlashAttribute("message", "用户保存成功!");
        return "redirect:/user/detail";
    }

    @GetMapping("/user/detail")
    public String userDetail(@RequestParam Long userId, Model model) {
        User user = userService.findById(userId);
        model.addAttribute("user", user);
        return "user-detail";
    }
}

六、总结

转发(Forward):适合服务器内部资源跳转,共享请求数据,性能更高。
重定向(Redirect):适合客户端跳转、防止重复提交,需注意数据传递方式。
开发建议
• 表单提交后 必须使用重定向 避免重复提交。
• 优先使用 RedirectAttributes 传递数据,避免 URL 参数暴露敏感信息。

07 接收请求参数和数据回显

一、接收请求参数

1. 基本参数接收

@RequestParam:获取 URL 参数或表单字段(默认必传,可设 required=false)。

@GetMapping("/user")
public String getUser(@RequestParam("id") Long userId, 
                     @RequestParam(value = "name", defaultValue = "Guest") String userName) {
    // URL: /user?id=1001&name=Alice
    // userId=1001, userName=Alice(若未传name,默认为"Guest")
    return "user/detail";
}

@PathVariable:获取 URL 路径变量。

@GetMapping("/user/{id}")
public String getUser(@PathVariable("id") Long userId) {
    // URL: /user/1001 → userId=1001
    return "user/detail";
}

2. 对象自动绑定

@ModelAttribute:自动将表单字段绑定到对象(支持级联属性)。

@PostMapping("/save")
public String saveUser(@ModelAttribute User user) {
    // 表单字段 name 和 email 自动绑定到 User 对象
    userService.save(user);
    return "redirect:/user/list";
}

无需注解:直接声明对象参数,Spring 自动绑定。

@PostMapping("/save")
public String saveUser(User user) { // 效果同上
    userService.save(user);
    return "redirect:/user/list";
}

3. 接收 JSON 数据

@RequestBody:将请求体中的 JSON 反序列化为对象。

@PostMapping("/api/user")
@ResponseBody
public ResponseEntity<User> createUser(@RequestBody User user) {
    User savedUser = userService.save(user);
    return ResponseEntity.ok(savedUser);
}

4. 接收原生对象

• 直接使用 HttpServletRequestHttpSession 等原生对象。

@GetMapping("/info")
public String getInfo(HttpServletRequest request, HttpSession session) {
    String param = request.getParameter("param");
    session.setAttribute("key", "value");
    return "info";
}

二、数据回显(传递到视图)

1. 使用 ModelModelMap

• 添加数据到模型,供视图(如 JSP、Thymeleaf)渲染。

@GetMapping("/user/edit")
public String editUser(@RequestParam Long id, Model model) {
    User user = userService.findById(id);
    model.addAttribute("user", user); // 回显到表单
    return "user/edit";
}

2. 使用 ModelAndView

• 同时返回视图名和数据。

@GetMapping("/user/detail")
public ModelAndView userDetail(@RequestParam Long id) {
    ModelAndView mav = new ModelAndView("user/detail");
    User user = userService.findById(id);
    mav.addObject("user", user);
    return mav;
}

08 JSON

在 Spring 生态中,JSON(JavaScript Object Notation) 是主流的轻量级数据交换格式,而 Jackson 是处理 JSON 序列化与反序列化的核心库。


一、JSON 简介

1. 什么是 JSON?

轻量级数据格式:以键值对(key: value)形式组织数据,易读且兼容性强。
数据结构
对象{ "key": value }
数组[ value1, value2 ]
值类型:字符串、数字、布尔值、null、对象、数组。

2. 应用场景

前后端数据交互:API 请求和响应。
配置文件(如 package.json)。
NoSQL 数据库(如 MongoDB)存储格式。

3. 对比 XML
特性 JSON XML
可读性 高(结构简洁) 较低(标签冗余)
数据体积 更小 更大
解析速度 更快 较慢
扩展性 弱(无命名空间、属性等概念) 强(支持复杂结构)

二、Jackson 核心功能

Jackson 是 Java 生态中最流行的 JSON 处理库,提供以下能力:

  1. 序列化:将 Java 对象转换为 JSON 字符串。
  2. 反序列化:将 JSON 字符串解析为 Java 对象。
  3. 数据绑定:支持注解驱动配置。
  4. 流式 API:高性能处理大 JSON 数据。

三、Spring 中集成 Jackson

Spring MVC 默认通过 MappingJackson2HttpMessageConverter 集成 Jackson,自动处理 JSON 转换。

1. 添加依赖

<dependency>
    <groupId>com.fasterxml.jackson.coregroupId>
    <artifactId>jackson-databindartifactId>
    <version>2.15.2version>
dependency>
2. 启用 JSON 支持

注解驱动:使用 @RestController@ResponseBody

@RestController // 等效于 @Controller + @ResponseBody
@RequestMapping("/api/users")
public class UserController {
    
    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.findById(id);
    }
}

四、Jackson 核心注解

通过注解控制序列化/反序列化行为:

1. 字段映射

@JsonProperty:指定 JSON 字段名。

public class User {
    @JsonProperty("user_name")
    private String name;
}
// 序列化为 { "user_name": "Alice" }

@JsonIgnore:忽略字段。

public class User {
    @JsonIgnore
    private String password;
}
2. 日期格式化

@JsonFormat:自定义日期格式。

public class Order {
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime createTime;
}
// 序列化为 "2023-10-01 14:30:00"
3. 空值处理

@JsonInclude:忽略空值字段。

@JsonInclude(JsonInclude.Include.NON_NULL)
public class User {
    private String email; // 若 email 为 null,不序列化
}

五、序列化与反序列化示例

1. Java 对象转 JSON(序列化)
ObjectMapper mapper = new ObjectMapper();
User user = new User("Alice", 30);
String json = mapper.writeValueAsString(user);
// 输出:{"name":"Alice","age":30}
2. JSON 转 Java 对象(反序列化)
String json = "{\"name\":\"Alice\",\"age\":30}";
User user = mapper.readValue(json, User.class);

六、Spring 中高级配置

1. 自定义 ObjectMapper
@Configuration
public class JacksonConfig {

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        return mapper;
    }
}

七、常见问题与解决方案

1. 日期格式不生效

问题:日期字段未按预期格式序列化。
解决:检查 @JsonFormattimezone 配置或全局 ObjectMapper 日期格式。

2. 字段丢失

问题:JSON 中缺少字段导致反序列化失败。
解决:配置 ObjectMapper 忽略未知字段:

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

09 Fastjson

在 Java 开发中,Fastjson 是阿里巴巴开源的高性能 JSON 库,广泛用于序列化(Java 对象转 JSON)和反序列化(JSON 转 Java 对象)。与 Jackson 相比,Fastjson 在部分场景下性能更优,且 API 设计更简单易用。以下是其核心特性、使用方式及注意事项:


一、Fastjson 核心特性

  1. 高性能
    • 序列化/反序列化速度极快,尤其在大数据量场景下表现优异。
    • 依赖 ASM 字节码技术优化(无需反射),性能优于 Jackson 和 Gson。

  2. 功能丰富
    • 支持复杂对象(泛型、嵌套对象、循环引用)。
    • 支持 Java 8 时间 API(如 LocalDateTime)。
    • 支持自定义序列化规则和过滤器。

  3. 简单 API
    • 核心类 JSON 提供静态方法(如 JSON.toJSONString()JSON.parseObject())。

  4. 注解驱动
    • 通过 @JSONField 注解灵活控制字段映射和格式。


二、与 Jackson 对比

特性 Fastjson Jackson
性能 更高(尤其序列化) 较高
安全性 历史漏洞较多(需使用最新版本) 安全性较好
API 简洁性 极简(静态方法) 稍复杂(需 ObjectMapper 实例)
社区生态 国内流行,文档丰富 国际主流,生态更成熟
维护状态 阿里巴巴维护,更新频繁 长期稳定更新

三、Spring 中集成 Fastjson

Spring Boot 默认使用 Jackson,若需替换为 Fastjson,需手动配置消息转换器。

1. 添加依赖

<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>fastjsonartifactId>
    <version>2.0.34version> 
dependency>
2. 配置 Fastjson 消息转换器
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 创建 Fastjson 消息转换器
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();

        // 配置序列化规则
        FastJsonConfig config = new FastJsonConfig();
        config.setSerializerFeatures(
            SerializerFeature.PrettyFormat,       // 格式化输出
            SerializerFeature.WriteMapNullValue,  // 输出空值字段
            SerializerFeature.WriteDateUseDateFormat // 日期格式化
        );
        config.setDateFormat("yyyy-MM-dd HH:mm:ss");
        converter.setFastJsonConfig(config);

        // 处理中文乱码
        List<MediaType> mediaTypes = new ArrayList<>();
        mediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
        converter.setSupportedMediaTypes(mediaTypes);

        // 替换默认 Jackson 转换器
        converters.add(0, converter);
    }
}

四、核心 API 使用示例

1. 序列化(Java → JSON)
User user = new User("Alice", 25, LocalDateTime.now());

// 简单序列化
String json = JSON.toJSONString(user); 
// 输出:{"age":25,"name":"Alice","createTime":"2023-10-01 14:30:00"}

// 带格式化的序列化
String prettyJson = JSON.toJSONString(user, SerializerFeature.PrettyFormat);
2. 反序列化(JSON → Java)
String json = "{\"name\":\"Bob\",\"age\":30}";

// 基本反序列化
User user = JSON.parseObject(json, User.class);

// 处理泛型(如 List)
String listJson = "[{\"name\":\"Alice\"}, {\"name\":\"Bob\"}]";
List<User> users = JSON.parseArray(listJson, User.class);

五、注解 @JSONField

通过注解控制字段的序列化行为:

1. 字段重命名
public class User {
    @JSONField(name = "user_name")
    private String name; // 序列化为 "user_name"
}
2. 忽略字段
public class User {
    @JSONField(serialize = false)
    private String password; // 不序列化
}
3. 日期格式化
public class User {
    @JSONField(format = "yyyy-MM-dd")
    private LocalDate birthDate;
}
4. 顺序控制
@JSONType(orders = {"id", "name", "age"}) // 类级别定义字段顺序
public class User {
    private Long id;
    private String name;
    private Integer age;
}

10 ssm整合项目搭建

Spring MVC 图书管理系统开发流程与示例


一、项目目录结构(简化版)
src/
├── main/
│   ├── java/
│   │   └── com/
│   │       └── example/
│   │           ├── controller/    # 控制器层
│   │           │   └── BookController.java
│   │           ├── dao/          # DAO层(MyBatis Mapper接口)
│   │           │   └── BookMapper.java
│   │           ├── service/      # 业务层
│   │           │   ├── BookService.java
│   │           │   └── impl/
│   │           │       └── BookServiceImpl.java
│   │           └── entity/       # 实体类
│   │               └── Book.java
│   └── resources/
│       ├── mapper/               # MyBatis Mapper XML
│       │   └── BookMapper.xml
│       ├── spring/              # Spring配置
│       │   ├── spring.xml
│       │   └── spring-mvc.xml
│       └── jdbc.properties      # 数据库配置
webapp/
├── WEB-INF/
│   └── views/                   # JSP视图
│       └── book/
│           └── list.jsp
└── index.jsp

二、开发流程与代码示例
1. 创建数据库表
CREATE TABLE book (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    author VARCHAR(50),
    price DECIMAL(10,2)
);

2. 实体类 Book.java(POJO层)
package com.example.entity;

public class Book {
    private Integer id;
    private String name;
    private String author;
    private Double price;
    
    // Getters and Setters
}

3. DAO层接口 BookMapper.java
package com.example.dao;

import com.example.entity.Book;
import java.util.List;

public interface BookMapper {
    List<Book> selectAll();
    int insert(Book book);
    int deleteById(Integer id);
}

4. MyBatis Mapper XML BookMapper.xml

DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.dao.BookMapper">
    <select id="selectAll" resultType="Book">
        SELECT id, name, author, price FROM book
    select>
    
    <insert id="insert" parameterType="Book">
        INSERT INTO book(name, author, price)
        VALUES(#{name}, #{author}, #{price})
    insert>

    <delete id="deleteById" parameterType="Integer">
        DELETE FROM book WHERE id = #{id}
    delete>
mapper>

5. Service层实现业务逻辑
// 接口 BookService.java
package com.example.service;
import com.example.entity.Book;
import java.util.List;

public interface BookService {
    List<Book> listBooks();
    void addBook(Book book);
    void deleteBook(Integer id);
}

// 实现类 BookServiceImpl.java
package com.example.service.impl;

import com.example.dao.BookMapper;
import com.example.entity.Book;
import com.example.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;

@Service
public class BookServiceImpl implements BookService {
    @Autowired
    private BookMapper bookMapper;

    @Override
    public List<Book> listBooks() {
        return bookMapper.selectAll();
    }

    @Override
    @Transactional
    public void addBook(Book book) {
        bookMapper.insert(book);
    }

    @Override
    @Transactional
    public void deleteBook(Integer id) {
        bookMapper.deleteById(id);
    }
}

6. Controller层处理请求
package com.example.controller;

import com.example.entity.Book;
import com.example.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

@Controller
@RequestMapping("/book")
public class BookController {
    @Autowired
    private BookService bookService;

    // 查询所有书籍
    @GetMapping("/list")
    public String listBooks(Model model) {
        model.addAttribute("books", bookService.listBooks());
        return "book/list";
    }

    // 添加书籍(表单提交)
    @PostMapping("/add")
    public String addBook(Book book) {
        bookService.addBook(book);
        return "redirect:/book/list";
    }

    // 删除书籍
    @GetMapping("/delete/{id}")
    public String deleteBook(@PathVariable Integer id) {
        bookService.deleteBook(id);
        return "redirect:/book/list";
    }
}

7. 配置文件
(1) jdbc.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/book_db?useSSL=false&serverTimezone=UTC
jdbc.username=root
jdbc.password=123456
(2) spring.xml(Spring核心配置)

<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}"/>
bean>


<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mapperLocations" value="classpath:mapper/*.xml"/>
bean>


<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.example.dao"/>
bean>


<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
bean>


<context:component-scan base-package="com.example.service"/>
(3) spring-mvc.xml(Spring MVC配置)

<mvc:annotation-driven/>


<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/"/>
    <property name="suffix" value=".jsp"/>
bean>


<context:component-scan base-package="com.example.controller"/>


<mvc:resources mapping="/static/**" location="/static/"/>

8. 视图层 list.jsp
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>


    图书列表


    

图书列表

ID 书名 作者 价格 操作
${book.id} ${book.name} ${book.author} ${book.price} 删除

添加新书

书名:
作者:
价格:

三、关键流程说明
  1. 请求处理流程

    浏览器请求 → DispatcherServlet → BookController → BookService → BookMapper → 数据库
    
  2. 分层职责
    DAO层:直接操作数据库,提供 insertdelete 等方法。
    Service层:处理业务逻辑(如事务管理 @Transactional)。
    Controller层:接收HTTP请求,返回视图或重定向。


四、启动与测试
  1. 部署到Tomcat,访问 http://localhost:8080/book/list
  2. 添加图书:填写表单提交,数据插入数据库。
  3. 删除图书:点击删除链接,触发 DELETE 操作。

11 整合SSM框架的配置文件

SSM 整合核心配置文件详解

以下是整合 Spring、Spring MVC 和 MyBatis(SSM)时 必须配置的核心内容,分步骤说明每个配置文件的作用和关键配置项。


一、项目结构
src/
├── main/
│   ├── java/
│   │   └── com/example/
│   │       ├── controller/   # Spring MVC 控制器
│   │       ├── service/      # 业务层接口和实现
│   │       ├── dao/          # MyBatis Mapper 接口
│   │       └── entity/       # 数据库实体类
│   └── resources/
│       ├── spring/
│       │   ├── spring.xml     # Spring 核心配置
│       │   └── spring-mvc.xml# Spring MVC 配置
│       ├── mapper/           # MyBatis Mapper XML 文件
│       └── jdbc.properties    # 数据库连接配置
webapp/
├── WEB-INF/
│   └── views/                # JSP 视图文件
└── index.jsp

二、Spring 核心配置 (spring.xml)

<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:tx="http://www.springframework.org/schema/tx"
       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/tx
                           http://www.springframework.org/schema/tx/spring-tx.xsd">

    
    <context:property-placeholder location="classpath:jdbc.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="5"/>
        <property name="maxActive" value="20"/>
    bean>

    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        
        <property name="dataSource" ref="dataSource"/>
        
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
        
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    bean>

    
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.example.dao"/>
    bean>

    
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    bean>

    
    <tx:annotation-driven transaction-manager="transactionManager"/>

    
    <context:component-scan base-package="com.example.service"/>
beans>
关键配置说明:

  1. 加载 jdbc.properties 文件中的数据库连接参数。
    jdbc.driver: 数据库驱动类(如 com.mysql.cj.jdbc.Driver)。
    jdbc.url: 数据库连接 URL(如 jdbc:mysql://localhost:3306/test)。
    jdbc.username/jdbc.password: 数据库用户名和密码。

  2. DruidDataSource
    • 使用 Druid 连接池管理数据库连接。
    initialSize/maxActive: 连接池初始大小和最大连接数。

  3. SqlSessionFactoryBean
    • 核心类,用于创建 MyBatis 的 SqlSession
    mapperLocations: 指定 Mapper XML 文件的路径(支持通配符 *)。

  4. MapperScannerConfigurer
    • 自动扫描 DAO 层的 Mapper 接口,并注册为 Spring Bean。
    basePackage: Mapper 接口所在的包路径。

  5. DataSourceTransactionManager
    • 基于数据源的事务管理器,用于管理数据库事务。
    开启 @Transactional 注解支持。


三、Spring MVC 配置 (spring-mvc.xml)

<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">

    
    <mvc:annotation-driven/>

    
    <mvc:resources mapping="/static/**" location="/static/"/>

    
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".jsp"/>
    bean>

    
    <context:component-scan base-package="com.example.controller"/>
beans>
关键配置说明:

  1. • 启用 Spring MVC 的注解驱动功能(如 @Controller@RequestMapping)。
    • 自动注册 RequestMappingHandlerMappingRequestMappingHandlerAdapter


  2. • 处理静态资源请求(如 /static/css/style.css)。
    mapping: URL 映射规则。
    location: 静态资源在项目中的路径。

  3. InternalResourceViewResolver
    • 将逻辑视图名解析为具体的 JSP 文件路径。
    prefix: 视图文件的前缀路径(如 /WEB-INF/views/book/list.jsp)。
    suffix: 视图文件的后缀(如 .jsp)。


四、MyBatis 全局配置 (mybatis-config.xml,可选)

DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    
    <settings>
        
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        
        <setting name="cacheEnabled" value="true"/>
    settings>

    
    <typeAliases>
        <package name="com.example.entity"/>
    typeAliases>
configuration>
关键配置说明:
  1. mapUnderscoreToCamelCase
    • 自动将数据库字段的下划线命名转换为 Java 属性的驼峰命名。

  2. typeAliases
    • 为实体类设置别名,例如


    二、文件下载
    1. 编写下载 Controller
    @Controller
    @RequestMapping("/file")
    public class FileController {
    
        /**
         * 文件下载处理
         * @param filename 要下载的文件名
         * @return 文件流响应
         */
        @GetMapping("/download")
        public ResponseEntity<byte[]> downloadFile(
                @RequestParam("filename") String filename
        ) {
            try {
                // 1. 指定文件存储路径
                String uploadDir = "uploads/";
                File file = new File(uploadDir + filename);
    
                // 2. 检查文件是否存在
                if (!file.exists()) {
                    return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
                }
    
                // 3. 读取文件内容到字节数组
                byte[] fileBytes = Files.readAllBytes(file.toPath());
    
                // 4. 设置响应头
                HttpHeaders headers = new HttpHeaders();
                // 指定 Content-Disposition 告诉浏览器以下载方式处理
                headers.add("Content-Disposition", "attachment;filename=" + filename);
                // 设置 Content-Type(根据实际文件类型调整)
                headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
                // 设置 Content-Length(可选)
                headers.setContentLength(fileBytes.length);
    
                // 5. 返回文件流
                return new ResponseEntity<>(fileBytes, headers, HttpStatus.OK);
            } catch (IOException e) {
                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
            }
        }
    }
    
    2. 前端下载链接(JSP)
    <%@ page contentType="text/html;charset=UTF-8" %>
    
    
        文件下载
    
    
        

    文件下载

    下载文件

    三、关键注解与配置说明
    1. @RequestParam("file")
      • 用于接收前端表单中 name="file" 的文件输入。

    2. MultipartFile
      • Spring 提供的文件上传接口,提供 transferTo() 保存文件。

    3. ResponseEntity
      • 封装 HTTP 响应的实体类,可直接返回字节数组和响应头。

    4. HttpHeaders
      • 设置响应头,如 Content-Disposition(告诉浏览器下载文件)。


    四、常见问题与解决
    1. 上传文件大小限制
      • 修改 CommonsMultipartResolvermaxUploadSize 属性。

    2. 中文文件名乱码
      • 确保 CommonsMultipartResolverdefaultEncoding 设置为 UTF-8

    3. 文件存储路径权限问题
      • 检查应用是否有权限写入目标目录。

    4. 安全建议
      • 使用 UUID 重命名文件,避免文件名冲突和路径遍历攻击。


    五、完整流程示意图
    客户端 → 上传表单 → Spring MVC → MultipartResolver 解析 → Controller 保存文件
    客户端 → 下载链接 → Controller 读取文件 → 返回字节流 → 浏览器下载
    

你可能感兴趣的:(spring,mvc,笔记)