【学习笔记】SpringBoot之初识篇(库存)

242 阅读8分钟

深入学习spring-boot

深入学习springboot之无敌诀窍--查文档spring.io/projects/sp…

1.一天一个开发小技巧之---Lombok

第一步:引入依赖

<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
</dependency>

第二步:idea中下载插件(切记搜索的时候要搜索Lombok plugin )

lombok使用:

@Data:

自动生成getter和setter方法(在编译的时候生成,代码中不体现)

@ToString

自动生成tostring方法

@AllArgsConstructor

全参构造器

@NoArgsConstructor

无参构造器

@EqualsAndHashCode

重写hashcode

@slf4j

里面带有一个log.info("内容");,可以打印信息,用于测试;

2.一天一个开发小技巧之---dev-tools

自动重启项目(热更新项目);本人觉得没什么用,所以不过多的描述了(我是菜鸡,只是我不会用罢了)。

还是过多的描述一下

首先,我们引入devtools这个依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
</dependency>

然后,我们需要配置一下

<build>
    <finalName>Spring_cloud</finalName>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <fork>true</fork>
          <addResources>true</addResources>
        </configuration>
      </plugin>
    </plugins>
  </build>

再然后,我们使用ctrl + shift + alt + /进入 mainintenance 选择registery,然后勾选如下图

image-20210706162146324

最后重启idea,即可生效

3.简单功能分析

3.1静态资源的访问

只要静态资源放在类路径下的:/static 或者/public 或者 /resources或者/META-INF/resources;那么只需要访问当前项目的根路径+静态资源名(即使静态资源路径改变,也是根路径加上【前缀】+静态资源名)。

原理:请求进来会先去controller查找处理,否则就会去静态资源路径下查找处理。

可以改变静态资源的类路径:

`resources:`
   static-locations: classpath:/文件夹/

(可以更改多个,[路径1,路径2,,])

3.2静态资源访问前缀
spring:
	mvc:
		static-path-pattern: /res/**

当前项目+ static-path-pattern+ 静态资源名 =静态资源文件夹下的资源【会导致默认欢迎页面失效,也会影响favicon功能】

3.3、欢迎页的支持
3.3.1静态资源路径下放一个index.html

​ 配置静态资源路径支持,但是如果配置了静态资源前缀就会导致不能被默认访问(底层仍然只有/**下的index.html但是由于静态资源路径路径有了前缀,所以访问不到了)。

3.3.2controller能处理/index
3.4、自定义favicon

将图标放在静态资源路径下,就会自动作为网站图标(仍然会受到静态资源前缀的影响)。

3.5静态资源配置原理

springboot启动时默认加载xxxAutoConfiguration类(springbootApplication中包含这个注解)

springMVC功能的自动配置类WebMvcConfiguration

4、请求参数的处理

4.1请求映射

@xxxMapping;

rest风格支持(使用http请求方式来表示对资源的操作)

对用户的操作统一使用/user路径,通过请求方法的不同来区分不同的操作 : GET--获取用户;DELETE--删除用户; PUT--修改用户; POST--保存用户;

​ 实现的核心是Filter;HiddenHttpMethodFilter

​ 用法:1.表单method = post,隐藏域_method=put;

​ 2.springboot手动开启

spring:
  mvc:
    hiddenmethod:
	  filter:
	    enabled: true
@Bean
	@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
		return new OrderedHiddenHttpMethodFilter();
}

rest原理(表单提交的时候):

​ 表单提交需要带上_method=put/DELETE(通常是隐藏的hidden)

​ 请求过去在底层被HiddenHttpMethodFilter拦截,

​ 查看请求正常,是不是post

​ 获取到_method的值(支持put,delete方式)

​ 原生的request(post)请求,包装模式requestwrapper则重写了这个getMethod方法,返回的是传入的请求方法

​ 过滤器链放行的时候用wrapper,以后的方法调用getMethod是调用requestwrapper的。

以上只支持表单提交。如果是客户端(postman)发送请求则可以直接发送put和delete请求。

所有请求映射都保存在了handlermapping中,然后从前到后的到handlermapping中去查找。最先查找的是requestmapping,然后是welcomemapping,之后还有三个handlermapping。

5、请求参数处理注解

@PathVariable:路径变量,通过路径上变量的不同,来获取不同的传递参数,从而获取到不同的信息。
@RequestHeader:获取请求头,获取到请求头里面的一些参数,支持获取全部的请求头,用map封装。
@ModelAttribute:
@RequestParam:获取参数。
@MaxtriVariable:矩阵变量(可以用来解决cookie失效的问题)

同时需要依赖路径变量(路径变量就是矩阵变量开始的地方),springboot默认是关闭矩阵变量的(默认将分号后面的内容扔掉)。两种方法开启(具体看代码)一、重写路径匹配方法configurePathMatch

二、写一个webmvcConfigutor组件添加到容器中,然后重写里面的configurePathMatch方法。

@CookieValue:获取cookie,当用string接受的时候获取的是cookie的值,当声明一个cookie接受的时候获取的就 cookie,然后调用方法获取cookie的名字和值。
@RequestBody:获取请求体
请求参数处理的原理
  1. handlerMapping中找到处理请求的handler(controller.method())

  2. 位当前handler找到一个适配器 HandlerAdapter

    0- 支持方法注解@RequestMapping

    1- 支持函数式变成的

​ 3.执行目标方法

​ 4.参数解析器(确定每一个目标方法的每一个参数的值是什么)

​ 当前解析器是否支持解析

​ 5.返回值处理器

复杂参数

Map,Model里面的数据就是放在request的请求域中的

Map<String,Object> map,Model model,HttpServletRequest request都是给request中放数据
数据绑定:

​ 自定义类型参数,使用的是ServletModelAttributeMethodProcessor这个参数处理器处理。(以后补学:自定义数据绑定方式)

数据响应

内容协商

根据客户端接收能力的不同,返回不同类型的数据

可以开启参数形式的返回数据格式

spring:
  mvc:
  contentnegotiation:
    favor-parameter: true  #开启请求参数内容协商模式

http://localhost:8888/saveuser?format=json

引入依赖

<!--支持xml数据返回格式-->
<dependency>   	     		   						<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>

测试返回类型,只需修改请求头中的accept字段的值。告诉服务器,客户端能接收的数据格式

原理:

​ 1、判断当前响应头中是否已经有了确定的媒体类型

​ 2、获取客户端支持的内容类型。(Accept请求头【application/xml】)

​ 3、便利循环当前所有的MessageConverter,看谁能支持操作这个对象。

​ 4、找到支持操作返回类型的converter,吧converter支持的媒体类型统计出来

​ 5、客户端需要哪种(application/xml)服务端的能力【10种,json,xml,等】

​ 6、进行内容协商的最佳匹配媒体类型

视图解析与模板引擎

模板引擎--thymeleaf(现代化服务端的Java模板引擎,类似jsp,不适合高并发)

引入 依赖

<!--现代化服务端模板引擎-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

自动配置好了themeleaf。

页面开发

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title >Title</title>
</head>
<body>
    <h1 th:text="${msg}">你好</h1>
<h2>
    <a href="http://www.baidu.com" th:href="${link}">去百度</a>
    <a href="http://www.baidu.com" th:href="@{link}">去百度</a>
</h2>
</body>
</html>

@ {} 和$ {}的区别

前者是将取得的值拼接到路径或者其他数据后面,后者是将值赋值给其他属性。

拦截器原理

1.根据当前请求,找到所有能处理请求的handler以及handler的所有拦截器

2.先来顺序执行所有拦截器的prehandle方法

​ 1.如果当前拦截器prohandler返回未true。则执行下一个拦截器。

​ 2.如果当前拦截器返回false, 倒叙执行所有已经执行了的拦截器的 aftercompetition;

3.如果任何一个拦截器返回false。直接跳出不执行目标方法。】

4.所有拦截器都返回true。执行目标方法。

5.倒序执行所有拦截器的posthandle方法

6.只要前面出现异常都会触发aftercompetition;

7.页面渲染完成后也都倒序触发aftercompetition;

public class JWTInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws BusinessException {
        String token = request.getHeader("token"); //获取请求头令牌
        try {
            JWTUtils.verifyToken(token);
        } catch (SignatureVerificationException e) {
            throw new BusinessException(EmBustinessError.PARAMETER_VALIDATION_ERROR, "无效签名");
        } catch (TokenExpiredException e) {
            throw new BusinessException(EmBustinessError.PARAMETER_VALIDATION_ERROR, "token过期");
        } catch (AlgorithmMismatchException e) {
            throw new BusinessException(EmBustinessError.PARAMETER_VALIDATION_ERROR, "算法不一致");
        } catch (Exception e) {
            throw new BusinessException(EmBustinessError.PARAMETER_VALIDATION_ERROR, "token无效");
        }
        return true;
    }
}

@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
//        registry.addInterceptor(new LoginInterceptor())
//                .addPathPatterns("/**")
//                .excludePathPatterns("/user/**");
        registry.addInterceptor(new JWTInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/user/**");
    }
}

文件上传

补一个前段知识:多文件上传在表单中添加Multiple就行

后端通过@RequestPart("photo") MultipartFile file【单文件形式】

多文件形式@RequestPart("photos") MultipartFile[] files进行接收。

由于springboot限制了文件上传的大小,所以需要手动设置文件上传的参数

spring:
  servlet:
    multipart:
      max-file-size: 10MB #文件上传的单个不超过10MB
      max-request-size: 100MB #总上传文件不能超过100MB

异常处理

原生组件的注入

@servletcomponentscan(basePackages="com.zero"):指定原生servlet组件放在哪里。

@webServlet(urlPatterns="/my"):效果:直接响应,没有经过拦截器

@webFilter(urlpatterns={"/css/","/images/"}):指

@WebListener

@WebServlet(urlPatterns = "/my")
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }
}


@Slf4j
@WebListener //项目启动监听器
public class Mylistener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        log.info("项目启动");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        log.info("项目销毁");
    }
}


@Slf4j
@WebFilter("/file/upload") //制定拦截路径
public class MyFilter extends BaseController implements Filter{
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("myfilter初始化完成");
    }
    @SneakyThrows
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
        log.info("工作");
    }

    @Override
    public void destroy() {
        log.info("销毁");
    }
}






方式2:

@Configuration(proxyBeanMethods = true) //有组件依赖
public class MyRegisConfig {
    @Bean
    public ServletRegistrationBean myServlet() {
        MyServlet myServlet = new MyServlet();

        return new ServletRegistrationBean(myServlet,"/file/upload");
    }
    @Bean
    public FilterRegistrationBean myFilter() {
        MyFilter myFilter = new MyFilter();
//        return new FilterRegistrationBean(myFilter,myServlet());//拦截servlet路径
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter); //自定义拦截路径
        filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/css/*"));
        return filterRegistrationBean;
    }
    @Bean
    public ServletListenerRegistrationBean myListenler() {
        Mylistener myListener = new Mylistener();
        return new ServletListenerRegistrationBean(myListener);

    }
}

定制化原理

定制化常见方式

1、修改配置文件

2、xxxxCustomizer;

3、编写自定义的配置类 xxxConfiguration + @Bean替换、增加容器中默认组件;

4、实现webmvcconfigurer

5、@EnableWebMvc + WebMvcConfirurer --@Bean 可以全面接管springMVC,所有的规则都需要自己配置,