Spring 注解汇总

# SpringBoot简介

SSM=Spring+SpringMVC+Mybatis

传统Spring开发缺点:

1. 导入依赖繁琐
2. 项目配置繁琐

Spring Boot是全新框架(更像是一个工具,脚手架),是Spring提供的一个子项目,用于快速构建Spring应用程序。

随着Spring 3.0的发布,Spring 团队逐渐开始摆脱XML配置文件,并且在开发过程中大量使用“约定优先配置”(convention over configuration)的思想来摆脱Spring框架中各类繁复纷杂的配置。

SpringBoot的特性:

  1. 起步依赖 jar包的管理 starter
  2. 自动配置 AutoConfiguration
  3. 内置tomcat

springboot 4.0一下要选择 spring boot dev toos 和springboot web 才会有resources文件夹

三层架构

image-20260805084905395

1. Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。
2. Service:业务逻辑层。处理具体的业务逻辑。
3. Dao:数据访问层(Data Access Object),也称为持久层。负责数据访问操作,包括数据的增、删、改、查。

执行流程:

1. 前端发起的请求,由Controller层接收(Controller响应数据给前端)
2. Controller层调用Service层来进行逻辑处理(Service层处理完后,把处理结果返回给Controller层)
3. Serivce层调用Dao层(逻辑处理过程中需要用到的一些数据要从Dao层获取)
4. Dao层操作文件中的数据(Dao拿到的数据会返回给Service层)

IOC、DI

控制反转(Inversion on Control)IOC:对象的创建交给外部容器来完成(这里就是交给Spring容器),这就叫控制反转。

IOC:Spring就是一个大的内存容器(一块内存区域),三层架构里面上一层不需要再去new下一层对象,在上一层只需要写下一层的接口,new对象由Spring容器帮我们完成,各层直接向Spring容器要对象就可以。

class StudentController{ // 需要什么,就去创建什么(自己去new),这就叫“控制正转”(通俗一点就是自己控制new哪个对象) private IStudentService studentService = new StudentServiceImpl(); }

依赖注入:Dependency injection (DI)

现在new这个对象不是由自己new,是由Spring容器帮我们new对象,现在要得到这个Spring容器new出来的对象,就要“依赖”Spring容器,“注入”Spring容器new出来的对象。

IOC和DI区别:

IOC:解决对象创建的问题(对象的创建交给别人)Inversion of Control。

DI:在创建完对象后,对象关系的处理就是依赖注入(通过set方法实现依赖注入)Dependency injection。

先有IOC(对象创建),再有DI(处理对象关系)

在三层架构中最终实现的效果是:在Controller不会出现Service层具体的实现类代码,只会看到Service层接口,Service层也不会出现Dao层具体实现类的代码,也只会看到Dao层的接口。IOC:解决对象创建的问题(对象的创建交给别人)Inversion of Control。

DI:在创建完对象后,对象关系的处理就是依赖注入(通过set方法实现依赖注入)Dependency injection。

先有IOC(对象创建),再有DI(处理对象关系)

在三层架构中最终实现的效果是:在Controller不会出现Service层具体的实现类代码,只会看到Service层接口,Service层也不会出现Dao层具体实现类的代码,也只会看到Dao层的接口。

Spring 注解汇总

Spring 核心常用注解

核心重点:覆盖 Bean 的实例化注册、依赖注入、容器配置三类核心注解。

注解 说明
@Component 通用组件注解,标注在类上,将该类实例化为 Bean 并交给 Spring 容器管理
@Controller 标注在控制层类上,是 @Component 的衍生注解,用于标识表现层 Bean
@Service 标注在业务层类上,是 @Component 的衍生注解,用于标识业务层 Bean
@Repository 标注在数据访问层(DAO/Mapper)类上,是 @Component 的衍生注解,用于标识持久层 Bean
@Autowired 标注在字段/构造器/setter 方法上,默认按类型(byType)完成依赖注入
@Qualifier 必须配合 @Autowired 使用,当容器存在多个同类型 Bean 时,按名称(byName)指定注入的 Bean
@Scope 标注 Bean 的作用范围,默认值为 singleton(单例),可选 prototype(多例)、request、session 等
@Configuration 标注在类上,声明当前类为 Spring 配置类,替代 XML 配置文件,容器启动时会加载该类中的配置
@ComponentScan 指定 Spring 容器初始化时扫描的包路径,自动扫描包下带组件注解的类并注册为 Bean
@Bean 标注在方法上,将方法的返回值对象存入 Spring IOC 容器,常用于将第三方类注册为 Bean
@Import 用于导入其他配置类或普通类,被导入的类会自动被 Spring 加载并注册为 Bean
@Aspect / @Before / @After / @Around / @Pointcut 用于 AOP 切面编程,分别标识切面类、前置通知、后置通知、环绕通知、切点表达式

SpringMVC 常用注解

核心重点:覆盖请求路径映射、参数接收、数据响应相关注解。

注解 说明
@RequestMapping 请求路径映射注解,可标注在类和方法上;标注在类上时,类中所有方法共享该父路径
@GetMapping GET 请求专用映射注解,等价于 @RequestMapping(method = RequestMethod.GET)
@PostMapping POST 请求专用映射注解,等价于 @RequestMapping(method = RequestMethod.POST)
@RequestBody 接收 HTTP 请求中的 JSON 数据,自动将 JSON 转换为 Java 实体对象
@RequestParam 指定请求参数名称,适用于前后端参数名不一致的场景,也可设置参数默认值、是否必传
@PathVariable 从 REST 风格 URL 的占位符中获取参数,例如 /user/{id} 路径中的 id
@ResponseBody 将 Controller 方法的返回对象转换为 JSON 格式,响应给客户端
@RequestHeader 获取请求头中指定名称的数据,注入到控制器方法参数中
@RestController 组合注解,等价于 @Controller + @ResponseBody,标注在类上时,类中所有方法都返回 JSON
@CookieValue 将指定名称的 Cookie 值,注入到控制器方法的参数中

SpringBoot 常用注解

核心重点:启动类、自动配置核心注解。

注解 说明
@SpringBootApplication SpringBoot 项目启动类核心注解,标注在启动类上,是一个组合注解
@SpringBootConfiguration 等价于 @Configuration,用于标识 SpringBoot 的主配置类
@EnableAutoConfiguration 开启 SpringBoot 自动配置功能,也可通过属性排除指定的自动配置类
@ComponentScan 组件扫描注解,默认扫描启动类所在包及其子包下的所有组件

补充:@ComponentScan 是 Spring 注解还是 SpringBoot 注解?

spring MVC

@ComponentScan 本质是 Spring 框架原生注解,并非 SpringBoot 独有。

  1. 原生 Spring 中,它的作用是指定包扫描路径,自动识别 @Component、@Service、@Repository、@Controller 等注解的类,并注册为 Spring Bean。
  2. 在 SpringBoot 中,它被整合进了启动注解 @SpringBootApplication 中。@SpringBootApplication 本质是 @Configuration + @EnableAutoConfiguration + @ComponentScan 三个注解的组合。
  3. 结论:它是 Spring 原生注解,在 SpringBoot 中被默认集成使用,无需手动声明也能生效,也可以手动配置自定义扫描路径。

image-20260805191859035

MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式。这种模式用于应用程序的分层开发。

1. Model(模型) – 模型代表一个存取数据的对象或 JAVA POJO。它也可以带有逻辑,在数据变化时更新控制器。
2. View(视图) – 界面设计人员进行图形界面设计。
3. Controller(控制器) – 负责转发请求,对请求进行处理。

POJO(Plain Ordinary Java Object)简单的Java对象

JavaBean:一种规范,表达实体和信息的规范,便于封装重用

1. 所有属性为private
2. 提供默认无参构造方法
3. 提供getter和setter
4. 实现serializable接口

@RequestMapping("/selectAll")
public String selectAll(Model model) {
    System.out.println("StudentController.selectAll");
    List<Student> list = studentService.selectAll();
    model.addAttribute("list", list);
    return "student_list";
}

thymeleaf使用

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org/">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--<link rel="stylesheet" type="text/css" th:href="@{/static/bootstrap-3.4.1-dist/css/bootstrap.css}"/>-->
    <link rel="stylesheet" type="text/css" href="/static/bootstrap-3.4.1-dist/css/bootstrap.css"/>
</head>
<body>
    <table class="table table-bordered table-condensed table-hover table-striped">
      <tr>
        <td>编号</td>
        <td>姓名</td>
        <td>年龄</td>
        <td>性别</td>
      </tr>
      <tr th:each="student:${list}">
        <td th:text="${student.id}"></td>
        <td th:text="${student.name}"></td>
        <td th:text="${student.age}"></td>
        <td th:text="${student.gender}"></td>
      </tr>
    </table>
</body>
</html>

登录、转发、重定向、Get、Post

转发和重定向

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/toLogin")
    public String toLogin() {
        return "login";
    }

    @RequestMapping("/login")
    public String login(String name, String password, Model model) {
        User user = userService.login(name, password);
        if (ObjectUtils.isEmpty(user)) {
            model.addAttribute("errorMsg", "用户名或密码错误");
            return "login";
        }
        
        return "redirect:/student/selectAll";
    }
}

不需要加@ResponseBody 会使return变为json格式不是转发

Http Get和Post请求的区别?

GET 和 POST 是 HTTP 协议中两种常用的请求方法,它们在不同的场景和目的下有不同的特点和用法。

1. 语义上的区别:GET 通常用于查询资源,而 POST 通常用于创建。
2. 格式上的区别:GET 请求的参数通常放在 URL 中,形成查询字符串(querystring),用?形式拼接在地址栏后面,而 POST 请求的参数通常放在请求体(body)中,GET 请求的 URL 长度受到浏览器的限制,而 POST 请求的 body 大小则没有明确的限制。

1. 安全性上的区别:GET 请求和 POST 请求都不是绝对安全的,因为 HTTP 协议本身是明文传输的,无论是 URL、请求体(body)中都可能被窃取或篡改。为了保证安全性,必须使用 HTTPS 协议来加密传输数据。不过,在一些场景下,GET 请求相比 POST 请求更容易泄露敏感数据,因为 GET 请求的参数会出现在 URL 中。

Cookie、Session

会话技术分为:Cookie和Session

  1. Cookie:数据存储在浏览器客户端本地,减少服务器端的存储的压力,安全性不好,客户端可以清除cookie
  2. Session:将数据存储到服务器端,安全性相对好,增加服务器的压力

Session与Cookie的区别

对比项 Cookie Session
存储位置 ✅ 客户端(浏览器) ✅ 服务器端
保存数据 键值对,只能存字符串,小体积(4KB以内) 键值对,值可以存储对象,容量大
数据安全性 ❌ 容易被查看/篡改(保存在用户机器) ✅ 更安全,保存在服务器
生命周期 可设置过期时间,默认浏览器关闭失效 服务器关闭或超时失效(如30分钟)
是否占用服务器资源 ❌ 不占用 ✅ 占用(每个用户一个 Session)
典型使用场景 记住用户名、自动登录、广告跟踪 用户登录状态、权限控制

Cookie:数据存在客户端,不安全但节省服务器资源;

Session:数据存在服务器,更安全但占内存,需要通过 Cookie 维持连接。

@RequestMapping("/setCookie")
public void setCookie(HttpServletResponse response) {
    Cookie cookie = new Cookie("goods", "IPhone");
    // Cookie有效路径,表示这个 Cookie 对当前域名下所有 URL 路径生效,是登录认证 Cookie 最常用的设置。
    cookie.setPath("/");
    // 有效时间(秒)
    cookie.setMaxAge(60 * 60);
    response.addCookie(cookie);
}

@RequestMapping("/getCookie1")
@ResponseBody
public String getCookie1(HttpServletRequest request) {
    Cookie[] cookies = request.getCookies();
    for (Cookie cookie : cookies) {
        System.out.println(cookie.getName() + ":" + cookie.getValue());
    }
    return "ok";
}

//更简洁的写法
@RequestMapping("/getCookie2")
@ResponseBody
public String getCookie2(@CookieValue("goods") String goods) {
    System.out.println(goods);
    return "ok";
}


存储到seesion中
@RequestMapping("/login")
public String login(String name, String password, Model model, HttpSession session) {
    System.out.println("UserController.login");
    User user = userService.login(name, password);
    if (ObjectUtils.isEmpty(user)) {
        model.addAttribute("errorMsg", "用户名或密码错误");
        return "login";
    }

    session.setAttribute("user", user);
    return "redirect:/student/selectAll";
}

登录拦截器


//拦截器的作用:浏览器访问服务器的请求,都要首先经过拦截器
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        
        //1.判断用户有没有登录
        //2.如果登录了,就放行,可以访问后台的资源
        //3.如果没有登录,跳转到登录界面
        HttpSession session = request.getSession();
        User user = (User) session.getAttribute("user");
        if (user == null) {
            //没有登录,跳转到登录界面
            response.sendRedirect("/user/toLogin");
            return false;
        }

        //已经登录,放行
        return true;
    }
}

拦截器配置 WebMvcConfigurer提供了配置SpringMVC底层的所有组件入口

// @Component    <bean>
// @Controller  @Service @Repository
// 这四个注解的作用是一样的,下面三个不一样主要是为了区分不同层

// @Configuration用于定义配置类,可以替换xml配置文件,
// 加了这个注解的类的内部包含一个或多个被@Bean注解的方法
@Configuration
public class WebConfig implements WebMvcConfigurer {

    /* <bean name="student" class="com.situ.springboot.pojo.Student"/>*/
    @Bean
    public Student createStudent() {
        return new Student();
    }

    /*<!-- 配置拦截器 -->
   <mvc:interceptors>
      <mvc:interceptor>
         <mvc:mapping path="/**"/>
         <mvc:exclude-mapping path=""/>
         <bean class="com.situ.mvc.interceptor.MyInterceptor1"></bean>
      </mvc:interceptor>
   </mvc:interceptors>*/
    // 这个方法用来注册拦截器,我们写的拦截器需要在这里配置才能生效
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //把登录的拦截器配置上才能起作用
        // addPathPatterns("/**") 拦截器拦截所有的请求,静态资源也拦截了,需要放行
        // excludePathPatterns 代表哪些请求不需要拦截
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/user/toLogin", "/user/login", "/user/logout", "/static/**");
    }
}

axios

最大特点:异步请求,不刷新整个页面,只刷新局部也叫局部刷新。

image-20260807091216768

案例使用

<form id="loginForm">
    <label for="name">用户名</label>
    <input type="text" id="name" name="name"
           placeholder="请输入用户名" required autofocus/>
    <br>
    <label for="password">密码</label>
    <input type="password" id="password" name="password"
           placeholder="请输入密码" required/>
    <br>
    <input type="submit" value="登录"/>
</form>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
    document.getElementById('loginForm').addEventListener('submit', function (event) {
        //是 JavaScript 中用于阻止浏览器默认行为的核心方法。阻止表单自动提交与页面刷新
        event.preventDefault();
        let name = document.getElementById('name').value;
        let password = document.getElementById('password').value;
        //方式一:
        //let params = new URLSearchParams();
        //params.append("name", name);
        //params.append("password", password);
        //方式二:
        let params = {
            name: name,
            password: password
        }
        axios.post('/user/login', params).then(function (resp) {
            let result = resp.data;
            console.log(result);
            if (result.code == 1) {
                alert(result.msg);
                location.href = '/student/selectAll';
            } else {
                alert(result.msg);
            }
        }).catch(function (error) {
            alert('请求失败,请稍后重试');
        });
    });
</script>

请求方式

1. axios.get(url[, config]) 查找
2. axios.delete(url[, config]) 删除
3. axios.post(url[, data[, config]]) 添加
4. axios.put(url[, data[, config]]) 更新

get和delect中没有data 传值时 要axios.delete('/student/delectById',{params:{id:id}}).then(function(resp){--}用config包裹这params来传递数据

四种都可以拼接axios.delete("/teacher/deleteById?id=5")

location.href = '/student/selectAll1'; 返回值为get类型

data 是请求体(body),但 body 是什么格式,取决于你传的数据类型:

x-www-form-urlencoded json
来源 HTML 表单默认就是这格式 前后端分离 / RESTful API 主流
前端产生 new URLSearchParams() 后 append 直接传js普通对象,axios 自动 JSON.stringify
格式 键值对,& 分隔,= 连接 name=zhangsan&age=23 JSON 结构{“name”:”zhangsan”,”age”:23,”gender”:”男”}
Spring 接收 参数绑定 / 对象绑定 必须 @RequestBody

Axios 的 config 理解成请求配置对象,里面放的是请求控制信息:

{    params: {},       // URL参数   
     headers: {},      // 请求头   
     timeout: 5000,    // 超时
}
async function login() {
  const url = '/api/user/login'
  const data = { username: 'admin', password: '123456' }
  // 第三段 config 配置
  const config = {
    timeout: 10000, // 超时10秒
    headers: {
      'token': localStorage.getItem('token'), // 携带登录令牌
      'Content-Type': 'application/json'
    }
  }

  const res = await axios.post(url, data, config)
  console.log(res.data)
}

后端 → 前端(后端把数据传给页面)

1. Model 传值(单次请求有效,转发可用、重定向失效)

底层数据存放于 request 请求域,一次请求生命周期内生效。

@GetMapping("/list")
public String list(Model model){
    model.addAttribute("userName","管理员");
    model.addAttribute("userList", userList);
    return "user/list";
}

页面取值:

<html lang="en" xmlns:th="http://www.thymeleaf.org/">
 

<table class="table table-striped table-bordered table-hover table-condensed">
    <tr>
        <td>ID</td>
        <td>名字</td>
        <td>年龄</td>
        <td>性别</td>
        <td>操作</td>
        <td>添加</td>

    </tr>
    <tr th:each="student:${students}">
        <td th:text="${student.id}">1</td>
        <td th:text="${student.name}">zhangsan</td>
        <td th:text="${student.age}">23</td>
        <td th:text="${student.gender}">23</td>
        <td><button class="btn btn-danger btn-sm" th:onclick="|delectById(${student.id})|">删除</button></td>

        <td><button  class="btn btn-success btn-sm"  th:onclick="|update(${student.id})|">修改</button></td>
    </tr>
</table>


    
    

特点:

  • 仅转发页面可以拿到数据;return redirect:/xxx 重定向会丢失 Model 数据;
  • 适合列表渲染、表单回填。

2. Session 传值(会话级别,浏览器不关闭就一直存在)

数据存入 session域,整个会话所有页面均可读取。

// 方式1:注入HttpSession
@GetMapping("/login")
public String login(HttpSession session){
    session.setAttribute("loginUser","张三");
    return "index";
}
// 方式2:Model自动存入session
model.addAttribute("loginUser","张三").setSessionAttributes("loginUser");

页面取值:

<span th:text="${session.loginUser}"></span>

适用场景:存放登录用户、全局登录状态。

二者核心区别

载体 生命周期 重定向能否保留数据
Model(request) 一次请求结束销毁 ❌ 重定向丢失
Session 浏览器会话期间有效 ✅ 任意页面均可读取

前端 → 后端(页面把数据传给后端)

方式1:原生 Form 表单提交(同步提交,页面刷新)

① 普通表单(能正常传参)

表单 name 属性和后端实体字段一致即可接收参数:

<form th:action="@{/user/add}" method="post">
    <input name="username">
    <input name="age">
    <button type="submit">提交</button>
</form>

后端接收:

// 等价默认 @ModelAttribute,接收表单参数
@PostMapping("/user/add")
public String add(User user){}

② 阻止默认提交

正确阻止默认提交后依然可以传参:

<form id="form">
    <input name="username" id="username">
    <button onclick="submitForm()">提交</button>
</form>
<script>
function submitForm(event){
    // 阻止表单默认刷新提交
    event.preventDefault();
    // 方式A:序列化表单参数传给后端
    let formData = new FormData(document.getElementById('form'));
    axios.post('/user/add', formData).then(res=>{})
}
</script>

拦截表单只是阻止浏览器原生同步跳转,依旧可以拿到表单数据异步提交。

方式2:Axios 异步提交(主流,页面不刷新)

分为两种传参格式:

  1. JSON格式(后端搭配 @RequestBody)

  1. 表单键值对(后端搭配 @ModelAttribute)
axios.post('/user/add',`username=张三&age=18`,{
    headers:{'Content-Type':'application/x-www-form-urlencoded'}
})

两种URL传参方式

URL拼接参数(查询参数)

地址样式:/delete?id=1&name=dxk 前端参数拼接在 ? 后面,使用 & 分隔多个参数,后端使用 @RequestParam 接收。

前端写法

<!-- 超链接 -->
<a th:href="@{/delete?id=1}">删除</a>

<!-- axios 发送 -->
axios.get('/delete?id=1')
// 等价写法
axios.get('/delete', { params: { id: 1 } })

后端接收

// 写法1:参数名和前端参数名一致
@GetMapping("/delete")
public String delete(@RequestParam Integer id) {
    System.out.println(id);
    return "redirect:/list";
}

// 写法2:参数名不一致,指定name映射
@GetMapping("/delete")
public String delete(@RequestParam(name = "id") Integer uid) {
    return "redirect:/list";
}

// 写法3:非必传参数,设置required=false
@GetMapping("/delete")
public String delete(@RequestParam(value = "id", required = false) Integer id) {
    return "redirect:/list";
}

特点

  1. 参数暴露在URL中,适合传递简单非敏感参数;
  2. 参数顺序无要求;
  3. 参数可以省略(配置 required=false)。

REST风格路径参数

地址样式:/user/1、/user/1/edit 参数拼接在URL路径中,后端使用 @PathVariable 绑定路径占位符。

前端写法

<a th:href="@{/user/1}">查看用户</a>

axios.get('/user/1')

后端接收

// 写法1:占位符名称与形参名称一致
@GetMapping("/user/{id}")
public String getUser(@PathVariable Integer id) {
    System.out.println(id);
    return "detail";
}

// 写法2:名称不一致,手动绑定
@GetMapping("/user/{uid}")
public String getUser(@PathVariable("uid") Integer id) {
    return "detail";
}

// 多路径参数示例
@GetMapping("/user/{id}/{name}")
public String getUser(@PathVariable Integer id, @PathVariable String name) {
    return "detail";
}

特点

  1. URL风格简洁,符合REST规范;
  2. 路径占位符必须传值,不能省略;
  3. 常用于详情、删除接口:/delete/5。

对比表格

方式 地址格式 注解 是否可缺省参数 适用场景
查询参数 /delete?id=1 @RequestParam 可以(required=false) 筛选、分页、模糊查询
路径参数 /delete/1 @PathVariable 不可省略 详情、删除、REST接口

混合使用示例

同时存在路径参数 + 查询参数 地址:/user/1?type=edit

@GetMapping("/user/{id}")
public void test(@PathVariable Integer id, @RequestParam String type){
    // id = 1,type = edit
}

RequestParam和RequestBody

对比项 @RequestParam @RequestBody
参数位置 URL 查询串 ?id=1 请求体 Body
支持请求方式 GET/POST/PUT/DELETE 全都支持 仅 POST、PUT、DELETE(GET 无 body,不能用)
数据格式 key=value&key=value JSON 对象
Content-Type application/x-www-form-urlencoded、普通 URL 参数 application/json
能否接收对象 可以,但需要实体属性和参数名一一对应 直接完整映射实体类,最适合传完整对象
典型场景 分页、删除、根据 ID 查询、筛选 新增、修改,传递完整表单对象
上一篇
下一篇