less SSM

"成为J佬的一天"

Posted by HZY on December 13, 2025

写在前面

对于SSM的很多知识点,我们只是过了一遍而已,学习远远不仅于此,所以本篇文章将记载作者使用过的所有功能,每次使用一次功能,都会在这里详细记载

Spring基于注解+配置类开发

@Bean
  • bean的id的作用,也就是在
  • @Scope标注作用域
  • @PreDestory
  • @PostConstruct
  • @Bean(initMethod = "init", destroyMethod = "destroy")
    • 这里详细说一下这个@Bean,假设我们想要引入外部的类,那么我们要么找到这个类,在它头上标注@Component,要么我们就用@Bean在配置类中把它加入组件。

    • 对于这个initMethod,destoryMethod,它俩和@PreDestory@PostConstruct本质上没什么区别,实际上就是用法的区别,前者是后期@Bean指定,而后者则是侵入性的;前者是Spring框架的,后者是JSR标准,泛用性不同

      @Component

      创建组件的方法

  • @Service
  • @Controller
  • @Reposity

  • @PreDestory
  • @PostConstruc

    这些注解就是完成不同类型的组件的创建,声明要把哪些组件放入容器

    @Bean 与 @Component

    其实有很多人搞不清楚这两个的概念,实际上二者都作为组件,本身来说没有什么差别,都有各种各样的方法等等。。。

场景 推荐
自己写的 Bean @PostConstruct / @PreDestroy
第三方类 @Bean(initMethod, destroyMethod)
线程池 / MQ @PreDestroy
数据源 通常不需要
@Import

在很多情况,我们不方便用,也不适合用@Component和@Bean,比如我们要从外部的包里面导入一个组件,但我们肯定不想侵入这个类,这时候我们就2使用Import导入

注解 核心角色 解决什么问题
@Component 声明组件 “这是一个 Spring 管理的业务组件”
@Bean 定义对象 “这个对象由我来创建和配置”
@Import 引入配置 “把别人定义的一整套 Bean 引进来”
@Configuration

方便我们统一进行@Bean,方便对同类型Bean的管理,也可以进行一些其他的配置操作

  • @ComponentScan("{}")
  • PropertyScan("")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Configuration
@ComponentScan(basePackages = "com.atguigu")
@PropertySource("classpath:jdbc.properties")
public class JavaConfig {

    @Value("${atguigu.url}")
    private String url;
    @Value("${atguigu.driver}")
    private String driver;
    @Value("${atguigu.username}")
    private String username;
    @Value("${atguigu.password}")
    private String password;

    @Bean(destroyMethod = "close")
    public DruidDataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driver);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }

    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

}
@Scope

首先需要明白,bean或者component都是组件,所以@Scope不存在只能谁用的概念

Scope 含义 常见场景
singleton(默认) 容器唯一 Service / DAO
prototype 每次新建 临时上下文
request 每次 HTTP 请求 Web 请求数据
session 每个 Session 登录态
application ServletContext 级 全局共享
自定义 自己实现 高级场景

什么时候要使用prototype呢?遇到并发的时候,一个TaskContext可能同时被两个线程调用,这样可能导致数据混乱,所以要使用prototype

Spring 不做的事情

  • ❌ 不跟踪这个 Bean
  • ❌ 不管理生命周期结束
  • ❌ 不调用@PreDestroy
  • ❌ 不调用destroyMethod

Sping做的事情

  1. new 实例
  2. 依赖注入
  3. 调用 @PostConstruct
  4. 调用 initMethod(如果有)
  5. 把对象交给你
@Conditional

决定是否要加入为Bean的注解,常在加入Bean时进行Conditional判断

@Autowired

自动注入,自动注入的时候会遇到需要指定的情况,比如不知道要注入给哪个实例。 这时候可以使用@Qualifier@Primary进行指定

  • 普通方法注入方式(Spring推荐)
  • setter方法注入
@Value

上面刚才说了很多关于Bean注入的方法,但是对于一些值,比如我们要给实例的属性注入值,这时候就需要用到@Value注解了。

注意事项:

  • 要先加入资源@PropertySource
  • 允许@Value(“#{表达式}”)
  • 允许@Value(“#{方法/…}”)
    数据源配置

    之前我们使用的是@Profile方法配置,其实我们可以直接使用配置文件进行配置

  • 创建三个配置文件(不要乱放,spring默认是config文件夹)
  • 在application.properties 中调用就行
  • spring.profiles.active=prod
    生命周期

AOP

SpringMVC

  • http默认访问80,https访问443
  • 要不要在MyConfig配置类 implements WebMvcConfigurer
    • 如果你选择实现接口,那么你可以重写方法,自定义MVC的一些规则
    • 如果你不实现接口,使用默认处理方法
    • @EnableWebMvc千万不要随便加,这会取消所有默认MVC处理方法
      注解使用
  • Controller+@ResponseBody = @RestController
  • @RequestMapping("/")标注路径
  • GetMapping("") @PostMapping("")
    swagger的使用
  • 访问knife4j
  • 导入依赖
  • 添加配置文件,
  • 访问/doc.html

在我们配置全局异常处理器的时候,只要涉及到ControllerAdvice,这个knife4j就会炸,这不是我们的问题,换软件吧

跨域问题

跨域问题到底在保护谁? 保护你自己!假设这样一个场景, 你访问了一个恶意网站,这个网站向向中国银行服务器发送请求,请求链路恶意网站->浏览器->中国银行 如果跨域请求没有被禁止,这个返回值就会给恶意网站,网站就可以拿到一些东西

1
2
3
4
5
6
7
@CrossOrigin(
    origins = "http://localhost:5173",
    methods = {RequestMethod.GET, RequestMethod.POST},
    allowedHeaders = "*",
    allowCredentials = "true",
    maxAge = 3600
)
参数 作用
origins 允许的前端域
methods 允许的 HTTP 方法
allowedHeaders 允许的请求头
exposedHeaders 前端可读取的响应头
allowCredentials 是否允许携带 cookie
maxAge 预检缓存时间(秒)
状态码与返回值

返回json总是没有一个标准是不舒服的,所有我们封装Result类,提供返回值包装方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
@Getter
public class Result<T> {
    private int code;
    private String msg;
    private T data;
    private Result(int code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
    private Result(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    private Result(ResultCode resultCode,T data) {
        this.code = resultCode.getCode();
        this.msg = resultCode.getMsg();
        this.data = data;
    }

    public static <T> Result<T> make(ResultCode resultCode,T data) {
        return new Result<T>(resultCode,data);
    }

    public static <T> Result<T> ok(T data) {
        return make(ResultCode.SUCCESS,data);
    }
    public static <T> Result<T> fail( ) {
        return make(ResultCode.FAIL,null);
    }
    public static <T> Result<T> fail(String msg) {
        return new Result<T>(500,msg,null );
    }

    public static <T> Result<T> fail(int code,String msg) {
        return new Result<T>(code,msg,null );
    }
}


@Getter
public enum ResultCode {
    SUCCESS(200, "success"),
    FAIL(500, "fail");

    private int code;
    private String msg;
    private ResultCode(int code, String msg) {
         this.code = code;
         this.msg = msg;
    }

}
全局统一异常处理

我们每次遇到错误,本来都是try-catch之后自己吃了,return一个fail。 这样不够爽,我们以后遇见错误,我们就直接抛出异常,我看参数不够,我就抛出异常,我看你不爽就抛出异常 由全局异常处理器捕获(主要是运行中异常)异常,然后return fail()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(BusinessException.class)
    public Result<?> handleBusinessException(BusinessException e) {
        e.printStackTrace();
        return Result.fail(e.getCode(), e.getMessage());
    }

    //这样处理有点不负责任
    @ExceptionHandler(Exception.class)
    public Result<?> handleException(Exception e) {
        e.printStackTrace();
        return Result.fail(e.getMessage());
    }
}


@Getter
public class BusinessException extends RuntimeException {

    private final int code;


    public BusinessException(int code, String msg) {
        super(msg);
        this.code = code;
    }

}

MyBatis

PageHelper

配置方法有三种“

  • PageHelper 不推荐过时了
  • PageInterceptor 推荐(如果使用这种方式,不再需要把PageHelper添加为Bean)
  • xml直接配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
      @Bean
      public PageInterceptor pageInterceptor() {
          final PageInterceptor pageInterceptor = new PageInterceptor();
          Properties props = new Properties();
          props.setProperty("helperDialect", "mysql");
          props.setProperty("reasonable", "true");
          pageInterceptor.setProperties(props);
          return pageInterceptor;
      }
    
      @GetMapping
      Result<PageInfo<AlertInfo>> alertInfoListPage(
              @RequestParam(defaultValue = "1") int begin,
              @RequestParam(defaultValue = "20") int size) {
          PageHelper.startPage(begin, size);
          List<AlertInfo> list = alterInfoService.getAllAlterInfo();
          PageInfo<AlertInfo> pageInfo = new PageInfo<>(list);
          //这里的list转pageinfo很舒适,记得泛型写T就行
          return Result.ok(pageInfo);
      }