写在前面
对于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做的事情
- new 实例
- 依赖注入
- 调用 @PostConstruct
- 调用 initMethod(如果有)
- 把对象交给你
@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); }