Springboot知识点
1. Spring boot简介
2. @Controller
3. @ResponseBody
1 @RequestMapping("/login") 2 @ResponseBody 3 public User login(User user){ 4 return user; 5 }
1 '{"userName":"xxx","pwd":"xxx"}'
1 @RequestMapping("/login") 2 public void login(User user, HttpServletResponse response){ 3 response.getWriter.write(JSONObject.fromObject(user).toString()); 4 }
4. @RequestBody
1 @PostMapping(value = "/log/runtime/info") 2 public CommonResponse getMesosClusterInfo(@RequestBody QueryLogRequest request) throws BearException { 3 CommonResponse commonResponse = new CommonResponse(); 4 commonResponse.setData(request); 5 return commonResponse; 6 }
5. @RestController
6. @RequestMapping简介
1 <servlet> 2 <servlet-name>servletName</servlet-name> 3 <servlet-class>ServletClass</servlet-class> 4 </servlet> 5 <servlet-mapping> 6 <servlet-name>serveltName</servlet-name> 7 <url-pattern>url</url-pattern> 8 </servlet-mapping>
7. @Configuration 和 @Bean 注解
8. @EnableAutoConfiguration
9. @ComponentScan
10. @SpringBootApplication
11. @Primary和@Qualifier
1 /** 2 * EntityManager profile. 3 */ 4 @Primary 5 @Bean(name = "entityManagerPrimary") 6 public EntityManager entityManager(EntityManagerFactoryBuilder builder) { 7 return entityManagerFactoryPrimary(builder).getObject().createEntityManager(); 8 }
使用场景:如果在@Autowired自动注入时有多个候选实现类的Bean,可以通过@Qualifier在自动注入的地方传入一个限定名(也就是类的别名)来选取指定的实现类,此时自动注入的策略就从 byType 转变成 byName,同样在JPA的多数源实现中也使用到了@Qualifier。
1 @Configuration 2 public class DataSourceConfig { 3 @Bean(name = "primaryDataSource") 4 @Qualifier("primaryDataSource") 5 @Primary 6 @ConfigurationProperties(prefix = "spring.datasource.primary") 7 public DataSource primaryDataSource() { 8 return DataSourceBuilder.create().build(); 9 } 10 11 @Bean(name = "secondaryDataSource") 12 @Qualifier("secondaryDataSource") 13 @ConfigurationProperties(prefix = "spring.datasource.secondary") 14 public DataSource secondaryDataSource() { 15 return DataSourceBuilder.create().build(); 16 } 17 }
12. @CreatedDate 和 @LastModifiedDate
用处:Spring Data JPA 提供了相应的时间注解,一个是更新时间,一个是创建时间。
用法:
(1) 在Application启动类中添加注解@EnableJpaAuditing;
(2) 在实体类上加上注解 @EntityListeners(AuditingEntityListener.class);
(3) 在相应的字段上添加对应的时间注解 @LastModifiedDate 和 @CreatedDate
13. @Slf4j
用它不用每次都写private final Logger logger = LoggerFactory.getLogger(XXX.class);14. Lombok
⚠️注意:lombok中的@Builder注解默认生成的构造器是“default”的,可以被同package的类调用(default限制不同package类的调用),而我们希望构造器设为private,此时需要用到“@AllArgsConstructor(access = AccessLevel.PRIVATE)”。所以最终写法:
1 @Builder 2 @AllArgsConstructor(access = AccessLevel.PRIVATE)
15. URL命名规则
- URL尽量全部小写,用户方便输入;
- 不建议驼峰或者下划线_连接,搜索引擎会把下划线自动忽略掉,可以使用中划线‘-’连接,sou;
- 对于CURD,URL相同,请求方法(get、post、put、delete)不同,也作为不同的接口;
- URL参数尽量不超过3个;
- 资源必须采用资源名词复数的形式,比如https://api.github.com/user/emails
16. URL和URI
17. IDEA中的classpath问题
18. Springboot中日志打印问题
springboot默认是logback日志,初始构建日志有颜色,但由于某种操作之后颜色消失了,一种解决方法是在相应目录resource下增加logback.xml,如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 3 <!-- Logback configuration. See http://logback.qos.ch/manual/index.html --> 4 <configuration scan="true" scanPeriod="10 seconds"> 5 <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> 6 <encoder> 7 <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 : 8 |%blue(%thread) 线程 如 :DiscoveryClient-CacheRefreshExecutor-0--> 9 <pattern>%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%green(%logger:%line) |%black(%msg%n)</pattern> 10 </encoder> 11 </appender> 12 13 <!-- 日志输出级别 --> 14 <root level="INFO"> 15 <appender-ref ref="STDOUT" /> 16 </root> 17 </configuration>
效果如下:
如果采用log4j日志打印,可以使用log4j.properties文件配置,该文件默认从resources目录下读取,比如:
1 #设置日志打印级别 2 log4j.rootLogger = INFO, FILE 3 4 log4j.appender.FILE=org.apache.log4j.RollingFileAppender 5 #设置日志存放位置 6 log4j.appender.FILE.File=/home/log/report-start.log 7 #每个日志达到100MB时切块 8 log4j.appender.FILE.MaxFileSize=100MB 9 #保存10个备份日志文件 10 log4j.appender.FILE.MaxBackupIndex=10 11 log4j.appender.FILE.Append=true 12 log4j.appender.FILE.Threshold=INFO 13 log4j.appender.FILE.layout=org.apache.log4j.PatternLayout 14 log4j.appender.FILE.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p %-60c %x - %m%n
19. JPA清空数据库
Repository层里定义该方法:
@Transactional
@Modifying
@Query(value = "truncate table t",nativeQuery = true)
public void truncateTable();
@Transactional和@Modifying很重要
20. 切面小例子
今天看大佬代码,发现个很好玩的东西,他用切面做url的访问量和时长统计,这么棒的小例子收了,如果有侵权马上删除哈😂。
1 // 实体类,存数据库 2 @Data 3 @Entity 4 @AllArgsConstructor 5 @NoArgsConstructor 6 @Accessors(chain = true) 7 @Table(name = "user_action") 8 @EntityListeners(AuditingEntityListener.class) 9 public class UserActionEntity { 10 @Id 11 @GeneratedValue 12 private Long id; 13 14 @Column 15 private String email; 16 17 @Column 18 private String uri; 19 20 @Column 21 private Long duration; 22 23 @Column 24 @CreatedDate 25 private Date date; 26 27 @Column 28 private String ip; 29 30 @Column 31 private String action; 32 }
再写注解
1 @Inherited 2 @Documented 3 @Target({ElementType.METHOD}) 4 @Retention(RetentionPolicy.RUNTIME) 5 public @interface UserAction { 6 String value(); 7 }
然后在访问之前设置start-time,访问之后统计时长
1 @Aspect 2 @Component 3 @Order(4) 4 public class UserActionAspect { 5 private final UserActionDao userStatisticDao; 6 private static final String START_TIME = "startTime"; 7 8 @Autowired 9 public UserActionAspect(UserActionDao userStatisticDao) { 10 this.userStatisticDao = userStatisticDao; 11 } 12 13 @Pointcut(value = "@annotation(yidian.data.bear.annotation.UserAction)") 14 public void userActionAspect() { 15 //fix the target 16 } 17 18 @Before("userActionAspect()") 19 public void doBefore(JoinPoint joinPoint) { 20 Signature signature = joinPoint.getSignature(); 21 Method method = ((MethodSignature) signature).getMethod(); 22 UserAction annotation = method.getAnnotation(UserAction.class); 23 if (null == annotation) { 24 return; 25 } 26 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder 27 .getRequestAttributes()).getRequest(); 28 request.setAttribute(START_TIME, Instant.now()); 29 } 30 31 @AfterReturning(pointcut = "userActionAspect()") 32 public void doAfterReturning(JoinPoint joinPoint) { 33 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder 34 .getRequestAttributes()).getRequest(); 35 Instant endTime = Instant.now(); 36 Instant startTime = (Instant) request.getAttribute(START_TIME); 37 long duration = endTime.toEpochMilli() - startTime.toEpochMilli(); 38 String ip = request.getRemoteAddr(); 39 String uri = request.getRequestURI(); 40 String email = request.getHeader("email"); 41 Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); 42 String action = method.getAnnotation(UserAction.class).value(); 43 UserActionEntity userAction = new UserActionEntity(); 44 userAction.setUri(uri).setDuration(duration).setEmail(email).setAction(action).setIp(ip); 45 userStatisticDao.save(userAction); 46 } 47 }
最后在controller里边方法上加注解就欧了
1 @UserAction(value = "xxx")
21. ApiModel和ApiModelProperty
- @ApiModel在实体类上边使用,标记swagger的解析类
value 类的备用名
description 类的详细描述
- @ApiModelProperty()用于方法,字段;
value 字段说明
name 重写属性名字
dataType 重写属性类型
required 是否必填
example 举例说明
hidden 隐藏
@ApiModel(value="user对象",description="用户对象user") public class User implements Serializable{ private static final long serialVersionUID = 1L; @ApiModelProperty(value="用户名",name="username",example="xingguo") private String username; @ApiModelProperty(value="状态",name="state",required=true) private Integer state; private String password; private String nickName; private Integer isDeleted; @ApiModelProperty(value="id数组",hidden=true) private String[] ids; private List<String> idList; //省略get/set }
22. SpringBoot整合JPA报错:“No Identifier specified for entity”
检查自己是否在实体类中加以下注解: