找回密码
 立即注册
首页 业界区 业界 MVC快速入门

MVC快速入门

些耨努 6 小时前
前言

什么是MVC

MVC英文是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计规范,本质上也是一种解耦。
1.png


  • Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。
  • View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。
  • Controller(控制器)是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
什么是SpringMVC

而Spring Web MVC 则是一种基于Java 的实现了Web MVC 设计模式的请求驱动类型的轻量级Web 框架,即使用了MVC 架构模式的思想,将 web 层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是为了简化开 发,Spring Web MVC 也是要简化我们日常Web 开发的。
说白了,Spring MVC 就是 【接收请求】【响应数据】
Spring MVC 下一般把后端项目分为 Service 层(处理业务)、Dao 层(数据库操作)、Entity 层(实体类)、Controller 层(控制层,返回数据给前台页面)。
常用组件:

  • 前端控制器(DispatcherServlet):接收用户请求,给用户返回结果。
  • 处理器映射器(HandlerMapping):根据请求的url路径,通过注解或者xml配置,寻找匹配的Handler。
  • 处理器适配器(HandlerAdapter):Handler 的适配器,调用 handler 的方法处理请求。
  • 处理器(Handler):执行相关的请求处理逻辑,并返回相应的数据和视图信息,将其封装到ModelAndView对象中。
  • 视图解析器(ViewResolver):将逻辑视图名解析成真正的视图View。
  • 视图(View):接口类,实现类可支持不同的View类型(JSP、FreeMarker、Excel等)
MVC案例

基于webxml

2.png

示例源码点击这里
maven引入
  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2.          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  3.     <modelVersion>4.0.0</modelVersion>
  4.     <parent>
  5.         <groupId>com.seven</groupId>
  6.         spring-demo</artifactId>
  7.         <version>1.0-SNAPSHOT</version>
  8.     </parent>
  9.     07-spring-mvc-helloworld</artifactId>
  10.     <packaging>war</packaging>
  11.     <name>07-spring-mvc-helloworld Maven Webapp</name>
  12.     <url>http://maven.apache.org</url>
  13.     <properties>
  14.         <maven.compiler.source>8</maven.compiler.source>
  15.         <maven.compiler.target>8</maven.compiler.target>
  16.         <spring.version>5.3.37</spring.version>
  17.         <servlet.version>4.0.1</servlet.version>
  18.     </properties>
  19.     <dependencies>
  20.         <dependency>
  21.             <groupId>org.springframework</groupId>
  22.             spring-webmvc</artifactId>
  23.             <version>${spring.version}</version>
  24.         </dependency>
  25.         <dependency>
  26.             <groupId>javax.servlet</groupId>
  27.             javax.servlet-api</artifactId>
  28.             <version>${servlet.version}</version>
  29.         </dependency>
  30.         <dependency>
  31.             <groupId>javax.servlet</groupId>
  32.             jstl</artifactId>
  33.             <version>1.2</version>
  34.         </dependency>
  35.         <dependency>
  36.             <groupId>taglibs</groupId>
  37.             standard</artifactId>
  38.             <version>1.1.2</version>
  39.         </dependency>
  40.     </dependencies>
  41.     <build>
  42.         <finalName>07-spring-mvc-helloworld</finalName>
  43.     </build>
  44. </project>
复制代码
业务代码编写


  • entity的User类
  1. @Data
  2. @AllArgsConstructor
  3. public class User {
  4.     private String name;
  5.     private int age;
  6. }
复制代码

  • dao层
  1. @Repository
  2. public class UserDaoImpl {
  3.     public List<User> findUserList() {
  4.         return Collections.singletonList(new User("seven", 18));
  5.     }
  6. }
复制代码

  • service层
  1. @Service
  2. public class UserServiceImpl {
  3.     @Autowired
  4.     private UserDaoImpl userDao;
  5.     public List<User> findUserList() {
  6.         return userDao.findUserList();
  7.     }
  8. }
复制代码

  • controller层
  1. @Controller
  2. public class UserController {
  3.     @Autowired
  4.     private UserServiceImpl userService;
  5.     @RequestMapping("/user")
  6.     public ModelAndView list(HttpServletRequest request, HttpServletResponse response) {
  7.         ModelAndView modelAndView = new ModelAndView();
  8.         modelAndView.addObject("dateTime", new Date());
  9.         modelAndView.addObject("userList", userService.findUserList());
  10.         modelAndView.setViewName("userList"); // views目录下userList.jsp
  11.         return modelAndView;
  12.     }
  13. }
复制代码
webapp下的web.xml
  1. <!DOCTYPE web-app PUBLIC
  2.         "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
  3.         "http://java.sun.com/dtd/web-app_2_3.dtd" >
  4. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  5.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  6.          xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  7.          version="3.1">
  8.     <display-name>Archetype Created Web Application</display-name>
  9.     <servlet>
  10.         <servlet-name>springmvc-demo</servlet-name>
  11.         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  12.         
  13.         <init-param>
  14.             <param-name>contextConfigLocation</param-name>
  15.             <param-value>classpath:springmvc.xml</param-value>
  16.         </init-param>
  17.         <load-on-startup>1</load-on-startup>
  18.     </servlet>
  19.     <servlet-mapping>
  20.         <servlet-name>springmvc-demo</servlet-name>
  21.         <url-pattern>/</url-pattern>
  22.     </servlet-mapping>
  23.     <filter>
  24.         <filter-name>encodingFilter</filter-name>
  25.         <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  26.         <init-param>
  27.             <param-name>encoding</param-name>
  28.             <param-value>UTF-8</param-value>
  29.         </init-param>
  30.         <init-param>
  31.             <param-name>forceEncoding</param-name>
  32.             <param-value>true</param-value>
  33.         </init-param>
  34.     </filter>
  35.     <filter-mapping>
  36.         <filter-name>encodingFilter</filter-name>
  37.         <url-pattern>/*</url-pattern>
  38.     </filter-mapping>
  39. </web-app>
复制代码
springmvc.xml

web.xml中配置初始化参数contextConfigLocation,路径是classpath:springmvc.xml,因此文件直接创建在resources目录下
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.        xmlns:context="http://www.springframework.org/schema/context"
  5.        xmlns:mvc="http://www.springframework.org/schema/mvc"
  6.        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  7.        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
  8.        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
  9.    
  10.     <context:component-scan base-package="com.seven.springmvchelloworld"/>
  11.    
  12.     <mvc:default-servlet-handler/>
  13.    
  14.     <mvc:annotation-driven/>
  15.    
  16.    
  17.        
  18.        
  19.        
  20.    
  21.    
  22.     <bean id="jspViewResolver" >
  23.         <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
  24.         <property name="prefix" value="/views/"/>
  25.         <property name="suffix" value=".jsp"/>
  26.     </bean>
  27. </beans>
复制代码
JSP视图

创建userList.jsp
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  3. <!DOCTYPE html>
  4. <html lang="zh-CN">
  5. <head>
  6.     <meta charset="utf-8">
  7.     <meta http-equiv="X-UA-Compatible" content="IE=edge">
  8.     <meta name="viewport" content="width=device-width, initial-scale=1">
  9.     <title>User List</title>
  10.    
  11.     <link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
  12. </head>
  13. <body>
  14.     <c:if test="${!empty userList}">
  15.         <table >
  16.             <tr>
  17.                 <th>Name</th>
  18.                 <th>Age</th>
  19.             </tr>
  20.             <c:forEach items="${userList}" var="user">
  21.                 <tr>
  22.                     <td>${user.name}</td>
  23.                     <td>${user.age}</td>
  24.                 </tr>
  25.             </c:forEach>
  26.         </table>
  27.     </c:if>
  28. </body>
  29. </html>
复制代码
之后就是使用tomcat部署测试了,这块就不说了
纯注解版

无需配置xml文件,依靠注解和配置类完成配置,注意需要注意满足sevlet3.0规范
具体源码点击这里
这个不做过多讲解,真实项目的用得较少。因为若是老项目,就是基于webxml的,若是新项目,则直接上springboot了。
Spring MVC响应请求

直接返回ModelAndView对象

ModelAndView对象将数据模型和视图信息封装在一起。
  1. @RequestMapping("/order")
  2. public ModelAndView getOrderPage() {
  3.     // 1. 创建ModelAndView对象
  4.     ModelAndView mav = new ModelAndView();
  5.    
  6.     // 2. 添加模型数据(相当于model.addAttribute)
  7.     Order order = orderService.getLatestOrder();
  8.     mav.addObject("currentOrder", order);
  9.     mav.addObject("pageTitle", "订单详情");
  10.    
  11.     // 3. 设置视图名称
  12.     mav.setViewName("orderDetail"); // 视图解析器会处理为完整路径
  13.    
  14.     return mav;
  15. }
复制代码
返回视图名称(页面跳转)

该方法返回 "userDetail.jsp",并可以在页面上通过 ${user}获取数据
  1. @Controller
  2. @RequestMapping("/user")
  3. public class UserController {
  4.    
  5.     @RequestMapping("/detail")
  6.     public String getUserDetail(Model model) {
  7.         // 模拟查询用户信息
  8.         User user = userService.findUserById(1);
  9.         // 将数据添加到Model中,会自动存入请求域
  10.         model.addAttribute("user", user);
  11.         // 返回逻辑视图名,视图解析器会将其拼接为 "/WEB-INF/views/userDetail.jsp"
  12.         return "userDetail.jsp";
  13.     }
  14. }
复制代码
使用Map传递数据

该方法返回 "userDetail.jsp",并可以在页面上通过 ${user}获取数据
  1. @Controller
  2. @RequestMapping("/user")
  3. public class UserController {
  4.    
  5.     @RequestMapping("/detail")
  6.     public String getUserDetail(Map<String, User> map) {
  7.         // 模拟查询用户信息
  8.         User user = userService.findUserById(1);
  9.         // 将数据添加到Model中,会自动存入请求域
  10.         map.addAttribute("user", user);
  11.         // 返回逻辑视图名,视图解析器会将其拼接为 "/WEB-INF/views/userDetail.jsp"
  12.         return "userDetail.jsp";
  13.     }
  14. }
复制代码
返回void

这种方式绕过了SpringMVC的视图解析,提供了最大灵活性,但需要自行处理响应细节,与Servlet API耦合度高,一般不推荐作为主要方式
  1. @RequestMapping("/raw")
  2. public void handleRawResponse(HttpServletResponse response) throws IOException {
  3.     // 设置响应类型和编码
  4.     response.setContentType("text/plain; charset=UTF-8");
  5.     // 直接通过HttpServletResponse输出
  6.     PrintWriter out = response.getWriter();
  7.     out.write("这是一个直接输出的响应");
  8.     out.flush();
  9. }
复制代码
重定向跳转

redirect:会让浏览器地址栏变为新的URL。注意,重定向是两次请求,原始请求域(request scope)中的数据会丢失。若要传递参数,可使用 RedirectAttributes
  1. @PostMapping("/submit")
  2. public String submitForm(LoginForm form) {
  3.     // ... 处理表单提交逻辑,如保存数据
  4.     boolean isSuccess = loginService.processLogin(form);
  5.    
  6.     // 重定向到另一个地址,防止用户刷新浏览器导致表单重复提交
  7.     return "redirect:/login/success"; // 浏览器会向 "/login/success" 发起新请求
  8. }
  9. @GetMapping("/success")
  10. public String successPage() {
  11.     return "success"; // 展示成功页面
  12. }
复制代码
使用HttpServletResponse

此方式适用于文件下载、输出特定二进制内容等需要精细控制输出流的场景。它完全绕过了SpringMVC的视图解析机制
  1. @RequestMapping("/download")
  2. public void downloadFile(HttpServletResponse response) throws IOException {
  3.     // 设置响应头,告诉浏览器这是一个要下载的PDF文件
  4.     response.setContentType("application/pdf");
  5.     response.setHeader("Content-Disposition", "attachment; filename="document.pdf"");
  6.    
  7.     // 获取文件流(此处为模拟)
  8.     byte[] fileContent = getFileContent();
  9.    
  10.     // 通过ServletResponse的输出流直接写入数据
  11.     ServletOutputStream out = response.getOutputStream();
  12.     out.write(fileContent);
  13.     out.flush();
  14. }
复制代码
直接返回数据(如JSON)

@ResponseBody注解是核心,它告诉Spring将方法返回值直接写入响应流。若项目中配置了消息转换器(如Jackson),可直接返回对象,Spring会自动将其转为JSON
  1. @Controller
  2. @RequestMapping("/api")
  3. public class ApiController {
  4.     @RequestMapping(value = "/user", produces = "application/json;charset=UTF-8")
  5.     @ResponseBody // 关键注解:表明返回值直接作为HTTP响应体,不进行视图解析
  6.     public String getUserAsJson() {
  7.         User user = new User("张三", 25);
  8.         // 手动将对象转为JSON字符串(需Jackson等库)
  9.         ObjectMapper mapper = new ObjectMapper();
  10.         try {
  11.             return mapper.writeValueAsString(user);
  12.         } catch (JsonProcessingException e) {
  13.             return "{"error": "转换失败"}";
  14.         }
  15.         // 更佳实践:直接返回对象,配置消息转换器自动转JSON(见后续说明)
  16.     }
  17. }
复制代码
SringMVC接收数据

基本数据类型接收
  1. @RestController
  2. @RequestMapping("/api/user")
  3. public class UserController {
  4.    
  5.     /**
  6.      * 接收单个基本类型参数
  7.      * GET /api/user/detail?id=123
  8.      */
  9.     @GetMapping("/detail")
  10.     public String getUserDetail(@RequestParam("id") Long userId) {
  11.         // @RequestParam将请求参数"id"映射到方法参数userId
  12.         return "用户ID: " + userId;
  13.     }
  14.    
  15.     /**
  16.      * 参数可选,设置默认值
  17.      * GET /api/user/list 或 /api/user/list?page=2
  18.      */
  19.     @GetMapping("/list")
  20.     public String getUserList(
  21.             @RequestParam(value = "page", required = false, defaultValue = "1") Integer page,
  22.             @RequestParam(value = "size", required = false, defaultValue = "10") Integer size) {
  23.         // required=false表示参数可选,defaultValue设置默认值
  24.         return String.format("第%d页,每页%d条", page, size);
  25.     }
  26.    
  27.     /**
  28.      * 简化写法:参数名与方法参数名一致时可省略@RequestParam
  29.      * GET /api/user/simple?name=张三&age=25
  30.      */
  31.     @GetMapping("/simple")
  32.     public String simpleParams(String name, Integer age) {
  33.         // 当请求参数名与方法参数名一致时,可以省略@RequestParam
  34.         return "姓名: " + name + ", 年龄: " + age;
  35.     }
  36. }
复制代码
接收路径参数
  1. @RestController
  2. @RequestMapping("/api/product")
  3. public class ProductController {
  4.    
  5.     /**
  6.      * 接收路径参数
  7.      * GET /api/product/1001/category/2001
  8.      */
  9.     @GetMapping("/{productId}/category/{categoryId}")
  10.     public String getProductInfo(
  11.             @PathVariable("productId") Long productId,
  12.             @PathVariable("categoryId") Long categoryId) {
  13.         // @PathVariable从URL路径中提取参数
  14.         return String.format("产品ID: %d, 分类ID: %d", productId, categoryId);
  15.     }
  16.    
  17.     /**
  18.      * 正则表达式限制路径参数格式
  19.      * GET /api/product/2023-10-25
  20.      */
  21.     @GetMapping("/{date:\\d{4}-\\d{2}-\\d{2}}")
  22.     public String getProductsByDate(@PathVariable String date) {
  23.         // 使用正则表达式限制日期格式
  24.         return "查询日期: " + date;
  25.     }
  26. }
复制代码
对象接收(自动绑定)

接收简单对象参数
  1. /**
  2. * 用户查询参数对象
  3. */
  4. public class UserQueryParams {
  5.     private String username;
  6.     private String email;
  7.     private Integer age;
  8.     private Date createTime;
  9.    
  10.     // 必须提供getter和setter方法
  11.     public String getUsername() { return username; }
  12.     public void setUsername(String username) { this.username = username; }
  13.    
  14.     public String getEmail() { return email; }
  15.     public void setEmail(String email) { this.email = email; }
  16.    
  17.     public Integer getAge() { return age; }
  18.     public void setAge(Integer age) { this.age = age; }
  19.    
  20.     public Date getCreateTime() { return createTime; }
  21.     public void setCreateTime(Date createTime) { this.createTime = createTime; }
  22.    
  23.     @Override
  24.     public String toString() {
  25.         return String.format("UserQuery{username='%s', email='%s', age=%d}",
  26.                            username, email, age);
  27.     }
  28. }
  29. @RestController
  30. @RequestMapping("/api/users")
  31. public class UserController {
  32.    
  33.     /**
  34.      * 对象接收 - GET请求
  35.      * GET /api/users/search?username=张三&email=zhang@example.com&age=25
  36.      */
  37.     @GetMapping("/search")
  38.     public String searchUsers(UserQueryParams params) {
  39.         // Spring自动将请求参数绑定到对象属性
  40.         return "查询参数: " + params.toString();
  41.     }
  42.    
  43.     /**
  44.      * 对象接收 - POST表单提交
  45.      * POST /api/users/create
  46.      * Content-Type: application/x-www-form-urlencoded
  47.      * Body: username=李四&email=li@example.com&age=30
  48.      */
  49.     @PostMapping("/create")
  50.     public String createUser(UserQueryParams user) {
  51.         return "创建用户: " + user.toString();
  52.     }
  53. }
复制代码
接收嵌套对象参数
  1. /**
  2. * 地址信息
  3. */
  4. public class Address {
  5.     private String province;
  6.     private String city;
  7.     private String street;
  8.     // getter/setter省略...
  9. }
  10. /**
  11. * 用户信息(包含嵌套对象)
  12. */
  13. public class UserInfo {
  14.     private String name;
  15.     private Integer age;
  16.     private Address address; // 嵌套对象
  17.    
  18.     // getter/setter...
  19.     public String getName() { return name; }
  20.     public void setName(String name) { this.name = name; }
  21.    
  22.     public Integer getAge() { return age; }
  23.     public void setAge(Integer age) { this.age = age; }
  24.    
  25.     public Address getAddress() { return address; }
  26.     public void setAddress(Address address) { this.address = address; }
  27. }
  28. @RestController
  29. @RequestMapping("/api/profile")
  30. public class ProfileController {
  31.    
  32.     /**
  33.      * 接收嵌套对象参数
  34.      * GET /api/profile/update?name=王五&age=28&address.province=北京&address.city=北京市
  35.      */
  36.     @PostMapping("/update")
  37.     public String updateProfile(UserInfo userInfo) {
  38.         // 使用点号语法接收嵌套对象属性
  39.         return String.format("用户: %s, 年龄: %d, 地址: %s-%s",
  40.             userInfo.getName(), userInfo.getAge(),
  41.             userInfo.getAddress().getProvince(),
  42.             userInfo.getAddress().getCity());
  43.     }
  44. }
复制代码
数组接收

数组在表单中的应用
  1. <form action="/api/products/batch-delete" method="post">
  2.    
  3.     <input type="checkbox" name="productIds" value="1001"> 产品A
  4.     <input type="checkbox" name="productIds" value="1002"> 产品B
  5.     <input type="checkbox" name="productIds" value="1003"> 产品C
  6.     <button type="submit">批量删除</button>
  7. </form>
复制代码
  1. @RestController
  2. @RequestMapping("/api/products")
  3. public class ProductController {
  4.    
  5.     /**
  6.      * 批量删除产品
  7.      * POST /api/products/batch-delete
  8.      * Body: productIds=1001&productIds=1002&productIds=1003
  9.      */
  10.     @PostMapping("/batch-delete")
  11.     public String batchDeleteProducts(@RequestParam Long[] productIds) {
  12.         return "删除的产品ID: " + Arrays.toString(productIds);
  13.     }
  14. }
复制代码
集合接收(通过包装对象)

SpringMVC 不能直接在方法参数中接收集合,但可以通过对象包装的方式来接收。
  1. /**
  2. * 包装类,包含集合属性
  3. */
  4. public class BatchOperation {
  5.     private List<Long> ids;
  6.     private List<String> names;
  7.    
  8.     // getter/setter...
  9.     public List<Long> getIds() { return ids; }
  10.     public void setIds(List<Long> ids) { this.ids = ids; }
  11.    
  12.     public List<String> getNames() { return names; }
  13.     public void setNames(List<String> names) { this.names = names; }
  14. }
  15. @RestController
  16. @RequestMapping("/api/batch")
  17. public class BatchController {
  18.    
  19.     /**
  20.      * 接收集合参数 - 通过包装对象
  21.      * POST /api/batch/process
  22.      * 请求体格式1: ids=1&ids=2&ids=3
  23.      * 请求体格式2: names=Alice&names=Bob&names=Charlie
  24.      */
  25.     @PostMapping("/process")
  26.     public String processBatch(BatchOperation operation) {
  27.         StringBuilder result = new StringBuilder();
  28.         if (operation.getIds() != null) {
  29.             result.append("ID列表: ").append(operation.getIds());
  30.         }
  31.         if (operation.getNames() != null) {
  32.             result.append("名称列表: ").append(operation.getNames());
  33.         }
  34.         return result.toString();
  35.     }
  36. }
复制代码
自定义转换器


  • 日期格式转换器
  1. /**
  2. * 自定义日期转换器
  3. * 将字符串转换为Date对象
  4. */
  5. @Component
  6. public class StringToDateConverter implements Converter<String, Date> {
  7.    
  8.     private static final String[] DATE_PATTERNS = {
  9.         "yyyy-MM-dd",
  10.         "yyyy/MM/dd",
  11.         "yyyy-MM-dd HH:mm:ss",
  12.         "yyyy/MM/dd HH:mm:ss"
  13.     };
  14.    
  15.     @Override
  16.     public Date convert(String source) {
  17.         if (source == null || source.trim().isEmpty()) {
  18.             return null;
  19.         }
  20.         
  21.         // 尝试多种日期格式
  22.         for (String pattern : DATE_PATTERNS) {
  23.             try {
  24.                 SimpleDateFormat format = new SimpleDateFormat(pattern);
  25.                 format.setLenient(false); // 严格模式
  26.                 return format.parse(source);
  27.             } catch (ParseException e) {
  28.                 // 尝试下一种格式
  29.                 continue;
  30.             }
  31.         }
  32.         
  33.         throw new IllegalArgumentException("无效的日期格式: " + source +
  34.             ",支持的格式: " + Arrays.toString(DATE_PATTERNS));
  35.     }
  36. }
复制代码

  • 枚举类型转换器
  1. /**
  2. * 用户状态枚举
  3. */
  4. public enum UserStatus {
  5.     ACTIVE("活跃"),
  6.     INACTIVE("非活跃"),
  7.     DELETED("已删除");
  8.    
  9.     private final String description;
  10.    
  11.     UserStatus(String description) {
  12.         this.description = description;
  13.     }
  14.    
  15.     public String getDescription() {
  16.         return description;
  17.     }
  18. }
  19. /**
  20. * 字符串到枚举转换器
  21. */
  22. @Component
  23. public class StringToUserStatusConverter implements Converter<String, UserStatus> {
  24.    
  25.     @Override
  26.     public UserStatus convert(String source) {
  27.         if (source == null || source.trim().isEmpty()) {
  28.             return null;
  29.         }
  30.         
  31.         // 不区分大小写匹配
  32.         for (UserStatus status : UserStatus.values()) {
  33.             if (status.name().equalsIgnoreCase(source)) {
  34.                 return status;
  35.             }
  36.         }
  37.         
  38.         // 也支持中文描述匹配
  39.         for (UserStatus status : UserStatus.values()) {
  40.             if (status.getDescription().equals(source)) {
  41.                 return status;
  42.             }
  43.         }
  44.         
  45.         throw new IllegalArgumentException("无效的用户状态: " + source);
  46.     }
  47. }
复制代码

  • 注册自定义转换器
  1. @Configuration
  2. public class WebConfig implements WebMvcConfigurer {
  3.    
  4.     @Autowired
  5.     private StringToDateConverter stringToDateConverter;
  6.    
  7.     @Autowired
  8.     private StringToUserStatusConverter stringToUserStatusConverter;
  9.    
  10.     /**
  11.      * 注册自定义转换器
  12.      */
  13.     @Override
  14.     public void addFormatters(FormatterRegistry registry) {
  15.         registry.addConverter(stringToDateConverter);
  16.         registry.addConverter(stringToUserStatusConverter);
  17.     }
  18. }
复制代码

  • 在控制器中使用自定义转换
  1. @RestController
  2. @RequestMapping("/api/converter")
  3. public class ConverterController {
  4.    
  5.     /**
  6.      * 使用自定义日期转换器
  7.      * GET /api/converter/date?date=2023-10-25
  8.      */
  9.     @GetMapping("/date")
  10.     public String handleDateParam(@RequestParam Date date) {
  11.         // Spring会自动使用我们注册的StringToDateConverter
  12.         SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
  13.         return "转换后的日期: " + format.format(date);
  14.     }
  15.    
  16.     /**
  17.      * 使用自定义枚举转换器
  18.      * GET /api/converter/status?status=ACTIVE
  19.      * GET /api/converter/status?status=活跃
  20.      */
  21.     @GetMapping("/status")
  22.     public String handleStatusParam(@RequestParam UserStatus status) {
  23.         return "用户状态: " + status.getDescription();
  24.     }
  25.    
  26.     /**
  27.      * 在对象中使用自定义转换
  28.      * GET /api/converter/user?name=张三&createTime=2023-10-25 14:30:00&status=INACTIVE
  29.      */
  30.     @GetMapping("/user")
  31.     public String handleUserObject(UserQuery userQuery) {
  32.         // UserQuery对象中包含Date和UserStatus属性
  33.         return String.format("用户: %s, 创建时间: %s, 状态: %s",
  34.             userQuery.getName(),
  35.             userQuery.getCreateTime(),
  36.             userQuery.getStatus().getDescription());
  37.     }
  38. }
  39. /**
  40. * 用户查询对象(包含需要自定义转换的属性)
  41. */
  42. class UserQuery {
  43.     private String name;
  44.     private Date createTime;      // 需要自定义转换
  45.     private UserStatus status;    // 需要自定义转换
  46.    
  47.     // getter/setter...
  48.     public String getName() { return name; }
  49.     public void setName(String name) { this.name = name; }
  50.    
  51.     public Date getCreateTime() { return createTime; }
  52.     public void setCreateTime(Date createTime) { this.createTime = createTime; }
  53.    
  54.     public UserStatus getStatus() { return status; }
  55.     public void setStatus(UserStatus status) { this.status = status; }
  56. }
复制代码
SpringMVC其它使用

视图解析器添加前后缀

配置视图解析器可以免去重复书写视图文件路径的前后缀。

  • xml 或者Java Config
  1.     <bean id="jspViewResolver" >
  2.         <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
  3.         <property name="prefix" value="/views/"/>
  4.         <property name="suffix" value=".jsp"/>
  5.     </bean>
复制代码
  1. @Configuration
  2. public class ViewConfig {
  3.    
  4.     @Bean
  5.     public ViewResolver viewResolver() {
  6.         InternalResourceViewResolver resolver = new InternalResourceViewResolver();
  7.         // 设置所有视图文件所在的公共前缀
  8.         resolver.setPrefix("/views/");
  9.         // 设置视图文件的公共后缀
  10.         resolver.setSuffix(".jsp");
  11.         return resolver;
  12.     }
  13. }
复制代码

  • 控制器代码
此配置后,控制器返回的 "index"会被自动补全为 /views/index.jsp,极大简化了视图管理
  1. @Controller
  2. public class HomeController {
  3.    
  4.     @RequestMapping("/home")
  5.     public String home() {
  6.         // 控制器中只需返回逻辑视图名 "index"
  7.         // 视图解析器会自动拼接为 "/WEB-INF/views/index.jsp"
  8.         return "index";
  9.     }
  10. }
复制代码
中文乱码问题处理
  1.                 characterEncodingFilter        org.springframework.web.filter.CharacterEncodingFilter<?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.        xmlns:mvc="http://www.springframework.org/schema/mvc"
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans
  6.         http://www.springframework.org/schema/beans/spring-beans.xsd
  7.         http://www.springframework.org/schema/mvc
  8.         http://www.springframework.org/schema/mvc/spring-mvc.xsd">
  9.    
  10.     <mvc:default-servlet-handler/>
  11.    
  12.    
  13.     <mvc:annotation-driven/>
  14.    
  15.    
  16.     <context:component-scan base-package="com.example.controller"/>
  17. </beans>encoding            UTF-8
  18.     <bean id="jspViewResolver" >
  19.         <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
  20.         <property name="prefix" value="/views/"/>
  21.         <property name="suffix" value=".jsp"/>
  22.     </bean>       forceEncoding            true                            characterEncodingFilter        /*   
复制代码
静态资源处理

默认情况下,DispatcherServlet 会拦截所有请求,包括静态资源请求,这会导致静态资源无法正常访问。因此,我们需要配置 Spring MVC 以允许容器直接提供静态资源。
有两种主要方式来处理静态资源:

  • 使用 标签(XML 配置)
  • 使用 WebMvcConfigurer的 addResourceHandlers方法(Java 配置)
另外,还可以使用 来允许容器默认的 Servlet 处理静态资源。

  • XML 配置方式-使用默认Servlet处理(简单方式)
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.        xmlns:mvc="http://www.springframework.org/schema/mvc"
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans
  6.         http://www.springframework.org/schema/beans/spring-beans.xsd
  7.         http://www.springframework.org/schema/mvc
  8.         http://www.springframework.org/schema/mvc/spring-mvc.xsd">
  9.    
  10.     <mvc:default-servlet-handler/>
  11.    
  12.    
  13.     <mvc:annotation-driven/>
  14.    
  15.    
  16.     <context:component-scan base-package="com.example.controller"/>
  17. </beans>
复制代码

  • XML 配置方式-使用资源映射(推荐方式)
  1.     <bean id="jspViewResolver" >
  2.         <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
  3.         <property name="prefix" value="/views/"/>
  4.         <property name="suffix" value=".jsp"/>
  5.     </bean>
  6.     <bean id="jspViewResolver" >
  7.         <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
  8.         <property name="prefix" value="/views/"/>
  9.         <property name="suffix" value=".jsp"/>
  10.     </bean>      
复制代码

  • JavaConfig 配置方式
  1. import org.springframework.context.annotation.Configuration;
  2. import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
  3. import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  4. @Configuration
  5. public class WebMvcConfig implements WebMvcConfigurer {
  6.    
  7.     /**
  8.      * 配置静态资源处理
  9.      */
  10.     @Override
  11.     public void addResourceHandlers(ResourceHandlerRegistry registry) {
  12.         // 1. 类路径下的静态资源
  13.         registry.addResourceHandler("/static/**")
  14.                 .addResourceLocations("classpath:/static/")
  15.                 .setCachePeriod(3600); // 缓存1小时
  16.         
  17.         // 2. Web根目录下的资源
  18.         registry.addResourceHandler("/css/**")
  19.                 .addResourceLocations("/css/");
  20.         
  21.         registry.addResourceHandler("/js/**")
  22.                 .addResourceLocations("/js/");
  23.         
  24.         registry.addResourceHandler("/images/**")
  25.                 .addResourceLocations("/images/");
  26.         
  27.         // 3. 外部文件系统资源
  28.         registry.addResourceHandler("/uploads/**")
  29.                 .addResourceLocations("file:/var/uploads/");
  30.         
  31.         // 4. WebJars支持
  32.         registry.addResourceHandler("/webjars/**")
  33.                 .addResourceLocations("classpath:/META-INF/resources/webjars/");
  34.     }
  35. }
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册