SpringBoot基础学习

SpringBoot

静态资源

1、静态资源目录

默认情况下,Spring Boot 提供来自类路径中名为/static(或/public/resources/META-INF/resources)的目录或从ServletContext. 它使用ResourceHttpRequestHandler来自 Spring MVC 的,以便您可以通过添加自己WebMvcConfigurer类的addResourceHandlers方法并覆盖该方法来修改该行为。

在独立的 Web 应用程序中,容器中的默认 servlet 也被启用并充当回退,ServletContext如果 Spring 决定不处理它,则从根目录提供内容。大多数情况下,这不会发生(除非您修改默认的 MVC 配置),因为 Spring 始终可以通过DispatcherServlet.

先走controller查找请求路径,如果未找到对应的controller,则查找静态资源

静态资源前缀:spring.mvc.static-path-pattern=/resources/**

默认情况下,资源映射在 上/**(默认无前缀),但您可以使用spring.mvc.static-path-pattern属性对其进行调整。例如,将所有资源重新分配到/resources/**可以实现如下:spring.mvc.static-path-pattern=/resources/**

您还可以使用该spring.web.resources.static-locations属性自定义静态资源位置(用目录位置列表替换默认值)。根 Servlet 上下文路径"/"也自动添加为一个位置。

除了前面提到的“标准”静态资源位置之外,还为Webjars 内容制作了一个特殊情况。/webjars/**如果它们以 Webjars 格式打包,则任何带有路径的资源都从 jar 文件提供。

spring:
  mvc:
    static-path-pattern: /res/** #给静态资源访问路径添加前缀:http://localhost:8080/res/login-logo.png 添加此配置则会导致欢迎页失效,如果配置此项,则需使用模板化欢迎页面,即编写controller来访问
  web:
    resources:
      static-locations: classpath:/res/ #自定义静态资源文件存放的位置,测试发现,虽指定了静态资源文件路径,但是/META-INF/resources/下的文件依旧能够访问
2、欢迎页

Spring Boot 支持静态模板化欢迎页面。它首先index.html配置的静态内容位置中查找文件。如果没有找到,它就会寻找一个index(编写一个controller能处理index请求)模板。如果找到其中之一,它会自动用作应用程序的欢迎页面。

所有的请求映射都在HandlerMapping中

  • SpringBoot自动配置欢迎页的WelcomePageHandlerMapping,访问"/"就能访问到index.html
  • SpringBoot自动配置了默认的RequestMappingHandlerMapping
  • 请求进来,挨个尝试所有的HandlerMapping看是否有请求信息
    • 如果有就找到对应的这个handler
    • 如果没有就是下一个handlermapping
  • 我们如果需要自定义一些handlermapping,就可以自己给容器中放handlermapping

请求参数

@RestController
public class ParameterTestController {

    @GetMapping("/car/{id}/owner/{username}")
    public Map<String, Object> getCar(@PathVariable("id") Integer id,
                                      @PathVariable("username") String username,
                                      @PathVariable Map<String, String> pv,
                                      @RequestHeader("User-Agent") String userAgent,
                                      @RequestHeader Map<String, String> header,
                                      @RequestParam("age") Integer age,
                                      @RequestParam("interests") List<String> interests,
                                      @RequestParam MultiValueMap<String, Object> params){
        Map<String, Object> map = new HashMap<>();
        map.put("id",id);
        map.put("name",username);

        /**
         * @PathVariable
         * If the method parameter is {@link java.util.Map Map&lt;String, String&gt;}
         * then the map is populated with all path variable names and values.
         */
        map.put("pv",pv);

        /**
         * @RequestHeader
         * If the method parameter is {@link java.util.Map Map&lt;String, String&gt;},
         * {@link org.springframework.util.MultiValueMap MultiValueMap&lt;String, String&gt;},
         * or {@link org.springframework.http.HttpHeaders HttpHeaders} then the map is
         * populated with all header names and values.
         */
        map.put("userAgent",userAgent);
        map.put("header",header);

        /**
         * @RequestParam
         * If the method parameter is {@link java.util.Map Map&lt;String, String&gt;} or
         * {@link org.springframework.util.MultiValueMap MultiValueMap&lt;String, String&gt;}
         * and a parameter name is not specified, then the map parameter is populated
         * with all request parameter names and values.
         * http://localhost:8080/car/2/owner/djx?age=20&interests=computer&interests=BBQ&interests=game
         * 使用Map不能接收多选框的多个内容,推荐使用MultiValueMap,会将参数封装成LIst放入MultiValueMap中
         * MultiValueMap封装的内容:"params":{"age":["20"],"interests":["computer","BBQ","game"]}
         */
        map.put("age",age);
        map.put("interests",interests);
        map.put("params",params);

        /**
         * @CookieValue
         * The method parameter may be declared as type {@link javax.servlet.http.Cookie}
         * or as cookie value type (String, int, etc.).
         * Note that with spring-webmvc 5.3.x and earlier, the cookie value is URL
         * decoded. This will be changed in 6.0 but in the meantime, applications can
         * also declare parameters of type {@link javax.servlet.http.Cookie} to access
         * the raw value.
         *通过此注解可以获取Cookie的值,可通过String或Cookie类型参数获取
         */

        /**
         * @RequestBody
         * 当发送的请求是POST时,可以使用该注解获取请求体的内容
         * @RequestBody String content
         */

        /**
         * @RequestAttribute
         * 当进行请求转发时,可以使用此注解获取请求转发携带的数据
         * @RequestAttribute("msg") String msg
         */

        /**
         * @MatrixVariable
         * SpringBoot默认禁用了矩阵变量的功能
         * 需要手动开启:
         * 原理:对于路径的处理--》UrlPathHelper进行解析。
         * 其中removeSemicolonContent方法会移除分号后面的内容
         * 只要编写一个配置类,并实现WebMvcConfigurer接口,再重写configurePathMatch方法
         * @Configuration
         * public class WebConfig implements WebMvcConfigurer {
         *     @Override
         *     public void configurePathMatch(PathMatchConfigurer configurer) {
         *         UrlPathHelper urlPathHelper = new UrlPathHelper();
         *         urlPathHelper.setRemoveSemicolonContent(false);
         *         configurer.setUrlPathHelper(urlPathHelper);
         *     }
         * }
         * 或在配置类中
         * @Bean
         * public WebMvcConfigurer webMvcConfigurer(){
         *     return new WebMvcConfigurer() {
         *         @Override
         *         public void configurePathMatch(PathMatchConfigurer configurer) {
         *             UrlPathHelper urlPathHelper = new UrlPathHelper();
         *             urlPathHelper.setRemoveSemicolonContent(false);
         *             configurer.setUrlPathHelper(urlPathHelper);
         *         }
         *    };
         * }
         *
         * 通过上面的方式进行矩阵变量的开启
         *
         * http://localhost:8080/car/{path;low=34;brand=byd,audi,yd} 矩阵变量
         *
         * /boss/1;age=20/2;age=18
         * @GetMapping("/boss/{bossId}/{empId}")
         * @MatrixVariable(pathVar = "bossId",value = "age") Integer bossAge
         * @MatrixVariable(pathVar = "empId",value = "age") Integer empAge
         *
         * 当cookie被用户禁用后,可以使用矩阵变量的方式将cookie携带在url中
         * /cars/sell/;low=34;brand=byd,audi,yd
         * @GetMapping("/cars/sell")
         * public Map carsSell(@MatrixVariable("low") Integer low, @MatrixVariable("brand" List<String> brand))
         *
         */
        
        return map;
    }


}

参数解析器:HandlerMethodArgumentResolver

决定了@RequestMapping方法的参数的类型

在这里插入图片描述


Servlet API :ServletRequestMethodArgumentResolver
WebRequest
ServletRequest
MultipartRequest
HttpSession
Principal
InputStream 
Reader
HttpMethod
Locale
TimeZone
ZoneId
PushBuilder

以上方法可以在参数中直接使用

复杂参数

MapModel(map、model里面的数据会被放在request的请求域中 相当于 request.setAttribute)、Errors/BindingResult、RedirectAttributes(重定向携带数据)、ServletResponse(response)、SessionStatus、UriComponentsBuilder、ServletUriComponentsBuilder

自定义类型参数 封装POJO:ServletModelAttributeMethodProcessor

在这里插入图片描述

底层利用反射,WebDataBinder(数据绑定器)将请求参数的值绑定到指定的JavaBean里面,创建一个与参数中对应的POJO中的类,利用Converter的实现类实现了将http中携带的文本参数转换为POJO类中对应的属性的类型,并进行正确的属性赋值,这样便实现了从http文本到实体类的封装。

自定义转换器

@Bean
public WebMvcConfigurer webMvcConfigurer(){
    return new WebMvcConfigurer() {
        @Override
        public void addFormatters(FormatterRegistry registry) {
            registry.addConverter(new Converter<String, Pet>() {
                @Override
                public Pet convert(String source) {
                    //将前端传来的字符串进行格式化
                    //阿猫,3
                    if(StringUtils.hasLength(source)){
                        Pet pet = new Pet();
                        String[] split = source.split(",");
                        pet.setName(split[0]);
                        pet.setAge(Integer.valueOf(split[1]));
                        return pet;
                    }
                    return null;
                }
            });
        }
    };
}

SpringMVC官方文档

响应JSON

1、返回值解析器:HandlerMethodReturnValueHandler

在这里插入图片描述

决定了支持的返回值类型

ModelAndView

Model

View

PesponseEntity

ResponseBodyEmitter

StreamingResponseBody

HttpEntity

HttpHeaders

Callable

DeferredResult

ListenableFuture

CompletionStage

WebAsyncTask

标注了@ModelAttribute

标注了@ResponseBody:RequestResponseBodyMethodProcessor(返回值处理器)通过它来处理返回值标注了@ResponseBody注解的方法

再通过消息转换器(HttpMessageConverter),判断能给浏览器返回的数据类型

在这里插入图片描述

内容协商

浏览器(请求头)与服务器(根据请求头内容决定返回给浏览器的数据类型)之间的消息交互

/**
 * Whether a request parameter ("format" by default) should be used to determine
 * the requested media type.
 * 是否应使用请求参数来确定请求的媒体类型。
 * http://localhost:8080/test/person?format=json
 * 上述请求则表明,向服务器请求的是json数据
 * 默认只支持json和xml
 */
private boolean favorParameter = false;

application.yaml配置

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

自定义MessageConverter

实现多协议数据兼容。Json、xml

1、@ResponseBody响应数据出去,调用RequestResponseBodyMethodProcessor处理

2、Processor处理方法返回值。通过MessageConverter处理

3、所有MessageConverter合起来可以支持各种媒体类型数据的操作(读、写)

3、内容协商找到最终的MessageConverter

自定义一个MessageConverter

public class MyConverter implements HttpMessageConverter<Pet> {
    @Override
    public boolean canRead(Class<?> clazz, MediaType mediaType) {
        return false;
    }

    @Override
    public boolean canWrite(Class<?> clazz, MediaType mediaType) {
        return clazz.isAssignableFrom(Pet.class);
    }

    /**
     * 服务器要统计所有MessageConverter都能写出那些内容类型
     * @return
     */
    @Override
    public List<MediaType> getSupportedMediaTypes() {
        return MediaType.parseMediaTypes("application/x-djx");
    }

    @Override
    public Pet read(Class<? extends Pet> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        return null;
    }

    @Override
    public void write(Pet pet, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        String data = pet.getName()+";"+pet.getAge();
        OutputStream body = outputMessage.getBody();
        body.write(data.getBytes(StandardCharsets.UTF_8));
    }
}

在配置类中

@Configuration
public class WebConfig{
    @Bean
    public WebMvcConfigurer webMvcConfigurer(){
        return new WebMvcConfigurer() {
            //添加自定义的MessageConverter
            @Override
            public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
                converters.add(new MyConverter());
            }

            //自定义内容协商策略
            @Override
            public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
                HashMap<String, MediaType> map = new HashMap<>();
                map.put("json",MediaType.APPLICATION_JSON);
                map.put("xml",MediaType.APPLICATION_XML);
                map.put("pet",MediaType.parseMediaType("application/x-djx"));

                ParameterContentNegotiationStrategy parameterStrategy = new ParameterContentNegotiationStrategy(map);
                HeaderContentNegotiationStrategy headerStrategy = new HeaderContentNegotiationStrategy();
                //即支持请求参数携带的媒体类型(上述定义的json、xml、pet),又支持请求头自带的媒体类型
                configurer.strategies(Arrays.asList(parameterStrategy,headerStrategy));
            }
        };
    }
}

最终得到自定义的解析数据,以分号";"分割每一个数据

在这里插入图片描述

文件上传

1、在配置文件中配置上传文件的大小限制

spring:
  servlet:
    multipart:
#      配置文件上传大小限制
      max-file-size: 1000MB
      max-request-size: 10000MB

2、编写控制器

@Slf4j
@Controller
public class FileController {

    @RequestMapping("/")
    public String index(){
        return "index";
    }

    @RequestMapping("/upload")
    public String file(@RequestParam(value = "username") String username,
                       @RequestPart("file") MultipartFile file,
                       @RequestPart("files") MultipartFile[] files,
                       Model model) throws IOException {
        log.info("上传的信息:名字={},headerImg={},headerImg的ContentType={},photos={}",username,file.getOriginalFilename(),file.getContentType(),files.length);
        //指定上传路径
        String path = "C:\\JAVA\\upload";
        //创建相应目录
        File uploadDir = new File(path);
        if (!uploadDir.exists()){
            uploadDir.mkdirs();
        }
        //单文件上传
        if (!file.isEmpty()){
            //保存到文件服务器,OSS服务器
            String filename = file.getOriginalFilename();
            file.transferTo(new File(path+File.separator+filename));
        }
        //多文件上传
        if (files.length>0){
            for (MultipartFile f : files) {
                if (!f.isEmpty()){
                    String filename = f.getOriginalFilename();
                    f.transferTo(new File(path+File.separator+filename));
                }
            }
        }

        model.addAttribute("msg",username+"上传成功!");
        return "index";
    }
}

错误页面

当出现错误后,SpringBoot提供/error处理所有的错误映射

其会将错误信息封装成JSON响应给浏览器

在这里插入图片描述

自定义错误页面

只需将错误页面放在templates/error/下并命名为5xx.html 404.html等

Web原生组件注入(Servlet、Filter、Listener)

1、使用Servlet API

  1. 在启动类上添加@ServletComponentScan注解

  2. 将三大组件统一放在servlet包下

  3. @WebServlet(urlPatterns = "/my")
    public class Myservlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            req.setCharacterEncoding("utf-8");
            resp.setContentType("text/html");
            resp.setCharacterEncoding("utf-8");
            resp.getWriter().write("你好");
        }
    }
    
    @WebFilter(urlPatterns = "/my")
    public class MyFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            Filter.super.init(filterConfig);
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            System.out.println("Filter工作了");
            filterChain.doFilter(servletRequest, servletResponse);
        }
    
        @Override
        public void destroy() {
            Filter.super.destroy();
        }
    }
    
    @Slf4j
    @WebListener
    public class MyServletContextListener implements ServletContextListener {
    
        @Override
        public void contextInitialized(ServletContextEvent sce) {
            log.info("监听到项目初始化完成");
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
            log.info("监听到项目销毁完成");
        }
    }
    

2、使用RegistrationBean(推荐使用)

将上面编写的三个类的注解去掉,在此类中注入

@Configuration
public class MyRegistionConfig {

    @Bean
    public ServletRegistrationBean servletRegistrationBean(){
        Myservlet myservlet = new Myservlet();
        return new ServletRegistrationBean(myservlet,"/my","/mytest");
    }

    @Bean
    public FilterRegistrationBean filterRegistrationBean(){
        MyFilter myFilter = new MyFilter();
//        return new FilterRegistrationBean(myFilter,servletRegistrationBean());
        FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>(myFilter);
        filterRegistrationBean.addUrlPatterns("my","/mytest");
//        filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/mys"));
        return filterRegistrationBean;
    }

    @Bean
    public ServletListenerRegistrationBean servletListenerRegistrationBean(){
        MyServletContextListener myServletContextListener = new MyServletContextListener();
        return new ServletListenerRegistrationBean(myServletContextListener);
    }
}

阿里巴巴druid配置

spring:
  datasource:
    username: xxxxxx
    password: xxxxxxxxxxxxx
    url: jdbc:mysql://localhost:3306/mybatis-plus
    driver-class-name: com.mysql.cj.jdbc.Driver
    druid:
      stat-view-servlet:
        enabled: true
        login-password: xxxx
        login-username: xxxx
        reset-enable: true
      web-stat-filter:
        enabled: true
      aop-patterns: com.djx
      filters: stat,wall
      filter:
        stat:
          log-slow-sql: true
          slow-sql-millis: 1000
        wall:
          enabled: true
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值