SprinBoot5详解

1.依赖管理

修改默认依赖版本:

<properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <mysql.version>5.1.48</mysql.version>
</properties>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

再刷新maven即可, 默认不需要需改依赖版本号

spring-boot-starter-*:spring-boot某种场景依赖的集成、包括redis、cache等;

spring-boot所以支持的场景:https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.build-systems.starters

自定义与第三方依赖场景的命名规则:*-spring-boot-starter

所有场景启动器最底层的依赖:

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>2.6.7</version>
      <scope>compile</scope>
    </dependency>

2.自动配置

spring-boot已经为我们配置好了所有web开发的常见场景

默认包结构:

主程序(main方法)所在的包及其下面的所有子包的组件都会被默认扫描进来

指定扫描包路径:

@RestController
@SpringBootApplication(scanBasePackages = "com")
public class MyApplication {...}

//或者
@RestController
//@SpringBootApplication(scanBasePackages = "com")
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com")
public class MyApplication {...}    

各种配置都有默认值,这些配置最终都是映射到某个类上,这些类会在容器中创建对象

spring-boot是按需加载自动配置项的,按需加载取决于引入了哪些场景

spring-boot的所有配置功能都在

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-autoconfigure</artifactId>
  <version>2.6.7</version>
  <scope>compile</scope>
</dependency>

将组件配置入容器:

只有在容器中的组件才能使用springboot的强大功能

①编写配置类,用@Configuration标注,里面编写要注册入容器的类;

②向容器注册组件(类),可以使用@Bean,@Import,@ConditionalOnBean(条件注入)注入

/**
 * @Configuration标注配置类、配置文件
 * 配置类里面用@Bean给容器注册组件,默认也是单实例的
 *  proxyBeanMethods属性:代理bean方法,如果proxyBeanMethods属性是true,那么spring使用代理对象调用方法,多次调用组件方法springboot总会去容器里面获取这个对象,保持组件的单实例
 *  proxyBeanMethods=true是@Configuration的full模式,每次调用该类的方法返回的都是容器中的对象
 *  proxyBeanMethods=false是@Configuration的lite模式,每次调用该类的方法返回的是新的对象
 *  设置true开启单例,false不开启单例
 */
@Configuration(proxyBeanMethods = true)

/**
 * 在容器中自动创建这两个类型的组件
 * 默认组件的id是组件的全类名
 */
//@Import({Director.class, JDBC42Helper.class})

public class MyConfig {

    /**
     * 被作为依赖的bean一定要写在依赖方法的上方,因为需要先加载被依赖的bean,才能加载依赖方法
     * @return
     */
    @Bean("myplayer")
    public Player player(){
        return new Player("刘德华",55);
    }

    /**
     * 给容器添加组件,以方法名作为组件的id,返回值类型就是组件的类型,返回的值就是组件在容器中的实例
     * @Bean的value属性可以自定义组件id
     * @return
     */
    @ConditionalOnBean(name = "myplayer")
    @Bean("dianying")
    public Movie movie(){
        Movie cjh=new Movie("长津湖",2021);
        cjh.setPlayer(player());
        return  cjh;
    }

    @Bean
    public Director director(){
        return new Director("张艺谋",35);
    }
}

使用配置文件向容器注入组件:

@ImportResource(locations = "classpath:bean.xml")   //往配置类中导入文件资源
public class MyConfig {...}

配置绑定:

方式一:@Component+@ConfigurationProperties(prefix = “mycom”)

@Component
@ConfigurationProperties(prefix = "mycom")
public class Company {

    private String name;
    private double price;
    ...
}  
server.port=8888

mycom.name="北京文化"
mycom.price=5.78

方式二:@ConfigurationProperties(prefix = “mycom”)+@EnableConfigurationProperties(Company.class)

开启配置绑定功能,把组件自动注册到容器中

其中@EnableConfigurationProperties写在配置类上方

@EnableConfigurationProperties(Company.class)
public class MyConfig {...}
@ConfigurationProperties(prefix = "mycom")
public class Company {...}

3.自动配置源码解析

@SpringBootApplication由以下3个注解合成

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
@SpringBootConfiguration	//代表当前是一个配置类
@ComponentScan		//指定扫描的类、包

@EnableAutoConfiguration由以下构成

@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {}

@AutoConfigurationPackage解析:

@Import({Registrar.class})	//给容器导入组件
public @interface AutoConfigurationPackage {
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};
}
//利于Registrar给容器中导入一系列组件
//将主方法所在的包下的所有组件注册入容器

@Import({AutoConfigurationImportSelector.class})解析:

利用this.getAutoConfigurationEntry(annotationMetadata)给容器导入一些组件
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes) 获取所以需要导入到容器中的配置类
利用工厂加载Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) ,得到所有组件
从META-INF/spring.factories加载文件,默认扫描当前系统所有jar包里的META-INF/spring.factories位置的文件
spring-boot-test-autoconfigure-2.6.7.jar中的META-INF/spring.factories文件写死了spring-boot一启动就要往容器中注册的所有配置类
int c = run.getBeanDefinitionCount(); 	//c是143
//总共有143个自动配置启动的时候默认全部加载,但最终会按需加载,因为很多类都是@ConditionalOnXXX注解,只有在某种条件下才会注册入容器

SpringBoot会在底层配置好所有的组件,如果用户已经配置了,以用户的优先

总结:

  • SpringBoot先加载所有的自动配置类,XXXXAutoConfiguration
  • 每个自动配置类按照条件生效,并且都会默认绑定相应的配置类,XXXXProperties.class,配置类又正好绑定了XXXX.properties文件
  • 生效的配置类就会往容器里面注册很多组件,于是这些功能就生效了
  • 如果用户已经配置了组件,以用户的配置类优先
  • 定制化配置的两种方式
    • 用户直接自己@Bean替换底层组件
    • 修改配置文件(application.properties)即可,此方式更常用

4.开发中实用的注解

简化Bean开发:lombok

  • 安装依赖
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
@ToString   //生成ToString
@Data       //设置getter和setter方法
@AllArgsConstructor     //全部有参构造方法
@NoArgsConstructor      //无参构造方法
@EqualsAndHashCode      //重写Equals和HashCode方法
@Component
public class Adder {
    private String province;
    private String city;
}
@RestController
@Slf4j      //日志注解
public class TestCon1 {

    @RequestMapping("/test1")
    public void test1(){
        //打印日志
        log.info("test1请求");
        System.out.println(new Adder("浙江省","温州市"));
    }
}

dev-tools:

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

添加依赖,ctrl+f9进行热更新

5.yaml配置

SpringBoot同时会将application.properties与application.yml作为配置文件,如果两个文件配置了相同的属性,properties文件优先级更高

person:
  #pName: '刘德华\n  dadad'   #单引号将特殊字符转义
  #pName: "刘德华\n  dadad"   #双引号不转义特殊字符
  pName: 刘德华\n  dadad #不加引号效果与单引号一致,转义特殊字符
  married: true
  birth: 2013/05/04
  age: 58
#  interests: [唱,跳,rap]   #数组写法
  interests:    #数组写法
    - 篮球
    - 足球
    - 网球
  animal: [,,]
#  score:   #对象写法
#    English: 80
#    Math: 75
#    Chinese: 65
  scope: {English: 80,Math: 75,Chinese: 65}   #对象写法
  salary:
    - 9999
    - 8888
    - 7777
  movie:
    mName: 无间道
    mUpYear: 2003
  allMovie:
    war:  #数组里面存对象写法
      - {mName: 辛德勒名单,mUpYear: 1998}
      - mName: 敦刻尔克
        mUpYear: 2008
    science:
      - mName: 后天
        mUpYear: 2002
      - mName: 降临
        mUpYear: 2012
        
spring:
  banner:
    charset: UTF-8

对比properties,yml文件结构层次更清晰

开启yam文件对bean属性的自动提示功能(测试过但是没有效果)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

6.WEB开发简单功能分析

静态资源访问:

官方说明:By default, Spring Boot serves static content from a directory called /static (or /public or /resources or /META-INF/resources) in the classpath or from the root of the ServletContext.

即类路径下的/static (or /public or /resources or /META-INF/resources)文件夹下的文件可以通过http://localhost:8080/+文件名访问,例如http://localhost:8080/5.jpg

原理:静态映射规则是/**,SpringBoot先去Controller找相应的请求,如果没有相应的请求,就去静态资源目录里面找资源,如果静态资源也没有找到则返回404

配置静态资源访问前缀,在使用拦截器的时候可以放行对应的静态资源:

spring:
  mvc:
    static-path-pattern: /res/**	#该配置同时

配置了配置静态资源访问前缀后,静态资源文件的访问规则就变成了:当前项目+/res/+静态资源文件名,例如:http://localhost:8080/res/1.jpg

配置欢迎页:

在任意静态资源文件夹下配置index.html,即可通过http://localhost:8080/访问欢迎页,如果配置了静态资源访问前缀,就必须通过http://localhost:8080/res/index.html访问欢迎页

配置favicon.ico:

将favicon.ico文件放入static文件夹下,重启IDEA即可

7.获取请求参数

SpringBoot的底层仍然是SpringMVC,所以SpringMVC获取参数的方式依然可用,在此再补充几个获取请求参数的方式

使用Map集合获取Rest风格请求参数:

@GetMapping("/t1/{id}/aa/{name}")
public Map<String,String> test1(@PathVariable("id") int id,@PathVariable("name") String name,@PathVariable Map<String,String> pv){
    return pv;
}

使用Map集合获取Header参数:

@GetMapping("/t1/{id}/bb/{name}")
public Map<String,String> test2(@RequestHeader Map<String,String> pv2){
    return pv2;
}

使用List跟Map获取普通参数

@RequestParam("type") List<String> list,
@RequestParam Map<String,String> map

获取cookie参数:

@CookieValue("_bl_uid") String cookie
//或者
@CookieValue("_bl_uid") Cookie cookie2

获取POST请求体

@PostMapping("/t2")
public Map<String,Object> test4(@RequestBody String body){
    Map<String,Object> allMap =new HashMap<>();
    allMap.put("body",body);
    return allMap;
}

获取请求域属性:

@GetMapping("/t2")
@ResponseBody
public Map<String,Object> t2(@RequestAttribute("msg") String msg,
                     @RequestAttribute("code") int code,
                     HttpServletRequest request){
    ...
}

获取矩阵变量:

//矩阵变量必须要有url路径变量才能解析
//请求:http://localhost:8080/con1/t3/adf;aa=aaa,bbb,ccc;dd=dddd
@GetMapping("/t3/{a}")
@ResponseBody
public Map<String,Object> t3(@PathVariable("a")String a,
                             @MatrixVariable("aa")List<String> list,
                             @MatrixVariable("dd") String d){
    Map<String,Object> m=new HashMap<>();
    m.put("a",a);
    m.put("list",list);
    m.put("d",d);
    return m;
}

//http://localhost:8080/con1/t3/11;id=121/22;id=333
@GetMapping("/t3/{a}/{b}")
@ResponseBody
public Map<String,Object> t3(@MatrixVariable(value = "id",pathVar = "a") int aID,@MatrixVariable(value = "id",pathVar = "b") int bID){
        Map<String,Object> m=new HashMap<>();
        m.put("aid",aID);
        m.put("bid",bID);
        return m;
    }

//有些版本的SpringBoot需要开启识别url里面的分号:

//在配置类里面:
//方式一
//    @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);
            }
        };
    }

通过对象属性获取参数:

@PostMapping("/t6")
@ResponseBody
public Movie t6(Movie movie) {
    return movie;
}
//请求信息
mName----霸王别姬
mUpYear----2013
player.pName----张国荣
player.pAge----32

Model、Map里面的数据会被放在同一个请求域中:

@GetMapping("/t4")
public String t4(Map<String,Object> map, Model model, HttpServletRequest request, HttpServletResponse response){
    map.put("wjd","无间道");
    model.addAttribute("bwbj","霸王别姬");
    request.setAttribute("ht","后天");
    response.addHeader("header","这是header");
    return "forward:/con1/t5";
}

@GetMapping("/t5")
@ResponseBody
public Map<String,Object> t5(HttpServletRequest request){

    Map<String,Object> m=new HashMap<>();
    m.put("data1",request.getAttribute("wjd"));
    m.put("data2",request.getAttribute("bwbj"));
    m.put("data3",request.getAttribute("ht"));

    return m;
}

8.内容协商

根据请求头的accept与服务器协商响应格式

Acceptapplication/xml
Acceptapplication/json

开启基于参数的内容协商:

spring:
  mvc:
    contentnegotiation:
      favor-parameter: true

请求路径带上内容协商格式参数:

http://localhost:8080/con1/t4?format=json

http://localhost:8080/con1/t4?format=xml

自定义内容协商:

@Configuration
public class MyConfig  {
    @Bean
    public WebMvcConfigurer webMvcConfigurer(){
        return new WebMvcConfigurer() {
            
            @Override
            public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
                converters.add(new YwxkConverter());
            }
        };
    }

}
/**
 * 自定义converter
 */
public class YwxkConverter implements HttpMessageConverter<Movie> {

    @Override
    public boolean canRead(Class clazz, MediaType mediaType) {
        return false;
    }

    @Override
    public boolean canWrite(Class clazz, MediaType mediaType) {
        return clazz.isAssignableFrom(Movie.class);
    }

    /**
     * 设置服务器能输出的自定义协商内容
     * @return
     */
    @Override
    public List<MediaType> getSupportedMediaTypes() {
        return MediaType.parseMediaTypes("application/ywxk");
    }

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

    @Override
    public void write(Movie movie, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {

        //写出去自定义数据
        String strs=movie.getmName()+";"+movie.getmUpYear();
        OutputStream out=outputMessage.getBody();
        out.write(strs.getBytes(StandardCharsets.UTF_8));
    }
}
//浏览器参数format=yw方式
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    //map参数
    Map<String, MediaType> map=new HashMap<>();
    map.put("json",MediaType.APPLICATION_JSON);
    map.put("xml",MediaType.APPLICATION_XML);
    map.put("yw",MediaType.parseMediaType("application/ywxk"));
    //指定支持解析哪些参数对应的哪些媒体类型
    ParameterContentNegotiationStrategy strategy = new ParameterContentNegotiationStrategy(map);
    //设置format参数为ff参数
    //strategy.setParameterName("ff");
    HeaderContentNegotiationStrategy headerStrategy = new HeaderContentNegotiationStrategy();
    configurer.strategies(Arrays.asList(strategy,headerStrategy));
}

9.视图解析与模板引擎

SpringBoot默认不支持jsp,需要引入第三方模板引擎实现视图渲染

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

10.配置拦截器

@Configuration
public class MyConfig implements WebMvcConfigurer {

    //添加拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //拦截器默认拦截所有请求,包括所有静态资源路径,不拦截/con1/t7,/con1/t8
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").excludePathPatterns("/con1/t7","/con1/t8");
    }
}
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //编写拦截逻辑
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

11.文件上传

@RequestMapping("/image")
public String upload(@RequestPart("file1")MultipartFile file1,
                     @RequestPart("file2")MultipartFile[] file2) throws IOException {
    if(!file1.isEmpty()){
        String newFile1=file1.getOriginalFilename();
        file1.transferTo(new File("D:/temp/"+newFile1));
    }
    if(file2.length>0){
        for (MultipartFile file2Con: file2) {
            if(!file2Con.isEmpty()){
                String file2ConName=file2Con.getOriginalFilename();
                file2Con.transferTo(new File("D:/temp/"+file2ConName));
            }
        }
    }
    log.info("单个文件大小:"+file1.getSize()+"---多文件数量:"+file2.length);
    return "测试";
}
spring:
  servlet:
    multipart:
      max-file-size: 15MB #单文件最大上传大小
      max-request-size: 100MB #一次请求最大上传大小

12.异常处理

如果是客户端发送的请求发生异常,SpringBoot返回json;

如果是浏览器发送的请求发生异常,SpringBoot返回error页面;

配置错误静态页自动映射异常

src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- public/
             +- error/
             |   +- 404.html
             +- <other public assets>
src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- templates/
             +- error/
             |   +- 5xx.html
             +- <other templates>

错误页面配置在public/error或者templates/error目录下均可

SpringBoot会根据异常状态码找到error目录下相应的静态页

自定义处理异常:

方案一:@ControllerAdvice+@ExceptionHandler,会自动捕获对应的异常

底层是ExceptionHandlerExceptionResolver提供的支持

/**
 * 处理整个web controller异常
 */
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    //异常处理器
    @ExceptionHandler({ArithmeticException.class,NullPointerException.class})
    public String mathExceptionHandler(Exception e){
        log.error("异常是:{}",e);
        //返回视图地址
        return "error/mathError";
    }
}

方案二:自定义异常类,需要手动抛出

底层是ResponseStatusExceptionResolver提供的支持

@ResponseStatus(value=HttpStatus.BAD_GATEWAY,reason = "我的错误提示")
public class MyException extends RuntimeException{

    public MyException() {
        super();
    }

    public MyException(String message) {
        super(message);
    }
}

@GetMapping("/t10")
    @ResponseBody
    public String t10() {
        if(1==1){

            throw new MyException();
        }
        return "t9方法";
    }
//框架底层的处理异常
DefaultHandlerExceptionResolver

方案三:基于HandlerExceptionResolver的自定义异常

@Order(value = Ordered.HIGHEST_PRECEDENCE)  //异常优先级,也可以给数字,数字越小,优先级越高
@Component
public class CustomerHandlerException implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        try {
            response.sendError(520,"520错误");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new ModelAndView();
    }
}

13.SpringBoot注入原生Servlet、listener、Filter

第一种方式:

@ServletComponentScan(basePackages = "com.ywxk.demo3")
@SpringBootApplication
public class Demo3Application {
    public static void main(String[] args) {
        SpringApplication.run(Demo3Application.class, args);
    }
}
@Slf4j
@WebFilter(urlPatterns = {"/con1/*"})
public class MyFilter implements Filter {
    //实现方法
}
@WebServlet(urlPatterns = "/my")
public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("myServlet");
    }
}
@WebListener
@Slf4j
public class MyListener implements ServletContextListener {
    //重写方法
}

第二种方式:

@ServletComponentScan(basePackages = "com.ywxk.demo3")
@SpringBootApplication
public class Demo3Application {
    public static void main(String[] args) {
        SpringApplication.run(Demo3Application.class, args);
    }
}
public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("myServlet");
    }
}
//filter、listener与上面一样,不需要@WebListener、@WebFilter
//proxyBeanMethods = true保证依赖的组件始终是单实例的
@Configuration(proxyBeanMethods = true)
public class MyRegisterConfig {

    @Bean
    public ServletRegistrationBean myServlert(){
        MyServlet myServlet = new MyServlet();
        return new ServletRegistrationBean(myServlet,"/my","/my2");
    }

    @Bean
    public FilterRegistrationBean myFilter(){
        MyFilter myFilter = new MyFilter();
        //return new FilterRegistrationBean(myFilter,myServlert());
        //或者
        FilterRegistrationBean<MyFilter> myFilterBean = new FilterRegistrationBean<>(myFilter);
        myFilterBean.setUrlPatterns(Arrays.asList("/my","/con1/*"));
        return myFilterBean;
    }

    @Bean
    public ServletListenerRegistrationBean myListener(){
        return new ServletListenerRegistrationBean(new MyListener());
    }
}
14.jdbc方式访问数据库

①导入jdbc场景与驱动

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>

②配置数据库信息

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/movie
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
  jdbc:
    template:
      query-timeout: 3  #超时时间3秒
    

③使用

@Autowired
JdbcTemplate jdbcTemplate;

@Test
public void t1(){
    int c= jdbcTemplate.queryForObject("select count(*) from y_movie",Integer.class);
    log.info("条数:{}",c);
}

15.整合Druid数据源

方式一:手动引入依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.6</version>
</dependency>
@Configuration
public class MyDataSourceConfig {

    //从yaml文件引入数据库名称,账号,密码
    @ConfigurationProperties("spring.datasource")
    @Bean
    public DataSource dataSource() throws SQLException {

        DruidDataSource druidDataSource = new DruidDataSource();
        //也可以在yaml文件设置spring.datasources.filters: wall,stat
        druidDataSource.setFilters("stat,wall");
        return druidDataSource;
    }

    /**
     * 配置druid监控页功能
     * @return
     */
    @Bean
    public ServletRegistrationBean servletRegistrationBean(){

        StatViewServlet statViewServlet=new StatViewServlet();
        ServletRegistrationBean<StatViewServlet> registrationBean=new ServletRegistrationBean<>(statViewServlet,"/druid/*");
        //设置监控页的访问账号密码
        registrationBean.addInitParameter("loginUsername","root");
        registrationBean.addInitParameter("loginPassword","root");
        return  registrationBean;
    }

    /**
     * WebStatFilter 采集web-jdbc关联监控的数据
     */
    @Bean
    public FilterRegistrationBean webStatFilter(){
        WebStatFilter webStatFilter = new WebStatFilter();

        FilterRegistrationBean<WebStatFilter> bean = new FilterRegistrationBean<>(webStatFilter);
        bean.setUrlPatterns(Arrays.asList("/*"));
        bean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return bean;
    }
}

方式二:druid-spring-boot-starter

<dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid-spring-boot-starter</artifactId>
      <version>1.1.17</version>
</dependency>

扩展配置项:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/movie
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
    druid:
      filters: stat,wall	#开启底层功能,stat(sql监控功能),wall(防火墙功能)
      filter:
        stat:
          slow-sql-millis: 1000 #超过1秒的语句都是慢查询
          log-slow-sql: true  #记录慢查询
          enabled: true
        wall:
          enabled: true
      stat-view-servlet:	#配置监控页功能
        enabled: true
        login-username: root
        login-password: root
        reset-enable: false
      web-stat-filter:	#监控web
        enabled: true
        url-pattern: /*
      aop-patterns: com.ywxk.demo3.*	#监控SpringBean

16.整合mybatis

方式一:配置文件模式

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.2</version>
</dependency>
mybatis:
  #config-location: classpath:mybatis/mybatis-config.xml   #mybatis全局配置文件位置
  mapper-locations: classpath:mybatis/mapper/*.xml    #mapper映射文件位置
  configuration:  #指定mybatis的全局配置,该配置与config-location不能同时存在
    map-underscore-to-camel-case: true  
//mapper接口一定要标注@Mapper
//或者在Application类上@MapperScan("com.ywxk.demo3.mapper")来批量扫描mapper文件进入容器
@Mapper
public interface MovieMapper {

    public Movie getMovie(int id);
}
@Service
public class MovieService {

    @Autowired
    MovieMapper movieMapper;

    public Movie getMovieById(int id){
        return movieMapper.getMovie(id);
    }
}
@GetMapping("/t12")
@ResponseBody
public Movie t12(@RequestParam("id") int id){
    Movie movie=movieService.getMovieById(id);
    return movie;
}

方式二:纯注解方式

@Mapper
public interface DirectorMapper {

    @Select("select * from y_director where d_id=#{id}")
    public Director getDirectorById(int id);
}
@Service
public class DirectorService {

    @Autowired
    public DirectorMapper directorMapper;

    public Director getDirectorById(int id){
        return directorMapper.getDirectorById(id);
    }
}
@GetMapping("/t13")
@ResponseBody
public Director t13(@RequestParam("id") int id){
    return directorService.getDirectorById(id);
}

方式三:混合写法

<mapper namespace="com.ywxk.demo3.mapper.DirectorMapper">
    <insert id="insertDirector" useGeneratedKeys="true" keyProperty="d_id">
        insert into y_director(d_name,d_age)
        values (#{d_name},#{d_age})
    </insert>
</mapper>
@Mapper
public interface DirectorMapper {

    @Select("select * from y_director where d_id=#{id}")
    public Director getDirectorById(int id);

    //    @Insert("insert into y_director(d_name,d_age) values (#{d_name},#{d_age})")
	//    @Options(useGeneratedKeys = true,keyProperty = "d_id")
    public int insertDirector(Director director);

}
public int insertDirector(Director director){
    return directorMapper.insertDirector(director);
}
@GetMapping("/t15")
@ResponseBody
public Director t15(Director director){
    directorService.insertDirector(director);
    return director;
}

17.整合Mybatis-plus

详见:https://blog.csdn.net/y_w_x_k/article/details/125208908

18.整合Redis

待补充…

19.单元测试JUnit5

https://blog.csdn.net/y_w_x_k/article/details/125221282

20.指标监控

开启指标监控有两种方式:

第一种:在cmd里输入jconsole

第二种: http方式

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
management:     #management是所有actuator的配置起点
  endpoint:   #详细配置某一个端点
    health:
      show-details: always
      enabled: true   #开放指定端点
    info:
      enabled: true
  endpoints:
    enabled-by-default: true    #是否开启所有监控端点
    web:
      exposure:
        include: '*'    #以web方式暴露所有端点
info:
  appName: testSpringBoot
  appVersion: 1.0
  mavenProjectName: @project.artifactId@
  mavenParentName: @project.parent.artifactId@

使用:

http://localhost:8080/actuator/beans

http://localhost:8080/actuator/metrics

http://localhost:8080/actuator/metrics/application.ready.time

常用的endpoints:

Health:监控状况

Metrics: 运行时指标

Loggers: 日志记录

定制EndPoint:

//定制Health
@Component
public class MyComHealthIndicator extends AbstractHealthIndicator {

    @Override
    protected void doHealthCheck(Health.Builder builder) throws Exception {
        //这里编写判断应用健康代码
        Map<String,Object> map=new HashMap<>();
        if(1==2){
            builder.status(Status.UP);
            map.put("wjd","无间道");
            map.put("bwbj","霸王别姬");
        }else {
            builder.status(Status.OUT_OF_SERVICE);
            map.put("dkek","敦刻尔克");
        }
        builder.withDetail("code",200).withDetails(map);
    }
}
//定制Info
@Component
public class AppInfo implements InfoContributor {
    @Override
    public void contribute(Info.Builder builder) {
        builder.withDetail("blsm","北落师门").withDetail("lh","猎户座").withDetails(Collections.singletonMap("tjs","天津四"));
    }
}
//定制Metrics
@Service
public class MovieService {

    @Autowired
    MovieMapper movieMapper;

    Counter counter;

    public MovieService(MeterRegistry meterRegistry){
        counter = meterRegistry.counter("moviecounter");
    }

    public Movie getMovieById(int id){
        counter.increment();
        return movieMapper.getMovie(id);
    }
}
//定制endpoint
@Component
@Endpoint(id = "myServiceEndpoint")
public class MyServiceEndpoint {

    @ReadOperation
    public Map getDockerInfo(){
        return Collections.singletonMap("dockerInfo","docker started");
    }

    @WriteOperation
    public void updateDocker(){
        System.out.println("docker stop");
    }
}

21.服务器监控

监控应用配置:

<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-server</artifactId>
    <version>2.5.1</version>
</dependency>
server.port=8888
@Configuration
@EnableAdminServer
@SpringBootApplication
public class Demo4Application {
    public static void main(String[] args) {
        SpringApplication.run(Demo4Application.class, args);
    }
}

被监控应用:

<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-client</artifactId>
    <version>2.5.1</version>
</dependency>
spring:
  boot:
    admin:
      client:
        url: http://localhost:8888/
        instance:
          prefer-ip: true

22.profile生产与开发环境切换

application.properties:默认配置环境,永远会被加载,与环境配置文件同时生效,如果有同名配置,以环境配置文件优先

server.port=8080
#配置环境
spring.profiles.active=test

application-prod.yaml: 生产环境配置文件

movie:
  name: prod-十面埋伏
server:
  port: 8000

application-test.yaml: 测试环境配置文件

movie:
  name: test-天地英雄
server:
  port: 7000

也可以命令行修改运行环境与配置:

java -jar demo3-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod  --movie.name=无极

@Profile条件装配

public interface Movie2 {
    String getName();
    int getUpYear();
}
//生产环境是LoveMovie生效
@Profile("prod")
@Component
@ConfigurationProperties("movie2")
@Data
public class LoveMovie implements Movie2{
    private String name;
    private int upYear;
}
//测试环境是WarMovie生效
@Profile("test")
@Component
@ConfigurationProperties("movie2")
@Data
public class WarMovie implements Movie2{
    private String name;
    private int upYear;
}

配置分组

#如果环境配置内容较多的话,可以将一个配置文件分成多个,然后这些配置文件归为一组配置,同组文件内容会自动合并
#生产环境组
spring.profiles.group.production[0]=prod
spring.profiles.group.production[1]=prod2

#测试环境组
spring.profiles.group.production[0]=prod

23.配置文件

SpringBoot默认会去以下路径读取application.properties与application.yaml配置文件

  • resources目录下
  • resources目录下的config目录下
  • jar包同级的目录下(可以在服务器上临时修改配置)
  • jar包同级的目录下的config目录下(可以在服务器上临时修改配置)
  • jar包同级的目录下的config目录下的一级子目录下(可以在服务器上临时修改配置)

如果配置属性相同,指定环境优先,jar包外部优先

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

y_w_x_k

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值