springmvc注解的使用

Spring MVC 核心注解全解析:从基础到实战

Spring MVC 提供了丰富的注解体系,简化了请求映射、参数绑定、数据共享等核心功能的开发。从 “注解作用→核心属性→实战示例→注意事项” 四个维度,详细解析 @RequestMapping@PathVariable@RequestParam 等常用注解的使用方法与设计思想。

@RequestMapping:请求路径映射的核心注解

@RequestMapping 是 Spring MVC 中最基础的注解,用于将 HTTP 请求映射到 Controller 方法,可标注在类或方法上,实现细粒度的路径控制。

1. 核心作用

  • 类级别:定义当前 Controller 的基础路径(所有方法路径的前缀);
  • 方法级别:定义具体方法的映射路径(与类级别路径组合为完整路径)。

2. 核心属性

属性名 类型 作用描述 示例
value/path String[] 映射的 URL 路径(支持 Ant 表达式) @RequestMapping(path = "/user/list")
method RequestMethod[] 指定允许的 HTTP 请求方法(如 GET、POST) method = {RequestMethod.GET, RequestMethod.POST}
params String[] 限制请求必须包含指定参数(支持表达式) params = {"id", "name!=admin"}(必须有 id 参数,name 不能为 admin)
headers String[] 限制请求必须包含指定请求头 headers = "Content-Type=application/json"
consumes String[] 限制请求的 Content-Type 类型 consumes = "application/json"
produces String[] 限制响应的 Content-Type 类型 produces = "application/json;charset=UTF-8"

3. Ant 路径匹配规则

@RequestMappingpath 属性支持 Ant 风格的路径表达式,灵活匹配 URL:

通配符 含义 示例 匹配 URL 示例
* 匹配任意单个字符 /user/* /user/1/user/a(不匹配/user/1/2
** 匹配任意路径(含子路径) /user/** /user/1/user/1/2/user/a/b
? 匹配单个字符 /user/? /user/1/user/a(不匹配/user/12

4. 实战示例

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

// 类级别 @RequestMapping:基础路径为 /user
@Controller
@RequestMapping("/user")
public class UserController {

    // 1. 方法级别路径:完整路径为 /user/list(仅允许 GET 请求)
    @RequestMapping(path = "/list", method = RequestMethod.GET)
    @ResponseBody
    public String getUserList() {
        return "用户列表";
    }

    // 2. 支持 Ant 表达式:匹配 /user/1、/user/2 等
    @RequestMapping("/{id}")
    @ResponseBody
    public String getUserById() {
        return "查询单个用户";
    }

    // 3. 限制请求参数:必须包含 name 参数,且 age 不能为 0
    @RequestMapping(path = "/save", params = {"name", "age!=0"})
    @ResponseBody
    public String saveUser() {
        return "保存用户";
    }
}

5. 派生注解(推荐使用)

Spring 4.3+ 提供了 @RequestMapping 的派生注解,简化常用请求方法的配置:

派生注解 对应 HTTP 方法 等效于
@GetMapping GET @RequestMapping(method = RequestMethod.GET)
@PostMapping POST @RequestMapping(method = RequestMethod.POST)
@PutMapping PUT @RequestMapping(method = RequestMethod.PUT)
@DeleteMapping DELETE @RequestMapping(method = RequestMethod.DELETE)

示例

// 等效于 @RequestMapping(path = "/list", method = RequestMethod.GET)
@GetMapping("/list")
@ResponseBody
public String getUserList() {
    return "用户列表";
}

@PathVariable:REST 风格的 URL 参数绑定

@PathVariable 用于从 URL 路径中提取参数,适用于 RESTful 风格的 API 设计(如 /user/1 中的 1 表示用户 ID)。

1. 核心作用

将 URL 中的模板变量(如 {id})绑定到方法参数,实现路径参数的获取。

2. 核心属性

属性名 类型 作用描述
value String 模板变量名(与 URL 中的 {name} 对应)
required boolean 是否必填(默认 true,缺失会抛异常)

3. 实战示例

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/rest/user")
public class RestUserController {

    // 1. 单个路径参数:/rest/user/1 → id=1
    @GetMapping("/{id}")
    public String getUser(@PathVariable("id") Integer userId) {
        return "查询用户 ID:" + userId;
    }

    // 2. 多个路径参数:/rest/user/1/detail/info → id=1, type=info
    @GetMapping("/{id}/detail/{type}")
    public String getUserDetail(
            @PathVariable Integer id, // 变量名与 {id} 一致,可省略 value
            @PathVariable("type") String detailType) {
        return "用户 ID:" + id + ",详情类型:" + detailType;
    }

    // 3. 可选参数(required = false):/rest/user/optional 或 /rest/user/optional/123
    @GetMapping("/optional/{name:.+}") // .+ 匹配含小数点的字符串(如文件名)
    public String getOptionalParam(
            @PathVariable(required = false) String name) {
        return "可选参数:" + (name == null ? "未提供" : name);
    }
}

注意

  • 若路径参数包含特殊字符(如 ./),需通过正则表达式显式匹配(如 {name:.+} 匹配含 . 的字符串);
  • 参数名与路径变量名一致时,可省略 @PathVariablevalue 属性。

@RequestParam:请求参数绑定(查询字符串 / 表单)

@RequestParam 用于获取 HTTP 请求中的参数(包括 URL 查询字符串和表单提交的参数),适用于 ?id=1&name=张三 形式的参数。

1. 核心作用

将请求参数(键值对)绑定到方法参数,支持设置默认值、是否必填等。

2. 核心属性

属性名 类型 作用描述
value/name String 请求参数名(与前端传递的参数键对应)
required boolean 是否必填(默认 true,缺失会抛 MissingServletRequestParameterException
defaultValue String 默认值(若参数缺失则使用该值,required 自动变为 false

3. 实战示例

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/param")
public class ParamController {

    // 1. 基础用法:获取 ?id=1&name=张三
    @GetMapping("/user")
    public String getUser(
            @RequestParam("id") Integer userId,
            @RequestParam String name) { // 参数名与请求参数一致,可省略 value
        return "ID:" + userId + ",姓名:" + name;
    }

    // 2. 可选参数与默认值:?page=2 或 无page参数(默认1)
    @GetMapping("/list")
    public String getList(
            @RequestParam(defaultValue = "1") Integer page,
            @RequestParam(defaultValue = "10") Integer size) {
        return "第 " + page + " 页,每页 " + size + " 条";
    }

    // 3. 非必填参数:?keyword=java 或 无keyword参数(值为null)
    @GetMapping("/search")
    public String search(
            @RequestParam(required = false) String keyword) {
        return "搜索关键词:" + (keyword == null ? "无" : keyword);
    }
}

4. 与 @PathVariable 的区别

维度 @PathVariable @RequestParam
参数位置 URL 路径中(如 /user/{id} URL 查询字符串或表单(如 ?id=1
适用场景 RESTful API 路径参数 传统表单提交、查询参数
示例 /user/1 → 获取 id=1 /user?id=1 → 获取 id=1

@RequestHeader:获取请求头信息

@RequestHeader 用于获取 HTTP 请求头中的信息(如 User-AgentContent-TypeCookie 等)。

1. 核心作用

绑定请求头中的键值对到方法参数,常用于获取客户端信息、认证令牌等。

2. 核心属性

@RequestParam 一致:value(请求头名)、required(是否必填)、defaultValue(默认值)。

3. 实战示例

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/header")
public class HeaderController {

    @GetMapping("/info")
    public String getHeaderInfo(
            // 获取 User-Agent(客户端浏览器/设备信息)
            @RequestHeader("User-Agent") String userAgent,
            // 获取 Content-Type(请求体类型)
            @RequestHeader("Content-Type") String contentType,
            // 获取自定义请求头(如前端传递的 Token)
            @RequestHeader(value = "X-Token", required = false) String token) {
        
        return "User-Agent:" + userAgent + "\n" +
               "Content-Type:" + contentType + "\n" +
               "X-Token:" + (token == null ? "未传递" : token);
    }
}

@CookieValue 用于获取请求中携带的 Cookie 值(如 JSESSIONID、自定义 Cookie)。

1. 核心作用

直接绑定 Cookie 的值到方法参数,无需手动通过 HttpServletRequest 获取。

2. 核心属性

@RequestParam 一致:value(Cookie 名)、requireddefaultValue

3. 实战示例

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/cookie")
public class CookieController {

    @GetMapping("/info")
    public String getCookieInfo(
            // 获取 JSESSIONID(Tomcat 自动生成的会话 ID)
            @CookieValue("JSESSIONID") String sessionId,
            // 获取自定义 Cookie(如前端设置的 theme=dark)
            @CookieValue(value = "theme", defaultValue = "light") String theme) {
        
        return "JSESSIONID:" + sessionId + "\n" +
               "主题:" + theme;
    }
}

@SessionAttributes@SessionAttribute:会话域数据操作

这两个注解用于处理会话域(HttpSession)中的数据,实现跨请求的数据共享(如用户登录信息)。

1. @SessionAttributes:类级别,将模型数据存入 Session

  • 作用:标注在 Controller 类上,指定模型(Model)中的哪些属性需要同步到 HttpSession 中;
  • 核心属性value(属性名数组)、types(属性类型数组)。

2. @SessionAttribute:参数级别,从 Session 中获取数据

  • 作用:标注在方法参数上,从 HttpSession 中获取指定属性的值;
  • 核心属性value(Session 属性名)、required(是否必填)。

3. 实战示例

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.SessionAttribute;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;

// 类级别:将模型中 "userName" 和 "role" 属性存入 Session
@Controller
@RequestMapping("/session")
@SessionAttributes(value = {"userName", "role"})
public class SessionController {

    // 1. 向模型添加数据(会被 @SessionAttributes 同步到 Session)
    @GetMapping("/login")
    public String login(Model model) {
        model.addAttribute("userName", "张三"); // 存入 Model + Session
        model.addAttribute("role", "admin");   // 存入 Model + Session
        return "loginSuccess";
    }

    // 2. 从 Session 中获取数据(三种方式)
    @GetMapping("/info")
    public String getSessionInfo(
            Model model, // 方式1:从 Model 中获取(已同步 Session 数据)
            HttpSession session, // 方式2:通过 HttpSession 获取
            @SessionAttribute("userName") String userName, // 方式3:通过 @SessionAttribute 获取
            @SessionAttribute(value = "role", required = false) String role) {
        
        System.out.println("Model 中的 userName:" + model.getAttribute("userName")); // 张三
        System.out.println("HttpSession 中的 role:" + session.getAttribute("role")); // admin
        System.out.println("@SessionAttribute 获取的 userName:" + userName); // 张三
        
        return "sessionInfo";
    }

    // 3. 清除 @SessionAttributes 管理的 Session 数据
    @GetMapping("/logout")
    public String logout(SessionStatus status) {
        status.setComplete(); // 标记会话完成,清除 Session 中的属性
        return "logoutSuccess";
    }
}

注意

  • @SessionAttributes 仅作用于当前 Controller 及其子类;
  • 清除 Session 数据需通过 SessionStatus.setComplete(),而非 session.invalidate()(后者会销毁整个会话)。

@InitBinder:自定义数据绑定器

@InitBinder 用于注册自定义数据转换器或格式化器,解决 HTTP 请求参数到 Java 对象的类型转换问题(如字符串转日期、自定义枚举转换)。

1. 核心作用

@RequestMapping 方法执行前,初始化 WebDataBinder,注册转换器,实现参数的个性化转换。

2. 实战示例:日期格式化

import org.springframework.format.datetime.DateFormatter;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;

@RestController
@RequestMapping("/binder")
public class BinderController {

    // 1. 注册日期格式化器:将 "yyyy-MM-dd" 字符串转为 Date 对象
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        // 自定义日期格式
        binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
    }

    // 2. 接收 Date 参数(自动通过上面的格式化器转换)
    @GetMapping("/date")
    public String getDate(Date birthday) { // 请求参数:?birthday=2000-01-01
        return "生日:" + birthday.toLocaleString(); // 输出格式化后的日期
    }
}

扩展:自定义类型转换器(如字符串转枚举)

import org.springframework.core.convert.converter.Converter;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;

// 自定义转换器:String → GenderEnum(枚举)
enum GenderEnum {
    MALE, FEMALE;
}

class StringToGenderConverter implements Converter<String, GenderEnum> {
    @Override
    public GenderEnum convert(String source) {
        return "男".equals(source) ? GenderEnum.MALE : GenderEnum.FEMALE;
    }
}

@RestController
public class ConverterController {
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        // 注册自定义转换器
        binder.addConverter(new StringToGenderConverter());
    }

    @GetMapping("/gender")
    public String getGender(GenderEnum gender) { // 请求参数:?gender=男 → 转换为 MALE
        return "性别枚举:" + gender;
    }
}

@ModelAttribute:模型数据预置与参数绑定

@ModelAttribute 是多功能注解,可标注在方法参数上,分别用于 “预置模型数据” 和 “绑定请求参数到对象”。

1. 标注在方法上:预置模型数据

  • 作用:在当前 Controller 的所有 @RequestMapping 方法执行前执行,用于预置模型数据(如全局查询条件、用户信息);
  • 执行时机:优先于同 Controller 中的 @RequestMapping 方法。
示例:预置全局数据
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/model")
public class ModelAttributeController {

    // 1. 无返回值:手动添加数据到 Model
    @ModelAttribute
    public void preHandle(@RequestParam(required = false) String version, Model model) {
        model.addAttribute("systemVersion", version == null ? "1.0.0" : version);
    }

    // 2. 有返回值:自动将返回值添加到 Model(键名为返回值类型名首字母小写,如 User → "user")
    @ModelAttribute
    public User preUser() {
        return new User("默认用户", 20); // 自动存入 Model:key = "user"
    }

    // 3. 有返回值+指定键名:通过 @ModelAttribute("key") 指定模型键名
    @ModelAttribute("globalTime")
    public Long preTime() {
        return System.currentTimeMillis(); // 存入 Model:key = "globalTime"
    }

    // 4. 使用预置的模型数据
    @GetMapping("/info")
    public String getInfo(Model model) {
        return "系统版本:" + model.getAttribute("systemVersion") + "\n" +
               "默认用户:" + ((User) model.getAttribute("user")).getName() + "\n" +
               "时间戳:" + model.getAttribute("globalTime");
    }

    static class User {
        private String name;
        private Integer age;
        // 构造器、getter/setter
        public User(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
    }
}

2. 标注在参数上:绑定请求参数到对象

  • 作用:将请求参数自动绑定到 Java 对象(如表单提交的用户信息),并将该对象存入模型;
  • 核心属性value(模型中的键名,默认是对象类型名首字母小写)。
示例:表单参数绑定到对象
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/user")
public class UserFormController {

    // 接收表单参数:?name=张三&age=25 → 自动绑定到 User 对象
    @PostMapping("/save")
    public String saveUser(@ModelAttribute("user") User user) {
        // @ModelAttribute("user"):将 user 对象存入 Model,键名为 "user"
        return "保存用户:" + user.getName() + ",年龄:" + user.getAge();
    }

    static class User {
        private String name;
        private Integer age;
        // 无参构造器(必须,Spring 反射创建对象)、getter/setter
    }
}

注意

  • @ModelAttribute 标注的参数对象,会自动存入模型,视图可直接访问;
  • 若参数对象已通过 “方法级 @ModelAttribute” 预置,则直接复用该对象,而非新建。

注解优先级与使用场景总结

注解 核心场景 优先级 / 执行顺序
@RequestMapping 请求路径映射 类级别 → 方法级别
@PathVariable RESTful 路径参数 无(按参数顺序绑定)
@RequestParam 查询字符串 / 表单参数 无(按参数顺序绑定)
@InitBinder 数据绑定器初始化 先于 @RequestMapping 方法执行
@ModelAttribute 方法级:预置模型数据;参数级:绑定对象 方法级 @ModelAttribute@InitBinder@RequestMapping 方法 → 参数级 @ModelAttribute
@SessionAttributes 模型数据同步到 Session 类级别,作用于所有方法

最佳实践

  1. 路径映射:优先使用 @GetMapping@PostMapping 等派生注解,简化代码;
  2. 参数获取:REST 风格用 @PathVariable,查询 / 表单参数用 @RequestParam
  3. 数据共享:跨请求数据用 @SessionAttributes + @SessionAttribute,单次请求用 Model;
  4. 数据绑定:复杂类型转换用 @InitBinder 注册转换器,表单对象用 @ModelAttribute 绑定;
  5. 全局处理:全局数据预置用 @ControllerAdvice + @ModelAttribute,全局异常用 @ControllerAdvice + @ExceptionHandler