核心
idea配置热重启服务器
- pom.xml添加
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency>
- 组合键Ctrl+Shift+Alt+/,选择Registry,勾选complier.automake.allow.when.app.running
- File-Settings-Compiler-Build Project automatically
开闭原则 OCP 扩展开放 修改封闭
面向抽象编程实现可维护代码
面向对象主要做两件事:实例化对象
和调用方法
解决方法 | 优缺点 |
---|---|
inteface接口 | 统一方法的调用不能统一对象的实例化 |
工厂模式 | 不稳定是常态,把不稳定的代码隔离在一起,保证其他代码是稳定的 简单普通抽象工厂 |
IOC/DI | 当处理不稳定的代码非常强大,我们就认为这个容器是稳定的.我们向工厂要依赖对象,容器直接给我们一个对象通过反射实现任意类的实例化 |
View层常用注解
@Lazy延迟注入
@ResponseBody 将JavaBean对象序列化为json对象写入responseBody返回给前端
@ConfigurationProperties 指定前缀 默认注入到类中Map类型字段
@PathVariable 获取url中参数{xxx}
@RequestParam 获取url中?xxx参数
@RequestBody获取Post请求中body
@RequestHeader 获取请求头 value=“请求头名”
发现机制
注入方式
- 属性注入
- 构造函数注入
- setter注入,
可以在静态方法中注入Bean对象
@Component public class GenericAndJson { private static ObjectMapper mapper; @Autowired public void setMapper(ObjectMapper mapper) { GenericAndJson.mapper = mapper; }
- @Configuration注解 xml变为注解方式
@Configuration public class HeroConfiguration{ @Bean public ISkill camille(){ return new Camille(); } }
多个实现类选择机制
- 被动注入法方式 先根据类型 后根据名字
- 主动注入方式
策略模式
@Qualifier @Primary - 条件注解 @Conditional+org.springframe.Condition接口
常用成品提供注解有@ConditionalOnProperty
特殊注入方法
-
component+实现特定接口
@Component public class AutoPrefixConfiguration implements WebMvcRegistrations { @Override public RequestMappingHandlerMapping getRequestMappingHandlerMapping() { return new AutoPrefixUrlMapping(); } }
-
添加特定注解 eg.
@ControllerAdvice
-
@Autowtred属性注入不能注入静态属性,要想在静态方法中调用Ioc当中的对象,采用setter注入
@Component public class GenericAndJson { private static ObjectMapper mapper; @Autowired public void setMapper(ObjectMapper mapper) { GenericAndJson.mapper = mapper; }
配置文件注入方法
- 在配置类中
@PropertySource
(value = “classpath:config/exception-code.properties”) 将配置文件和类进行关联 @ConfigurationProperties
(prefix = “li”) 指定配置文件中字段的前缀@ConfigurationProperties(prefix = "li") @PropertySource(value = "classpath:config/exception-code.properties") @Component public class ExceptionCodeConfiguration { private Map<Integer,String> codes = new HashMap<>(); }
@Value("${}")
直接从application.properties读取配置
统一异常处理 已知异常 未知异常
- 实现类上打上
@ControllerAdvice
注解 - 方法打上
@ExceptionHandler
(value = Exception.class)指定监控异常类@ControllerAdvice public class GlobalExceptionAdvice { @ExceptionHandler(value = Exception.class) public UnifyResponse handleException(HttpServletRequest req, Exception e) {} } UnifyResponse响应实体结构为 { code:10001 message:XXXX request:GET url }
根据目录结构自动生成路由前缀
实现类是AutoPrefixConfiguration和AutoPrefixUrlMapping
通过反射
获取类绝对路径,配置文件
指定api根目录,在映射url时注入AutoPrefixUrlMapping干预
public class AutoPrefixUrlMapping extends RequestMappingHandlerMapping {
@Value("${missyou.api-package}")
private String apiPackagePath;
@Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo mappingInfo = super.getMappingForMethod(method, handlerType);
if (mappingInfo != null) {
String prefix = getPrefix(handlerType);
return RequestMappingInfo.paths(prefix).build().combine(mappingInfo);
}
return mappingInfo;
}
private String getPrefix(Class<?> handleType) {
String packageName = handleType.getPackage().getName();
String dotPath = packageName.replaceAll(this.apiPackagePath, "");
return dotPath.replace(".", "/");
}
}
注入的类类型
SpringBean注入默认为单例类型
,用法类似于静态方法。要注入多例对象
将业务类作为一个普普通通的java类,不加上@Component注解,使用的时候手动new出来,需要的对象通过构造函数传过来。这样很多Spring特性就无法使用,不推荐这种方法。还可以用
在类上 | 调用的时候 |
---|---|
加@Scope(value = “prototype”) | 多个实例注入 |
加@Scope(value = “prototype”) | 参数注入 |
加@Scope(value = “prototype”) | @Autowired private ObjectFactory t |
加@Scope(value = “prototype”, proxyMode = ScopedProxyMode.TARGET_CLASS) | @Autowired private T t |
加入IOC容器的类默认调用的是无参构造方法,即便是有参的构造函数,参数也是加入到IOC容器的对象,Spring不能管理不在IOC容器中的对象。
自动配置原理
SPI思想 Service Provider Interface 模块装配
- @SpringBootApplication注解主要有@ComponentScan包扫描注解和
@EnableAutoConfiguration
自动装配注解 - 在@EnableAutoConfiguration中有
@Import(AutoConfigurationImportSelector.class)
他实现了selectImportspublic String[]selectImports
(AnnotationMetadata annotationMetadata)方法 - 根据
spring.factories
使用条件注解加载模块从而实现自动装配
业务实现基于interface 策略模式+配置文件
自动装配解决的是如何将SDK作为Bean加入到容器中
Ioc容器中Bean的生命周期
BeanPostProcessor 在bean的生命周期间做一些操作。
postProcessBeforeInitialization()
在初始化之前
postProcessAfterInitialization()
在初始化之后 例如对权限注解上的信息进行收集
执行构造方法
注入BeanName
注入BeanFactory
注入ApplicationContext
@Autowired(依赖注入)
执行BeanPostProcessor的postProcessBeforeInitialization方法
执行postConstruct注解方法
执行InitializingBean的afterPropertiesSet方法
执行bean定义的initMethod方法
执行BeanPostProcessor的postProcessAfterInitialization方法
ApplicationContext事件监听
ApplicationListener 初始化或者刷新是,权限发生了变化进行更新
AOP
@Transactional注解
声明式事务管理,使用在类或接口实现方法上,实际使用了JDBC的事务DataSourceTransactionManager 来进行事务控制的。Spring 关闭数据库中自动提交:在方法执行前关闭自动提交,方法执行完毕后再开启自动提交,若超过一定时间没有提交,就回滚。
事务的隔离级别:是指若干个并发的事务之间的隔离程度。
事务传播行为:如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。
Lombok常用注解
注解名 | 作用 |
---|---|
@Getter@Setter | 生成属性的get和set |
@RequiredArgsConstructor | 生成属性加了@NonNull的构造方法 |
@NoArgsConstructor | 无参构造方法 |
@Builder | new对象可以链式传参,一定配合@Getter |
@AllArgsConstructor | 生成带有所有属性的构造方法 |
参数校验 BeanValidation
Hibernate-Validator
实现了JSR-303
命名 | 用法 | |
---|---|---|
@Valid | java规范命名 | Controller类和参数为DTO类前 |
@Validated | Hibernate实现命名 | 级联私有属性上 |
一些基础注解 @Max(value=10) @Range(min=1,max=10) @Positive检查元素是否严格为正
自定义校验器
对象关系设计
实体类常用注解
- @Entity(name=“sql语句表名的别名,默认为类名”)
- @Table(name=“数据库中表名,默认为类名”)
- @GeneratedValue(strategy="主键的生成方式
mysql一定用GenerationType.IDENTITY"
) - @Column(name=“数据库中列名,默认会把驼峰命名变为小写下划线”,
- columnDefinition=“字段约束直接放在sql语句中”)
- @ColumnDefault(“设置默认值”)
这只是约束.实体类还要设置默认值
- @JoinColumn(name=“外键在表中的名字”,referencedColumnName=“关联表主键在表中的名字”)
- @MappedSuperclass 指定此类是实体类的基类,其中的字段可以查询映射到model
- @Column(insertable = false,updatable = false) 加上此注解的字段在更新和插入时会忽略此字段。create_time,update_time是有数据库进行赋值的,程序不应该更改他,程序虽然没管它但给数据库传null他也认为是一个值,造成错误
对象关系注解
- @OneToMany@ManyToOne("mappedBy=“双向关系中维持关系的实体类对象字段名,
剔除关系的实体类对象字段上加此注解
”)
DTO VO
DO、VO、PO,POJO,DTO
DTO 前端传给后端
VO 后端传给前端
PO 业务层向控制层传输可以外延成业务层对象
DAO 数据层向业务层返回的数据
Bean对象拷贝
实际开发中,会有大量的DTO,VO等Bean对象互相转换,用setter方法一个个设值太麻烦,可以使用DozerMapper,BeanUtils等工具
- 使用BeanUtils.copyProperties(Object source, Object target)浅拷贝
- 使用DozerMapper深拷贝
注入后就可以直接使用mapper.<dependency> <groupId>com.github.dozermapper</groupId> <artifactId>dozer-spring-boot-starter</artifactId> <version>6.5.0</version> </dependency>
map
(Object source, Class destinationClass)
fastjson序列化和双向关系JPA导致Infinite recursion (StackOverflowError)
在使用SpringDataJpa或者hibernate框架时,向前端返回Json数据,序列化时会造成循环调用导致栈溢出,解决的方法有
- 双方都有@Entity注解,在One方类加上
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
,property默认是@id,要改为id,即主键的名字 - 增加VO视图模型层,将要序列化的字段重新实例化,就可以切断JPA的影响,这样数据重复性可能很大,
- 以后尝试@JsonView
网上有很多说用@JsonIgnore@JsonManagedReference@JsonBackReference但这些都要忽略某个属性不进行序列化,但我的项目需要所有属性序列化
hibernate中因双向依赖而造成的json怪相
Jackson JSON - Using @JsonIdentityInfo to handle circular references
Jackson小写下划线与驼峰格式转换
在application.properties增加
spring.jackson.property-naming-strategy=SNAKE_CASE
@JsonProperty(“属性序列化别名”)#
双向关系使用Lombok注解会导致StackOverflowError
使用@ToString @EqualsAndHashCode @Data导致栈溢出
在@Many方或子方添加@ToString
(exclud={“指向父方或@One方属性名”})
SpringDataJpa分页设计
- 使用start和count算出显示第几页,一页有多少数据,
- 使用
PageRequest.of()
创建分页对象,第一个参数是页码,第二个是一页有多少条数据,第三个是按照某字段进行倒叙排列,返回的是实现Pageable接口的对象 - Page为分页结果,他包含当前数据有多少条,总数量,当前页码,一共有多少页
- 构造VO层Paging对象返回前端,利用属性拷贝将数据库对象转换成VO对象
Pageable page = PageRequest.of(pageNum,size, Sort.by("createTime").descending());
return spuRepository.findAll(page);
实体属性类型转换器
插入数据库时,转为json字符串,查询出来后转为对象
- 主要实现
AttributeConverter
类和使用@Converter@Convert
注解 - 另一种方法覆盖属性的get和set方法,使用工具类GenericAndJson进行转换
部署jar到Linux
https://github.com/nodejs/help/wiki/Installation
https://www.cnblogs.com/linck/p/11574704.html
事务不等于加锁
IDEA快捷键
###IDEA快捷键
ctrl+H 查看类层级关系
ctrl+p 参数列表
ctrl+alt+v 类型推断
ctrl+o 覆盖或实现方法
alt+7 类结构视图 ctrl+r12
ctrl+alt+鼠标左键 跳转到实现
idea properties文件乱码
ctrl+ 减号 折叠代码
idea database插件和jpa关联
idea自动生成jpa实体类
logging.level.com.li.missyou=debug 控制台开启debug指定包范围
ctrl+W 选中单词 行
待办
- 内联 懒加载
- 查询
- Optional 类
- 静态资源服务器
- 源码阅读Spring Data Jpa 分页类 Page
- 模板校验jsr303