1、系统环境

IDE:intellij IDEA 2017.3

2、新建项目

2.1、新建项目

springboot 开发环境为什么运行的是生产环境的数据源 springboot开发环境搭建_xml

2.2、选择项目类型

springboot 开发环境为什么运行的是生产环境的数据源 springboot开发环境搭建_配置文件_02

2.3、填写项目信息

这里选默认的Maven Project就行了。

springboot 开发环境为什么运行的是生产环境的数据源 springboot开发环境搭建_配置文件_03

2.4、选择依赖

springboot 开发环境为什么运行的是生产环境的数据源 springboot开发环境搭建_配置文件_04


对应于:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

springboot 开发环境为什么运行的是生产环境的数据源 springboot开发环境搭建_xml_05


对应于:

<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、环境搭建

项目完成后这样子的:

springboot 开发环境为什么运行的是生产环境的数据源 springboot开发环境搭建_配置文件_06

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。

具体日志名如下:

springboot 开发环境为什么运行的是生产环境的数据源 springboot开发环境搭建_xml_07


当天的就是没有加日期的,有日期的就是日期当天的。

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