昨天搭建ssm框架时突然想到可以搭建springboot来完美解决配置复杂的问题,今天学习了一下springboot的搭建,在此记录一下搭建的过程和踩过的坑
这里给自己定一个该框架搭建完成的目标,如下
框架要求功能:
- 处理http/json 请求
- 日志记录
- 持久化
- 数据源,事务控制
- 定时任务
- 视图模版
搭建环境:
- 编译器:idea 2016.2.4
- Maven : maven3.0
- JDK: java7
- 系统: mac OS 10.10.4
- 数据库: mysql5.6
2017-03-29
搭建记录
- 新建maven应用(不需要web应用)
- 在pom中添加以下配置
<!-- Spring boot 父引用-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.RELEASE</version>
</parent>
<!-- Spring boot 核心web-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
- 新建controller
@Controller
@EnableAutoConfiguration
public class TestBootController {
@RequestMapping("/")
@ResponseBody
String home() {
return "hello world";
}
public static void main(String[] args) throws Exception {
SpringApplication.run(TestBootController.class, args);
}
}
此时的项目目录结构是这样的
- 启动main函数,可以看到控制台输出,非常简单明了
端口默认是8080,启动log已经写了,访问后如图所示
在搭建了基础应用的基础上,想增加service层抽离控制层和业务层代码
//业务层接口
public interface TestInterFace {
public int testInterFace();
public User testUser();
}
//业务层接口实现
@Service
public class TestInterFaceImpl implements TestInterFace {
@Override public int testInterFace() {
return 0;
}
@Override public User testUser() {
return new User();
}
}
修改controller层代码
@Controller
@EnableAutoConfiguration
public class TestBootController {
@Autowired
private TestInterFace testInterFace;
@RequestMapping("/num")
@ResponseBody
int home() {
int i = testInterFace.testInterFace();
return i;
}
@RequestMapping("/get")
@ResponseBody User getUser() {
return testInterFace.testUser();
}
public static void main(String[] args) throws Exception {
SpringApplication.run(TestBootController.class, args);
}
}
启动后抛异常
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘testBootController’: Unsatisfied dependency expressed through field ‘testInterFace’: No qualifying bean of type [com.kx.springboot.service.TestInterFace] found for dependency [com.kx.springboot.service.TestInterFace]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.kx.springboot.service.TestInterFace] found for dependency [com.kx.springboot.service.TestInterFace]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
相信大家对这种异常非常常见,注入失败,这时候问题来了,按照传统的方式,对注入进行检查。service层已经加了@service的注解,怎么还是注入失败了呢,想查看配置文件,发现springboot没有配置文件,那么他是怎么扫描注解的呢?
百度了一下才知道,springboot默认按照包顺序注入,所以在创建controller时service还没有注入,springboot不需要传统的xml配置扫描包,只需要添加注解@ComponentScan(basePackages={“com.kx.springboot.service”}),代码如下
@Controller
@EnableAutoConfiguration
@ComponentScan(basePackages={
"com.kx.springboot.service"})//添加的注解
public class TestBootController {
@Autowired
private TestInterFace testInterFace;
@RequestMapping("/num")
@ResponseBody
int home() {
int i = testInterFace.testInterFace();
return i;
}
@RequestMapping("/get")
@ResponseBody User getUser() {
return testInterFace.testUser();
}
public static void main(String[] args) throws Exception {
SpringApplication.run(TestBootController.class, args);
}
}
再次启动,成功,访问http://localhost:8088/get
{“username”:”username寇鑫123”,”password”:”password寇鑫123”}
- 这时候,又有一个问题,web应用都是多controller,这种启动方式一次只能启动一个controller,那么,怎么才能启动应用后访问多个controller,查阅springboot官方教程后,修改代码如下
增加 UserController
@Controller
@RequestMapping("user")
public class UserController {
@Autowired
private TestInterFace testInterFace;
@RequestMapping("/get")
@ResponseBody User getUser() {
return testInterFace.testUser();
}
}
修改原来 TestBootController
@Controller
@RequestMapping("test")
public class TestBootController {
@Autowired
private TestInterFace testInterFace;
@RequestMapping("/num")
@ResponseBody
int home() {
int i = testInterFace.testInterFace();
return i;
}
@RequestMapping("/get")
@ResponseBody User getUser() {
return testInterFace.testUser();
}
}
在包的最外层增加新的应用启动入口 —> Application
@EnableAutoConfiguration
@ComponentScan(basePackages={
"com.kx.springboot"})
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
可以看到,应用启动入口配置了扫描所有包。此时整个项目的结构如图所示
- 启动应用后访问
http://localhost:8080/test/get
{“username”:”username寇鑫123”,”password”:”password寇鑫123”}
http://localhost:8080/user/get
{“username”:”username寇鑫123”,”password”:”password寇鑫123”}
到此,符合处理http/json 的web框架已经搭建ok了
============2017-3-30 =============
第一步处理http/json已经完成了,现在给我们的框架里加上日志记录的功能
要求:
- 日志按天记录,自动生成当天的记录文件
- 日志分级存储(info,error)
Springboot自带日志,所以我们现在直接在SpringBoot中添加日志
修改 TestController
@Controller
@RequestMapping("test")
public class TestBootController {
//增加日志
private final Logger log = LoggerFactory.getLogger(TestBootController.class);
@Autowired
private TestInterFace testInterFace;
@RequestMapping("/num")
@ResponseBody
int home() {
int i = testInterFace.testInterFace();
return i;
}
@RequestMapping("/get")
@ResponseBody User getUser() {
//打印日志
log.info("TestBootController getUser info");
return testInterFace.testUser();
}
}
只增加了两行代码,现在启动尝试打印日志
访问 http://localhost:8080/test/get
可以看到我们的日志已经打出来了,那么现在又有疑问了,这个日志只是打在控制台了,并没有生成文件,查询后发现默认日志如果要打印生成文件需要添加application.properties,而添加这个只可以打固定名称格式的日志,并不能灵活的配置,所以添加Springboot默认支持的logback作为标准日志输出
添加新的pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
在resource下添加logback配置文件logback.xml
首先配置按天生成日志,尝试日志文件打印输出
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="/Users/kx/Desktop" />
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->