SpringBoot学习笔记

SpringBoot 学习笔记


SpringBoot 介绍:

  • 该框架使用了特定的方式进行配置,从而要求不需要定义模板化的配置。
  • 通过集成大量的框架使得依赖包的版本冲突,以及引用的不稳定性等问题得到了很好的解决。
  • 简化了配置,不需要太多的xml配置文件。

SpringBoot 项目创建:

  • 通过 IDEA 创建。

  • 通过 网站创建。

    • https://spring.io/

SpringBoot AOP 思想的使用:

  • 使用 AOP 的思想进行编程
    • AOP 是一种程序设计思想,与语言无关,面向切面编程,将通用的逻辑从业务逻辑值分离出来。
    • 编程思想:
      • AOP 面向切面编程
      • OOP 面向对象编程
      • POP 面向过程编程
  • 引入依赖

    org.springframework.boot
    spring-boot-starter-aop

  • 使用 AOP 的思想进行日志记录

    • 引入注解: @Aspect @Component
@Aspect
@Component
public class HttpAspect {
    private final static Logger logger = LoggerFactory.getLogger(HttpAspect.class);


    @Pointcut("execution(public * com.example.luckymoney.controller.*.*(..))")
    public void log() {
    }

    @Before("log()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //url
        logger.info("url={}", request.getRequestURL());
        //method
        logger.info("method={}", request.getMethod());
        //ip
        logger.info("ip={}", request.getRemoteAddr());
        //类方法
        logger.info("class_method={}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        //参数
        logger.info("args={}", joinPoint.getArgs());
    }

    @After("log()")
    public void doAfter() {
        logger.info("\n");
    }

    @AfterReturning(returning = "object", pointcut = "log()")
    public void doAfterReturning(Object object) {
        logger.info("response={}", object.toString());
    }
}


SpringBoot 整合 logback 日志:

  • logback 帮助文档

    • 参考文档链接: http://www.logback.cn/
  • 引入依赖


    org.springframework.boot
    spring-boot-starter-parent
    2.2.2.RELEASE

  • 引入 logback-pring.xml 配置文件

    • 使用 logback-spring.xml 而不是使用 logback.xml 的原因:
          因为带spring后缀的可以使用这个标签。



    logback
    

    
    
    
    
    
    
    

    
    
        
            ${CONSOLE_LOG_PATTERN}
            
            UTF-8
        
        
            
                %d-%msg%n
            
        
    

    
    
        log_info.log
        
        
            %d - %msg%n
            UTF-8
        

        
        
            logInfo.%d{yyyy-MM-dd}.log
            30
            10KB
        
        
        
            ERROR
            DENY
            ACCEPT
        
    


    
        log_error.log
        
            ERROR
        
        error
            
                %d - %msg%n
            
            UTF-8
        
        
        
            
            logError.%d{yyyy-MM-dd}.log
            
            30
            10KB
        
    


    
        
        
        
    


SpringBoot 异常处理:

  • 异常处理的作用:

    •   异常处理提供了处理程序运行时出现的任何意外或者异常情况的方法。增强了代码的可读性,方便了维护者的阅读和理解
  • 异常处理的操作:

    • 自定义一个异常类 : 注意这个类要继承 RuntimeException ,因为只有这个异常才会进行回滚。
    import lombok.Data;
    @Data
    public class MyException extends RuntimeException {
        private Integer code;
        public MyException (Integer code,String message){
            super(message);
            this.code = code;
        }
        public MyException(ResultEnum resultEnum){
            super(resultEnum.getMsg());
            this.code = resultEnum.getCode();
        }
    }
    
    • 自定义一个拦截器
    import com.example.luckymoney.domain.Result;
    import com.example.luckymoney.exception.MyException;
    import com.example.luckymoney.utils.ResultUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @ControllerAdvice
    public class ExceptionHandle {
        private final static Logger logger = LoggerFactory.getLogger(ExceptionHandle.class);
        @ExceptionHandler(value = Exception.class)
        @ResponseBody
        public Result handle(Exception e){
            if(e instanceof MyException){
                MyException myException = (MyException) e;
                return ResultUtils.error(myException.getCode(),myException.getMessage());
            }else{
                logger.error("[系统异常]");
                return ResultUtils.error(-1,"未知错误");
            }
        }
    }
    
    
    import com.example.demo01.pojo.JsonResult;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    // 抛出异常时会被这个类捕获
    @ControllerAdvice
    public class AllExceptionHandler {
        public static final String ERROR_VIEW = "error";
    
        @ExceptionHandler(value = Exception.class)
        public Object errorHandler(HttpServletRequest reqest,
                                   HttpServletResponse response, Exception e) throws Exception {
    
            e.printStackTrace();
    
            if (isAjax(reqest)) {
                JsonResult jsonResult = JsonResult.errorException(e.getMessage());
                return jsonResult;
            } else {
                ModelAndView mav = new ModelAndView();
                mav.addObject("exception", e);
                mav.addObject("url", reqest.getRequestURL());
                mav.setViewName(ERROR_VIEW);
                return mav;
            }
        }
        /**
         * 判断是不是 Ajax 请求
         * */
        public static boolean isAjax(HttpServletRequest httpRequest){
            return  (httpRequest.getHeader("X-Requested-With") != null
                    && "XMLHttpRequest"
                    .equals( httpRequest.getHeader("X-Requested-With").toString()) );
        }
    }
    
    

SpringBoot 使用拦截器:

  • 拦截器的作用

    • 完成特定功能。比如日志记录,登录判断,权限检查等。
    • 拦截器可以让代码通用化并作为可重用的类。
  • 拦截器的实现

    • 使用注解 @Configuration 配置拦截器
    • 继承 WebMvcConfigurerAdapter
    • 重写 addInterceptors 添加需要的拦截器地址
    import com.example.demo01.controller.interceptor.OneInterceptor;
    import com.example.demo01.controller.interceptor.TwoInterceptor;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    @Configuration
    public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
        public void addInterceptors(InterceptorRegistry registry) {
            /**
             * 拦截器按照顺序执行
             */
            registry.addInterceptor(new OneInterceptor()).addPathPatterns("/one/**")
                                                         .addPathPatterns("/two/**");
            registry.addInterceptor(new TwoInterceptor()).addPathPatterns("/two/**")
                    .addPathPatterns("/one/**");
    
            super.addInterceptors(registry);
        }
    }
    
    

SpringBoot 整合异步处理:

  • 异步的作用:

    • 节省程序的运行时间:
      • eg. 发送短信, 发送消息, APP消息推送
  • 异步的实现:

    • 在根目录上添加注解:
    开启异步调用方法
    @EnableAsync
    
    • 实现任务和控制器
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.scheduling.annotation.AsyncResult;
    import org.springframework.stereotype.Component;
    import java.util.concurrent.Future;
    @Component
    public class AsyncTask {
        @Async
        public Future doTask11() throws Exception {
            long start = System.currentTimeMillis();
            Thread.sleep(1000);
            long end = System.currentTimeMillis();
            System.out.println("任务1耗时:" + (end - start) + "毫秒");
            return new AsyncResult<>(true);
        }
    
        @Async
        public Future doTask22() throws Exception {
            long start = System.currentTimeMillis();
            Thread.sleep(700);
            long end = System.currentTimeMillis();
            System.out.println("任务2耗时:" + (end - start) + "毫秒");
            return new AsyncResult<>(true);
        }
    
        @Async
        public Future doTask33() throws Exception {
            long start = System.currentTimeMillis();
            Thread.sleep(600);
            long end = System.currentTimeMillis();
            System.out.println("任务3耗时:" + (end - start) + "毫秒");
            return new AsyncResult<>(true);
        }
    }
    
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import java.util.concurrent.Future;
    @RestController
    @RequestMapping("tasks")
    public class DoTask {
        @Autowired
        private AsyncTask asyncTask;
    
        @RequestMapping("test1")
        public String test1() throws Exception {
            long start = System.currentTimeMillis();
            Future a = asyncTask.doTask11();
            Future b = asyncTask.doTask22();
            Future c = asyncTask.doTask33();
            while (!a.isDone() || !b.isDone() || !c.isDone()) {
                if (a.isDone() && b.isDone() && c.isDone()) {
                    break;
                }
            }
            long end = System.currentTimeMillis();
            String times = "任务全部完成,总耗时:" + (end - start) + "毫秒";
            System.out.println(times);
    
            return times;
        }
    }
    
    

SpringBoot 整合定时任务:

  • 开启定时任务,会自动扫描,在根类上加。在启动 SpringBoot 时会自动执行的
@EnableScheduling 
  • 设置定时任务
    • @Component @Scheduled(cron = "3-30 * * * * ? ")
    • 定时设置链接: http://cron.qqe2.com
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Component;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    @Component
    public class TestTask {
        private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
    
    //    @Scheduled(fixedRate = 3000)
    	@Scheduled(cron = "3-30 * * * * ? ")
        public void reportCurrentTime() {
            System.out.println("现在时间:" + dateFormat.format(new Date()));
        }
    }
    

SpringBoot 测试:

  • 测试 dao:

    import com.nick.hello.dao.UserMapper;
    import com.nick.hello.entity.User;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    import java.util.Iterator;
    import java.util.List;
    @RunWith(SpringRunner.class)
    @SpringBootTest
    @EnableAutoConfiguration
    public class HellospringApplicationTests {
    
        @Autowired
        private UserMapper userMapper;
    
        @Test
        public void selectAllTest() {
            List list = userMapper.selectAll();
            System.out.println(list);
            Iterator iterator = list.iterator();
            int i = 1;
            while (iterator.hasNext()) {
                User user = (User)iterator.next();
                System.out.println(i + " : " + user.getId());
                i++;
            }
        }
    }
    
  • 测试 service:

    import com.example.luckymoney.domain.Luckymoney;
    import com.example.luckymoney.service.LuckymoneyService;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class LuckymoneyServiceTest {
        @Autowired
        private LuckymoneyService luckymoneyService;
    
        @Test
        public void findOneTest(){
            Luckymoney luckymoney = luckymoneyService.findOne(1);
            System.out.println(luckymoney);
        }
    }
    
  • 测试 controller:

    import org.junit.jupiter.api.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    import org.springframework.test.web.servlet.MockMvc;
    import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
    import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
    @RunWith(SpringRunner.class)
    @SpringBootTest
    @AutoConfigureMockMvc
    class LuckymoneyControllerTest {
    
        @Autowired
        private MockMvc mockMvc;
        @Test
        void list() throws Exception {
            mockMvc.perform(MockMvcRequestBuilders.get("/luckymoneys"))
                    .andExpect(MockMvcResultMatchers.status().isOk())
            .andExpect(MockMvcResultMatchers.content().string("abc")); //判断返回内容是否是 abc
        }
    }
    

SpringBoot 整合前端模板:

  • SpringBoot 整合 freemarker:

    • 引入配置
    # freemarker 静态资源配置
    spring.freemarker.template-loader-path=classpath:/templates/
    # 生产环境就改为 true
    spring.freemarker.cache=false
    spring.freemarker.charset=UTF-8
    spring.freemarker.check-template-location=true
    spring.freemarker.content-type=text/html
    spring.freemarker.expose-request-attributes=true
    spring.freemarker.expose-session-attributes=true
    spring.freemarker.request-context-attribute=request
    spring.freemarker.suffix=.ftl
    
    • 引入依赖
    
        org.springframework.boot
        spring-boot-starter-freemarker
    
    
  • SpringBoot 整合 thymeleaf:

    • 引入配置
    # thymeleaf 静态环境配置
    spring.thymeleaf.prefix=classpath:/templates/
    spring.thymeleaf.suffix=.html
    spring.thymeleaf.mode=HTML5
    spring.thymeleaf.encoding=UTF-8
    spring.thymeleaf.servlet.content-type=text/html
    #springboot 官方文档建议我们关闭thymeleaf的缓存
    spring.thymeleaf.cache=false
    
    • 引入依赖
     
        org.springframework.boot
        spring-boot-starter-thymeleaf
    
    

SpringBoot 整合 MyBatis:

  • 添加配置:
# MyBatis 配置
mybatis.type-aliases-package=com.example.demo01.pojo
mybatis.mapper-locations=classpath:mapper/*.xml
mapper.mappers=com.example.demo01.utils.MyMapper
mapper.not-empty=false
mapper.identity=MYSQL

# druid 数据源配置
spring.datasource.url=jdbc:mysql://123.56.25.127:3306/db_leecx?characterEncoding=utf8&useSSL=false
spring.datasource.username=zq
spring.datasource.password=admin
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.initial-size=1
spring.datasource.druid.min-idle=1
spring.datasource.druid.max-active=20
spring.datasource.druid.test-on-borrow=true
spring.datasource.druid.stat-view-servlet.allow=true

# pagehelper 配置
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql
  • 添加依赖:

    com.alibaba
    druid
    1.1.10



    mysql
    mysql-connector-java
    5.1.41



    org.mybatis.spring.boot
    mybatis-spring-boot-starter
    2.0.1



    tk.mybatis
    mapper-spring-boot-starter
    1.2.4



    com.github.pagehelper
    pagehelper-spring-boot-starter
    1.2.12



    org.mybatis.generator
    mybatis-generator-core
    1.3.2
    compile
    true

  • 逆向生成配置和bean:




    
        
        

        
            
        

        
        

        
        

		
        

		
        


		
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
public class GeneratorDisplay {

	public void generator() throws Exception{
		List warnings = new ArrayList();
		boolean overwrite = true;
		//指定 逆向工程配置文件
		File configFile = new File("generatorConfig.xml");
		ConfigurationParser cp = new ConfigurationParser(warnings);
		Configuration config = cp.parseConfiguration(configFile);
		DefaultShellCallback callback = new DefaultShellCallback(overwrite);
		MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
		myBatisGenerator.generate(null);
	} 
	public static void main(String[] args) throws Exception {
		try {
			GeneratorDisplay generatorSqlmap = new GeneratorDisplay();
			generatorSqlmap.generator();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}


SpringBoot 整合 jpa:

  • 添加配置:
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://123.56.25.127:3306/db_luckymoney?characterEncoding=utf-8
    username: zq
    password: admin
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
  • 添加依赖:

    org.springframework.boot
    spring-boot-starter-data-jpa

  • 当以其他条件进行查询时:

    • 在jpa的操作文件中添加方法:
    import com.example.luckymoney.domain.Luckymoney;
    import org.springframework.data.jpa.repository.JpaRepository;
    import java.math.BigDecimal;
    import java.util.List;
    public interface LuckmoneyRespository extends JpaRepository {
        public List findByMoney(BigDecimal money);
    
        public List findByProducer(String producer);
    
        public List findByProducerAndConsumer(String producer,String consumer);
    }
    
    

SpringBoot 整合 redis:

  • 添加配置:
# redis 配置
# redis 数据库索引
spring.redis.database=2
spring.redis.host=123.56.25.127
spring.redis.port=6379
spring.redis.password=123456
# redis 最大连接数
spring.redis.jedis.pool.max-active=1000
# 连接池最大阻塞等待时间 -1 表示没有
spring.redis.jedis.pool.max-wait=-1
# 连接池中最大空闲连接数
spring.redis.jedis.pool.max-idle=10
# 连接池中最小空闲连接数
spring.redis.jedis.pool.min-idle=2
spring.redis.timeout=5000
  • 添加依赖:

    org.springframework.boot
    spring-boot-starter-data-redis

  • 封装redis 的 api:

SpringBoot 热部署:

  • 引入依赖:

    org.springframework.boot
    spring-boot-devtools

  • 热部署快的原因:
    只对修改的类进行了加载,没有对 jar 包进行加载。

SpringBoot 整合 jackson:

  • 例子:

    • @JsonIgnore : 查询时不对该字段进行展示
    • @JsonFormat(pattern = “yyyy-MM-dd hh:mm:ss a”,locale = “zh”,timezone = “GMT+8”) : 按照固定格式进行展示
    • @JsonInclude(JsonInclude.Include.NON_NULL) : 如果字段为空的话,不进行展示
    • @Id @GeneratedValue: 作为主键,自增
    • @Min(value = 1, message = “不能太小了”) : 设置最小值
    • @NotNull(message = “必传”):该信息必填

附两个 SpringBoot 的代码:

  • https://github.com/github3332422/SpringBootDemo01
  • https://github.com/github3332422/SpringBootDemo02

你可能感兴趣的:(SpringBoot学习笔记)