SpringBoot学习笔记2 - 20181128

一.Springboot常见错误总结

  1. 控制台乱码问题(插件启动,控制台乱码问题)
    在pom文件,springboot插件启动中,增加如下(一些虚拟机方法)
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <!-- spring-boot:run 中文乱码解决 -->
    <configuration>
        <fork>true</fork>
        <!--增加jvm参数-->
        <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>springloaded</artifactId>
            <version>1.2.5.RELEASE</version>
        </dependency>
    </dependencies>
</plugin>
  1. 无法自动注入问题
    ①.包扫描错误,@MapperScan指定错误 或 @ComponentScan入口类位置错误
    ②.Mapper文件错误,dao的实现类无法创建,导致无法注入
  2. yml文件格式错误
  3. springboot的pom文件中引入多余jar包
  4. springboot的版本问题(springboot 2.0 使用 spring 5.x)

二.Springboot自带日志

  • 默认使用 logback,相比log4j更轻量级,无需引入依赖或jar
  • 导入logback.xml 定制显示信息
  • 日志 (面试关键点)
  1. 级别

OFF > FATAL> ERROR > WARN > INFO > DEBUG > TRACE > ALL

  • OFF Level是最高等级的,用于关闭所有日志记录。

  • FATAL Level指出每个严重的错误事件将会导致应用程序的退出。

指出每个严重的错误事件将会导致应用程序的退出。这个级别比较高了。重大错误,这种级别你可以直接停止程序了。

  • ERROR Level指出虽然发生错误事件,但仍然不影响系统的继续运行。

指出虽然发生错误事件,但仍然不影响系统的继续运行。打印错误和异常信息,如果不想输出太多的日志,可以使用这个级别。

  • WARN Level表明会出现潜在错误的情形。

  • INFO Level表明 消息在粗粒度级别上突出强调应用程序的运行过程。

消息在粗粒度级别上突出强调应用程序的运行过程。打印一些你感兴趣的或者重要的信息,这个可以用于生产环境中输出程序运行的一些重要信息,但是不能滥用,避免打印过多的日志。

  • DEBUG Level指出细粒度信息事件对调试应用程序是非常有帮助的。

  • TRACE Level较低的日志级别,一般不会使用。

  • ALL Level是最低等级的,用于打开所有日志记录。

    扫描二维码关注公众号,回复: 4422387 查看本文章

ps:log4j建议只使用四个级别

  1. 两个种类
    ①.根日志:项目级别日志,项目中所有指定的信息都会被日志展示出来。
    ②.子日志:包级别/类级别的日志,获取指定包或类的日志信息。
  • logback日志框架使用
    logback.xml (resources根目录下)
<?xml version="1.0" encoding="UTF-8" ?>
<!--配置项-->
<configuration>
    <!-- appender:日志如何做展示的配置 name:展示配置的别名 class:日志如何做展示-->
    <appender name="out" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 展示布局 -->
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern> [%p] %d{yyyy-MM-dd HH:mm:ss} %m %n</pattern>
        </layout>
    </appender>

    <!-- 根日志 -->
    <root level="ERROR">
        <appender-ref ref="out"/>
    </root>
    
    <!-- 子日志 使用根日志的展示配置-->
    <logger name="com.abc.dao" level="DEBUG"/>
</configuration>

三.Springboot的热部署

  • 热部署是什么?
    大家都知道在项目开发过程中,常常会改动页面数据或者修改数据结构,为了显示改动效果,往往需要重启应用查看改变效果,其实就是重新编译生成了新的 Class 文件,这个文件里记录着和代码等对应的各种信息,然后 Class 文件将被虚拟机的 ClassLoader 加载。
    而热部署正是利用了这个特点,它监听到如果有 Class 文件改动了,就会创建一个新的 ClaassLoader 进行加载该文件,经过一系列的过程,最终将结果呈现在我们眼前。
  1. 使用 Spring Loaded
  2. 使用 spring-boot-devtools
  3. jrebel插件
    要求:springboot项目,电脑配置好
    原理:
    java编译,使用类加载器,编译成class文件
    jrebel使用两个类加载器,一个在文件运行时生效,一个在代码变动时类加载器生效

四.Springboot中面向切面编程(AOP)

  • 回顾spring基于注解的aop开发(spring 4 提出概念,纯注解开发)
  1. 引入aop注解依赖
		<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.7.1</version>
		</dependency>
  1. 通知类上加上@Aspect,指定类为通知类
    @Around(execution(* com.baizhi.service..(…))) 指定方法为环绕通知方法
  • springboot基于注解的aop开发
  1. 引入依赖
	<!-- Springboot的AOP支持 -->
    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
  1. 开发通知类
    常用注解:
@Configuration
@Component

@Aspect	//作用是把当前类标识为一个切面供容器读取
@Before	//标识一个前置增强方法,相当于BeforeAdvice的功能
@After	//final增强,不管是抛出异常或者正常退出都会执行
@Around	//环绕增强,相当于MethodInterceptor

@AfterReturning	//后置增强,相当于AfterReturningAdvice,方法退出时执行
@AfterThrowing	//异常抛出增强,相当于ThrowsAdvice

示例代码:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//使用在哪里:方法生效
@Target({ElementType.METHOD})
//什么时候生效
@Retention(RetentionPolicy.RUNTIME)
public @interface AspectAnnotion {	//自定义注解
    public String value() default "no search method~~~";

}
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;

//@Component
@Configuration  //开启Spring相关自动配置
@Aspect         //指定类为通知类
public class AspectDemo {

    @Pointcut("execution(public * com.abc.service.*.*(..))")
    public void pointCut(){
    }

    /**
     * @Before 前置通知
     * @param joinPoint
     */
    @Before("execution(* com.abc.service.*.*(..))")
    public void before(JoinPoint joinPoint){
        System.out.println(joinPoint.getArgs());    //获取参数
        System.out.println(joinPoint.getTarget());  //获取目标对象
        System.out.println(joinPoint.getSignature().getName()); //获取方法名
        System.out.println("------------this is before-------------");
    }

    /**
     * @Around 环绕通知
     * @param proceedingJoinPoint
     * @return
     */
    @Around(value = "@annotation(com.baizhi.aspect.AspectAnnotion)")
    public Object around(ProceedingJoinPoint proceedingJoinPoint){
        //获取方法上注解
        //拿到方法method
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        Method method = signature.getMethod();
        //拿到类对象 反射
        AspectAnnotion aspectAnnotion = method.getAnnotation(AspectAnnotion.class);
        //通过反射拿到实例 调用方法 拿到自定义的方法名
        String name = aspectAnnotion.value();

        System.out.println(proceedingJoinPoint.getArgs());    //同joinPoint

        try {
            //前置

            Object proceed = proceedingJoinPoint.proceed();     //放行目标方法

            //后置

            return proceed;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            return null;
        }
    }

    /**
     * @After 后置通知
     * @param joinPoint
     */
    @After("pointCut()")
    public void after(JoinPoint joinPoint) {
    }
}

Proceedingjoinpoint 和 JoinPoint 的关系?
环绕通知=前置+目标方法执行+后置通知,proceed方法就是用于启动目标方法执行的。

环绕通知 ProceedingJoinPoint 执行proceed方法的作用是让目标方法执行,这也是环绕通知和前置、后置通知方法的一个最大区别。

Proceedingjoinpoint 继承了 JoinPoint 。是在JoinPoint的基础上暴露出 proceed 这个方法。proceed很重要,这个是aop代理链执行的方法。

图2
暴露出这个方法,就能支持 aop:around 这种切面(而其他的几种切面只需要用到JoinPoint,这跟切面类型有关), 能决定是否走代理链还是走自己拦截的其他逻辑。建议看一下JdkDynamicAopProxy的invoke方法,了解一下代理链的执行原理。

五.Springboot中拦截器的实现

  • 回顾springMVC中如何实现拦截器
  1. 实现HandlerInterceptor接口,覆盖preHandle(进入前)、postHandle(跳转前)、afterCompletion(跳转后)
  2. springmvc.xml中配置
		<!--配置拦截器示例 student-->
		<mvc:interceptors>
			<mvc:interceptor>
				<mvc:mapping path="/**"/>
				<mvc:exclude-mapping path="/user/*"/>
				<mvc:exclude-mapping path="/vcode/*"/>
				<bean class="com.abc.interceptor.InterceptorController"/>
			</mvc:interceptor>
		</mvc:interceptors>
  • springboot中实现拦截器
  1. 实现一个自定义拦截器
  2. 书写配置类 extends WebMvcConfigurerAdapter
@EnableWebMvc
@Configuration	//或者 @SpringBootConfiguration
public class InterceptorConfig extends WebMvcConfigurerAdapter {
	//类似DI注入
    @Bean
    InterceptorController localInterceptor() {
        return new InterceptorController();
    }
    //覆盖springboot中的默认拦截器方法
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(localInterceptor())
        		.addPathPatterns("/menu/*")		//拦截哪些
                .excludePathPatterns("/user/*","/vcode/*");	 //不拦截哪些
        
        super.addInterceptors(registry);
    }
}

注意:存在静态资源丢失问题。。。

六.Springboot中上传下载

  • 在yml文件中,修改上传文件大小限制
spring:
   http:
    multipart:
      enabled: true
      max-file-size: 30MB      #上传文件限制大小
      max-request-size: 30MB  #限制文件大小
  • 上传几乎没有什么变化
  • 下载,使用springboot内置FileCopyUtils.copy 方式
@RequestMapping("/download")
    @ResponseBody
    public void download(String filename, HttpServletRequest request, HttpServletResponse response) throws IOException {
        //获取文件路径
        String realPath = request.getSession().getServletContext().getRealPath("/upload");
        //找到文件,获取输入流
        File file = new File(realPath, filename);
        FileInputStream fileInputStream = new FileInputStream(file);
        //获取响应类型
        String substring = filename.substring(filename.lastIndexOf("."));
        //设置响应类型
        response.setContentType(substring);
        //设置响应头
        response.setHeader("Content-Disposition", "attachment;fileName=" + filename);
        //获取输出流
        ServletOutputStream outputStream = response.getOutputStream();
        //文件Copy
        FileCopyUtils.copy(fileInputStream,outputStream);
    }

补充.我的后期项目.yml

server:
  port: 9090
  context-path: /cmfz
  jsp-servlet:
    init-parameters:
      development: true #开启jsp的热部署配置
  tomcat:
    max-http-post-size: -1

spring:
  mvc:
    view:
      prefix: /
      suffix: .jsp
  profiles:
    active: dev #激活哪个文件生效
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource #指定数据源
    driver-class-name: com.mysql.jdbc.Driver #指定驱动
    url: jdbc:mysql://localhost:3306/abc?characterEncoding=UTF-8 #指定url
    username: root
    password: root
  jackson:
    date-format: "yyyy-MM-dd" #适用responseBody时,设置全局日期格式
    time-zone: "GMT+08" #设置时区
  http:
    multipart:
      enabled: true
      max-file-size: 30MB      #上传文件限制大小
      max-request-size: 30MB  #限制文件大小

mybatis:
  mapper-locations: classpath:com/baizhi/mapper/*Mapper.xml #指定mapper配置文件位置
  type-aliases-package: com.abc.pojo #指定起别名的包

数据源测试

	@Autowired
    DataSourceProperties dataSourceProperties;
    @Autowired
    ApplicationContext applicationContext;

    @Test
    public void testttt() throws SQLException {
        DataSource dataSource = applicationContext.getBean(DataSource.class);
        System.out.println(dataSource.getConnection());
    }

猜你喜欢

转载自blog.csdn.net/weixin_42838993/article/details/84679548