SpringBoot2.x异步任务EnableAsync一 SpringBoot2项目创建
常见的创建SpringBoot创建方式
本地创建,maven依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
- 在线创建 :https://start.spring.io/
二 SpringBoot2.X常用的注解
- @Controller 作用:用于标记这个类是一个控制器,返回页面的时候使用;如果要返回JSON,则需要在接口上使用@ResponseBody才可以
- @RestController 作用:用于标记这个类是一个控制器,返回JSON数据的时候使用,如果使用这个注解,则接口返回数据会被序列化为JSON
- 所以:@RestController = @Controller+@ResponseBody
-
@RequestMapping 作用:路由映射,用于类上做1级路径;用于某个方法上做子路径
-
@SpringBootApplication 作用: 用于标记是SringBoot应用,里面包含多个子注解,即
@SpringBootApplication = @Configuration+@EnableAutoConfiguration+@ComponentScan (下面的目前只需简单理解即可,想深入的同学,后续可以看专门的Spring原理课程深入) @Configuration: 主要标注在某个类上,用于spring扫描注入,一般结合@Bean使用 @EnableAutoConfiguration: 启用Spring的自动加载配置,自动载入应用程序所需的所有Bean @ComponentScan:告诉spring扫描包的范围,默认是Applocation类所在的全部子包,可以指定其他包 @ComponentScan({"net.xdclass.package1","net.xdclass.package2"})
三 SpringBoot目录文件结构
-
目录讲解
- src/main/java:存放代码
- src/main/resources
- static: 存放静态文件,比如 css、js、image, (访问方式 http://localhost:8080/js/main.js)
- templates:存放静态页面jsp,html,tpl
- config:存放配置文件,application.properties
- resources:
-
同个文件的加载顺序,静态资源文件 Spring Boot 默认会挨个从
- META/resources >
- resources >
- static >
- public
里面找是否存在相应的资源,如果有则直接返回,不在默认加载的目录,则找不到 -
默认配置spring.resources.static-locations = classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
五 启动方式
Jar方式打包启动
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
如果没有加,则执行jar包 ,报错如下
java -jar spring-boot-demo-0.0.1-SNAPSHOT.jar
no main manifest attribute, in spring-boot-demo-0.0.1-SNAPSHOT.jar
必备打包、启动命令
构建:mvn install
构建跳过测试类 mvn install -Dmaven.test.skip=true
target目录下有对应的jar包就是打包后项目
进到对应的target目录启动 java -jar xxxxx.jar 即可
想后台运行,就用守护进程 nohup java -jar xxx.jar &
六 打包后的springboot里面的目录结构
解压后项目结构
example.jar
|
+-META-INF
| +-MANIFEST.MF
+-org
| +-springframework
| +-boot
| +-loader
| +-<spring boot loader classes>
+-BOOT-INF
+-classes
| +-mycompany
| +-project
| +-YourClasses.class
+-lib
+-dependency1.jar
+-dependency2.jar
七 springboot接口,http的get请求,各个注解使用
-
GET请求
- 场景:一般的查询接口就是get请求
- 注解:@GetMapping = @RequestMapping(method = RequestMethod.GET)
@GetMapping = @RequestMapping(method = RequestMethod.GET) @PostMapping = @RequestMapping(method = RequestMethod.POST) @PutMapping = @RequestMapping(method = RequestMethod.PUT) @DeleteMapping = @RequestMapping(method = RequestMethod.DELETE)
JSONData工具类开发
public class JsonData {
private int code;
private Object data;
private String msg;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public JsonData(){}
public JsonData(int code, Object data){
this.code = code;
this.data = data;
}
public JsonData(int code, Object data, String msg){
this.code = code;
this.data =data;
this.msg = msg;
}
public static JsonData buildSuccess(Object data){
return new JsonData(0,data);
}
public static JsonData buildError(String msg){
return new JsonData(-1,"",msg);
}
public static JsonData buildError(String msg,int code){
return new JsonData(code,"",msg);
}
}
jackson处理相关自动
- 指定字段不返回:@JsonIgnore
- 指定日期格式:@JsonFormat(pattern="yyyy-MM-dd hh:mm:ss",locale="zh",timezone="GMT+8")
- 空字段不返回:@JsonInclude(Include.NON_NULL)
- 指定别名:@JsonProperty
- 序列化和反序列化操作
//序列化操作 ObjectMapper objectMapper = new ObjectMapper(); String jsonStr = objectMapper.writeValueAsString(list); System.out.println(jsonStr); //反序列化操作 List<Video> temp = objectMapper.readValue(jsonStr,List.class);
七 使用dev-tool实现热部署
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork><!--必须添加这个配置--> </configuration> </plugin> </plugins> </build>
使用快捷键打开,选择Registry
注意默认快捷键: window快捷键 Shift+Ctrl+Alt+/ mac快捷键 Shift+Command+Alt+/ 如果自行修改了默认快捷键,则百度搜索相关博文,或者还原快捷键设置
选择compiler.automake.allow.when.app.running ,重启idea就行!!!
八 SpringBoot.2.X里面的配置文件
常见的配置文件格式
xml、properties、json、yaml
配置文件加载
-
方式一
- 1、Controller上面配置 @PropertySource({"classpath:resource.properties"})
- 2、增加属性 @Value("${test.name}") private String name;
- 方式二:实体类配置文件
-
1、添加 @Component 注解;
-
2、使用 @PropertySource 注解指定配置文件位置;
-
3、使用 @ConfigurationProperties 注解,设置相关属性;
-
4、必须 通过注入IOC对象Resource 进来 , 才能在类中使用获取的配置文件值。
-
例子: @Configuration @ConfigurationProperties(prefix="test") @PropertySource(value="classpath:resource.properties") public class ServerConstant { } 常见问题: 1、配置文件注入失败,Could not resolve placeholder 解决:根据springboot启动流程,会有自动扫描包没有扫描到相关注解, 默认Spring框架实现会从声明@ComponentScan所在的类的package进行扫描,来自动注入, 因此启动类最好放在根路径下面,或者指定扫描包范围 spring-boot扫描启动类对应的目录和子目录 2、注入bean的方式,属性名称和配置文件里面的key一一对应,就用加@Value 这个注解 如果不一样,就要加@value("${XXX}")
九 SpringBoot2.x的单元测试
<!--springboot程序测试依赖,如果是自动创建项目默认添加-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
@RunWith(SpringRunner.class) //底层用junit SpringJUnit4ClassRunner
@SpringBootTest(classes={XdclassApplication.class})//启动整个springboot工程
public class SpringBootTests { }
-
常用单元测试的注解
- @before
- @Test
- @After
-
断言
- 判断程序结果是否符合预期 TestCase.assertXXX
十 SpringBoot2.X全局异常处理
Springboot2.X怎么在项目中配置全局异常
-
类添加注解
- @ControllerAdvice,如果需要返回json数据,则方法需要加@ResponseBody
- @RestControllerAdvice, 默认返回json数据,方法不需要加@ResponseBody
-
方法添加处理器
- 捕获全局异常,处理所有不可知的异常
- @ExceptionHandler(value=Exception.class)
十一 SpringBoot2.X过滤器
ApplicationContextHeaderFilter
OrderedCharacterEncodingFilter
OrderedFormContentFilter
OrderedRequestContextFilter
使用Servlet3.0的注解进行配置步骤
- 启动类里面增加 @ServletComponentScan,进行扫描
- 新建一个Filter类,implements Filter,并实现对应的接口
- @WebFilter 标记一个类为filter,被spring进行扫描
- urlPatterns:拦截规则,支持正则
- 控制chain.doFilter的方法的调用,来实现是否通过放行
- 不放行,web应用resp.sendRedirect("/index.html") 或者 返回json字符串
javaweb的使用doPost和doGet方法使用Servlet3.0替代更轻量级
@WebServlet(name = "userServlet", urlPatterns = "/api/v1/test/customs" )
class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
writer.write("this is my custom servlet");
writer.flush();
writer.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
十二 注解自定义原生Listener监听器
-
监听器:应用启动监听器,会话监听器,请求监听器
-
作用
- ServletContextListener 应用启动监听
- HttpSessionLisener 会话监听
- ServletRequestListener 请求监听
- 常用的监听器 ServletContextListener、HttpSessionListener、ServletRequestListener
@WebListener public class RequestListener implements ServletRequestListener { @Override public void contextDestroyed(ServletContextEvent sce) { System.out.println("======contextDestroyed========"); } @Override public void contextInitialized(ServletContextEvent sce) { System.out.println("======contextInitialized========"); } }
十三 Spingboot2.x新版本配置拦截器
-
拦截器: 和过滤器用途基本类似
-
SpringBoot2.x使用步骤
-
SpringBoot2.X 新版本配置拦截器 implements WebMvcConfigurer
-
自定义拦截器 HandlerInterceptor
- preHandle:调用Controller某个方法之前
- postHandle:Controller之后调用,视图渲染之前,如果控制器Controller出现了异常,则不会执行此方法
- afterCompletion:不管有没有异常,这个afterCompletion都会被调用,用于资源清理
-
按照注册顺序进行拦截,先注册,先被拦截
-
-
-
拦截器不生效常见问题:
- 是否有加@Configuration - 拦截路径是否有问题 ** 和 * - 拦截器最后路径一定要 /** 如果是目录的话则是 /*/
如何配置不拦截某些路径? registry.addInterceptor(new LoginIntercepter()).addPathPatterns("/api/v1/pri/**") //配置不拦截某些路径,比如静态资源 .excludePathPatterns("/**/*.html","/**/*.js");
十四 SpringBoot2.X定时任务schedule讲解
-
常见定时任务
- Java自带的java.util.Timer类配置比较麻烦,时间延后问题
- Quartz框架: 配置更简单,xml或者注解适合分布式或者大型调度作业
- SpringBoot框架自带
-
SpringBoot使用注解方式开启定时任务
- 启动类里面 @EnableScheduling开启定时任务,自动扫描
- 定时任务业务类 加注解 @Component被容器扫描
- 定时执行的方法加上注解 @Scheduled(fixedRate=2000) 定期执行一次
-
cron 定时任务表达式 @Scheduled(cron="*/1 * * * * *") 表示每秒
- crontab 工具 https://tool.lu/crontab/
-
fixedRate: 定时多久执行一次(上一次开始执行时间点后xx秒再次执行;)
-
fixedDelay: 上一次执行结束时间点后xx秒再次执行
十五 SpringBoot2.x异步任务EnableAsync
-
什么是异步任务和使用场景:适用于处理log、发送邮件、短信……等
- 下单接口->查库存 1000
- 余额校验 1500
- 风控用户1000
-
启动类里面使用@EnableAsync注解开启功能,自动扫描
-
定义异步任务类并使用@Component标记组件被容器扫描,异步方法加上@Async
定义异步任务类需要获取结果
-
注意点:
- 要把异步任务封装到类里面,不能直接写到Controller
- 增加Future 返回结果 AsyncResult("task执行完成");
- 如果需要拿到结果 需要判断全部的 task.isDone()