SpringBoot

一、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;
}

 

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值