SpringBoot
原创笔记
SpringBoot发展历史:
2002年,当时正是Java EE和EJB大行其道的时候,很多知名公司都是采用此技术方案进行项目开发。这时候有一个美国的小伙子认为 EJB 太过臃肿,并不是所有的项目都需要使用 EJB 这种大型框架,应该会有一种更好的方案来解决这个问题。
1、Spring1.x 时代
在Spring1.x时代,都是通过xml文件配置bean,随着项目的不断扩大,需要将xml配置分放到不同的配置文件中,需要频繁的在java类和xml配置文件中切换。
2、Spring2.x时代
随着JDK 1.5带来的注解支持,Spring2.x可以使用注解对Bean进行申明和注入(spring2.5),大大的减少了xml配置文件,同时也大大简化了项目的开发。那么,问题来了,究竟是应该使用xml还是注解呢?我们最终选择的是应用的基本配置(如数据库配置)使用xml,业务的配置用注解。
3、Spring3.x到Spring4.x
从Spring3.x开始提供了Java配置方式,使用Java配置方式可以更好的理解你配置的Bean,并且Spring4.x和Spring boot都推荐使用java配置的方式。
Pivotal 公司成立之后,于 2014 年发布了 Spring Boot,2015 年发布了 Spring Cloud,2018 年 Pivotal 公司在纽约上市。
springboot 简介:
Spring Boot 是由 Pivotal 团队提供的全新框架。Spring Boot 是所有基于 Spring Framework 5.0 开发的项目的起点。Spring Boot 的设计是为了让你尽可能快的跑起来 Spring 应用程序并且尽可能减少你的配置文件。
设计目的:用来简化新 Spring 应用的初始搭建以及开发过程。
从最根本上来讲,Spring Boot 就是一些库的集合,它能够被任意项目的构建系统所使用。它使用 “习惯优于配置” (项目中存在大量的配置,此外还内置一个习惯性的配置)的理念让你的项目快速运行起来。用大佬的话来理解,就是 spring boot 其实不是什么新的框架,它默认配置了很多框架的使用方式,就像 maven 整合了所有的 jar 包,spring boot 整合了所有的框架
版本说明:
项目创建:
一般都是创建一个空格project,里面创建spring-initer模块
snapshot 开发版,不稳定
后边不带snapshot是稳定版,也就是默认带RELEASE
mvnw maven
mvnw.cmd 这两个都是命令的文件,国内基本用不上
配置读取:
- @ConfigurationProperties(prefix="")注解必须要添加前缀,也就是没有前缀无法读取
需要成员变量名称和配置文件去掉前缀的名称一致
没有set方法的字段不会读入配置参数
1.在类上面添加注解
会自动读取配置,通过set方法注入到类的成员变量里面
2.可以标注在方法上面
这样会直接通过set方法,注入到返回对象的参数里面
-
@Value("${xx}")指定具体读取哪个配置参数给下面的成员变量(要写全称)
可以读取没有set方法的字段
上面两个注解可以结合@PropertySource("位置:文件名") 读取其他properties文件
(注意:这个注解不能读取yaml文件......)
@PropertySource("classpath:nima.properties")
不写@PropertySource默认读取application.yml/properties配置文件
神器:
1.创建启动类和配置文件, JBLSpringAppGen 一定要下载哦
这个东西是陷阱,妈的下载不了
2.JRebel 热部署插件
3.JSON-handle chrome插件
4.mybatisx idea插件
自动化配置
项目由父依赖控制版本
springboot使用了全新的一套starter体系,不同于传统的maven依赖
我们需要使用什么组件时,直接导入启动器坐标,不需要写版本,就是从父依赖取出.
一定要导入start-web,不然没有启动器,boot运行后直接结束
设置banner
在resource下面新建一个banner.txt,放入想要的banner
单元测试
需要导入starter-test
@Runwith(SpringRunner.class) //SpringRunner和SpringRunner4JUnit一模一样的,好像可以不使用这个注解了
@springbootTest
springboot的测试类上面必须添加这两个注解
注意必须导入import org.junit.Test;不要导错包
一般只需要测试controller层和service层
service层比较简单,直接注入service,测试方法就可以了
controller层使用单元测试比较复杂,需要用mockmvc模拟
重要注解:
大致的注解和mvc相同
@springBootApplication 启动类上面添加,启动类必须放在包的最外面
@RestController 集成了controller,里面所有的方法都返回json的字符串,所以内部方法不需要@ResponseBody
@Controller 如果还需要返回视图,那么就需要用这个注解,后面需要带上@ResponseBody
@GetMapping,PostMapping 这个注解还可以接收多个映射地址
@RequestBody在参数前面,表示收到的参数都是请求体内容
加不加这个注解影响很大
ajax的post请求和axios的post请求携带的参数默认在body里
ajax和axios的请求头内容需要自己进行拼接的,直接写在参数里面的默认为请求体
就是postman里面的body
不加这个参数携带的内容都是请求头里面的,会在地址栏出现
自动化配置原理:
@springBootApplication注解组合了
@springbootconfiguration,@enableautoconfiguration(自动读取META-INF/spring.factories的配置类)
yml:
yml是boot推荐的,比起properties,功能更加强大,而且不会乱码,可以进行格式检验
这是一种非标记语言,通过 冒号,缩进等组织数据,格式比较严格
与properties除了展示形式不同以外,其他功能一模一样,读取方式也不需要改变
语法:
1.树状层级结构,如果有关系,下一行开始空两格
2.值前面,冒号后面一定要有空格
3.数组与对象的表示
-
# 数组形式还可以写成namelist: [zhang, li,wang]
# 对象形式还可以写成 user: {name: zhangsan,age: 12}
空格没有强制的数量限制,只要对齐,就属于同一级别.
大小写敏感,松散表示
一定要用空格键,而不是tab
注意,里面的并列一定要用分号; 隔开, 而不是逗号
application.yml导入其他yml,application-xx.yml
这里的profiles就是指不同的生产环境,因此也可以用来设置不同的环境
开发环境:application-dev
测试环境:application-test
准生产环境:
生产环境:application-prod
spring:
profiles:
active:xx,xx
全局异常处理
springmvc里面实现HandlerExceptionResolver接口
boot里面也是使用相同的思路,也是定义一个全局异常处理类
用@ControllerAdvice标注为切面类(组合了@component)
用@ExceptionHandler(value = Exception.class)( 标注接收的异常类型)
这里面的方法也是返回modelandview对象,所以如果不是返回视图的话,需要用@ResponseBody
同样的操作,可以在上面标注@RestControllerAdvice,后面方法上不需要添加@ResponseBody
被全局异常捕获以后,console就不会报错信息了
推荐定义一个状态码,或者依据公司的定义,不要乱写
我也觉得应该使用阿里状态码
有一个规范以后,就可以通过enum定义状态
小小例子:
public enum BizCodeEnum
{
UNKOW_EXCEPTION(10000, "其他错误"),
VALID_EXCEPTION(10001, "参数错误");
public Integer getCode()
{
return code;
}
public String getMessage()
{
return message;
}
private BizCodeEnum(int code, String message)
{
this.code=code;
this.message=message;
}
private final Integer code;
private final String message;
}
1.第一种写法,超级重要
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Map<String,Object>handle(Exception e)
{
e.printStackTrace(); //打印日志信息 ,超级重要
Map<String,Object>map=new HashMap<>();
map.put("code",500);
map.put("msg","系统异常请重试");
if(e instanceof ParamsException)
{
ParamsException paramsException= (ParamsException) e;
map.put("code",500);
map.put("msg",paramsException.getMessage());
}
else if (e instanceof BindException)
{
BindException bindException = (BindException) e;
map.put("code", 500);
map.put("msg", bindException.getBindingResult().getFieldError().getDefaultMessage());
}
return map;
}
如果请求出错, 默认访问/error接口
springboot给我们提供了error接口的处理方法
2.或者继承ErrorController接口,这种写法不会抛出异常信息了,谨慎使用
@Controller
public class MyErrorController implements ErrorController
{
@Override
public String getErrorPath()
{
return null;
}
}
//然后编写error处理接口
@RequestMapping("/error")
public Map<String, Object> handleError() {
//用Map容器返回信息
Map<String, Object> map = new HashMap<String, Object>();
map.put("code", 404);
map.put("msg", "不存在");
return map;
}
普世修改方法
非常重要
autoconfig包下META_INF里面的spring.fatories文件定义了许多自动配置了
每次添加组件,都会进行自动配置
找到autoconfig包下面自己需要修改的组件
在下面的properties里面找到对应的标识符 xx.xx.xx
然后在applicaton.properties下面根据标识符修改
或者直接在yml里面点击进去,也能进入xx.properties文件
整合日志
默认的日志系统是logback,已经在web里面包含,所以不需要额外引入
一般也不修改配置,会使输出的日志失去颜色,变得很丑
只需要注意一下日志的输出方法:
```
Logger l=LoggerFactory.getLogger(启动类.class);
l.info/error/debug("msg");
```
注意导包问题,LoggerFactory和Logger都是slf4j从包里面的
整合mvc:
修改tomcat默认端口
在web下面的serverProperties
所以修改为server.port=80
修改项目路径
server.servlet.conetext-path=/name
server:
port: 80
servlet:
context-path: /name
静态资源:
指这些资源可以被浏览器直接访问到
resources下面可以有四种类型的文件夹,会被boot自动识别
static,public,resources
一般把(js,css,html,img)等静态资源放在static目录下面,浏览器访问时不需要添加/static前缀
也可以通过配置修改静态目录
spring:
web:
resources:
static-locations: /momo/
模板引擎(thymeleaf在templates下面会被视图解析器自动识别,但是不能直接被浏览器访问,需要配置静态目录)
如果不配置视图解析,则需要写文件全称,不能省略.html
例:
@GetMapping("addPage")
public String addPage()
{
return "/view/add.html";
}
视图解析:
spring:
mvc:
view:
prefix: /view/
suffix: .html
@GetMapping("addPage")
public String addPage()
{
return "add";
}
注意:直接访问的页面和经过视图转发得到的页面他们的请求头是不一样的
转发
拦截器:
1.编写自己的拦截器MyInterceptor ,实现HandlerInterceptor接口(同mvc)
public class AuthInterceptor implements HandlerInterceptor
{
@Autowired
private HttpSession session;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
if (!(handler instanceof HandlerMethod))
{
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
List<String> permission = (List<String>) session.getAttribute("permissions");
if (permission == null || permission.size() == 0)
{
throw new NoLoginException();
}
RequirePermission per = handlerMethod.getMethod().getDeclaredAnnotation(RequirePermission.class);
if (per!=null&&!permission.contains(per.code()))
{
throw new NoLoginException();
}
return true;
}
}
2.编写配置类WebmvcConf 实现WebmvcConfigurer接口
//1.使用@configuation标志为配置类
@Configuration
public class InterceptorConfig implements WebMvcConfigurer
{
// 2.注册拦截器
@Autowired
GlobalHandleInterceptor interceptor;
@Bean
public NoLoginInterceptor noLoginInterceptor()
{
return new NoLoginInterceptor();
}
@Bean
public AuthInterceptor authInterceptor()
{
return new AuthInterceptor();
}
//3.添加至拦截器链
@Override
public void addInterceptors(InterceptorRegistry registry)
{
//pwvi拦截器
registry.addInterceptor(interceptor).addPathPatterns("/**");
// registry.addInterceptor(authInterceptor()).addPathPatterns("/**").excludePathPatterns("/index","/main");
registry.addInterceptor(noLoginInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/index", "/user/login", "/css/**", "/images/**", "/js/**"
, "/lib/**");
}
}
跨域处理:
和上面类似,不过拦截器已经被官方写好了,我们只需要注册就行了
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.maxAge(3600);
}
}
整合连接池:
-
添加druid坐标,mysql-connector坐标
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.5</version> </dependency>
-
配置 :
通过spring配置的话,会自动注入容器,我们就不需要自己注入了
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
username: root
password: happycode0125
或者使用springboot官方推荐的连接池hikari(默认),就不需要设置type
hikari在速度上比druid快
mysql-connector8以上,数据库配置时差问题,需要设置上海时间或者北京时间
一定要设置unicode编码,不然数据库内中文就会变成?
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
username: root
password: happycode0125
整合mybatis:
需要先整合连接池
数据库字段一般使用下划线命名法,这里参考一下阿里建表规约
mybatis不能自动创建表,需要借助hibernate
-
添加坐标,这个组件是由mybaits出的,所以不一样mybatis-spring-boot-starter
-
配置(实体类包名(以后就只需要类名),日志记录)
mybatis:
type-aliases-package: cn.momoshenchi.demo.pojo
mapper-locations: classpath:/mappers/*.xml # 设置了xml映射文件位置
configuration:
map-underscore-to-camel-case: true # 设置下划线转驼峰
logging:
level:
cn:
momoshenchi:
demo:
dao: debug
#使用spring boot调试好的语句输出sql语句,格式十分美观
#通过logging可以定义各种日志
-
编写xml文件,模板如下(mybatis的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="cn.momoshenchi.dao层接口类名" > //业务方法 </mapper>
-
接口层的编写如下
增删改方法都返回int(受影响的行数)
List<CusDevPlan> selectAll(Integer sid); Integer insert(CusDevPlan cusDevPlan); Integer updateByPrimaryKey(CusDevPlan cusDevPlan); Integer deleteByPrimaryKey(ID id) throws DataAccessException;
-
事务提交(和spring里面相同)
在需要的service方法上面添加@Transaction(propagation =Propagation.REQUIRED)
REQUIRED支持当前事务,如果当前没有事务,就新建一个事务.这是最常见的选择. -
然后一般在启动器类上面添加mapper文件夹扫描(@MapperScan(dao中mapper接口层的全包名))
基本操作:
增删改查 分页
每个操作时都要判断一下是否操作成功
一般parameterType都不需要写
select操作 resultType必须写,如果没有实体,也可以通过resultmap可以设置自定义返回对象(以及名字不相同的映射)
增改时(service层)(也可以把一部分校验放在pojo里面,另外一部分需要查询数据库的放在service里面)
1.参数检验(用户名非空,是否已经存在) 使用commons-lang工具类判断,自己也写一个工具类判断(会抛出异常)
修改操作时(有唯一值),要判断是否为自己本身
比如:我要改name,如果name是自己本身,可以修改其他信息.如果name是别人已存在,那就不能修改
//一般字符串使用StringUtil.isBlank判断非空
// 对象使用 ==null 判断非空
唯一性判断(比较麻烦)
insert时只需要判断是否存在一样的
update需要判断一样的是不是自己本身
2.设置默认值(创建日期,is_valid等等字段)
3.判断操作是否成功
删除时一般也是假删,不然为什么能够找回啊
一般都是设置一个状态,然后修改状态(都是update操作)
分页:
使用分页插件,然后自己封装一个xxQuery 里面有第几页,每页数量,查询参数
自己写 (第几页-1)*记录数,记录数
service(把查询好的list传进去,就完成了)
其实底层就是使用数据库的limit关键字进行分页查询
注意:如果要使用分页插件,自己的sql语句后面不能加分号
PageHelper.startPage(第几页,每页条数);
PageHelper.startPage(第几页,每页条数);
//查询操作(自己写sql语句不需要考虑分页,分页插件会修改你的语句,自动在后面添加limit)
PageInfo<User> pageInfo=new PageInfo<>(list);
Map<String, Object> map = new HashMap<>();
map.put("code", 200);
map.put("msg", "成功");
map.put("data",list);
map.put("totalItem",pageInfo.getTotal());
map.put("currentPage",page);
map.put("size",size);
return map;
直接返回pageInfo对象包含了许多属性,可能有很多我们不需要
mybatis标签:
concat('','') 也是拼接sql语句,不过是sql函数
now()
数据校验:
service层这里的参数检验,也可以由valid模块检验
jsr 303:是一项标准,提供了一些规范
spring mvc里面添加了自动校验的模块,是对jsr303的实现
1.首先需要导入starter-validation
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
2.在bean上面加上校验的注解(见下面的常用注解),使用message输出不符合的信息
例如:
@Valid只是一个规范,里面啥也没有
而@Validated 里面有一个class[]数组
3.在controller接口方法的形参上面添加@Valid或者@Validated
其后可以添加BindingResult 参数来接收返回信息,但是很麻烦,一般使用全局异常处理
数据校验必须和全局异常一起使用
4.不符合校验后,会抛出BindException(注意bindException不要导包错误).
使用bindException.getBindingResult().getFieldError().getDefaultMessage()获取设置的message
超级常用的写法
if (e instanceof BindException)
{
BindException bindException = (BindException) e;
map.put("code", 500);
map.put("msg", bindException.getBindingResult().getFieldError().getDefaultMessage());
}
分组:
新增和修改可能需要使用不同的校验方法,所以我们可以使用分组校验
适合多场景的校验
可以通过groups指定什么情况使用什么校验方式
groups是一个class[],可以设置标志性接口来定义
此时必须使用@Validated
如果@Validated指定了分组,那么所有的pojo字段都必须添加分组,没有分组就不会起作用
如果@Validated没有携带分组信息,就可以校验pojo字段也没有携带的
常用注解:
字符串:
@NotNull 不能为null,但是可以为空
@NotEmpty 不能为null,trim后可以为""
@NotBlank 不能为null,trim后也不能是""
@Length 字符串的长度必须在指定范围内
@URL hibernate提供的 ,也需要添加非空判断
@Pattern 正则表达式校验,只能用于String
数字:
@min,@max
数组
@Size 集合,数组,map的size必须在指定范围内
自定义校验:
适合及其复杂的校验
通过自定义注解来实现
然后指定校验器@Constraint(validatedBy) 实现ConstraintValidator<>
示例:
整合spring data jpa:
1.导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
2.配置
基本的数据库连接池,配置jpa
ddl-auto:
create
:每次运行程序时,都会重新创建表,故而数据会丢失create-drop
:每次运行程序时会先创建表结构,然后待程序结束时清空表upadte
:每次运行程序,没有表时会创建表,如果对象发生改变会更新表结构,原有数据不会清空,只会更新(推荐使用)validate
:运行程序会校验数据与数据库的字段类型是否相同,字段不同会报错none
: 禁用DDL处理
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://47.98.50.20:3306/test?serverTimezone=Asia/Shanghai
username: root
password: Woai?520xunuo
jpa:
database: MySQL
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
show-sql: true
hibernate:
ddl-auto: update
3.使用
注解:
@Entity( name= "xx")如果数据库名称不是pojo名称,可以进行指定
@Id 注解表明该属性字段是一个主键,该属性必须具备,不可缺少。
@GeneratedValue(strategy = GenerationType.IDENTITY)
主键生成策略:
JPA自带的几种主键生成策略
- TABLE: 使用一个特定的数据库表格来保存主键
- SEQUENCE: 根据底层数据库的序列来生成主键,条件是数据库支持序列。这个值要与generator一起使用,generator 指定生成主键使用的生成器(可能是orcale中自己编写的序列)
- IDENTITY: 主键由数据库自动生成(主要是支持自动增长的数据库,如mysql)
- AUTO: 主键由程序控制,也是GenerationType的默认值
@Column () 设置数据库字段
@Query 自定义查询操作(可以select/update)
dao层继承JpaRepository<pojo,ID> , 即可基本的增删改查功能(有一定的命名规范)
findById(),findAll()
deleteById()
save() // 实现了insert和update,会自动根据数据判断增删改
DAO:
如果jpa提供的基本增删改查不满足需要,可以自己添加sql语句(操作jpa的核心)
位置绑定:
@Query 注解的使用非常简单,只需在声明的方法上面标注该注解,同时提供一个 JPQL 查询语句即可
@Query("select u from User u where u.email = ?1")
User getByEmail(String eamil);
@Query("select u from User u where u.username = ?1 and u.password = ?2")
User getByUsernameAndPassword(String username, String password);
@Query("select u from User u where u.username like %?1%")
List<User> getByUsernameLike(String username);
参数绑定:
默认情况下,Spring Data JPA使用基于位置的参数绑定,如前面所有示例中所述。 这使得查询方法在重构参数位置时容易出错。 要解决此问题,可以使用@Param
注解为方法参数指定具体名称并在查询中绑定名称,如以下示例所示:
@Query("select u from User u where u.id = :id")
User getById(@Param("id") String userId);
@Query("select u from User u where u.username = :username or u.email = :email")
User getByUsernameOrEmail(@Param("username") String username, @Param("email") String email);
分页:
//dao正常使用,只是多加了一个 Pageable 参数而已
@Query("select t from Teacher t where t.subject = :subject")
Page<Teacher> getPage(@Param("subject") String subject, Pageable pageable);
service层
使用pageRequest组装page参数
PageRequest request = PageRequest.of(page-1,size);
Page<Student> list = studentMapper.findAll(request);
//使用getTotalElements获取总共数据
Map<String, Object> map = new HashMap<>();
map.put("code", 200);
map.put("msg", "成功");
map.put("data",list.getContent());
map.put("totalItem",list.getTotalElements());
map.put("currentPage",page);
map.put("size",size);
性能优化:
尽量不要使用select * ,而是列出所有字段
使用缓存和mq进行多数据库联动
mybatis-G:
这是一个插件,使用maven导入
根据数据库表生成bean,interface.一般数据库表是启动sql脚本文件生成,而脚本文件是通过power-designer生成的
可以将数据库下划线命名法字段改成驼峰命名法的java bean
会自动使用包装类型代替基本类型,例如:使用Integer代替int来创建bean里面的变量
1.导入坐标
在plugin里面添加mybtis-generator,添加generatorConfig配置文件位置
2.配置
generatorConfig.xml(最核心的配置文件)
设置数据库连接信息,设置jdbc-connnect位置,设置不生成注解(因为注解都是英语的,没有什么用)
设置pojo,mapper,dao的位置
<table指定每张数据库表以及对应的bean
3.使用
双击maven里面的mybatis-generator
mybatis-p:
原来现在使用这个的比较多,大体上配置和mybatis相似,但是使用上面和hibernate相似
也可以生成代码
mybatis-plus:
type-aliases-package: cn.momoshenchi.demo.pojo
mapper-locations: classpath:/mappers/*.xml # 设置了xml映射文件位置
configuration:
map-underscore-to-camel-case: true # 设置下划线转驼峰
global-config:
db-config:
id-type: auto
但是字段类似于jpa,没搞懂为什么要加注解..不会是写好基本增删改查的那种吧..
通用mapper:
通用mapper,也不是springboot官方推出的
导入坐标 mapper-spring-boot-starter,
大致使用和room是相似的(在实体类上面标注table ,id,keysql,) 但是不需要在mapper上面标注
可以直接在service里面使用
最后也要在启动器上面添加mapper扫描(写法一样,但是包名不一样,一定要注意)
整合redis
简单示例,具体见redis文档
-
添加坐标 spring data redis
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
-
配置
本地环境可以不配置
spring:
redis:
host: localhost
port: 6379
测试时需要开启本地的服务端
@Autowired
private RedisTemplate redisTemplate; //这是springboot集成redis的操作对象
java的redis客户端Jedis已经被抛弃了
使用redisTemplate.opsForValue/Hash/List就可以进行相应的操作
示例
打包
pom.xml
(我这里这个打包插件怎么老是报错)
jab默认会以application.yml里面的配置为准
可以在命令行中通过 java -jar 带地址的项目名字.jar 来使用项目
war包有点麻烦,而且使用不多
需要在pom.xml里面配置
1.<>
2.<> 忽略内置tomcat
3.设置包名
4.重写config方法
war包需要放在外部tomcat中webapp目录下,而且配置都是默认的tomcat配置
swagger3 文档工具
前后端分离项目非常好用的工具,减轻后端维护的困难
使用swagger后,方法上面的注释也就不需要了
swagger3支持 OpenAPI,就是一套目前的api规范
- 导包
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
配置
写一个配置类(使用@configation,@EnableOpenapi)
但是在正常情况下,实际上不需要添加 @EnableOpenApi 注解。
设置扫描的api接口包名
文档名称以及版本
-
使用
在接口方法上面标注功能,以及参数解释
具体使用有一套规范,不能更改(只需要添加@Operation)
如果带有@RequesBody,接收json格式,那么就不会有parameter(地址栏参数),而是以schema为代替
返回类型不能是map,list等等,必须封装一下.不然就不能看到返回值类型(因为没有查询,map里面是空的)
接口类上面使用@Api标注
每个接口的说明ApiOperaion必须要有
pojo类不处理
也就是说,只需要给每个接口方法描述一下,其他参数说明等等都不需要
swagger3使用项目路径+swagger-ui/index.html 访问
注解:
这些注解都是swagger2里面的注解,swagger3已经更新了
@Api(tags="")用在类上面,说明类的作用
@ApiOperation(value="方法作用说明",notes="备注说明") 用在方法上面,必填的(前端大部分时候需要知道每个方法的作用)
@ApiimplicitParams(name="参数名",value="参数的解释",required=true/false) 一般只写三个参数
(paramtype="方法获取类型[header@RequestHeader地址栏/path@pathVariable/body/form表单] ")
@ApiResponses 写在方法上面
@ApiModel (value="") 放在响应类上面(一般是实体类)
@ApiModelProperty (value="") 在实体类的字段上面
swagger3注解:
@Operation代替上面的@ApiOperation
(summary="方法上面的描述",description="点开的具体描述(可以说明一下参数,以及响应信息)")
工具类推荐
commons-lang3
热部署
好像找到了以往代码的龟速开发惨痛史
热部署就是运行的时候可以更新代码,简直是学生党福音啊
原理上是使用了两个classLoader,一个加载那些第三方jar包,一个加载更改的类.
类更改后,会重新创建一个classLoader,代替旧的
由于需要加载的类比较少,所以实现了较快的重启时间
注意: 重启会清空项目session中的值,以及缓存中的值
需要修改idea的一些配置,开启自动编译,无论任何热部署方法都需要(自动编译,运行时编译)
JRebel or devtools
如果jRebel不收费,那绝对使用jRebel的
作为热部署界的前辈,JRebel依然是敌得过后浪,果然是姜还是老的辣
使用devtools需要引入依赖,设置yml配置(所以每个项目都需要配置)
JRebel只需要下载插件,然后功能栏上面就会多两个按钮
激活:上面填的这个到底是什么东西,为什么是网站加上GUID
使用:
原来就是build里面
ctrl+f9更新编译整个项目
ctrl+shift+f9更新当前文件
分布式缓存Ehcache
Ehcache是一个比较成熟的缓存框架,最早由hibernate发展而来.
与后面的redis比较类似,都是有策略的缓存一部分数据
也是key-value型的非关系型数据库
可以放在jvm内存或者本地磁盘
- 导入坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
注解:
@CacheConfig(cachename="")
放在类上面
@Cacheable
放在读取数据的方法上面,设置可缓存的方法
下次查询时,从缓存中读取.如果缓存中没有,从数据库中查询并放在缓存中
value 集合名
key ="#id" 注意:key里面首先带一个#
@CachePut (value ,key)
放在新增,更新数据的方法上面
调用方法后会自动把返回的类型放入缓存,与数据库同步
@CacheEvict (value ,key)
放在删除方法上,数据自动从缓存移除
-
配置文件
ehcache.xml(比较繁琐,复制就好了)
yml中配置xml地址 -
使用
启动类上面添加@EnableCaching ,pojo实现序列化
在相应的方法上面添加对应的注解
如果数据已经有了,缓存会不会执行service操作,应该不会
注意:最好把缓存放在service层
这里面查询,增加,修改方法必须返回数据,而且数据类型必须一致.(不能返回void,否则不会放入内存)
删除方法可以返回void
一般这里面的key取不变的值,比如userid之类
集成Thymeleaf
freemarker,thymeleaf都是前端模板引擎,jsp也是模板引擎不过早就过时了
thymeleaf基于html,这是boot官方推荐的前端模板引擎
使用比较简单,开箱即用(一般只需要配置不使用缓存就行了)
默认后缀.html
使用th: xx ="${}"属性读取数据
接口写法
一般最外层都是状态码和描述说明
这里
使用commons-lang工具类判断,自己也写一个工具类判断
今天又看到了linux客户端,ssh,xshell
又想到了阿里云等云端
quartz 定时器
功能比起js里面的计时器要强很多,因为有cron表达式
java里面还有自带的Timer,
boot自带的Scheduled等等定时器
-
导包
starter-quartz -
使用
- 定义job,实现Job接口(要执行的任务)
在execute里面实现业务逻辑
2.定义调度配置类(使用@Configuration)
创建JobDetail实例(使用前面的job),
使用scheduleBuilder(计划构建器)和detail实例 定义Trigger(触发器)
- 定义job,实现Job接口(要执行的任务)
启动服务后,定时任务就会一直进行
可以到网上查找cron表达式,直接复制到cronSchedule里面就行了
cron是linux中的计时任务,在java中也使用cron表达式.
秒 分钟 小时 日 月 星期 年