前言
什么是MVC
MVC英文是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计规范,本质上也是一种解耦。
- 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
示例源码点击这里
maven引入
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>com.seven</groupId>
- spring-demo</artifactId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- 07-spring-mvc-helloworld</artifactId>
- <packaging>war</packaging>
- <name>07-spring-mvc-helloworld Maven Webapp</name>
- <url>http://maven.apache.org</url>
- <properties>
- <maven.compiler.source>8</maven.compiler.source>
- <maven.compiler.target>8</maven.compiler.target>
- <spring.version>5.3.37</spring.version>
- <servlet.version>4.0.1</servlet.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework</groupId>
- spring-webmvc</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>javax.servlet</groupId>
- javax.servlet-api</artifactId>
- <version>${servlet.version}</version>
- </dependency>
- <dependency>
- <groupId>javax.servlet</groupId>
- jstl</artifactId>
- <version>1.2</version>
- </dependency>
- <dependency>
- <groupId>taglibs</groupId>
- standard</artifactId>
- <version>1.1.2</version>
- </dependency>
- </dependencies>
- <build>
- <finalName>07-spring-mvc-helloworld</finalName>
- </build>
- </project>
复制代码 业务代码编写
- @Data
- @AllArgsConstructor
- public class User {
- private String name;
- private int age;
- }
复制代码- @Repository
- public class UserDaoImpl {
- public List<User> findUserList() {
- return Collections.singletonList(new User("seven", 18));
- }
- }
复制代码- @Service
- public class UserServiceImpl {
- @Autowired
- private UserDaoImpl userDao;
- public List<User> findUserList() {
- return userDao.findUserList();
- }
- }
复制代码- @Controller
- public class UserController {
- @Autowired
- private UserServiceImpl userService;
- @RequestMapping("/user")
- public ModelAndView list(HttpServletRequest request, HttpServletResponse response) {
- ModelAndView modelAndView = new ModelAndView();
- modelAndView.addObject("dateTime", new Date());
- modelAndView.addObject("userList", userService.findUserList());
- modelAndView.setViewName("userList"); // views目录下userList.jsp
- return modelAndView;
- }
- }
复制代码 webapp下的web.xml
- <!DOCTYPE web-app PUBLIC
- "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
- "http://java.sun.com/dtd/web-app_2_3.dtd" >
- <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
- version="3.1">
- <display-name>Archetype Created Web Application</display-name>
- <servlet>
- <servlet-name>springmvc-demo</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
-
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath:springmvc.xml</param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>springmvc-demo</servlet-name>
- <url-pattern>/</url-pattern>
- </servlet-mapping>
- <filter>
- <filter-name>encodingFilter</filter-name>
- <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
- <init-param>
- <param-name>encoding</param-name>
- <param-value>UTF-8</param-value>
- </init-param>
- <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>
- </web-app>
复制代码 springmvc.xml
web.xml中配置初始化参数contextConfigLocation,路径是classpath:springmvc.xml,因此文件直接创建在resources目录下- <?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">
-
- <context:component-scan base-package="com.seven.springmvchelloworld"/>
-
- <mvc:default-servlet-handler/>
-
- <mvc:annotation-driven/>
-
-
-
-
-
-
-
- <bean id="jspViewResolver" >
- <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
- <property name="prefix" value="/views/"/>
- <property name="suffix" value=".jsp"/>
- </bean>
- </beans>
复制代码 JSP视图
创建userList.jsp- <%@ page contentType="text/html;charset=UTF-8" language="java" %>
- <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <title>User List</title>
-
- <link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
- </head>
- <body>
- <c:if test="${!empty userList}">
- <table >
- <tr>
- <th>Name</th>
- <th>Age</th>
- </tr>
- <c:forEach items="${userList}" var="user">
- <tr>
- <td>${user.name}</td>
- <td>${user.age}</td>
- </tr>
- </c:forEach>
- </table>
- </c:if>
- </body>
- </html>
复制代码 之后就是使用tomcat部署测试了,这块就不说了
纯注解版
无需配置xml文件,依靠注解和配置类完成配置,注意需要注意满足sevlet3.0规范
具体源码点击这里
这个不做过多讲解,真实项目的用得较少。因为若是老项目,就是基于webxml的,若是新项目,则直接上springboot了。
Spring MVC响应请求
直接返回ModelAndView对象
ModelAndView对象将数据模型和视图信息封装在一起。- @RequestMapping("/order")
- public ModelAndView getOrderPage() {
- // 1. 创建ModelAndView对象
- ModelAndView mav = new ModelAndView();
-
- // 2. 添加模型数据(相当于model.addAttribute)
- Order order = orderService.getLatestOrder();
- mav.addObject("currentOrder", order);
- mav.addObject("pageTitle", "订单详情");
-
- // 3. 设置视图名称
- mav.setViewName("orderDetail"); // 视图解析器会处理为完整路径
-
- return mav;
- }
复制代码 返回视图名称(页面跳转)
该方法返回 "userDetail.jsp",并可以在页面上通过 ${user}获取数据- @Controller
- @RequestMapping("/user")
- public class UserController {
-
- @RequestMapping("/detail")
- public String getUserDetail(Model model) {
- // 模拟查询用户信息
- User user = userService.findUserById(1);
- // 将数据添加到Model中,会自动存入请求域
- model.addAttribute("user", user);
- // 返回逻辑视图名,视图解析器会将其拼接为 "/WEB-INF/views/userDetail.jsp"
- return "userDetail.jsp";
- }
- }
复制代码 使用Map传递数据
该方法返回 "userDetail.jsp",并可以在页面上通过 ${user}获取数据- @Controller
- @RequestMapping("/user")
- public class UserController {
-
- @RequestMapping("/detail")
- public String getUserDetail(Map<String, User> map) {
- // 模拟查询用户信息
- User user = userService.findUserById(1);
- // 将数据添加到Model中,会自动存入请求域
- map.addAttribute("user", user);
- // 返回逻辑视图名,视图解析器会将其拼接为 "/WEB-INF/views/userDetail.jsp"
- return "userDetail.jsp";
- }
- }
复制代码 返回void
这种方式绕过了SpringMVC的视图解析,提供了最大灵活性,但需要自行处理响应细节,与Servlet API耦合度高,一般不推荐作为主要方式- @RequestMapping("/raw")
- public void handleRawResponse(HttpServletResponse response) throws IOException {
- // 设置响应类型和编码
- response.setContentType("text/plain; charset=UTF-8");
- // 直接通过HttpServletResponse输出
- PrintWriter out = response.getWriter();
- out.write("这是一个直接输出的响应");
- out.flush();
- }
复制代码 重定向跳转
redirect:会让浏览器地址栏变为新的URL。注意,重定向是两次请求,原始请求域(request scope)中的数据会丢失。若要传递参数,可使用 RedirectAttributes- @PostMapping("/submit")
- public String submitForm(LoginForm form) {
- // ... 处理表单提交逻辑,如保存数据
- boolean isSuccess = loginService.processLogin(form);
-
- // 重定向到另一个地址,防止用户刷新浏览器导致表单重复提交
- return "redirect:/login/success"; // 浏览器会向 "/login/success" 发起新请求
- }
- @GetMapping("/success")
- public String successPage() {
- return "success"; // 展示成功页面
- }
复制代码 使用HttpServletResponse
此方式适用于文件下载、输出特定二进制内容等需要精细控制输出流的场景。它完全绕过了SpringMVC的视图解析机制- @RequestMapping("/download")
- public void downloadFile(HttpServletResponse response) throws IOException {
- // 设置响应头,告诉浏览器这是一个要下载的PDF文件
- response.setContentType("application/pdf");
- response.setHeader("Content-Disposition", "attachment; filename="document.pdf"");
-
- // 获取文件流(此处为模拟)
- byte[] fileContent = getFileContent();
-
- // 通过ServletResponse的输出流直接写入数据
- ServletOutputStream out = response.getOutputStream();
- out.write(fileContent);
- out.flush();
- }
复制代码 直接返回数据(如JSON)
@ResponseBody注解是核心,它告诉Spring将方法返回值直接写入响应流。若项目中配置了消息转换器(如Jackson),可直接返回对象,Spring会自动将其转为JSON- @Controller
- @RequestMapping("/api")
- public class ApiController {
- @RequestMapping(value = "/user", produces = "application/json;charset=UTF-8")
- @ResponseBody // 关键注解:表明返回值直接作为HTTP响应体,不进行视图解析
- public String getUserAsJson() {
- User user = new User("张三", 25);
- // 手动将对象转为JSON字符串(需Jackson等库)
- ObjectMapper mapper = new ObjectMapper();
- try {
- return mapper.writeValueAsString(user);
- } catch (JsonProcessingException e) {
- return "{"error": "转换失败"}";
- }
- // 更佳实践:直接返回对象,配置消息转换器自动转JSON(见后续说明)
- }
- }
复制代码 SringMVC接收数据
基本数据类型接收
- @RestController
- @RequestMapping("/api/user")
- public class UserController {
-
- /**
- * 接收单个基本类型参数
- * GET /api/user/detail?id=123
- */
- @GetMapping("/detail")
- public String getUserDetail(@RequestParam("id") Long userId) {
- // @RequestParam将请求参数"id"映射到方法参数userId
- return "用户ID: " + userId;
- }
-
- /**
- * 参数可选,设置默认值
- * GET /api/user/list 或 /api/user/list?page=2
- */
- @GetMapping("/list")
- public String getUserList(
- @RequestParam(value = "page", required = false, defaultValue = "1") Integer page,
- @RequestParam(value = "size", required = false, defaultValue = "10") Integer size) {
- // required=false表示参数可选,defaultValue设置默认值
- return String.format("第%d页,每页%d条", page, size);
- }
-
- /**
- * 简化写法:参数名与方法参数名一致时可省略@RequestParam
- * GET /api/user/simple?name=张三&age=25
- */
- @GetMapping("/simple")
- public String simpleParams(String name, Integer age) {
- // 当请求参数名与方法参数名一致时,可以省略@RequestParam
- return "姓名: " + name + ", 年龄: " + age;
- }
- }
复制代码 接收路径参数
- @RestController
- @RequestMapping("/api/product")
- public class ProductController {
-
- /**
- * 接收路径参数
- * GET /api/product/1001/category/2001
- */
- @GetMapping("/{productId}/category/{categoryId}")
- public String getProductInfo(
- @PathVariable("productId") Long productId,
- @PathVariable("categoryId") Long categoryId) {
- // @PathVariable从URL路径中提取参数
- return String.format("产品ID: %d, 分类ID: %d", productId, categoryId);
- }
-
- /**
- * 正则表达式限制路径参数格式
- * GET /api/product/2023-10-25
- */
- @GetMapping("/{date:\\d{4}-\\d{2}-\\d{2}}")
- public String getProductsByDate(@PathVariable String date) {
- // 使用正则表达式限制日期格式
- return "查询日期: " + date;
- }
- }
复制代码 对象接收(自动绑定)
接收简单对象参数
- /**
- * 用户查询参数对象
- */
- public class UserQueryParams {
- private String username;
- private String email;
- private Integer age;
- private Date createTime;
-
- // 必须提供getter和setter方法
- public String getUsername() { return username; }
- public void setUsername(String username) { this.username = username; }
-
- public String getEmail() { return email; }
- public void setEmail(String email) { this.email = email; }
-
- public Integer getAge() { return age; }
- public void setAge(Integer age) { this.age = age; }
-
- public Date getCreateTime() { return createTime; }
- public void setCreateTime(Date createTime) { this.createTime = createTime; }
-
- @Override
- public String toString() {
- return String.format("UserQuery{username='%s', email='%s', age=%d}",
- username, email, age);
- }
- }
- @RestController
- @RequestMapping("/api/users")
- public class UserController {
-
- /**
- * 对象接收 - GET请求
- * GET /api/users/search?username=张三&email=zhang@example.com&age=25
- */
- @GetMapping("/search")
- public String searchUsers(UserQueryParams params) {
- // Spring自动将请求参数绑定到对象属性
- return "查询参数: " + params.toString();
- }
-
- /**
- * 对象接收 - POST表单提交
- * POST /api/users/create
- * Content-Type: application/x-www-form-urlencoded
- * Body: username=李四&email=li@example.com&age=30
- */
- @PostMapping("/create")
- public String createUser(UserQueryParams user) {
- return "创建用户: " + user.toString();
- }
- }
复制代码 接收嵌套对象参数
- /**
- * 地址信息
- */
- public class Address {
- private String province;
- private String city;
- private String street;
- // getter/setter省略...
- }
- /**
- * 用户信息(包含嵌套对象)
- */
- public class UserInfo {
- private String name;
- private Integer age;
- private Address address; // 嵌套对象
-
- // getter/setter...
- public String getName() { return name; }
- public void setName(String name) { this.name = name; }
-
- public Integer getAge() { return age; }
- public void setAge(Integer age) { this.age = age; }
-
- public Address getAddress() { return address; }
- public void setAddress(Address address) { this.address = address; }
- }
- @RestController
- @RequestMapping("/api/profile")
- public class ProfileController {
-
- /**
- * 接收嵌套对象参数
- * GET /api/profile/update?name=王五&age=28&address.province=北京&address.city=北京市
- */
- @PostMapping("/update")
- public String updateProfile(UserInfo userInfo) {
- // 使用点号语法接收嵌套对象属性
- return String.format("用户: %s, 年龄: %d, 地址: %s-%s",
- userInfo.getName(), userInfo.getAge(),
- userInfo.getAddress().getProvince(),
- userInfo.getAddress().getCity());
- }
- }
复制代码 数组接收
数组在表单中的应用- <form action="/api/products/batch-delete" method="post">
-
- <input type="checkbox" name="productIds" value="1001"> 产品A
- <input type="checkbox" name="productIds" value="1002"> 产品B
- <input type="checkbox" name="productIds" value="1003"> 产品C
- <button type="submit">批量删除</button>
- </form>
复制代码- @RestController
- @RequestMapping("/api/products")
- public class ProductController {
-
- /**
- * 批量删除产品
- * POST /api/products/batch-delete
- * Body: productIds=1001&productIds=1002&productIds=1003
- */
- @PostMapping("/batch-delete")
- public String batchDeleteProducts(@RequestParam Long[] productIds) {
- return "删除的产品ID: " + Arrays.toString(productIds);
- }
- }
复制代码 集合接收(通过包装对象)
SpringMVC 不能直接在方法参数中接收集合,但可以通过对象包装的方式来接收。- /**
- * 包装类,包含集合属性
- */
- public class BatchOperation {
- private List<Long> ids;
- private List<String> names;
-
- // getter/setter...
- public List<Long> getIds() { return ids; }
- public void setIds(List<Long> ids) { this.ids = ids; }
-
- public List<String> getNames() { return names; }
- public void setNames(List<String> names) { this.names = names; }
- }
- @RestController
- @RequestMapping("/api/batch")
- public class BatchController {
-
- /**
- * 接收集合参数 - 通过包装对象
- * POST /api/batch/process
- * 请求体格式1: ids=1&ids=2&ids=3
- * 请求体格式2: names=Alice&names=Bob&names=Charlie
- */
- @PostMapping("/process")
- public String processBatch(BatchOperation operation) {
- StringBuilder result = new StringBuilder();
- if (operation.getIds() != null) {
- result.append("ID列表: ").append(operation.getIds());
- }
- if (operation.getNames() != null) {
- result.append("名称列表: ").append(operation.getNames());
- }
- return result.toString();
- }
- }
复制代码 自定义转换器
- /**
- * 自定义日期转换器
- * 将字符串转换为Date对象
- */
- @Component
- public class StringToDateConverter implements Converter<String, Date> {
-
- private static final String[] DATE_PATTERNS = {
- "yyyy-MM-dd",
- "yyyy/MM/dd",
- "yyyy-MM-dd HH:mm:ss",
- "yyyy/MM/dd HH:mm:ss"
- };
-
- @Override
- public Date convert(String source) {
- if (source == null || source.trim().isEmpty()) {
- return null;
- }
-
- // 尝试多种日期格式
- for (String pattern : DATE_PATTERNS) {
- try {
- SimpleDateFormat format = new SimpleDateFormat(pattern);
- format.setLenient(false); // 严格模式
- return format.parse(source);
- } catch (ParseException e) {
- // 尝试下一种格式
- continue;
- }
- }
-
- throw new IllegalArgumentException("无效的日期格式: " + source +
- ",支持的格式: " + Arrays.toString(DATE_PATTERNS));
- }
- }
复制代码- /**
- * 用户状态枚举
- */
- public enum UserStatus {
- ACTIVE("活跃"),
- INACTIVE("非活跃"),
- DELETED("已删除");
-
- private final String description;
-
- UserStatus(String description) {
- this.description = description;
- }
-
- public String getDescription() {
- return description;
- }
- }
- /**
- * 字符串到枚举转换器
- */
- @Component
- public class StringToUserStatusConverter implements Converter<String, UserStatus> {
-
- @Override
- public UserStatus convert(String source) {
- if (source == null || source.trim().isEmpty()) {
- return null;
- }
-
- // 不区分大小写匹配
- for (UserStatus status : UserStatus.values()) {
- if (status.name().equalsIgnoreCase(source)) {
- return status;
- }
- }
-
- // 也支持中文描述匹配
- for (UserStatus status : UserStatus.values()) {
- if (status.getDescription().equals(source)) {
- return status;
- }
- }
-
- throw new IllegalArgumentException("无效的用户状态: " + source);
- }
- }
复制代码- @Configuration
- public class WebConfig implements WebMvcConfigurer {
-
- @Autowired
- private StringToDateConverter stringToDateConverter;
-
- @Autowired
- private StringToUserStatusConverter stringToUserStatusConverter;
-
- /**
- * 注册自定义转换器
- */
- @Override
- public void addFormatters(FormatterRegistry registry) {
- registry.addConverter(stringToDateConverter);
- registry.addConverter(stringToUserStatusConverter);
- }
- }
复制代码- @RestController
- @RequestMapping("/api/converter")
- public class ConverterController {
-
- /**
- * 使用自定义日期转换器
- * GET /api/converter/date?date=2023-10-25
- */
- @GetMapping("/date")
- public String handleDateParam(@RequestParam Date date) {
- // Spring会自动使用我们注册的StringToDateConverter
- SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
- return "转换后的日期: " + format.format(date);
- }
-
- /**
- * 使用自定义枚举转换器
- * GET /api/converter/status?status=ACTIVE
- * GET /api/converter/status?status=活跃
- */
- @GetMapping("/status")
- public String handleStatusParam(@RequestParam UserStatus status) {
- return "用户状态: " + status.getDescription();
- }
-
- /**
- * 在对象中使用自定义转换
- * GET /api/converter/user?name=张三&createTime=2023-10-25 14:30:00&status=INACTIVE
- */
- @GetMapping("/user")
- public String handleUserObject(UserQuery userQuery) {
- // UserQuery对象中包含Date和UserStatus属性
- return String.format("用户: %s, 创建时间: %s, 状态: %s",
- userQuery.getName(),
- userQuery.getCreateTime(),
- userQuery.getStatus().getDescription());
- }
- }
- /**
- * 用户查询对象(包含需要自定义转换的属性)
- */
- class UserQuery {
- private String name;
- private Date createTime; // 需要自定义转换
- private UserStatus status; // 需要自定义转换
-
- // getter/setter...
- public String getName() { return name; }
- public void setName(String name) { this.name = name; }
-
- public Date getCreateTime() { return createTime; }
- public void setCreateTime(Date createTime) { this.createTime = createTime; }
-
- public UserStatus getStatus() { return status; }
- public void setStatus(UserStatus status) { this.status = status; }
- }
复制代码 SpringMVC其它使用
视图解析器添加前后缀
配置视图解析器可以免去重复书写视图文件路径的前后缀。
-
- <bean id="jspViewResolver" >
- <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
- <property name="prefix" value="/views/"/>
- <property name="suffix" value=".jsp"/>
- </bean>
复制代码- @Configuration
- public class ViewConfig {
-
- @Bean
- public ViewResolver viewResolver() {
- InternalResourceViewResolver resolver = new InternalResourceViewResolver();
- // 设置所有视图文件所在的公共前缀
- resolver.setPrefix("/views/");
- // 设置视图文件的公共后缀
- resolver.setSuffix(".jsp");
- return resolver;
- }
- }
复制代码 此配置后,控制器返回的 "index"会被自动补全为 /views/index.jsp,极大简化了视图管理- @Controller
- public class HomeController {
-
- @RequestMapping("/home")
- public String home() {
- // 控制器中只需返回逻辑视图名 "index"
- // 视图解析器会自动拼接为 "/WEB-INF/views/index.jsp"
- return "index";
- }
- }
复制代码 中文乱码问题处理
- characterEncodingFilter org.springframework.web.filter.CharacterEncodingFilter<?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:mvc="http://www.springframework.org/schema/mvc"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/mvc
- http://www.springframework.org/schema/mvc/spring-mvc.xsd">
-
- <mvc:default-servlet-handler/>
-
-
- <mvc:annotation-driven/>
-
-
- <context:component-scan base-package="com.example.controller"/>
- </beans>encoding UTF-8
- <bean id="jspViewResolver" >
- <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
- <property name="prefix" value="/views/"/>
- <property name="suffix" value=".jsp"/>
- </bean> forceEncoding true characterEncodingFilter /*
复制代码 静态资源处理
默认情况下,DispatcherServlet 会拦截所有请求,包括静态资源请求,这会导致静态资源无法正常访问。因此,我们需要配置 Spring MVC 以允许容器直接提供静态资源。
有两种主要方式来处理静态资源:
- 使用 标签(XML 配置)
- 使用 WebMvcConfigurer的 addResourceHandlers方法(Java 配置)
另外,还可以使用 来允许容器默认的 Servlet 处理静态资源。
- XML 配置方式-使用默认Servlet处理(简单方式)
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:mvc="http://www.springframework.org/schema/mvc"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/mvc
- http://www.springframework.org/schema/mvc/spring-mvc.xsd">
-
- <mvc:default-servlet-handler/>
-
-
- <mvc:annotation-driven/>
-
-
- <context:component-scan base-package="com.example.controller"/>
- </beans>
复制代码-
- <bean id="jspViewResolver" >
- <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
- <property name="prefix" value="/views/"/>
- <property name="suffix" value=".jsp"/>
- </bean>
- <bean id="jspViewResolver" >
- <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
- <property name="prefix" value="/views/"/>
- <property name="suffix" value=".jsp"/>
- </bean>
复制代码- import org.springframework.context.annotation.Configuration;
- import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
- import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
- @Configuration
- public class WebMvcConfig implements WebMvcConfigurer {
-
- /**
- * 配置静态资源处理
- */
- @Override
- public void addResourceHandlers(ResourceHandlerRegistry registry) {
- // 1. 类路径下的静态资源
- registry.addResourceHandler("/static/**")
- .addResourceLocations("classpath:/static/")
- .setCachePeriod(3600); // 缓存1小时
-
- // 2. Web根目录下的资源
- registry.addResourceHandler("/css/**")
- .addResourceLocations("/css/");
-
- registry.addResourceHandler("/js/**")
- .addResourceLocations("/js/");
-
- registry.addResourceHandler("/images/**")
- .addResourceLocations("/images/");
-
- // 3. 外部文件系统资源
- registry.addResourceHandler("/uploads/**")
- .addResourceLocations("file:/var/uploads/");
-
- // 4. WebJars支持
- registry.addResourceHandler("/webjars/**")
- .addResourceLocations("classpath:/META-INF/resources/webjars/");
- }
- }
复制代码 来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |