什么是SpringBoot?

  • Spring Boot 是由 Pivotal 团队提供的全新框架
  • 目的是用来简化新 Spring 应用的初始搭建以及开发过程
  • 该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置
  • 通过这种方式,Spring Boot 致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。
  • Spring Boot 并不是对 Spring 功能上的增强,而是提供了一种快速使用 Spring 的方式。

特性

  • 约定大于配置
  • 创建独立的spring应用程序。
  • 嵌入的tomcat jetty 或者undertow 不用部署WAR文件。
  • 允许通过Maven来根据需要获取starter
  • 尽可能的使用自动配置spring
  • 提供生产就绪功能,如指标,健康检查和外部配置properties yaml yml
  • 开箱即用,没有代码生成,也无需 XML 配置,同时也可以修改默认值来满足特定的需求。

传统开发模式

  • 优点

    • 开发简单,集中式管理
    • 基本不会重复开发
    • 功能都在本地,没有分布式的管理和调用消耗
  • 缺点

    • 效率低:开发都在同一个项目改代码,相互等待,冲突不断
    • 维护难:代码功功能耦合在一起,新人不知道何从下手
    • 不灵活:构建时间长,任何小修改都要重构整个项目,耗时
    • 稳定性差:一个微小的问题,都可能导致整个应用挂掉
    • 扩展性不够:无法满足高并发下的业务需求
    • 对服务器的性能要求要统一,要高

微服务开发模式

  • 优点

    • 每个微服务都很小,这样能聚焦一个指定的业务功能或业务需求
    • 微服务能够被小团队开发,这个小团队2-5人就可以完成了
    • 微服务是松耦合的,是有功能,有意义的服务,开发阶段或部署阶段都是独立的
    • 微服务可以使用不同的语言开发
    • 微服务能部署在中低端配置的服务器上
    • 很容易和第三方集成
    • 每个服务都有自己的存储能力,单独的库,也可以有统一的库
  • 缺点:
    • 微服务会带来过多的操作
    • 可能有双倍的努力
    • 分布式系统可能复杂难管理
    • 分布跟踪部署难
    • 当服务数量增加时,管理复杂度增加

SpringBoot的配置

配置文件

  • properties文件

    #第一种配置文件
    #mysql
    jdbc.mysql.driverClassName=com.mysql.cj.jdbc.Driver
    jdbc.mysql.url=jdbc:mysql://localhost:3306/crm?serverTimezone=UTC
    jdbc.mysql.username=root
    jdbc.mysql.password=root#druid
    druid.initialSize=10
    druid.minIdle=10
    druid.maxActive=50
    druid.maxWait=60000
    

    yml文件

    #第二种配置文件
    #myKey: myValue#yaml 层级式键值对配置
    #层级:通过换行符+空格,同一层级必须对其,父层与子层之间通常使用2个空格
    #level1:
    #  level21: aaa
    #  level2:
    #    level31: bb
    #    level32: cc#数据类型
    #简单值
    #字符串:可以不使用引号包裹,但是有特殊符号时需要使用引号包裹(例如:空格)
    name: 张三
    age: 10
    birthday: 1998/07/25
    gender: true
    obj: ~#数组(也认为是LIst集合)
    #行内
    array1: [spring, springmvc, mybatis]
    array2:- html- css- javascript#对象(也可认为是Map集合)
    student:name: 李四age: 22birth: 1999/10/17gender: falsehobby: [football, games, swimming]address:city: 郑州市area: 金水区street: 民航路#主配置
    #激活环境配置profiles
    #spring:
    #  profiles:
    #    active: dev
    #server:
    #  port: 8080
    

读取配置文件

  • 本质是将配置类对象放到ioc容器中

  • 单个读取

    @Value("${name}")
    private String username;
    
  • 使用配置类读取

    • 第一种方式

      @Component + @ConfigurationProperties
      
    • 第二种方式

      @EnableConfigurationProperties + @ConfigurationProperties
      
  • 读取第三方的properties文件

    @Component
    @ConfigurationProperties(prefix = "jdbc.mysql")
    //加载第三方资源文件
    @PropertySource(value = "classpath:db.properties")
    
  • 读取原生的xml文件

  • demo

    /*** 读取配置文件数据*/
    @RestController
    public class ReadConfigController {/*** 单个读取,不方便* 使用@Value注解+SpringEL来实现配置读取 */@Value("${name}")private String username;@Value("${age}")private Integer age;@Value("${birthday}")private Date birthday;@Value("${gender}")private Boolean gender;@Value("${student.name}")private String studentName;@GetMapping("/read")public String read(){return "姓名:" + username + " 年龄:" + age + " 生日:" + birthday + " 性别:" + gender + " 学生姓名:" + studentName;}/*** 使用配置类* 将配置类放到IOC容器,在这里自动注入*/@Autowiredprivate StudentProperties studentProperties;@GetMapping("/readProperties")public StudentProperties readProperties(){return studentProperties;}/*** 读取第三方的properties文件*/@Autowiredprivate MysqlProperties mysqlProperties;@GetMapping("/readProp")public MysqlProperties readProp(){return mysqlProperties;}/*** 读取原生的xml配置文件*/@Autowiredprivate Emp emp;@GetMapping("/readXml")public Emp readXml(){return emp;}
    }
    

    在配置类上加注解

    //加载原生的xml spring配置文件
    @ImportResource(locations = "classpath:applicationContext.xml")
    //开启配置文件读取,属性为要读取的配置类,可以批量读取配置类
    @EnableConfigurationProperties({StudentProperties.class, AddressProperties.class})
    @SpringBootApplication
    public class Springboot02ConfigApplication {public static void main(String[] args) {SpringApplication.run(Springboot02ConfigApplication.class, args);}
    }
    

    读取yaml文件的配置类

    /*** 学生配置读取类,自动读取yml配置文件** 成员变量名称必须与配置名称保持一致(驼峰与中划线)* 1.@Component + @ConfigurationProperties* 2.@EnableConfigurationProperties + @ConfigurationProperties** 第二种方式的@EnableConfigurationProperties注解* 需要放到配置类上* 作用是:开启配置文件读取*/
    @Data
    //@Component //配置bean
    @ConfigurationProperties(prefix = "student")  //读取配置文件,属性用来指定层级
    public class StudentProperties {private String name;private Integer age;private Date birth;private Boolean gender;private String[] hobby;private AddressProperties address;//get...  set...
    }
    
    // @Component
    @Data
    @ConfigurationProperties(prefix = "student.address")
    public class AddressProperties {private String city;private String area;private String street;
    }
    

    读取properties文件的配置类

    /*** 读取#第三方的priperties文件*/
    @Data
    @Component
    @ConfigurationProperties(prefix = "jdbc.mysql")
    //加载第三方资源文件
    @PropertySource(value = "classpath:db.properties")
    public class MysqlProperties {private String driverClassName;private String url;private String username;private String password;
    }
    

    读取原生的applicationContext.xml文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--使用原生的xml配置文件,此文件默认不读,需要在配置--><bean id="dept" class="com.dx.bean.Dept"><property name="id" value="10"/><property name="dname" value="研发部"/></bean><bean id="emp" class="com.dx.bean.Emp"><property name="id" value="1001"/><property name="ename" value="汤姆"/><property name="dept" ref="dept"/></bean>
    </beans>
    
    @Data
    public class Emp {private Integer id;private String ename;private Dept dept;
    }
    
    @Data
    //开启链式调用
    @Accessors(chain = true)
    public class Dept {private Integer id;private String dname;
    }
    

profile配置文件

  • 三种工作环境配置文件:开发环境(dev)、生产环境(prod)、测试环境(test)

    #环境配置
    #需要激活:在application.yml中激活
    #命名规则:application-xxx.xml#开发环境配置
    server:#端口号port: 8001servlet:#根路径context-path: /web-dev
    
    #生产环境配置
    server:port: 8003servlet:context-path: /web-prod
    
    #测试环境
    server:port: 8002servlet:context-path: /web-test
    

    在测试的时候,需要修改pom的编译路径,确保把所有的配置文件都编译以后再测试

    <build><!-- 将所有的配置文件都编译--><resources><resource><directory>D:\workspace\SpringBoot-Code\02-spring-boot-config</directory><includes><include>**/*.yml</include><include>application.yml</include></includes></resource></resources>
    </build>
    

部署时配置文件

  • 外部配置文件

    在D盘放一个application.yml文件 端口指定为8009
    打包后使用命令行运行并且指定java -jar aaa.jar --spring.config.location=D:/application.yml
    
  • 命令修改配置文件

    可以使用命令行参数指定(文档一行写不下的时候,不要回车)java -jar aaa.jar --server.port=8888 --server.servlet.context-path=/bjpowernode
    

配置优先级

  • 后加载的会覆盖先加载的

  • 最后加载的优先级最高

  • spring boot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件

    其中同一目标下的properties文件的优先级大于yml文件

  • 配置文件可以放的位置和优先级
    classpath:/ --优先级4

    classpath:/config/ --优先级3

    file:./ --优先级2

    file:./config/ --优先级1

日志logback

配置日志级别

  • @RestController
    //注解式日志:动态为该类声明一个静态Logger成员变量
    //@Slf4j
    public class LogController {/*** 使用日志:* 在当前类中声明一个成员变量,类型为Logger类型*/private Logger log = LoggerFactory.getLogger(LogController.class);@GetMapping("/getLog")public String getLog(){/*** 在各个日志框架都有级别* 错误error,警告warn,信息info,调试debug,底层trace** springboot默认级别为info* 可以在application.yml配置文件中配置** 例如:当级别为info,日志输入仅会输入info以及以上级别日志*///程序出现异常log.error("error级别的日志");//程序有可能出现问题,提醒或警告log.warn("warn级别的日志");//信息:记录用户操作log.info("info级别的日志");//调试信息:开发时使用log.debug("debug级别的日志");//程序底层信息log.trace("trace级别的日志");//热部署添加内容log.info("无需重启自动生效...");return "正在记录日志";}
    }
    
  • 全局配置 局部配置

    #配置日志
    logging:level:#使用root配置全局的日志级别root: info#局部日志级别,两种写法
    #    com.dx.controller: tracecom:dx:controller: trace
    

自定义日志输出格式

  #自定义日志格式pattern:console: "%d{yyyy-MM-dd HH:mm:ss SSS} %-5level [%thread] %logger -- %msg%n"

生成日志文件

  #日志在文件中的输出file:#日志文件名,在根目录下可以找到文件name: demo.log#指定日志文件路径,但是不能与那么同时配置,两个只能用一个
#    path: c:/log/#如果想既自定义文件名 又指定文件位置,可以导入logback.xml文件,如果使用logback.xml记得把这里的配置去掉,不然会冲突

logback.xml:可以直接使用,直接放到项目中就可以

<?xml version="1.0" encoding="UTF-8"?>
<!--
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration scan="false" scanPeriod="60 seconds" debug="false"><!-- 定义日志的根目录 --><property name="LOG_HOME" value="d:/logback/" /><!-- 定义日志文件名称 --><property name="appName" value="springboot"></property><!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 --><appender name="cc" class="ch.qos.logback.core.ConsoleAppender"><!--日志输出格式:%d表示日期时间,%thread表示线程名,%-5level:级别从左显示5个字符宽度%logger{50} 表示logger名字最长50个字符,否则按照句点分割。%msg:日志消息,%n是换行符--><layout class="ch.qos.logback.classic.PatternLayout"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern></layout></appender><!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 --><appender name="ff" class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 指定日志文件的名称d:/logback/springboot.log--><file>${LOG_HOME}/${appName}.log</file><!--当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。--><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!--滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动%i:当文件大小超过maxFileSize时,按照i进行文件滚动--><fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern><!--可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动,且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除。--><MaxHistory>365</MaxHistory><!--当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy--><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>10MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><!-- 日志输出格式: --><layout class="ch.qos.logback.classic.PatternLayout"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern></layout></appender><!--logger主要用于存放日志对象,也可以定义日志类型、级别name:表示匹配的logger类型前缀,也就是包的前半部分level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERRORadditivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出,false:表示只用当前logger的appender-ref,true:表示当前logger的appender-ref和rootLogger的appender-ref都有效--><!-- 自定义的 logger --><logger name="com.bjpowernode.controller" level="debug" /><!-- Spring framework logger --><logger name="org.springframework" level="debug" additivity="false"></logger><!--root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应,要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。--><root level="info"><!--        控制台--><appender-ref ref="cc" /><!--        滚动文件--><appender-ref ref="ff" /></root>
</configuration>

工具

自定义配置提示

<!--实现自定义配置的提示功能-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional>
</dependency>

热部署

<!--热部署:更新代码或页面不需要重启服务,直接Build一下就可以-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional>
</dependency>

lombok

<!--简化工具作用:实现注解式get/set,构造方法,toString方法...注解式日志条件:1.依赖,2.IDEA插件
-->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional>
</dependency>
//开启对象中set方法的链式调用
@Accessors(chain = true)
//链式调用
Student s3 = new Student().setId(30).setName("王五").setAddress("深圳").setScore(82.6);
System.out.println(s3);

注解式日志

//注解式日志:动态为该类声明一个静态Logger成员变量
@Slf4j
public class LogController {//可以代替这条语句
//     private Logger log = LoggerFactory.getLogger(LogController.class);@GetMapping("/getLog")public String getLog(){log.error("error级别的日志");log.warn("warn级别的日志");log.info("info级别的日志");log.debug("debug级别的日志");log.trace("trace级别的日志");log.info("无需重启自动生效...");return "正在记录日志";}
}

处理静态资源

配置静态资源路径

  • 默认位置

    # 默认静态资源路径:
    #   "classpath:/META-INF/resources/"
    #   "classpath:/resources/"
    #   "classpath:/static/"
    #   "classpath:/public/"
    
  • 配置自定义位置

  • 配置静态资源访问路径

    spring:web:resources:#设置当前项目静态资源目录#注意:配置自定义静态资源目录时,需要添加原有配置项,否则会覆盖原有配置#classpath表示在类路径下查找资源,file表示在操作系统的文件系统下查找资源 d:/static-locations: classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,classpath:/my/,file:${custom.upload}mvc:#设置当前项目静态资源的访问前缀static-path-pattern: /static/**#配置自定义本地的资源路径
    custom:upload: E:\文件\图片\壁纸
    

使用静态资源jar包

  • 导入bootstrap和jqury依赖

    <!--jquery-->
    <dependency><groupId>org.webjars</groupId><artifactId>jquery</artifactId><version>3.6.0</version>
    </dependency>
    <!--bootstrap-->
    <dependency><groupId>org.webjars</groupId><artifactId>bootstrap</artifactId><version>3.4.1</version>
    </dependency>
    
  • 使用demo

    <!DOCTYPE html>
    <html lang="en">
    <head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="/webjars/bootstrap/3.4.1/css/bootstrap.min.css">
    </head>
    <body><div style="text-align: center"><h1>首页</h1><div><span id="hello">你好</span></div><div><button type="button" class="btn btn-primary">按钮</button></div><div><img src="/static/bbb.jpg" alt="" style="width: 300px; height: 200px"></div><!--webjars:以jar包的方式引入静态资源,可以从maven配置依赖--><script type="text/javascript" src="/webjars/jquery/3.6.0/jquery.min.js"></script><script type="text/javascript">$(function (){var str = $('#hello').html();alert(str);$('#hello').append('springboot');})</script></div>
    </body>
    </html>
    

使用模板引擎 Thymeleaf

配置Thymeleaf

  • 开发时关闭缓存、发布时打开缓存

    spring:   #Thymeleaf的配置thymeleaf:#页面缓存,开发时关闭缓存、发布时打开缓存cache: false#前后缀,使用默认值就可以
    #    prefix: classpath:/templates/
    #    suffix: .html
    

动态属性获取数据

  • 取值

    <!--
    要在头上添加这个,不然${msg}会报错
    xmlns:th="http://www.w3.org/1999/xhtml"-->
    <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
    ......
    <!--
    通过动态属性来获取数据
    th:text 从域对象中获取数据,渲染到指定标签中,对特殊符号进行转码  会将传过来的标签直接当字符串输出
    th:utext 从域对象中获取数据,渲染到指定标签中,不处理特殊符号       传过来的标签会生效
    [[${msg}]]  加两个中括号,表示里面的内容是动态的
    -->
    <p th:text="${msg}"></p>
    <p th:text="${message}"></p>
    <p th:utext="${message}"></p>
    <p>[[${msg}]]</p><!--表单取各种值-->
    <form action="/emp/edit" th:action="@{/emp/edit}" method="post"><div class="form-group"><label>员工编号</label><!--取值方式一:${emp.id}--><input type="text" name="id" class="form-control" th:value="${emp.id}"></div><div class="form-group"><label>员工姓名</label><!--取值方式二:*{ename}--><input type="text" name="ename" class="form-control" th:value="*{ename}"></div><div class="form-group"><label>入职日期</label><!--取日期--><input type="date" name="hiredate" class="form-control" th:value="${#dates.format(emp.hiredate, 'yyyy-MM-dd')}"></div><div class="form-group"><label>员工性别</label><!--select取值--><select name="gender" class="form-control"><option value=""></option><option value="1" th:selected="${emp.gender=='1'}">男性</option><option value="2" th:selected="${emp.gender=='2'}">女性</option></select></div><div class="form-group"><button type="button" class="btn btn-primary">提交</button></div>
    </form>
    
  • 循环

    <tr th:each="emp : ${empList}"><td>[[${emp.id}]]</td><td th:text="${emp.ename}"></td>
    </tr>
    
  • 判断

    <td><span th:if="${emp.gender=='1'}">男性</span><span th:if="${emp.gender=='2'}">女性</span>
    </td>
    <td th:switch="${emp.gender}"><span th:case="'1'">帅哥</span><span th:case="'2'">靓女</span>
    </td>
    
  • 日期格式化

    //日期格式化
    //在成员变量上添加注解  @DateTimeFormat:接收参数时格式化      @JsonFormat:发送参数时格式化
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    private Date hiredate;
    
    <!--动态页面中的日期格式化-->
    <td th:text="${#dates.format(emp.hiredate, 'yyyy-MM-dd')}"></td>
    
  • 自动根路径 @{...}

    #在application.yml文件中
    #修改项目的根路径
    server:servlet:context-path: /boot
    
    <!--
    静态路径:href="/emp/list"
    动态路径:th:href="@{/emp/list}"
    可以设置一个静态的和一个动态的,静态的留给前端用
    -->
    <p><a href="/emp/list" th:href="@{/emp/list}">员工列表</a></p>
    
  • 路径传参

    <td><!--路径传参--><a href="/emp/get/1" th:href="@{'/emp/get/' + ${emp.id}}" class="btn btn-warning btn-xs">编辑</a>&emsp;<!--路径拼接传参,传的是名值对--><a href="#" th:href="@{/emp/remove(id=${emp.id},ename=${emp.ename},job=${emp.job})}" class="btn btn-danger btn-xs">删除</a>
    </td><!--表单传参-->
    <form th:action="@{/auth/login}" method="post" style="width: 350px;margin: 10px auto;"><div style="color: red;">[[${message}]]</div><div class="form-group"><label>用户名</label><input type="text" name="username" class="form-control"></div><div class="form-group"><label>密码</label><input type="password" name="password" class="form-control"></div><div class="form-group"><button type="submit" class="btn btn-primary">登录</button></div>
    </form>
    

SpringMVC配置

/*** 自定义WebMvc配置类* 实现一个接口WebMvcConfigurer的配置类,相当于原生springmvc.xml配置文件*/
@Configuration
public class WebConfig implements WebMvcConfigurer {/*** 动态页面访问映射*/@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/page/login").setViewName("login");registry.addViewController("/").setViewName("login");registry.addViewController("/page/index").setViewName("index");}/*** 注册拦截器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry//配置拦截器对象.addInterceptor(new LoginInterceptor())//配置拦截器拦截路径.addPathPatterns("/**")//配置拦截器放行路径(白名单).excludePathPatterns("/static/**", "/webjars/**", "/auth/login", "/page/login", "/");}/*** 对静态资源处理*/// @Override// public void addResourceHandlers(ResourceHandlerRegistry registry) {//     registry//             .addResourceHandler("/static2/**")//             .addResourceLocations("classpath:/my2/");// }/*** 添加自定义的数据格式转换器*/@Overridepublic void addFormatters(FormatterRegistry registry) {// registry.addFormatter();registry.addConverter(new PointConverter());}/*** 前后端分离的项目:设置全局跨域处理*/@Overridepublic void addCorsMappings(CorsRegistry registry) {}
}

拦截器

public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {Object loginUser = request.getSession().getAttribute("loginUser");if(loginUser == null){request.setAttribute("message", "没有登录");request.getRequestDispatcher("/page/login").forward(request, response);return false;}return true;}
}

类型转换器

/*** 自定义的类型转换器:* 作用:将String转换为自定义Point*/
public class PointConverter implements Converter<String, Point> {@Overridepublic Point convert(String source) {String[] ss = source.split(",");Point point = new Point(ss[0], ss[1]);return point;}
}
<p><a th:href="@{/getPoint(point='15,58')}">类型转换器案例</a></p>

web中的三大组件

  • servlet、filter、listener

  • 默认不支持,需要在配置类中配置bean

  • 配置三大组件

    @Configuration
    public class ServletConfig {/*** 注册servlet*/@Beanpublic ServletRegistrationBean servletRegistrationBean(){ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();//设置Servlet对象servletRegistrationBean.setServlet(new DemoServlet());//设置路径映射servletRegistrationBean.addUrlMappings("/demo");//设置初始化参数//单个servletRegistrationBean.addInitParameter("msg", "hello");//批量// servletRegistrationBean.setInitParameters();return servletRegistrationBean;}/*** 注册Filter*/@Beanpublic FilterRegistrationBean filterRegistrationBean(){FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();filterRegistrationBean.setFilter(new DemoFilter());filterRegistrationBean.addUrlPatterns("/*");// filterRegistrationBean.addInitParameter();return filterRegistrationBean;}/*** 注册Listener*/@Beanpublic ServletListenerRegistrationBean servletListenerRegistrationBean(){ServletListenerRegistrationBean servletListenerRegistrationBean = new ServletListenerRegistrationBean();servletListenerRegistrationBean.setListener(new DemoListener());return servletListenerRegistrationBean;}
    }
    

    DemoFilter.java

    @WebFilter("/*")
    public class DemoFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("DemoFilter执行了.........");//过滤器放行filterChain.doFilter(servletRequest, servletResponse);}
    }
    

    DemoListener.java

    @WebListener
    public class DemoListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {System.out.println("DemoListener执行了.....");}
    }
    

    DemoServlet.java

    @WebServlet("/demo")
    public class DemoServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("DemoServlet.........." + msg);resp.getWriter().write("ok");}private String msg;@Overridepublic void init(ServletConfig config) throws ServletException {msg = config.getInitParameter("msg");}
    }
    

全局异常处理器

  • public class CustomException extends RuntimeException{}
    
  • /*** 全局异常处理器* @RestControllerAdvice:全局异常处理器的注解*/
    // @ControllerAdvice
    @RestControllerAdvice
    public class GlobalExceptionHander {@ExceptionHandler(CustomException.class)public Map<String, Object> customExceptionHandle(CustomException e){Map<String, Object> map = new HashMap<>();map.put("code", -2);map.put("message", "自定义异常发生");return map;}@ExceptionHandler(Exception.class)public Map<String, Object> exceptionHandle(Exception e){Map<String, Object> map = new HashMap<>();map.put("code", -1);map.put("message", "其他异常发生");return map;}
    }
    

全局日期格式化

  • 在SpringMVC使用@DateTimeFormat和@JsonFormat

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    private Date hiredate;
    
  • application.yml

    #全局输入日期格式化,局部@DateTimeFormat
    spring: mvc: format:date: yyyy-MM-dd HH:mm:ss#全局输出日期格式化,局部@JsonFormatjackson:date-format: yyyy-MM-dd HH:mm:sstime-zone: GMT+8
    

配置文件上传

#配置文件上传
spring: servlet:multipart:#单个文件大小限制max-file-size: 1MB#单次请求总文件大小限制max-request-size: 10MB

前后端分离

设置全局跨域处理

  • WebConfig.java配置文件

    /*** 前后端分离的项目:设置全局跨域处理* 浏览器的同源策略:* 在发送异步请求时,请求地址中 协议、服务器地址、服务器端口号必须保持一致* 如果不一致就违反浏览器同源策略,浏览器禁止访问,会接收到一个CORS错误** 注意:协议http与https不同源*      地址localhost与127.0.0.1不同源** 前后端分离的项目:设置全局跨域处理*/
    @Override
    public void addCorsMappings(CorsRegistry registry) {registry//跨域访问的路径(资源).addMapping("/**")//设置允许跨域的服务器地址// .allowedOriginPatterns("http://localhost:63342").allowedOriginPatterns("*")//设置允许跨域访问的请求方式// .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS").allowedMethods("*")//设置允许跨域访问时的头部信息// .allowedHeaders()//设置暴露给请求服务器头部信息// .exposedHeaders()//设置跨域访问时是否允许携带凭证(cookie中JSESSIONID).allowCredentials(true)//跨域访问时会先发送一个询问请求(询问当前请求是否允许跨域)//设置询问请求的发送周期.maxAge(3600);
    }
    
  • 后端资源

    @RestController
    public class UserController {@GetMapping("/user/list")public List<User> list(){User user1 = new User(1, "zhangsan", "123");User user2 = new User(2, "lisi", "123");User user3 = new User(3, "wangwu", "123");User user4 = new User(4, "zhaoliu", "123");return Arrays.asList(user1,user2,user3,user4);}
    }
    
  • 前端请求(另一个项目)

    $.ajax('http://localhost:8080/boot/user/list',{type:'get',success:function (res) {var str='';$.each(res,function () {str+='<tr>';str+='<td>'+this.id+'</td>';str+='<td>'+this.username+'</td>';str+='<td>'+this.password+'</td>';str+='</tr>';});$('#tab').html(str);}
    });
    

外部Tomcat

  • 外部Tomcat支持tomcat jsp,内部Tomcat不支持tomcat jsp

  • 新建项目的时候与SpringBoot相似,唯一不同是打包方式改为war

  • 自己配置TomCat

  • 将静态资源文件放到 webapp/WEB-IF/ 下面

  • 自动生成ServletInitializer.java文件

    /*** 在外部tomcat启动服务器时加载springboot程序* 如果把这个类去掉,不会启动springboot,也就无法使用@Controller等组件*/
    public class ServletInitializer extends SpringBootServletInitializer {@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {return application.sources(SpringBoot05JspApplication.class);}
    }
    
  • 可以使用 jsp 文件

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head><base href="${pageContext.request.contextPath}/"><title>Title</title>
    </head>
    <body><div style="text-align: center"><h1>首页</h1><p><a href="/hello">测试</a></p></div>
    </body>
    </html>
    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head><base href="${pageContext.request.contextPath}/"><title>成功</title>
    </head>
    <body><div style="text-align: center"><h1>成功</h1><p>${message}</p></div>
    </body>
    </html>
    
  • Controller

    @Controller
    public class HelloController {@GetMapping("/hello")public String hello(HttpServletRequest request){System.out.println("HelloController中的hello方法执行了....");request.setAttribute("message", "hello jsp");return "success";}
    }
    
  • application.yml

    #配置jsp页面的前缀与后缀
    spring:mvc:view:prefix: /WEB-INF/pages/suffix: .jsp
    

后端数据校验

  • 新建项目时除了选中工具和核心包外,还要选中IO中的Validation依赖

  • 自动引入依赖

    <!--后台数据校验-->
    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    

数据校验

  • /*** hibernate-validator框架,后台数据校验,通过注解的方式来实现*/
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Accessors(chain = true)
    public class Student {/*** @NotNull 数据不能为null* @NotEmpty 数据不能为null,也不能为空字符串* @NotBlank 数据不能为null,也不能为空字符串,也不能由空白字符组成* @Size 校验字符串、数组、集合的长度* @Range 校验数字的范围* @Email 校验有效是否合法* @Pattern 通过正则表达式校验** 注解通用配置项:message,校验失败时提示信息*/@NotBlank(message = "姓名不能为空")@Size(message = "姓名长度为4~10个字符", min = 4, max = 10)private String name;@NotNull(message = "年龄不能为空")@Range(message = "年龄范围为0~100岁", min = 0, max = 100)private Integer age;@NotBlank(message = "邮箱不能为空")//xxx@xx.xx@Email(message = "邮箱格式不合法")//正则校验// @Pattern(message = "", regexp = "")private String email;
    }
    
  • 开启数据校验

    @RestController
    public class ValidationController {/*** 开启校验 @Validated** 在方法的参数上标注@Validated表示开启后台数据校验,每个开启的数据校验数据之后,需要跟随一个BindingResult类型的参数* BindingResult对象用于接收校验失败的信息*/@PostMapping("/save")public String save(@Validated Student student, BindingResult bindingResult){//判断校验是否通过if(bindingResult.hasErrors()){List<ObjectError> allErrors = bindingResult.getAllErrors();for (ObjectError error : allErrors) {System.out.println(error.getDefaultMessage());}}else{System.out.println(student);}return "ok";}
    }
    

配置文件校验

  • application.yml

    #用于校验配置文件
    user:username: zhangsanage: 20email: aa@aa.aa
    
  • 配置类

    @SpringBootApplication
    //使配置类的注解生效
    @EnableConfigurationProperties(UserProperties.class)
    public class Springboot06ValidationApplication {public static void main(String[] args) {SpringApplication.run(Springboot06ValidationApplication.class, args);}
    }
    
    @Data
    @ConfigurationProperties(prefix = "user")
    //添加批量读取配置文件的类上
    @Validated
    public class UserProperties {@NotBlank(message = "用户名不能为空")@Size(message = "用户名长度为6~16个字符", min = 6, max = 16)private String username;@NotNull(message = "年龄不能为空")@Range(message = "年龄范围为0~100岁", min = 0, max = 100)private Integer age;@NotBlank(message = "邮箱不能为空")@Email(message = "邮箱格式不合法")private String email;
    }
    

正则表达式

  • 可以参考JDK手册:java.util.regex / Pattern

  • 后端使用正则表达式

    public class ParttenTests {@Testpublic void run(){/*** 正则表达式,验证字符串是否符合指定的规则*///1.String类String str = "zhang#123";System.out.println(str.matches("[abc]"));System.out.println(str.matches("[^abc]"));System.out.println(str.matches("[a-zA-Z]"));System.out.println(str.matches("[0-9]"));System.out.println(str.matches("[a-zA-Z0-9]"));System.out.println(str.matches("\\S"));System.out.println(str.matches("\\w{5,10}"));System.out.println(str.matches(".{5,10}"));System.out.println(str.matches(".*"));System.out.println("14345678901".matches("^1[3|5|6|7|8|9]\\d{9}$"));//2.Pattern类boolean result = Pattern.matches("^[0-9]+$", "123");System.out.println(result);//3.Matcher类Pattern pattern = Pattern.compile("^[0-9]+$");Matcher matcher = pattern.matcher("123a");System.out.println(matcher.matches());}
    }
    
  • 前端使用正则表达式

    <script type="text/javascript">var regex = /^[0-9]+$/;var result = regex.test('123');alert(result);
    </script>
    
  • 使用注解

    //正则校验
    // @Pattern(message = "", regexp = "")
    private String email;
    

aop

  • 引入依赖

    <!--aop-->
    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    
  • Controller

    @RestController
    public class AopController {@GetMapping("/list")public String list(){System.out.println("AopController中的list方法....");return "ok";}
    }
    
  • AopAspect.java

    /*** 切面类*/
    @Component
    @Aspect
    // @Order(1)   //设置切面的启动顺序
    public class AopAspect {//公共切点表达式,方式一public static final String POINT_CUT = "execution(* com.bjpowernode.controller.*.*(..))";//公共切点表达式,方式二@Pointcut("execution(* com.bjpowernode.controller.*.*(..))")public void exp(){}/*** 前置通知*/@Before("execution(* com.bjpowernode.controller.*.*(..))")public void before(){System.out.println("切面的前置通知...");}/*** 后置通知*/@After(POINT_CUT)public void after(){System.out.println("切面的后置通知...");}/*** 返回通知*/@AfterReturning(value = "exp()", returning = "result")public void returning(Object result){System.out.println("切面的返回通知..." + result);}
    }
    

连接数据库

使用jdbc

  • 创建项目选择 jdbc api和Mysql Dirver 依赖

  • application.yml

    #使用jdbc
    spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/studentusername: rootpassword: 111111#?切换数据源,需要配置才能生效type: com.alibaba.druid.pool.DruidDataSource#数据源配置initialSize: 5minIdle: 10maxActive: 50maxWait: 30000
    
  • entity层 略

  • dao

    public class DeptDaoImpl implements DeptDao {/*** 注入JdbcTemplate对象* JdbcTemplate是spring-jdbc中提供的工具类,用于操作数据库*/@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic int insert(Dept dept) {String sql="insert into dept(dname,loc) values(?,?)";return jdbcTemplate.update(sql,dept.getDname(),dept.getLoc());}
    }
    
  • 测试

    @SpringBootTest
    class Springboot08JdbcApplicationTests {@Autowiredprivate DataSource dataSource;//查看数据源配置信息@Testvoid contextLoads() {//自带数据源是: HikariDataSourceSystem.out.println("数据源:"+dataSource);}/*** 使用jdbc完成查询*/@Testvoid testJdbc() throws SQLException {Connection connection = dataSource.getConnection();String sql="select deptno,dname,loc from dept where deptno=?";PreparedStatement preparedStatement = connection.prepareStatement(sql);preparedStatement.setInt(1,60);ResultSet resultSet = preparedStatement.executeQuery();while (resultSet.next()){int deptno = resultSet.getInt("deptno");String dname = resultSet.getString("dname");String loc = resultSet.getString("loc");System.out.println("编号="+deptno+" 名字="+dname+" 地址="+loc);}resultSet.close();preparedStatement.close();connection.close();}
    }
    

使用数据库连接池Druid

自定义配置类

  • 引入依赖,版本号不能省略

    <!--德鲁伊数据源,自己写配置类-->
    <dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version>
    </dependency>
    
  • 配置文件按application.yml

    #配置数据源
    spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/studentusername: rootpassword: 111111#切换数据源,需要配置才能生效type: com.alibaba.druid.pool.DruidDataSource#数据源配置initialSize: 5minIdle: 10maxActive: 50maxWait: 30000#开启监控: 监控stat,SQL防火墙wall,日志slf4j,需要配置filters: stat,wall,slf4j
    
  • 自定义的配置类

    /*** 自定义德鲁伊数据源配置类*/
    @Configuration
    public class DruidConfig {@Bean//使用注解使配置文件的数据源生效@ConfigurationProperties(prefix = "spring.datasource")public DruidDataSource dataSource(){DruidDataSource druidDataSource = new DruidDataSource();//可以在这配置,也可以使用配置文件配置
    //        druidDataSource.setInitialSize(10);return druidDataSource;}/*** sql监控的servlet*/@Beanpublic ServletRegistrationBean servletRegistrationBean(){ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();servletRegistrationBean.setServlet(new StatViewServlet());servletRegistrationBean.addUrlMappings("/druid/*");servletRegistrationBean.addInitParameter("loginUsername","admin");servletRegistrationBean.addInitParameter("loginPassword", "123");return servletRegistrationBean;}/*** sql监控过滤器*/@Beanpublic FilterRegistrationBean filterRegistrationBean(){FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();filterRegistrationBean.setFilter(new WebStatFilter());filterRegistrationBean.addUrlPatterns("/*");//排除路径filterRegistrationBean.addInitParameter("exclusions", "/druid/*,*.js,*.css,*.jpg,*.png");return filterRegistrationBean;}
    }
    

自带配置类

  • 引入依赖

    <!--自带启动器的德鲁伊,配置类不用写了-->
    <dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.10</version>
    </dependency>
    
  • 配置

    #使用自带启动类的德鲁伊
    spring:datasource:#切换数据源type: com.alibaba.druid.pool.DruidDataSourcedruid:#必要信息driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/studentusername: rootpassword: 111111#连接池基本信息initial-size: 6min-idle: 7max-active: 15max-wait: 20000#sql监控filter: stat,wall,slf4j#serlvetstat-view-servlet:enabled: trueurl-pattern: /druid/*login-password: 111login-username: root#filterweb-stat-filter:enabled: trueurl-pattern: /*exclusions: "/druid/*,*.js,*.css,*.jpg,*.png"
    

JdbcTemplate工具

  • 封装了jdbc的工具

  • DeptDaoImpl.java

    @Repository
    public class DeptDaoImpl implements DeptDao {/*** 注入JdbcTemplate对象* JdbcTemplate是spring-jdbc中提供的工具类,用于操作数据库*/@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic int insert(Dept dept) {String sql="insert into dept(dname,loc) values(?,?)";return jdbcTemplate.update(sql,dept.getDname(),dept.getLoc());}@Overridepublic List<Dept> select() {/*** queryForList() 批量查询返回数据封装在map集合中* query(sql, rowMapper) 批量查询返回数据封装在指定的实体对象中** RowMapper 行映射器,将字段与实体中的属性对照* BeanPropertyRowMapper 是RowMapper接口的实现类对象,根据字段名称与实体类中属性名称实现自动映射*/String sql = "select deptno, dname, loc from dept order by deptno desc";//手动映射// jdbcTemplate.query(sql, new RowMapper<Dept>(){//     @Override//     public Dept mapRow(ResultSet rs, int rowNum) throws SQLException {//         Dept dept = new Dept();//         dept.setDeptno(rs.getInt("deptno"));//         dept.setDname(rs.getString("dname"));//         dept.setLoc(rs.getString("loc"));//         return dept;//     }// });RowMapper<Dept> rowMapper = new BeanPropertyRowMapper<>(Dept.class);List<Dept> list = jdbcTemplate.query(sql, rowMapper);return list;}@Overridepublic Dept selectById(Integer deptno) {String sql = "select deptno, dname, loc from dept where deptno=?";/*** queryForObject(String sql, RowMapper rowMapper) 返回结果为单行多列* queryForObject(String sql, Class<T> requiredType) 返回结果为单行单列*/// int i = jdbcTemplate.queryForObject(sql, Integer.class);RowMapper<Dept> rowMapper = new BeanPropertyRowMapper<>(Dept.class);Dept dept = jdbcTemplate.queryForObject(sql, rowMapper, deptno);return dept;}
    }
    
  • 测试类

    @SpringBootTest
    class Springboot08JdbcApplicationTests {@Autowiredprivate DataSource dataSource;@Testvoid contextLoads() {//自带数据源是: HikariDataSource//查看数据源配置信息System.out.println("数据源:"+dataSource);if (dataSource instanceof DruidDataSource){DruidDataSource druidDataSource=(DruidDataSource) dataSource;System.out.println(druidDataSource.getInitialSize());System.out.println(druidDataSource.getMinIdle());System.out.println(druidDataSource.getMaxActive());System.out.println(druidDataSource.getMaxWait());}}@AutowiredDeptDao deptDao;@Testvoid testInsert(){Dept dept = new Dept();dept.setDname("采购部");dept.setLoc("深圳");int result = deptDao.insert(dept);System.out.println(result);}@Testvoid testSelect(){List<Dept> list = deptDao.select();for (Dept dept : list) {System.out.println(dept);}}@Testvoid testSelectById(){Dept dept = deptDao.selectById(48);System.out.println(dept);}
    }
    

整合MyBatis

  • 创建项目时,加上MyBatisFramwork依赖

    <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.2</version>
    </dependency>
    
  • 数据库连接池依赖和分页插件

    <!--德鲁伊数据源-->
    <dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.10</version>
    </dependency>
    <!--分页插件-->
    <dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.4.2</version>
    </dependency>
    
  • 配置文件

    #配置数据源
    spring:jackson:date-format: yyyy-MM-ddtime-zone: GMT+8mvc:format:date: yyyy-MM-dddatasource:#切换数据源type: com.alibaba.druid.pool.DruidDataSourcedruid:#必要信息driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/bjpowernodeusername: rootpassword: root#连接池基本信息initial-size: 6min-idle: 7max-active: 15max-wait: 20000#sql监控filter: stat,wall,slf4j#serlvetstat-view-servlet:enabled: trueurl-pattern: /druid/*login-password: 111login-username: root#filterweb-stat-filter:enabled: trueurl-pattern: /*exclusions: "/druid/*,*.js,*.css,*.jpg,*.png"#mybatis配置
    #1.SqlSessionFactory配置bean -- 在自动化配置中已实现
    #2.mapper代理对象配置bean -- 通过注解的方式来实现
    mybatis:#加载核心配置文件#  config-location: classpath:mybatis.xml#加载mapper文件mapper-locations: classpath:mapper/*.xml#  mapper-locations: classpath:mapper/**/*.xml#类型别名type-aliases-package: com.bjpowernode.entity#全局参数: 与加载核心配置文件项冲突configuration:#开启下划线转驼峰map-underscore-to-camel-case: true#日志输出log-impl: org.apache.ibatis.logging.stdout.StdOutImpl#插件:分页(单独配置)#分页组件pagehelper
    pagehelper:#自动识别数据库,应用数据库方言#mysql: select * from table_name limit offset,pageSize#oracle: select * from (select *,rownum myrow from (select * from table_name) where rownum <= 10) where myrow >= 5#  auto-dialect: true#合理化分页reasonable: true
    
  • @SpringBootApplication
    /*** 批量配置mapper代理* 需要指定dao接口所在包*/@MapperScans({@MapperScan(basePackages = "com.bjpowernode.dao"),@MapperScan(basePackages = "com.bjpowernode.dao2")})@MapperScan(basePackages = "com.bjpowernode.dao")
    public class Springboot09MybatisApplication {public static void main(String[] args) {SpringApplication.run(Springboot09MybatisApplication.class, args);}
    }
    
  • entity

    @Data
    public class Emp {private Integer empno;private String ename;private String job;private Integer mgr;private Date hiredate;private Double sal;private Double comm;private Integer deptno;
    }
    
  • dao

    /*** 使用注解来配置mapper代理对象** @Mapper* 作用:为当前接口生成mapper代理对象,并将代理对象放入ioc容器*      类似于spring中单个接口代理对象的配置*/
    @Mapper
    public interface EmpDao {List<Emp> select();Emp selectById(Integer id);int insert(Emp entity);int update(Emp entity);int delete(Integer id);
    }
    
  • mapper

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.bjpowernode.dao.EmpDao"><select id="select" resultType="emp">select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp order by empno asc</select><select id="selectById" parameterType="int" resultType="Emp">select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where empno=#{empno}</select><insert id="insert" parameterType="com.bjpowernode.entity.Emp">insert into emp(ename,job,mgr,hiredate,sal,comm,deptno)values(#{ename},#{job},#{mgr},#{hiredate},#{sal},#{comm},#{deptno})</insert><update id="update" parameterType="com.bjpowernode.entity.Emp">update emp set ename=#{ename},job=#{job},mgr=#{mgr},hiredate=#{hiredate},sal=#{sal},comm=#{comm},deptno=#{deptno}where empno=#{empno}</update><delete id="delete" parameterType="int">delete from emp where empno=#{empno}</delete>
    </mapper>
    
  • service

    public interface EmpService {Map<String, Object> page(Integer pageNumber, Integer pageSize);Emp get(Integer id);boolean save(Emp entity);boolean update(Emp entity);boolean remove(Integer id);
    }
    
    
    @Service
    public class EmpServiceImpl implements EmpService {@Autowiredprivate EmpDao empDao;@Overridepublic Map<String, Object> page(Integer pageNumber, Integer pageSize) {PageHelper.startPage(pageNumber, pageSize);PageInfo<Emp> pageInfo = new PageInfo<>(empDao.select());Map<String, Object> pageMap = new HashMap<>();pageMap.put("list", pageInfo.getList());pageMap.put("total", pageInfo.getTotal());return pageMap;}@Overridepublic Emp get(Integer id) {return empDao.selectById(id);}/*** springboot中事务管理* 使用注解的方式来实现*/@Override@Transactional(rollbackFor = Exception.class)public boolean save(Emp entity) {return empDao.insert(entity) > 0;}@Override@Transactional(rollbackFor = Exception.class)public boolean update(Emp entity) {return empDao.update(entity) > 0;}@Override@Transactional(rollbackFor = Exception.class)public boolean remove(Integer id) {return empDao.delete(id) > 0;}
    }
    
  • Controller

    @RestController
    @RequestMapping("/emp")
    public class EmpController {@Autowiredprivate EmpService empService;@GetMapping("/page")public Map<String, Object> page(Integer pageNumber, Integer pageSize){Map<String, Object> pageMap = empService.page(pageNumber, pageSize);Map<String, Object> result = new HashMap<>();result.put("code", 200);result.put("message", "ok");result.put("data", pageMap);return result;}@GetMapping("/get/{id}")public Map<String, Object> get(@PathVariable("id") Integer id){Map<String, Object> result = new HashMap<>();result.put("code", 200);result.put("message", "ok");result.put("data", empService.get(id));return result;}@PostMapping("/save")public Map<String, Object> save(@RequestBody Emp emp){Map<String, Object> result = new HashMap<>();result.put("code", 200);result.put("message", "ok");result.put("data", empService.save(emp));return result;}@PutMapping("/edit")public Map<String, Object> edit(@RequestBody Emp emp){Map<String, Object> result = new HashMap<>();result.put("code", 200);result.put("message", "ok");result.put("data", empService.update(emp));return result;}@DeleteMapping("/remove/{id}")public Map<String, Object> remove(@PathVariable("id") Integer id){Map<String, Object> result = new HashMap<>();result.put("code", 200);result.put("message", "ok");result.put("data", empService.remove(id));return result;}
    }
    

Api接口文档 swagger

  • 引入依赖

    <!--swagger starter-->
    <dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version>
    </dependency>
    
  • 配置文件

    #swagger自定义配置
    #测试访问文档页面:http://localhost:8080/swagger-ui/index.html
    swagger3:base-package: com.dx.controllername: xxxurl: https://gitee.com/email: 1233453534@qq.comversion: 1.0group-name: dxtitle: "标题 "description: "描述信息"terms-of-service-url: https://gitee.com/license: cxslicense-url: https://gitee.com/#时间格式
    spring:jackson:date-format: yyyy-MM-dd HH:mm:sstime-zone: GMT+8mvc:format:date: yyyy-MM-dd HH:mm:ss#解决swagger3.0和springboot整合的时问题pathmatch:matching-strategy: ant_path_matcher
    
  • 读取配置的类

    @Data
    @ConfigurationProperties(prefix = "swagger3")
    public class SwaggerProperties {// 扫描的包// 给这个包下面的接口创建文档private String basePackage;// 作者姓名private String name;// 作者主页链接private String url;// 作者邮箱private String email;// 版本号private String version;// 分组名称private String groupName;// 文档标题private String title;//文档描述private String description;// 组织地址private String termsOfServiceUrl;// 许可证private String license;// 许可链接private String licenseUrl;
    }
    
  • 注入配置类,配置swagger

    @Configuration
    @EnableConfigurationProperties(SwaggerProperties.class)
    public class SwaggerConfig {@Autowiredprivate SwaggerProperties swaggerProperties;/*** 配置swagger中的标题,描述,联系人,联系方法...*/public ApiInfo getApiInfo(){//创建联系人对象Contact contact = new Contact(swaggerProperties.getName(), swaggerProperties.getUrl(), swaggerProperties.getEmail());return new ApiInfoBuilder().contact(contact).title(swaggerProperties.getTitle()).description(swaggerProperties.getDescription()).version(swaggerProperties.getVersion()).license(swaggerProperties.getLicense()).licenseUrl(swaggerProperties.getLicenseUrl()).termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl()).build();}/*** swagger的配置,基础信息,设置接口路径等等* RequestHandlerSelectors.basePackage()通过指定基础包来生成文档* RequestHandlerSelectors.withMethodAnnotation()通过指定的方法上注解来实现生成文档*/@Beanpublic Docket docket(){return new Docket(DocumentationType.OAS_30).apiInfo(getApiInfo()).select()//文档的生成的位置,两种方式// .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage())).apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).paths(PathSelectors.any()).build();}
    }
    
  • 实体

    @Data
    @ApiModel("学生实体")
    public class Student {@ApiModelProperty("学生编号")private Integer id;@ApiModelProperty("学生姓名")private String name;@ApiModelProperty("学生住址")private String address;@ApiModelProperty("出生日期")private Date birthday;
    }
    
  • Controller

    • 配置对类的描述注解

    • 配置对方法的描述的注解

    • 对参数的注解

      @RestController
      @RequestMapping("/student")
      public class StudentController {@ApiOperation("分页+条件查询 学生信息")@ApiImplicitParams({@ApiImplicitParam(name = "pageNumber", value = "当前页码", required = false, dataType = "Integer",defaultValue = "1", paramType = "query"),@ApiImplicitParam(name = "pageSize", value = "每页条数", required = false, dataType = "Integer",defaultValue = "10", paramType = "query")})@ApiResponses({@ApiResponse(code = 0, message = "成功"),@ApiResponse(code = -1, message = "失败")})@GetMapping("/page")public Result page(@RequestParam(value = "pageNumber",defaultValue = "1") Integer pagerNumber,@RequestParam(value = "pageSize",defaultValue = "5") Integer pageSize,Student student) {System.out.println(pagerNumber);System.out.println(pageSize);System.out.println(student);return Result.success();}@GetMapping("/get/{id}")@ApiOperation("根据ID获取学生信息")@ApiImplicitParam(name="id",value = "学生编号",required = true, dataType="Integer", paramType = "path")public Result get(@PathVariable("id") Integer id) {System.out.println(id);return Result.success();}@PutMapping("/edit")@ApiOperation("编辑学生信息")public Result edit(@RequestBody Student student){System.out.println(student);return Result.success();}@DeleteMapping("/remove/{id}")@ApiOperation("根据编号删除学生信息")@ApiImplicitParam(name = "id", value = "学生编号", required = true, dataType = "Integer", paramType = "path")public Result remove(@PathVariable("id") Integer id){System.out.println(id);return Result.success();}
      }
      
  • 查看swagger页面

    #测试访问文档页面:http://localhost:8080/swagger-ui/index.html
    

其他功能

spring boot 异步

  • 异步调用需要配置注解@Async

  • 启动类 开启异步调用

    //开启异步调用
    @EnableAsync
    
  • 案例:统计耗时

    @Service
    public class AsyncService {/*** 异步调用注解* 在处理请求的业务时,其中核心业务必须在同步处理中完成*                  辅助业务可以在异步处理中完成*/@Asyncpublic void task1(){try {long start = System.currentTimeMillis();//模拟程序执行耗时Thread.sleep(1000);long end = System.currentTimeMillis();System.out.println("task1耗时:" + (end - start) + "毫秒");} catch (InterruptedException e) {e.printStackTrace();}}@Asyncpublic void task2(){try {long start = System.currentTimeMillis();//模拟程序执行耗时Thread.sleep(2000);long end = System.currentTimeMillis();System.out.println("task2耗时:" + (end - start) + "毫秒");} catch (InterruptedException e) {e.printStackTrace();}}@Asyncpublic void task3(){try {long start = System.currentTimeMillis();//模拟程序执行耗时Thread.sleep(3000);long end = System.currentTimeMillis();System.out.println("task3耗时:" + (end - start) + "毫秒");} catch (InterruptedException e) {e.printStackTrace();}}
    }
    
    @RestController
    public class AsyncController {@Autowiredprivate AsyncService asyncService;@GetMapping("/doAsync")public Map<String, Object> doAsync(){long start = System.currentTimeMillis();//调用service中的三个任务方法//同步:第一个方法完成之后才能调用第二方法...耗时:三个方法时间相加//异步:三个方法仅调用,不再登录方法执行完毕,即可向下执行asyncService.task1();asyncService.task2();asyncService.task3();Map<String, Object> map = new HashMap<>();long end = System.currentTimeMillis();map.put("code", 200);map.put("message", "调用方法成功,总耗时为" + (end-start) + "毫秒");return map;}
    }
    

定时任务

  • 在启动类上开启定时任务

    //开启定时任务
    @EnableScheduling
    
  • service 定时任务注解

  • 定时表达式

    @Service
    public class JobService {/*** @Scheduled* 定时任务注解* cron配置项,为定时表达式* 秒 分 时 日 月 周 年(可选)* *星号:表示每,每秒、每分、每时...* ?问好:只能在日和周两个位置出现,排除冲突* -中划线:表示一个范围* ,逗号:表示一个列表值,比如在星期中使用1,2,4*/// @Scheduled(cron = "* * * ? * 1-5")@Scheduled(cron = "0/5 * * ? * 1-5")public void myJob(){System.out.println("定时任务...");}
    }
    

邮件

  • io中的 java mail … 依赖

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
    
  • 开启邮箱pop3的服务,写配置文件

    spring:mail:#邮箱服务器地址     qq:smtp.qq.com    网易163:smtp.163.comhost: smtp.qq.com#授权码,邮箱-》设置-》账户-》POP3/AMTP服务,开启服务后会获得授权码password: xxxxxceoibdaaaaausername: 11118422@qq.comdefault-encoding: UTF-8
    
  • 发送简单的内容

    @Autowired
    private JavaMailSender javaMailSender;/*** 发送基本的内容(纯文本)*/
    @Test
    void testSend() {SimpleMailMessage simpleMailMessage = new SimpleMailMessage();//发件人simpleMailMessage.setFrom("11112342@qq.com");//收件人simpleMailMessage.setTo("22212342@qq.com");//主题simpleMailMessage.setSubject("这是一个测试邮件20220812");//邮件内容simpleMailMessage.setText("测试内容2022-08-12");javaMailSender.send(simpleMailMessage);
    }
    
  • 发送邮件工具类

    • 添加文件
    • 添加附件
    /*** 测试发送复杂内容,例如图片和附件等*/
    @Test
    void testSend2() throws MessagingException {MimeMessage mimeMessage = javaMailSender.createMimeMessage();// 创建一个邮件工具,可以发送附件MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage,true,"utf-8");mimeMessageHelper.setFrom("28718422@qq.com");mimeMessageHelper.setTo("28718422@qq.com");mimeMessage.setSubject("这是一个携带了图片和附件的邮件20220812");//拼接内容参数StringBuilder sb = new StringBuilder();sb.append("<html> <body> <h1 style='color:red'>springboot 测试邮件发送复杂格式o</h1>");sb.append("<p style='color:blue;font-size:16px'>哈哈哈</p>");sb.append("<p style='text-align:center'>居中</p>");sb.append("<img src='cid:picture'/> </body></html>");  //如果要插入图片src='cid:picture'//设置内容,可以被html解析mimeMessageHelper.setText(sb.toString(), true);// 从本地磁盘中读取到图片 站位到内容中去mimeMessageHelper.addInline("picture",new File("C:\\Users\\NINGMEI\\Desktop\\aaa\\ddd.jpg"));// 添加附件mimeMessageHelper.addAttachment("SpringBoot.doc",new File("D:\\course\\05-SpringBoot\\springboot\\document\\SpringBoot.doc"));javaMailSender.send(mimeMessage);
    }
    

SpringBoot知识点总结-DX的笔记相关推荐

  1. SpringBoot整合第三方技术学习笔记(自用)

    SpringBoot整合第三方技术学习笔记 搬运黑马视频配套笔记 KF-4.数据层解决方案 KF-4-1.SQL 回忆一下之前做SSMP整合的时候数据层解决方案涉及到了哪些技术?MySQL数据库与My ...

  2. springboot知识点整理(2021)

    springboot知识点整理 参考网址 https://mp.weixin.qq.com/s/GjjxJt8OauumW_J2ps7tow Demo 脚手架项目地址: https://github. ...

  3. springboot中下面哪一个作为jpa默认实现_35个超高频SpringBoot知识点(附解析),别怪我没给你机会收藏...

    Spring Boot 是微服务中最好的 Java 框架. 我们建议你能够成为一名 Spring Boot 的专家.本文精选了三十五个高频的Spring Boot知识点,助你一臂之力! 35问 问题一 ...

  4. SEO优化知识点以及思路学习笔记

    文章目录 前言 实用网站 工具网站 SEO知识博客 一.初步认识SEO 二.网页爬虫的管理规则 三.链接提交与页面收录 四.知识点学习 4.1.了解权重 4.2.点击率.访问量与停留时间 五.SEO优 ...

  5. springboot尚硅谷雷神学习笔记

    学习要求 熟悉Spring基础 熟悉Maven使用 环境要求 Java8及以上 Maven 3.3及以上:https://docs.spring.io/spring-boot/docs/current ...

  6. 《你不知道的JavaScript上卷》知识点整理与读书笔记

    各位路过的的大佬.求关注.求点赞.谢谢 第一部分 作用域和闭包 第1章 作用域是什么 1.1编译原理 1.2理解作用域 1.3作用域嵌套 1.5异常 第2章 词法作用域 2.1词法阶段 2.2欺骗词法 ...

  7. CSS知识点之W3schools学习笔记

    近来把在w3schools上面把html.css.javascript的知识又从头到尾过了一遍,又发现了一些平时不了解的知识点,在此作下CSS的笔记,前端技术无穷尽,要时时学习时时总结! 1. tex ...

  8. 搭建SpringBoot、Jsp支持学习笔记

    Spring Boot 添加JSP支持 大体步骤: (1)            创建Maven web project: (2)            在pom.xml文件添加依赖: (3)     ...

  9. springboot中接口实例化_疫情爆发在家闲出屁的我,梳理一下SpringBoot知识点

    在过去两三年的Spring生态圈,最让人兴奋的莫过于Spring Boot框架.或许从命名上就能看出这个框架的设计初衷:快速的启动Spring应用.因而Spring Boot应用本质上就是一个基于Sp ...

最新文章

  1. 重构是提高可测试性的主要手段 《设计模式》《代码重构》《从重构到模式》 《反模式》 重构时机 编写测试时候 修改BUG时候
  2. 【SSM框架系列】SpringMVC的请求和响应
  3. Python与MySQL
  4. (四)代码优化 (快来看看怎样写出真正高性能的代码)
  5. flash java 通信,Flash到JavaScript的通信实例
  6. win10存储池_3个光威480G SSD组WIN10存储池,深度测试到底值不值得搞
  7. html里面textfield属性,StyleableTextField的CSS属性htmlText
  8. “Python编程及大数据应用”课程教师(厦门)寒假研修班
  9. codevs 5958 无
  10. java-----抽象类与接口
  11. HTML语言的一些元素(二)
  12. 关于如果减少勒索病毒的侵扰:
  13. MSN在线代码|QQ在线客服代码|SKYPE 贸易通在线代码
  14. Python Pyecharts模块Map绘制中国地图自定义省份名称
  15. 2020年回顾,这一年,不容易
  16. slim 搭建rnn_RNN入门(三)利用LSTM生成旅游点评
  17. xubuntu language support
  18. C语言:在屏幕输出如下图案(*/ )
  19. SWUST OJ题目解析(C语言):160促销计算
  20. 奇异值分解SVD数学原理及代码(Python)

热门文章

  1. springboot注解@NotNull,@NotBlank,@Valid自动判定空值
  2. EMCP应用于——空调系统远程管理物联网云平台
  3. python 生成词云图
  4. oracle impdp参数,expdp impdp参数详细
  5. 做好博客平台,互通知识有无
  6. CVPR 2021 论文大盘点-图像修复篇
  7. 年历显示。功能要求:1.输入一个年份,输出时在屏幕上显示该年的日历。假定输入的年份在1940-2040年之间。2.输入年月,输出该月的日历。
  8. 企业采购如何才能更高效的进行?
  9. 根据自己的学习经验,推荐给大家一些Java方向的“技术提升秘籍”
  10. python读取前两列数据对比_使用Python的Dataframe取两列时间值相差一年的所有行方法...