一、SpringBoot概述
SpringBoot未来主流
1.敏捷开发(整合任何框架),弊端:封装的太死了,不方便扩展,springboot高版本没有这个问题。
2.无需Tomcat(springboot运行是通过java应用程序运行,实际是jar包),内置Tomcat
3.减少xml配置(没有xml),以配置文件形式,全部只写properties文件
4.SpringCloud+SpringBoot 微服务
5.使用注解
SpringBoot和微服务有什么关联?
目前来说SpringCloud(http接口+rest),基于SpringBoot,web组件封装SpringMVC
之后互联网项目,面向服务架构(SOA)转变成微服务架构
springboot安不安全?安全。
二、创建第一个SpringBoot项目
pom.xml
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
三、SpringBoot提供接口
微服务架构SpringCloud 使用rpc远程调用 协议:http协议+restful风格,SpringCloud核心依赖SpringBoot,SpringBoot依赖web组件是SpringMvc,所有写SpringCloud接口的时候,都是在写SpringMvc,写Controller。
使用SpringBoot写第一个接口(服务)
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* -- @EnableAutoConfiguration 表示注入spring容器,创建Tomcat,默认只扫描当前服务
* -- @RestController 标识该接口全部返回json格式
* Created by yz on 2018/3/19.
*/
@EnableAutoConfiguration
@RestController
public class MyBootController {
@RequestMapping("/index")
public String index(){
return "success";
}
@RequestMapping("/getMap")
public Map<String,Object> getMeg(){
Map<String, Object> result = new HashMap<>();
result.put("errorCode",200);
result.put("errorMsg","成功..");
return result;
}
public static void main(String[] args) {
// 主函数运行springboot项目
SpringApplication.run(MyBootController.class,args);
}
}
四、SpringBoot第二种启动方式
一个应用程序中,只能有一个main,每个Controller中都有main的话,会找不到入口,入口太多了。
controller1:
/**
* -- @EnableAutoConfiguration 表示注入spring容器,创建Tomcat,默认只扫描当前服务
* -- @RestController 标识该接口全部返回json格式
* Created by yz on 2018/3/19.
*/
@RestController
public class MyBootController {
@RequestMapping("/index")
public String index(){
return "success";
}
@RequestMapping("/getMap")
public Map<String,Object> getMeg(){
Map<String, Object> result = new HashMap<>();
result.put("errorCode",200);
result.put("errorMsg","成功..");
return result;
}
}
controller2:
/**
* Created by yz on 2018/3/19.
*/
@RestController
public class IndexController {
@RequestMapping("/indexController")
public String indexController(){
return "indexController";
}
}
启动类:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
/**
* -- @EnableAutoConfiguration 表示注入spring容器,创建Tomcat,默认只扫描当前服务
* -- @ComponentScan 扫包
* -- @SpringBootApplication 表示只要在当前同级包下不用加任何框架注解
* Created by yz on 2018/3/19.
*/
@EnableAutoConfiguration
@ComponentScan("com.simple.springboot.controller")
@SpringBootApplication
public class App {
public static void main(String[] args) {
// 主函数运行springboot项目
SpringApplication.run(App.class,args);
}
}
五、SpringBoot访问静态资源
web开发
在开发Web应用的时候,需要引用大量的js,css,图片等静态资源。
默认配置:
SpringBoot默认提供静态资源目录位置配置于classpath下,目录名需符合如下规则:
/static
/public
/resources
/META-INF/resources
举例:可以在src/main/resources目录下创建static,在该位置放置一个图片文件。启动程序后,尝试访问http://localhost:8080/D.jpg。 如能显示图片,配置成功。
动静分离--后台服务与前台页面图片全部拆开
静态资源做CDN结点加速,比如湖北放一个结点,宽带以最近的去访问服务,节约宽带传输效率。
六、SpringBoot全局捕获异常
什么是全局捕获异常?
web开发的时候,请求返回500,404,不要把这些给客户看,给客户返回一个有好的错误页面。
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;
/**
* 全局捕获异常
* -- @ControllerAdvice 切面
* -- @ResponseBody 返回json格式
* -- @ExceptionHandler 表示需要拦截的异常 aop异常通知
* Created by yz on 2018/3/19.
*/
@ControllerAdvice
public class GlobalExceptionHandler {
/**
* 如果返回json格式,加@ResponseBody 返回页面 返回String类型 返回结果指定500页面
* @return
*/
@ExceptionHandler(RuntimeException.class)
@ResponseBody
public Map<String,Object> resultError(){
Map<String, Object> result = new HashMap<>();
result.put("errorCode",500);
result.put("errorMsg","系统错误!");
return result;
}
}
@RestController
public class IndexController {
@RequestMapping("/indexController")
public String indexController(){
int i=1/0;
return "indexController";
}
}
七、SpringBoot整合Freemarker
SpringBoot整合页面
SpringBoot优先模板引擎,不建议使用jsp。
什么是模板引擎(springboot推荐)?
伪html格式,动态html实现,提高搜索引擎搜索。动态页面静态化。
SpringBoot提供了默认配置的模板引擎主要以下几种:
FreeMarker
Thymeleaf
Velocity
Groovy
Mustache
默认的模板配置路径为:src/main/resources/templates
使用Freemarker模板引擎渲染web视图
pom.xml文件引入
<!-- 引入freeMarker的依赖包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
在src/main/resources/templates目录下 新建index.ftl文件
this is my freeMarker <br>
${name}
<#if sex==1>
男
<#elseif sex==2>
女
<#else>
其他
</#if>
<#list userlist as user>
${user}
</#list>
controller:
/**
* 返回index页面,注解使用@Controller
* 模板引擎文件默认放在resources/templates目录下
* Created by yz on 2018/3/19.
*/
@Controller
public class IndexController {
@RequestMapping("/indexController")
public String indexController(Map<String, Object> result){
System.out.println("IndexController..,index");
result.put("name","小明");
result.put("sex",0);
List<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
result.put("userlist",list);
return "index";
}
}
新建application.properties
springBoot中配置文件命名:要么是bootstarp.yml 要么是 application.properties
Freemarker配置:
########################################################
###FREEMARKER (FreeMarkerAutoConfiguration)
########################################################
spring.freemarker.allow-request-override=false
spring.freemarker.cache=true
spring.freemarker.check-template-location=true
spring.freemarker.charset=UTF-8
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=false
spring.freemarker.expose-session-attributes=false
spring.freemarker.expose-spring-macro-helpers=false
#spring.freemarker.prefix=
#spring.freemarker.request-context-attribute=
#spring.freemarker.settings.*=
spring.freemarker.suffix=.ftl
spring.freemarker.template-loader-path=classpath:/templates/
#comma-separated list
#spring.freemarker.view-names= # whitelist of view names that can be resolved
八、SpringBoot整合JSP视图
SpringBoot整合jsp建项目建war类型的
pom.xml
<groupId>com.springboot.jsp</groupId>
<artifactId>springboot-jsp</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- springboot整合jsp需要的包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
</dependencies>
在application.properties创建以下配置
spring.mvc.view.prefix=/WEB-INF/view/
spring.mvc.view.suffix=.jsp
/**
* 返回index.jsp页面
* Created by yz on 2018/03/19.
*/
@Controller
public class IndexController {
@RequestMapping("/index")
public String index(){
return "index";
}
}
/**
* Created by yz on 2018/03/19.
*/
@ComponentScan("com.springboot.controller")
@EnableAutoConfiguration
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class,args);
}
}
九、springboot整合使用JdbcTemplate
pom.xml 引入
<!-- springboot整合JdbcTemplate-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=1234
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
CREATE TABLE users(
id INT(18) AUTO_INCREMENT,
NAME VARCHAR(32) ,
age INT(18),
PRIMARY KEY(id)
)ENGINE = INNODB CHARSET utf8;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
/**
* Created by yz on 2018/03/19.
*/
@Service
public class UserService {
@Autowired
private JdbcTemplate jdbcTemplate;
public void createUser(String name,Integer age){
jdbcTemplate.update("insert into users(name,age) values(?,?)",name,age);
System.out.println("创建用户成功...");
}
}
import com.simple.springboot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Created by yz on 2018/03/19.
*/
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/createUser")
public String createUser(String name,Integer age){
userService.createUser(name,age);
return "success";
}
}
/**
* -- @EnableAutoConfiguration 表示注入spring容器,创建Tomcat,默认只扫描当前服务
* -- @ComponentScan 扫包
* -- @SpringBootApplication 表示只要在当前同级包下不用加任何框架注解
* Created by yz on 2018/3/19.
*/
@EnableAutoConfiguration
@ComponentScan(basePackages = {"com.simple.springboot.controller","com.simple.springboot.service"})
@SpringBootApplication
public class App {
public static void main(String[] args) {
// 主函数运行springboot项目
SpringApplication.run(App.class,args);
}
}
十、Springboot整合使用Springjpa
Spring-data-jpa 框架封装hibernate
SpringBoot项目整合jdbc框架、jpa、mybatis不会有冲突。
十一、@SpringBootApplication用法
@SpringBootApplication作用:
启动项目、整合常用注解、扫包作用,只能在当前同级包下。所以需要将启动类放在controller包外层。
@SpringBootApplication 整合了: @Configuration + @EnableAutoConfiguration + @ComponentScan
/**
* -- @EnableAutoConfiguration 表示注入spring容器,创建Tomcat,默认只扫描当前服务
* -- @ComponentScan 扫包
* -- @SpringBootApplication 表示只要在当前同级包下不用加任何框架注解
* Created by yz on 2018/3/19.
*/
//@EnableAutoConfiguration
//@ComponentScan("com.simple.springboot.controller")
@SpringBootApplication
public class App {
public static void main(String[] args) {
// 主函数运行springboot项目
SpringApplication.run(App.class,args);
}
}
十二、SpringBoot多数据源拆分思路
springboot整合多数据源(分布式、微服务)
在一个项目中,有多个jdbc连接
多数据源产生的问题:事务的管理
在实际项目中,怎样搭建多数据源 区分数据源
举例:有两个数据源 test01数据库 test02数据库
1.分包结构
com.boot.test01 ---访问test01数据库
dao
service
com.boot.test02 ---访问test02数据库
dao
service
分布式事务解决方案:jta+automatic 传统项目
2.使用注解方式,同一个包
com.boot.test
dao
service
class UserService{
@dataSourcetest01(自定义注解)
public void test01(){
// 操作test01数据库
}
@dataSourcetest02(自定义注解)
public void test02(){
// 操作test02数据库
}
}
十三、SpringBoot整合多数据源实现
注释掉全局捕获异常类GlobalExceptionHandler,方便调错
create database test01;
create database test02;
create table `user` (
`id` int(11) not null auto_increment,
`name` varchar(32) default null,
`age` int(11) default null,
`password` varchar(32) default null,
primary key (`id`)
) engine=innodb default charset=utf8;
application.properties 配置:
### 多数据源 属于自定义的数据源 需要创建代码文件
spring.datasource.test1.slaveDriverClass=com.mysql.jdbc.Driver
spring.datasource.test1.url=jdbc:mysql://localhost:3306/test01?useUnicode=true&characterEncoding=utf-8
spring.datasource.test1.username=root
spring.datasource.test1.password=1234
spring.datasource.test2.slaveDriverClass=com.mysql.jdbc.Driver
spring.datasource.test2.url=jdbc:mysql://localhost:3306/test02?useUnicode=true&characterEncoding=utf-8
spring.datasource.test2.username=root
spring.datasource.test2.password=1234
pom.xml
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.1</version>
</dependency>
创建dasourceConfig配置文件:
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
/**
* -- @Configuration 注入到springboot容器
* -- @Bean 属于自定义数据源
* -- @ConfigurationProperties 读取application.properties配置文件中以"spring.datasource.test1"开头
* -- @Primary 默认的,意思是在众多相同的bean中,优先使用用@Primary注解的bean
* primary secondary
* Created by yz on 2018/3/20.
*/
@Configuration
public class DataSourceConfig {
// @Bean(name = "test1DataSource")
// @Qualifier("test1DataSource")
// @ConfigurationProperties(prefix="spring.datasource.test1")
// @Primary
// public DataSource primaryDataSource() {
// return DataSourceBuilder.create().build();
// }
//
// @Bean(name = "test2DataSource")
// @Qualifier("test2DataSource")
// @ConfigurationProperties(prefix="spring.datasource.test2")
// public DataSource secondaryDataSource() {
// return DataSourceBuilder.create().build();
// }
@Value("${spring.datasource.test1.url}")
private String slaveUrl;
@Value("${spring.datasource.test1.username}")
private String slaveUser;
@Value("${spring.datasource.test1.password}")
private String slavePassword;
@Value("${spring.datasource.test1.driverClassName}")
private String slaveDriverClass;
@Value("${spring.datasource.test2.url}")
private String slaveUrl2;
@Value("${spring.datasource.test2.username}")
private String slaveUser2;
@Value("${spring.datasource.test2.password}")
private String slavePassword2;
@Value("${spring.datasource.test2.driverClassName}")
private String slaveDriverClass2;
@Bean(name = "test1DataSource")
@Qualifier("test1DataSource")
@Primary
public DataSource slave1DataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(slaveDriverClass);
dataSource.setUrl(slaveUrl);
dataSource.setUsername(slaveUser);
dataSource.setPassword(slavePassword);
dataSource.setInitialSize(1);
dataSource.setMaxWait(600000);
dataSource.setMinIdle(1);
dataSource.setTimeBetweenEvictionRunsMillis(60000);
dataSource.setMinEvictableIdleTimeMillis(30000);
dataSource.setMaxActive(250);
dataSource.setValidationQuery("select 1");
dataSource.setTestWhileIdle(true);
dataSource.setTestOnBorrow(false);
dataSource.setTestOnReturn(false);
dataSource.setPoolPreparedStatements(true);
dataSource.setMaxPoolPreparedStatementPerConnectionSize(50);
return dataSource;
}
@Bean(name = "test2DataSource")
@Qualifier("test2DataSource")
public DataSource slave2DataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(slaveDriverClass2);
dataSource.setUrl(slaveUrl2);
dataSource.setUsername(slaveUser2);
dataSource.setPassword(slavePassword2);
dataSource.setInitialSize(1);
dataSource.setMaxWait(600000);
dataSource.setMinIdle(1);
dataSource.setTimeBetweenEvictionRunsMillis(60000);
dataSource.setMinEvictableIdleTimeMillis(30000);
dataSource.setMaxActive(250);
dataSource.setValidationQuery("select 1");
dataSource.setTestWhileIdle(true);
dataSource.setTestOnBorrow(false);
dataSource.setTestOnReturn(false);
dataSource.setMaxPoolPreparedStatementPerConnectionSize(50);
dataSource.setPoolPreparedStatements(true);
return dataSource;
}
@Bean(name = "slave1JdbcTemplate")
public JdbcTemplate primaryJdbcTemplate(@Qualifier("test1DataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean(name = "slave2JdbcTemplate")
public JdbcTemplate secondaryJdbcTemplate(@Qualifier("test2DataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* Created by yz on 2018/3/20.
*/
@Service
public class UserService {
/******指定使用数据源********/
@Autowired
@Qualifier("slave1JdbcTemplate")
private JdbcTemplate jdbcTemplate1;
@Autowired
@Qualifier("slave2JdbcTemplate")
private JdbcTemplate jdbcTemplate2;
@Transactional
public void createUser001(String name,Integer age){
jdbcTemplate1.update("insert into user(name,age) values(?,?)",name,age);
System.out.println("创建用户成功...数据库01");
int i = 1/0;
}
@Transactional
public void createUser002(String name,Integer age){
jdbcTemplate2.update("insert into user(name,age) values(?,?)",name,age);
System.out.println("创建用户成功...数据库02");
//int i = 1/0;
}
}
/**
* 操作数据库test01
* @param name
* @param age
*/
@RequestMapping("/test001")
public void test001(String name,Integer age){
userService.createUser001(name,age);
System.out.println("test001");
}
/**
* 操作数据库test02
* @param name
* @param age
*/
@RequestMapping("/test002")
public void test002(String name,Integer age){
userService.createUser002(name,age);
System.out.println("test002");
}
springboot多数据源:https://blog.csdn.net/qq_35206261/article/details/81778224
十四、SpringBoot事物
SpringBoot整合事务
Spring事务分类:编程事务、声明事务(XML方式、注解方式)
使用注解事务:@Transactional
十五、SpringBoot分布式事物
默认的Spring事务只支持单数据源,而实际上一个系统往往需要写多个数据源,这个时候就需要Spring实现对分布式事务的支持。
/******指定使用数据源********/
@Autowired
@Qualifier("slave1JdbcTemplate")
private JdbcTemplate jdbcTemplate1;
@Autowired
@Qualifier("slave2JdbcTemplate")
private JdbcTemplate jdbcTemplate2;
/**
* 操作两个数据源,异常应同时回滚
* @param name
* @param age
*/
@Transactional
public void createUser001(String name,Integer age){
jdbcTemplate1.update("insert into user(name,age) values(?,?)",name,age);
jdbcTemplate2.update("insert into user(name,age) values(?,?)",name,age);
System.out.println("创建用户成功...数据库01");
int i = 1/0;
}
分布式事务进行管理jta+atomikos
test01和test02数据库的数据源事务注册到第三方 ---- 两段提交协议2pc
pom.xml 引入
<!-- 多数据源事务管理 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
配置地址:http://blog.csdn.net/WI_232995/article/details/78124885
十六、SpringBoot整合日志
log4j.properties
project=datasight
logdir=/home/logs/${project}
### set log levels ###
log4j.rootLogger = info,stdout
# config this project appender,log level:info,error #
log4j.logger.com.ts.report = info,error,bizInfo,bizError
### 控制台输出 ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyy-MM-dd HH\:mm\:ss} %5p %c{1}\:%L - %m%n
# info log everyday file#
log4j.loger.bizInfo = info,bizInfo
log4j.appender.bizInfo=org.apache.log4j.DailyRollingFileAppender
log4j.appender.bizInfo.File=${logdir}/info.log
log4j.appender.bizInfo.layout=org.apache.log4j.PatternLayout
log4j.appender.bizInfo.DatePattern='_'yyyy-MM-dd
log4j.appender.bizInfo.layout.ConversionPattern=%d{yyy-MM-dd HH\:mm\:ss} %5p %c{1}\:%L - %m%n
log4j.appender.bizInfo.Threshold=INFO
#log4j.additivity.bizInfo=false
## error log ##
log4j.loger.bizError = info,bizError
log4j.appender.bizError = org.apache.log4j.DailyRollingFileAppender
log4j.appender.bizError.File = ${logdir}/error.log
log4j.appender.bizError.layout = org.apache.log4j.PatternLayout
log4j.appender.bizError.DatePattern='_'yyyy-MM-dd
log4j.appender.bizError.layout.ConversionPattern =%d{yyy-MM-dd HH\:mm\:ss} %5p %c{1}\:%L - %m%n
log4j.appender.bizError.Threshold = ERROR
#log4j.additivity.error=false
import org.apache.log4j.Logger;
private static Logger logger = Logger.getLogger(IndexController.class);
十七、SpringBootAOP统一处理Web请求
使用AOP打印web请求参数
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Enumeration;
/**
* 使用AOP打印web请求参数
* Created by yz on 2018/03/20.
*/
@Aspect
@Component
public class WebLogAspect {
private Logger logger = Logger.getLogger(getClass());
ThreadLocal<Long> startTime = new ThreadLocal<Long>();
@Pointcut("execution(public * com.simple.springboot.controller..*.*(..))")
public void webLog(){}
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
startTime.set(System.currentTimeMillis());
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
logger.info("####################请求开始#######################");
// 记录下请求内容
logger.info("URL : " + request.getRequestURL().toString());
logger.info("HTTP_METHOD : " + request.getMethod());
logger.info("IP : " + request.getRemoteAddr());
logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
//获取所有参数方法:
Enumeration<String> enu = request.getParameterNames();
while (enu.hasMoreElements()) {
String paraName = enu.nextElement();
logger.info("paraName:"+paraName + "value:" + request.getParameter(paraName));
}
}
@AfterReturning(returning = "ret", pointcut = "webLog()")
public void doAfterReturning(Object ret) throws Throwable {
// 处理完请求,返回内容
logger.info("RESPONSE : " + ret);
logger.info("SPEND TIME : " + (System.currentTimeMillis() - startTime.get()));
logger.info("####################请求结束#######################");
}
}
十八、SpringBoot实现定时任务
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* 定时任务
* -- @EnableScheduling 启动定时任务注解
* Created by yz on 2018/03/20.
*/
@Component
@EnableScheduling
public class ScheduledTasks {
int count =0;
/**
* 5秒执行一次
*/
@Scheduled(fixedRate = 5000)
public void test(){
// 执行任务调度方法
System.out.println("我正在每隔5秒执行一次任务...");
}
/**
* 1秒执行一次
*/
@Scheduled(cron = "0/1 * * * * ?")
public void test1(){
// 执行任务调度方法
count++;
System.out.println("我正在每隔1秒执行一次任务..."+count);
}
}
十九、SpringBoot异步调用
异步调用是相对于同步调用而言的,同步调用是指程序按预定顺序一步步执行,每一步必须等到上一步执行完后才能执行,而异步调用则无需等待上一步程序执行完即可执行。提高程序执行效率,类似mq。
/**
* -- @EnableAsync 启动异步调用注解
* Created by yz on 2018/03/20.
*/
@Component
@EnableAsync
public class AsyncTask {
@Async
public void task1() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
Thread.sleep(1000);
long currentTimeMillis1 = System.currentTimeMillis();
System.out.println("task1任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
}
@Async
public void task2() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
Thread.sleep(2000);
long currentTimeMillis1 = System.currentTimeMillis();
System.out.println("task2任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
}
@Async
public void task3() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
Thread.sleep(3000);
long currentTimeMillis1 = System.currentTimeMillis();
System.out.println("task3任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 异步调用
* Created by yz on 2018/03/20.
*/
@RestController
public class AsyncTaskController {
@Autowired
private AsyncTask asyncTask;
@RequestMapping("/asyncTask")
public String doTask() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
asyncTask.task1();
asyncTask.task2();
asyncTask.task3();
long currentTimeMillis1 = System.currentTimeMillis();
return "task任务总耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms";
}
}
二十、SpringBoot读取配置文件
配置文件中自定义变量:
customParam:123456
读取参数:
@Value("${customParam}")
private Integer customParam;
二十一、SpringBoot区分不同环境
什么是多环境配置?
企业中,分为不同环境配置文件:
测试环境 test
预发布环境 pre
生产环境 online
application.properties 文件拷贝三份,分别命名为:
application-test.properties 定义参数 customParam:111111
application-pre.properties 定义参数 customParam:222222
application-online.properties 定义参数 customParam:333333
application.properties 定义参数 spring.profiles.active=pre 表示读取pre配置文件的参数信息
二十二、SpringBoot修改端口号
server.port:8090
server.context-path:/yz
二十三、SpringBootYML文件
springboot配置文件yml 以后主流 减少配置,减少字符数
application.properties 可以和 application.yml 一起读
application.yml
### 规范:冒号后加空格
server:
port: 8090
context-path: /yz
二十四、SpringBoot打包发布
pom.xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.simple.springboot.App</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
进入到Terminal控制台:maven package
idea 在target文件夹右键 Show in Exploer 进入文件夹
cmd java -jar simple-springboot-1.0-SNAPSHOT.jar 启动项目
二十五、SpringBoot集成Redis
pom.xml
<!-- 引入redis的依赖包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
<version>1.3.5.RELEASE</version>
</dependency>
配置文件:
# REDIS (RedisProperties)
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=0
配置类:
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import java.lang.reflect.Method;
/**
* -- @Configuration 注入到springboot容器
* Created by yz on 2018/03/21.
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
/**
* 生成key的策略
* @return
*/
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
/**
* 管理缓存
*/
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
return rcm;
}
/**
* RedisTemplate配置
*/
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Service;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* 封装redis
* Created by yz on 2018/03/21.
*/
@Service
public class RedisService {
@Autowired
private RedisTemplate redisTemplate;
/**
* 写入缓存
* @param key
* @param value
* @return
*/
public boolean set(final String key, Object value) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 写入缓存设置时效时间
* @param key
* @param value
* @return
*/
public boolean set(final String key, Object value, Long expireTime) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 批量删除对应的value
* @param keys
*/
public void remove(final String... keys) {
for (String key : keys) {
remove(key);
}
}
/**
* 批量删除key
* @param pattern
*/
public void removePattern(final String pattern) {
Set<Serializable> keys = redisTemplate.keys(pattern);
if (keys.size() > 0)
redisTemplate.delete(keys);
}
/**
* 删除对应的value
* @param key
*/
public void remove(final String key) {
if (exists(key)) {
redisTemplate.delete(key);
}
}
/**
* 判断缓存中是否有对应的value
* @param key
* @return
*/
public boolean exists(final String key) {
return redisTemplate.hasKey(key);
}
/**
* 读取缓存
* @param key
* @return
*/
public Object get(final String key) {
Object result = null;
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
result = operations.get(key);
return result;
}
/**
* 哈希 添加
* @param key
* @param hashKey
* @param value
*/
public void hmSet(String key, Object hashKey, Object value){
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
hash.put(key,hashKey,value);
}
/**
* 哈希获取数据
* @param key
* @param hashKey
* @return
*/
public Object hmGet(String key, Object hashKey){
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
return hash.get(key,hashKey);
}
/**
* 列表添加
* @param k
* @param v
*/
public void lPush(String k,Object v){
ListOperations<String, Object> list = redisTemplate.opsForList();
list.rightPush(k,v);
}
/**
* 列表获取
* @param k
* @param l
* @param l1
* @return
*/
public List<Object> lRange(String k, long l, long l1){
ListOperations<String, Object> list = redisTemplate.opsForList();
return list.range(k,l,l1);
}
/**
* 集合添加
* @param key
* @param value
*/
public void add(String key,Object value){
SetOperations<String, Object> set = redisTemplate.opsForSet();
set.add(key,value);
}
/**
* 集合获取
* @param key
* @return
*/
public Set<Object> setMembers(String key){
SetOperations<String, Object> set = redisTemplate.opsForSet();
return set.members(key);
}
/**
* 有序集合添加
* @param key
* @param value
* @param scoure
*/
public void zAdd(String key,Object value,double scoure){
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
zset.add(key,value,scoure);
}
/**
* 有序集合获取
* @param key
* @param scoure
* @param scoure1
* @return
*/
public Set<Object> rangeByScore(String key, double scoure, double scoure1){
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
return zset.rangeByScore(key, scoure, scoure1);
}
}
测试:
@RequestMapping("/testRedis")
@ResponseBody
public String testRedis(){
redisService.set("123456","test-redis");
String redis = (String) redisService.get("123456");
return redis;
}