SpringBoot知识点总结-DX的笔记
什么是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:/ --优先级4classpath:/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> <!--路径拼接传参,传的是名值对--><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的笔记相关推荐
- SpringBoot整合第三方技术学习笔记(自用)
SpringBoot整合第三方技术学习笔记 搬运黑马视频配套笔记 KF-4.数据层解决方案 KF-4-1.SQL 回忆一下之前做SSMP整合的时候数据层解决方案涉及到了哪些技术?MySQL数据库与My ...
- springboot知识点整理(2021)
springboot知识点整理 参考网址 https://mp.weixin.qq.com/s/GjjxJt8OauumW_J2ps7tow Demo 脚手架项目地址: https://github. ...
- springboot中下面哪一个作为jpa默认实现_35个超高频SpringBoot知识点(附解析),别怪我没给你机会收藏...
Spring Boot 是微服务中最好的 Java 框架. 我们建议你能够成为一名 Spring Boot 的专家.本文精选了三十五个高频的Spring Boot知识点,助你一臂之力! 35问 问题一 ...
- SEO优化知识点以及思路学习笔记
文章目录 前言 实用网站 工具网站 SEO知识博客 一.初步认识SEO 二.网页爬虫的管理规则 三.链接提交与页面收录 四.知识点学习 4.1.了解权重 4.2.点击率.访问量与停留时间 五.SEO优 ...
- springboot尚硅谷雷神学习笔记
学习要求 熟悉Spring基础 熟悉Maven使用 环境要求 Java8及以上 Maven 3.3及以上:https://docs.spring.io/spring-boot/docs/current ...
- 《你不知道的JavaScript上卷》知识点整理与读书笔记
各位路过的的大佬.求关注.求点赞.谢谢 第一部分 作用域和闭包 第1章 作用域是什么 1.1编译原理 1.2理解作用域 1.3作用域嵌套 1.5异常 第2章 词法作用域 2.1词法阶段 2.2欺骗词法 ...
- CSS知识点之W3schools学习笔记
近来把在w3schools上面把html.css.javascript的知识又从头到尾过了一遍,又发现了一些平时不了解的知识点,在此作下CSS的笔记,前端技术无穷尽,要时时学习时时总结! 1. tex ...
- 搭建SpringBoot、Jsp支持学习笔记
Spring Boot 添加JSP支持 大体步骤: (1) 创建Maven web project: (2) 在pom.xml文件添加依赖: (3) ...
- springboot中接口实例化_疫情爆发在家闲出屁的我,梳理一下SpringBoot知识点
在过去两三年的Spring生态圈,最让人兴奋的莫过于Spring Boot框架.或许从命名上就能看出这个框架的设计初衷:快速的启动Spring应用.因而Spring Boot应用本质上就是一个基于Sp ...
最新文章
- 重构是提高可测试性的主要手段 《设计模式》《代码重构》《从重构到模式》 《反模式》 重构时机 编写测试时候 修改BUG时候
- 【SSM框架系列】SpringMVC的请求和响应
- Python与MySQL
- (四)代码优化 (快来看看怎样写出真正高性能的代码)
- flash java 通信,Flash到JavaScript的通信实例
- win10存储池_3个光威480G SSD组WIN10存储池,深度测试到底值不值得搞
- html里面textfield属性,StyleableTextField的CSS属性htmlText
- “Python编程及大数据应用”课程教师(厦门)寒假研修班
- codevs 5958 无
- java-----抽象类与接口
- HTML语言的一些元素(二)
- 关于如果减少勒索病毒的侵扰:
- MSN在线代码|QQ在线客服代码|SKYPE 贸易通在线代码
- Python Pyecharts模块Map绘制中国地图自定义省份名称
- 2020年回顾,这一年,不容易
- slim 搭建rnn_RNN入门(三)利用LSTM生成旅游点评
- xubuntu language support
- C语言:在屏幕输出如下图案(*/ )
- SWUST OJ题目解析(C语言):160促销计算
- 奇异值分解SVD数学原理及代码(Python)
热门文章
- springboot注解@NotNull,@NotBlank,@Valid自动判定空值
- EMCP应用于——空调系统远程管理物联网云平台
- python 生成词云图
- oracle impdp参数,expdp impdp参数详细
- 做好博客平台,互通知识有无
- CVPR 2021 论文大盘点-图像修复篇
- 年历显示。功能要求:1.输入一个年份,输出时在屏幕上显示该年的日历。假定输入的年份在1940-2040年之间。2.输入年月,输出该月的日历。
- 企业采购如何才能更高效的进行?
- 根据自己的学习经验,推荐给大家一些Java方向的“技术提升秘籍”
- python读取前两列数据对比_使用Python的Dataframe取两列时间值相差一年的所有行方法...