Springboot知识点

1Spring boot简介

主要用来简化spring开发,快速地创建独立的spring项目,并且与云计算天然集成。

2. @Controller 

标记一个类是Controller,也可以标记方法,标记方法时是指传统Web的Controller,返回的是字符串。

3. @ResponseBody

注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML。例如:  
1 @RequestMapping("/login")
2 @ResponseBody
3 public User login(User user){
4   return user;
5 }
User字段:userName pwd
那么在前台接收到的数据为:
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

将前端发来的json格式数据转换成java对象,比如
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

@RestController = @Controller + @ResponseBody
在编写接口时标记方法是一个Rest接口,返回一个可序列化的Json或者XML对象。Controller中的注解具体可以参考:必须知道的Spring Boot中的一些Controller注解

6. @RequestMapping简介

指定控制器可以处理哪些URL请求,相当于Servlet中在web.xml中配置:
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>
(1)在@Target中有两个属性,分别为 ElementType.METHOD 和 ElementType.TYPE ,也就是说 @RequestMapping 可以在方法和类的声明中使用;
(2)可以看到注解中的属性除了 name() 返回的字符串,其它的方法均返回数组,也就是可以定义多个属性值,例如 value() 和 path() 都可以同时定义多个字符串值来接收多个URL请求。

7. @Configuration 和 @Bean 注解

@Configuration 的注解类表示这个类可以使用 Spring IoC 容器作为 bean 定义的来源。@Bean 注解告诉 Spring,一个带有 @Bean 的注解方法将返回一个对象,该对象应该被注册为在 Spring 应用程序上下文中的 bean。具体解释可见:https://www.cnblogs.com/wuchanming/p/5426746.html 

8. @EnableAutoConfiguration 

作用是从classpath中搜索所有META-INF/spring.factories配置文件,然后将其中org.springframework.boot.autoconfigure.EnableAutoConfiguration key对应的配置项加载到spring容器
只有spring.boot.enableautoconfiguration为true(默认为true)的时候,才启用自动配置。

9. @ComponentScan

自定扫描路径下边带有@Controller,@Service,@Repository,@Component注解加入spring容器
通过includeFilters加入扫描路径下没有以上注解的类加入spring容器
通过excludeFilters过滤出不用加入spring容器的类。具体参见https://blog.51cto.com/4247649/2118342

10. @SpringBootApplication

@SpringBootApplication=@Configuration+@EnableAutoConfiguration+@ComponentScan

11. @Primary和@Qualifier

使用场景:如果在通过@Autowired自动注入时,注入的接口存在多个实现类且当我们不具体指定哪个实现类时,SpringBoot会报错,此时可以使用@Primary指定一个类为默认偏好(preference)的实现类,在JPA的多数据源实现中就使用到了@Primary。
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优雅的编码

⚠️注意: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

URI(Uniform Resource Identifier)字面上的意思是,统一资源标示
URL(Uniform Resource Locator),统一资源定位
但是标示是什么意思?定位又是什么意思?
举个简单的栗子🌰
比如说我们查到东北大学校长赵X,办公室地址辽宁省沈阳市东北大学xx教xx号。这样大家都知道了东北大学的校长姓赵,这样赵校长就和这个头衔对应了起来。同样地我们可以通过一个URI来确定它代表着什么,比如baidu.com代表百度,xxx@qq.com代表QQ邮箱,这样就是一个标示。URI就是网络资源的头衔,通过URI标记可以把网络世界里面的每一个事物都加以标记并区分。
如果有一天,我们去拜访我们学校的校长,只知道我们学校的校长姓赵,在东北大学,但是他不知道准确的办公室地址,也不能去找到他。所以我们为了能够使网络上的资源能被广泛的大多数的人能访问到,还需要给他添加一个地址,比如通过东北大学xx教xx号能可以找到赵校长的办公室。反应到网络世界中去就是,我们知道baidu.com代表是一个百度,标示它是百度,当有一天我们想要访问百度地图的时候,我们只有一个baidu.com是找不到百度地图的,但是如果map.baidu.com这样和百度地图对应起来,我们就可以直接找到百度地图的网络资源。相当于给我们提供了资源存放的地址门牌号,我们只是去取得资源。

17. IDEA中的classpath问题

Thread.currentThread().getContextClassLoader().getResource("")得到当前的classpath的绝对路径的URI表示。如:file:/Users/admin/akia/data/bin/
一般情况下,用到的资源文件(各种xml,properites,xsd文件等)都放在src/main/resources下面,maven打包时能把这些资源文件打包到相应的jar或者war里。
例如:

 

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 }
View Code

再写注解

1 @Inherited
2 @Documented
3 @Target({ElementType.METHOD})
4 @Retention(RetentionPolicy.RUNTIME)
5 public @interface UserAction {
6   String value();
7 }
View Code

然后在访问之前设置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 }
View Code

最后在controller里边方法上加注解就欧了

1 @UserAction(value = "xxx")
View Code

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”

检查自己是否在实体类中加以下注解:

 
 
posted @ 2019-04-20 21:37  akia开凯  阅读(461)  评论(0编辑  收藏  举报