需求
从今天开始花一些时间来搭建springboot项目,构建的需求
- 初始化springboot的maven项目
- 引入数据源连接mysql数据库
- 引入orm框架
- 基础配置
- 引入分页
- 引入日志
构建项目
- 地址:http://start.spring.io/
- Jdk版本1.8及以上
- 如你所见,项目里面基本没有代码,除了几个空目录外,还包含如下几样东西。
pom.xml:Maven构建说明文件。
DemoApplication.java:一个带有main()方法的类,用于启动应用程序(关键)。
DemoApplicationTests.java:一个空的Junit测试类,它加载了一个使用Spring Boot字典配置功能的Spring应用程序上下文。
application.properties:一个空的properties文件,你可以根据需要添加配置属性。
初始化代码
创建TestController类,添加如下代码。
@RestController
@EnableAutoConfiguration
public class TestController {
@RequestMapping("/")
public String test() {
return "Hello world";
}
}
启动程序
在DemoApplication.java 文件点击右键运行main方法(也可以另外一种启动方式:
mvn spring-boot:run -Dspring.profiles.active=dev
),之后运行http://localhost:8080/就会看到Hello world
了。
- 注意一点:DemoApplication这个启动类必须放在最外层,要不会抱一个错误
Whitelabel Error Page
,详细解释也可以看官网http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#using-boot-structuring-your-code
代码规范
接下来我们做一下代码规范要求,以后都按照这种格式统一书写。
业务分层
- domain层:实体类。
- api层:对外接口。
- service层:业务层。
- dao层:持久层。
- Controller层:控制层。
pom文件配置
以下是基础jar文件:
<dependencies>
<!-- base -->
<dependency>
<groupId>com.lulj</groupId>
<artifactId>bruce-bean</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<!-- spring boot start -->
<!--核心模块,包括自动配置支持、日志和YAM-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--测试模块,包括JUnit、Hamcrest、Mockito-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--支持web的模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--引用AOP-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--启动时启动内置tomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<!-- 集成log-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<!--mapper-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>1.2.4</version>
</dependency>
<!-- 热部署,不用重启 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- 添加freemarker依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- spring boot end -->
<!--spring2.0集成redis所需common-pool2-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<!-- 将作为Redis对象序列化器 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<!-- MySql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 集成druid,使用连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.0</version>
</dependency>
<!-- lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
<!--pagehelper-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
</dependency>
框架配置
在resources目录下新建application.properties或者application.yml配置文件,本文使用properties,添加如下配置:
#公共配置与profiles选择无关
mybatis.typeAliasesPackage=com.example.demo.domain
mybatis.mapperLocations=classpath*:com/example/demo/dao/**/*Mapper.xml
configuration.cacheEnabled=true
configuration.useGeneratedKeys=true
configuration.defaultExecutorType=REUSE
configuration.log-imp=LOGBACK
#驼峰标识
configuration.mapUnderscoreToCamelCase=true
configuration.jdbcTypeForNull=NULL
#sql日志
logging.level.com.example.demo..dao=DEBUG
###########################################开发配置###########################################
#端口
server.port=8080
#项目名称
server.servlet.context-path=/demo
#服务名称
spring.application.name=demo
###mysql驱动配置信息
spring.datasource.url=jdbc:mysql://192.168.179.191:3306/wx?useUnicode=true&useSSL=false&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# 连接池的配置信息
spring.datasource.filters=stat
spring.datasource.maxActive=20
spring.datasource.initialSize=1
spring.datasource.maxWait=60000
spring.datasource.minIdle=1
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=select 'x'
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
poolPreparedStatements=true
spring.datasource.maxOpenPreparedStatements=20
########分页#######
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql
pagehelper.offset-as-page-num=true
pagehelper.row-bounds-with-count=true
引入日志配置
SpringBoot 的日志文件放在resources目录下,在resources目录下新建logback.xml.
logback.xml配置及说明
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2010-2011 The myBatis Team Licensed under the Apache License,
Version 2.0 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
OR CONDITIONS OF ANY KIND, either express or implied. See the License for
the specific language governing permissions and limitations under the License. -->
<configuration>
<contextName>demo</contextName>
<property name="log.name" value="demo" />
<property name="log.dir" value="../logs" />
<appender name="FILEERROR"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.dir}/log_error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.dir}/error/${log.name}-error-%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>2MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<append>true</append>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>[%date{ISO8601}] [%-5level] - [%thread] [%X{requestId}] [%logger] [%X{akkaSource}] - %msg
%rootException %n
</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>error</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="FILEWARN"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.dir}/${log.name}_warn.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.dir}/warn/${log.name}-warn-%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>2MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<append>true</append>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>[%date{ISO8601}] [%-5level] - [%thread] [%X{requestId}] [%logger] [%X{akkaSource}] - %msg
%rootException %n
</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="FILEINFO"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.dir}/${log.name}_info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.dir}/info/${log.name}-info-%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>2MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<append>true</append>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>[%date{ISO8601}] [%-5level] - [%thread] [%X{requestId}] [%logger] [%X{akkaSource}] - %msg
%rootException %n
</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%black() %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight([%-5level]) %cyan([%X{requestId}]) %boldMagenta([%logger]) [%X{akkaSource}] - %cyan(%msg
%rootException %n)
</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
</appender>
<logger name="org.springframework" level="WARN" />
<logger name="org.hibernate" level="WARN" />
<root level="INFO">
<appender-ref ref="FILEERROR" />
<appender-ref ref="FILEWARN" />
<appender-ref ref="FILEINFO" />
<!-- 生产环境将请stdout,testfile去掉 -->
<appender-ref ref="STDOUT" />
</root>
</configuration>
日志统一管理
@Aspect
@Order(-99)
@Configuration
@Slf4j
public class LogConfig {
@Pointcut("execution(* com.example.demo.controller..*.*(..))," +
"execution(* com.example.demo.api..*.*(..))")
public void executionService() {
}
@Before(value = "executionService()")
public void doBefore(JoinPoint joinPoint) {
String requestId = String.valueOf(UUID.randomUUID());
MDC.put("requestId", requestId);
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
log.info("HTTP URL : " + request.getRequestURL().toString());
log.info("HTTP METHOD : " + request.getMethod());
log.info("IP : " + IPAddrUtil.localAddress());
log.info("CLASS METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "."
+ joinPoint.getSignature().getName());
log.info("PARAMS : " + Arrays.toString(joinPoint.getArgs()));
}
@AfterReturning(pointcut = "executionService()", returning = "returnValue")
public void doAfterReturning(Object returnValue) {
log.info("=====>@AfterReturning:The response parameter is:{}", returnValue);
MDC.clear();
}
@Around("executionService()")
public Object timeAround(ProceedingJoinPoint joinPoint) {
long startTime = System.currentTimeMillis();
Object obj = null;
try {
obj = joinPoint.proceed();
} catch (Throwable e) {
log.error("=====>Counts the elapsed time of a method execution to surround notification errors:", e);
}
long endTime = System.currentTimeMillis();
log.info("=====>Processing this request takes time:{} ms", endTime - startTime);
return obj;
}
}
说明
- 本文只做学习参考,如有任何不准确的地方欢迎指正。
- 源码参考 :https://gitee.com/lulongji/springboot-demo.git
- 我的邮箱:
lulongji2011@163.com
版权声明:
本文为博主原创文章,转载请附上原文出处链接和本声明。