1、系统环境
IDE:intellij IDEA 2017.3
2、新建项目
2.1、新建项目
2.2、选择项目类型
2.3、填写项目信息
这里选默认的Maven Project就行了。
2.4、选择依赖
对应于:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
对应于:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
接着完成创建。
由于要进行数据库连接,所以pom.xml添加如下依赖:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
3、环境搭建
项目完成后这样子的:
3.1、配置文件
Spring Boot可以使用application-{profile}.properties这样的形式来加载配置文件,其中profile是spring.profiles.active这个配置的占位符名字。
我们的application.properties很简单,就如下一句:
application.properties
spring.profiles.active=dev
application-dev.properties
logging.path=F:\\demo\\log
logging.file=classpath:logback-spring.xml
logging.level.com.example.demo=debug
server.port=8080
# DB config
spring.jpa.database=mysql
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/boot
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jackson.serialization..indent-output=true
application-prod.properties
logging.path=/opt/log
logging.level.com.example.demo=info
server.port=80
# DB config
spring.jpa.database=mysql
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/boot
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jackson.serialization..indent-output=true
dev和prod基本一致,主配置文件只负责加载这两个配置文件之一。spring.profiles.active=dev这句的值是dev说明加载占位符是dev的配置文件。
3.2、日志配置文件
Spring Boot默认的spring-boot-starter-web就包含了spring-boot-starter-logging这个日志依赖,而已这个日志依赖默认使用logback作为默认日志实现。所以我们使用logback作为日志框架,下面我们配置一下。
在resource文件下新建logback-spring.xml(也可以是logback.xml,多了-spring可以加入Spring Boot的一些特殊配置,所以加了-Spring),使用这个名字,不用配置,Spring Boot默认就会加载这个日志配置文件。
logback-spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<contextName>logback-demo</contextName><!--可有可无-->
<springProperty scope="context" name="logback.logdir" source="logging.path" defaultValue="F:/demo/log"/>
<!--property name="logback.logdir" value="F:/demo/log"/-->
<property name="logback.appname" value="DemoApp"/>
<include resource="logback-console-appender.xml" />
<include resource="logback-error-file-appender.xml" />
<include resource="logback-debug-file-appender.xml" />
<include resource="logback-info-file-appender.xml" />
<root level="info"><!--root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性-->
<!--appender将会添加到这个loger-->
<appender-ref ref="consoleLog"/>
<appender-ref ref="fileDebugLog" />
<appender-ref ref="fileErrorLog" />
<appender-ref ref="fileInfoLog" />
</root>
</configuration>
这里root节点要在最后,不然报错;使用include节点让配置文件短点而已,可以把include换成对应xml的内容;include中使用了占位符,所以property节点来配置占位符,但是这里我希望从Spring Boot配置文件读取配置,所以springProperty节点来配置占位符。
其余日志的内容如下:
logback-console-appender.xml:
<!--输出到控制台 ConsoleAppender-->
<appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
<!--展示格式 layout-->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>
<pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
</pattern>
</layout>
<!--
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
-->
</appender>
这个console-appender要有,不然你IDE控制台就没输出了。所以要价格console-appender。
logback-debug-file-appender.xml:
<appender name="fileDebugLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--如果只是想要 Debug 级别的日志,那么只匹配DEBUG级别,其余不匹配-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--过滤 Error-->
<level>DEBUG</level>
<!--匹配到就禁止-->
<onMatch>ACCEPT</onMatch>
<!--没有匹配到就允许-->
<onMismatch>DENY</onMismatch>
</filter>
<!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则
如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天
的日志改名为今天的日期。即,<File> 的日志都是当天的。
-->
<File>${logback.logdir}/debug.${logback.appname}.log</File>
<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->
<FileNamePattern>${logback.logdir}/debug.${logback.appname}.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--只保留最近90天的日志-->
<maxHistory>90</maxHistory>
<!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
<!--<totalSizeCap>1GB</totalSizeCap>-->
</rollingPolicy>
<!--日志输出编码格式化-->
<encoder>
<charset>UTF-8</charset>
<pattern>%d [%thread] %-5level %logger{36} %line - %msg%n</pattern>
</encoder>
</appender>
File节点和FileNamePattern使用了上面提到的占位符。这个配置文件只输出debug日志到这个文件。
logback-error-file-appender.xml:
<appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--如果只是想要 Error 级别的日志,那么需要过滤一下,默认是 info 级别的,ThresholdFilter-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>Error</level>
</filter>
<!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则
如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天
的日志改名为今天的日期。即,<File> 的日志都是当天的。
-->
<File>${logback.logdir}/error.${logback.appname}.log</File>
<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->
<FileNamePattern>${logback.logdir}/error.${logback.appname}.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--只保留最近90天的日志-->
<maxHistory>90</maxHistory>
<!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
<!--<totalSizeCap>1GB</totalSizeCap>-->
</rollingPolicy>
<!--日志输出编码格式化-->
<encoder>
<charset>UTF-8</charset>
<pattern>%d [%thread] %-5level %logger{36} %line - %msg%n</pattern>
</encoder>
</appender>
这个配置文件只输出debug日志到这个文件。
logback-info-file-appender.xml:
<appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--如果只是想要 Info 级别的日志,只是过滤 info 还是会输出 Error 日志,因为 Error 的级别高,
所以我们使用下面的策略,可以避免输出 Error 的日志-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--过滤 Error-->
<level>ERROR</level>
<!--匹配到就禁止-->
<onMatch>DENY</onMatch>
<!--没有匹配到就允许-->
<onMismatch>ACCEPT</onMismatch>
</filter>
<!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则
如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天
的日志改名为今天的日期。即,<File> 的日志都是当天的。
-->
<File>${logback.logdir}/info.${logback.appname}.log</File>
<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->
<FileNamePattern>${logback.logdir}/info.${logback.appname}.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--只保留最近90天的日志-->
<maxHistory>90</maxHistory>
<!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
<!--<totalSizeCap>1GB</totalSizeCap>-->
</rollingPolicy>
<!--日志输出编码格式化-->
<encoder>
<charset>UTF-8</charset>
<pattern>%d [%thread] %-5level %logger{36} %line - %msg%n</pattern>
</encoder>
</appender>
除了Error之外的日志都写入info。
具体日志名如下:
当天的就是没有加日期的,有日期的就是日期当天的。
3.3、编写JavaEE每层的代码
其实我们做了两件事,一是添加了数据库配置,二是添加了日志(可选),那么我们就可以编写Spring、Spring MVC、Spring Data JPA的代码了,环境这就好了,剩下代码了。
我们demo的数据库sql如下:
CREATE TABLE `demo` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`type` int(11) DEFAULT NULL,
`desc` varchar(200) DEFAULT NULL,
`value` decimal(9,2) DEFAULT NULL,
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8;
bean如下:
@Entity()
@Table(name = "demo", schema = "boot", catalog = "")
@DynamicInsert()//动态生成插入语句的值
@DynamicUpdate()//动态生成更新语句的值
public class DemoEntity {
private long id;
private Integer type;
private String desc;
private BigDecimal value;
private Date createTime;
private Date updateTime;
@Id
@Column(name = "id")
@GeneratedValue(strategy=GenerationType.AUTO) //主键生成策略
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@Basic
@Column(name = "type")
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
@Basic
@Column(name = "[desc]")
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Basic
@Column(name = "[value]")
public BigDecimal getValue() {
return value;
}
public void setValue(BigDecimal value) {
this.value = value;
}
@Basic
@Column(name = "create_time" , columnDefinition="DATETIME")
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Basic
@Column(name = "update_time" , columnDefinition="DATETIME" )
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DemoEntity that = (DemoEntity) o;
return id == that.id &&
Objects.equals(type, that.type) &&
Objects.equals(desc, that.desc) &&
Objects.equals(value, that.value) &&
Objects.equals(createTime, that.createTime) &&
Objects.equals(updateTime, that.updateTime);
}
@Override
public int hashCode() {
return Objects.hash(id, type, desc, value, createTime, updateTime);
}
}
这里使用idea的hiberante插件生成基础注解,修改了一下。看到sql有两个 sql关键字 desc和value所以@Column(name = “[value]”)在name的值加了“[”和“]”,还添加了@DynamicInsert()和@DynamicUpdate()让sql的create_time和update_time为空的时候能不被更行,使用数据库默认值。
dao层如下:
public interface DemoRepository extends JpaRepository<DemoEntity,Long> {
List<DemoEntity> findByDesc(String desc);
}
写个接口继承JpaRepository,接口的两个泛型,一个是bean的类型,一个主键的类型,JpaRepository是Spring Date JPA的类,还有很多关键字用方法名构建sql查询,具体自己去了解,JpaRepository提供了许多默认的方法,还是很方便的。
service层如下:
@Service
public class DemoService {
private final Logger logger = LoggerFactory.getLogger(DemoService.class);
@Autowired
private DemoRepository demoRepository;
public List<DemoEntity> doSomething(){
logger.debug("debug...");
logger.info("info...");
logger.warn("warn...");
logger.error("error...");
DemoEntity demo =new DemoEntity();
demo.setDesc("test log");
demo.setValue(new BigDecimal(666));
demo.setType(0);
demo.setCreateTime(Calendar.getInstance().getTime());
demo.setUpdateTime(Calendar.getInstance().getTime());
demoRepository.save(demo);
return demoRepository.findAll();
}
}
直接在service层注入dao层接口即可用,有点像mybatis的接口。
controller层如下:
@RestController
public class DemoController {
@Autowired
public DemoService service;
@RequestMapping("/")
public Object index(){
return service.doSomething();
}
}
普通controller而已。
DemoApplication:
@SpringBootApplication
@ComponentScan(value = "com.example")//扫描不同于当前包的注解
@EnableJpaRepositories(value = "com.example")//扫描不同于当前包的dao层
@EntityScan(value = "com.example")//扫描不同于当前包的Entity
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
如果你建包不在Application本包或者子包,那就添加那三个注解的吧。不添加找不到异构包的这些类。后面我把DemoApplication提到com.example了。应该不加注解就能找到了。
参考博客:
Spring Boot 日志配置方法(超详细)
数据表表名或字段名为SQL关键字时Hibernate解决方案
spring boot 日志输出到 log.path_IS_UNDEFINED目录
还有一些参考博客没有记下来。
最后给出此demo源码:https://gitee.com/1099764422/BootDemo